xref: /plan9/sys/src/cmd/usb/audio/audiosub.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5 #include "audio.h"
6 #include "audioctl.h"
7 
8 typedef struct Namelist Namelist;
9 
10 struct Namelist
11 {
12 	short	index;
13 	char		*name;
14 };
15 
16 Namelist terminal_types[] = {
17 	{	0x100, "USB Terminal, undefined type"},
18 	{	0x101, "USB Streaming"},
19 	{	0x201, "Microphone"},
20 	{	0x301, "Speaker"},
21 	{	0x603, "Line connector"},
22 	{	0x605, "S/PDIF"},
23 	{	0, nil }
24 };
25 
26 units[2][8];	/* rec and play units */
27 nunits[2];		/* number in use */
28 
29 char *
namefor(Namelist * list,int item)30 namefor(Namelist *list, int item)
31 {
32 	while(list->name){
33 		if(list->index == item)
34 			return list->name;
35 		list++;
36 	}
37 	return "<unnamed>";
38 }
39 
40 static int
findunit(int nr)41 findunit(int nr)
42 {
43 	int rec, i;
44 	for(rec = 0; rec < 2; rec++)
45 		for(i = 0; i < nunits[rec]; i++)
46 			if(units[rec][i] == nr)
47 				return rec;
48 	return -1;
49 }
50 
51 void
audio_interface(Dev *,Desc * dd)52 audio_interface(Dev *, Desc *dd)
53 {
54 	byte *b = (uchar*)&dd->data;
55 	byte *bb = b;
56 	int nb = dd->data.bLength;
57 	int ctl, ch, u, x;
58 	byte *p;
59 	int class, subclass;
60 	Audioalt *aa;
61 	char *hd;
62 
63 	class = Class(dd->iface->csp);
64 	subclass = Subclass(dd->iface->csp);
65 
66 	dprint(2, "%d.%d: ", class, subclass);
67 	switch (subclass){
68 	case 1:	// control
69 		switch (b[2]){
70 		case 0x01:
71 			dprint(2, "Class-Specific AC Interface Header Descriptor\n");
72 			dprint(2, "\tAudioDevClass release (bcd)%c%c%c%c, "
73 				"TotalLength %d, InCollection %d aInterfaceNr %d\n",
74 					'0'+((b[4]>>4)&0xf), '0'+(b[4]&0xf),
75 					'0'+((b[3]>>4)&0xf), '0'+(b[3]&0xf),
76 					b[5]|(b[6]<<8), b[7], b[8]);
77 			break;
78 		case 0x02:	// input
79 			dprint(2, "Audio Input Terminal Descriptor\n");
80 			dprint(2, "\tbTerminalId %d, wTerminalType "
81 				"0x%x (%s), bAssocTerminal %d bNrChannels %d, "
82 				"wChannelConfig %d, iChannelNames %d iTerminal %d\n",
83 					b[3], b[4]|(b[5]<<8),
84 					namefor(terminal_types, b[4]|(b[5]<<8)),
85 					b[6], b[7], b[8]|(b[9]<<8), b[10], b[11]);
86 			if((b[4]|b[5]<<8) == 0x101){
87 				if(verbose)
88 					fprint(2, "Audio output unit %d\n", b[3]);
89 				/* USB streaming input: play interface */
90 				units[Play][nunits[Play]++] = b[3];
91 			}else{
92 				if(verbose)
93 					fprint(2, "Dev can record from %s\n",
94 						namefor(terminal_types, b[4]|(b[5]<<8)));
95 				/* Non-USB input: record interface */
96 				units[Record][nunits[Record]++] = b[3];
97 			}
98 			break;
99 		case 0x03:	// output
100 			if(usbdebug){
101 				fprint(2, "Audio Output Terminal Descriptor\n");
102 				fprint(2, "\tbTerminalId %d, wTerminalType 0x%x (%s), bAssocTerminal %d bSourceId %d, iTerminal %d\n",
103 					b[3], b[4]|(b[5]<<8),
104 					namefor(terminal_types, b[4]|(b[5]<<8)),
105 					b[6], b[7], b[8]);
106 			}
107 			if((b[4]|b[5]<<8) == 0x101){
108 				if(verbose)
109 					fprint(2, "Audio input unit %d\n", b[3]);
110 				/* USB streaming output: record interface */
111 				units[Record][nunits[Record]++] = b[3];
112 				if(verbose)
113 					fprint(2, "Dev can play to %s\n",
114 						namefor(terminal_types, b[4]|(b[5]<<8)));
115 				/* Non-USB output: play interface */
116 				units[Play][nunits[Play]++] = b[3];
117 			}
118 			break;
119 		case 0x04:
120 			if(verbose)
121 				fprint(2, "Audio Mixer Unit %d\n", b[3]);
122 			if(usbdebug){
123 				fprint(2, "\t%d bytes:", nb);
124 				for(ctl = 0; ctl < nb; ctl++)
125 					fprint(2, " 0x%2.2x", b[ctl]);
126 				fprint(2, "\n\tbUnitId %d, bNrInPins %d", b[3], b[4]);
127 			}
128 			if(b[4]){
129 				dprint(2, ", baSourceIDs: [%d", b[5]);
130 				u = findunit(b[5]);
131 				for(ctl = 1; ctl < b[4]; ctl++){
132 					if(u < 0)
133 						u = findunit(b[5+ctl]);
134 					else if((x = findunit(b[5+ctl])) >= 0 && u != x && verbose)
135 						fprint(2, "\tMixer %d for I & O \n", b[3]);
136 					dprint(2, ", %d", b[5+ctl]);
137 				}
138 				dprint(2, "]\n");
139 				if(u >= 0){
140 					units[u][nunits[u]++] = b[3];
141 					if(mixerid[u] >= 0)
142 						fprint(2, "Second mixer (%d, %d) on %s\n",
143 						 mixerid[u], b[3], u?"record":"playback");
144 					mixerid[u] = b[3];
145 				}
146 				if(usbdebug){
147 					fprint(2, "Channels %d, config %d, ",
148 						b[ctl+5], b[ctl+5+1] | b[ctl+5+2] << 8);
149 					x = b[ctl+5] * b[4];
150 					fprint(2, "programmable: %d bits, 0x", x);
151 					x = (x + 7) >> 3;
152 					while(x--)
153 						fprint(2, "%2.2x", b[ctl+x+5+4]);
154 				}
155 			}
156 			break;
157 		case 0x05:
158 			if(verbose)
159 				fprint(2, "Audio Selector Unit %d\n", b[3]);
160 			dprint(2, "\tbUnitId %d, bNrInPins %d", b[3], b[4]);
161 			if(b[4]){
162 				u = findunit(b[5]);
163 				dprint(2, ", baSourceIDs: %s [%d",
164 					u?"record":"playback", b[5]);
165 				for(ctl = 1; ctl < b[4]; ctl++){
166 					if(u < 0)
167 						u = findunit(b[5+ctl]);
168 					else if((x = findunit(b[5+ctl])) >= 0 &&
169 						u != x && verbose)
170 						fprint(2, "\tSelector %d for I & O\n", b[3]);
171 					dprint(2, ", %d", b[5+ctl]);
172 				}
173 				dprint(2, "]\n");
174 				if(u >= 0){
175 					units[u][nunits[u]++] = b[3];
176 					if(selectorid[u] >= 0)
177 						fprint(2, "Second selector (%d, %d) on %s\n", selectorid[u], b[3], u?"record":"playback");
178 					selectorid[u] = b[3];
179 					controls[u][Selector_control].readable = 1;
180 					controls[u][Selector_control].settable = 1;
181 					controls[u][Selector_control].chans = 0;
182 				}
183 			}
184 			break;
185 		case 0x06:	// feature
186 			if(verbose) fprint(2, "Audio Feature Unit %d", b[3]);
187 			dprint(2, "\tbUnitId %d, bSourceId %d, bControlSize %d\n",
188 				b[3], b[4], b[5]);
189 			u = findunit(b[4]);
190 			if(u >= 0){
191 				if(verbose) fprint(2, " for %s\n", u?"Record":"Playback");
192 				units[u][nunits[u]++] = b[3];
193 				if(featureid[u] >= 0)
194 					if(verbose)
195 						fprint(2, "Second feature unit (%d, %d)"
196 							" on %s\n", featureid[u], b[3],
197 							u?"record":"playback");
198 				featureid[u] = b[3];
199 			}else
200 				if(verbose) fprint(2, ", not known what for\n");
201 			p = b + 6;
202 			for(ctl = 1; ctl < 0x0b; ctl++)
203 				if((1<<(ctl-1)) & (b[6] | ((b[5]>1)?(b[7]<<8):0))){
204 					if(verbose)
205 						fprint(2, "\t%s control on master channel\n",
206 							controls[0][ctl].name);
207 					if(u >= 0){
208 						controls[u][ctl].readable = 1;
209 						controls[u][ctl].settable = 1;
210 						controls[u][ctl].chans = 0;
211 					}
212 				}
213 			p += (b[5]>1)?2:1;
214 			for(ch = 0; ch < (nb - 8)/b[5]; ch++){
215 				for(ctl = 1; ctl < 0x0b; ctl++)
216 					if((1<<(ctl-1)) & (p[0] | ((b[5]>1)?(p[1]<<8):0))){
217 						if(verbose)
218 						  fprint(2, "\t%s control on channel %d\n",
219 							controls[0][ctl].name, ch+1);
220 						if(u >= 0){
221 							controls[u][ctl].readable = 1;
222 							controls[u][ctl].settable = 1;
223 							controls[u][ctl].chans |= 1 <<(ch+1);
224 						}
225 					}
226 				p += (b[5]>1)?2:1;
227 			}
228 			break;
229 		default:
230 			hd = hexstr(bb, nb);
231 			fprint(2, "audio control unknown: %s\n", hd);
232 			free(hd);
233 		}
234 		break;
235 	case 2: // stream
236 		switch (b[2]){
237 		case 0x01:
238 			dprint(2, "Audio stream for TerminalID %d, delay %d, format_tag %#ux\n",
239 				b[3], b[4], b[5] | (b[6]<<8));
240 			break;
241 		case 0x02:
242 			aa = (Audioalt *)dd->altc->aux;
243 			if(aa == nil){
244 				aa = mallocz(sizeof(Audioalt), 1);
245 				dd->altc->aux = aa;
246 			}
247 			if(verbose){
248 				if(b[4] <= 2)
249 					fprint(2, "Interface %d: %s, %d bits, ",
250 						dd->iface->id, (b[4] == 1)?"mono":"stereo", b[6]);
251 				else
252 					fprint(2, "Interface %d, %d channels, %d bits, ",
253 						dd->iface->id, b[4], b[6]);
254 			}
255 			if(b[7] == 0){
256 				if(verbose)
257 					fprint(2, "frequency variable between %d and %d\n",
258 						b[8] | b[9]<<8 | b[10]<<16, b[11] | b[12]<<8 | b[13]<<16);
259 				aa->minfreq = b[8] | b[9]<<8 | b[10]<<16;
260 				aa->maxfreq = b[11] | b[12]<<8 | b[13]<<16;
261 				aa->caps |= has_contfreq;
262 			}else{
263 				if(verbose)
264 					fprint(2, "discrete frequencies are:");
265 				for(ch = 0; ch < b[7] && ch < 8; ch++){
266 					aa->freqs[ch] = b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16;
267 					if(verbose)
268 						fprint(2, " %d", b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16);
269 				}
270 				if(ch < 8)
271 					aa->freqs[ch] = -1;
272 				if(verbose)
273 					fprint(2, "\n");
274 				if(ch > 1)
275 					aa->caps |= has_discfreq;	/* more than one frequency */
276 				else
277 					aa->caps |= onefreq;		/* only one frequency */
278 			}
279 			aa->nchan = b[4];
280 			aa->res = b[6];
281 			aa->subframesize = b[5];
282 			break;
283 		default:
284 			if(usbdebug){
285 				hd = hexstr(bb, nb);
286 				fprint(2, "audio stream unknown: %s\n", hd);
287 				free(hd);
288 			}
289 		}
290 		break;
291 	case 3: // midi
292 	default:
293 		if(usbdebug){
294 			hd = hexstr(bb, nb);
295 			fprint(2, "Unknown audio stream type: CS_INTERFACE: %s\n", hd);
296 			free(hd);
297 		}
298 	}
299 }
300 
301