]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/audiohda.c
b706c1834e921fcaad24413e6ab746f7876a2746
[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 static uint
572 getinamprange(Widget *w)
573 {
574         uint r;
575
576         if((w->cap & Winampcap) == 0)
577                 return 0;
578         if((w->cap & Wampovrcap) == 0)
579                 r = cmd(w->fg->id, Getparm, Inampcap);
580         else
581                 r = cmd(w->id, Getparm, Inampcap);
582         return (r >> 8) & 0x7f;
583 }
584
585 static void
586 getinamp(Widget *w, int vol[2])
587 {
588         vol[0] = vol[1] = 0;
589         if((w->cap & Winampcap) == 0)
590                 return;
591         vol[0] = cmd(w->id, Getamp, Agetin | Agetleft) & Againmask;
592         vol[1] = cmd(w->id, Getamp, Agetin | Agetright) & Againmask;
593 }
594
595 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
596 static void
597 setinamp(Widget *w, Widget *in, int mute, int *vol)
598 {
599         uint q, r, i, j;
600         uint zerodb;
601
602         if((w->cap & Winampcap) == 0)
603                 return;
604         if((w->cap & Wampovrcap) == 0)
605                 r = cmd(w->fg->id, Getparm, Inampcap);
606         else
607                 r = cmd(w->id, Getparm, Inampcap);
608         zerodb = r & 0x7f;
609         
610         for(i=0; i<2; i++){
611                 q = Asetin | (i == 0 ? Asetleft : Asetright);
612                 if(mute)
613                         q |= Asetmute;
614                 else if(vol == nil)
615                         q |= zerodb << Again;
616                 else
617                         q |= vol[i] << Again;
618                 for(j=0; j<w->nlist; j++){
619                         if(in == nil || w->list[j] == in)
620                                 cmd(w->id, Setamp, q | (j << Asetidx));
621                 }
622         }
623 }
624
625 static Widget *
626 findpath(Widget *jack, int type, char *route)
627 {
628         Widget *q[Maxwidgets];
629         uint l, r, i;
630         Widget *w, *to;
631         Fungroup *fg;
632
633         fg = jack->fg;
634
635         l = r = 0;
636         for(w=fg->first; w != nil; w = w->next)
637                 w->link = nil;
638
639         if(route != nil && *route != 0){
640                 w = jack;
641                 while(*route++ == ','){
642                         i = strtoul(route, &route, 0);
643                         if(i >= Maxwidgets)
644                                 return nil;
645                         to = fg->codec->widgets[i];
646                         if(to == nil || to->fg != fg || to->link != nil)
647                                 return nil;
648                         if(type == Waout)
649                                 to->link = w;
650                         else
651                                 w->link = to;
652                         w = to;
653                 }
654                 if(w == jack || w->type != type)
655                         w = nil;
656                 return w;
657         }
658
659         if(type == Waout){
660                 q[r++] = jack;
661                 jack->link = jack;
662         } else {
663                 for(w=fg->first; w != nil; w = w->next)
664                         if(w->type == type){
665                                 q[r++] = w;
666                                 w->link = w;
667                         }
668         }
669
670         while(l < r){
671                 w = q[l++];
672                 if(type == Waout){
673                         if(w->type == type)
674                                 return w;
675                 } else if(w == jack){
676                         for(w = jack->link; w != nil; w = w->link)
677                                 if(w->type == type)
678                                         return w;
679                         break;
680                 }
681                 for(i=0; i<w->nlist; i++){
682                         to = w->list[i];
683                         if(to == nil || to->link)
684                                 continue;
685                         to->link = w;
686                         q[r++] = to;
687                 }
688         }
689
690         return nil;
691 }
692
693 static void
694 disconnectpath(Widget *from, Widget *to)
695 {
696         Widget *next;
697
698         for(; from != nil && from != to; from = next){
699                 next = from->path;
700                 from->path = nil;
701                 setoutamp(from, 1, nil);
702                 if(next != nil)
703                         setinamp(next, from, 1, nil);
704         }
705         setoutamp(to, 1, nil);
706 }
707
708 static void
709 muteall(Ctlr *ctlr)
710 {
711         Fungroup *fg;
712         Widget *w;
713         int i;
714
715         for(i=0; i<Maxcodecs; i++){
716                 if(ctlr->codec[i] == nil)
717                         continue;
718                 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
719                         for(w=fg->first; w != nil; w=w->next){
720                                 setinamp(w, nil, 1, nil);
721                                 setoutamp(w, 1, nil);
722                                 switch(w->type){
723                                 case Wain:
724                                 case Waout:
725                                         cmd(w->id, Setstream, 0);
726                                         break;
727                                 case Wpin:
728                                         cmd(w->id, Setpinctl, 0);
729                                         break;
730                                 }
731                         }
732                 }
733         }
734 }
735
736 static void
737 connectpath(Widget *from, Widget *to)
738 {
739         Widget *next;
740         uint i;
741
742         for(; from != nil && from != to; from = next){
743                 next = from->link;
744                 from->path = next;
745                 setoutamp(from, 0, nil);
746                 if(next != nil){
747                         setinamp(next, from, 0, nil);
748                         for(i=0; i < next->nlist; i++){
749                                 if(next->list[i] == from){
750                                         cmd(next->id, Setconn, i);      
751                                         break;
752                                 }
753                         }
754                 }
755         }
756         setoutamp(to, 0, nil);
757 }
758
759 static void
760 addconn(Widget *w, uint nid)
761 {
762         Widget *src;
763
764         src = nil;
765         if(nid < Maxwidgets)
766                 src = w->fg->codec->widgets[nid];
767         if(src == nil || (src->fg != w->fg)){
768                 print("hda: invalid connection %d:%s[%d] -> %d\n",
769                         w->id.nid, widtype[w->type & 7], w->nlist, nid);
770                 src = nil;
771         }
772         if((w->nlist % 16) == 0){
773                 void *p;
774
775                 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
776                         print("hda: no memory for Widgetlist\n");
777                         return;
778                 }
779                 w->list = p;
780         }
781         w->list[w->nlist++] = src;
782 }
783
784 static void
785 enumconns(Widget *w)
786 {
787         uint r, f, b, m, i, n, x, y;
788
789         if((w->cap & Wconncap) == 0)
790                 return;
791
792         r = cmd(w->id, Getparm, Connlistlen);
793         n = r & 0x7f;
794         b = (r & 0x80) ? 16 : 8;
795         m = (1<<b)-1;
796         f = (32/b)-1;
797         x = 0;
798         for(i=0; i<n; i++){
799                 if(i & f)
800                         r >>= b;
801                 else
802                         r = cmd(w->id, Getconnlist, i);
803                 y = r & (m>>1);
804                 if(i && (r & m) != y)
805                         while(++x < y)
806                                 addconn(w, x);
807                 addconn(w, y);
808                 x = y;
809         }
810 }
811
812 static void
813 enumwidget(Widget *w)
814 {
815         w->cap = cmd(w->id, Getparm, Widgetcap);
816         w->type = (w->cap >> 20) & 0x7;
817         if(w->cap & Wpwrcap){
818                 cmd(w->id, Setpower, 0);
819                 delay(10);
820         }       
821         switch(w->type){
822         case Wpin:
823                 w->pin = cmd(w->id, Getdefault, 0);
824                 w->pincap = cmd(w->id, Getparm, Pincap);
825                 if(w->pincap & Peapd)
826                         cmd(w->id, Seteapd, Eapdenable);
827                 break;
828         }
829 }
830
831 static Fungroup *
832 enumfungroup(Codec *codec, Id id)
833 {
834         Fungroup *fg;
835         Widget *w, **tail;
836         uint i, r, n, base;
837
838         r = cmd(id, Getparm, Fungrtype) & 0x7f;
839         if(r != Graudio){
840                 cmd(id, Setpower, 3);   /* turn off */
841                 return nil;
842         }
843
844         /* open eyes */
845         cmd(id, Setpower, 0);
846         delay(10);
847
848         r = cmd(id, Getparm, Subnodecnt);
849         n = r & 0xff;
850         base = (r >> 16) & 0xff;
851         if(base >= Maxwidgets){
852                 print("hda: enumfungroup: base %d out of range\n", base);
853                 return nil;
854         }
855         if(base+n > Maxwidgets){
856                 print("hda: enumfungroup: widgets %d - %d out of range\n", base, base+n);
857                 n = Maxwidgets - base;
858         }
859
860         fg = mallocz(sizeof *fg, 1);
861         if(fg == nil){
862 Nomem:
863                 print("hda: enumfungroup: out of memory\n");
864                 return nil;
865         }
866         fg->codec = codec;
867         fg->id = id;
868         fg->type = r;
869
870         tail = &fg->first;
871         for(i=0; i<n; i++){
872                 if(codec->widgets[base + i] != nil){
873                         print("hda: enumfungroup: duplicate widget %d\n", base + i);
874                         continue;
875                 }
876                 w = mallocz(sizeof(Widget), 1);
877                 if(w == nil){
878                         while(w = fg->first){
879                                 fg->first = w->next;
880                                 codec->widgets[w->id.nid] = nil;
881                                 free(w);
882                         }
883                         free(fg);
884                         goto Nomem;
885                 }
886                 w->id = newnid(id, base + i);
887                 w->fg = fg;
888                 *tail = w;
889                 tail = &w->next;
890                 codec->widgets[w->id.nid] = w;
891         }
892
893         for(i=0; i<n; i++)
894                 enumwidget(codec->widgets[base + i]);
895         for(i=0; i<n; i++)
896                 enumconns(codec->widgets[base + i]);
897
898         return fg;
899 }
900
901 static int
902 enumcodec(Codec *codec, Id id)
903 {
904         Fungroup *fg;
905         uint i, r, n, base;
906         uint vid, rid;
907         
908         if(cmderr(id, Getparm, Vendorid, &vid) < 0)
909                 return -1;
910         if(cmderr(id, Getparm, Revid, &rid) < 0)
911                 return -1;
912         
913         codec->id = id;
914         codec->vid = vid;
915         codec->rid = rid;
916
917         r = cmd(id, Getparm, Subnodecnt);
918         n = r & 0xff;
919         base = (r >> 16) & 0xff;
920
921         for(i=0; i<n; i++){
922                 fg = enumfungroup(codec, newnid(id, base + i));
923                 if(fg == nil)
924                         continue;
925                 fg->next = codec->fgroup;
926                 codec->fgroup = fg;
927         }
928         if(codec->fgroup == nil)
929                 return -1;
930
931         print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
932                 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
933
934         return 0;
935 }
936
937 static int
938 enumdev(Ctlr *ctlr)
939 {
940         Codec *codec;
941         int ret;
942         Id id;
943         int i;
944
945         ret = -1;
946         id.ctlr = ctlr;
947         id.nid = 0;
948         for(i=0; i<Maxcodecs; i++){
949                 if(((1<<i) & ctlr->codecmask) == 0)
950                         continue;
951                 codec = mallocz(sizeof(Codec), 1);
952                 if(codec == nil){
953                         print("hda: no memory for Codec\n");
954                         break;
955                 }
956                 id.codec = i;
957                 ctlr->codec[i] = codec;
958                 if(enumcodec(codec, id) < 0){
959                         ctlr->codec[i] = nil;
960                         free(codec);
961                         continue;
962                 }
963                 ret++;
964         }
965         return ret;
966 }
967
968 static int
969 connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad, char *route)
970 {
971         Widget *jack, *conv;
972
973         if(s->atag == 0)
974                 return -1;
975         if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
976                 return -1;
977         jack = ctlr->codec[cad]->widgets[pin];
978         if(jack == nil)
979                 return -1;
980         if(jack->type != Wpin)
981                 return -1;
982
983         conv = findpath(jack, type, route);
984         if(conv == nil)
985                 return -1;
986
987         if(s->conv != nil && s->jack != nil){
988                 if(s->conv->type == Waout)
989                         disconnectpath(s->conv, s->jack);
990                 else
991                         disconnectpath(s->jack, s->conv);
992                 cmd(s->conv->id, Setstream, 0);
993                 cmd(s->jack->id, Setpinctl, 0);
994         }
995
996         if(type == Waout){
997                 connectpath(conv, jack);
998                 cmd(jack->id, Setpinctl, Pinctlout);
999         } else {
1000                 connectpath(jack, conv);
1001                 cmd(jack->id, Setpinctl, Pinctlin);
1002         }
1003
1004         cmd(conv->id, Setconvfmt, s->afmt);
1005         cmd(conv->id, Setstream, (s->atag << 4) | 0);
1006         cmd(conv->id, Setchancnt, 1);
1007
1008         s->conv = conv;
1009         s->jack = jack;
1010         s->pin = pin;
1011         s->cad = cad;
1012
1013         return 0;
1014 }
1015
1016 static int
1017 scoreout(Widget *w)
1018 {
1019         int score;
1020         uint r;
1021
1022         if((w->pincap & Pout) == 0)
1023                 return -1;
1024         if(w->id.ctlr->sin.jack == w)
1025                 return -1;
1026
1027         score = 0;
1028         r = w->pin;
1029         if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1030                 score |= 32;
1031         if(((r >> 12) & 0xf) == 4) /* green */
1032                 score |= 32;
1033         if(((r >> 24) & 0xf) == 1) /* rear */
1034                 score |= 16;
1035         if(((r >> 28) & 0x3) == 0) /* ext */
1036                 score |= 8;
1037         if(((r >> 20) & 0xf) == 2) /* hpout */
1038                 score |= 4;
1039         if(((r >> 20) & 0xf) == 0) /* lineout */
1040                 score |= 4;
1041         return score;
1042 }
1043
1044 static int
1045 scorein(Widget *w)
1046 {
1047         int score;
1048         uint r;
1049
1050         if((w->pincap & Pin) == 0)
1051                 return -1;
1052         if(w->id.ctlr->sout.jack == w)
1053                 return -1;
1054
1055         score = 0;
1056         r = w->pin;
1057         if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1058                 score |= 4;
1059         return score;
1060 }
1061
1062 static int
1063 bestpin(Ctlr *ctlr, int *pcad, int (*fscore)(Widget *))
1064 {
1065         Fungroup *fg;
1066         Widget *w;
1067         int best, pin, score;
1068         int i;
1069
1070         pin = -1;
1071         best = -1;
1072         for(i=0; i<Maxcodecs; i++){
1073                 if(ctlr->codec[i] == nil)
1074                         continue;
1075                 for(fg=ctlr->codec[i]->fgroup; fg != nil; fg=fg->next){
1076                         for(w=fg->first; w != nil; w=w->next){
1077                                 if(w->type != Wpin)
1078                                         continue;
1079                                 score = (*fscore)(w);
1080                                 if(score >= 0 && score >= best){
1081                                         best = score;
1082                                         pin = w->id.nid;
1083                                         *pcad = i;
1084                                 }
1085                         }
1086                 }
1087         }
1088         return pin;
1089 }
1090
1091 static long
1092 buffered(Ring *r)
1093 {
1094         ulong ri, wi;
1095
1096         ri = r->ri;
1097         wi = r->wi;
1098         if(wi >= ri)
1099                 return wi - ri;
1100         else
1101                 return r->nbuf - (ri - wi);
1102 }
1103
1104 static long
1105 available(Ring *r)
1106 {
1107         long m;
1108
1109         m = (r->nbuf - BytesPerSample) - buffered(r);
1110         if(m < 0)
1111                 m = 0;
1112         return m;
1113 }
1114
1115 static long
1116 readring(Ring *r, uchar *p, long n)
1117 {
1118         long n0, m;
1119
1120         n0 = n;
1121         while(n > 0){
1122                 if((m = buffered(r)) <= 0)
1123                         break;
1124                 if(m > n)
1125                         m = n;
1126                 if(p){
1127                         if(r->ri + m > r->nbuf)
1128                                 m = r->nbuf - r->ri;
1129                         memmove(p, r->buf + r->ri, m);
1130                         p += m;
1131                 }
1132                 r->ri = (r->ri + m) % r->nbuf;
1133                 n -= m;
1134         }
1135         return n0 - n;
1136 }
1137
1138 static long
1139 writering(Ring *r, uchar *p, long n)
1140 {
1141         long n0, m;
1142
1143         n0 = n;
1144         while(n > 0){
1145                 if((m = available(r)) <= 0)
1146                         break;
1147                 if(m > n)
1148                         m = n;
1149                 if(p){
1150                         if(r->wi + m > r->nbuf)
1151                                 m = r->nbuf - r->wi;
1152                         memmove(r->buf + r->wi, p, m);
1153                         p += m;
1154                 }
1155                 r->wi = (r->wi + m) % r->nbuf;
1156                 n -= m;
1157         }
1158         return n0 - n;
1159 }
1160
1161 static int
1162 streamalloc(Ctlr *ctlr, Stream *s, int num)
1163 {
1164         Ring *r;
1165         int i;
1166
1167         r = &s->ring;
1168         r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
1169         s->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
1170         if(r->buf == nil || s->blds == nil){
1171                 print("hda: no memory for stream\n");
1172                 return -1;
1173         }
1174         for(i=0; i<Nblocks; i++){
1175                 s->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
1176                 s->blds[i].addrhi = 0;
1177                 s->blds[i].len = Blocksize;
1178                 s->blds[i].flags = 0x01;        /* interrupt on completion */
1179         }
1180
1181         s->sdnum = num;
1182         s->sdctl = Sdctl0 + s->sdnum*0x20;
1183         s->sdintr = 1<<s->sdnum;
1184         s->atag = s->sdnum+1;
1185         s->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
1186         s->active = 0;
1187
1188         /* perform reset */
1189         csr8(ctlr, s->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
1190         csr8(ctlr, s->sdctl) |= Srst;
1191         microdelay(Codecdelay);
1192         waitup8(ctlr, s->sdctl, Srst, Srst);
1193         csr8(ctlr, s->sdctl) &= ~Srst;
1194         microdelay(Codecdelay);
1195         waitup8(ctlr, s->sdctl, Srst, 0);
1196
1197         /* set stream number */
1198         csr32(ctlr, s->sdctl) = (s->atag << Stagbit) |
1199                 (csr32(ctlr, s->sdctl) & ~(0xF << Stagbit));
1200
1201         /* set stream format */
1202         csr16(ctlr, Sdfmt+s->sdctl) = s->afmt;
1203
1204         /* program stream DMA & parms */
1205         csr32(ctlr, Sdbdplo+s->sdctl) = PADDR(s->blds);
1206         csr32(ctlr, Sdbdphi+s->sdctl) = 0;
1207         csr32(ctlr, Sdcbl+s->sdctl) = r->nbuf;
1208         csr16(ctlr, Sdlvi+s->sdctl) = (Nblocks - 1) & 0xff;
1209
1210         /* mask out ints */
1211         csr8(ctlr, Sdsts+s->sdctl) = Scompl | Sfifoerr | Sdescerr;
1212
1213         /* enable global intrs for this stream */
1214         csr32(ctlr, Intctl) |= s->sdintr;
1215         csr8(ctlr, s->sdctl) |= Scie | Seie | Sdie;
1216
1217         return 0;
1218 }
1219
1220 static void
1221 streamstart(Ctlr *ctlr, Stream *s)
1222 {
1223         s->active = 1;
1224         csr8(ctlr, s->sdctl) |= Srun;
1225         waitup8(ctlr, s->sdctl, Srun, Srun);
1226 }
1227
1228 static void
1229 streamstop(Ctlr *ctlr, Stream *s)
1230 {
1231         csr8(ctlr, s->sdctl) &= ~Srun;
1232         waitup8(ctlr, s->sdctl, Srun, 0);
1233         s->active = 0;
1234 }
1235
1236 static uint
1237 streampos(Ctlr *ctlr, Stream *s)
1238 {
1239         uint p;
1240
1241         p = csr32(ctlr, Sdlpib+s->sdctl);
1242         if(p >= s->ring.nbuf)
1243                 p = 0;
1244         return p;
1245 }
1246
1247 static long
1248 hdactl(Audio *adev, void *va, long n, vlong)
1249 {
1250         char *p, *e, *x, *route, *tok[4];
1251         int ntok;
1252         Ctlr *ctlr;
1253         uint pin, cad;
1254         
1255         ctlr = adev->ctlr;
1256         p = va;
1257         e = p + n;
1258         
1259         for(; p < e; p = x){
1260                 route = nil;
1261                 if(x = strchr(p, '\n'))
1262                         *x++ = 0;
1263                 else
1264                         x = e;
1265                 ntok = tokenize(p, tok, 4);
1266                 if(ntok <= 0)
1267                         continue;
1268                 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1269                         cad = ctlr->sout.cad;
1270                         pin = strtoul(tok[1], &route, 0);
1271                         if(ntok > 2)
1272                                 cad = strtoul(tok[2], 0, 0);
1273                         if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad, route) < 0)
1274                                 error("connectpin failed");
1275                 }else
1276                 if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
1277                         cad = ctlr->sin.cad;
1278                         pin = strtoul(tok[1], &route, 0);
1279                         if(ntok > 2)
1280                                 cad = strtoul(tok[2], 0, 0);
1281                         if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad, route) < 0)
1282                                 error("connectpin failed");
1283                 }else
1284                         error(Ebadctl);
1285         }
1286         return n;
1287 }
1288
1289 static int
1290 inavail(void *arg)
1291 {
1292         Ring *r = arg;
1293         return buffered(r) > 0;
1294 }
1295
1296 static int
1297 outavail(void *arg)
1298 {
1299         Ring *r = arg;
1300         return available(r) > 0;
1301 }
1302
1303 static int
1304 outrate(void *arg)
1305 {
1306         Ctlr *ctlr = arg;
1307         int delay = ctlr->adev->delay*BytesPerSample;
1308         return (delay <= 0) || (buffered(&ctlr->sout.ring) <= delay) || (ctlr->sout.active == 0);
1309 }
1310
1311 static long
1312 hdabuffered(Audio *adev)
1313 {
1314         Ctlr *ctlr;
1315         ctlr = adev->ctlr;
1316         return buffered(&ctlr->sout.ring);
1317 }
1318
1319 static void
1320 hdakick(Ctlr *ctlr)
1321 {
1322         int delay;
1323
1324         if(ctlr->sout.active)
1325                 return;
1326         delay = ctlr->adev->delay*BytesPerSample;
1327         if(buffered(&ctlr->sout.ring) >= delay)
1328                 streamstart(ctlr, &ctlr->sout);
1329 }
1330
1331 static long
1332 hdaread(Audio *adev, void *vp, long n, vlong)
1333 {
1334         uchar *p, *e;
1335         Ctlr *ctlr;
1336         Ring *ring;
1337
1338         p = vp;
1339         e = p + n;
1340         ctlr = adev->ctlr;
1341         ring = &ctlr->sin.ring;
1342         if(ring->buf == nil || ctlr->sin.conv == nil)
1343                 return 0;
1344         while(p < e) {
1345                 if((n = readring(ring, p, e - p)) <= 0){
1346                         if(!ctlr->sin.active)
1347                                 streamstart(ctlr, &ctlr->sin);
1348                         sleep(&ring->r, inavail, ring);
1349                         continue;
1350                 }
1351                 p += n;
1352         }
1353         return p - (uchar*)vp;
1354 }
1355
1356 static long
1357 hdawrite(Audio *adev, void *vp, long n, vlong)
1358 {
1359         uchar *p, *e;
1360         Ctlr *ctlr;
1361         Ring *ring;
1362
1363         p = vp;
1364         e = p + n;
1365         ctlr = adev->ctlr;
1366         ring = &ctlr->sout.ring;
1367         if(ring->buf == nil || ctlr->sout.conv == nil)
1368                 return 0;
1369         while(p < e) {
1370                 if((n = writering(ring, p, e - p)) <= 0){
1371                         hdakick(ctlr);
1372                         sleep(&ring->r, outavail, ring);
1373                         continue;
1374                 }
1375                 p += n;
1376         }
1377         hdakick(ctlr);
1378         while(outrate(ctlr) == 0)
1379                 sleep(&ring->r, outrate, ctlr);
1380         return p - (uchar*)vp;
1381 }
1382
1383 static void
1384 hdaclose(Audio *adev, int mode)
1385 {
1386         Ctlr *ctlr;
1387         Ring *ring;
1388
1389         ctlr = adev->ctlr;
1390         if(mode == OREAD || mode == ORDWR){
1391                 if(ctlr->sin.active)
1392                         streamstop(ctlr, &ctlr->sin);
1393         }
1394         if(mode == OWRITE || mode == ORDWR){
1395                 ring = &ctlr->sout.ring;
1396                 while(ring->wi % Blocksize)
1397                         if(writering(ring, (uchar*)"", 1) <= 0)
1398                                 break;
1399         }
1400 }
1401
1402 enum {
1403         Vmaster,
1404         Vrecord,
1405         Vspeed,
1406         Vdelay,
1407         Nvol,
1408 };
1409
1410 static Volume voltab[] = {
1411         [Vmaster] "master", 0, 0x7f, Stereo, 0,
1412         [Vrecord] "recgain", 0, 0x7f, Stereo, 0,
1413         [Vspeed] "speed", 0, 0, Absolute, 0,
1414         [Vdelay] "delay", 0, 0, Absolute, 0,
1415         0
1416 };
1417
1418 static Widget*
1419 findoutamp(Stream *s)
1420 {
1421         Widget *w;
1422
1423         for(w = s->conv; w != nil; w = w->path){
1424                 if(w->cap & Woutampcap)
1425                         return w;
1426                 if(w == s->jack)
1427                         break;
1428         }
1429         return nil;
1430 }
1431
1432 static Widget*
1433 findinamp(Stream *s)
1434 {
1435         Widget *w, *p, *a;
1436
1437         a = nil;
1438         for(p = nil, w = s->jack; w != nil; p = w, w = w->path){
1439                 w->link = p;    /* for setinamp */
1440                 if(w->cap & Winampcap)
1441                         a = w;
1442                 if(w == s->conv)
1443                         break;
1444         }
1445         return a;
1446 }
1447
1448 static int
1449 hdagetvol(Audio *adev, int x, int a[2])
1450 {
1451         Ctlr *ctlr = adev->ctlr;
1452         Widget *w;
1453
1454         switch(x){
1455         case Vmaster:
1456                 if((w = findoutamp(&ctlr->sout)) != nil)
1457                         getoutamp(w, a);
1458                 break;
1459         case Vrecord:
1460                 if((w = findinamp(&ctlr->sin)) != nil)
1461                         getinamp(w, a);
1462                 break;
1463         case Vspeed:
1464                 a[0] = adev->speed;
1465                 break;
1466         case Vdelay:
1467                 a[0] = adev->delay;
1468                 break;
1469         }
1470         return 0;
1471 }
1472
1473 static int
1474 hdasetvol(Audio *adev, int x, int a[2])
1475 {
1476         Ctlr *ctlr = adev->ctlr;
1477         Widget *w;
1478
1479         switch(x){
1480         case Vmaster:
1481                 if((w = findoutamp(&ctlr->sout)) != nil)
1482                         setoutamp(w, 0, a);
1483                 break;
1484         case Vrecord:
1485                 if((w = findinamp(&ctlr->sin)) != nil)
1486                         setinamp(w, w->link, 0, a);
1487                 break;
1488         case Vspeed:
1489                 adev->speed = a[0];
1490                 break;
1491         case Vdelay:
1492                 if(a[0] < Blocksize/BytesPerSample) {
1493                         adev->delay = Blocksize/BytesPerSample;
1494                 } else if(a[0] > (ctlr->sout.ring.nbuf/BytesPerSample)-1) {
1495                         adev->delay = (ctlr->sout.ring.nbuf/BytesPerSample)-1;
1496                 } else {
1497                         adev->delay = a[0];
1498                 }
1499                 break;
1500         }
1501         return 0;
1502 }
1503
1504 static void
1505 fillvoltab(Ctlr *ctlr, Volume *vt)
1506 {
1507         Widget *w;
1508
1509         memmove(vt, voltab, sizeof(voltab));
1510         if((w = findoutamp(&ctlr->sout)) != nil)
1511                 vt[Vmaster].range = getoutamprange(w);
1512         if((w = findinamp(&ctlr->sin)) != nil)
1513                 vt[Vrecord].range = getinamprange(w);
1514 }
1515
1516 static long
1517 hdavolread(Audio *adev, void *a, long n, vlong)
1518 {
1519         Volume voltab[Nvol+1];
1520         fillvoltab(adev->ctlr, voltab);
1521         return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1522 }
1523
1524 static long
1525 hdavolwrite(Audio *adev, void *a, long n, vlong)
1526 {
1527         Volume voltab[Nvol+1];
1528         fillvoltab(adev->ctlr, voltab);
1529         return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1530 }
1531
1532 static void
1533 hdainterrupt(Ureg *, void *arg)
1534 {
1535         Ctlr *ctlr;
1536         Audio *adev;
1537         Ring *r;
1538         uint sts;
1539
1540         adev = arg;
1541         ctlr = adev->ctlr;
1542         ilock(ctlr);
1543         sts = csr32(ctlr, Intsts);
1544         if(sts & ctlr->sout.sdintr){
1545                 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
1546
1547                 r = &ctlr->sout.ring;
1548                 r->ri = streampos(ctlr, &ctlr->sout);
1549                 if(ctlr->sout.active && buffered(r) < Blocksize){
1550                         streamstop(ctlr, &ctlr->sout);
1551                         r->ri = r->wi = streampos(ctlr, &ctlr->sout);
1552                 }
1553                 wakeup(&r->r);
1554         }
1555         if(sts & ctlr->sin.sdintr){
1556                 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
1557
1558                 r = &ctlr->sin.ring;
1559                 r->wi = streampos(ctlr, &ctlr->sin);
1560                 if(ctlr->sin.active && available(r) < Blocksize){
1561                         streamstop(ctlr, &ctlr->sin);
1562                         r->ri = r->wi = streampos(ctlr, &ctlr->sin);
1563                 }
1564                 wakeup(&r->r);
1565         }
1566         iunlock(ctlr);
1567 }
1568
1569 static long
1570 hdastatus(Audio *adev, void *a, long n, vlong)
1571 {
1572         Ctlr *ctlr = adev->ctlr;
1573         Codec *codec;
1574         Widget *w;
1575         uint r;
1576         int i, j, k;
1577         char *s, *e;
1578         
1579         s = a;
1580         e = s + n;
1581         s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->sout.ring));
1582         for(i=0; i<Maxcodecs; i++){
1583                 if((codec = ctlr->codec[i]) == nil)
1584                         continue;
1585                 s = seprint(s, e, "codec %d pin %d inpin %d\n",
1586                         codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
1587                 for(j=0; j<Maxwidgets; j++){
1588                         if((w = codec->widgets[j]) == nil)
1589                                 continue;
1590                         switch(w->type){
1591                         case Wpin:
1592                                 r = w->pin;
1593                                 s = seprint(s, e, "%s %d %s%s %s %s %s %s %s%s%s",
1594                                         widtype[w->type&7], w->id.nid,
1595                                         (w->pincap & Pin) != 0 ? "in" : "",
1596                                         (w->pincap & Pout) != 0 ? "out" : "",
1597                                         pinport[(r >> 30) & 0x3],
1598                                         pinloc2[(r >> 28) & 0x3],
1599                                         pinloc[(r >> 24) & 0xf],
1600                                         pinfunc[(r >> 20) & 0xf],
1601                                         pincol[(r >> 12) & 0xf],
1602                                         (w->pincap & Phdmi) ? " hdmi" : "",
1603                                         (w->pincap & Peapd) ? " eapd" : ""
1604                                 );
1605                                 break;
1606                         default:
1607                                 s = seprint(s, e, "%s %d %lux",
1608                                         widtype[w->type&7], w->id.nid,
1609                                         (ulong)w->cap);
1610                         }
1611                         if(w->nlist > 0){
1612                                 s = seprint(s, e, " ← ");
1613                                 for(k=0; k<w->nlist; k++){
1614                                         if(k > 0)
1615                                                 s = seprint(s, e, ", ");
1616                                         if(w->list[k] != nil)
1617                                                 s = seprint(s, e, "%s %d", widtype[w->list[k]->type&7], w->list[k]->id.nid);
1618                                 }
1619                         }
1620                         s = seprint(s, e, "\n");
1621                 }
1622         }
1623
1624         if(ctlr->sout.conv != nil && ctlr->sout.jack != nil){
1625                 s = seprint(s, e, "outpath ");
1626                 for(w=ctlr->sout.conv; w != nil; w = w->path){
1627                         s = seprint(s, e, "%s %d", widtype[w->type&7], w->id.nid);
1628                         if(w == ctlr->sout.jack)
1629                                 break;
1630                         s = seprint(s, e, " → ");
1631                 }
1632                 s = seprint(s, e, "\n");
1633                 if((w = findoutamp(&ctlr->sout)) != nil)
1634                         s = seprint(s, e, "outamp %s %d\n", widtype[w->type&7], w->id.nid);
1635         }
1636
1637         if(ctlr->sin.conv != nil && ctlr->sin.jack != nil){
1638                 s = seprint(s, e, "inpath ");
1639                 for(w=ctlr->sin.jack; w != nil; w = w->path){
1640                         s = seprint(s, e, "%s %d", widtype[w->type&7], w->id.nid);
1641                         if(w == ctlr->sin.conv)
1642                                 break;
1643                         s = seprint(s, e, " → ");
1644                 }
1645                 s = seprint(s, e, "\n");
1646                 if((w = findinamp(&ctlr->sin)) != nil)
1647                         s = seprint(s, e, "inamp %s %d\n", widtype[w->type&7], w->id.nid);
1648         }
1649
1650         return s - (char*)a;
1651 }
1652
1653
1654 static int
1655 hdastart(Ctlr *ctlr)
1656 {
1657         static int cmdbufsize[] = { 2, 16, 256, 2048 };
1658         int n, size;
1659         uint cap;
1660         
1661         /* reset controller */
1662         csr32(ctlr, Gctl) &= ~Rst;
1663         waitup32(ctlr, Gctl, Rst, 0);
1664         microdelay(Codecdelay);
1665         csr32(ctlr, Gctl) |= Rst;
1666         if(waitup32(ctlr, Gctl, Rst, Rst) && 
1667             waitup32(ctlr, Gctl, Rst, Rst)){
1668                 print("#A%d: hda failed to reset\n", ctlr->no);
1669                 return -1;
1670         }
1671         microdelay(Codecdelay);
1672
1673         ctlr->codecmask = csr16(ctlr, Statests);
1674         if(ctlr->codecmask == 0){
1675                 print("#A%d: hda no codecs\n", ctlr->no);
1676                 return -1;
1677         }
1678
1679         cap = csr16(ctlr, Gcap);
1680         ctlr->bss = (cap>>3) & 0x1F;
1681         ctlr->iss = (cap>>8) & 0xF;
1682         ctlr->oss = (cap>>12) & 0xF;
1683
1684         csr8(ctlr, Corbctl) = 0;
1685         waitup8(ctlr, Corbctl, Corbdma, 0);
1686
1687         csr8(ctlr, Rirbctl) = 0;
1688         waitup8(ctlr, Rirbctl, Rirbdma, 0);
1689
1690         /* alloc command buffers */
1691         size = csr8(ctlr, Corbsz);
1692         n = cmdbufsize[size & 3];
1693         ctlr->corb = xspanalloc(n * 4, 128, 0);
1694         memset(ctlr->corb, 0, n * 4);
1695         ctlr->corbsize = n;
1696
1697         size = csr8(ctlr, Rirbsz);
1698         n = cmdbufsize[size & 3];
1699         ctlr->rirb = xspanalloc(n * 8, 128, 0);
1700         memset(ctlr->rirb, 0, n * 8);
1701         ctlr->rirbsize = n;
1702
1703         /* setup controller  */
1704         csr32(ctlr, Dplbase) = 0;
1705         csr32(ctlr, Dpubase) = 0;
1706         csr16(ctlr, Statests) = csr16(ctlr, Statests);
1707         csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1708         
1709         /* setup CORB */
1710         csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1711         csr32(ctlr, Corbubase) = 0;
1712         csr16(ctlr, Corbwp) = 0;
1713         csr16(ctlr, Corbrp) = Corbptrrst;
1714         waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1715         csr16(ctlr, Corbrp) = 0;
1716         waitup16(ctlr, Corbrp, Corbptrrst, 0);
1717         csr8(ctlr, Corbctl) = Corbdma;
1718         waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1719         
1720         /* setup RIRB */
1721         csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1722         csr32(ctlr, Rirbubase) = 0;
1723         csr16(ctlr, Rirbwp) = Rirbptrrst;
1724         csr8(ctlr, Rirbctl) = Rirbdma;
1725         waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1726         
1727         /* enable interrupts */
1728         csr32(ctlr, Intctl) |= Gie | Cie;
1729         
1730         return 0;
1731 }
1732
1733 static Pcidev*
1734 hdamatch(Pcidev *p)
1735 {
1736         while(p = pcimatch(p, 0, 0))
1737                 switch((p->vid << 16) | p->did){
1738                 case (0x8086 << 16) | 0x2668:   /* Intel ICH6 (untested) */
1739                 case (0x8086 << 16) | 0x27d8:   /* Intel ICH7 */
1740                 case (0x8086 << 16) | 0x269a:   /* Intel ESB2 (untested) */
1741                 case (0x8086 << 16) | 0x284b:   /* Intel ICH8 */
1742                 case (0x8086 << 16) | 0x293f:   /* Intel ICH9 (untested) */
1743                 case (0x8086 << 16) | 0x293e:   /* Intel P35 (untested) */
1744                 case (0x8086 << 16) | 0x3b56:   /* Intel P55 (Ibex Peak) */
1745                 case (0x8086 << 16) | 0x811b:   /* Intel SCH (Poulsbo) */
1746                 case (0x8086 << 16) | 0x080a:   /* Intel SCH (Oaktrail) */
1747                 case (0x8086 << 16) | 0x1c20:   /* Intel PCH */
1748                 case (0x8086 << 16) | 0x1e20:   /* Intel (Thinkpad x230t) */
1749                 case (0x8086 << 16) | 0x8c20:   /* Intel 8 Series/C220 Series */
1750                 case (0x8086 << 16) | 0x9c20:   /* Intel 8 Series Lynx Point */
1751                 case (0x8086 << 16) | 0x9ca0:   /* Intel Wildcat Point */
1752
1753                 case (0x10de << 16) | 0x026c:   /* NVidia MCP51 (untested) */
1754                 case (0x10de << 16) | 0x0371:   /* NVidia MCP55 (untested) */
1755                 case (0x10de << 16) | 0x03e4:   /* NVidia MCP61 (untested) */
1756                 case (0x10de << 16) | 0x03f0:   /* NVidia MCP61A (untested) */
1757                 case (0x10de << 16) | 0x044a:   /* NVidia MCP65 (untested) */
1758                 case (0x10de << 16) | 0x055c:   /* NVidia MCP67 (untested) */
1759
1760                 case (0x1002 << 16) | 0x437b:   /* ATI SB450 (untested) */
1761                 case (0x1002 << 16) | 0x4383:   /* ATI SB600 */
1762                 case (0x1002 << 16) | 0xaa55:   /* ATI HDMI (8500 series) */
1763                 case (0x1002 << 16) | 0x7919:   /* ATI HDMI */
1764
1765                 case (0x1106 << 16) | 0x3288:   /* VIA (untested) */
1766                 case (0x1039 << 16) | 0x7502:   /* SIS (untested) */
1767                 case (0x10b9 << 16) | 0x5461:   /* ULI (untested) */
1768
1769                 case (0x1022 << 16) | 0x780d:   /* AMD FCH Azalia Controller */
1770
1771                 case (0x15ad << 16) | 0x1977:   /* Vmware */
1772                         return p;
1773                 }
1774         return nil;
1775 }
1776
1777 static long
1778 hdacmdread(Chan *, void *a, long n, vlong)
1779 {
1780         Ctlr *ctlr;
1781         
1782         ctlr = lastcard;
1783         if(ctlr == nil)
1784                 error(Enodev);
1785         if(n & 7)
1786                 error(Ebadarg);
1787         return qread(ctlr->q, a, n);
1788 }
1789
1790 static long
1791 hdacmdwrite(Chan *, void *a, long n, vlong)
1792 {
1793         Ctlr *ctlr;
1794         ulong *lp;
1795         int i;
1796         uint w[2];
1797         
1798         ctlr = lastcard;
1799         if(ctlr == nil)
1800                 error(Enodev);
1801         if(n & 3)
1802                 error(Ebadarg);
1803         lp = a;
1804         qlock(ctlr);
1805         for(i=0; i<n/4; i++){
1806                 if(hdacmd(ctlr, lp[i], w) <= 0){
1807                         w[0] = 0;
1808                         w[1] = ~0;
1809                 }
1810                 qproduce(ctlr->q, w, sizeof(w));
1811         }
1812         qunlock(ctlr);
1813         return n;
1814 }
1815
1816 static int
1817 hdareset(Audio *adev)
1818 {
1819         static Ctlr *cards = nil;
1820         int irq, tbdf, best, cad;
1821         Ctlr *ctlr;
1822         Pcidev *p;
1823
1824         /* make a list of all cards if not already done */
1825         if(cards == nil){
1826                 p = nil;
1827                 while(p = hdamatch(p)){
1828                         ctlr = mallocz(sizeof(Ctlr), 1);
1829                         if(ctlr == nil){
1830                                 print("hda: can't allocate memory\n");
1831                                 return -1;
1832                         }
1833                         ctlr->pcidev = p;
1834                         ctlr->next = cards;
1835                         cards = ctlr;
1836                 }
1837         }
1838
1839         /* pick a card from the list */
1840         for(ctlr = cards; ctlr != nil; ctlr = ctlr->next){
1841                 if(p = ctlr->pcidev){
1842                         ctlr->pcidev = nil;
1843                         goto Found;
1844                 }
1845         }
1846         return -1;
1847
1848 Found:
1849         adev->ctlr = ctlr;
1850         ctlr->adev = adev;
1851
1852         irq = p->intl;
1853         tbdf = p->tbdf;
1854
1855         if(p->vid == 0x10de){
1856                 /* magic for NVidia */
1857                 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1858         }
1859         if(p->vid == 0x10b9){
1860                 /* magic for ULI */
1861                 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1862                 pcicfgw32(p, PciBAR1, 0);
1863         }
1864         if(p->vid == 0x8086){
1865                 /* magic for Intel */
1866                 switch(p->did){
1867                 case 0x1c20:    /* PCH */
1868                 case 0x1e20:
1869                 case 0x811b:    /* SCH */
1870                 case 0x080a:
1871                 case 0x8c20:
1872                 case 0x9c20:
1873                 case 0x9ca0:
1874                         pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1875                 }
1876         }
1877         if(p->vid == 0x1002){
1878                 /* magic for ATI */
1879                 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1880         } else {
1881                 /* TCSEL */
1882                 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1883         }
1884
1885         pcisetbme(p);
1886         pcisetpms(p, 0);
1887
1888         ctlr->no = adev->ctlrno;
1889         ctlr->size = p->mem[0].size;
1890         ctlr->q = qopen(256, 0, 0, 0);
1891         ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1892         if(ctlr->mem == nil){
1893                 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1894                 return -1;
1895         }
1896         print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1897
1898         if(hdastart(ctlr) < 0){
1899                 print("#A%d: unable to start hda\n", ctlr->no);
1900                 return -1;
1901         }
1902
1903         /* iss + oss + bss */
1904         if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1905                 print("#A%d: output streamalloc failed\n", ctlr->no);
1906         if(ctlr->iss > 0){
1907                 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1908                         print("#A%d: input streamalloc failed\n", ctlr->no);
1909         }
1910         else if(ctlr->bss > 0){
1911                 if(ctlr->oss > 0){
1912                         if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1913                                 print("#A%d: input streamalloc failed\n", ctlr->no);
1914                 } else if(ctlr->bss > 1) {
1915                         if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1916                                 print("#A%d: input streamalloc failed\n", ctlr->no);
1917                 }
1918         }
1919
1920         if(enumdev(ctlr) < 0){
1921                 print("#A%d: no audio codecs found\n", ctlr->no);
1922                 return -1;
1923         }
1924         muteall(ctlr);
1925
1926         best = bestpin(ctlr, &cad, scoreout);
1927         if(best < 0)
1928                 print("#A%d: no output pins found\n", ctlr->no);
1929         else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad, nil) < 0)
1930                 print("#A%d: error connecting output pin\n", ctlr->no);
1931
1932         best = bestpin(ctlr, &cad, scorein);
1933         if(best < 0)
1934                 print("#A%d: no input pins found\n", ctlr->no);
1935         else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad, nil) < 0)
1936                 print("#A%d: error connecting input pin\n", ctlr->no);
1937
1938         adev->read = hdaread;
1939         adev->write = hdawrite;
1940         adev->close = hdaclose;
1941         adev->buffered = hdabuffered;
1942         adev->volread = hdavolread;
1943         adev->volwrite = hdavolwrite;
1944         adev->status = hdastatus;
1945         adev->ctl = hdactl;
1946         
1947         intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1948         lastcard = ctlr;
1949         addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1950         
1951         return 0;
1952 }
1953
1954 void
1955 audiohdalink(void)
1956 {
1957         addaudiocard("hda", hdareset);
1958 }
1959