2 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
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;
17 typedef struct Widget Widget;
18 typedef struct Codec Codec;
19 typedef struct Fungroup Fungroup;
20 typedef struct Pinprop Pinprop;
67 /* Warning: Sdctl is 24bit register */
99 Bufsize = 64 * 1024 * 4,
101 Blocksize = Bufsize / Nblocks,
104 Maxrirbwait = 1000, /* microseconds */
105 Maxwaitup = 500, /* microseconds */
106 Codecdelay = 1000, /* microseconds */
110 /* 12-bit cmd + 8-bit payload */
173 Getunsolresp = 0xf08,
174 Setunsolresp = 0x708,
192 /* 4-bit cmd + 16-bit payload */
247 Widget *conv; /* DAC or ADC */
248 Widget *jack; /* the pin jack */
267 uint convrate, convfmt;
270 Widget *next; /* next in function group */
271 Widget *path; /* next in audio path */
273 Widget *link; /* temporary for findpath */
287 Widget *widgets[Maxwidgets];
291 /* hardware structures */
304 Lock; /* interrupt lock */
305 QLock; /* command lock */
325 Codec *codec[Maxcodecs];
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])
332 static char *widtype[] = {
343 static char *pinport[] = {
350 static char *pinfunc[] = {
370 static char *pincol[] = {
389 static char *pinloc[] = {
408 static char *pinloc2[] = {
418 waitup8(Ctlr *ctlr, int reg, uchar mask, uchar set)
421 for(i=0; i<Maxwaitup; i++){
422 if((csr8(ctlr, reg) & mask) == set)
426 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
427 ctlr->no, reg, mask, set);
432 waitup16(Ctlr *ctlr, int reg, ushort mask, ushort set)
435 for(i=0; i<Maxwaitup; i++){
436 if((csr16(ctlr, reg) & mask) == set)
440 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
441 ctlr->no, reg, mask, set);
446 waitup32(Ctlr *ctlr, int reg, uint mask, uint set)
449 for(i=0; i<Maxwaitup; i++){
450 if((csr32(ctlr, reg) & mask) == set)
454 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
455 ctlr->no, reg, mask, set);
460 hdacmd(Ctlr *ctlr, uint request, uint reply[2])
466 re = csr16(ctlr, Rirbwp);
467 rp = csr16(ctlr, Corbrp);
468 wp = (csr16(ctlr, Corbwp) + 1) % ctlr->corbsize;
470 print("#A%d: corb full\n", ctlr->no);
473 ctlr->corb[wp] = request;
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);
488 cmderr(Id id, uint verb, uint par, uint *ret)
491 q = (id.codec << 28) | (id.nid << 20);
492 if((verb & 0x700) == 0x700)
493 q |= (verb << 8) | par;
495 q |= (verb << 16) | par;
496 if(hdacmd(id.ctlr, q, w) != 1)
505 cmd(Id id, uint verb, uint par)
508 if(cmderr(id, verb, par, w) == -1)
514 newnid(Id id, uint nid)
521 getoutamprange(Widget *w)
525 if((w->cap & Woutampcap) == 0)
527 if((w->cap & Wampovrcap) == 0)
528 r = cmd(w->fg->id, Getparm, Outampcap);
530 r = cmd(w->id, Getparm, Outampcap);
531 return (r >> 8) & 0x7f;
535 getoutamp(Widget *w, int vol[2])
538 if((w->cap & Woutampcap) == 0)
540 vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
541 vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
544 /* vol is 0...range or nil for 0dB; mute is 0/1 */
546 setoutamp(Widget *w, int mute, int *vol)
551 if((w->cap & Woutampcap) == 0)
553 if((w->cap & Wampovrcap) == 0)
554 r = cmd(w->fg->id, Getparm, Outampcap);
556 r = cmd(w->id, Getparm, Outampcap);
560 q = Asetout | (i == 0 ? Asetleft : Asetright);
564 q |= zerodb << Again;
566 q |= vol[i] << Again;
567 cmd(w->id, Setamp, q);
572 getinamprange(Widget *w)
576 if((w->cap & Winampcap) == 0)
578 if((w->cap & Wampovrcap) == 0)
579 r = cmd(w->fg->id, Getparm, Inampcap);
581 r = cmd(w->id, Getparm, Inampcap);
582 return (r >> 8) & 0x7f;
586 getinamp(Widget *w, int vol[2])
589 if((w->cap & Winampcap) == 0)
591 vol[0] = cmd(w->id, Getamp, Agetin | Agetleft) & Againmask;
592 vol[1] = cmd(w->id, Getamp, Agetin | Agetright) & Againmask;
595 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
597 setinamp(Widget *w, Widget *in, int mute, int *vol)
602 if((w->cap & Winampcap) == 0)
604 if((w->cap & Wampovrcap) == 0)
605 r = cmd(w->fg->id, Getparm, Inampcap);
607 r = cmd(w->id, Getparm, Inampcap);
611 q = Asetin | (i == 0 ? Asetleft : Asetright);
615 q |= zerodb << Again;
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));
626 findpath(Widget *jack, int type, char *route)
628 Widget *q[Maxwidgets];
636 for(w=fg->first; w != nil; w = w->next)
639 if(route != nil && *route != 0){
641 while(*route++ == ','){
642 i = strtoul(route, &route, 0);
645 to = fg->codec->widgets[i];
646 if(to == nil || to->fg != fg || to->link != nil)
654 if(w == jack || w->type != type)
663 for(w=fg->first; w != nil; w = w->next)
675 } else if(w == jack){
676 for(w = jack->link; w != nil; w = w->link)
681 for(i=0; i<w->nlist; i++){
683 if(to == nil || to->link)
694 disconnectpath(Widget *from, Widget *to)
698 for(; from != nil && from != to; from = next){
701 setoutamp(from, 1, nil);
703 setinamp(next, from, 1, nil);
705 setoutamp(to, 1, nil);
715 for(i=0; i<Maxcodecs; i++){
716 if(ctlr->codec[i] == nil)
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);
725 cmd(w->id, Setstream, 0);
728 cmd(w->id, Setpinctl, 0);
737 connectpath(Widget *from, Widget *to)
742 for(; from != nil && from != to; from = next){
745 setoutamp(from, 0, 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);
756 setoutamp(to, 0, nil);
760 addconn(Widget *w, uint nid)
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);
772 if((w->nlist % 16) == 0){
775 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
776 print("hda: no memory for Widgetlist\n");
781 w->list[w->nlist++] = src;
787 uint r, f, b, m, i, n, x, y;
789 if((w->cap & Wconncap) == 0)
792 r = cmd(w->id, Getparm, Connlistlen);
794 b = (r & 0x80) ? 16 : 8;
802 r = cmd(w->id, Getconnlist, i);
804 if(i && (r & m) != y)
813 enumwidget(Widget *w)
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);
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);
832 enumfungroup(Codec *codec, Id id)
838 r = cmd(id, Getparm, Fungrtype) & 0x7f;
840 cmd(id, Setpower, 3); /* turn off */
845 cmd(id, Setpower, 0);
848 r = cmd(id, Getparm, Subnodecnt);
850 base = (r >> 16) & 0xff;
851 if(base >= Maxwidgets){
852 print("hda: enumfungroup: base %d out of range\n", base);
855 if(base+n > Maxwidgets){
856 print("hda: enumfungroup: widgets %d - %d out of range\n", base, base+n);
857 n = Maxwidgets - base;
860 fg = mallocz(sizeof *fg, 1);
863 print("hda: enumfungroup: out of memory\n");
872 if(codec->widgets[base + i] != nil){
873 print("hda: enumfungroup: duplicate widget %d\n", base + i);
876 w = mallocz(sizeof(Widget), 1);
878 while(w = fg->first){
880 codec->widgets[w->id.nid] = nil;
886 w->id = newnid(id, base + i);
890 codec->widgets[w->id.nid] = w;
894 enumwidget(codec->widgets[base + i]);
896 enumconns(codec->widgets[base + i]);
902 enumcodec(Codec *codec, Id id)
908 if(cmderr(id, Getparm, Vendorid, &vid) < 0)
910 if(cmderr(id, Getparm, Revid, &rid) < 0)
917 r = cmd(id, Getparm, Subnodecnt);
919 base = (r >> 16) & 0xff;
922 fg = enumfungroup(codec, newnid(id, base + i));
925 fg->next = codec->fgroup;
928 if(codec->fgroup == nil)
931 print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
932 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
948 for(i=0; i<Maxcodecs; i++){
949 if(((1<<i) & ctlr->codecmask) == 0)
951 codec = mallocz(sizeof(Codec), 1);
953 print("hda: no memory for Codec\n");
957 ctlr->codec[i] = codec;
958 if(enumcodec(codec, id) < 0){
959 ctlr->codec[i] = nil;
969 connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad, char *route)
975 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
977 jack = ctlr->codec[cad]->widgets[pin];
980 if(jack->type != Wpin)
983 conv = findpath(jack, type, route);
987 if(s->conv != nil && s->jack != nil){
988 if(s->conv->type == Waout)
989 disconnectpath(s->conv, s->jack);
991 disconnectpath(s->jack, s->conv);
992 cmd(s->conv->id, Setstream, 0);
993 cmd(s->jack->id, Setpinctl, 0);
997 connectpath(conv, jack);
998 cmd(jack->id, Setpinctl, Pinctlout);
1000 connectpath(jack, conv);
1001 cmd(jack->id, Setpinctl, Pinctlin);
1004 cmd(conv->id, Setconvfmt, s->afmt);
1005 cmd(conv->id, Setstream, (s->atag << 4) | 0);
1006 cmd(conv->id, Setchancnt, 1);
1022 if((w->pincap & Pout) == 0)
1024 if(w->id.ctlr->sin.jack == w)
1029 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1031 if(((r >> 12) & 0xf) == 4) /* green */
1033 if(((r >> 24) & 0xf) == 1) /* rear */
1035 if(((r >> 28) & 0x3) == 0) /* ext */
1037 if(((r >> 20) & 0xf) == 2) /* hpout */
1039 if(((r >> 20) & 0xf) == 0) /* lineout */
1050 if((w->pincap & Pin) == 0)
1052 if(w->id.ctlr->sout.jack == w)
1057 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
1063 bestpin(Ctlr *ctlr, int *pcad, int (*fscore)(Widget *))
1067 int best, pin, score;
1072 for(i=0; i<Maxcodecs; i++){
1073 if(ctlr->codec[i] == nil)
1075 for(fg=ctlr->codec[i]->fgroup; fg != nil; fg=fg->next){
1076 for(w=fg->first; w != nil; w=w->next){
1079 score = (*fscore)(w);
1080 if(score >= 0 && score >= best){
1101 return r->nbuf - (ri - wi);
1109 m = (r->nbuf - BytesPerSample) - buffered(r);
1116 readring(Ring *r, uchar *p, long n)
1122 if((m = buffered(r)) <= 0)
1127 if(r->ri + m > r->nbuf)
1128 m = r->nbuf - r->ri;
1129 memmove(p, r->buf + r->ri, m);
1132 r->ri = (r->ri + m) % r->nbuf;
1139 writering(Ring *r, uchar *p, long n)
1145 if((m = available(r)) <= 0)
1150 if(r->wi + m > r->nbuf)
1151 m = r->nbuf - r->wi;
1152 memmove(r->buf + r->wi, p, m);
1155 r->wi = (r->wi + m) % r->nbuf;
1162 streamalloc(Ctlr *ctlr, Stream *s, int num)
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");
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 */
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;
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);
1197 /* set stream number */
1198 csr32(ctlr, s->sdctl) = (s->atag << Stagbit) |
1199 (csr32(ctlr, s->sdctl) & ~(0xF << Stagbit));
1201 /* set stream format */
1202 csr16(ctlr, Sdfmt+s->sdctl) = s->afmt;
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;
1211 csr8(ctlr, Sdsts+s->sdctl) = Scompl | Sfifoerr | Sdescerr;
1213 /* enable global intrs for this stream */
1214 csr32(ctlr, Intctl) |= s->sdintr;
1215 csr8(ctlr, s->sdctl) |= Scie | Seie | Sdie;
1221 streamstart(Ctlr *ctlr, Stream *s)
1224 csr8(ctlr, s->sdctl) |= Srun;
1225 waitup8(ctlr, s->sdctl, Srun, Srun);
1229 streamstop(Ctlr *ctlr, Stream *s)
1231 csr8(ctlr, s->sdctl) &= ~Srun;
1232 waitup8(ctlr, s->sdctl, Srun, 0);
1237 streampos(Ctlr *ctlr, Stream *s)
1241 p = csr32(ctlr, Sdlpib+s->sdctl);
1242 if(p >= s->ring.nbuf)
1248 hdactl(Audio *adev, void *va, long n, vlong)
1250 char *p, *e, *x, *route, *tok[4];
1259 for(; p < e; p = x){
1261 if(x = strchr(p, '\n'))
1265 ntok = tokenize(p, tok, 4);
1268 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1269 cad = ctlr->sout.cad;
1270 pin = strtoul(tok[1], &route, 0);
1272 cad = strtoul(tok[2], 0, 0);
1273 if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad, route) < 0)
1274 error("connectpin failed");
1276 if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
1277 cad = ctlr->sin.cad;
1278 pin = strtoul(tok[1], &route, 0);
1280 cad = strtoul(tok[2], 0, 0);
1281 if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad, route) < 0)
1282 error("connectpin failed");
1293 return buffered(r) > 0;
1300 return available(r) > 0;
1307 int delay = ctlr->adev->delay*BytesPerSample;
1308 return (delay <= 0) || (buffered(&ctlr->sout.ring) <= delay) || (ctlr->sout.active == 0);
1312 hdabuffered(Audio *adev)
1316 return buffered(&ctlr->sout.ring);
1324 if(ctlr->sout.active)
1326 delay = ctlr->adev->delay*BytesPerSample;
1327 if(buffered(&ctlr->sout.ring) >= delay)
1328 streamstart(ctlr, &ctlr->sout);
1332 hdaread(Audio *adev, void *vp, long n, vlong)
1341 ring = &ctlr->sin.ring;
1342 if(ring->buf == nil || ctlr->sin.conv == nil)
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);
1353 return p - (uchar*)vp;
1357 hdawrite(Audio *adev, void *vp, long n, vlong)
1366 ring = &ctlr->sout.ring;
1367 if(ring->buf == nil || ctlr->sout.conv == nil)
1370 if((n = writering(ring, p, e - p)) <= 0){
1372 sleep(&ring->r, outavail, ring);
1378 while(outrate(ctlr) == 0)
1379 sleep(&ring->r, outrate, ctlr);
1380 return p - (uchar*)vp;
1384 hdaclose(Audio *adev, int mode)
1390 if(mode == OREAD || mode == ORDWR){
1391 if(ctlr->sin.active)
1392 streamstop(ctlr, &ctlr->sin);
1394 if(mode == OWRITE || mode == ORDWR){
1395 ring = &ctlr->sout.ring;
1396 while(ring->wi % Blocksize)
1397 if(writering(ring, (uchar*)"", 1) <= 0)
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,
1419 findoutamp(Stream *s)
1423 for(w = s->conv; w != nil; w = w->path){
1424 if(w->cap & Woutampcap)
1433 findinamp(Stream *s)
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)
1449 hdagetvol(Audio *adev, int x, int a[2])
1451 Ctlr *ctlr = adev->ctlr;
1456 if((w = findoutamp(&ctlr->sout)) != nil)
1460 if((w = findinamp(&ctlr->sin)) != nil)
1474 hdasetvol(Audio *adev, int x, int a[2])
1476 Ctlr *ctlr = adev->ctlr;
1481 if((w = findoutamp(&ctlr->sout)) != nil)
1485 if((w = findinamp(&ctlr->sin)) != nil)
1486 setinamp(w, w->link, 0, a);
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;
1505 fillvoltab(Ctlr *ctlr, Volume *vt)
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);
1517 hdavolread(Audio *adev, void *a, long n, vlong)
1519 Volume voltab[Nvol+1];
1520 fillvoltab(adev->ctlr, voltab);
1521 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1525 hdavolwrite(Audio *adev, void *a, long n, vlong)
1527 Volume voltab[Nvol+1];
1528 fillvoltab(adev->ctlr, voltab);
1529 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1533 hdainterrupt(Ureg *, void *arg)
1543 sts = csr32(ctlr, Intsts);
1544 if(sts & ctlr->sout.sdintr){
1545 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
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);
1555 if(sts & ctlr->sin.sdintr){
1556 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
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);
1570 hdastatus(Audio *adev, void *a, long n, vlong)
1572 Ctlr *ctlr = adev->ctlr;
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)
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)
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" : ""
1607 s = seprint(s, e, "%s %d %lux",
1608 widtype[w->type&7], w->id.nid,
1612 s = seprint(s, e, " ← ");
1613 for(k=0; k<w->nlist; k++){
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);
1620 s = seprint(s, e, "\n");
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)
1630 s = seprint(s, e, " → ");
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);
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)
1643 s = seprint(s, e, " → ");
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);
1650 return s - (char*)a;
1655 hdastart(Ctlr *ctlr)
1657 static int cmdbufsize[] = { 2, 16, 256, 2048 };
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);
1671 microdelay(Codecdelay);
1673 ctlr->codecmask = csr16(ctlr, Statests);
1674 if(ctlr->codecmask == 0){
1675 print("#A%d: hda no codecs\n", ctlr->no);
1679 cap = csr16(ctlr, Gcap);
1680 ctlr->bss = (cap>>3) & 0x1F;
1681 ctlr->iss = (cap>>8) & 0xF;
1682 ctlr->oss = (cap>>12) & 0xF;
1684 csr8(ctlr, Corbctl) = 0;
1685 waitup8(ctlr, Corbctl, Corbdma, 0);
1687 csr8(ctlr, Rirbctl) = 0;
1688 waitup8(ctlr, Rirbctl, Rirbdma, 0);
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);
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);
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);
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);
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);
1727 /* enable interrupts */
1728 csr32(ctlr, Intctl) |= Gie | Cie;
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) */
1750 case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1751 case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1752 case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1753 case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1754 case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1755 case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1757 case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1758 case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1759 case (0x1002 << 16) | 0xaa55: /* ATI HDMI (8500 series) */
1760 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1762 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1763 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1764 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1766 case (0x15ad << 16) | 0x1977: /* Vmware */
1773 hdacmdread(Chan *, void *a, long n, vlong)
1782 return qread(ctlr->q, a, n);
1786 hdacmdwrite(Chan *, void *a, long n, vlong)
1800 for(i=0; i<n/4; i++){
1801 if(hdacmd(ctlr, lp[i], w) <= 0){
1805 qproduce(ctlr->q, w, sizeof(w));
1812 hdareset(Audio *adev)
1814 static Ctlr *cards = nil;
1815 int irq, tbdf, best, cad;
1819 /* make a list of all cards if not already done */
1822 while(p = hdamatch(p)){
1823 ctlr = mallocz(sizeof(Ctlr), 1);
1825 print("hda: can't allocate memory\n");
1834 /* pick a card from the list */
1835 for(ctlr = cards; ctlr != nil; ctlr = ctlr->next){
1836 if(p = ctlr->pcidev){
1850 if(p->vid == 0x10de){
1851 /* magic for NVidia */
1852 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1854 if(p->vid == 0x10b9){
1856 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1857 pcicfgw32(p, PciBAR1, 0);
1859 if(p->vid == 0x8086){
1860 /* magic for Intel */
1862 case 0x1c20: /* PCH */
1864 case 0x811b: /* SCH */
1866 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1869 if(p->vid == 0x1002){
1871 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1874 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1880 ctlr->no = adev->ctlrno;
1881 ctlr->size = p->mem[0].size;
1882 ctlr->q = qopen(256, 0, 0, 0);
1883 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1884 if(ctlr->mem == nil){
1885 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1888 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1890 if(hdastart(ctlr) < 0){
1891 print("#A%d: unable to start hda\n", ctlr->no);
1895 /* iss + oss + bss */
1896 if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1897 print("#A%d: output streamalloc failed\n", ctlr->no);
1899 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1900 print("#A%d: input streamalloc failed\n", ctlr->no);
1902 else if(ctlr->bss > 0){
1904 if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1905 print("#A%d: input streamalloc failed\n", ctlr->no);
1906 } else if(ctlr->bss > 1) {
1907 if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1908 print("#A%d: input streamalloc failed\n", ctlr->no);
1912 if(enumdev(ctlr) < 0){
1913 print("#A%d: no audio codecs found\n", ctlr->no);
1918 best = bestpin(ctlr, &cad, scoreout);
1920 print("#A%d: no output pins found\n", ctlr->no);
1921 else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad, nil) < 0)
1922 print("#A%d: error connecting output pin\n", ctlr->no);
1924 best = bestpin(ctlr, &cad, scorein);
1926 print("#A%d: no input pins found\n", ctlr->no);
1927 else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad, nil) < 0)
1928 print("#A%d: error connecting input pin\n", ctlr->no);
1930 adev->read = hdaread;
1931 adev->write = hdawrite;
1932 adev->close = hdaclose;
1933 adev->buffered = hdabuffered;
1934 adev->volread = hdavolread;
1935 adev->volwrite = hdavolwrite;
1936 adev->status = hdastatus;
1939 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1941 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1949 addaudiocard("hda", hdareset);