}
}
+static uint
+getinamprange(Widget *w)
+{
+ uint r;
+
+ if((w->cap & Winampcap) == 0)
+ return 0;
+ if((w->cap & Wampovrcap) == 0)
+ r = cmd(w->fg->id, Getparm, Inampcap);
+ else
+ r = cmd(w->id, Getparm, Inampcap);
+ return (r >> 8) & 0x7f;
+}
+
+static void
+getinamp(Widget *w, int vol[2])
+{
+ vol[0] = vol[1] = 0;
+ if((w->cap & Winampcap) == 0)
+ return;
+ vol[0] = cmd(w->id, Getamp, Agetin | Agetleft) & Againmask;
+ vol[1] = cmd(w->id, Getamp, Agetin | Agetright) & Againmask;
+}
+
/* vol is 0...range or nil for 0dB; mute is 0/1; in is widget or nil for all */
static void
setinamp(Widget *w, Widget *in, int mute, int *vol)
}
static Widget *
-findpath(Widget *jack, int type)
+findpath(Widget *jack, int type, char *route)
{
Widget *q[Maxwidgets];
uint l, r, i;
Widget *w, *to;
+ Fungroup *fg;
+
+ fg = jack->fg;
l = r = 0;
- for(w=jack->fg->first; w != nil; w = w->next)
+ for(w=fg->first; w != nil; w = w->next)
w->link = nil;
+ if(route != nil && *route != 0){
+ w = jack;
+ while(*route++ == ','){
+ i = strtoul(route, &route, 0);
+ if(i >= Maxwidgets)
+ return nil;
+ to = fg->codec->widgets[i];
+ if(to == nil || to->fg != fg || to->link != nil)
+ return nil;
+ if(type == Waout)
+ to->link = w;
+ else
+ w->link = to;
+ w = to;
+ }
+ if(w == jack || w->type != type)
+ w = nil;
+ return w;
+ }
+
if(type == Waout){
q[r++] = jack;
jack->link = jack;
} else {
- for(w=jack->fg->first; w != nil; w = w->next)
+ for(w=fg->first; w != nil; w = w->next)
if(w->type == type){
q[r++] = w;
w->link = w;
next = from->path;
from->path = nil;
setoutamp(from, 1, nil);
- setinamp(next, from, 1, nil);
+ if(next != nil)
+ setinamp(next, from, 1, nil);
}
setoutamp(to, 1, nil);
}
+static void
+muteall(Ctlr *ctlr)
+{
+ Fungroup *fg;
+ Widget *w;
+ int i;
+
+ for(i=0; i<Maxcodecs; i++){
+ if(ctlr->codec[i] == nil)
+ continue;
+ for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
+ for(w=fg->first; w != nil; w=w->next){
+ setinamp(w, nil, 1, nil);
+ setoutamp(w, 1, nil);
+ switch(w->type){
+ case Wain:
+ case Waout:
+ cmd(w->id, Setstream, 0);
+ break;
+ case Wpin:
+ cmd(w->id, Setpinctl, 0);
+ break;
+ }
+ }
+ }
+ }
+}
+
static void
connectpath(Widget *from, Widget *to)
{
next = from->link;
from->path = next;
setoutamp(from, 0, nil);
- setinamp(next, from, 0, nil);
- if(next->nlist == 1)
- continue;
- for(i=0; i < next->nlist; i++)
- if(next->list[i] == from){
- cmd(next->id, Setconn, i);
- break;
+ if(next != nil){
+ setinamp(next, from, 0, nil);
+ for(i=0; i < next->nlist; i++){
+ if(next->list[i] == from){
+ cmd(next->id, Setconn, i);
+ break;
+ }
}
+ }
}
setoutamp(to, 0, nil);
}
w->list = p;
}
w->list[w->nlist++] = src;
- return;
}
static void
{
w->cap = cmd(w->id, Getparm, Widgetcap);
w->type = (w->cap >> 20) & 0x7;
- if(w->cap & Wpwrcap)
+ if(w->cap & Wpwrcap){
cmd(w->id, Setpower, 0);
-
- enumconns(w);
-
+ delay(10);
+ }
switch(w->type){
case Wpin:
w->pin = cmd(w->id, Getdefault, 0);
/* open eyes */
cmd(id, Setpower, 0);
- microdelay(100);
+ delay(10);
+
+ r = cmd(id, Getparm, Subnodecnt);
+ n = r & 0xff;
+ base = (r >> 16) & 0xff;
+ if(base >= Maxwidgets){
+ print("hda: enumfungroup: base %d out of range\n", base);
+ return nil;
+ }
+ if(base+n > Maxwidgets){
+ print("hda: enumfungroup: widgets %d - %d out of range\n", base, base+n);
+ n = Maxwidgets - base;
+ }
fg = mallocz(sizeof *fg, 1);
if(fg == nil){
fg->id = id;
fg->type = r;
- r = cmd(id, Getparm, Subnodecnt);
- n = r & 0xff;
- base = (r >> 16) & 0xff;
-
- if(base + n > Maxwidgets){
- free(fg);
- return nil;
- }
-
tail = &fg->first;
for(i=0; i<n; i++){
+ if(codec->widgets[base + i] != nil){
+ print("hda: enumfungroup: duplicate widget %d\n", base + i);
+ continue;
+ }
w = mallocz(sizeof(Widget), 1);
if(w == nil){
while(w = fg->first){
for(i=0; i<n; i++)
enumwidget(codec->widgets[base + i]);
+ for(i=0; i<n; i++)
+ enumconns(codec->widgets[base + i]);
return fg;
}
-
static int
enumcodec(Codec *codec, Id id)
{
}
static int
-connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad)
+connectpin(Ctlr *ctlr, Stream *s, int type, uint pin, uint cad, char *route)
{
Widget *jack, *conv;
if(jack->type != Wpin)
return -1;
- conv = findpath(jack, type);
+ conv = findpath(jack, type, route);
if(conv == nil)
return -1;
for(i=0; i<Maxcodecs; i++){
if(ctlr->codec[i] == nil)
continue;
- for(fg=ctlr->codec[i]->fgroup; fg; fg=fg->next){
- for(w=fg->first; w; w=w->next){
+ for(fg=ctlr->codec[i]->fgroup; fg != nil; fg=fg->next){
+ for(w=fg->first; w != nil; w=w->next){
if(w->type != Wpin)
continue;
score = (*fscore)(w);
static long
hdactl(Audio *adev, void *va, long n, vlong)
{
- char *p, *e, *x, *tok[4];
+ char *p, *e, *x, *route, *tok[4];
int ntok;
Ctlr *ctlr;
uint pin, cad;
e = p + n;
for(; p < e; p = x){
+ route = nil;
if(x = strchr(p, '\n'))
*x++ = 0;
else
continue;
if(cistrcmp(tok[0], "pin") == 0 && ntok >= 2){
cad = ctlr->sout.cad;
- pin = strtoul(tok[1], 0, 0);
+ pin = strtoul(tok[1], &route, 0);
if(ntok > 2)
cad = strtoul(tok[2], 0, 0);
- if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad) < 0)
+ if(connectpin(ctlr, &ctlr->sout, Waout, pin, cad, route) < 0)
error("connectpin failed");
}else
if(cistrcmp(tok[0], "inpin") == 0 && ntok >= 2){
cad = ctlr->sin.cad;
- pin = strtoul(tok[1], 0, 0);
+ pin = strtoul(tok[1], &route, 0);
if(ntok > 2)
cad = strtoul(tok[2], 0, 0);
- if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad) < 0)
+ if(connectpin(ctlr, &ctlr->sin, Wain, pin, cad, route) < 0)
error("connectpin failed");
}else
error(Ebadctl);
static void
hdakick(Ctlr *ctlr)
{
+ int delay;
+
if(ctlr->sout.active)
return;
- if(buffered(&ctlr->sout.ring) > Blocksize)
+ delay = ctlr->adev->delay*BytesPerSample;
+ if(buffered(&ctlr->sout.ring) >= delay)
streamstart(ctlr, &ctlr->sout);
}
0
};
+static Widget*
+findoutamp(Stream *s)
+{
+ Widget *w;
+
+ for(w = s->conv; w != nil; w = w->path){
+ if(w->cap & Woutampcap)
+ return w;
+ if(w == s->jack)
+ break;
+ }
+ return nil;
+}
+
+static Widget*
+findinamp(Stream *s)
+{
+ Widget *w, *p, *a;
+
+ a = nil;
+ for(p = nil, w = s->jack; w != nil; p = w, w = w->path){
+ w->link = p; /* for setinamp */
+ if(w->cap & Winampcap)
+ a = w;
+ if(w == s->conv)
+ break;
+ }
+ return a;
+}
+
static int
hdagetvol(Audio *adev, int x, int a[2])
{
Ctlr *ctlr = adev->ctlr;
+ Widget *w;
switch(x){
case Vmaster:
- if(ctlr->sout.conv != nil)
- getoutamp(ctlr->sout.conv, a);
+ if((w = findoutamp(&ctlr->sout)) != nil)
+ getoutamp(w, a);
+ break;
+ case Vrecord:
+ if((w = findinamp(&ctlr->sin)) != nil)
+ getinamp(w, a);
break;
case Vspeed:
a[0] = adev->speed;
hdasetvol(Audio *adev, int x, int a[2])
{
Ctlr *ctlr = adev->ctlr;
+ Widget *w;
switch(x){
case Vmaster:
- if(ctlr->sout.conv != nil)
- setoutamp(ctlr->sout.conv, 0, a);
+ if((w = findoutamp(&ctlr->sout)) != nil)
+ setoutamp(w, 0, a);
break;
case Vrecord:
- if(ctlr->sin.conv != nil)
- setinamp(ctlr->sin.conv, nil, 0, a);
+ if((w = findinamp(&ctlr->sin)) != nil)
+ setinamp(w, w->link, 0, a);
break;
case Vspeed:
adev->speed = a[0];
break;
case Vdelay:
- adev->delay = a[0];
+ if(a[0] < Blocksize/BytesPerSample) {
+ adev->delay = Blocksize/BytesPerSample;
+ } else if(a[0] > (ctlr->sout.ring.nbuf/BytesPerSample)-1) {
+ adev->delay = (ctlr->sout.ring.nbuf/BytesPerSample)-1;
+ } else {
+ adev->delay = a[0];
+ }
break;
}
return 0;
static void
fillvoltab(Ctlr *ctlr, Volume *vt)
{
+ Widget *w;
+
memmove(vt, voltab, sizeof(voltab));
- if(ctlr->sout.conv != nil)
- vt[Vmaster].range = getoutamprange(ctlr->sout.conv);
+ if((w = findoutamp(&ctlr->sout)) != nil)
+ vt[Vmaster].range = getoutamprange(w);
+ if((w = findinamp(&ctlr->sin)) != nil)
+ vt[Vrecord].range = getinamprange(w);
}
static long
{
Ctlr *ctlr = adev->ctlr;
Codec *codec;
- Fungroup *fg;
Widget *w;
uint r;
- int i;
+ int i, j, k;
char *s, *e;
s = a;
for(i=0; i<Maxcodecs; i++){
if((codec = ctlr->codec[i]) == nil)
continue;
- s = seprint(s, e, "codec %2d pin %3d inpin %3d\n",
+ s = seprint(s, e, "codec %d pin %d inpin %d\n",
codec->id.codec, ctlr->sout.pin, ctlr->sin.pin);
- for(fg=codec->fgroup; fg; fg=fg->next){
- for(w=fg->first; w; w=w->next){
- if(w->type != Wpin)
- continue;
+ for(j=0; j<Maxwidgets; j++){
+ if((w = codec->widgets[j]) == nil)
+ continue;
+ switch(w->type){
+ case Wpin:
r = w->pin;
- s = seprint(s, e, "pin %3d %s%s %s %s %s %s %s%s%s\n",
- w->id.nid,
+ s = seprint(s, e, "%s %d %s%s %s %s %s %s %s%s%s",
+ widtype[w->type&7], w->id.nid,
(w->pincap & Pin) != 0 ? "in" : "",
(w->pincap & Pout) != 0 ? "out" : "",
pinport[(r >> 30) & 0x3],
(w->pincap & Phdmi) ? " hdmi" : "",
(w->pincap & Peapd) ? " eapd" : ""
);
+ break;
+ default:
+ s = seprint(s, e, "%s %d %lux",
+ widtype[w->type&7], w->id.nid,
+ (ulong)w->cap);
+ }
+ if(w->nlist > 0){
+ s = seprint(s, e, " ← ");
+ for(k=0; k<w->nlist; k++){
+ if(k > 0)
+ s = seprint(s, e, ", ");
+ if(w->list[k] != nil)
+ s = seprint(s, e, "%s %d", widtype[w->list[k]->type&7], w->list[k]->id.nid);
+ }
}
+ s = seprint(s, e, "\n");
}
}
- s = seprint(s, e, "outpath ");
- for(w=ctlr->sout.conv; w != nil; w = w->path){
- s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
- (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
- if(w == ctlr->sout.jack)
- break;
- s = seprint(s, e, " → ");
+ if(ctlr->sout.conv != nil && ctlr->sout.jack != nil){
+ s = seprint(s, e, "outpath ");
+ for(w=ctlr->sout.conv; w != nil; w = w->path){
+ s = seprint(s, e, "%s %d", widtype[w->type&7], w->id.nid);
+ if(w == ctlr->sout.jack)
+ break;
+ s = seprint(s, e, " → ");
+ }
+ s = seprint(s, e, "\n");
+ if((w = findoutamp(&ctlr->sout)) != nil)
+ s = seprint(s, e, "outamp %s %d\n", widtype[w->type&7], w->id.nid);
}
- s = seprint(s, e, "\n");
- s = seprint(s, e, "inpath ");
- for(w=ctlr->sin.jack; w != nil; w = w->path){
- s = seprint(s, e, "%s %3d %lux %lux %lux", widtype[w->type&7], w->id.nid,
- (ulong)w->cap, (ulong)w->pin, (ulong)w->pincap);
- if(w == ctlr->sin.conv)
- break;
- s = seprint(s, e, " → ");
+ if(ctlr->sin.conv != nil && ctlr->sin.jack != nil){
+ s = seprint(s, e, "inpath ");
+ for(w=ctlr->sin.jack; w != nil; w = w->path){
+ s = seprint(s, e, "%s %d", widtype[w->type&7], w->id.nid);
+ if(w == ctlr->sin.conv)
+ break;
+ s = seprint(s, e, " → ");
+ }
+ s = seprint(s, e, "\n");
+ if((w = findinamp(&ctlr->sin)) != nil)
+ s = seprint(s, e, "inamp %s %d\n", widtype[w->type&7], w->id.nid);
}
- s = seprint(s, e, "\n");
return s - (char*)a;
}
case (0x8086 << 16) | 0x080a: /* Intel SCH (Oaktrail) */
case (0x8086 << 16) | 0x1c20: /* Intel PCH */
case (0x8086 << 16) | 0x1e20: /* Intel (Thinkpad x230t) */
+ case (0x8086 << 16) | 0x8c20: /* Intel 8 Series/C220 Series */
+ case (0x8086 << 16) | 0x8ca0: /* Intel 9 Series */
+ case (0x8086 << 16) | 0x9c20: /* Intel 8 Series Lynx Point */
+ case (0x8086 << 16) | 0x9ca0: /* Intel Wildcat Point */
+ case (0x8086 << 16) | 0xa170: /* Intel Sunrise Point-H */
+ case (0x8086 << 16) | 0x3a6e: /* Intel ICH10 */
case (0x10de << 16) | 0x026c: /* NVidia MCP51 (untested) */
case (0x10de << 16) | 0x0371: /* NVidia MCP55 (untested) */
case (0x10de << 16) | 0x03f0: /* NVidia MCP61A (untested) */
case (0x10de << 16) | 0x044a: /* NVidia MCP65 (untested) */
case (0x10de << 16) | 0x055c: /* NVidia MCP67 (untested) */
+ case (0x10de << 16) | 0x0fbb: /* NVidia GM204 (untested) */
case (0x1002 << 16) | 0x437b: /* ATI SB450 (untested) */
case (0x1002 << 16) | 0x4383: /* ATI SB600 */
case (0x1106 << 16) | 0x3288: /* VIA (untested) */
case (0x1039 << 16) | 0x7502: /* SIS (untested) */
case (0x10b9 << 16) | 0x5461: /* ULI (untested) */
+
+ case (0x1022 << 16) | 0x780d: /* AMD FCH Azalia Controller */
+
+ case (0x15ad << 16) | 0x1977: /* Vmware */
return p;
}
return nil;
}
/* pick a card from the list */
- for(ctlr = cards; ctlr; ctlr = ctlr->next){
+ for(ctlr = cards; ctlr != nil; ctlr = ctlr->next){
if(p = ctlr->pcidev){
ctlr->pcidev = nil;
goto Found;
case 0x1e20:
case 0x811b: /* SCH */
case 0x080a:
+ case 0x8c20:
+ case 0x8ca0:
+ case 0x9c20:
+ case 0x9ca0:
+ case 0xa170:
pcicfgw16(p, 0x78, pcicfgr16(p, 0x78) & ~0x800);
}
}
print("#A%d: no audio codecs found\n", ctlr->no);
return -1;
}
+ muteall(ctlr);
best = bestpin(ctlr, &cad, scoreout);
if(best < 0)
print("#A%d: no output pins found\n", ctlr->no);
- else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad) < 0)
+ else if(connectpin(ctlr, &ctlr->sout, Waout, best, cad, nil) < 0)
print("#A%d: error connecting output pin\n", ctlr->no);
best = bestpin(ctlr, &cad, scorein);
if(best < 0)
print("#A%d: no input pins found\n", ctlr->no);
- else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad) < 0)
+ else if(connectpin(ctlr, &ctlr->sin, Wain, best, cad, nil) < 0)
print("#A%d: error connecting input pin\n", ctlr->no);
adev->read = hdaread;