]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audiohda.c
audioac97: fix inverted recgain control, init to zero recgain
[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         sleep(&ring->r, outrate, ctlr);
1292         return p - (uchar*)vp;
1293 }
1294
1295 static void
1296 hdaclose(Audio *adev, int mode)
1297 {
1298         Ctlr *ctlr;
1299         Ring *ring;
1300
1301         ctlr = adev->ctlr;
1302         if(mode == OREAD || mode == ORDWR){
1303                 if(ctlr->sin.active)
1304                         streamstop(ctlr, &ctlr->sin);
1305         }
1306         if(mode == OWRITE || mode == ORDWR){
1307                 ring = &ctlr->sout.ring;
1308                 while(ring->wi % Blocksize)
1309                         if(writering(ring, (uchar*)"", 1) <= 0)
1310                                 break;
1311         }
1312 }
1313
1314 enum {
1315         Vmaster,
1316         Vrecord,
1317         Vspeed,
1318         Vdelay,
1319         Nvol,
1320 };
1321
1322 static Volume voltab[] = {
1323         [Vmaster] "master", 0, 0x7f, Stereo, 0,
1324         [Vrecord] "recgain", 0, 0x7f, Stereo, 0,
1325         [Vspeed] "speed", 0, 0, Absolute, 0,
1326         [Vdelay] "delay", 0, 0, Absolute, 0,
1327         0
1328 };
1329
1330 static int
1331 hdagetvol(Audio *adev, int x, int a[2])
1332 {
1333         Ctlr *ctlr = adev->ctlr;
1334
1335         switch(x){
1336         case Vmaster:
1337                 if(ctlr->sout.conv != nil)
1338                         getoutamp(ctlr->sout.conv, a);
1339                 break;
1340         case Vspeed:
1341                 a[0] = adev->speed;
1342                 break;
1343         case Vdelay:
1344                 a[0] = adev->delay;
1345                 break;
1346         }
1347         return 0;
1348 }
1349
1350 static int
1351 hdasetvol(Audio *adev, int x, int a[2])
1352 {
1353         Ctlr *ctlr = adev->ctlr;
1354
1355         switch(x){
1356         case Vmaster:
1357                 if(ctlr->sout.conv != nil)
1358                         setoutamp(ctlr->sout.conv, 0, a);
1359                 break;
1360         case Vrecord:
1361                 if(ctlr->sin.conv != nil)
1362                         setinamp(ctlr->sin.conv, nil, 0, a);
1363                 break;
1364         case Vspeed:
1365                 adev->speed = a[0];
1366                 break;
1367         case Vdelay:
1368                 adev->delay = a[0];
1369                 break;
1370         }
1371         return 0;
1372 }
1373
1374 static void
1375 fillvoltab(Ctlr *ctlr, Volume *vt)
1376 {
1377         memmove(vt, voltab, sizeof(voltab));
1378         if(ctlr->sout.conv != nil)
1379                 vt[Vmaster].range = getoutamprange(ctlr->sout.conv);
1380 }
1381
1382 static long
1383 hdavolread(Audio *adev, void *a, long n, vlong)
1384 {
1385         Volume voltab[Nvol+1];
1386         fillvoltab(adev->ctlr, voltab);
1387         return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1388 }
1389
1390 static long
1391 hdavolwrite(Audio *adev, void *a, long n, vlong)
1392 {
1393         Volume voltab[Nvol+1];
1394         fillvoltab(adev->ctlr, voltab);
1395         return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1396 }
1397
1398 static void
1399 hdainterrupt(Ureg *, void *arg)
1400 {
1401         Ctlr *ctlr;
1402         Audio *adev;
1403         Ring *r;
1404         uint sts;
1405
1406         adev = arg;
1407         ctlr = adev->ctlr;
1408         ilock(ctlr);
1409         sts = csr32(ctlr, Intsts);
1410         if(sts & ctlr->sout.sdintr){
1411                 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
1412
1413                 r = &ctlr->sout.ring;
1414                 r->ri = streampos(ctlr, &ctlr->sout);
1415                 if(ctlr->sout.active && buffered(r) < Blocksize){
1416                         streamstop(ctlr, &ctlr->sout);
1417                         r->ri = r->wi = streampos(ctlr, &ctlr->sout);
1418                 }
1419                 wakeup(&r->r);
1420         }
1421         if(sts & ctlr->sin.sdintr){
1422                 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
1423
1424                 r = &ctlr->sin.ring;
1425                 r->wi = streampos(ctlr, &ctlr->sin);
1426                 if(ctlr->sin.active && available(r) < Blocksize){
1427                         streamstop(ctlr, &ctlr->sin);
1428                         r->ri = r->wi = streampos(ctlr, &ctlr->sin);
1429                 }
1430                 wakeup(&r->r);
1431         }
1432         iunlock(ctlr);
1433 }
1434
1435 static long
1436 hdastatus(Audio *adev, void *a, long n, vlong)
1437 {
1438         Ctlr *ctlr = adev->ctlr;
1439         Codec *codec;
1440         Fungroup *fg;
1441         Widget *w;
1442         uint r;
1443         int i;
1444         char *s, *e;
1445         
1446         s = a;
1447         e = s + n;
1448         s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->sout.ring));
1449         for(i=0; i<Maxcodecs; i++){
1450                 if((codec = ctlr->codec[i]) == nil)
1451                         continue;
1452                 s = seprint(s, e, "codec %2d pin %3d inpin %3d\n",
1453                         codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
1454                 for(fg=codec->fgroup; fg; fg=fg->next){
1455                         for(w=fg->first; w; w=w->next){
1456                                 if(w->type != Wpin)
1457                                         continue;
1458                                 r = w->pin;
1459                                 s = seprint(s, e, "pin %3d %s%s %s %s %s %s %s%s%s\n",
1460                                         w->id.nid,
1461                                         (w->pincap & Pin) != 0 ? "in" : "",
1462                                         (w->pincap & Pout) != 0 ? "out" : "",
1463                                         pinport[(r >> 30) & 0x3],
1464                                         pinloc2[(r >> 28) & 0x3],
1465                                         pinloc[(r >> 24) & 0xf],
1466                                         pinfunc[(r >> 20) & 0xf],
1467                                         pincol[(r >> 12) & 0xf],
1468                                         (w->pincap & Phdmi) ? " hdmi" : "",
1469                                         (w->pincap & Peapd) ? " eapd" : ""
1470                                 );
1471                         }
1472                 }
1473         }
1474
1475         s = seprint(s, e, "outpath ");
1476         for(w=ctlr->sout.conv; w != nil; w = w->path){
1477                 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1478                         (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1479                 if(w == ctlr->sout.jack)
1480                         break;
1481                 s = seprint(s, e, " â†’ ");
1482         }
1483         s = seprint(s, e, "\n");
1484
1485         s = seprint(s, e, "inpath ");
1486         for(w=ctlr->sin.jack; w != nil; w = w->path){
1487                 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1488                         (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1489                 if(w == ctlr->sin.conv)
1490                         break;
1491                 s = seprint(s, e, " â†’ ");
1492         }
1493         s = seprint(s, e, "\n");
1494
1495         return s - (char*)a;
1496 }
1497
1498
1499 static int
1500 hdastart(Ctlr *ctlr)
1501 {
1502         static int cmdbufsize[] = { 2, 16, 256, 2048 };
1503         int n, size;
1504         uint cap;
1505         
1506         /* reset controller */
1507         csr32(ctlr, Gctl) &= ~Rst;
1508         waitup32(ctlr, Gctl, Rst, 0);
1509         microdelay(Codecdelay);
1510         csr32(ctlr, Gctl) |= Rst;
1511         if(waitup32(ctlr, Gctl, Rst, Rst) && 
1512             waitup32(ctlr, Gctl, Rst, Rst)){
1513                 print("#A%d: hda failed to reset\n", ctlr->no);
1514                 return -1;
1515         }
1516         microdelay(Codecdelay);
1517
1518         ctlr->codecmask = csr16(ctlr, Statests);
1519         if(ctlr->codecmask == 0){
1520                 print("#A%d: hda no codecs\n", ctlr->no);
1521                 return -1;
1522         }
1523
1524         cap = csr16(ctlr, Gcap);
1525         ctlr->bss = (cap>>3) & 0x1F;
1526         ctlr->iss = (cap>>8) & 0xF;
1527         ctlr->oss = (cap>>12) & 0xF;
1528
1529         csr8(ctlr, Corbctl) = 0;
1530         waitup8(ctlr, Corbctl, Corbdma, 0);
1531
1532         csr8(ctlr, Rirbctl) = 0;
1533         waitup8(ctlr, Rirbctl, Rirbdma, 0);
1534
1535         /* alloc command buffers */
1536         size = csr8(ctlr, Corbsz);
1537         n = cmdbufsize[size & 3];
1538         ctlr->corb = xspanalloc(n * 4, 128, 0);
1539         memset(ctlr->corb, 0, n * 4);
1540         ctlr->corbsize = n;
1541
1542         size = csr8(ctlr, Rirbsz);
1543         n = cmdbufsize[size & 3];
1544         ctlr->rirb = xspanalloc(n * 8, 128, 0);
1545         memset(ctlr->rirb, 0, n * 8);
1546         ctlr->rirbsize = n;
1547
1548         /* setup controller  */
1549         csr32(ctlr, Dplbase) = 0;
1550         csr32(ctlr, Dpubase) = 0;
1551         csr16(ctlr, Statests) = csr16(ctlr, Statests);
1552         csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1553         
1554         /* setup CORB */
1555         csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1556         csr32(ctlr, Corbubase) = 0;
1557         csr16(ctlr, Corbwp) = 0;
1558         csr16(ctlr, Corbrp) = Corbptrrst;
1559         waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1560         csr16(ctlr, Corbrp) = 0;
1561         waitup16(ctlr, Corbrp, Corbptrrst, 0);
1562         csr8(ctlr, Corbctl) = Corbdma;
1563         waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1564         
1565         /* setup RIRB */
1566         csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1567         csr32(ctlr, Rirbubase) = 0;
1568         csr16(ctlr, Rirbwp) = Rirbptrrst;
1569         csr8(ctlr, Rirbctl) = Rirbdma;
1570         waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1571         
1572         /* enable interrupts */
1573         csr32(ctlr, Intctl) |= Gie | Cie;
1574         
1575         return 0;
1576 }
1577
1578 static Pcidev*
1579 hdamatch(Pcidev *p)
1580 {
1581         while(p = pcimatch(p, 0, 0))
1582                 switch((p->vid << 16) | p->did){
1583                 case (0x8086 << 16) | 0x2668:   /* Intel ICH6 (untested) */
1584                 case (0x8086 << 16) | 0x27d8:   /* Intel ICH7 */
1585                 case (0x8086 << 16) | 0x269a:   /* Intel ESB2 (untested) */
1586                 case (0x8086 << 16) | 0x284b:   /* Intel ICH8 */
1587                 case (0x8086 << 16) | 0x293f:   /* Intel ICH9 (untested) */
1588                 case (0x8086 << 16) | 0x293e:   /* Intel P35 (untested) */
1589                 case (0x8086 << 16) | 0x811b:   /* Intel SCH (Poulsbo) */
1590                 case (0x8086 << 16) | 0x080a:   /* Intel SCH (Oaktrail) */
1591                 case (0x8086 << 16) | 0x1c20:   /* Intel PCH */
1592                 case (0x8086 << 16) | 0x1e20:   /* Intel (Thinkpad x230t) */
1593
1594                 case (0x10de << 16) | 0x026c:   /* NVidia MCP51 (untested) */
1595                 case (0x10de << 16) | 0x0371:   /* NVidia MCP55 (untested) */
1596                 case (0x10de << 16) | 0x03e4:   /* NVidia MCP61 (untested) */
1597                 case (0x10de << 16) | 0x03f0:   /* NVidia MCP61A (untested) */
1598                 case (0x10de << 16) | 0x044a:   /* NVidia MCP65 (untested) */
1599                 case (0x10de << 16) | 0x055c:   /* NVidia MCP67 (untested) */
1600
1601                 case (0x1002 << 16) | 0x437b:   /* ATI SB450 (untested) */
1602                 case (0x1002 << 16) | 0x4383:   /* ATI SB600 */
1603                 case (0x1002 << 16) | 0x7919:   /* ATI HDMI */
1604
1605                 case (0x1106 << 16) | 0x3288:   /* VIA (untested) */
1606                 case (0x1039 << 16) | 0x7502:   /* SIS (untested) */
1607                 case (0x10b9 << 16) | 0x5461:   /* ULI (untested) */
1608                         return p;
1609                 }
1610         return nil;
1611 }
1612
1613 static long
1614 hdacmdread(Chan *, void *a, long n, vlong)
1615 {
1616         Ctlr *ctlr;
1617         
1618         ctlr = lastcard;
1619         if(ctlr == nil)
1620                 error(Enodev);
1621         if(n & 7)
1622                 error(Ebadarg);
1623         return qread(ctlr->q, a, n);
1624 }
1625
1626 static long
1627 hdacmdwrite(Chan *, void *a, long n, vlong)
1628 {
1629         Ctlr *ctlr;
1630         ulong *lp;
1631         int i;
1632         uint w[2];
1633         
1634         ctlr = lastcard;
1635         if(ctlr == nil)
1636                 error(Enodev);
1637         if(n & 3)
1638                 error(Ebadarg);
1639         lp = a;
1640         qlock(ctlr);
1641         for(i=0; i<n/4; i++){
1642                 if(hdacmd(ctlr, lp[i], w) <= 0){
1643                         w[0] = 0;
1644                         w[1] = ~0;
1645                 }
1646                 qproduce(ctlr->q, w, sizeof(w));
1647         }
1648         qunlock(ctlr);
1649         return n;
1650 }
1651
1652 static int
1653 hdareset(Audio *adev)
1654 {
1655         static Ctlr *cards = nil;
1656         int irq, tbdf, best, cad;
1657         Ctlr *ctlr;
1658         Pcidev *p;
1659
1660         /* make a list of all cards if not already done */
1661         if(cards == nil){
1662                 p = nil;
1663                 while(p = hdamatch(p)){
1664                         ctlr = mallocz(sizeof(Ctlr), 1);
1665                         if(ctlr == nil){
1666                                 print("hda: can't allocate memory\n");
1667                                 return -1;
1668                         }
1669                         ctlr->pcidev = p;
1670                         ctlr->next = cards;
1671                         cards = ctlr;
1672                 }
1673         }
1674
1675         /* pick a card from the list */
1676         for(ctlr = cards; ctlr; ctlr = ctlr->next){
1677                 if(p = ctlr->pcidev){
1678                         ctlr->pcidev = nil;
1679                         goto Found;
1680                 }
1681         }
1682         return -1;
1683
1684 Found:
1685         adev->ctlr = ctlr;
1686         ctlr->adev = adev;
1687
1688         irq = p->intl;
1689         tbdf = p->tbdf;
1690
1691         if(p->vid == 0x10de){
1692                 /* magic for NVidia */
1693                 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1694         }
1695         if(p->vid == 0x10b9){
1696                 /* magic for ULI */
1697                 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1698                 pcicfgw32(p, PciBAR1, 0);
1699         }
1700         if(p->vid == 0x8086){
1701                 /* magic for Intel */
1702                 switch(p->did){
1703                 case 0x1c20:    /* PCH */
1704                 case 0x811b:    /* SCH */
1705                 case 0x080a:
1706                         pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1707                 }
1708         }
1709         if(p->vid == 0x1002){
1710                 /* magic for ATI */
1711                 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1712         } else {
1713                 /* TCSEL */
1714                 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1715         }
1716
1717         pcisetbme(p);
1718         pcisetpms(p, 0);
1719
1720         ctlr->no = adev->ctlrno;
1721         ctlr->size = p->mem[0].size;
1722         ctlr->q = qopen(256, 0, 0, 0);
1723         ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1724         if(ctlr->mem == nil){
1725                 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1726                 return -1;
1727         }
1728         print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1729
1730         if(hdastart(ctlr) < 0){
1731                 print("#A%d: unable to start hda\n", ctlr->no);
1732                 return -1;
1733         }
1734
1735         /* iss + oss + bss */
1736         if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1737                 print("#A%d: output streamalloc failed\n", ctlr->no);
1738         if(ctlr->iss > 0){
1739                 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1740                         print("#A%d: input streamalloc failed\n", ctlr->no);
1741         }
1742         else if(ctlr->bss > 0){
1743                 if(ctlr->oss > 0){
1744                         if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1745                                 print("#A%d: input streamalloc failed\n", ctlr->no);
1746                 } else if(ctlr->bss > 1) {
1747                         if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1748                                 print("#A%d: input streamalloc failed\n", ctlr->no);
1749                 }
1750         }
1751
1752         if(enumdev(ctlr) < 0){
1753                 print("#A%d: no audio codecs found\n", ctlr->no);
1754                 return -1;
1755         }
1756
1757         best = bestpin(ctlr, &cad, scoreout);
1758         if(best < 0)
1759                 print("#A%d: no output pins found\n", ctlr->no);
1760         else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad) < 0)
1761                 print("#A%d: error connecting output pin\n", ctlr->no);
1762
1763         best = bestpin(ctlr, &cad, scorein);
1764         if(best < 0)
1765                 print("#A%d: no input pins found\n", ctlr->no);
1766         else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad) < 0)
1767                 print("#A%d: error connecting input pin\n", ctlr->no);
1768
1769         adev->read = hdaread;
1770         adev->write = hdawrite;
1771         adev->close = hdaclose;
1772         adev->buffered = hdabuffered;
1773         adev->volread = hdavolread;
1774         adev->volwrite = hdavolwrite;
1775         adev->status = hdastatus;
1776         adev->ctl = hdactl;
1777         
1778         intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1779         lastcard = ctlr;
1780         addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1781         
1782         return 0;
1783 }
1784
1785 void
1786 audiohdalink(void)
1787 {
1788         addaudiocard("hda", hdareset);
1789 }
1790