]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audiohda.c
audiohda: add support for PCH (Dell E5420)
[plan9front.git] / sys / src / 9 / pc / audiohda.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
9
10 typedef struct Codec Codec;
11 typedef struct Ctlr Ctlr;
12 typedef struct Bld Bld;
13 typedef struct Ring Ring;
14 typedef struct Id Id;
15 typedef struct Widget Widget;
16 typedef struct Codec Codec;
17 typedef struct Fungroup Fungroup;
18 typedef struct Pinprop Pinprop;
19
20 enum {
21         Gcap = 0x00,
22         Gctl = 0x08,
23                 Rst = 1,
24                 Flush = 2,
25                 Acc = 1<<8,
26         Wakeen = 0x0c,
27         Statests = 0x0e,
28                 Sdiwake = 1 | 2 | 4,
29         Intctl = 0x20,
30                 Gie = 1<<31,
31                 Cie = 1<<30,
32         Intsts = 0x24,
33                 Gis = 1<<31,
34                 Cis = 1<<30,
35         Walclk = 0x30,
36         Corblbase = 0x40,
37         Corbubase = 0x44,
38         Corbwp = 0x48,
39         Corbrp = 0x4a,
40                 Corbptrrst = 1<<15,
41         Corbctl = 0x4c,
42                 Corbdma = 2,
43                 Corbint = 1,
44         Corbsts = 0x4d,
45                 Cmei = 1,
46         Corbsz = 0x4e,
47         Rirblbase = 0x50,
48         Rirbubase = 0x54,
49         Rirbwp = 0x58,
50                 Rirbptrrst = 1<<15,
51         Rintcnt = 0x5a,
52         Rirbctl = 0x5c,
53                 Rirbover = 4,
54                 Rirbdma = 2,
55                 Rirbint = 1,
56         Rirbsts = 0x5d,
57                 Rirbrover = 4,
58                 Rirbrint = 1,
59         Rirbsz = 0x5e,
60         Immcmd = 0x60,
61         Immresp = 0x64,
62         Immstat = 0x68,
63         Dplbase = 0x70,
64         Dpubase = 0x74,
65         /* Warning: Sdctl is 24bit register */
66         Sdctl0 = 0x80,
67                 Srst = 1<<0,
68                 Srun = 1<<1,
69                 Scie = 1<<2,
70                 Seie = 1<<3,
71                 Sdie = 1<<4,
72                 Stagbit = 20,
73         Sdsts = 0x03,
74                 Scompl = 1<<2,
75                 Sfifoerr = 1<<3,
76                 Sdescerr = 1<<4,
77                 Sfifordy = 1<<5,
78         Sdlpib = 0x04,
79         Sdcbl =  0x08,
80         Sdlvi =  0x0c,
81         Sdfifow = 0x0e,
82         Sdfifos = 0x10,
83         Sdfmt = 0x12,
84                 Fmtmono = 0,
85                 Fmtstereo = 1,
86                 Fmtsampw = 1<<4,
87                 Fmtsampb = 0<<4,
88                 Fmtdiv1 = 0<<8,
89                 Fmtmul1 = 0<<11,
90                 Fmtbase441 = 1<<14,
91                 Fmtbase48 = 0<<14,
92         Sdbdplo = 0x18,
93         Sdbdphi = 0x1c,
94 };
95
96 enum {
97         Bufsize = 64 * 1024 * 4,
98         Nblocks = 256,
99         Blocksize = Bufsize / Nblocks,
100         BytesPerSample = 4,
101
102         Maxrirbwait = 1000, /* microseconds */
103         Maxwaitup = 500, /* microseconds */
104         Codecdelay = 1000, /* microseconds */
105 };
106
107 enum {
108         /* 12-bit cmd + 8-bit payload */
109         Getparm = 0xf00,
110                 Vendorid = 0x00,
111                 Revid = 0x02,
112                 Subnodecnt = 0x04,
113                 Fungrtype = 0x05,
114                         Graudio = 0x01,
115                         Grmodem = 0x02,
116                 Fungrcap = 0x08,
117                 Widgetcap = 0x09,
118                         Waout = 0,
119                         Wain = 1,
120                         Wamix = 2,
121                         Wasel = 3,
122                         Wpin = 4,
123                         Wpower = 5,
124                         Wknob = 6,
125                         Wbeep = 7,
126                         Winampcap = 0x0002,
127                         Woutampcap = 0x0004,
128                         Wampovrcap = 0x0008,
129                         Wfmtovrcap = 0x0010,
130                         Wstripecap = 0x0020,
131                         Wproccap = 0x0040,
132                         Wunsolcap = 0x0080,
133                         Wconncap = 0x0100,
134                         Wdigicap = 0x0200,
135                         Wpwrcap = 0x0400,
136                         Wlrcap = 0x0800,
137                         Wcpcap = 0x1000,                         
138                 Streamrate = 0x0a,
139                 Streamfmt = 0x0b,
140                 Pincap = 0x0c,
141                         Psense = 1<<0,
142                         Ptrigreq = 1<<1,
143                         Pdetect = 1<<2,
144                         Pheadphone = 1<<3,
145                         Pout = 1<<4,
146                         Pin = 1<<5,
147                         Pbalanced = 1<<6,
148                         Phdmi = 1<<7,
149                         Peapd = 1<<16,
150                 Inampcap = 0x0d,
151                 Outampcap = 0x12,
152                 Connlistlen = 0x0e,
153                 Powerstates = 0x0f,
154                 Processcap = 0x10,
155                 Gpiocount = 0x11,
156                 Knobcap = 0x13,
157         Getconn = 0xf01,
158         Setconn = 0x701,
159         Getconnlist = 0xf02,
160         Getstate = 0xf03,
161         Setstate = 0x703,
162         Setpower = 0x705,
163         Getpower = 0xf05,
164         Getstream = 0xf06,
165         Setstream = 0x706,
166         Getpinctl = 0xf07,
167         Setpinctl = 0x707,
168                 Pinctlin = 1<<5,
169                 Pinctlout = 1<<6,
170                 Pinctlhphn = 1<<7,
171         Getunsolresp = 0xf08,
172         Setunsolresp = 0x708,
173         Getpinsense = 0xf09,
174         Exepinsense = 0x709,
175         Getgpi = 0xf10,
176         Setgpi = 0x710,
177         Getbeep = 0xf0a,
178         Setbeep = 0x70a,
179         Seteapd = 0x70c,
180                 Btlenable = 1,
181                 Eapdenable = 2,
182                 LRswap = 4,
183         Getknob = 0xf0f,
184         Setknob = 0x70f,
185         Getdefault = 0xf1c,
186         Funreset = 0x7ff,
187         Getchancnt = 0xf2d,
188         Setchancnt = 0x72d,
189         
190         /* 4-bit cmd + 16-bit payload */
191         Getcoef = 0xd,
192         Setcoef = 0x5,
193         Getproccoef = 0xc,
194         Setproccoef = 0x4,
195         Getamp = 0xb,
196         Setamp = 0x3,
197                 Asetout = 1<<15,
198                 Asetin = 1<<14,
199                 Asetleft = 1<<13,
200                 Asetright = 1<<12,
201                 Asetmute = 1<<7,
202                 Asetidx = 8,
203                 Agetin = 0<<15,
204                 Agetout = 1<<15,
205                 Agetleft = 1<<13,
206                 Agetright = 1<<15,
207                 Agetidx = 0,
208                 Again = 0,
209                 Againmask = 0x7f,
210         Getconvfmt = 0xa,
211         Setconvfmt = 0x2,
212 };
213
214 enum {
215         Maxcodecs = 16,
216         Maxwidgets = 256,
217 };
218
219 struct Ring {
220         Rendez r;
221
222         uchar   *buf;
223         ulong   nbuf;
224
225         ulong   ri;
226         ulong   wi;
227 };
228
229 struct Id {
230         Ctlr *ctlr;
231         uint codec, nid;
232 };
233
234 struct Widget {
235         Id id;
236         Fungroup *fg;
237         uint cap, type;
238         uint nlist;
239         Widget **list;
240         union {
241                 struct {
242                         uint pin, pincap;
243                 };
244                 struct {
245                         uint convrate, convfmt;
246                 };
247         };
248         Widget *next;
249         Widget *from;
250 };
251
252 struct Fungroup {
253         Id id;
254         Codec *codec;
255         uint type;
256         Widget *first;
257         Widget *mixer;
258         Widget *src, *dst;
259         Fungroup *next;
260 };
261
262 struct Codec {
263         Id id;
264         uint vid, rid;
265         Widget *widgets[Maxwidgets];
266         Fungroup *fgroup;
267 };
268
269 /* hardware structures */
270
271 struct Bld {
272         ulong addrlo;
273         ulong addrhi;
274         ulong len;
275         ulong flags;
276 };
277
278 struct Ctlr {
279         Ctlr *next;
280         uint no;
281
282         Lock;                   /* interrupt lock */
283         QLock;                  /* command lock */
284
285         Audio *adev;
286         Pcidev *pcidev;
287         
288         uchar *mem;
289         ulong size;
290         
291         Queue *q;
292         ulong *corb;
293         ulong corbsize;
294         ulong *rirb;
295         ulong rirbsize;
296         
297         uint sdctl;
298         uint sdintr;
299         uint sdnum;
300
301         Bld *blds;
302
303         Ring ring;
304
305         uint iss, oss, bss;
306
307         uint codecmask; 
308         Codec *codec[Maxcodecs];
309
310         Widget *amp, *src;
311         uint pin;
312         uint cad;
313
314         int active;
315         uint afmt, atag;
316 };
317
318 #define csr32(c, r)     (*(ulong *)&(c)->mem[r])
319 #define csr16(c, r)     (*(ushort *)&(c)->mem[r])
320 #define csr8(c, r)      (*(uchar *)&(c)->mem[r])
321
322 static char *widtype[] = {
323         "aout",
324         "ain",
325         "amix",
326         "asel",
327         "pin",
328         "power",
329         "knob",
330         "beep",
331 };
332
333 static char *pinport[] = {
334         "jack",
335         "nothing",
336         "fix",
337         "jack+fix",
338 };
339
340 static char *pinfunc[] = {
341         "lineout",
342         "speaker",
343         "hpout",
344         "cd",
345         "spdifout",
346         "digiout",
347         "modemline",
348         "modemhandset",
349         "linein",
350         "aux",
351         "micin",
352         "telephony",
353         "spdifin",
354         "digiin",
355         "resvd",
356         "other",
357 };
358
359
360 static char *pincol[] = {
361         "?",
362         "black",
363         "grey",
364         "blue",
365         "green",
366         "red",
367         "orange",
368         "yellow",
369         "purple",
370         "pink",
371         "resvd",
372         "resvd",
373         "resvd",
374         "resvd",
375         "white",
376         "other",
377 };
378
379 static char *pinloc[] = {
380         "N/A",
381         "rear",
382         "front",
383         "left",
384         "right",
385         "top",
386         "bottom",
387         "special",
388         "special",
389         "special",
390         "resvd",
391         "resvd",
392         "resvd",
393         "resvd",
394         "resvd",
395         "resvd",
396 };
397
398 static char *pinloc2[] = {
399         "ext",
400         "int",
401         "sep",
402         "other",
403 };
404
405 Ctlr *lastcard;
406
407 static int
408 waitup8(Ctlr *ctlr, int reg, uchar mask, uchar set)
409 {
410         int i;
411         for(i=0; i<Maxwaitup; i++){
412                 if((csr8(ctlr, reg) & mask) == set)
413                         return 0;
414                 microdelay(1);
415         }
416         print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
417                 ctlr->no, reg, mask, set);
418         return -1;
419 }
420
421 static int
422 waitup16(Ctlr *ctlr, int reg, ushort mask, ushort set)
423 {
424         int i;
425         for(i=0; i<Maxwaitup; i++){
426                 if((csr16(ctlr, reg) & mask) == set)
427                         return 0;
428                 microdelay(1);
429         }
430         print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
431                 ctlr->no, reg, mask, set);
432         return -1;
433 }
434
435 static int
436 waitup32(Ctlr *ctlr, int reg, uint mask, uint set)
437 {
438         int i;
439         for(i=0; i<Maxwaitup; i++){
440                 if((csr32(ctlr, reg) & mask) == set)
441                         return 0;
442                 microdelay(1);
443         }
444         print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
445                 ctlr->no, reg, mask, set);
446         return -1;
447 }
448
449 static int
450 hdacmd(Ctlr *ctlr, uint request, uint reply[2])
451 {
452         uint rp, wp;
453         uint re;
454         int wait;
455         
456         re = csr16(ctlr, Rirbwp);
457         rp = csr16(ctlr, Corbrp);
458         wp = (csr16(ctlr, Corbwp) + 1) % ctlr->corbsize;
459         if(rp == wp){
460                 print("#A%d: corb full\n", ctlr->no);
461                 return -1;
462         }
463         ctlr->corb[wp] = request;
464         coherence();
465         csr16(ctlr, Corbwp) = wp;
466         for(wait=0; wait < Maxrirbwait; wait++){
467                 if(csr16(ctlr, Rirbwp) != re){
468                         re = (re + 1) % ctlr->rirbsize;
469                         memmove(reply, &ctlr->rirb[re*2], 8);
470                         return 1;
471                 }
472                 microdelay(1);
473         }
474         return 0;
475 }
476
477 static int
478 cmderr(Id id, uint verb, uint par, uint *ret)
479 {
480         uint q, w[2];
481         q = (id.codec << 28) | (id.nid << 20);
482         if((verb & 0x700) == 0x700)
483                 q |= (verb << 8) | par;
484         else
485                 q |= (verb << 16) | par;
486         if(hdacmd(id.ctlr, q, w) != 1)
487                 return -1;
488         if(w[1] != id.codec)
489                 return -1;
490         *ret = w[0];
491         return 0;
492 }
493
494 static uint
495 cmd(Id id, uint verb, uint par)
496 {
497         uint w[2];
498         if(cmderr(id, verb, par, w) == -1)
499                 return ~0;
500         return w[0];
501 }
502
503 static Id
504 newnid(Id id, uint nid)
505 {
506         id.nid = nid;
507         return id;
508 }
509
510 static uint
511 getoutamprange(Widget *w)
512 {
513         uint r;
514
515         if((w->cap & Woutampcap) == 0)
516                 return 0;
517         if((w->cap & Wampovrcap) == 0)
518                 r = cmd(w->fg->id, Getparm, Outampcap);
519         else
520                 r = cmd(w->id, Getparm, Outampcap);
521         return (r >> 8) & 0x7f;
522 }
523
524 static void
525 getoutamp(Widget *w, int vol[2])
526 {
527         vol[0] = vol[1] = 0;
528         if((w->cap & Woutampcap) == 0)
529                 return;
530         vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
531         vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
532 }
533
534 /* vol is 0...range or nil for 0dB; mute is 0/1 */
535 static void
536 setoutamp(Widget *w, int mute, int *vol)
537 {
538         uint q, r, i;
539         uint zerodb;
540
541         if((w->cap & Woutampcap) == 0)
542                 return;
543         if((w->cap & Wampovrcap) == 0)
544                 r = cmd(w->fg->id, Getparm, Outampcap);
545         else
546                 r = cmd(w->id, Getparm, Outampcap);
547         zerodb = r & 0x7f;
548         
549         for(i=0; i<2; i++){
550                 q = Asetout | (i == 0 ? Asetleft : Asetright);
551                 if(mute)
552                         q |= Asetmute;
553                 else if(vol == nil)
554                         q |= zerodb << Again;
555                 else
556                         q |= vol[i] << Again;
557                 cmd(w->id, Setamp, q);
558         }
559 }
560
561 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
562 static void
563 setinamp(Widget *w, Widget *in, int mute, int *vol)
564 {
565         uint q, r, i, j;
566         uint zerodb;
567
568         if((w->cap & Winampcap) == 0)
569                 return;
570         if((w->cap & Wampovrcap) == 0)
571                 r = cmd(w->fg->id, Getparm, Inampcap);
572         else
573                 r = cmd(w->id, Getparm, Inampcap);
574         zerodb = r & 0x7f;
575         
576         for(i=0; i<2; i++){
577                 q = Asetin | (i == 0 ? Asetleft : Asetright);
578                 if(mute)
579                         q |= Asetmute;
580                 else if(vol == nil)
581                         q |= zerodb << Again;
582                 else
583                         q |= vol[i] << Again;
584                 for(j=0; j<w->nlist; j++){
585                         if(in == nil || w->list[j] == in)
586                                 cmd(w->id, Setamp, q | (j << Asetidx));
587                 }
588         }
589 }
590
591 static Widget *
592 findpath(Widget *src)
593 {
594         Widget *q[Maxwidgets];
595         uint l, r, i;
596         Widget *w, *v;
597         
598         l = r = 0;
599         q[r++] = src;
600         for(w=src->fg->first; w; w=w->next)
601                 w->from = nil;
602         src->from = src;
603
604         while(l < r){
605                 w = q[l++];
606                 if(w->type == Waout)
607                         break;
608                 for(i=0; i<w->nlist; i++){
609                         v = w->list[i];
610                         if(v == nil || v->from)
611                                 continue;
612                         v->from = w;
613                         q[r++] = v;
614                 }
615         }
616         if(w->type != Waout)
617                 return nil;
618         return w;
619 }
620
621 static void
622 connectpath(Widget *src, Widget *dst)
623 {
624         Widget *w, *v;
625         uint i;
626
627         for(w=dst; w != src; w=v){
628                 v = w->from;
629                 setoutamp(w, 0, nil);
630                 setinamp(v, w, 0, nil);
631                 if(v->nlist == 1)
632                         continue;
633                 for(i=0; i < v->nlist; i++)
634                         if(v->list[i] == w){
635                                 cmd(v->id, Setconn, i); 
636                                 break;
637                         }
638         }
639         setoutamp(src, 0, nil);
640         cmd(src->id, Setpinctl, Pinctlout);
641 }
642
643 static void
644 addconn(Widget *w, uint nid)
645 {
646         Widget *src;
647
648         src = nil;
649         if(nid < Maxwidgets)
650                 src = w->fg->codec->widgets[nid];
651         if(src == nil || (src->fg != w->fg)){
652                 print("hda: invalid connection %d:%s[%d] -> %d\n",
653                         w->id.nid, widtype[w->type & 7], w->nlist, nid);
654                 src = nil;
655         }
656         if((w->nlist % 16) == 0){
657                 void *p;
658
659                 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
660                         print("hda: no memory for Widgetlist\n");
661                         return;
662                 }
663                 w->list = p;
664         }
665         w->list[w->nlist++] = src;
666         return;
667 }
668
669 static void
670 enumconns(Widget *w)
671 {
672         uint r, f, b, m, i, n, x, y;
673
674         if((w->cap & Wconncap) == 0)
675                 return;
676
677         r = cmd(w->id, Getparm, Connlistlen);
678         n = r & 0x7f;
679         b = (r & 0x80) ? 16 : 8;
680         m = (1<<b)-1;
681         f = (32/b)-1;
682         x = 0;
683         for(i=0; i<n; i++){
684                 if(i & f)
685                         r >>= b;
686                 else
687                         r = cmd(w->id, Getconnlist, i);
688                 y = r & (m>>1);
689                 if(i && (r & m) != y)
690                         while(++x < y)
691                                 addconn(w, x);
692                 addconn(w, y);
693                 x = y;
694         }
695 }
696
697 static void
698 enumwidget(Widget *w)
699 {
700         w->cap = cmd(w->id, Getparm, Widgetcap);
701         w->type = (w->cap >> 20) & 0x7;
702         if(w->cap & Wpwrcap)
703                 cmd(w->id, Setpower, 0);
704
705         enumconns(w);
706         
707         switch(w->type){
708         case Wpin:
709                 w->pin = cmd(w->id, Getdefault, 0);
710                 w->pincap = cmd(w->id, Getparm, Pincap);
711                 if(w->pincap & Peapd)
712                         cmd(w->id, Seteapd, Eapdenable);
713                 break;
714         }
715 }
716
717 static Fungroup *
718 enumfungroup(Codec *codec, Id id)
719 {
720         Fungroup *fg;
721         Widget *w, **tail;
722         uint i, r, n, base;
723
724         r = cmd(id, Getparm, Fungrtype) & 0x7f;
725         if(r != Graudio){
726                 cmd(id, Setpower, 3);   /* turn off */
727                 return nil;
728         }
729
730         /* open eyes */
731         cmd(id, Setpower, 0);
732         microdelay(100);
733
734         fg = mallocz(sizeof *fg, 1);
735         if(fg == nil){
736 Nomem:
737                 print("hda: enumfungroup: out of memory\n");
738                 return nil;
739         }
740         fg->codec = codec;
741         fg->id = id;
742         fg->type = r;
743
744         r = cmd(id, Getparm, Subnodecnt);
745         n = r & 0xff;
746         base = (r >> 16) & 0xff;
747         
748         if(base + n > Maxwidgets){
749                 free(fg);
750                 return nil;
751         }
752
753         tail = &fg->first;
754         for(i=0; i<n; i++){
755                 w = mallocz(sizeof(Widget), 1);
756                 if(w == nil){
757                         while(w = fg->first){
758                                 fg->first = w->next;
759                                 codec->widgets[w->id.nid] = nil;
760                                 free(w);
761                         }
762                         free(fg);
763                         goto Nomem;
764                 }
765                 w->id = newnid(id, base + i);
766                 w->fg = fg;
767                 *tail = w;
768                 tail = &w->next;
769                 codec->widgets[w->id.nid] = w;
770         }
771
772         for(i=0; i<n; i++)
773                 enumwidget(codec->widgets[base + i]);
774
775         return fg;
776 }
777
778
779 static int
780 enumcodec(Codec *codec, Id id)
781 {
782         Fungroup *fg;
783         uint i, r, n, base;
784         uint vid, rid;
785         
786         if(cmderr(id, Getparm, Vendorid, &vid) < 0)
787                 return -1;
788         if(cmderr(id, Getparm, Revid, &rid) < 0)
789                 return -1;
790         
791         codec->id = id;
792         codec->vid = vid;
793         codec->rid = rid;
794
795         r = cmd(id, Getparm, Subnodecnt);
796         n = r & 0xff;
797         base = (r >> 16) & 0xff;
798
799         for(i=0; i<n; i++){
800                 fg = enumfungroup(codec, newnid(id, base + i));
801                 if(fg == nil)
802                         continue;
803                 fg->next = codec->fgroup;
804                 codec->fgroup = fg;
805         }
806         if(codec->fgroup == nil)
807                 return -1;
808
809         print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
810                 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
811
812         return 0;
813 }
814
815 static int
816 enumdev(Ctlr *ctlr)
817 {
818         Codec *codec;
819         int ret;
820         Id id;
821         int i;
822
823         ret = -1;
824         id.ctlr = ctlr;
825         id.nid = 0;
826         for(i=0; i<Maxcodecs; i++){
827                 if(((1<<i) & ctlr->codecmask) == 0)
828                         continue;
829                 codec = mallocz(sizeof(Codec), 1);
830                 if(codec == nil){
831                         print("hda: no memory for Codec\n");
832                         break;
833                 }
834                 id.codec = i;
835                 ctlr->codec[i] = codec;
836                 if(enumcodec(codec, id) < 0){
837                         ctlr->codec[i] = nil;
838                         free(codec);
839                         continue;
840                 }
841                 ret++;
842         }
843         return ret;
844 }
845
846 static int
847 connectpin(Ctlr *ctlr, uint pin, uint cad)
848 {
849         Widget *w, *src, *dst;
850
851         if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
852                 return -1;
853         src = ctlr->codec[cad]->widgets[pin];
854         if(src == nil)
855                 return -1;
856         if(src->type != Wpin)
857                 return -1;
858         if((src->pincap & Pout) == 0)
859                 return -1;
860
861         dst = findpath(src);
862         if(dst == nil)
863                 return -1;
864
865         /* mute all widgets, clear stream */
866         for(w=src->fg->first; w != nil; w=w->next){
867                 setoutamp(w, 1, nil);
868                 setinamp(w, nil, 1, nil);
869                 cmd(w->id, Setstream, 0);
870         }
871
872         connectpath(src, dst);
873
874         cmd(dst->id, Setconvfmt, ctlr->afmt);
875         cmd(dst->id, Setstream, (ctlr->atag << 4) | 0);
876         cmd(dst->id, Setchancnt, 1);
877
878         ctlr->amp = dst;
879         ctlr->src = src;
880         ctlr->pin = pin;
881         ctlr->cad = cad;
882         return 0;
883 }
884
885 static int
886 bestpin(Ctlr *ctlr, int *pcad)
887 {
888         Fungroup *fg;
889         Widget *w;
890         int best, pin, score;
891         uint r;
892         int i;
893
894         pin = -1;
895         best = -1;
896         for(i=0; i<Maxcodecs; i++){
897                 if(ctlr->codec[i] == nil)
898                         continue;
899                 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
900                         for(w=fg->first; w; w=w->next){
901                                 if(w->type != Wpin)
902                                         continue;
903                                 if((w->pincap & Pout) == 0)
904                                         continue;
905                                 score = 0;
906                                 r = w->pin;
907                                 if(((r >> 12) & 0xf) == 4) /* green */
908                                         score |= 32;
909                                 if(((r >> 24) & 0xf) == 1) /* rear */
910                                         score |= 16;
911                                 if(((r >> 28) & 0x3) == 0) /* ext */
912                                         score |= 8;
913                                 if(((r >> 20) & 0xf) == 2) /* hpout */
914                                         score |= 4;
915                                 if(((r >> 20) & 0xf) == 0) /* lineout */
916                                         score |= 4;
917                                 if(score >= best){
918                                         best = score;
919                                         pin = w->id.nid;
920                                         *pcad = i;
921                                 }
922                         }
923                 }
924         }
925         return pin;
926 }
927
928 static long
929 buffered(Ring *r)
930 {
931         ulong ri, wi;
932
933         ri = r->ri;
934         wi = r->wi;
935         if(wi >= ri)
936                 return wi - ri;
937         else
938                 return r->nbuf - (ri - wi);
939 }
940
941 static long
942 available(Ring *r)
943 {
944         long m;
945
946         m = (r->nbuf - BytesPerSample) - buffered(r);
947         if(m < 0)
948                 m = 0;
949         return m;
950 }
951
952 static long
953 writering(Ring *r, uchar *p, long n)
954 {
955         long n0, m;
956
957         n0 = n;
958         while(n > 0){
959                 if((m = available(r)) <= 0)
960                         break;
961                 if(m > n)
962                         m = n;
963                 if(p){
964                         if(r->wi + m > r->nbuf)
965                                 m = r->nbuf - r->wi;
966                         memmove(r->buf + r->wi, p, m);
967                         p += m;
968                 }
969                 r->wi = (r->wi + m) % r->nbuf;
970                 n -= m;
971         }
972         return n0 - n;
973 }
974
975 static int
976 streamalloc(Ctlr *ctlr)
977 {
978         Ring *r;
979         int i;
980
981         r = &ctlr->ring;
982         memset(r, 0, sizeof(*r));
983         r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
984         ctlr->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
985         if(r->buf == nil || ctlr->blds == nil){
986                 print("hda: no memory for stream\n");
987                 return -1;
988         }
989         for(i=0; i<Nblocks; i++){
990                 ctlr->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
991                 ctlr->blds[i].addrhi = 0;
992                 ctlr->blds[i].len = Blocksize;
993                 ctlr->blds[i].flags = 0x01;     /* interrupt on completion */
994         }
995
996         /* output dma engine starts after inputs */
997         ctlr->sdnum = ctlr->iss;
998         ctlr->sdctl = Sdctl0 + ctlr->sdnum*0x20;
999         ctlr->sdintr = 1<<ctlr->sdnum;
1000         ctlr->atag = ctlr->sdnum+1;
1001         ctlr->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
1002         ctlr->active = 0;
1003
1004         /* perform reset */
1005         csr8(ctlr, ctlr->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
1006         csr8(ctlr, ctlr->sdctl) |= Srst;
1007         microdelay(Codecdelay);
1008         waitup8(ctlr, ctlr->sdctl, Srst, Srst);
1009         csr8(ctlr, ctlr->sdctl) &= ~Srst;
1010         microdelay(Codecdelay);
1011         waitup8(ctlr, ctlr->sdctl, Srst, 0);
1012
1013         /* set stream number */
1014         csr32(ctlr, ctlr->sdctl) = (ctlr->atag << Stagbit) |
1015                 (csr32(ctlr, ctlr->sdctl) & ~(0xF << Stagbit));
1016
1017         /* set stream format */
1018         csr16(ctlr, Sdfmt+ctlr->sdctl) = ctlr->afmt;
1019
1020         /* program stream DMA & parms */
1021         csr32(ctlr, Sdbdplo+ctlr->sdctl) = PADDR(ctlr->blds);
1022         csr32(ctlr, Sdbdphi+ctlr->sdctl) = 0;
1023         csr32(ctlr, Sdcbl+ctlr->sdctl) = r->nbuf;
1024         csr16(ctlr, Sdlvi+ctlr->sdctl) = (Nblocks - 1) & 0xff;
1025
1026         /* mask out ints */
1027         csr8(ctlr, Sdsts+ctlr->sdctl) = Scompl | Sfifoerr | Sdescerr;
1028
1029         /* enable global intrs for this stream */
1030         csr32(ctlr, Intctl) |= ctlr->sdintr;
1031         csr8(ctlr, ctlr->sdctl) |= Scie | Seie | Sdie;
1032
1033         return 0;
1034 }
1035
1036 static void
1037 streamstart(Ctlr *ctlr)
1038 {
1039         ctlr->active = 1;
1040         
1041         csr8(ctlr, ctlr->sdctl) |= Srun;
1042         waitup8(ctlr, ctlr->sdctl, Srun, Srun);
1043 }
1044
1045 static void
1046 streamstop(Ctlr *ctlr)
1047 {
1048         csr8(ctlr, ctlr->sdctl) &= ~Srun;
1049         waitup8(ctlr, ctlr->sdctl, Srun, 0);
1050
1051         ctlr->active = 0;
1052 }
1053
1054 static uint
1055 streampos(Ctlr *ctlr)
1056 {
1057         Ring *r;
1058         uint p;
1059
1060         r = &ctlr->ring;
1061         p = csr32(ctlr, Sdlpib+ctlr->sdctl);
1062         if(p >= r->nbuf)
1063                 p = 0;
1064         return p;
1065 }
1066
1067 static long
1068 hdactl(Audio *adev, void *va, long n, vlong)
1069 {
1070         char *p, *e, *x, *tok[4];
1071         int ntok;
1072         Ctlr *ctlr;
1073         uint pin, cad;
1074         
1075         ctlr = adev->ctlr;
1076         p = va;
1077         e = p + n;
1078         
1079         for(; p < e; p = x){
1080                 if(x = strchr(p, '\n'))
1081                         *x++ = 0;
1082                 else
1083                         x = e;
1084                 ntok = tokenize(p, tok, 4);
1085                 if(ntok <= 0)
1086                         continue;
1087                 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1088                         cad = ctlr->cad;
1089                         pin = strtoul(tok[1], 0, 0);
1090                         if(ntok > 2)
1091                                 cad = strtoul(tok[2], 0, 0);
1092                         connectpin(ctlr, pin, cad);
1093                 }else
1094                         error(Ebadctl);
1095         }
1096         return n;
1097 }
1098
1099 static int
1100 outavail(void *arg)
1101 {
1102         Ctlr *ctlr = arg;
1103         return available(&ctlr->ring) > 0;
1104 }
1105
1106 static int
1107 outrate(void *arg)
1108 {
1109         Ctlr *ctlr = arg;
1110         int delay = ctlr->adev->delay*BytesPerSample;
1111         return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || (ctlr->active == 0);
1112 }
1113
1114 static long
1115 hdabuffered(Audio *adev)
1116 {
1117         Ctlr *ctlr;
1118         ctlr = adev->ctlr;
1119         return buffered(&ctlr->ring);
1120 }
1121
1122 static void
1123 hdakick(Ctlr *ctlr)
1124 {
1125         if(ctlr->active)
1126                 return;
1127         if(buffered(&ctlr->ring) > Blocksize)
1128                 streamstart(ctlr);
1129 }
1130
1131 static long
1132 hdawrite(Audio *adev, void *vp, long n, vlong)
1133 {
1134         uchar *p, *e;
1135         Ctlr *ctlr;
1136         Ring *ring;
1137
1138         p = vp;
1139         e = p + n;
1140         ctlr = adev->ctlr;
1141         ring = &ctlr->ring;
1142         while(p < e) {
1143                 if((n = writering(ring, p, e - p)) <= 0){
1144                         hdakick(ctlr);
1145                         sleep(&ring->r, outavail, ctlr);
1146                         continue;
1147                 }
1148                 p += n;
1149         }
1150         hdakick(ctlr);
1151         sleep(&ring->r, outrate, ctlr);
1152         return p - (uchar*)vp;
1153 }
1154
1155 static void
1156 hdaclose(Audio *adev)
1157 {
1158         Ctlr *ctlr;
1159         uchar z[1];
1160         Ring *r;
1161
1162         ctlr = adev->ctlr;
1163         if(!ctlr->active)
1164                 return;
1165         z[0] = 0;
1166         r = &ctlr->ring;
1167         while(r->wi % Blocksize)
1168                 hdawrite(adev, z, sizeof(z), 0);
1169 }
1170
1171 enum {
1172         Vmaster,
1173         Vspeed,
1174         Vdelay,
1175         Nvol,
1176 };
1177
1178 static Volume voltab[] = {
1179         [Vmaster] "master", 0, 0x7f, Stereo, 0,
1180         [Vspeed] "speed", 0, 0, Absolute, 0,
1181         [Vdelay] "delay", 0, 0, Absolute, 0,
1182         0
1183 };
1184
1185 static int
1186 hdagetvol(Audio *adev, int x, int a[2])
1187 {
1188         Ctlr *ctlr = adev->ctlr;
1189
1190         switch(x){
1191         case Vmaster:
1192                 if(ctlr->amp != nil)
1193                         getoutamp(ctlr->amp, a);
1194                 break;
1195         case Vspeed:
1196                 a[0] = adev->speed;
1197                 break;
1198         case Vdelay:
1199                 a[0] = adev->delay;
1200                 break;
1201         }
1202         return 0;
1203 }
1204
1205 static int
1206 hdasetvol(Audio *adev, int x, int a[2])
1207 {
1208         Ctlr *ctlr = adev->ctlr;
1209
1210         switch(x){
1211         case Vmaster:
1212                 if(ctlr->amp != nil)
1213                         setoutamp(ctlr->amp, 0, a);
1214                 break;
1215         case Vspeed:
1216                 adev->speed = a[0];
1217                 break;
1218         case Vdelay:
1219                 adev->delay = a[0];
1220                 break;
1221         }
1222         return 0;
1223 }
1224
1225 static void
1226 fillvoltab(Ctlr *ctlr, Volume *vt)
1227 {
1228         memmove(vt, voltab, sizeof(voltab));
1229         if(ctlr->amp != nil)
1230                 vt[Vmaster].range = getoutamprange(ctlr->amp);
1231 }
1232
1233 static long
1234 hdavolread(Audio *adev, void *a, long n, vlong)
1235 {
1236         Volume voltab[Nvol+1];
1237         fillvoltab(adev->ctlr, voltab);
1238         return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1239 }
1240
1241 static long
1242 hdavolwrite(Audio *adev, void *a, long n, vlong)
1243 {
1244         Volume voltab[Nvol+1];
1245         fillvoltab(adev->ctlr, voltab);
1246         return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1247 }
1248
1249 static void
1250 hdainterrupt(Ureg *, void *arg)
1251 {
1252         Ctlr *ctlr;
1253         Audio *adev;
1254         uint sts;
1255         Ring *r;
1256
1257         adev = arg;
1258         ctlr = adev->ctlr;
1259         
1260         ilock(ctlr);
1261         sts = csr32(ctlr, Intsts);
1262         if(sts & ctlr->sdintr){
1263                 /* ack interrupt */
1264                 csr8(ctlr, Sdsts+ctlr->sdctl) |= Scompl;
1265                 r = &ctlr->ring;
1266                 r->ri = streampos(ctlr);
1267                 if(ctlr->active && buffered(r) < Blocksize){
1268                         streamstop(ctlr);
1269                         r->ri = r->wi = streampos(ctlr);
1270                 }
1271                 wakeup(&r->r);
1272         }
1273         iunlock(ctlr);
1274 }
1275
1276 static long
1277 hdastatus(Audio *adev, void *a, long n, vlong)
1278 {
1279         Ctlr *ctlr = adev->ctlr;
1280         Codec *codec;
1281         Fungroup *fg;
1282         Widget *w;
1283         uint r;
1284         int i;
1285         char *s, *e;
1286         
1287         s = a;
1288         e = s + n;
1289         s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->ring));
1290         for(i=0; i<Maxcodecs; i++){
1291                 if((codec = ctlr->codec[i]) == nil)
1292                         continue;
1293                 s = seprint(s, e, "codec %2d pin %3d\n",
1294                         codec->id.codec, ctlr->pin);
1295                 for(fg=codec->fgroup; fg; fg=fg->next){
1296                         for(w=fg->first; w; w=w->next){
1297                                 if(w->type != Wpin)
1298                                         continue;
1299                                 r = w->pin;
1300                                 s = seprint(s, e, "pin %3d %s %s %s %s %s %s%s%s\n",
1301                                         w->id.nid,
1302                                         (w->pincap & Pout) != 0 ? "out" : "in",
1303                                         pinport[(r >> 30) & 0x3],
1304                                         pinloc2[(r >> 28) & 0x3],
1305                                         pinloc[(r >> 24) & 0xf],
1306                                         pinfunc[(r >> 20) & 0xf],
1307                                         pincol[(r >> 12) & 0xf],
1308                                         (w->pincap & Phdmi) ? " hdmi" : "",
1309                                         (w->pincap & Peapd) ? " eapd" : ""
1310                                 );
1311                         }
1312                 }
1313         }
1314
1315         s = seprint(s, e, "path ");
1316         for(w=ctlr->amp; w != nil; w = w->from){
1317                 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1318                         (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1319                 if(w == ctlr->src)
1320                         break;
1321                 s = seprint(s, e, " â†’ ");
1322         }
1323         s = seprint(s, e, "\n");
1324
1325         return s - (char*)a;
1326 }
1327
1328
1329 static int
1330 hdastart(Ctlr *ctlr)
1331 {
1332         static int cmdbufsize[] = { 2, 16, 256, 2048 };
1333         int n, size;
1334         uint cap;
1335         
1336         /* reset controller */
1337         csr32(ctlr, Gctl) &= ~Rst;
1338         waitup32(ctlr, Gctl, Rst, 0);
1339         microdelay(Codecdelay);
1340         csr32(ctlr, Gctl) |= Rst;
1341         if(waitup32(ctlr, Gctl, Rst, Rst) && 
1342             waitup32(ctlr, Gctl, Rst, Rst)){
1343                 print("#A%d: hda failed to reset\n", ctlr->no);
1344                 return -1;
1345         }
1346         microdelay(Codecdelay);
1347
1348         ctlr->codecmask = csr16(ctlr, Statests);
1349         if(ctlr->codecmask == 0){
1350                 print("#A%d: hda no codecs\n", ctlr->no);
1351                 return -1;
1352         }
1353
1354         cap = csr16(ctlr, Gcap);
1355         ctlr->bss = (cap>>3) & 0x1F;
1356         ctlr->iss = (cap>>8) & 0xF;
1357         ctlr->oss = (cap>>12) & 0xF;
1358
1359         csr8(ctlr, Corbctl) = 0;
1360         waitup8(ctlr, Corbctl, Corbdma, 0);
1361
1362         csr8(ctlr, Rirbctl) = 0;
1363         waitup8(ctlr, Rirbctl, Rirbdma, 0);
1364
1365         /* alloc command buffers */
1366         size = csr8(ctlr, Corbsz);
1367         n = cmdbufsize[size & 3];
1368         ctlr->corb = xspanalloc(n * 4, 128, 0);
1369         memset(ctlr->corb, 0, n * 4);
1370         ctlr->corbsize = n;
1371
1372         size = csr8(ctlr, Rirbsz);
1373         n = cmdbufsize[size & 3];
1374         ctlr->rirb = xspanalloc(n * 8, 128, 0);
1375         memset(ctlr->rirb, 0, n * 8);
1376         ctlr->rirbsize = n;
1377
1378         /* setup controller  */
1379         csr32(ctlr, Dplbase) = 0;
1380         csr32(ctlr, Dpubase) = 0;
1381         csr16(ctlr, Statests) = csr16(ctlr, Statests);
1382         csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1383         
1384         /* setup CORB */
1385         csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1386         csr32(ctlr, Corbubase) = 0;
1387         csr16(ctlr, Corbwp) = 0;
1388         csr16(ctlr, Corbrp) = Corbptrrst;
1389         waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1390         csr16(ctlr, Corbrp) = 0;
1391         waitup16(ctlr, Corbrp, Corbptrrst, 0);
1392         csr8(ctlr, Corbctl) = Corbdma;
1393         waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1394         
1395         /* setup RIRB */
1396         csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1397         csr32(ctlr, Rirbubase) = 0;
1398         csr16(ctlr, Rirbwp) = Rirbptrrst;
1399         csr8(ctlr, Rirbctl) = Rirbdma;
1400         waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1401         
1402         /* enable interrupts */
1403         csr32(ctlr, Intctl) |= Gie | Cie;
1404         
1405         return 0;
1406 }
1407
1408 static Pcidev*
1409 hdamatch(Pcidev *p)
1410 {
1411         while(p = pcimatch(p, 0, 0))
1412                 switch((p->vid << 16) | p->did){
1413                 case (0x8086 << 16) | 0x2668:   /* Intel ICH6 (untested) */
1414                 case (0x8086 << 16) | 0x27d8:   /* Intel ICH7 */
1415                 case (0x8086 << 16) | 0x269a:   /* Intel ESB2 (untested) */
1416                 case (0x8086 << 16) | 0x284b:   /* Intel ICH8 */
1417                 case (0x8086 << 16) | 0x293f:   /* Intel ICH9 (untested) */
1418                 case (0x8086 << 16) | 0x293e:   /* Intel P35 (untested) */
1419                 case (0x8086 << 16) | 0x811b:   /* Intel SCH (Poulsbo) */
1420                 case (0x8086 << 16) | 0x080a:   /* Intel SCH (Oaktrail) */
1421                 case (0x8086 << 16) | 0x1c20:   /* Intel PCH */
1422                 case (0x8086 << 16) | 0x1e20:   /* Intel (Thinkpad x230t) */
1423
1424                 case (0x10de << 16) | 0x026c:   /* NVidia MCP51 (untested) */
1425                 case (0x10de << 16) | 0x0371:   /* NVidia MCP55 (untested) */
1426                 case (0x10de << 16) | 0x03e4:   /* NVidia MCP61 (untested) */
1427                 case (0x10de << 16) | 0x03f0:   /* NVidia MCP61A (untested) */
1428                 case (0x10de << 16) | 0x044a:   /* NVidia MCP65 (untested) */
1429                 case (0x10de << 16) | 0x055c:   /* NVidia MCP67 (untested) */
1430
1431                 case (0x1002 << 16) | 0x437b:   /* ATI SB450 (untested) */
1432                 case (0x1002 << 16) | 0x4383:   /* ATI SB600 */
1433                 case (0x1002 << 16) | 0x7919:   /* ATI HDMI */
1434
1435                 case (0x1106 << 16) | 0x3288:   /* VIA (untested) */
1436                 case (0x1039 << 16) | 0x7502:   /* SIS (untested) */
1437                 case (0x10b9 << 16) | 0x5461:   /* ULI (untested) */
1438                         return p;
1439                 }
1440         return nil;
1441 }
1442
1443 static long
1444 hdacmdread(Chan *, void *a, long n, vlong)
1445 {
1446         Ctlr *ctlr;
1447         
1448         ctlr = lastcard;
1449         if(ctlr == nil)
1450                 error(Enodev);
1451         if(n & 7)
1452                 error(Ebadarg);
1453         return qread(ctlr->q, a, n);
1454 }
1455
1456 static long
1457 hdacmdwrite(Chan *, void *a, long n, vlong)
1458 {
1459         Ctlr *ctlr;
1460         ulong *lp;
1461         int i;
1462         uint w[2];
1463         
1464         ctlr = lastcard;
1465         if(ctlr == nil)
1466                 error(Enodev);
1467         if(n & 3)
1468                 error(Ebadarg);
1469         lp = a;
1470         qlock(ctlr);
1471         for(i=0; i<n/4; i++){
1472                 if(hdacmd(ctlr, lp[i], w) <= 0){
1473                         w[0] = 0;
1474                         w[1] = ~0;
1475                 }
1476                 qproduce(ctlr->q, w, sizeof(w));
1477         }
1478         qunlock(ctlr);
1479         return n;
1480 }
1481
1482 static int
1483 hdareset(Audio *adev)
1484 {
1485         static Ctlr *cards = nil;
1486         int irq, tbdf, best, cad;
1487         Ctlr *ctlr;
1488         Pcidev *p;
1489
1490         /* make a list of all cards if not already done */
1491         if(cards == nil){
1492                 p = nil;
1493                 while(p = hdamatch(p)){
1494                         ctlr = mallocz(sizeof(Ctlr), 1);
1495                         if(ctlr == nil){
1496                                 print("hda: can't allocate memory\n");
1497                                 return -1;
1498                         }
1499                         ctlr->pcidev = p;
1500                         ctlr->next = cards;
1501                         cards = ctlr;
1502                 }
1503         }
1504
1505         /* pick a card from the list */
1506         for(ctlr = cards; ctlr; ctlr = ctlr->next){
1507                 if(p = ctlr->pcidev){
1508                         ctlr->pcidev = nil;
1509                         goto Found;
1510                 }
1511         }
1512         return -1;
1513
1514 Found:
1515         adev->ctlr = ctlr;
1516         ctlr->adev = adev;
1517
1518         irq = p->intl;
1519         tbdf = p->tbdf;
1520
1521         if(p->vid == 0x10de){
1522                 /* magic for NVidia */
1523                 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1524         }
1525         if(p->vid == 0x10b9){
1526                 /* magic for ULI */
1527                 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1528                 pcicfgw32(p, PciBAR1, 0);
1529         }
1530         if(p->vid == 0x8086){
1531                 /* magic for Intel */
1532                 switch(p->did){
1533                 case 0x1c20:    /* PCH */
1534                 case 0x811b:    /* SCH */
1535                 case 0x080a:
1536                         pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1537                 }
1538         }
1539         if(p->vid == 0x1002){
1540                 /* magic for ATI */
1541                 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1542         } else {
1543                 /* TCSEL */
1544                 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1545         }
1546
1547         pcisetbme(p);
1548         pcisetpms(p, 0);
1549
1550         ctlr->no = adev->ctlrno;
1551         ctlr->size = p->mem[0].size;
1552         ctlr->q = qopen(256, 0, 0, 0);
1553         ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1554         if(ctlr->mem == nil){
1555                 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1556                 return -1;
1557         }
1558         print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1559
1560         if(hdastart(ctlr) < 0){
1561                 print("#A%d: unable to start hda\n", ctlr->no);
1562                 return -1;
1563         }
1564         if(streamalloc(ctlr) < 0){
1565                 print("#A%d: streamalloc failed\n", ctlr->no);
1566                 return -1;
1567         }
1568         if(enumdev(ctlr) < 0){
1569                 print("#A%d: no audio codecs found\n", ctlr->no);
1570                 return -1;
1571         }
1572         best = bestpin(ctlr, &cad);
1573         if(best < 0){
1574                 print("#A%d: no output pins found!\n", ctlr->no);
1575                 return -1;
1576         }
1577         if(connectpin(ctlr, best, cad) < 0){
1578                 print("#A%d: error connecting pin\n", ctlr->no);
1579                 return -1;
1580         }
1581
1582         adev->write = hdawrite;
1583         adev->close = hdaclose;
1584         adev->buffered = hdabuffered;
1585         adev->volread = hdavolread;
1586         adev->volwrite = hdavolwrite;
1587         adev->status = hdastatus;
1588         adev->ctl = hdactl;
1589         
1590         intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1591         lastcard = ctlr;
1592         addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1593         
1594         return 0;
1595 }
1596
1597 void
1598 audiohdalink(void)
1599 {
1600         addaudiocard("hda", hdareset);
1601 }
1602