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)
892 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
894 jack = ctlr->codec[cad]->widgets[pin];
897 if(jack->type != Wpin)
900 conv = findpath(jack, type);
904 if(s->conv != nil && s->jack != nil){
905 if(s->conv->type == Waout)
906 disconnectpath(s->conv, s->jack);
908 disconnectpath(s->jack, s->conv);
909 cmd(s->conv->id, Setstream, 0);
910 cmd(s->jack->id, Setpinctl, 0);
914 connectpath(conv, jack);
915 cmd(jack->id, Setpinctl, Pinctlout);
917 connectpath(jack, conv);
918 cmd(jack->id, Setpinctl, Pinctlin);
921 cmd(conv->id, Setconvfmt, s->afmt);
922 cmd(conv->id, Setstream, (s->atag << 4) | 0);
923 cmd(conv->id, Setchancnt, 1);
939 if((w->pincap & Pout) == 0)
941 if(w->id.ctlr->sin.jack == w)
946 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
948 if(((r >> 12) & 0xf) == 4) /* green */
950 if(((r >> 24) & 0xf) == 1) /* rear */
952 if(((r >> 28) & 0x3) == 0) /* ext */
954 if(((r >> 20) & 0xf) == 2) /* hpout */
956 if(((r >> 20) & 0xf) == 0) /* lineout */
967 if((w->pincap & Pin) == 0)
969 if(w->id.ctlr->sout.jack == w)
974 if(((r >> 30) & 0x3) >= 2) /* fix or fix+jack */
980 bestpin(Ctlr *ctlr, int *pcad, int (*fscore)(Widget *))
984 int best, pin, score;
989 for(i=0; i<Maxcodecs; i++){
990 if(ctlr->codec[i] == nil)
992 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
993 for(w=fg->first; w; w=w->next){
996 score = (*fscore)(w);
997 if(score >= 0 && score >= best){
1018 return r->nbuf - (ri - wi);
1026 m = (r->nbuf - BytesPerSample) - buffered(r);
1033 readring(Ring *r, uchar *p, long n)
1039 if((m = buffered(r)) <= 0)
1044 if(r->ri + m > r->nbuf)
1045 m = r->nbuf - r->ri;
1046 memmove(p, r->buf + r->ri, m);
1049 r->ri = (r->ri + m) % r->nbuf;
1056 writering(Ring *r, uchar *p, long n)
1062 if((m = available(r)) <= 0)
1067 if(r->wi + m > r->nbuf)
1068 m = r->nbuf - r->wi;
1069 memmove(r->buf + r->wi, p, m);
1072 r->wi = (r->wi + m) % r->nbuf;
1079 streamalloc(Ctlr *ctlr, Stream *s, int num)
1085 r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
1086 s->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
1087 if(r->buf == nil || s->blds == nil){
1088 print("hda: no memory for stream\n");
1091 for(i=0; i<Nblocks; i++){
1092 s->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
1093 s->blds[i].addrhi = 0;
1094 s->blds[i].len = Blocksize;
1095 s->blds[i].flags = 0x01; /* interrupt on completion */
1099 s->sdctl = Sdctl0 + s->sdnum*0x20;
1100 s->sdintr = 1<<s->sdnum;
1101 s->atag = s->sdnum+1;
1102 s->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
1106 csr8(ctlr, s->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
1107 csr8(ctlr, s->sdctl) |= Srst;
1108 microdelay(Codecdelay);
1109 waitup8(ctlr, s->sdctl, Srst, Srst);
1110 csr8(ctlr, s->sdctl) &= ~Srst;
1111 microdelay(Codecdelay);
1112 waitup8(ctlr, s->sdctl, Srst, 0);
1114 /* set stream number */
1115 csr32(ctlr, s->sdctl) = (s->atag << Stagbit) |
1116 (csr32(ctlr, s->sdctl) & ~(0xF << Stagbit));
1118 /* set stream format */
1119 csr16(ctlr, Sdfmt+s->sdctl) = s->afmt;
1121 /* program stream DMA & parms */
1122 csr32(ctlr, Sdbdplo+s->sdctl) = PADDR(s->blds);
1123 csr32(ctlr, Sdbdphi+s->sdctl) = 0;
1124 csr32(ctlr, Sdcbl+s->sdctl) = r->nbuf;
1125 csr16(ctlr, Sdlvi+s->sdctl) = (Nblocks - 1) & 0xff;
1128 csr8(ctlr, Sdsts+s->sdctl) = Scompl | Sfifoerr | Sdescerr;
1130 /* enable global intrs for this stream */
1131 csr32(ctlr, Intctl) |= s->sdintr;
1132 csr8(ctlr, s->sdctl) |= Scie | Seie | Sdie;
1138 streamstart(Ctlr *ctlr, Stream *s)
1141 csr8(ctlr, s->sdctl) |= Srun;
1142 waitup8(ctlr, s->sdctl, Srun, Srun);
1146 streamstop(Ctlr *ctlr, Stream *s)
1148 csr8(ctlr, s->sdctl) &= ~Srun;
1149 waitup8(ctlr, s->sdctl, Srun, 0);
1154 streampos(Ctlr *ctlr, Stream *s)
1158 p = csr32(ctlr, Sdlpib+s->sdctl);
1159 if(p >= s->ring.nbuf)
1165 hdactl(Audio *adev, void *va, long n, vlong)
1167 char *p, *e, *x, *tok[4];
1176 for(; p < e; p = x){
1177 if(x = strchr(p, '\n'))
1181 ntok = tokenize(p, tok, 4);
1184 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1185 cad = ctlr->sout.cad;
1186 pin = strtoul(tok[1], 0, 0);
1188 cad = strtoul(tok[2], 0, 0);
1189 if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad) < 0)
1190 error("connectpin failed");
1192 if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
1193 cad = ctlr->sin.cad;
1194 pin = strtoul(tok[1], 0, 0);
1196 cad = strtoul(tok[2], 0, 0);
1197 if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad) < 0)
1198 error("connectpin failed");
1209 return buffered(r) > 0;
1216 return available(r) > 0;
1223 int delay = ctlr->adev->delay*BytesPerSample;
1224 return (delay <= 0) || (buffered(&ctlr->sout.ring) <= delay) || (ctlr->sout.active == 0);
1228 hdabuffered(Audio *adev)
1232 return buffered(&ctlr->sout.ring);
1238 if(ctlr->sout.active)
1240 if(buffered(&ctlr->sout.ring) > Blocksize)
1241 streamstart(ctlr, &ctlr->sout);
1245 hdaread(Audio *adev, void *vp, long n, vlong)
1254 ring = &ctlr->sin.ring;
1255 if(ring->buf == nil || ctlr->sin.conv == nil)
1258 if((n = readring(ring, p, e - p)) <= 0){
1259 if(!ctlr->sin.active)
1260 streamstart(ctlr, &ctlr->sin);
1261 sleep(&ring->r, inavail, ring);
1266 return p - (uchar*)vp;
1270 hdawrite(Audio *adev, void *vp, long n, vlong)
1279 ring = &ctlr->sout.ring;
1280 if(ring->buf == nil || ctlr->sout.conv == nil)
1283 if((n = writering(ring, p, e - p)) <= 0){
1285 sleep(&ring->r, outavail, ring);
1291 while(outrate(ctlr) == 0)
1292 sleep(&ring->r, outrate, ctlr);
1293 return p - (uchar*)vp;
1297 hdaclose(Audio *adev, int mode)
1303 if(mode == OREAD || mode == ORDWR){
1304 if(ctlr->sin.active)
1305 streamstop(ctlr, &ctlr->sin);
1307 if(mode == OWRITE || mode == ORDWR){
1308 ring = &ctlr->sout.ring;
1309 while(ring->wi % Blocksize)
1310 if(writering(ring, (uchar*)"", 1) <= 0)
1323 static Volume voltab[] = {
1324 [Vmaster] "master", 0, 0x7f, Stereo, 0,
1325 [Vrecord] "recgain", 0, 0x7f, Stereo, 0,
1326 [Vspeed] "speed", 0, 0, Absolute, 0,
1327 [Vdelay] "delay", 0, 0, Absolute, 0,
1332 hdagetvol(Audio *adev, int x, int a[2])
1334 Ctlr *ctlr = adev->ctlr;
1338 if(ctlr->sout.conv != nil)
1339 getoutamp(ctlr->sout.conv, a);
1352 hdasetvol(Audio *adev, int x, int a[2])
1354 Ctlr *ctlr = adev->ctlr;
1358 if(ctlr->sout.conv != nil)
1359 setoutamp(ctlr->sout.conv, 0, a);
1362 if(ctlr->sin.conv != nil)
1363 setinamp(ctlr->sin.conv, nil, 0, a);
1376 fillvoltab(Ctlr *ctlr, Volume *vt)
1378 memmove(vt, voltab, sizeof(voltab));
1379 if(ctlr->sout.conv != nil)
1380 vt[Vmaster].range = getoutamprange(ctlr->sout.conv);
1384 hdavolread(Audio *adev, void *a, long n, vlong)
1386 Volume voltab[Nvol+1];
1387 fillvoltab(adev->ctlr, voltab);
1388 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1392 hdavolwrite(Audio *adev, void *a, long n, vlong)
1394 Volume voltab[Nvol+1];
1395 fillvoltab(adev->ctlr, voltab);
1396 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1400 hdainterrupt(Ureg *, void *arg)
1410 sts = csr32(ctlr, Intsts);
1411 if(sts & ctlr->sout.sdintr){
1412 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
1414 r = &ctlr->sout.ring;
1415 r->ri = streampos(ctlr, &ctlr->sout);
1416 if(ctlr->sout.active && buffered(r) < Blocksize){
1417 streamstop(ctlr, &ctlr->sout);
1418 r->ri = r->wi = streampos(ctlr, &ctlr->sout);
1422 if(sts & ctlr->sin.sdintr){
1423 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
1425 r = &ctlr->sin.ring;
1426 r->wi = streampos(ctlr, &ctlr->sin);
1427 if(ctlr->sin.active && available(r) < Blocksize){
1428 streamstop(ctlr, &ctlr->sin);
1429 r->ri = r->wi = streampos(ctlr, &ctlr->sin);
1437 hdastatus(Audio *adev, void *a, long n, vlong)
1439 Ctlr *ctlr = adev->ctlr;
1449 s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->sout.ring));
1450 for(i=0; i<Maxcodecs; i++){
1451 if((codec = ctlr->codec[i]) == nil)
1453 s = seprint(s, e, "codec %2d pin %3d inpin %3d\n",
1454 codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
1455 for(fg=codec->fgroup; fg; fg=fg->next){
1456 for(w=fg->first; w; w=w->next){
1460 s = seprint(s, e, "pin %3d %s%s %s %s %s %s %s%s%s\n",
1462 (w->pincap & Pin) != 0 ? "in" : "",
1463 (w->pincap & Pout) != 0 ? "out" : "",
1464 pinport[(r >> 30) & 0x3],
1465 pinloc2[(r >> 28) & 0x3],
1466 pinloc[(r >> 24) & 0xf],
1467 pinfunc[(r >> 20) & 0xf],
1468 pincol[(r >> 12) & 0xf],
1469 (w->pincap & Phdmi) ? " hdmi" : "",
1470 (w->pincap & Peapd) ? " eapd" : ""
1476 s = seprint(s, e, "outpath ");
1477 for(w=ctlr->sout.conv; w != nil; w = w->path){
1478 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1479 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1480 if(w == ctlr->sout.jack)
1482 s = seprint(s, e, " → ");
1484 s = seprint(s, e, "\n");
1486 s = seprint(s, e, "inpath ");
1487 for(w=ctlr->sin.jack; w != nil; w = w->path){
1488 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1489 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1490 if(w == ctlr->sin.conv)
1492 s = seprint(s, e, " → ");
1494 s = seprint(s, e, "\n");
1496 return s - (char*)a;
1501 hdastart(Ctlr *ctlr)
1503 static int cmdbufsize[] = { 2, 16, 256, 2048 };
1507 /* reset controller */
1508 csr32(ctlr, Gctl) &= ~Rst;
1509 waitup32(ctlr, Gctl, Rst, 0);
1510 microdelay(Codecdelay);
1511 csr32(ctlr, Gctl) |= Rst;
1512 if(waitup32(ctlr, Gctl, Rst, Rst) &&
1513 waitup32(ctlr, Gctl, Rst, Rst)){
1514 print("#A%d: hda failed to reset\n", ctlr->no);
1517 microdelay(Codecdelay);
1519 ctlr->codecmask = csr16(ctlr, Statests);
1520 if(ctlr->codecmask == 0){
1521 print("#A%d: hda no codecs\n", ctlr->no);
1525 cap = csr16(ctlr, Gcap);
1526 ctlr->bss = (cap>>3) & 0x1F;
1527 ctlr->iss = (cap>>8) & 0xF;
1528 ctlr->oss = (cap>>12) & 0xF;
1530 csr8(ctlr, Corbctl) = 0;
1531 waitup8(ctlr, Corbctl, Corbdma, 0);
1533 csr8(ctlr, Rirbctl) = 0;
1534 waitup8(ctlr, Rirbctl, Rirbdma, 0);
1536 /* alloc command buffers */
1537 size = csr8(ctlr, Corbsz);
1538 n = cmdbufsize[size & 3];
1539 ctlr->corb = xspanalloc(n * 4, 128, 0);
1540 memset(ctlr->corb, 0, n * 4);
1543 size = csr8(ctlr, Rirbsz);
1544 n = cmdbufsize[size & 3];
1545 ctlr->rirb = xspanalloc(n * 8, 128, 0);
1546 memset(ctlr->rirb, 0, n * 8);
1549 /* setup controller */
1550 csr32(ctlr, Dplbase) = 0;
1551 csr32(ctlr, Dpubase) = 0;
1552 csr16(ctlr, Statests) = csr16(ctlr, Statests);
1553 csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1556 csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1557 csr32(ctlr, Corbubase) = 0;
1558 csr16(ctlr, Corbwp) = 0;
1559 csr16(ctlr, Corbrp) = Corbptrrst;
1560 waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1561 csr16(ctlr, Corbrp) = 0;
1562 waitup16(ctlr, Corbrp, Corbptrrst, 0);
1563 csr8(ctlr, Corbctl) = Corbdma;
1564 waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1567 csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1568 csr32(ctlr, Rirbubase) = 0;
1569 csr16(ctlr, Rirbwp) = Rirbptrrst;
1570 csr8(ctlr, Rirbctl) = Rirbdma;
1571 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1573 /* enable interrupts */
1574 csr32(ctlr, Intctl) |= Gie | Cie;
1582 while(p = pcimatch(p, 0, 0))
1583 switch((p->vid << 16) | p->did){
1584 case (0x8086 << 16) | 0x2668: /* Intel ICH6 (untested) */
1585 case (0x8086 << 16) | 0x27d8: /* Intel ICH7 */
1586 case (0x8086 << 16) | 0x269a: /* Intel ESB2 (untested) */
1587 case (0x8086 << 16) | 0x284b: /* Intel ICH8 */
1588 case (0x8086 << 16) | 0x293f: /* Intel ICH9 (untested) */
1589 case (0x8086 << 16) | 0x293e: /* Intel P35 (untested) */
1590 case (0x8086 << 16) | 0x3b56: /* Intel P55 (Ibex Peak) */
1591 case (0x8086 << 16) | 0x811b: /* Intel SCH (Poulsbo) */
1592 case (0x8086 << 16) | 0x080a: /* Intel SCH (Oaktrail) */
1593 case (0x8086 << 16) | 0x1c20: /* Intel PCH */
1594 case (0x8086 << 16) | 0x1e20: /* Intel (Thinkpad x230t) */
1596 case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1597 case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1598 case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1599 case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1600 case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1601 case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1603 case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1604 case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1605 case (0x1002 << 16) | 0xaa55: /* ATI HDMI (8500 series) */
1606 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1608 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1609 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1610 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1617 hdacmdread(Chan *, void *a, long n, vlong)
1626 return qread(ctlr->q, a, n);
1630 hdacmdwrite(Chan *, void *a, long n, vlong)
1644 for(i=0; i<n/4; i++){
1645 if(hdacmd(ctlr, lp[i], w) <= 0){
1649 qproduce(ctlr->q, w, sizeof(w));
1656 hdareset(Audio *adev)
1658 static Ctlr *cards = nil;
1659 int irq, tbdf, best, cad;
1663 /* make a list of all cards if not already done */
1666 while(p = hdamatch(p)){
1667 ctlr = mallocz(sizeof(Ctlr), 1);
1669 print("hda: can't allocate memory\n");
1678 /* pick a card from the list */
1679 for(ctlr = cards; ctlr; ctlr = ctlr->next){
1680 if(p = ctlr->pcidev){
1694 if(p->vid == 0x10de){
1695 /* magic for NVidia */
1696 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1698 if(p->vid == 0x10b9){
1700 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1701 pcicfgw32(p, PciBAR1, 0);
1703 if(p->vid == 0x8086){
1704 /* magic for Intel */
1706 case 0x1c20: /* PCH */
1707 case 0x811b: /* SCH */
1709 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1712 if(p->vid == 0x1002){
1714 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1717 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1723 ctlr->no = adev->ctlrno;
1724 ctlr->size = p->mem[0].size;
1725 ctlr->q = qopen(256, 0, 0, 0);
1726 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1727 if(ctlr->mem == nil){
1728 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1731 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1733 if(hdastart(ctlr) < 0){
1734 print("#A%d: unable to start hda\n", ctlr->no);
1738 /* iss + oss + bss */
1739 if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1740 print("#A%d: output streamalloc failed\n", ctlr->no);
1742 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1743 print("#A%d: input streamalloc failed\n", ctlr->no);
1745 else if(ctlr->bss > 0){
1747 if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1748 print("#A%d: input streamalloc failed\n", ctlr->no);
1749 } else if(ctlr->bss > 1) {
1750 if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1751 print("#A%d: input streamalloc failed\n", ctlr->no);
1755 if(enumdev(ctlr) < 0){
1756 print("#A%d: no audio codecs found\n", ctlr->no);
1760 best = bestpin(ctlr, &cad, scoreout);
1762 print("#A%d: no output pins found\n", ctlr->no);
1763 else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad) < 0)
1764 print("#A%d: error connecting output pin\n", ctlr->no);
1766 best = bestpin(ctlr, &cad, scorein);
1768 print("#A%d: no input pins found\n", ctlr->no);
1769 else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad) < 0)
1770 print("#A%d: error connecting input pin\n", ctlr->no);
1772 adev->read = hdaread;
1773 adev->write = hdawrite;
1774 adev->close = hdaclose;
1775 adev->buffered = hdabuffered;
1776 adev->volread = hdavolread;
1777 adev->volwrite = hdavolwrite;
1778 adev->status = hdastatus;
1781 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1783 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1791 addaudiocard("hda", hdareset);