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;
15 typedef struct Widget Widget;
16 typedef struct Codec Codec;
17 typedef struct Fungroup Fungroup;
18 typedef struct Pinprop Pinprop;
65 /* Warning: Sdctl is 24bit register */
97 Bufsize = 64 * 1024 * 4,
99 Blocksize = Bufsize / Nblocks,
102 Maxrirbwait = 1000, /* microseconds */
103 Maxwaitup = 500, /* microseconds */
104 Codecdelay = 1000, /* microseconds */
108 /* 12-bit cmd + 8-bit payload */
171 Getunsolresp = 0xf08,
172 Setunsolresp = 0x708,
190 /* 4-bit cmd + 16-bit payload */
245 uint convrate, convfmt;
265 Widget *widgets[Maxwidgets];
269 /* hardware structures */
282 Lock; /* interrupt lock */
283 QLock; /* command lock */
308 Codec *codec[Maxcodecs];
318 #define csr32(c, r) (*(ulong *)&(c)->mem[r])
319 #define csr16(c, r) (*(ushort *)&(c)->mem[r])
320 #define csr8(c, r) (*(uchar *)&(c)->mem[r])
322 static char *widtype[] = {
333 static char *pinport[] = {
340 static char *pinfunc[] = {
360 static char *pincol[] = {
379 static char *pinloc[] = {
398 static char *pinloc2[] = {
408 waitup8(Ctlr *ctlr, int reg, uchar mask, uchar set)
411 for(i=0; i<Maxwaitup; i++){
412 if((csr8(ctlr, reg) & mask) == set)
416 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
417 ctlr->no, reg, mask, set);
422 waitup16(Ctlr *ctlr, int reg, ushort mask, ushort set)
425 for(i=0; i<Maxwaitup; i++){
426 if((csr16(ctlr, reg) & mask) == set)
430 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
431 ctlr->no, reg, mask, set);
436 waitup32(Ctlr *ctlr, int reg, uint mask, uint set)
439 for(i=0; i<Maxwaitup; i++){
440 if((csr32(ctlr, reg) & mask) == set)
444 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
445 ctlr->no, reg, mask, set);
450 hdacmd(Ctlr *ctlr, uint request, uint reply[2])
456 re = csr16(ctlr, Rirbwp);
457 rp = csr16(ctlr, Corbrp);
458 wp = (csr16(ctlr, Corbwp) + 1) % ctlr->corbsize;
460 print("#A%d: corb full\n", ctlr->no);
463 ctlr->corb[wp] = request;
465 csr16(ctlr, Corbwp) = wp;
466 for(wait=0; wait < Maxrirbwait; wait++){
467 if(csr16(ctlr, Rirbwp) != re){
468 re = (re + 1) % ctlr->rirbsize;
469 memmove(reply, &ctlr->rirb[re*2], 8);
478 cmderr(Id id, uint verb, uint par, uint *ret)
481 q = (id.codec << 28) | (id.nid << 20);
482 if((verb & 0x700) == 0x700)
483 q |= (verb << 8) | par;
485 q |= (verb << 16) | par;
486 if(hdacmd(id.ctlr, q, w) != 1)
495 cmd(Id id, uint verb, uint par)
498 if(cmderr(id, verb, par, w) == -1)
504 newnid(Id id, uint nid)
511 getoutamprange(Widget *w)
515 if((w->cap & Woutampcap) == 0)
517 if((w->cap & Wampovrcap) == 0)
518 r = cmd(w->fg->id, Getparm, Outampcap);
520 r = cmd(w->id, Getparm, Outampcap);
521 return (r >> 8) & 0x7f;
525 getoutamp(Widget *w, int vol[2])
528 if((w->cap & Woutampcap) == 0)
530 vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
531 vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
534 /* vol is 0...range or nil for 0dB; mute is 0/1 */
536 setoutamp(Widget *w, int mute, int *vol)
541 if((w->cap & Woutampcap) == 0)
543 if((w->cap & Wampovrcap) == 0)
544 r = cmd(w->fg->id, Getparm, Outampcap);
546 r = cmd(w->id, Getparm, Outampcap);
550 q = Asetout | (i == 0 ? Asetleft : Asetright);
554 q |= zerodb << Again;
556 q |= vol[i] << Again;
557 cmd(w->id, Setamp, q);
561 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
563 setinamp(Widget *w, Widget *in, int mute, int *vol)
568 if((w->cap & Winampcap) == 0)
570 if((w->cap & Wampovrcap) == 0)
571 r = cmd(w->fg->id, Getparm, Inampcap);
573 r = cmd(w->id, Getparm, Inampcap);
577 q = Asetin | (i == 0 ? Asetleft : Asetright);
581 q |= zerodb << Again;
583 q |= vol[i] << Again;
584 for(j=0; j<w->nlist; j++){
585 if(in == nil || w->list[j] == in)
586 cmd(w->id, Setamp, q | (j << Asetidx));
592 findpath(Widget *src)
594 Widget *q[Maxwidgets];
600 for(w=src->fg->first; w; w=w->next)
608 for(i=0; i<w->nlist; i++){
610 if(v == nil || v->from)
622 connectpath(Widget *src, Widget *dst)
627 for(w=dst; w != src; w=v){
629 setoutamp(w, 0, nil);
630 setinamp(v, w, 0, nil);
633 for(i=0; i < v->nlist; i++)
635 cmd(v->id, Setconn, i);
639 setoutamp(src, 0, nil);
640 cmd(src->id, Setpinctl, Pinctlout);
644 addconn(Widget *w, uint nid)
650 src = w->fg->codec->widgets[nid];
651 if(src == nil || (src->fg != w->fg)){
652 print("hda: invalid connection %d:%s[%d] -> %d\n",
653 w->id.nid, widtype[w->type & 7], w->nlist, nid);
656 if((w->nlist % 16) == 0){
659 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
660 print("hda: no memory for Widgetlist\n");
665 w->list[w->nlist++] = src;
672 uint r, f, b, m, i, n, x, y;
674 if((w->cap & Wconncap) == 0)
677 r = cmd(w->id, Getparm, Connlistlen);
679 b = (r & 0x80) ? 16 : 8;
687 r = cmd(w->id, Getconnlist, i);
689 if(i && (r & m) != y)
698 enumwidget(Widget *w)
700 w->cap = cmd(w->id, Getparm, Widgetcap);
701 w->type = (w->cap >> 20) & 0x7;
703 cmd(w->id, Setpower, 0);
709 w->pin = cmd(w->id, Getdefault, 0);
710 w->pincap = cmd(w->id, Getparm, Pincap);
711 if(w->pincap & Peapd)
712 cmd(w->id, Seteapd, Eapdenable);
718 enumfungroup(Codec *codec, Id id)
724 r = cmd(id, Getparm, Fungrtype) & 0x7f;
726 cmd(id, Setpower, 3); /* turn off */
731 cmd(id, Setpower, 0);
734 fg = mallocz(sizeof *fg, 1);
737 print("hda: enumfungroup: out of memory\n");
744 r = cmd(id, Getparm, Subnodecnt);
746 base = (r >> 16) & 0xff;
748 if(base + n > Maxwidgets){
755 w = mallocz(sizeof(Widget), 1);
757 while(w = fg->first){
759 codec->widgets[w->id.nid] = nil;
765 w->id = newnid(id, base + i);
769 codec->widgets[w->id.nid] = w;
773 enumwidget(codec->widgets[base + i]);
780 enumcodec(Codec *codec, Id id)
786 if(cmderr(id, Getparm, Vendorid, &vid) < 0)
788 if(cmderr(id, Getparm, Revid, &rid) < 0)
795 r = cmd(id, Getparm, Subnodecnt);
797 base = (r >> 16) & 0xff;
800 fg = enumfungroup(codec, newnid(id, base + i));
803 fg->next = codec->fgroup;
806 if(codec->fgroup == nil)
809 print("#A%d: codec #%d, vendor %08ux, rev %08ux\n",
810 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
826 for(i=0; i<Maxcodecs; i++){
827 if(((1<<i) & ctlr->codecmask) == 0)
829 codec = mallocz(sizeof(Codec), 1);
831 print("hda: no memory for Codec\n");
835 ctlr->codec[i] = codec;
836 if(enumcodec(codec, id) < 0){
837 ctlr->codec[i] = nil;
847 connectpin(Ctlr *ctlr, uint pin, uint cad)
849 Widget *w, *src, *dst;
851 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
853 src = ctlr->codec[cad]->widgets[pin];
856 if(src->type != Wpin)
858 if((src->pincap & Pout) == 0)
865 /* mute all widgets, clear stream */
866 for(w=src->fg->first; w != nil; w=w->next){
867 setoutamp(w, 1, nil);
868 setinamp(w, nil, 1, nil);
869 cmd(w->id, Setstream, 0);
872 connectpath(src, dst);
874 cmd(dst->id, Setconvfmt, ctlr->afmt);
875 cmd(dst->id, Setstream, (ctlr->atag << 4) | 0);
876 cmd(dst->id, Setchancnt, 1);
886 bestpin(Ctlr *ctlr, int *pcad)
890 int best, pin, score;
896 for(i=0; i<Maxcodecs; i++){
897 if(ctlr->codec[i] == nil)
899 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
900 for(w=fg->first; w; w=w->next){
903 if((w->pincap & Pout) == 0)
907 if(((r >> 12) & 0xf) == 4) /* green */
909 if(((r >> 24) & 0xf) == 1) /* rear */
911 if(((r >> 28) & 0x3) == 0) /* ext */
913 if(((r >> 20) & 0xf) == 2) /* hpout */
915 if(((r >> 20) & 0xf) == 0) /* lineout */
938 return r->nbuf - (ri - wi);
946 m = (r->nbuf - BytesPerSample) - buffered(r);
953 writering(Ring *r, uchar *p, long n)
959 if((m = available(r)) <= 0)
964 if(r->wi + m > r->nbuf)
966 memmove(r->buf + r->wi, p, m);
969 r->wi = (r->wi + m) % r->nbuf;
976 streamalloc(Ctlr *ctlr)
982 memset(r, 0, sizeof(*r));
983 r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
984 ctlr->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
985 if(r->buf == nil || ctlr->blds == nil){
986 print("hda: no memory for stream\n");
989 for(i=0; i<Nblocks; i++){
990 ctlr->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
991 ctlr->blds[i].addrhi = 0;
992 ctlr->blds[i].len = Blocksize;
993 ctlr->blds[i].flags = 0x01; /* interrupt on completion */
996 /* output dma engine starts after inputs */
997 ctlr->sdnum = ctlr->iss;
998 ctlr->sdctl = Sdctl0 + ctlr->sdnum*0x20;
999 ctlr->sdintr = 1<<ctlr->sdnum;
1000 ctlr->atag = ctlr->sdnum+1;
1001 ctlr->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
1005 csr8(ctlr, ctlr->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
1006 csr8(ctlr, ctlr->sdctl) |= Srst;
1007 microdelay(Codecdelay);
1008 waitup8(ctlr, ctlr->sdctl, Srst, Srst);
1009 csr8(ctlr, ctlr->sdctl) &= ~Srst;
1010 microdelay(Codecdelay);
1011 waitup8(ctlr, ctlr->sdctl, Srst, 0);
1013 /* set stream number */
1014 csr32(ctlr, ctlr->sdctl) = (ctlr->atag << Stagbit) |
1015 (csr32(ctlr, ctlr->sdctl) & ~(0xF << Stagbit));
1017 /* set stream format */
1018 csr16(ctlr, Sdfmt+ctlr->sdctl) = ctlr->afmt;
1020 /* program stream DMA & parms */
1021 csr32(ctlr, Sdbdplo+ctlr->sdctl) = PADDR(ctlr->blds);
1022 csr32(ctlr, Sdbdphi+ctlr->sdctl) = 0;
1023 csr32(ctlr, Sdcbl+ctlr->sdctl) = r->nbuf;
1024 csr16(ctlr, Sdlvi+ctlr->sdctl) = (Nblocks - 1) & 0xff;
1027 csr8(ctlr, Sdsts+ctlr->sdctl) = Scompl | Sfifoerr | Sdescerr;
1029 /* enable global intrs for this stream */
1030 csr32(ctlr, Intctl) |= ctlr->sdintr;
1031 csr8(ctlr, ctlr->sdctl) |= Scie | Seie | Sdie;
1037 streamstart(Ctlr *ctlr)
1041 csr8(ctlr, ctlr->sdctl) |= Srun;
1042 waitup8(ctlr, ctlr->sdctl, Srun, Srun);
1046 streamstop(Ctlr *ctlr)
1048 csr8(ctlr, ctlr->sdctl) &= ~Srun;
1049 waitup8(ctlr, ctlr->sdctl, Srun, 0);
1055 streampos(Ctlr *ctlr)
1061 p = csr32(ctlr, Sdlpib+ctlr->sdctl);
1068 hdactl(Audio *adev, void *va, long n, vlong)
1070 char *p, *e, *x, *tok[4];
1079 for(; p < e; p = x){
1080 if(x = strchr(p, '\n'))
1084 ntok = tokenize(p, tok, 4);
1087 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1089 pin = strtoul(tok[1], 0, 0);
1091 cad = strtoul(tok[2], 0, 0);
1092 connectpin(ctlr, pin, cad);
1103 return available(&ctlr->ring) > 0;
1110 int delay = ctlr->adev->delay*BytesPerSample;
1111 return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || (ctlr->active == 0);
1115 hdabuffered(Audio *adev)
1119 return buffered(&ctlr->ring);
1127 if(buffered(&ctlr->ring) > Blocksize)
1132 hdawrite(Audio *adev, void *vp, long n, vlong)
1143 if((n = writering(ring, p, e - p)) <= 0){
1145 sleep(&ring->r, outavail, ctlr);
1151 sleep(&ring->r, outrate, ctlr);
1152 return p - (uchar*)vp;
1156 hdaclose(Audio *adev)
1167 while(r->wi % Blocksize)
1168 hdawrite(adev, z, sizeof(z), 0);
1178 static Volume voltab[] = {
1179 [Vmaster] "master", 0, 0x7f, Stereo, 0,
1180 [Vspeed] "speed", 0, 0, Absolute, 0,
1181 [Vdelay] "delay", 0, 0, Absolute, 0,
1186 hdagetvol(Audio *adev, int x, int a[2])
1188 Ctlr *ctlr = adev->ctlr;
1192 if(ctlr->amp != nil)
1193 getoutamp(ctlr->amp, a);
1206 hdasetvol(Audio *adev, int x, int a[2])
1208 Ctlr *ctlr = adev->ctlr;
1212 if(ctlr->amp != nil)
1213 setoutamp(ctlr->amp, 0, a);
1226 fillvoltab(Ctlr *ctlr, Volume *vt)
1228 memmove(vt, voltab, sizeof(voltab));
1229 if(ctlr->amp != nil)
1230 vt[Vmaster].range = getoutamprange(ctlr->amp);
1234 hdavolread(Audio *adev, void *a, long n, vlong)
1236 Volume voltab[Nvol+1];
1237 fillvoltab(adev->ctlr, voltab);
1238 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1242 hdavolwrite(Audio *adev, void *a, long n, vlong)
1244 Volume voltab[Nvol+1];
1245 fillvoltab(adev->ctlr, voltab);
1246 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1250 hdainterrupt(Ureg *, void *arg)
1261 sts = csr32(ctlr, Intsts);
1262 if(sts & ctlr->sdintr){
1264 csr8(ctlr, Sdsts+ctlr->sdctl) |= Scompl;
1266 r->ri = streampos(ctlr);
1267 if(ctlr->active && buffered(r) < Blocksize){
1269 r->ri = r->wi = streampos(ctlr);
1277 hdastatus(Audio *adev, void *a, long n, vlong)
1279 Ctlr *ctlr = adev->ctlr;
1289 s = seprint(s, e, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->ring));
1290 for(i=0; i<Maxcodecs; i++){
1291 if((codec = ctlr->codec[i]) == nil)
1293 s = seprint(s, e, "codec %2d pin %3d\n",
1294 codec->id.codec, ctlr->pin);
1295 for(fg=codec->fgroup; fg; fg=fg->next){
1296 for(w=fg->first; w; w=w->next){
1300 s = seprint(s, e, "pin %3d %s %s %s %s %s %s%s%s\n",
1302 (w->pincap & Pout) != 0 ? "out" : "in",
1303 pinport[(r >> 30) & 0x3],
1304 pinloc2[(r >> 28) & 0x3],
1305 pinloc[(r >> 24) & 0xf],
1306 pinfunc[(r >> 20) & 0xf],
1307 pincol[(r >> 12) & 0xf],
1308 (w->pincap & Phdmi) ? " hdmi" : "",
1309 (w->pincap & Peapd) ? " eapd" : ""
1315 s = seprint(s, e, "path ");
1316 for(w=ctlr->amp; w != nil; w = w->from){
1317 s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
1318 (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
1321 s = seprint(s, e, " → ");
1323 s = seprint(s, e, "\n");
1325 return s - (char*)a;
1330 hdastart(Ctlr *ctlr)
1332 static int cmdbufsize[] = { 2, 16, 256, 2048 };
1336 /* reset controller */
1337 csr32(ctlr, Gctl) &= ~Rst;
1338 waitup32(ctlr, Gctl, Rst, 0);
1339 microdelay(Codecdelay);
1340 csr32(ctlr, Gctl) |= Rst;
1341 if(waitup32(ctlr, Gctl, Rst, Rst) &&
1342 waitup32(ctlr, Gctl, Rst, Rst)){
1343 print("#A%d: hda failed to reset\n", ctlr->no);
1346 microdelay(Codecdelay);
1348 ctlr->codecmask = csr16(ctlr, Statests);
1349 if(ctlr->codecmask == 0){
1350 print("#A%d: hda no codecs\n", ctlr->no);
1354 cap = csr16(ctlr, Gcap);
1355 ctlr->bss = (cap>>3) & 0x1F;
1356 ctlr->iss = (cap>>8) & 0xF;
1357 ctlr->oss = (cap>>12) & 0xF;
1359 csr8(ctlr, Corbctl) = 0;
1360 waitup8(ctlr, Corbctl, Corbdma, 0);
1362 csr8(ctlr, Rirbctl) = 0;
1363 waitup8(ctlr, Rirbctl, Rirbdma, 0);
1365 /* alloc command buffers */
1366 size = csr8(ctlr, Corbsz);
1367 n = cmdbufsize[size & 3];
1368 ctlr->corb = xspanalloc(n * 4, 128, 0);
1369 memset(ctlr->corb, 0, n * 4);
1372 size = csr8(ctlr, Rirbsz);
1373 n = cmdbufsize[size & 3];
1374 ctlr->rirb = xspanalloc(n * 8, 128, 0);
1375 memset(ctlr->rirb, 0, n * 8);
1378 /* setup controller */
1379 csr32(ctlr, Dplbase) = 0;
1380 csr32(ctlr, Dpubase) = 0;
1381 csr16(ctlr, Statests) = csr16(ctlr, Statests);
1382 csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1385 csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1386 csr32(ctlr, Corbubase) = 0;
1387 csr16(ctlr, Corbwp) = 0;
1388 csr16(ctlr, Corbrp) = Corbptrrst;
1389 waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1390 csr16(ctlr, Corbrp) = 0;
1391 waitup16(ctlr, Corbrp, Corbptrrst, 0);
1392 csr8(ctlr, Corbctl) = Corbdma;
1393 waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1396 csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1397 csr32(ctlr, Rirbubase) = 0;
1398 csr16(ctlr, Rirbwp) = Rirbptrrst;
1399 csr8(ctlr, Rirbctl) = Rirbdma;
1400 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1402 /* enable interrupts */
1403 csr32(ctlr, Intctl) |= Gie | Cie;
1411 while(p = pcimatch(p, 0, 0))
1412 switch((p->vid << 16) | p->did){
1413 case (0x8086 << 16) | 0x2668: /* Intel ICH6 (untested) */
1414 case (0x8086 << 16) | 0x27d8: /* Intel ICH7 */
1415 case (0x8086 << 16) | 0x269a: /* Intel ESB2 (untested) */
1416 case (0x8086 << 16) | 0x284b: /* Intel ICH8 */
1417 case (0x8086 << 16) | 0x293f: /* Intel ICH9 (untested) */
1418 case (0x8086 << 16) | 0x293e: /* Intel P35 (untested) */
1419 case (0x8086 << 16) | 0x811b: /* Intel SCH (Poulsbo) */
1420 case (0x8086 << 16) | 0x080a: /* Intel SCH (Oaktrail) */
1421 case (0x8086 << 16) | 0x1c20: /* Intel PCH */
1422 case (0x8086 << 16) | 0x1e20: /* Intel (Thinkpad x230t) */
1424 case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
1425 case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
1426 case (0x10de << 16) | 0x03e4: /* NVidia MCP61 (untested) */
1427 case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
1428 case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
1429 case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
1431 case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
1432 case (0x1002 << 16) | 0x4383: /* ATI SB600 */
1433 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1435 case (0x1106 << 16) | 0x3288: /* VIA (untested) */
1436 case (0x1039 << 16) | 0x7502: /* SIS (untested) */
1437 case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
1444 hdacmdread(Chan *, void *a, long n, vlong)
1453 return qread(ctlr->q, a, n);
1457 hdacmdwrite(Chan *, void *a, long n, vlong)
1471 for(i=0; i<n/4; i++){
1472 if(hdacmd(ctlr, lp[i], w) <= 0){
1476 qproduce(ctlr->q, w, sizeof(w));
1483 hdareset(Audio *adev)
1485 static Ctlr *cards = nil;
1486 int irq, tbdf, best, cad;
1490 /* make a list of all cards if not already done */
1493 while(p = hdamatch(p)){
1494 ctlr = mallocz(sizeof(Ctlr), 1);
1496 print("hda: can't allocate memory\n");
1505 /* pick a card from the list */
1506 for(ctlr = cards; ctlr; ctlr = ctlr->next){
1507 if(p = ctlr->pcidev){
1521 if(p->vid == 0x10de){
1522 /* magic for NVidia */
1523 pcicfgw8(p, 0x4e, (pcicfgr8(p, 0x4e) & 0xf0) | 0x0f);
1525 if(p->vid == 0x10b9){
1527 pcicfgw16(p, 0x40, pcicfgr16(p, 0x40) | 0x10);
1528 pcicfgw32(p, PciBAR1, 0);
1530 if(p->vid == 0x8086){
1531 /* magic for Intel */
1533 case 0x1c20: /* PCH */
1534 case 0x811b: /* SCH */
1536 pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
1539 if(p->vid == 0x1002){
1541 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 0x02);
1544 pcicfgw8(p, 0x44, pcicfgr8(p, 0x44) & 0xf8);
1550 ctlr->no = adev->ctlrno;
1551 ctlr->size = p->mem[0].size;
1552 ctlr->q = qopen(256, 0, 0, 0);
1553 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1554 if(ctlr->mem == nil){
1555 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1558 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1560 if(hdastart(ctlr) < 0){
1561 print("#A%d: unable to start hda\n", ctlr->no);
1564 if(streamalloc(ctlr) < 0){
1565 print("#A%d: streamalloc failed\n", ctlr->no);
1568 if(enumdev(ctlr) < 0){
1569 print("#A%d: no audio codecs found\n", ctlr->no);
1572 best = bestpin(ctlr, &cad);
1574 print("#A%d: no output pins found!\n", ctlr->no);
1577 if(connectpin(ctlr, best, cad) < 0){
1578 print("#A%d: error connecting pin\n", ctlr->no);
1582 adev->write = hdawrite;
1583 adev->close = hdaclose;
1584 adev->buffered = hdabuffered;
1585 adev->volread = hdavolread;
1586 adev->volwrite = hdavolwrite;
1587 adev->status = hdastatus;
1590 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1592 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1600 addaudiocard("hda", hdareset);