ref: 315f20b9f46671ca1fd323b22de0722c7c561f97
parent: f5352eb50106bf3c5a938da15dfa7d24721c31dc
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Apr 4 20:59:47 EDT 2020
nusb/audio: set frequency only when supported before setting the sampling rate, check bit D0 "Sampling Frequency" in the audio class specific endpoint descriptor.
--- a/sys/src/cmd/nusb/audio/audio.c
+++ b/sys/src/cmd/nusb/audio/audio.c
@@ -5,13 +5,19 @@
#include <9p.h>
#include "usb.h"
-typedef struct Audio Audio;
-struct Audio
+typedef struct Range Range;
+struct Range
{
- Audio *next;
+ Range *next;
+ int min;
+ int max;
+};
- int minfreq;
- int maxfreq;
+typedef struct Aconf Aconf;
+struct Aconf
+{
+ Range *freq;
+ int caps;
};
int audiodelay = 1764; /* 40 ms */
@@ -29,35 +35,52 @@
void
parsedescr(Desc *dd)
{
- Audio *a, **ap;
+ Aconf *c;
+ Range *f;
uchar *b;
int i;
if(dd == nil || dd->iface == nil || dd->altc == nil)
return;
- b = (uchar*)&dd->data;
- if(Subclass(dd->iface->csp) != 2 || b[1] != 0x24 || b[2] != 0x02)
+ if(Subclass(dd->iface->csp) != 2)
return;
- if(b[4] != audiochan)
- return;
- if(b[6] != audiores)
- return;
- ap = (Audio**)&dd->altc->aux;
- if(b[7] == 0){
- a = mallocz(sizeof(*a), 1);
- a->minfreq = b[8] | b[9]<<8 | b[10]<<16;
- a->maxfreq = b[11] | b[12]<<8 | b[13]<<16;
- a->next = *ap;
- *ap = a;
- } else {
- for(i=0; i<b[7]; i++){
- a = mallocz(sizeof(*a), 1);
- a->minfreq = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
- a->maxfreq = a->minfreq;
- a->next = *ap;
- *ap = a;
+ c = dd->altc->aux;
+ if(c == nil){
+ c = mallocz(sizeof(*c), 1);
+ dd->altc->aux = c;
+ }
+
+ b = (uchar*)&dd->data;
+ switch(b[1]<<8 | b[2]){
+ case 0x2501: /* CS_ENDPOINT, EP_GENERAL */
+ c->caps |= b[3];
+ break;
+
+ case 0x2402: /* CS_INTERFACE, FORMAT_TYPE */
+ 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;
}
}
@@ -64,17 +87,20 @@
Dev*
setupep(Dev *d, Ep *e, int speed)
{
- uchar b[4];
- Audio *x;
- Altc *a;
+ Altc *x;
+ Aconf *c;
+ Range *f;
int i;
- for(i = 0; i < nelem(e->iface->altc); i++)
- if(a = e->iface->altc[i])
- for(x = a->aux; x; x = x->next)
- if(speed >= x->minfreq && speed <= x->maxfreq)
- goto Foundaltc;
-
+ for(i = 0; i < nelem(e->iface->altc); i++){
+ if((x = e->iface->altc[i]) == nil)
+ continue;
+ if((c = x->aux) == nil)
+ continue;
+ for(f = c->freq; f != nil; f = f->next)
+ if(speed >= f->min && speed <= f->max)
+ goto Foundaltc;
+ }
werrstr("no altc found");
return nil;
@@ -84,17 +110,21 @@
return nil;
}
- b[0] = speed;
- 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(c->caps & 1){
+ uchar b[4];
+ b[0] = speed;
+ 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){
werrstr("openep: %r");
return nil;
}
- devctl(d, "pollival %d", a->interval);
+ devctl(d, "pollival %d", x->interval);
devctl(d, "samplesz %d", audiochan*audiores/8);
devctl(d, "sampledelay %d", audiodelay);
devctl(d, "hz %d", speed);