2 #include "../port/lib.h"
7 #include "../port/pci.h"
8 #include "../port/error.h"
9 #include "../port/audioif.h"
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;
18 typedef struct Widget Widget;
19 typedef struct Codec Codec;
20 typedef struct Fungroup Fungroup;
21 typedef struct Pinprop Pinprop;
68 /* Warning: Sdctl is 24bit register */
100 Bufsize = 64 * 1024 * 4,
102 Blocksize = Bufsize / Nblocks,
105 Maxrirbwait = 1000, /* microseconds */
106 Maxwaitup = 500, /* microseconds */
107 Codecdelay = 1000, /* microseconds */
111 /* 12-bit cmd + 8-bit payload */
174 Getunsolresp = 0xf08,
175 Setunsolresp = 0x708,
193 /* 4-bit cmd + 16-bit payload */
248 Widget *conv; /* DAC or ADC */
249 Widget *jack; /* the pin jack */
268 uint convrate, convfmt;
271 Widget *next; /* next in function group */
272 Widget *path; /* next in audio path */
274 Widget *link; /* temporary for findpath */
288 Widget *widgets[Maxwidgets];
292 /* hardware structures */
305 Lock; /* interrupt lock */
306 QLock; /* command lock */
328 Codec *codec[Maxcodecs];
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])
335 static char *widtype[] = {
346 static char *pinport[] = {
353 static char *pinfunc[] = {
373 static char *pincol[] = {
392 static char *pinloc[] = {
411 static char *pinloc2[] = {
421 waitup8(Ctlr *ctlr, int reg, uchar mask, uchar set)
424 for(i=0; i<Maxwaitup; i++){
425 if((csr8(ctlr, reg) & mask) == set)
429 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
430 ctlr->no, reg, mask, set);
435 waitup16(Ctlr *ctlr, int reg, ushort mask, ushort set)
438 for(i=0; i<Maxwaitup; i++){
439 if((csr16(ctlr, reg) & mask) == set)
443 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
444 ctlr->no, reg, mask, set);
449 waitup32(Ctlr *ctlr, int reg, uint mask, uint set)
452 for(i=0; i<Maxwaitup; i++){
453 if((csr32(ctlr, reg) & mask) == set)
457 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
458 ctlr->no, reg, mask, set);
463 hdacmd(Ctlr *ctlr, uint request, uint reply[2])
468 re = csr16(ctlr, Rirbwp);
469 rp = csr16(ctlr, Corbrp);
470 wp = (csr16(ctlr, Corbwp) + 1) % ctlr->corbsize;
472 print("#A%d: corb full\n", ctlr->no);
475 ctlr->corb[wp] = request;
477 csr16(ctlr, Corbwp) = wp;
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);
490 /* reset intcnt for qemu */
491 csr8(ctlr, Rirbsts) = Rirbrover|Rirbrint;
497 cmderr(Id id, uint verb, uint par, uint *ret)
500 q = (id.codec << 28) | (id.nid << 20);
501 if((verb & 0x700) == 0x700)
502 q |= (verb << 8) | par;
504 q |= (verb << 16) | par;
505 if(hdacmd(id.ctlr, q, w) != 1)
514 cmd(Id id, uint verb, uint par)
517 if(cmderr(id, verb, par, w) == -1)
523 newnid(Id id, uint nid)
530 getoutamprange(Widget *w)
534 if((w->cap & Woutampcap) == 0)
536 if((w->cap & Wampovrcap) == 0)
537 r = cmd(w->fg->id, Getparm, Outampcap);
539 r = cmd(w->id, Getparm, Outampcap);
540 return (r >> 8) & 0x7f;
544 getoutamp(Widget *w, int vol[2])
547 if((w->cap & Woutampcap) == 0)
549 vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
550 vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
553 /* vol is 0...range or nil for 0dB; mute is 0/1 */
555 setoutamp(Widget *w, int mute, int *vol)
560 if((w->cap & Woutampcap) == 0)
562 if((w->cap & Wampovrcap) == 0)
563 r = cmd(w->fg->id, Getparm, Outampcap);
565 r = cmd(w->id, Getparm, Outampcap);
569 q = Asetout | (i == 0 ? Asetleft : Asetright);
573 q |= zerodb << Again;
575 q |= vol[i] << Again;
576 cmd(w->id, Setamp, q);
581 getinamprange(Widget *w)
585 if((w->cap & Winampcap) == 0)
587 if((w->cap & Wampovrcap) == 0)
588 r = cmd(w->fg->id, Getparm, Inampcap);
590 r = cmd(w->id, Getparm, Inampcap);
591 return (r >> 8) & 0x7f;
595 getinamp(Widget *w, int vol[2])
598 if((w->cap & Winampcap) == 0)
600 vol[0] = cmd(w->id, Getamp, Agetin | Agetleft) & Againmask;
601 vol[1] = cmd(w->id, Getamp, Agetin | Agetright) & Againmask;
604 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
606 setinamp(Widget *w, Widget *in, int mute, int *vol)
611 if((w->cap & Winampcap) == 0)
613 if((w->cap & Wampovrcap) == 0)
614 r = cmd(w->fg->id, Getparm, Inampcap);
616 r = cmd(w->id, Getparm, Inampcap);
620 q = Asetin | (i == 0 ? Asetleft : Asetright);
624 q |= zerodb << Again;
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));
635 findpath(Widget *jack, int type, char *route)
637 Widget *q[Maxwidgets];
645 for(w=fg->first; w != nil; w = w->next)
648 if(route != nil && *route != 0){
650 while(*route++ == ','){
651 i = strtoul(route, &route, 0);
654 to = fg->codec->widgets[i];
655 if(to == nil || to->fg != fg || to->link != nil)
663 if(w == jack || w->type != type)
672 for(w=fg->first; w != nil; w = w->next)
684 } else if(w == jack){
685 for(w = jack->link; w != nil; w = w->link)
690 for(i=0; i<w->nlist; i++){
692 if(to == nil || to->link)
703 disconnectpath(Widget *from, Widget *to)
707 for(; from != nil && from != to; from = next){
710 setoutamp(from, 1, nil);
712 setinamp(next, from, 1, nil);
714 setoutamp(to, 1, nil);
724 for(i=0; i<Maxcodecs; i++){
725 if(ctlr->codec[i] == nil)
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);
734 cmd(w->id, Setstream, 0);
737 cmd(w->id, Setpinctl, 0);
746 connectpath(Widget *from, Widget *to)
751 for(; from != nil && from != to; from = next){
754 setoutamp(from, 0, 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);
765 setoutamp(to, 0, nil);
769 addconn(Widget *w, uint nid)
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);
781 if((w->nlist % 16) == 0){
784 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
785 print("hda: no memory for Widgetlist\n");
790 w->list[w->nlist++] = src;
796 uint r, f, b, m, i, n, x, y;
798 if((w->cap & Wconncap) == 0)
801 r = cmd(w->id, Getparm, Connlistlen);
803 b = (r & 0x80) ? 16 : 8;
811 r = cmd(w->id, Getconnlist, i);
813 if(i && (r & m) != y)
822 enumwidget(Widget *w)
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);
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);
841 enumfungroup(Codec *codec, Id id)
847 r = cmd(id, Getparm, Fungrtype) & 0x7f;
849 cmd(id, Setpower, 3); /* turn off */
854 cmd(id, Setpower, 0);
857 r = cmd(id, Getparm, Subnodecnt);
859 base = (r >> 16) & 0xff;
860 if(base >= Maxwidgets){
861 print("hda: enumfungroup: base %d out of range\n", base);
864 if(base+n > Maxwidgets){
865 print("hda: enumfungroup: widgets %d - %d out of range\n", base, base+n);
866 n = Maxwidgets - base;
869 fg = mallocz(sizeof *fg, 1);
872 print("hda: enumfungroup: out of memory\n");
881 if(codec->widgets[base + i] != nil){
882 print("hda: enumfungroup: duplicate widget %d\n", base + i);
885 w = mallocz(sizeof(Widget), 1);
887 while(w = fg->first){
889 codec->widgets[w->id.nid] = nil;
895 w->id = newnid(id, base + i);
899 codec->widgets[w->id.nid] = w;
903 enumwidget(codec->widgets[base + i]);
905 enumconns(codec->widgets[base + i]);
911 enumcodec(Codec *codec, Id id)
917 if(cmderr(id, Getparm, Vendorid, &vid) < 0)
919 if(cmderr(id, Getparm, Revid, &rid) < 0)
926 r = cmd(id, Getparm, Subnodecnt);
928 base = (r >> 16) & 0xff;
931 fg = enumfungroup(codec, newnid(id, base + i));
934 fg->next = codec->fgroup;
937 if(codec->fgroup == nil)
940 print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
941 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
957 for(i=0; i<Maxcodecs; i++){
958 if(((1<<i) & ctlr->codecmask) == 0)
960 codec = mallocz(sizeof(Codec), 1);
962 print("hda: no memory for Codec\n");
966 ctlr->codec[i] = codec;
967 if(enumcodec(codec, id) < 0){
968 ctlr->codec[i] = nil;
978 connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad, char *route)
984 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
986 jack = ctlr->codec[cad]->widgets[pin];
989 if(jack->type != Wpin)
992 conv = findpath(jack, type, route);
996 if(s->conv != nil && s->jack != nil){
997 if(s->conv->type == Waout)
998 disconnectpath(s->conv, s->jack);
1000 disconnectpath(s->jack, s->conv);
1001 cmd(s->conv->id, Setstream, 0);
1002 cmd(s->jack->id, Setpinctl, 0);
1006 connectpath(conv, jack);
1007 cmd(jack->id, Setpinctl, Pinctlout);
1009 connectpath(jack, conv);
1010 cmd(jack->id, Setpinctl, Pinctlin);
1013 cmd(conv->id, Setconvfmt, s->afmt);
1014 cmd(conv->id, Setstream, (s->atag << 4) | 0);
1015 cmd(conv->id, Setchancnt, 1);
1031 if((w->pincap & Pout) == 0)
1033 if(w->id.ctlr->sin.jack == w)
1038 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1040 if(((r >> 12) & 0xf) == 4) /* green */
1042 if(((r >> 24) & 0xf) == 1) /* rear */
1044 if(((r >> 28) & 0x3) == 0) /* ext */
1046 if(((r >> 20) & 0xf) == 2) /* hpout */
1048 if(((r >> 20) & 0xf) == 0) /* lineout */
1059 if((w->pincap & Pin) == 0)
1061 if(w->id.ctlr->sout.jack == w)
1066 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1072 bestpin(Ctlr *ctlr, int *pcad, int (*fscore)(Widget *))
1076 int best, pin, score;
1081 for(i=0; i<Maxcodecs; i++){
1082 if(ctlr->codec[i] == nil)
1084 for(fg=ctlr->codec[i]->fgroup; fg != nil; fg=fg->next){
1085 for(w=fg->first; w != nil; w=w->next){
1088 score = (*fscore)(w);
1089 if(score >= 0 && score >= best){
1110 return r->nbuf - (ri - wi);
1118 m = (r->nbuf - BytesPerSample) - buffered(r);
1125 readring(Ring *r, uchar *p, long n)
1131 if((m = buffered(r)) <= 0)
1136 if(r->ri + m > r->nbuf)
1137 m = r->nbuf - r->ri;
1138 memmove(p, r->buf + r->ri, m);
1141 r->ri = (r->ri + m) % r->nbuf;
1148 writering(Ring *r, uchar *p, long n)
1154 if((m = available(r)) <= 0)
1159 if(r->wi + m > r->nbuf)
1160 m = r->nbuf - r->wi;
1161 memmove(r->buf + r->wi, p, m);
1164 r->wi = (r->wi + m) % r->nbuf;
1171 streamalloc(Ctlr *ctlr, Stream *s, int num)
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");
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 */
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;
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);
1208 /* set stream number */
1209 csr32(ctlr, s->sdctl) = (s->atag << Stagbit) |
1210 (csr32(ctlr, s->sdctl) & ~(0xF << Stagbit));
1212 /* set stream format */
1213 csr16(ctlr, Sdfmt+s->sdctl) = s->afmt;
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;
1223 csr8(ctlr, Sdsts+s->sdctl) = Scompl | Sfifoerr | Sdescerr;
1225 /* enable global intrs for this stream */
1226 csr32(ctlr, Intctl) |= s->sdintr;
1227 csr8(ctlr, s->sdctl) |= Scie | Seie | Sdie;
1233 streamstart(Ctlr *ctlr, Stream *s)
1236 csr8(ctlr, s->sdctl) |= Srun;
1237 waitup8(ctlr, s->sdctl, Srun, Srun);
1241 streamstop(Ctlr *ctlr, Stream *s)
1243 csr8(ctlr, s->sdctl) &= ~Srun;
1244 waitup8(ctlr, s->sdctl, Srun, 0);
1249 streampos(Ctlr *ctlr, Stream *s)
1253 p = csr32(ctlr, Sdlpib+s->sdctl);
1254 if(p >= s->ring.nbuf)
1260 hdactl(Audio *adev, void *va, long n, vlong)
1262 char *p, *e, *x, *route, *tok[4];
1271 for(; p < e; p = x){
1273 if(x = strchr(p, '\n'))
1277 ntok = tokenize(p, tok, 4);
1280 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1281 cad = ctlr->sout.cad;
1282 pin = strtoul(tok[1], &route, 0);
1284 cad = strtoul(tok[2], 0, 0);
1285 if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad, route) < 0)
1286 error("connectpin failed");
1288 if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
1289 cad = ctlr->sin.cad;
1290 pin = strtoul(tok[1], &route, 0);
1292 cad = strtoul(tok[2], 0, 0);
1293 if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad, route) < 0)
1294 error("connectpin failed");
1305 return buffered(r) > 0;
1312 return available(r) > 0;
1319 int delay = ctlr->adev->delay*BytesPerSample;
1320 return (delay <= 0) || (buffered(&ctlr->sout.ring) <= delay) || (ctlr->sout.active == 0);
1324 hdabuffered(Audio *adev)
1328 return buffered(&ctlr->sout.ring);
1336 if(ctlr->sout.active)
1338 delay = ctlr->adev->delay*BytesPerSample;
1339 if(buffered(&ctlr->sout.ring) >= delay)
1340 streamstart(ctlr, &ctlr->sout);
1344 hdaread(Audio *adev, void *vp, long n, vlong)
1353 ring = &ctlr->sin.ring;
1354 if(ring->buf == nil || ctlr->sin.conv == nil)
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);
1365 return p - (uchar*)vp;
1369 hdawrite(Audio *adev, void *vp, long n, vlong)
1378 ring = &ctlr->sout.ring;
1379 if(ring->buf == nil || ctlr->sout.conv == nil)
1382 if((n = writering(ring, p, e - p)) <= 0){
1384 sleep(&ring->r, outavail, ring);
1390 while(outrate(ctlr) == 0)
1391 sleep(&ring->r, outrate, ctlr);
1392 return p - (uchar*)vp;
1396 hdaclose(Audio *adev, int mode)
1402 if(mode == OREAD || mode == ORDWR){
1403 if(ctlr->sin.active)
1404 streamstop(ctlr, &ctlr->sin);
1406 if(mode == OWRITE || mode == ORDWR){
1407 ring = &ctlr->sout.ring;
1408 while(ring->wi % Blocksize)
1409 if(writering(ring, (uchar*)"", 1) <= 0)
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,
1431 findoutamp(Stream *s)
1435 for(w = s->conv; w != nil; w = w->path){
1436 if(w->cap & Woutampcap)
1445 findinamp(Stream *s)
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)
1461 hdagetvol(Audio *adev, int x, int a[2])
1463 Ctlr *ctlr = adev->ctlr;
1468 if((w = findoutamp(&ctlr->sout)) != nil)
1472 if((w = findinamp(&ctlr->sin)) != nil)
1486 hdasetvol(Audio *adev, int x, int a[2])
1488 Ctlr *ctlr = adev->ctlr;
1493 if((w = findoutamp(&ctlr->sout)) != nil)
1497 if((w = findinamp(&ctlr->sin)) != nil)
1498 setinamp(w, w->link, 0, a);
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;
1517 fillvoltab(Ctlr *ctlr, Volume *vt)
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);
1529 hdavolread(Audio *adev, void *a, long n, vlong)
1531 Volume voltab[Nvol+1];
1532 fillvoltab(adev->ctlr, voltab);
1533 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1537 hdavolwrite(Audio *adev, void *a, long n, vlong)
1539 Volume voltab[Nvol+1];
1540 fillvoltab(adev->ctlr, voltab);
1541 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1545 hdainterrupt(Ureg *, void *arg)
1554 if(ctlr == nil || ctlr->adev != adev)
1557 sts = csr32(ctlr, Intsts);
1558 if(sts & ctlr->sout.sdintr){
1559 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
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);
1569 if(sts & ctlr->sin.sdintr){
1570 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
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);
1581 csr8(ctlr, Rirbsts) = Rirbrover|Rirbrint;
1587 hdastatus(Audio *adev, void *a, long n, vlong)
1589 Ctlr *ctlr = adev->ctlr;
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)
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)
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" : ""
1624 s = seprint(s, e, "%s %d %lux",
1625 widtype[w->type&7], w->id.nid,
1629 s = seprint(s, e, " ← ");
1630 for(k=0; k<w->nlist; k++){
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);
1637 s = seprint(s, e, "\n");
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)
1647 s = seprint(s, e, " → ");
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);
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)
1660 s = seprint(s, e, " → ");
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);
1667 return s - (char*)a;
1672 hdastart(Ctlr *ctlr)
1674 static int cmdbufsize[] = { 2, 16, 256, 2048 };
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);
1689 microdelay(Codecdelay);
1691 ctlr->codecmask = csr16(ctlr, Statests);
1692 if(ctlr->codecmask == 0){
1693 print("#A%d: hda no codecs\n", ctlr->no);
1697 cap = csr16(ctlr, Gcap);
1698 ctlr->bss = (cap>>3) & 0x1F;
1699 ctlr->iss = (cap>>8) & 0xF;
1700 ctlr->oss = (cap>>12) & 0xF;
1702 csr8(ctlr, Corbctl) = 0;
1703 waitup8(ctlr, Corbctl, Corbdma, 0);
1705 csr8(ctlr, Rirbctl) = 0;
1706 waitup8(ctlr, Rirbctl, Rirbdma, 0);
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);
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);
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);
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);
1740 pa = PCIWADDR(ctlr->rirb);
1741 csr32(ctlr, Rirblbase) = pa;
1742 csr32(ctlr, Rirbubase) = pa >> 32;
1743 csr16(ctlr, Rirbwp) = Rirbptrrst;
1746 * qemu requires interrupt handshake,
1747 * even tho we just poll the irb write
1748 * pointer for command completion.
1750 csr16(ctlr, Rintcnt) = 1;
1751 csr8(ctlr, Rirbctl) = Rirbdma|Rirbint;
1753 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
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* */
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) */
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 */
1799 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1800 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1801 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
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 */
1808 case (0x15ad << 16) | 0x1977: /* Vmware */
1815 hdacmdread(Chan *, void *a, long n, vlong)
1824 return qread(ctlr->q, a, n);
1828 hdacmdwrite(Chan *, void *a, long n, vlong)
1842 for(i=0; i<n/4; i++){
1843 if(hdacmd(ctlr, lp[i], w) <= 0){
1847 qproduce(ctlr->q, w, sizeof(w));
1854 hdareset1(Audio *adev, Ctlr *ctlr)
1856 int best, cad, irq, tbdf;
1863 if(p->vid == 0x10de){
1864 /* magic for NVidia */
1865 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1867 if(p->vid == 0x10b9){
1869 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1870 pcicfgw32(p, PciBAR1, 0);
1872 if(p->vid == 0x8086){
1873 /* magic for Intel */
1875 case 0x1c20: /* PCH */
1877 case 0x811b: /* SCH */
1884 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1887 if(p->vid == 0x1002){
1889 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1892 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1895 if(p->mem[0].bar & 1){
1896 print("hda: bar0 %llux: not memory\n", p->mem[0].bar);
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);
1906 ctlr->no = adev->ctlrno;
1907 print("#A%d: hda mem %llux irq %d\n", ctlr->no, ctlr->port, irq);
1909 if(hdastart(ctlr) < 0){
1910 print("#A%d: unable to start hda\n", ctlr->no);
1914 /* iss + oss + bss */
1915 if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1916 print("#A%d: output streamalloc failed\n", ctlr->no);
1918 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1919 print("#A%d: input streamalloc failed\n", ctlr->no);
1921 else if(ctlr->bss > 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);
1932 if(enumdev(ctlr) < 0){
1933 print("#A%d: no audio codecs found\n", ctlr->no);
1938 best = bestpin(ctlr, &cad, scoreout);
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);
1944 best = bestpin(ctlr, &cad, scorein);
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);
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;
1960 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1962 /* enable interrupts */
1963 csr32(ctlr, Intctl) |= Gie | Cie;
1965 ctlr->q = qopen(256, 0, 0, 0);
1968 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1974 hdareset(Audio *adev)
1976 static Ctlr *cards = nil;
1980 /* make a list of all cards if not already done */
1983 while((p = hdamatch(p)) != nil){
1984 ctlr = mallocz(sizeof(Ctlr), 1);
1986 print("hda: can't allocate memory\n");
1995 /* pick a card from the list */
1996 for(ctlr = cards; ctlr != nil; ctlr = ctlr->next){
1997 if(ctlr->adev == nil && ctlr->pcidev != nil){
1999 pcienable(ctlr->pcidev);
2000 if(hdareset1(adev, ctlr) == 0)
2002 pcidisable(ctlr->pcidev);
2013 addaudiocard("hda", hdareset);