nusb/audio: set frequency only when supported

before setting the sampling rate, check bit D0
"Sampling Frequency" in the audio class specific
endpoint descriptor.
This commit is contained in:
cinap_lenrek 2020-04-05 00:59:47 +02:00
parent f5352eb501
commit 315f20b9f4

View file

@ -5,13 +5,19 @@
#include <9p.h> #include <9p.h>
#include "usb.h" #include "usb.h"
typedef struct Audio Audio; typedef struct Range Range;
struct Audio struct Range
{ {
Audio *next; Range *next;
int min;
int max;
};
int minfreq; typedef struct Aconf Aconf;
int maxfreq; struct Aconf
{
Range *freq;
int caps;
}; };
int audiodelay = 1764; /* 40 ms */ int audiodelay = 1764; /* 40 ms */
@ -29,52 +35,72 @@ Ep *audioepout = nil;
void void
parsedescr(Desc *dd) parsedescr(Desc *dd)
{ {
Audio *a, **ap; Aconf *c;
Range *f;
uchar *b; uchar *b;
int i; int i;
if(dd == nil || dd->iface == nil || dd->altc == nil) if(dd == nil || dd->iface == nil || dd->altc == nil)
return; return;
b = (uchar*)&dd->data; if(Subclass(dd->iface->csp) != 2)
if(Subclass(dd->iface->csp) != 2 || b[1] != 0x24 || b[2] != 0x02)
return;
if(b[4] != audiochan)
return;
if(b[6] != audiores)
return; return;
ap = (Audio**)&dd->altc->aux; c = dd->altc->aux;
if(b[7] == 0){ if(c == nil){
a = mallocz(sizeof(*a), 1); c = mallocz(sizeof(*c), 1);
a->minfreq = b[8] | b[9]<<8 | b[10]<<16; dd->altc->aux = c;
a->maxfreq = b[11] | b[12]<<8 | b[13]<<16; }
a->next = *ap;
*ap = a; b = (uchar*)&dd->data;
} else { switch(b[1]<<8 | b[2]){
for(i=0; i<b[7]; i++){ case 0x2501: /* CS_ENDPOINT, EP_GENERAL */
a = mallocz(sizeof(*a), 1); c->caps |= b[3];
a->minfreq = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16; break;
a->maxfreq = a->minfreq;
a->next = *ap; case 0x2402: /* CS_INTERFACE, FORMAT_TYPE */
*ap = a; if(b[4] != audiochan)
break;
if(b[6] != audiores)
break;
if(b[7] == 0){
f = mallocz(sizeof(*f), 1);
f->min = b[8] | b[9]<<8 | b[10]<<16;
f->max = b[11] | b[12]<<8 | b[13]<<16;
f->next = c->freq;
c->freq = f;
} else {
for(i=0; i<b[7]; i++){
f = mallocz(sizeof(*f), 1);
f->min = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
f->max = f->min;
f->next = c->freq;
c->freq = f;
}
} }
break;
} }
} }
Dev* Dev*
setupep(Dev *d, Ep *e, int speed) setupep(Dev *d, Ep *e, int speed)
{ {
uchar b[4]; Altc *x;
Audio *x; Aconf *c;
Altc *a; Range *f;
int i; int i;
for(i = 0; i < nelem(e->iface->altc); i++) for(i = 0; i < nelem(e->iface->altc); i++){
if(a = e->iface->altc[i]) if((x = e->iface->altc[i]) == nil)
for(x = a->aux; x; x = x->next) continue;
if(speed >= x->minfreq && speed <= x->maxfreq) if((c = x->aux) == nil)
goto Foundaltc; continue;
for(f = c->freq; f != nil; f = f->next)
if(speed >= f->min && speed <= f->max)
goto Foundaltc;
}
werrstr("no altc found"); werrstr("no altc found");
return nil; return nil;
@ -84,17 +110,21 @@ Foundaltc:
return nil; return nil;
} }
b[0] = speed; if(c->caps & 1){
b[1] = speed >> 8; uchar b[4];
b[2] = speed >> 16;
if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0) b[0] = speed;
fprint(2, "warning: set freq: %r\n"); b[1] = speed >> 8;
b[2] = speed >> 16;
if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0)
fprint(2, "warning: set freq: %r\n");
}
if((d = openep(d, e->id)) == nil){ if((d = openep(d, e->id)) == nil){
werrstr("openep: %r"); werrstr("openep: %r");
return nil; return nil;
} }
devctl(d, "pollival %d", a->interval); devctl(d, "pollival %d", x->interval);
devctl(d, "samplesz %d", audiochan*audiores/8); devctl(d, "samplesz %d", audiochan*audiores/8);
devctl(d, "sampledelay %d", audiodelay); devctl(d, "sampledelay %d", audiodelay);
devctl(d, "hz %d", speed); devctl(d, "hz %d", speed);