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 sleep(&ring->r, outrate, ctlr);
1292 return p - (uchar*)vp;
1296 hdaclose(Audio *adev, int mode)
1302 if(mode == OREAD || mode == ORDWR){
1303 if(ctlr->sin.active)
1304 streamstop(ctlr, &ctlr->sin);
1306 if(mode == OWRITE || mode == ORDWR){
1307 ring = &ctlr->sout.ring;
1308 while(ring->wi % Blocksize)
1309 if(writering(ring, (uchar*)"", 1) <= 0)
1322 static Volume voltab[] = {
1323 [Vmaster] "master", 0, 0x7f, Stereo, 0,
1324 [Vrecord] "record", 0, 0x7f, Stereo, 0,
1325 [Vspeed] "speed", 0, 0, Absolute, 0,
1326 [Vdelay] "delay", 0, 0, Absolute, 0,
1331 hdagetvol(Audio *adev, int x, int a[2])
1333 Ctlr *ctlr = adev->ctlr;
1337 if(ctlr->sout.conv != nil)
1338 getoutamp(ctlr->sout.conv, a);
1351 hdasetvol(Audio *adev, int x, int a[2])
1353 Ctlr *ctlr = adev->ctlr;
1357 if(ctlr->sout.conv != nil)
1358 setoutamp(ctlr->sout.conv, 0, a);
1361 if(ctlr->sin.conv != nil)
1362 setinamp(ctlr->sin.conv, nil, 0, a);
1375 fillvoltab(Ctlr *ctlr, Volume *vt)
1377 memmove(vt, voltab, sizeof(voltab));
1378 if(ctlr->sout.conv != nil)
1379 vt[Vmaster].range = getoutamprange(ctlr->sout.conv);
1383 hdavolread(Audio *adev, void *a, long n, vlong)
1385 Volume voltab[Nvol+1];
1386 fillvoltab(adev->ctlr, voltab);
1387 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1391 hdavolwrite(Audio *adev, void *a, long n, vlong)
1393 Volume voltab[Nvol+1];
1394 fillvoltab(adev->ctlr, voltab);
1395 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1399 hdainterrupt(Ureg *, void *arg)
1409 sts = csr32(ctlr, Intsts);
1410 if(sts & ctlr->sout.sdintr){
1411 csr8(ctlr, Sdsts+ctlr->sout.sdctl) |= Scompl;
1413 r = &ctlr->sout.ring;
1414 r->ri = streampos(ctlr, &ctlr->sout);
1415 if(ctlr->sout.active && buffered(r) < Blocksize){
1416 streamstop(ctlr, &ctlr->sout);
1417 r->ri = r->wi = streampos(ctlr, &ctlr->sout);
1421 if(sts & ctlr->sin.sdintr){
1422 csr8(ctlr, Sdsts+ctlr->sin.sdctl) |= Scompl;
1424 r = &ctlr->sin.ring;
1425 r->wi = streampos(ctlr, &ctlr->sin);
1426 if(ctlr->sin.active && available(r) < Blocksize){
1427 streamstop(ctlr, &ctlr->sin);
1428 r->ri = r->wi = streampos(ctlr, &ctlr->sin);
1436 hdastatus(Audio *adev, void *a, long n, vlong)
1438 Ctlr *ctlr = adev->ctlr;
1448 s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->sout.ring));
1449 for(i=0; i<Maxcodecs; i++){
1450 if((codec = ctlr->codec[i]) == nil)
1452 s = seprint(s, e, "codec %2d pin %3d inpin %3d\n",
1453 codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
1454 for(fg=codec->fgroup; fg; fg=fg->next){
1455 for(w=fg->first; w; w=w->next){
1459 s = seprint(s, e, "pin %3d %s%s %s %s %s %s %s%s%s\n",
1461 (w->pincap & Pin) != 0 ? "in" : "",
1462 (w->pincap & Pout) != 0 ? "out" : "",
1463 pinport[(r >> 30) & 0x3],
1464 pinloc2[(r >> 28) & 0x3],
1465 pinloc[(r >> 24) & 0xf],
1466 pinfunc[(r >> 20) & 0xf],
1467 pincol[(r >> 12) & 0xf],
1468 (w->pincap & Phdmi) ? " hdmi" : "",
1469 (w->pincap & Peapd) ? " eapd" : ""
1475 s = seprint(s, e, "outpath ");
1476 for(w=ctlr->sout.conv; w != nil; w = w->path){
1477 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1478 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1479 if(w == ctlr->sout.jack)
1481 s = seprint(s, e, " → ");
1483 s = seprint(s, e, "\n");
1485 s = seprint(s, e, "inpath ");
1486 for(w=ctlr->sin.jack; w != nil; w = w->path){
1487 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1488 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1489 if(w == ctlr->sin.conv)
1491 s = seprint(s, e, " → ");
1493 s = seprint(s, e, "\n");
1495 return s - (char*)a;
1500 hdastart(Ctlr *ctlr)
1502 static int cmdbufsize[] = { 2, 16, 256, 2048 };
1506 /* reset controller */
1507 csr32(ctlr, Gctl) &= ~Rst;
1508 waitup32(ctlr, Gctl, Rst, 0);
1509 microdelay(Codecdelay);
1510 csr32(ctlr, Gctl) |= Rst;
1511 if(waitup32(ctlr, Gctl, Rst, Rst) &&
1512 waitup32(ctlr, Gctl, Rst, Rst)){
1513 print("#A%d: hda failed to reset\n", ctlr->no);
1516 microdelay(Codecdelay);
1518 ctlr->codecmask = csr16(ctlr, Statests);
1519 if(ctlr->codecmask == 0){
1520 print("#A%d: hda no codecs\n", ctlr->no);
1524 cap = csr16(ctlr, Gcap);
1525 ctlr->bss = (cap>>3) & 0x1F;
1526 ctlr->iss = (cap>>8) & 0xF;
1527 ctlr->oss = (cap>>12) & 0xF;
1529 csr8(ctlr, Corbctl) = 0;
1530 waitup8(ctlr, Corbctl, Corbdma, 0);
1532 csr8(ctlr, Rirbctl) = 0;
1533 waitup8(ctlr, Rirbctl, Rirbdma, 0);
1535 /* alloc command buffers */
1536 size = csr8(ctlr, Corbsz);
1537 n = cmdbufsize[size & 3];
1538 ctlr->corb = xspanalloc(n * 4, 128, 0);
1539 memset(ctlr->corb, 0, n * 4);
1542 size = csr8(ctlr, Rirbsz);
1543 n = cmdbufsize[size & 3];
1544 ctlr->rirb = xspanalloc(n * 8, 128, 0);
1545 memset(ctlr->rirb, 0, n * 8);
1548 /* setup controller */
1549 csr32(ctlr, Dplbase) = 0;
1550 csr32(ctlr, Dpubase) = 0;
1551 csr16(ctlr, Statests) = csr16(ctlr, Statests);
1552 csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1555 csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1556 csr32(ctlr, Corbubase) = 0;
1557 csr16(ctlr, Corbwp) = 0;
1558 csr16(ctlr, Corbrp) = Corbptrrst;
1559 waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1560 csr16(ctlr, Corbrp) = 0;
1561 waitup16(ctlr, Corbrp, Corbptrrst, 0);
1562 csr8(ctlr, Corbctl) = Corbdma;
1563 waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1566 csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1567 csr32(ctlr, Rirbubase) = 0;
1568 csr16(ctlr, Rirbwp) = Rirbptrrst;
1569 csr8(ctlr, Rirbctl) = Rirbdma;
1570 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1572 /* enable interrupts */
1573 csr32(ctlr, Intctl) |= Gie | Cie;
1581 while(p = pcimatch(p, 0, 0))
1582 switch((p->vid << 16) | p->did){
1583 case (0x8086 << 16) | 0x2668: /* Intel ICH6 (untested) */
1584 case (0x8086 << 16) | 0x27d8: /* Intel ICH7 */
1585 case (0x8086 << 16) | 0x269a: /* Intel ESB2 (untested) */
1586 case (0x8086 << 16) | 0x284b: /* Intel ICH8 */
1587 case (0x8086 << 16) | 0x293f: /* Intel ICH9 (untested) */
1588 case (0x8086 << 16) | 0x293e: /* Intel P35 (untested) */
1589 case (0x8086 << 16) | 0x811b: /* Intel SCH (Poulsbo) */
1590 case (0x8086 << 16) | 0x080a: /* Intel SCH (Oaktrail) */
1591 case (0x8086 << 16) | 0x1c20: /* Intel PCH */
1592 case (0x8086 << 16) | 0x1e20: /* Intel (Thinkpad x230t) */
1594 case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1595 case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1596 case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1597 case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1598 case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1599 case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1601 case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1602 case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1603 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1605 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1606 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1607 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1614 hdacmdread(Chan *, void *a, long n, vlong)
1623 return qread(ctlr->q, a, n);
1627 hdacmdwrite(Chan *, void *a, long n, vlong)
1641 for(i=0; i<n/4; i++){
1642 if(hdacmd(ctlr, lp[i], w) <= 0){
1646 qproduce(ctlr->q, w, sizeof(w));
1653 hdareset(Audio *adev)
1655 static Ctlr *cards = nil;
1656 int irq, tbdf, best, cad;
1660 /* make a list of all cards if not already done */
1663 while(p = hdamatch(p)){
1664 ctlr = mallocz(sizeof(Ctlr), 1);
1666 print("hda: can't allocate memory\n");
1675 /* pick a card from the list */
1676 for(ctlr = cards; ctlr; ctlr = ctlr->next){
1677 if(p = ctlr->pcidev){
1691 if(p->vid == 0x10de){
1692 /* magic for NVidia */
1693 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1695 if(p->vid == 0x10b9){
1697 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1698 pcicfgw32(p, PciBAR1, 0);
1700 if(p->vid == 0x8086){
1701 /* magic for Intel */
1703 case 0x1c20: /* PCH */
1704 case 0x811b: /* SCH */
1706 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1709 if(p->vid == 0x1002){
1711 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1714 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1720 ctlr->no = adev->ctlrno;
1721 ctlr->size = p->mem[0].size;
1722 ctlr->q = qopen(256, 0, 0, 0);
1723 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1724 if(ctlr->mem == nil){
1725 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1728 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1730 if(hdastart(ctlr) < 0){
1731 print("#A%d: unable to start hda\n", ctlr->no);
1735 /* iss + oss + bss */
1736 if(streamalloc(ctlr, &ctlr->sout, ctlr->iss) < 0)
1737 print("#A%d: output streamalloc failed\n", ctlr->no);
1739 if(streamalloc(ctlr, &ctlr->sin, 0) < 0)
1740 print("#A%d: input streamalloc failed\n", ctlr->no);
1742 else if(ctlr->bss > 0){
1744 if(streamalloc(ctlr, &ctlr->sin, ctlr->oss) < 0)
1745 print("#A%d: input streamalloc failed\n", ctlr->no);
1746 } else if(ctlr->bss > 1) {
1747 if(streamalloc(ctlr, &ctlr->sin, 1) < 0)
1748 print("#A%d: input streamalloc failed\n", ctlr->no);
1752 if(enumdev(ctlr) < 0){
1753 print("#A%d: no audio codecs found\n", ctlr->no);
1757 best = bestpin(ctlr, &cad, scoreout);
1759 print("#A%d: no output pins found\n", ctlr->no);
1760 else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad) < 0)
1761 print("#A%d: error connecting output pin\n", ctlr->no);
1763 best = bestpin(ctlr, &cad, scorein);
1765 print("#A%d: no input pins found\n", ctlr->no);
1766 else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad) < 0)
1767 print("#A%d: error connecting input pin\n", ctlr->no);
1769 adev->read = hdaread;
1770 adev->write = hdawrite;
1771 adev->close = hdaclose;
1772 adev->buffered = hdabuffered;
1773 adev->volread = hdavolread;
1774 adev->volwrite = hdavolwrite;
1775 adev->status = hdastatus;
1778 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1780 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1788 addaudiocard("hda", hdareset);