changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/pc/audiohda.c

changeset 4350: 1f9d7811d546
parent: 50f453943ae5
child: 56c07c9aab70
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
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 
1752  case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1753  case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1754  case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1755  case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1756  case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1757  case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1758 
1759  case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1760  case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1761  case (0x1002 << 16) | 0xaa55: /* ATI HDMI (8500 series) */
1762  case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1763 
1764  case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1765  case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1766  case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1767 
1768  case (0x15ad << 16) | 0x1977: /* Vmware */
1769  return p;
1770  }
1771  return nil;
1772 }
1773 
1774 static long
1775 hdacmdread(Chan *, void *a, long n, vlong)
1776 {
1777  Ctlr *ctlr;
1778 
1779  ctlr = lastcard;
1780  if(ctlr == nil)
1781  error(Enodev);
1782  if(n & 7)
1783  error(Ebadarg);
1784  return qread(ctlr->q, a, n);
1785 }
1786 
1787 static long
1788 hdacmdwrite(Chan *, void *a, long n, vlong)
1789 {
1790  Ctlr *ctlr;
1791  ulong *lp;
1792  int i;
1793  uint w[2];
1794 
1795  ctlr = lastcard;
1796  if(ctlr == nil)
1797  error(Enodev);
1798  if(n & 3)
1799  error(Ebadarg);
1800  lp = a;
1801  qlock(ctlr);
1802  for(i=0; i<n/4; i++){
1803  if(hdacmd(ctlr, lp[i], w) <= 0){
1804  w[0] = 0;
1805  w[1] = ~0;
1806  }
1807  qproduce(ctlr->q, w, sizeof(w));
1808  }
1809  qunlock(ctlr);
1810  return n;
1811 }
1812 
1813 static int
1814 hdareset(Audio *adev)
1815 {
1816  static Ctlr *cards = nil;
1817  int irq, tbdf, best, cad;
1818  Ctlr *ctlr;
1819  Pcidev *p;
1820 
1821  /* make a list of all cards if not already done */
1822  if(cards == nil){
1823  p = nil;
1824  while(p = hdamatch(p)){
1825  ctlr = mallocz(sizeof(Ctlr), 1);
1826  if(ctlr == nil){
1827  print("hda: can't allocate memory\n");
1828  return -1;
1829  }
1830  ctlr->pcidev = p;
1831  ctlr->next = cards;
1832  cards = ctlr;
1833  }
1834  }
1835 
1836  /* pick a card from the list */
1837  for(ctlr = cards; ctlr != nil; ctlr = ctlr->next){
1838  if(p = ctlr->pcidev){
1839  ctlr->pcidev = nil;
1840  goto Found;
1841  }
1842  }
1843  return -1;
1844 
1845 Found:
1846  adev->ctlr = ctlr;
1847  ctlr->adev = adev;
1848 
1849  irq = p->intl;
1850  tbdf = p->tbdf;
1851 
1852  if(p->vid == 0x10de){
1853  /* magic for NVidia */
1854  pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1855  }
1856  if(p->vid == 0x10b9){
1857  /* magic for ULI */
1858  pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1859  pcicfgw32(p, PciBAR1, 0);
1860  }
1861  if(p->vid == 0x8086){
1862  /* magic for Intel */
1863  switch(p->did){
1864  case 0x1c20: /* PCH */
1865  case 0x1e20:
1866  case 0x811b: /* SCH */
1867  case 0x080a:
1868  case 0x8c20:
1869  case 0x9c20:
1870  pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1871  }
1872  }
1873  if(p->vid == 0x1002){
1874  /* magic for ATI */
1875  pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1876  } else {
1877  /* TCSEL */
1878  pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1879  }
1880 
1881  pcisetbme(p);
1882  pcisetpms(p, 0);
1883 
1884  ctlr->no = adev->ctlrno;
1885  ctlr->size = p->mem[0].size;
1886  ctlr->q = qopen(256, 0, 0, 0);
1887  ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1888  if(ctlr->mem == nil){
1889  print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1890  return -1;
1891  }
1892  print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1893 
1894  if(hdastart(ctlr) < 0){
1895  print("#A%d: unable to start hda\n", ctlr->no);
1896  return -1;
1897  }
1898 
1899  /* iss + oss + bss */
1900  if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1901  print("#A%d: output streamalloc failed\n", ctlr->no);
1902  if(ctlr->iss > 0){
1903  if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1904  print("#A%d: input streamalloc failed\n", ctlr->no);
1905  }
1906  else if(ctlr->bss > 0){
1907  if(ctlr->oss > 0){
1908  if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1909  print("#A%d: input streamalloc failed\n", ctlr->no);
1910  } else if(ctlr->bss > 1) {
1911  if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1912  print("#A%d: input streamalloc failed\n", ctlr->no);
1913  }
1914  }
1915 
1916  if(enumdev(ctlr) < 0){
1917  print("#A%d: no audio codecs found\n", ctlr->no);
1918  return -1;
1919  }
1920  muteall(ctlr);
1921 
1922  best = bestpin(ctlr, &cad, scoreout);
1923  if(best < 0)
1924  print("#A%d: no output pins found\n", ctlr->no);
1925  else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad, nil) < 0)
1926  print("#A%d: error connecting output pin\n", ctlr->no);
1927 
1928  best = bestpin(ctlr, &cad, scorein);
1929  if(best < 0)
1930  print("#A%d: no input pins found\n", ctlr->no);
1931  else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad, nil) < 0)
1932  print("#A%d: error connecting input pin\n", ctlr->no);
1933 
1934  adev->read = hdaread;
1935  adev->write = hdawrite;
1936  adev->close = hdaclose;
1937  adev->buffered = hdabuffered;
1938  adev->volread = hdavolread;
1939  adev->volwrite = hdavolwrite;
1940  adev->status = hdastatus;
1941  adev->ctl = hdactl;
1942 
1943  intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1944  lastcard = ctlr;
1945  addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1946 
1947  return 0;
1948 }
1949 
1950 void
1951 audiohdalink(void)
1952 {
1953  addaudiocard("hda", hdareset);
1954 }
1955