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 */
167 Getunsolresp = 0xf08,
168 Setunsolresp = 0x708,
182 /* 4-bit cmd + 16-bit payload */
237 uint convrate, convfmt;
257 Widget *widgets[Maxwidgets];
261 /* hardware structures */
274 Lock; /* interrupt lock */
275 QLock; /* command lock */
300 Codec *codec[Maxcodecs];
310 #define csr32(c, r) (*(ulong *)&(c)->mem[r])
311 #define csr16(c, r) (*(ushort *)&(c)->mem[r])
312 #define csr8(c, r) (*(uchar *)&(c)->mem[r])
314 static char *pinport[] = {
321 static char *pinfunc[] = {
341 static char *pincol[] = {
360 static char *pinloc[] = {
379 static char *pinloc2[] = {
389 waitup8(Ctlr *ctlr, int reg, uchar mask, uchar set)
392 for(i=0; i<Maxwaitup; i++){
393 if((csr8(ctlr, reg) & mask) == set)
397 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
398 ctlr->no, reg, mask, set);
403 waitup16(Ctlr *ctlr, int reg, ushort mask, ushort set)
406 for(i=0; i<Maxwaitup; i++){
407 if((csr16(ctlr, reg) & mask) == set)
411 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
412 ctlr->no, reg, mask, set);
417 waitup32(Ctlr *ctlr, int reg, uint mask, uint set)
420 for(i=0; i<Maxwaitup; i++){
421 if((csr32(ctlr, reg) & mask) == set)
425 print("#A%d: waitup timeout for reg=%x, mask=%x, set=%x\n",
426 ctlr->no, reg, mask, set);
431 hdacmd(Ctlr *ctlr, uint request, uint reply[2])
437 re = csr16(ctlr, Rirbwp);
438 rp = csr16(ctlr, Corbrp);
439 wp = (csr16(ctlr, Corbwp) + 1) % ctlr->corbsize;
441 print("#A%d: corb full\n", ctlr->no);
444 ctlr->corb[wp] = request;
446 csr16(ctlr, Corbwp) = wp;
447 for(wait=0; wait < Maxrirbwait; wait++){
448 if(csr16(ctlr, Rirbwp) != re){
449 re = (re + 1) % ctlr->rirbsize;
450 memmove(reply, &ctlr->rirb[re*2], 8);
459 cmderr(Id id, uint verb, uint par, uint *ret)
462 q = (id.codec << 28) | (id.nid << 20);
463 if((verb & 0x700) == 0x700)
464 q |= (verb << 8) | par;
466 q |= (verb << 16) | par;
467 if(hdacmd(id.ctlr, q, w) != 1)
476 cmd(Id id, uint verb, uint par)
479 if(cmderr(id, verb, par, w) == -1)
485 newnid(Id id, uint nid)
492 getoutamprange(Widget *w)
495 r = cmd(w->id, Getparm, Outampcap);
496 return (r >> 8) & 0x7f;
500 getoutamp(Widget *w, int vol[2])
503 if((w->cap & Woutampcap) == 0)
505 vol[0] = cmd(w->id, Getamp, Agetout | Agetleft) & Againmask;
506 vol[1] = cmd(w->id, Getamp, Agetout | Agetright) & Againmask;
509 /* vol is 0...range or nil for 0dB; mute is 0/1 */
511 setoutamp(Widget *w, int mute, int *vol)
516 if((w->cap & Woutampcap) == 0)
519 r = cmd(w->id, Getparm, Outampcap);
523 q = Asetout | (i == 0 ? Asetleft : Asetright);
527 q |= zerodb << Again;
529 q |= vol[i] << Again;
530 cmd(w->id, Setamp, q);
534 /* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
536 setinamp(Widget *w, Widget *in, int mute, int *vol)
541 if((w->cap & Winampcap) == 0)
544 r = cmd(w->id, Getparm, Inampcap);
548 q = Asetin | (i == 0 ? Asetleft : Asetright);
552 q |= zerodb << Again;
554 q |= vol[i] << Again;
555 for(j=0; j<w->nlist; j++){
556 if(in == nil || w->list[j] == in)
557 cmd(w->id, Setamp, q | (j << Asetidx));
563 findpath(Widget *src)
565 Widget *q[Maxwidgets];
571 for(w=src->fg->first; w; w=w->next)
579 for(i=0; i<w->nlist; i++){
581 if(v == nil || v->from)
593 connectpath(Widget *src, Widget *dst, uint stream)
598 for(w=src->fg->first; w != nil; w=w->next){
599 setoutamp(w, 1, nil);
600 setinamp(w, nil, 1, nil);
601 cmd(w->id, Setstream, 0);
603 for(w=dst; w != src; w=v){
605 setoutamp(w, 0, nil);
606 setinamp(v, w, 0, nil);
607 if(v->type == Waout || v->type == Wamix)
611 for(i=0; i < v->nlist && v->list[i] != w; i++)
613 cmd(v->id, Setconn, i);
615 setoutamp(src, 0, nil);
616 cmd(src->id, Setpinctl, Pinctlout);
617 cmd(dst->id, Setstream, (stream << 4) | 0);
618 cmd(dst->id, Setconvfmt, (1 << 14) | (1 << 4) | 1);
619 cmd(dst->id, Setchancnt, 1);
623 addconn(Widget *w, uint nid)
627 if(nid >= Maxwidgets)
629 if((src = w->fg->codec->widgets[nid]) == nil)
631 for(nid=0; nid<w->nlist; nid++)
632 if(w->list[nid] == src)
634 if((w->nlist % 16) == 0){
637 if((p = realloc(w->list, sizeof(Widget*) * (w->nlist+16))) == nil){
638 print("hda: no memory for Widgetlist\n");
643 w->list[w->nlist++] = src;
649 uint r, f, b, m, i, n, x, y;
651 r = cmd(w->id, Getparm, Connlistlen);
653 b = (r & 0x80) ? 16 : 8;
661 r = cmd(w->id, Getconnlist, i);
663 if(i && ((r & m) != y))
672 enumwidget(Widget *w)
674 w->cap = cmd(w->id, Getparm, Widgetcap);
675 w->type = (w->cap >> 20) & 0x7;
681 w->pin = cmd(w->id, Getdefault, 0);
682 w->pincap = cmd(w->id, Getparm, Pincap);
688 enumfungroup(Codec *codec, Id id)
694 r = cmd(id, Getparm, Fungrtype) & 0x7f;
698 fg = mallocz(sizeof *fg, 1);
701 print("hda: enumfungroup: out of memory\n");
708 r = cmd(id, Getparm, Subnodecnt);
710 base = (r >> 16) & 0xff;
712 if(base + n > Maxwidgets){
719 w = mallocz(sizeof(Widget), 1);
721 while(w = fg->first){
723 codec->widgets[w->id.nid] = nil;
729 w->id = newnid(id, base + i);
731 codec->widgets[base + i] = w;
737 enumwidget(codec->widgets[base + i]);
744 enumcodec(Codec *codec, Id id)
750 if(cmderr(id, Getparm, Vendorid, &vid) < 0)
752 if(cmderr(id, Getparm, Revid, &rid) < 0)
759 print("#A%d: codec #%d, vendor %08x, rev %08x\n",
760 id.ctlr->no, codec->id.codec, codec->vid, codec->rid);
762 r = cmd(id, Getparm, Subnodecnt);
764 base = (r >> 16) & 0xff;
767 fg = enumfungroup(codec, newnid(id, base + i));
770 fg->next = codec->fgroup;
773 if(codec->fgroup == nil)
789 for(i=0; i<Maxcodecs; i++){
790 if(((1<<i) & ctlr->codecmask) == 0)
792 codec = mallocz(sizeof(Codec), 1);
794 print("hda: no memory for Codec\n");
798 ctlr->codec[i] = codec;
799 if(enumcodec(codec, id) < 0){
800 ctlr->codec[i] = nil;
810 connectpin(Ctlr *ctlr, uint pin, uint cad)
814 if(cad >= Maxcodecs || pin >= Maxwidgets || ctlr->codec[cad] == nil)
816 src = ctlr->codec[cad]->widgets[pin];
819 if(src->type != Wpin)
821 if((src->pincap & Pout) == 0)
826 connectpath(src, dst, ctlr->atag);
835 bestpin(Ctlr *ctlr, int *pcad)
839 int best, pin, score;
845 for(i=0; i<Maxcodecs; i++){
846 if(ctlr->codec[i] == nil)
848 for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
849 for(w=fg->first; w; w=w->next){
852 if((w->pincap & Pout) == 0)
856 if(((r >> 12) & 0xf) == 4) /* green */
858 if(((r >> 24) & 0xf) == 1) /* rear */
860 if(((r >> 28) & 0x3) == 0) /* ext */
862 if(((r >> 20) & 0xf) == 2) /* hpout */
864 if(((r >> 20) & 0xf) == 0) /* lineout */
887 return r->nbuf - (ri - wi);
895 m = (r->nbuf - BytesPerSample) - buffered(r);
902 writering(Ring *r, uchar *p, long n)
908 if((m = available(r)) <= 0)
913 if(r->wi + m > r->nbuf)
915 memmove(r->buf + r->wi, p, m);
918 r->wi = (r->wi + m) % r->nbuf;
925 streamalloc(Ctlr *ctlr)
931 memset(r, 0, sizeof(*r));
932 r->buf = xspanalloc(r->nbuf = Bufsize, 128, 0);
933 ctlr->blds = xspanalloc(Nblocks * sizeof(Bld), 128, 0);
934 if(r->buf == nil || ctlr->blds == nil){
935 print("hda: no memory for stream\n");
938 for(i=0; i<Nblocks; i++){
939 ctlr->blds[i].addrlo = PADDR(r->buf) + i*Blocksize;
940 ctlr->blds[i].addrhi = 0;
941 ctlr->blds[i].len = Blocksize;
942 ctlr->blds[i].flags = 0x01; /* interrupt on completion */
945 /* output dma engine starts after inputs */
946 ctlr->sdnum = ctlr->iss;
947 ctlr->sdctl = Sdctl0 + ctlr->sdnum*0x20;
948 ctlr->sdintr = 1<<ctlr->sdnum;
949 ctlr->atag = ctlr->sdnum+1;
950 ctlr->afmt = Fmtstereo | Fmtsampw | Fmtdiv1 | Fmtmul1 | Fmtbase441;
954 csr8(ctlr, ctlr->sdctl) &= ~(Srst | Srun | Scie | Seie | Sdie);
955 csr8(ctlr, ctlr->sdctl) |= Srst;
956 microdelay(Codecdelay);
957 waitup8(ctlr, ctlr->sdctl, Srst, Srst);
958 csr8(ctlr, ctlr->sdctl) &= ~Srst;
959 microdelay(Codecdelay);
960 waitup8(ctlr, ctlr->sdctl, Srst, 0);
962 /* set stream number */
963 csr32(ctlr, ctlr->sdctl) = (ctlr->atag << Stagbit) |
964 (csr32(ctlr, ctlr->sdctl) & ~(0xF << Stagbit));
966 /* set stream format */
967 csr16(ctlr, Sdfmt+ctlr->sdctl) = ctlr->afmt;
969 /* program stream DMA & parms */
970 csr32(ctlr, Sdbdplo+ctlr->sdctl) = PADDR(ctlr->blds);
971 csr32(ctlr, Sdbdphi+ctlr->sdctl) = 0;
972 csr32(ctlr, Sdcbl+ctlr->sdctl) = r->nbuf;
973 csr16(ctlr, Sdlvi+ctlr->sdctl) = (Nblocks - 1) & 0xff;
976 csr8(ctlr, Sdsts+ctlr->sdctl) = Scompl | Sfifoerr | Sdescerr;
978 /* enable global intrs for this stream */
979 csr32(ctlr, Intctl) |= ctlr->sdintr;
980 csr8(ctlr, ctlr->sdctl) |= Scie | Seie | Sdie;
986 streamstart(Ctlr *ctlr)
990 csr8(ctlr, ctlr->sdctl) |= Srun;
991 waitup8(ctlr, ctlr->sdctl, Srun, Srun);
995 streamstop(Ctlr *ctlr)
997 csr8(ctlr, ctlr->sdctl) &= ~Srun;
998 waitup8(ctlr, ctlr->sdctl, Srun, 0);
1004 streampos(Ctlr *ctlr)
1010 p = csr32(ctlr, Sdlpib+ctlr->sdctl);
1017 hdactl(Audio *adev, void *va, long n, vlong)
1019 char *p, *e, *x, *tok[4];
1028 for(; p < e; p = x){
1029 if(x = strchr(p, '\n'))
1033 ntok = tokenize(p, tok, 4);
1036 if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
1038 pin = strtoul(tok[1], 0, 0);
1040 cad = strtoul(tok[2], 0, 0);
1041 connectpin(ctlr, pin, cad);
1052 return available(&ctlr->ring) > 0;
1059 int delay = ctlr->adev->delay*BytesPerSample;
1060 return (delay <= 0) || (buffered(&ctlr->ring) <= delay) || (ctlr->active == 0);
1064 hdabuffered(Audio *adev)
1068 return buffered(&ctlr->ring);
1076 if(buffered(&ctlr->ring) > Blocksize)
1081 hdawrite(Audio *adev, void *vp, long n, vlong)
1092 if((n = writering(ring, p, e - p)) <= 0){
1094 sleep(&ring->r, outavail, ctlr);
1100 sleep(&ring->r, outrate, ctlr);
1101 return p - (uchar*)vp;
1105 hdaclose(Audio *adev)
1116 while(r->wi % Blocksize)
1117 hdawrite(adev, z, sizeof(z), 0);
1127 static Volume voltab[] = {
1128 [Vmaster] "master", 0, 0x7f, Stereo, 0,
1129 [Vspeed] "speed", 0, 0, Absolute, 0,
1130 [Vdelay] "delay", 0, 0, Absolute, 0,
1135 hdagetvol(Audio *adev, int x, int a[2])
1137 Ctlr *ctlr = adev->ctlr;
1141 if(ctlr->amp != nil)
1142 getoutamp(ctlr->amp, a);
1155 hdasetvol(Audio *adev, int x, int a[2])
1157 Ctlr *ctlr = adev->ctlr;
1161 if(ctlr->amp != nil)
1162 setoutamp(ctlr->amp, 0, a);
1175 fillvoltab(Ctlr *ctlr, Volume *vt)
1177 memmove(vt, voltab, sizeof(voltab));
1178 if(ctlr->amp != nil)
1179 vt[Vmaster].range = getoutamprange(ctlr->amp);
1183 hdavolread(Audio *adev, void *a, long n, vlong)
1185 Volume voltab[Nvol+1];
1186 fillvoltab(adev->ctlr, voltab);
1187 return genaudiovolread(adev, a, n, 0, voltab, hdagetvol, 0);
1191 hdavolwrite(Audio *adev, void *a, long n, vlong)
1193 Volume voltab[Nvol+1];
1194 fillvoltab(adev->ctlr, voltab);
1195 return genaudiovolwrite(adev, a, n, 0, voltab, hdasetvol, 0);
1199 hdainterrupt(Ureg *, void *arg)
1210 sts = csr32(ctlr, Intsts);
1211 if(sts & ctlr->sdintr){
1213 csr8(ctlr, Sdsts+ctlr->sdctl) |= Scompl;
1215 r->ri = streampos(ctlr);
1216 if(ctlr->active && buffered(r) < Blocksize){
1218 r->ri = r->wi = streampos(ctlr);
1226 hdastatus(Audio *adev, void *a, long n, vlong)
1228 Ctlr *ctlr = adev->ctlr;
1237 k = snprint(s, n, "bufsize %6d buffered %6ld\n", Blocksize, buffered(&ctlr->ring));
1238 for(i=0; i<Maxcodecs; i++){
1239 if((codec = ctlr->codec[i]) == nil)
1241 k += snprint(s+k, n-k, "codec %2d pin %3d\n",
1242 codec->id.codec, ctlr->pin);
1243 for(fg=codec->fgroup; fg; fg=fg->next){
1244 for(w=fg->first; w; w=w->next){
1248 k += snprint(s+k, n-k, "pin %3d %s %s %s %s %s %s\n",
1250 (w->pincap & Pout) != 0 ? "out" : "in",
1251 pinport[(r >> 30) & 0x3],
1252 pinloc2[(r >> 28) & 0x3],
1253 pinloc[(r >> 24) & 0xf],
1254 pinfunc[(r >> 20) & 0xf],
1255 pincol[(r >> 12) & 0xf]
1265 hdastart(Ctlr *ctlr)
1267 static int cmdbufsize[] = { 2, 16, 256, 2048 };
1271 /* reset controller */
1272 csr32(ctlr, Gctl) &= ~Rst;
1273 waitup32(ctlr, Gctl, Rst, 0);
1274 microdelay(Codecdelay);
1275 csr32(ctlr, Gctl) |= Rst;
1276 if(waitup32(ctlr, Gctl, Rst, Rst) &&
1277 waitup32(ctlr, Gctl, Rst, Rst)){
1278 print("#A%d: hda failed to reset\n", ctlr->no);
1281 microdelay(Codecdelay);
1283 ctlr->codecmask = csr16(ctlr, Statests);
1284 if(ctlr->codecmask == 0){
1285 print("#A%d: hda no codecs\n", ctlr->no);
1289 cap = csr16(ctlr, Gcap);
1290 ctlr->bss = (cap>>3) & 0x1F;
1291 ctlr->iss = (cap>>8) & 0xF;
1292 ctlr->oss = (cap>>12) & 0xF;
1294 csr8(ctlr, Corbctl) = 0;
1295 waitup8(ctlr, Corbctl, Corbdma, 0);
1297 csr8(ctlr, Rirbctl) = 0;
1298 waitup8(ctlr, Rirbctl, Rirbdma, 0);
1300 /* alloc command buffers */
1301 size = csr8(ctlr, Corbsz);
1302 n = cmdbufsize[size & 3];
1303 ctlr->corb = xspanalloc(n * 4, 128, 0);
1304 memset(ctlr->corb, 0, n * 4);
1307 size = csr8(ctlr, Rirbsz);
1308 n = cmdbufsize[size & 3];
1309 ctlr->rirb = xspanalloc(n * 8, 128, 0);
1310 memset(ctlr->rirb, 0, n * 8);
1313 /* setup controller */
1314 csr32(ctlr, Dplbase) = 0;
1315 csr32(ctlr, Dpubase) = 0;
1316 csr16(ctlr, Statests) = csr16(ctlr, Statests);
1317 csr8(ctlr, Rirbsts) = csr8(ctlr, Rirbsts);
1320 csr32(ctlr, Corblbase) = PADDR(ctlr->corb);
1321 csr32(ctlr, Corbubase) = 0;
1322 csr16(ctlr, Corbwp) = 0;
1323 csr16(ctlr, Corbrp) = Corbptrrst;
1324 waitup16(ctlr, Corbrp, Corbptrrst, Corbptrrst);
1325 csr16(ctlr, Corbrp) = 0;
1326 waitup16(ctlr, Corbrp, Corbptrrst, 0);
1327 csr8(ctlr, Corbctl) = Corbdma;
1328 waitup8(ctlr, Corbctl, Corbdma, Corbdma);
1331 csr32(ctlr, Rirblbase) = PADDR(ctlr->rirb);
1332 csr32(ctlr, Rirbubase) = 0;
1333 csr16(ctlr, Rirbwp) = Rirbptrrst;
1334 csr8(ctlr, Rirbctl) = Rirbdma;
1335 waitup8(ctlr, Rirbctl, Rirbdma, Rirbdma);
1337 /* enable interrupts */
1338 csr32(ctlr, Intctl) |= Gie | Cie;
1346 while(p = pcimatch(p, 0, 0))
1347 switch((p->vid << 16) | p->did){
1348 case (0x8086 << 16) | 0x27d8:
1349 case (0x1002 << 16) | 0x4383: /* ATI */
1350 case (0x1002 << 16) | 0x7919: /* ATI HDMI */
1357 hdacmdread(Chan *, void *a, long n, vlong)
1366 return qread(ctlr->q, a, n);
1370 hdacmdwrite(Chan *, void *a, long n, vlong)
1384 for(i=0; i<n/4; i++){
1385 if(hdacmd(ctlr, lp[i], w) <= 0){
1389 qproduce(ctlr->q, w, sizeof(w));
1396 hdareset(Audio *adev)
1398 static Ctlr *cards = nil;
1399 int irq, tbdf, best, cad;
1403 /* make a list of all cards if not already done */
1406 while(p = hdamatch(p)){
1407 ctlr = xspanalloc(sizeof(Ctlr), 8, 0);
1408 memset(ctlr, 0, sizeof(Ctlr));
1415 /* pick a card from the list */
1416 for(ctlr = cards; ctlr; ctlr = ctlr->next){
1417 if(p = ctlr->pcidev){
1432 if(p->vid == 0x1002)
1433 pcicfgw8(p, 0x42, pcicfgr8(p, 0x42) | 2);
1438 ctlr->no = adev->ctlrno;
1439 ctlr->size = p->mem[0].size;
1440 ctlr->q = qopen(256, 0, 0, 0);
1441 ctlr->mem = vmap(p->mem[0].bar & ~0x0F, ctlr->size);
1442 if(ctlr->mem == nil){
1443 print("#A%d: can't map %.8lux\n", ctlr->no, p->mem[0].bar);
1446 print("#A%d: hda mem %p irq %d\n", ctlr->no, ctlr->mem, irq);
1448 if(hdastart(ctlr) < 0){
1449 print("#A%d: unable to start hda\n", ctlr->no);
1452 if(streamalloc(ctlr) < 0){
1453 print("#A%d: streamalloc failed\n", ctlr->no);
1456 if(enumdev(ctlr) < 0){
1457 print("#A%d: no audio codecs found\n", ctlr->no);
1460 best = bestpin(ctlr, &cad);
1462 print("#A%d: no output pins found!\n", ctlr->no);
1465 if(connectpin(ctlr, best, cad) < 0){
1466 print("#A%d: error connecting pin\n", ctlr->no);
1470 adev->write = hdawrite;
1471 adev->close = hdaclose;
1472 adev->buffered = hdabuffered;
1473 adev->volread = hdavolread;
1474 adev->volwrite = hdavolwrite;
1475 adev->status = hdastatus;
1478 intrenable(irq, hdainterrupt, adev, tbdf, "hda");
1480 addarchfile("hdacmd", 0664, hdacmdread, hdacmdwrite);
1488 addaudiocard("hda", hdareset);