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