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);
571 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
573 setinamp(Widget *w, Widget *in, int mute, int *vol)
578 if((w->cap & Winampcap) == 0)
580 if((w->cap & Wampovrcap) == 0)
581 r = cmd(w->fg->id, Getparm, Inampcap);
583 r = cmd(w->id, Getparm, Inampcap);
587 q = Asetin | (i == 0 ? Asetleft : Asetright);
591 q |= zerodb << Again;
593 q |= vol[i] << Again;
594 for(j=0; j<w->nlist; j++){
595 if(in == nil || w->list[j] == in)
596 cmd(w->id, Setamp, q | (j << Asetidx));
602 findpath(Widget *jack, int type)
604 Widget *q[Maxwidgets];
609 for(w=jack->fg->first; w != nil; w = w->next)
616 for(w=jack->fg->first; w != nil; w = w->next)
628 } else if(w == jack){
629 for(w = jack->link; w != nil; w = w->link)
634 for(i=0; i<w->nlist; i++){
636 if(to == nil || to->link)
647 disconnectpath(Widget *from, Widget *to)
651 for(; from != nil && from != to; from = next){
654 setoutamp(from, 1, nil);
655 setinamp(next, from, 1, nil);
657 setoutamp(to, 1, nil);
661 connectpath(Widget *from, Widget *to)
666 for(; from != nil && from != to; from = next){
669 setoutamp(from, 0, nil);
670 setinamp(next, from, 0, nil);
673 for(i=0; i < next->nlist; i++)
674 if(next->list[i] == from){
675 cmd(next->id, Setconn, i);
679 setoutamp(to, 0, nil);
683 addconn(Widget *w, uint nid)
689 src = w->fg->codec->widgets[nid];
690 if(src == nil || (src->fg != w->fg)){
691 print("hda: invalid connection %d:%s[%d] -> %d\n",
692 w->id.nid, widtype[w->type & 7], w->nlist, nid);
695 if((w->nlist % 16) == 0){
698 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
699 print("hda: no memory for Widgetlist\n");
704 w->list[w->nlist++] = src;
711 uint r, f, b, m, i, n, x, y;
713 if((w->cap & Wconncap) == 0)
716 r = cmd(w->id, Getparm, Connlistlen);
718 b = (r & 0x80) ? 16 : 8;
726 r = cmd(w->id, Getconnlist, i);
728 if(i && (r & m) != y)
737 enumwidget(Widget *w)
739 w->cap = cmd(w->id, Getparm, Widgetcap);
740 w->type = (w->cap >> 20) & 0x7;
742 cmd(w->id, Setpower, 0);
748 w->pin = cmd(w->id, Getdefault, 0);
749 w->pincap = cmd(w->id, Getparm, Pincap);
750 if(w->pincap & Peapd)
751 cmd(w->id, Seteapd, Eapdenable);
757 enumfungroup(Codec *codec, Id id)
763 r = cmd(id, Getparm, Fungrtype) & 0x7f;
765 cmd(id, Setpower, 3); /* turn off */
770 cmd(id, Setpower, 0);
773 fg = mallocz(sizeof *fg, 1);
776 print("hda: enumfungroup: out of memory\n");
783 r = cmd(id, Getparm, Subnodecnt);
785 base = (r >> 16) & 0xff;
787 if(base + n > Maxwidgets){
794 w = mallocz(sizeof(Widget), 1);
796 while(w = fg->first){
798 codec->widgets[w->id.nid] = nil;
804 w->id = newnid(id, base + i);
808 codec->widgets[w->id.nid] = w;
812 enumwidget(codec->widgets[base + i]);
819 enumcodec(Codec *codec, Id id)
825 if(cmderr(id, Getparm, Vendorid, &vid) < 0)
827 if(cmderr(id, Getparm, Revid, &rid) < 0)
834 r = cmd(id, Getparm, Subnodecnt);
836 base = (r >> 16) & 0xff;
839 fg = enumfungroup(codec, newnid(id, base + i));
842 fg->next = codec->fgroup;
845 if(codec->fgroup == nil)
848 print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
849 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
865 for(i=0; i<Maxcodecs; i++){
866 if(((1<<i) & ctlr->codecmask) == 0)
868 codec = mallocz(sizeof(Codec), 1);
870 print("hda: no memory for Codec\n");
874 ctlr->codec[i] = codec;
875 if(enumcodec(codec, id) < 0){
876 ctlr->codec[i] = nil;
886 connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad)
890 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
892 jack = ctlr->codec[cad]->widgets[pin];
895 if(jack->type != Wpin)
898 conv = findpath(jack, type);
902 if(s->conv != nil && s->jack != nil){
903 if(s->conv->type == Waout)
904 disconnectpath(s->conv, s->jack);
906 disconnectpath(s->jack, s->conv);
907 cmd(s->conv->id, Setstream, 0);
908 cmd(s->jack->id, Setpinctl, 0);
912 connectpath(conv, jack);
913 cmd(jack->id, Setpinctl, Pinctlout);
915 connectpath(jack, conv);
916 cmd(jack->id, Setpinctl, Pinctlin);
919 cmd(conv->id, Setconvfmt, s->afmt);
920 cmd(conv->id, Setstream, (s->atag << 4) | 0);
921 cmd(conv->id, Setchancnt, 1);
932 bestpin(Ctlr *ctlr, int *pcad)
936 int best, pin, score;
942 for(i=0; i<Maxcodecs; i++){
943 if(ctlr->codec[i] == nil)
945 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
946 for(w=fg->first; w; w=w->next){
949 if((w->pincap & Pout) == 0)
953 if(((r >> 12) & 0xf) == 4) /* green */
955 if(((r >> 24) & 0xf) == 1) /* rear */
957 if(((r >> 28) & 0x3) == 0) /* ext */
959 if(((r >> 20) & 0xf) == 2) /* hpout */
961 if(((r >> 20) & 0xf) == 0) /* lineout */
984 return r->nbuf - (ri - wi);
992 m = (r->nbuf - BytesPerSample) - buffered(r);
999 readring(Ring *r, uchar *p, long n)
1005 if((m = buffered(r)) <= 0)
1010 if(r->ri + m > r->nbuf)
1011 m = r->nbuf - r->ri;
1012 memmove(p, r->buf + r->ri, m);
1015 r->ri = (r->ri + m) % r->nbuf;
1022 writering(Ring *r, uchar *p, long n)
1028 if((m = available(r)) <= 0)
1033 if(r->wi + m > r->nbuf)
1034 m = r->nbuf - r->wi;
1035 memmove(r->buf + r->wi, p, m);
1038 r->wi = (r->wi + m) % r->nbuf;
1045 streamalloc(Ctlr *ctlr, Stream *s, int num)
1051 r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
1052 s->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
1053 if(r->buf == nil || s->blds == nil){
1054 print("hda: no memory for stream\n");
1057 for(i=0; i<Nblocks; i++){
1058 s->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
1059 s->blds[i].addrhi = 0;
1060 s->blds[i].len = Blocksize;
1061 s->blds[i].flags = 0x01; /* interrupt on completion */
1065 s->sdctl = Sdctl0 + s->sdnum*0x20;
1066 s->sdintr = 1<<s->sdnum;
1067 s->atag = s->sdnum+1;
1068 s->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
1072 csr8(ctlr, s->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
1073 csr8(ctlr, s->sdctl) |= Srst;
1074 microdelay(Codecdelay);
1075 waitup8(ctlr, s->sdctl, Srst, Srst);
1076 csr8(ctlr, s->sdctl) &= ~Srst;
1077 microdelay(Codecdelay);
1078 waitup8(ctlr, s->sdctl, Srst, 0);
1080 /* set stream number */
1081 csr32(ctlr, s->sdctl) = (s->atag << Stagbit) |
1082 (csr32(ctlr, s->sdctl) & ~(0xF << Stagbit));
1084 /* set stream format */
1085 csr16(ctlr, Sdfmt+s->sdctl) = s->afmt;
1087 /* program stream DMA & parms */
1088 csr32(ctlr, Sdbdplo+s->sdctl) = PADDR(s->blds);
1089 csr32(ctlr, Sdbdphi+s->sdctl) = 0;
1090 csr32(ctlr, Sdcbl+s->sdctl) = r->nbuf;
1091 csr16(ctlr, Sdlvi+s->sdctl) = (Nblocks - 1) & 0xff;
1094 csr8(ctlr, Sdsts+s->sdctl) = Scompl | Sfifoerr | Sdescerr;
1096 /* enable global intrs for this stream */
1097 csr32(ctlr, Intctl) |= s->sdintr;
1098 csr8(ctlr, s->sdctl) |= Scie | Seie | Sdie;
1104 streamstart(Ctlr *ctlr, Stream *s)
1107 csr8(ctlr, s->sdctl) |= Srun;
1108 waitup8(ctlr, s->sdctl, Srun, Srun);
1112 streamstop(Ctlr *ctlr, Stream *s)
1114 csr8(ctlr, s->sdctl) &= ~Srun;
1115 waitup8(ctlr, s->sdctl, Srun, 0);
1120 streampos(Ctlr *ctlr, Stream *s)
1124 p = csr32(ctlr, Sdlpib+s->sdctl);
1125 if(p >= s->ring.nbuf)
1131 hdactl(Audio *adev, void *va, long n, vlong)
1133 char *p, *e, *x, *tok[4];
1142 for(; p < e; p = x){
1143 if(x = strchr(p, '\n'))
1147 ntok = tokenize(p, tok, 4);
1150 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1151 cad = ctlr->sout.cad;
1152 pin = strtoul(tok[1], 0, 0);
1154 cad = strtoul(tok[2], 0, 0);
1155 if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad) < 0)
1156 error("connectpin failed");
1158 if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
1159 cad = ctlr->sout.cad;
1160 pin = strtoul(tok[1], 0, 0);
1162 cad = strtoul(tok[2], 0, 0);
1163 if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad) < 0)
1164 error("connectpin failed");
1175 return buffered(r) > 0;
1182 return available(r) > 0;
1189 int delay = ctlr->adev->delay*BytesPerSample;
1190 return (delay <= 0) || (buffered(&ctlr->sout.ring) <= delay) || (ctlr->sout.active == 0);
1194 hdabuffered(Audio *adev)
1198 return buffered(&ctlr->sout.ring);
1204 if(ctlr->sout.active)
1206 if(buffered(&ctlr->sout.ring) > Blocksize)
1207 streamstart(ctlr, &ctlr->sout);
1211 hdaread(Audio *adev, void *vp, long n, vlong)
1220 ring = &ctlr->sin.ring;
1221 if(ring->buf == nil || ctlr->sin.conv == nil)
1224 if((n = readring(ring, p, e - p)) <= 0){
1225 if(!ctlr->sin.active)
1226 streamstart(ctlr, &ctlr->sin);
1227 sleep(&ring->r, inavail, ring);
1232 return p - (uchar*)vp;
1236 hdawrite(Audio *adev, void *vp, long n, vlong)
1245 ring = &ctlr->sout.ring;
1247 if((n = writering(ring, p, e - p)) <= 0){
1249 sleep(&ring->r, outavail, ring);
1255 sleep(&ring->r, outrate, ctlr);
1256 return p - (uchar*)vp;
1260 hdaclose(Audio *adev, int mode)
1266 if(mode == OREAD || mode == ORDWR){
1267 if(ctlr->sin.active)
1268 streamstop(ctlr, &ctlr->sin);
1270 if(mode == OWRITE || mode == ORDWR){
1271 if(ctlr->sout.active){
1273 while(ctlr->sout.ring.wi % Blocksize)
1274 hdawrite(adev, z, sizeof(z), 0);
1287 static Volume voltab[] = {
1288 [Vmaster] "master", 0, 0x7f, Stereo, 0,
1289 [Vrecord] "record", 0, 0x7f, Stereo, 0,
1290 [Vspeed] "speed", 0, 0, Absolute, 0,
1291 [Vdelay] "delay", 0, 0, Absolute, 0,
1296 hdagetvol(Audio *adev, int x, int a[2])
1298 Ctlr *ctlr = adev->ctlr;
1302 if(ctlr->sout.conv != nil)
1303 getoutamp(ctlr->sout.conv, a);
1316 hdasetvol(Audio *adev, int x, int a[2])
1318 Ctlr *ctlr = adev->ctlr;
1322 if(ctlr->sout.conv != nil)
1323 setoutamp(ctlr->sout.conv, 0, a);
1326 if(ctlr->sin.conv != nil)
1327 setinamp(ctlr->sin.conv, nil, 0, a);
1340 fillvoltab(Ctlr *ctlr, Volume *vt)
1342 memmove(vt, voltab, sizeof(voltab));
1343 if(ctlr->sout.conv != nil)
1344 vt[Vmaster].range = getoutamprange(ctlr->sout.conv);
1348 hdavolread(Audio *adev, void *a, long n, vlong)
1350 Volume voltab[Nvol+1];
1351 fillvoltab(adev->ctlr, voltab);
1352 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1356 hdavolwrite(Audio *adev, void *a, long n, vlong)
1358 Volume voltab[Nvol+1];
1359 fillvoltab(adev->ctlr, voltab);
1360 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1364 hdainterrupt(Ureg *, void *arg)
1374 sts = csr32(ctlr, Intsts);
1375 if(sts & ctlr->sout.sdintr){
1376 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
1378 r = &ctlr->sout.ring;
1379 r->ri = streampos(ctlr, &ctlr->sout);
1380 if(ctlr->sout.active && buffered(r) < Blocksize){
1381 streamstop(ctlr, &ctlr->sout);
1382 r->ri = r->wi = streampos(ctlr, &ctlr->sout);
1386 if(sts & ctlr->sin.sdintr){
1387 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
1389 r = &ctlr->sin.ring;
1390 r->wi = streampos(ctlr, &ctlr->sin);
1391 if(ctlr->sin.active && available(r) < Blocksize){
1392 streamstop(ctlr, &ctlr->sin);
1393 r->ri = r->wi = streampos(ctlr, &ctlr->sin);
1401 hdastatus(Audio *adev, void *a, long n, vlong)
1403 Ctlr *ctlr = adev->ctlr;
1413 s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->sout.ring));
1414 for(i=0; i<Maxcodecs; i++){
1415 if((codec = ctlr->codec[i]) == nil)
1417 s = seprint(s, e, "codec %2d pin %3d inpin %3d\n",
1418 codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
1419 for(fg=codec->fgroup; fg; fg=fg->next){
1420 for(w=fg->first; w; w=w->next){
1424 s = seprint(s, e, "pin %3d %s%s %s %s %s %s %s%s%s\n",
1426 (w->pincap & Pin) != 0 ? "in" : "",
1427 (w->pincap & Pout) != 0 ? "out" : "",
1428 pinport[(r >> 30) & 0x3],
1429 pinloc2[(r >> 28) & 0x3],
1430 pinloc[(r >> 24) & 0xf],
1431 pinfunc[(r >> 20) & 0xf],
1432 pincol[(r >> 12) & 0xf],
1433 (w->pincap & Phdmi) ? " hdmi" : "",
1434 (w->pincap & Peapd) ? " eapd" : ""
1440 s = seprint(s, e, "outpath ");
1441 for(w=ctlr->sout.conv; w != nil; w = w->path){
1442 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1443 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1444 if(w == ctlr->sout.jack)
1446 s = seprint(s, e, " → ");
1448 s = seprint(s, e, "\n");
1450 s = seprint(s, e, "inpath ");
1451 for(w=ctlr->sin.jack; w != nil; w = w->path){
1452 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1453 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1454 if(w == ctlr->sin.conv)
1456 s = seprint(s, e, " → ");
1458 s = seprint(s, e, "\n");
1460 return s - (char*)a;
1465 hdastart(Ctlr *ctlr)
1467 static int cmdbufsize[] = { 2, 16, 256, 2048 };
1471 /* reset controller */
1472 csr32(ctlr, Gctl) &= ~Rst;
1473 waitup32(ctlr, Gctl, Rst, 0);
1474 microdelay(Codecdelay);
1475 csr32(ctlr, Gctl) |= Rst;
1476 if(waitup32(ctlr, Gctl, Rst, Rst) &&
1477 waitup32(ctlr, Gctl, Rst, Rst)){
1478 print("#A%d: hda failed to reset\n", ctlr->no);
1481 microdelay(Codecdelay);
1483 ctlr->codecmask = csr16(ctlr, Statests);
1484 if(ctlr->codecmask == 0){
1485 print("#A%d: hda no codecs\n", ctlr->no);
1489 cap = csr16(ctlr, Gcap);
1490 ctlr->bss = (cap>>3) & 0x1F;
1491 ctlr->iss = (cap>>8) & 0xF;
1492 ctlr->oss = (cap>>12) & 0xF;
1494 csr8(ctlr, Corbctl) = 0;
1495 waitup8(ctlr, Corbctl, Corbdma, 0);
1497 csr8(ctlr, Rirbctl) = 0;
1498 waitup8(ctlr, Rirbctl, Rirbdma, 0);
1500 /* alloc command buffers */
1501 size = csr8(ctlr, Corbsz);
1502 n = cmdbufsize[size & 3];
1503 ctlr->corb = xspanalloc(n * 4, 128, 0);
1504 memset(ctlr->corb, 0, n * 4);
1507 size = csr8(ctlr, Rirbsz);
1508 n = cmdbufsize[size & 3];
1509 ctlr->rirb = xspanalloc(n * 8, 128, 0);
1510 memset(ctlr->rirb, 0, n * 8);
1513 /* setup controller */
1514 csr32(ctlr, Dplbase) = 0;
1515 csr32(ctlr, Dpubase) = 0;
1516 csr16(ctlr, Statests) = csr16(ctlr, Statests);
1517 csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1520 csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1521 csr32(ctlr, Corbubase) = 0;
1522 csr16(ctlr, Corbwp) = 0;
1523 csr16(ctlr, Corbrp) = Corbptrrst;
1524 waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1525 csr16(ctlr, Corbrp) = 0;
1526 waitup16(ctlr, Corbrp, Corbptrrst, 0);
1527 csr8(ctlr, Corbctl) = Corbdma;
1528 waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1531 csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1532 csr32(ctlr, Rirbubase) = 0;
1533 csr16(ctlr, Rirbwp) = Rirbptrrst;
1534 csr8(ctlr, Rirbctl) = Rirbdma;
1535 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1537 /* enable interrupts */
1538 csr32(ctlr, Intctl) |= Gie | Cie;
1546 while(p = pcimatch(p, 0, 0))
1547 switch((p->vid << 16) | p->did){
1548 case (0x8086 << 16) | 0x2668: /* Intel ICH6 (untested) */
1549 case (0x8086 << 16) | 0x27d8: /* Intel ICH7 */
1550 case (0x8086 << 16) | 0x269a: /* Intel ESB2 (untested) */
1551 case (0x8086 << 16) | 0x284b: /* Intel ICH8 */
1552 case (0x8086 << 16) | 0x293f: /* Intel ICH9 (untested) */
1553 case (0x8086 << 16) | 0x293e: /* Intel P35 (untested) */
1554 case (0x8086 << 16) | 0x811b: /* Intel SCH (Poulsbo) */
1555 case (0x8086 << 16) | 0x080a: /* Intel SCH (Oaktrail) */
1556 case (0x8086 << 16) | 0x1c20: /* Intel PCH */
1557 case (0x8086 << 16) | 0x1e20: /* Intel (Thinkpad x230t) */
1559 case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1560 case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1561 case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1562 case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1563 case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1564 case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1566 case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1567 case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1568 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1570 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1571 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1572 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1579 hdacmdread(Chan *, void *a, long n, vlong)
1588 return qread(ctlr->q, a, n);
1592 hdacmdwrite(Chan *, void *a, long n, vlong)
1606 for(i=0; i<n/4; i++){
1607 if(hdacmd(ctlr, lp[i], w) <= 0){
1611 qproduce(ctlr->q, w, sizeof(w));
1618 hdareset(Audio *adev)
1620 static Ctlr *cards = nil;
1621 int irq, tbdf, best, cad;
1625 /* make a list of all cards if not already done */
1628 while(p = hdamatch(p)){
1629 ctlr = mallocz(sizeof(Ctlr), 1);
1631 print("hda: can't allocate memory\n");
1640 /* pick a card from the list */
1641 for(ctlr = cards; ctlr; ctlr = ctlr->next){
1642 if(p = ctlr->pcidev){
1656 if(p->vid == 0x10de){
1657 /* magic for NVidia */
1658 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1660 if(p->vid == 0x10b9){
1662 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1663 pcicfgw32(p, PciBAR1, 0);
1665 if(p->vid == 0x8086){
1666 /* magic for Intel */
1668 case 0x1c20: /* PCH */
1669 case 0x811b: /* SCH */
1671 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1674 if(p->vid == 0x1002){
1676 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1679 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1685 ctlr->no = adev->ctlrno;
1686 ctlr->size = p->mem[0].size;
1687 ctlr->q = qopen(256, 0, 0, 0);
1688 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1689 if(ctlr->mem == nil){
1690 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1693 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1695 if(hdastart(ctlr) < 0){
1696 print("#A%d: unable to start hda\n", ctlr->no);
1699 if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0){
1700 print("#A%d: output streamalloc failed\n", ctlr->no);
1704 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1705 print("#A%d: input streamalloc failed\n", ctlr->no);
1706 if(enumdev(ctlr) < 0){
1707 print("#A%d: no audio codecs found\n", ctlr->no);
1710 best = bestpin(ctlr, &cad);
1712 print("#A%d: no output pins found!\n", ctlr->no);
1715 if(connectpin(ctlr, &ctlr->sout, Waout, best, cad) < 0){
1716 print("#A%d: error connecting pin\n", ctlr->no);
1720 adev->read = hdaread;
1721 adev->write = hdawrite;
1722 adev->close = hdaclose;
1723 adev->buffered = hdabuffered;
1724 adev->volread = hdavolread;
1725 adev->volwrite = hdavolwrite;
1726 adev->status = hdastatus;
1729 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1731 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1739 addaudiocard("hda", hdareset);