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