Annotation of src/sys/dev/usb/uaudio.c, Revision 1.72
1.72 ! mycroft 1: /* $NetBSD: uaudio.c,v 1.71 2004/04/23 17:25:25 itojun Exp $ */
1.1 augustss 2:
3: /*
4: * Copyright (c) 1999 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
1.5 augustss 7: * This code is derived from software contributed to The NetBSD Foundation
1.24 augustss 8: * by Lennart Augustsson (lennart@augustsson.net) at
1.5 augustss 9: * Carlstedt Research & Technology.
1.1 augustss 10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
1.68 augustss 41: * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
42: * http://www.usb.org/developers/devclass_docs/frmts10.pdf
43: * http://www.usb.org/developers/devclass_docs/termt10.pdf
1.1 augustss 44: */
1.44 lukem 45:
46: #include <sys/cdefs.h>
1.72 ! mycroft 47: __KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.71 2004/04/23 17:25:25 itojun Exp $");
1.1 augustss 48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/kernel.h>
52: #include <sys/malloc.h>
53: #include <sys/device.h>
54: #include <sys/ioctl.h>
55: #include <sys/tty.h>
56: #include <sys/file.h>
1.40 augustss 57: #include <sys/reboot.h> /* for bootverbose */
1.1 augustss 58: #include <sys/select.h>
59: #include <sys/proc.h>
60: #include <sys/vnode.h>
61: #include <sys/device.h>
62: #include <sys/poll.h>
63:
64: #include <sys/audioio.h>
65: #include <dev/audio_if.h>
66: #include <dev/mulaw.h>
67: #include <dev/auconv.h>
68:
69: #include <dev/usb/usb.h>
70: #include <dev/usb/usbdi.h>
71: #include <dev/usb/usbdi_util.h>
72: #include <dev/usb/usb_quirks.h>
73:
74: #include <dev/usb/uaudioreg.h>
75:
1.4 augustss 76: #ifdef UAUDIO_DEBUG
1.1 augustss 77: #define DPRINTF(x) if (uaudiodebug) logprintf x
78: #define DPRINTFN(n,x) if (uaudiodebug>(n)) logprintf x
79: int uaudiodebug = 0;
80: #else
81: #define DPRINTF(x)
82: #define DPRINTFN(n,x)
83: #endif
84:
1.22 augustss 85: #define UAUDIO_NCHANBUFS 6 /* number of outstanding request */
1.55 kent 86: #define UAUDIO_NFRAMES 10 /* ms of sound in each request */
1.1 augustss 87:
88:
89: #define MIX_MAX_CHAN 8
90: struct mixerctl {
91: u_int16_t wValue[MIX_MAX_CHAN]; /* using nchan */
92: u_int16_t wIndex;
93: u_int8_t nchan;
94: u_int8_t type;
95: #define MIX_ON_OFF 1
96: #define MIX_SIGNED_16 2
97: #define MIX_UNSIGNED_16 3
98: #define MIX_SIGNED_8 4
99: #define MIX_SIZE(n) ((n) == MIX_SIGNED_16 || (n) == MIX_UNSIGNED_16 ? 2 : 1)
100: #define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16)
1.34 augustss 101: int minval, maxval;
102: u_int delta;
103: u_int mul;
1.1 augustss 104: u_int8_t class;
105: char ctlname[MAX_AUDIO_DEV_LEN];
106: char *ctlunit;
107: };
108: #define MAKE(h,l) (((h) << 8) | (l))
109:
110: struct as_info {
111: u_int8_t alt;
112: u_int8_t encoding;
1.50 kent 113: u_int8_t attributes; /* Copy of bmAttributes of
114: * usb_audio_streaming_endpoint_descriptor
115: */
1.37 mycroft 116: usbd_interface_handle ifaceh;
1.1 augustss 117: usb_interface_descriptor_t *idesc;
118: usb_endpoint_descriptor_audio_t *edesc;
119: struct usb_audio_streaming_type1_descriptor *asf1desc;
1.47 jdolecek 120: int sc_busy; /* currently used */
1.1 augustss 121: };
122:
123: struct chan {
1.67 wiz 124: void (*intr)(void *); /* DMA completion intr handler */
1.1 augustss 125: void *arg; /* arg for intr() */
126: usbd_pipe_handle pipe;
127:
128: u_int sample_size;
129: u_int sample_rate;
130: u_int bytes_per_frame;
131: u_int fraction; /* fraction/1000 is the extra samples/frame */
132: u_int residue; /* accumulates the fractional samples */
133:
134: u_char *start; /* upper layer buffer start */
135: u_char *end; /* upper layer buffer end */
136: u_char *cur; /* current position in upper layer buffer */
137: int blksize; /* chunk size to report up */
138: int transferred; /* transferred bytes not reported up */
139:
1.47 jdolecek 140: int altidx; /* currently used altidx */
1.31 augustss 141:
1.1 augustss 142: int curchanbuf;
143: struct chanbuf {
1.56 kent 144: struct chan *chan;
1.9 augustss 145: usbd_xfer_handle xfer;
1.56 kent 146: u_char *buffer;
147: u_int16_t sizes[UAUDIO_NFRAMES];
1.62 toshii 148: u_int16_t offsets[UAUDIO_NFRAMES];
1.56 kent 149: u_int16_t size;
1.1 augustss 150: } chanbufs[UAUDIO_NCHANBUFS];
1.8 augustss 151:
152: struct uaudio_softc *sc; /* our softc */
1.1 augustss 153: };
154:
155: struct uaudio_softc {
156: USBBASEDEVICE sc_dev; /* base device */
157: usbd_device_handle sc_udev; /* USB device */
158:
159: int sc_ac_iface; /* Audio Control interface */
160: usbd_interface_handle sc_ac_ifaceh;
161:
1.47 jdolecek 162: struct chan sc_playchan; /* play channel */
163: struct chan sc_recchan; /* record channel */
1.1 augustss 164:
165: int sc_nullalt;
166:
1.7 augustss 167: int sc_audio_rev;
168:
1.1 augustss 169: struct as_info *sc_alts;
170: int sc_nalts;
171:
172: int sc_altflags;
1.56 kent 173: #define HAS_8 0x01
174: #define HAS_16 0x02
175: #define HAS_8U 0x04
176: #define HAS_ALAW 0x08
177: #define HAS_MULAW 0x10
1.47 jdolecek 178: #define UA_NOFRAC 0x20 /* don't do sample rate adjustment */
1.51 kent 179: #define HAS_24 0x40
1.47 jdolecek 180:
181: int sc_mode; /* play/record capability */
1.1 augustss 182:
183: struct mixerctl *sc_ctls;
184: int sc_nctls;
185:
186: device_ptr_t sc_audiodev;
187: char sc_dying;
188: };
189:
190: #define UAC_OUTPUT 0
191: #define UAC_INPUT 1
192: #define UAC_EQUAL 2
1.63 augustss 193: #define UAC_NCLASSES 3
1.1 augustss 194:
1.26 augustss 195: Static usbd_status uaudio_identify_ac(struct uaudio_softc *sc,
196: usb_config_descriptor_t *cdesc);
197: Static usbd_status uaudio_identify_as(struct uaudio_softc *sc,
198: usb_config_descriptor_t *cdesc);
199: Static usbd_status uaudio_process_as(struct uaudio_softc *sc,
1.9 augustss 200: char *buf, int *offsp, int size,
1.26 augustss 201: usb_interface_descriptor_t *id);
1.1 augustss 202:
1.56 kent 203: Static void uaudio_add_alt(struct uaudio_softc *sc,
1.26 augustss 204: struct as_info *ai);
1.63 augustss 205: Static void uaudio_mixer_alias_ctl(struct uaudio_softc *sc,
206: struct mixerctl *mp, const char *ctl);
1.1 augustss 207:
1.26 augustss 208: Static usb_interface_descriptor_t *uaudio_find_iface(char *buf,
209: int size, int *offsp, int subtype);
1.1 augustss 210:
1.26 augustss 211: Static void uaudio_mixer_add_ctl(struct uaudio_softc *sc,
212: struct mixerctl *mp);
1.56 kent 213: Static char *uaudio_id_name(struct uaudio_softc *sc,
1.26 augustss 214: usb_descriptor_t **dps, int id);
215: Static struct usb_audio_cluster uaudio_get_cluster(int id,
216: usb_descriptor_t **dps);
217: Static void uaudio_add_input(struct uaudio_softc *sc,
218: usb_descriptor_t *v, usb_descriptor_t **dps);
1.56 kent 219: Static void uaudio_add_output(struct uaudio_softc *sc,
1.26 augustss 220: usb_descriptor_t *v, usb_descriptor_t **dps);
221: Static void uaudio_add_mixer(struct uaudio_softc *sc,
222: usb_descriptor_t *v, usb_descriptor_t **dps);
223: Static void uaudio_add_selector(struct uaudio_softc *sc,
224: usb_descriptor_t *v, usb_descriptor_t **dps);
225: Static void uaudio_add_feature(struct uaudio_softc *sc,
226: usb_descriptor_t *v, usb_descriptor_t **dps);
227: Static void uaudio_add_processing_updown(struct uaudio_softc *sc,
1.56 kent 228: usb_descriptor_t *v, usb_descriptor_t **dps);
1.26 augustss 229: Static void uaudio_add_processing(struct uaudio_softc *sc,
230: usb_descriptor_t *v, usb_descriptor_t **dps);
231: Static void uaudio_add_extension(struct uaudio_softc *sc,
232: usb_descriptor_t *v, usb_descriptor_t **dps);
1.56 kent 233: Static usbd_status uaudio_identify(struct uaudio_softc *sc,
1.26 augustss 234: usb_config_descriptor_t *cdesc);
235:
1.56 kent 236: Static int uaudio_signext(int type, int val);
237: Static int uaudio_value2bsd(struct mixerctl *mc, int val);
238: Static int uaudio_bsd2value(struct mixerctl *mc, int val);
239: Static int uaudio_get(struct uaudio_softc *sc, int type,
1.26 augustss 240: int which, int wValue, int wIndex, int len);
241: Static int uaudio_ctl_get(struct uaudio_softc *sc, int which,
242: struct mixerctl *mc, int chan);
243: Static void uaudio_set(struct uaudio_softc *sc, int type,
244: int which, int wValue, int wIndex, int l, int v);
1.56 kent 245: Static void uaudio_ctl_set(struct uaudio_softc *sc, int which,
1.26 augustss 246: struct mixerctl *mc, int chan, int val);
247:
248: Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, u_int);
249:
250: Static usbd_status uaudio_chan_open(struct uaudio_softc *sc,
251: struct chan *ch);
252: Static void uaudio_chan_close(struct uaudio_softc *sc,
253: struct chan *ch);
254: Static usbd_status uaudio_chan_alloc_buffers(struct uaudio_softc *,
255: struct chan *);
256: Static void uaudio_chan_free_buffers(struct uaudio_softc *,
257: struct chan *);
1.54 kent 258: Static void uaudio_chan_init(struct chan *, int,
1.65 toshii 259: const struct audio_params *, int);
1.54 kent 260: Static void uaudio_chan_set_param(struct chan *ch, u_char *start,
1.26 augustss 261: u_char *end, int blksize);
262: Static void uaudio_chan_ptransfer(struct chan *ch);
1.56 kent 263: Static void uaudio_chan_pintr(usbd_xfer_handle xfer,
1.26 augustss 264: usbd_private_handle priv, usbd_status status);
265:
266: Static void uaudio_chan_rtransfer(struct chan *ch);
1.56 kent 267: Static void uaudio_chan_rintr(usbd_xfer_handle xfer,
1.26 augustss 268: usbd_private_handle priv, usbd_status status);
269:
270: Static int uaudio_open(void *, int);
271: Static void uaudio_close(void *);
272: Static int uaudio_drain(void *);
273: Static int uaudio_query_encoding(void *, struct audio_encoding *);
1.50 kent 274: Static void uaudio_get_minmax_rates(int, const struct as_info *,
275: const struct audio_params *,
276: int, u_long *, u_long *);
277: Static int uaudio_match_alt_sub(int, const struct as_info *,
278: const struct audio_params *,
279: int, u_long);
1.53 kent 280: Static int uaudio_match_alt_chan(int, const struct as_info *,
281: struct audio_params *, int);
1.50 kent 282: Static int uaudio_match_alt(int, const struct as_info *,
283: struct audio_params *, int);
1.56 kent 284: Static int uaudio_set_params(void *, int, int,
1.26 augustss 285: struct audio_params *, struct audio_params *);
286: Static int uaudio_round_blocksize(void *, int);
287: Static int uaudio_trigger_output(void *, void *, void *,
288: int, void (*)(void *), void *,
289: struct audio_params *);
290: Static int uaudio_trigger_input (void *, void *, void *,
291: int, void (*)(void *), void *,
292: struct audio_params *);
293: Static int uaudio_halt_in_dma(void *);
294: Static int uaudio_halt_out_dma(void *);
295: Static int uaudio_getdev(void *, struct audio_device *);
296: Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *);
297: Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *);
298: Static int uaudio_query_devinfo(void *, mixer_devinfo_t *);
299: Static int uaudio_get_props(void *);
1.1 augustss 300:
1.21 augustss 301: Static struct audio_hw_if uaudio_hw_if = {
1.1 augustss 302: uaudio_open,
303: uaudio_close,
304: uaudio_drain,
305: uaudio_query_encoding,
306: uaudio_set_params,
307: uaudio_round_blocksize,
308: NULL,
309: NULL,
310: NULL,
311: NULL,
312: NULL,
313: uaudio_halt_out_dma,
314: uaudio_halt_in_dma,
315: NULL,
316: uaudio_getdev,
317: NULL,
318: uaudio_mixer_set_port,
319: uaudio_mixer_get_port,
320: uaudio_query_devinfo,
321: NULL,
322: NULL,
323: NULL,
324: NULL,
325: uaudio_get_props,
326: uaudio_trigger_output,
327: uaudio_trigger_input,
1.43 augustss 328: NULL,
1.1 augustss 329: };
330:
1.21 augustss 331: Static struct audio_device uaudio_device = {
1.1 augustss 332: "USB audio",
333: "",
334: "uaudio"
335: };
336:
337: USB_DECLARE_DRIVER(uaudio);
338:
339: USB_MATCH(uaudio)
340: {
341: USB_MATCH_START(uaudio, uaa);
342: usb_interface_descriptor_t *id;
1.56 kent 343:
1.9 augustss 344: if (uaa->iface == NULL)
1.1 augustss 345: return (UMATCH_NONE);
346:
347: id = usbd_get_interface_descriptor(uaa->iface);
348: /* Trigger on the control interface. */
1.56 kent 349: if (id == NULL ||
1.19 augustss 350: id->bInterfaceClass != UICLASS_AUDIO ||
351: id->bInterfaceSubClass != UISUBCLASS_AUDIOCONTROL ||
1.10 augustss 352: (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_AUDIO))
1.1 augustss 353: return (UMATCH_NONE);
354:
355: return (UMATCH_IFACECLASS_IFACESUBCLASS);
356: }
357:
358: USB_ATTACH(uaudio)
359: {
360: USB_ATTACH_START(uaudio, sc, uaa);
361: usb_interface_descriptor_t *id;
362: usb_config_descriptor_t *cdesc;
363: char devinfo[1024];
1.9 augustss 364: usbd_status err;
1.37 mycroft 365: int i, j, found;
1.1 augustss 366:
1.71 itojun 367: usbd_devinfo(uaa->device, 0, devinfo, sizeof(devinfo));
1.1 augustss 368: printf(": %s\n", devinfo);
369:
370: sc->sc_udev = uaa->device;
371:
372: cdesc = usbd_get_config_descriptor(sc->sc_udev);
1.13 augustss 373: if (cdesc == NULL) {
374: printf("%s: failed to get configuration descriptor\n",
375: USBDEVNAME(sc->sc_dev));
1.1 augustss 376: USB_ATTACH_ERROR_RETURN;
1.13 augustss 377: }
1.1 augustss 378:
1.9 augustss 379: err = uaudio_identify(sc, cdesc);
380: if (err) {
1.1 augustss 381: printf("%s: audio descriptors make no sense, error=%d\n",
1.9 augustss 382: USBDEVNAME(sc->sc_dev), err);
1.1 augustss 383: USB_ATTACH_ERROR_RETURN;
384: }
385:
386: sc->sc_ac_ifaceh = uaa->iface;
387: /* Pick up the AS interface. */
388: for (i = 0; i < uaa->nifaces; i++) {
1.37 mycroft 389: if (uaa->ifaces[i] == NULL)
390: continue;
391: id = usbd_get_interface_descriptor(uaa->ifaces[i]);
392: if (id == NULL)
393: continue;
394: found = 0;
395: for (j = 0; j < sc->sc_nalts; j++) {
396: if (id->bInterfaceNumber ==
397: sc->sc_alts[j].idesc->bInterfaceNumber) {
398: sc->sc_alts[j].ifaceh = uaa->ifaces[i];
399: found = 1;
1.1 augustss 400: }
401: }
1.37 mycroft 402: if (found)
403: uaa->ifaces[i] = NULL;
1.1 augustss 404: }
405:
1.37 mycroft 406: for (j = 0; j < sc->sc_nalts; j++) {
407: if (sc->sc_alts[j].ifaceh == NULL) {
1.40 augustss 408: printf("%s: alt %d missing AS interface(s)\n",
409: USBDEVNAME(sc->sc_dev), j);
1.37 mycroft 410: USB_ATTACH_ERROR_RETURN;
411: }
1.1 augustss 412: }
413:
1.40 augustss 414: printf("%s: audio rev %d.%02x\n", USBDEVNAME(sc->sc_dev),
1.7 augustss 415: sc->sc_audio_rev >> 8, sc->sc_audio_rev & 0xff);
416:
1.47 jdolecek 417: sc->sc_playchan.sc = sc->sc_recchan.sc = sc;
1.60 kent 418: sc->sc_playchan.altidx = -1;
419: sc->sc_recchan.altidx = -1;
1.8 augustss 420:
1.31 augustss 421: if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_FRAC)
1.47 jdolecek 422: sc->sc_altflags |= UA_NOFRAC;
1.31 augustss 423:
1.40 augustss 424: #ifndef UAUDIO_DEBUG
425: if (bootverbose)
426: #endif
427: printf("%s: %d mixer controls\n", USBDEVNAME(sc->sc_dev),
428: sc->sc_nctls);
429:
1.41 augustss 430: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
431: USBDEV(sc->sc_dev));
432:
1.1 augustss 433: DPRINTF(("uaudio_attach: doing audio_attach_mi\n"));
1.23 augustss 434: #if defined(__OpenBSD__)
435: audio_attach_mi(&uaudio_hw_if, sc, &sc->sc_dev);
436: #else
1.1 augustss 437: sc->sc_audiodev = audio_attach_mi(&uaudio_hw_if, sc, &sc->sc_dev);
1.23 augustss 438: #endif
1.17 augustss 439:
1.1 augustss 440: USB_ATTACH_SUCCESS_RETURN;
441: }
442:
443: int
1.26 augustss 444: uaudio_activate(device_ptr_t self, enum devact act)
1.1 augustss 445: {
446: struct uaudio_softc *sc = (struct uaudio_softc *)self;
1.2 augustss 447: int rv = 0;
1.1 augustss 448:
449: switch (act) {
450: case DVACT_ACTIVATE:
451: return (EOPNOTSUPP);
452: break;
453:
454: case DVACT_DEACTIVATE:
1.40 augustss 455: if (sc->sc_audiodev != NULL)
1.2 augustss 456: rv = config_deactivate(sc->sc_audiodev);
1.1 augustss 457: sc->sc_dying = 1;
458: break;
459: }
1.2 augustss 460: return (rv);
1.1 augustss 461: }
462:
463: int
1.26 augustss 464: uaudio_detach(device_ptr_t self, int flags)
1.1 augustss 465: {
466: struct uaudio_softc *sc = (struct uaudio_softc *)self;
467: int rv = 0;
468:
1.8 augustss 469: /* Wait for outstanding requests to complete. */
470: usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
471:
1.9 augustss 472: if (sc->sc_audiodev != NULL)
1.1 augustss 473: rv = config_detach(sc->sc_audiodev, flags);
1.17 augustss 474:
475: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
476: USBDEV(sc->sc_dev));
1.1 augustss 477:
478: return (rv);
479: }
480:
481: int
1.26 augustss 482: uaudio_query_encoding(void *addr, struct audio_encoding *fp)
1.1 augustss 483: {
484: struct uaudio_softc *sc = addr;
485: int flags = sc->sc_altflags;
486: int idx;
487:
488: if (sc->sc_dying)
489: return (EIO);
1.56 kent 490:
1.1 augustss 491: if (sc->sc_nalts == 0 || flags == 0)
492: return (ENXIO);
493:
494: idx = fp->index;
495: switch (idx) {
496: case 0:
1.71 itojun 497: strlcpy(fp->name, AudioEulinear, sizeof(fp->name));
1.1 augustss 498: fp->encoding = AUDIO_ENCODING_ULINEAR;
499: fp->precision = 8;
500: fp->flags = flags&HAS_8U ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
501: return (0);
502: case 1:
1.71 itojun 503: strlcpy(fp->name, AudioEmulaw, sizeof(fp->name));
1.1 augustss 504: fp->encoding = AUDIO_ENCODING_ULAW;
505: fp->precision = 8;
506: fp->flags = flags&HAS_MULAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
507: return (0);
508: case 2:
1.71 itojun 509: strlcpy(fp->name, AudioEalaw, sizeof(fp->name));
1.1 augustss 510: fp->encoding = AUDIO_ENCODING_ALAW;
511: fp->precision = 8;
512: fp->flags = flags&HAS_ALAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
513: return (0);
514: case 3:
1.71 itojun 515: strlcpy(fp->name, AudioEslinear, sizeof(fp->name));
1.1 augustss 516: fp->encoding = AUDIO_ENCODING_SLINEAR;
517: fp->precision = 8;
518: fp->flags = flags&HAS_8 ? 0 : AUDIO_ENCODINGFLAG_EMULATED;
519: return (0);
1.56 kent 520: case 4:
1.71 itojun 521: strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name));
1.1 augustss 522: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
523: fp->precision = 16;
524: fp->flags = 0;
525: return (0);
526: case 5:
1.71 itojun 527: strlcpy(fp->name, AudioEulinear_le, sizeof(fp->name));
1.1 augustss 528: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
529: fp->precision = 16;
530: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
531: return (0);
532: case 6:
1.71 itojun 533: strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name));
1.1 augustss 534: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
535: fp->precision = 16;
536: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
537: return (0);
538: case 7:
1.71 itojun 539: strlcpy(fp->name, AudioEulinear_be, sizeof(fp->name));
1.1 augustss 540: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
541: fp->precision = 16;
542: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
543: return (0);
544: default:
545: return (EINVAL);
546: }
547: }
548:
549: usb_interface_descriptor_t *
1.26 augustss 550: uaudio_find_iface(char *buf, int size, int *offsp, int subtype)
1.1 augustss 551: {
552: usb_interface_descriptor_t *d;
553:
554: while (*offsp < size) {
555: d = (void *)(buf + *offsp);
556: *offsp += d->bLength;
557: if (d->bDescriptorType == UDESC_INTERFACE &&
1.19 augustss 558: d->bInterfaceClass == UICLASS_AUDIO &&
1.1 augustss 559: d->bInterfaceSubClass == subtype)
560: return (d);
561: }
1.40 augustss 562: return (NULL);
1.1 augustss 563: }
564:
565: void
1.26 augustss 566: uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
1.1 augustss 567: {
1.33 augustss 568: int res;
1.42 christos 569: size_t len = sizeof(*mc) * (sc->sc_nctls + 1);
570: struct mixerctl *nmc = sc->sc_nctls == 0 ?
571: malloc(len, M_USBDEV, M_NOWAIT) :
572: realloc(sc->sc_ctls, len, M_USBDEV, M_NOWAIT);
1.33 augustss 573:
1.42 christos 574: if (nmc == NULL) {
1.1 augustss 575: printf("uaudio_mixer_add_ctl: no memory\n");
576: return;
577: }
1.42 christos 578: sc->sc_ctls = nmc;
1.1 augustss 579:
1.33 augustss 580: mc->delta = 0;
1.1 augustss 581: if (mc->type != MIX_ON_OFF) {
582: /* Determine min and max values. */
1.56 kent 583: mc->minval = uaudio_signext(mc->type,
584: uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE,
585: mc->wValue[0], mc->wIndex,
1.1 augustss 586: MIX_SIZE(mc->type)));
1.56 kent 587: mc->maxval = 1 + uaudio_signext(mc->type,
1.1 augustss 588: uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE,
589: mc->wValue[0], mc->wIndex,
590: MIX_SIZE(mc->type)));
1.34 augustss 591: mc->mul = mc->maxval - mc->minval;
592: if (mc->mul == 0)
593: mc->mul = 1;
1.33 augustss 594: res = uaudio_get(sc, GET_RES, UT_READ_CLASS_INTERFACE,
595: mc->wValue[0], mc->wIndex,
596: MIX_SIZE(mc->type));
1.34 augustss 597: if (res > 0)
1.69 wiz 598: mc->delta = (res * 255 + mc->mul/2) / mc->mul;
1.1 augustss 599: } else {
600: mc->minval = 0;
601: mc->maxval = 1;
602: }
603:
604: sc->sc_ctls[sc->sc_nctls++] = *mc;
605:
1.4 augustss 606: #ifdef UAUDIO_DEBUG
1.1 augustss 607: if (uaudiodebug > 2) {
608: int i;
609: DPRINTF(("uaudio_mixer_add_ctl: wValue=%04x",mc->wValue[0]));
610: for (i = 1; i < mc->nchan; i++)
611: DPRINTF((",%04x", mc->wValue[i]));
612: DPRINTF((" wIndex=%04x type=%d name='%s' unit='%s' "
613: "min=%d max=%d\n",
614: mc->wIndex, mc->type, mc->ctlname, mc->ctlunit,
615: mc->minval, mc->maxval));
616: }
617: #endif
618: }
619:
1.63 augustss 620: void
621: uaudio_mixer_alias_ctl(struct uaudio_softc *sc, struct mixerctl *mc,
622: const char *name)
623: {
624: /* XXX mark as alias? */
1.71 itojun 625: strlcpy(mc->ctlname, name, sizeof(mc->ctlname));
1.63 augustss 626: uaudio_mixer_add_ctl(sc, mc);
627: }
628:
1.1 augustss 629: char *
1.26 augustss 630: uaudio_id_name(struct uaudio_softc *sc, usb_descriptor_t **dps, int id)
1.1 augustss 631: {
632: static char buf[32];
1.70 itojun 633: snprintf(buf, sizeof(buf), "i%d", id);
1.1 augustss 634: return (buf);
635: }
636:
637: struct usb_audio_cluster
1.26 augustss 638: uaudio_get_cluster(int id, usb_descriptor_t **dps)
1.1 augustss 639: {
640: struct usb_audio_cluster r;
641: usb_descriptor_t *dp;
642: int i;
643:
644: for (i = 0; i < 25; i++) { /* avoid infinite loops */
645: dp = dps[id];
646: if (dp == 0)
647: goto bad;
648: switch (dp->bDescriptorSubtype) {
649: case UDESCSUB_AC_INPUT:
650: #define p ((struct usb_audio_input_terminal *)dp)
651: r.bNrChannels = p->bNrChannels;
652: USETW(r.wChannelConfig, UGETW(p->wChannelConfig));
653: r.iChannelNames = p->iChannelNames;
654: #undef p
655: return (r);
656: case UDESCSUB_AC_OUTPUT:
657: #define p ((struct usb_audio_output_terminal *)dp)
658: id = p->bSourceId;
659: #undef p
660: break;
661: case UDESCSUB_AC_MIXER:
662: #define p ((struct usb_audio_mixer_unit *)dp)
663: r = *(struct usb_audio_cluster *)
664: &p->baSourceId[p->bNrInPins];
665: #undef p
666: return (r);
667: case UDESCSUB_AC_SELECTOR:
668: /* XXX This is not really right */
669: #define p ((struct usb_audio_selector_unit *)dp)
670: id = p->baSourceId[0];
671: #undef p
672: break;
673: case UDESCSUB_AC_FEATURE:
674: #define p ((struct usb_audio_feature_unit *)dp)
675: id = p->bSourceId;
676: #undef p
677: break;
678: case UDESCSUB_AC_PROCESSING:
679: #define p ((struct usb_audio_processing_unit *)dp)
680: r = *(struct usb_audio_cluster *)
681: &p->baSourceId[p->bNrInPins];
682: #undef p
683: return (r);
684: case UDESCSUB_AC_EXTENSION:
685: #define p ((struct usb_audio_extension_unit *)dp)
686: r = *(struct usb_audio_cluster *)
687: &p->baSourceId[p->bNrInPins];
688: #undef p
689: return (r);
690: default:
691: goto bad;
692: }
693: }
694: bad:
695: printf("uaudio_get_cluster: bad data\n");
696: memset(&r, 0, sizeof r);
1.9 augustss 697: return (r);
1.1 augustss 698:
699: }
700:
701: void
1.56 kent 702: uaudio_add_input(struct uaudio_softc *sc, usb_descriptor_t *v,
1.26 augustss 703: usb_descriptor_t **dps)
1.1 augustss 704: {
1.4 augustss 705: #ifdef UAUDIO_DEBUG
1.56 kent 706: struct usb_audio_input_terminal *d =
1.1 augustss 707: (struct usb_audio_input_terminal *)v;
708:
709: DPRINTFN(2,("uaudio_add_input: bTerminalId=%d wTerminalType=0x%04x "
710: "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
711: "iChannelNames=%d iTerminal=%d\n",
712: d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
713: d->bNrChannels, UGETW(d->wChannelConfig),
714: d->iChannelNames, d->iTerminal));
715: #endif
716: }
717:
718: void
1.26 augustss 719: uaudio_add_output(struct uaudio_softc *sc, usb_descriptor_t *v,
720: usb_descriptor_t **dps)
1.1 augustss 721: {
1.4 augustss 722: #ifdef UAUDIO_DEBUG
1.56 kent 723: struct usb_audio_output_terminal *d =
1.1 augustss 724: (struct usb_audio_output_terminal *)v;
725:
726: DPRINTFN(2,("uaudio_add_output: bTerminalId=%d wTerminalType=0x%04x "
727: "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
728: d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
729: d->bSourceId, d->iTerminal));
730: #endif
731: }
732:
733: void
1.26 augustss 734: uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v,
735: usb_descriptor_t **dps)
1.1 augustss 736: {
737: struct usb_audio_mixer_unit *d = (struct usb_audio_mixer_unit *)v;
738: struct usb_audio_mixer_unit_1 *d1;
739: int c, chs, ichs, ochs, i, o, bno, p, mo, mc, k;
740: uByte *bm;
741: struct mixerctl mix;
742:
743: DPRINTFN(2,("uaudio_add_mixer: bUnitId=%d bNrInPins=%d\n",
744: d->bUnitId, d->bNrInPins));
1.56 kent 745:
1.1 augustss 746: /* Compute the number of input channels */
747: ichs = 0;
748: for (i = 0; i < d->bNrInPins; i++)
749: ichs += uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
750:
751: /* and the number of output channels */
752: d1 = (struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins];
753: ochs = d1->bNrChannels;
754: DPRINTFN(2,("uaudio_add_mixer: ichs=%d ochs=%d\n", ichs, ochs));
755:
756: bm = d1->bmControls;
757: mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
758: mix.class = -1;
759: mix.type = MIX_SIGNED_16;
760: mix.ctlunit = AudioNvolume;
761: #define BIT(bno) ((bm[bno / 8] >> (7 - bno % 8)) & 1)
762: for (p = i = 0; i < d->bNrInPins; i++) {
763: chs = uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels;
764: mc = 0;
765: for (c = 0; c < chs; c++) {
766: mo = 0;
767: for (o = 0; o < ochs; o++) {
768: bno = (p + c) * ochs + o;
769: if (BIT(bno))
770: mo++;
771: }
772: if (mo == 1)
773: mc++;
774: }
775: if (mc == chs && chs <= MIX_MAX_CHAN) {
776: k = 0;
777: for (c = 0; c < chs; c++)
778: for (o = 0; o < ochs; o++) {
779: bno = (p + c) * ochs + o;
780: if (BIT(bno))
1.56 kent 781: mix.wValue[k++] =
1.1 augustss 782: MAKE(p+c+1, o+1);
783: }
1.70 itojun 784: snprintf(mix.ctlname, sizeof(mix.ctlname), "mix%d-%s",
785: d->bUnitId, uaudio_id_name(sc, dps,
786: d->baSourceId[i]));
1.1 augustss 787: mix.nchan = chs;
788: uaudio_mixer_add_ctl(sc, &mix);
789: } else {
790: /* XXX */
791: }
792: #undef BIT
793: p += chs;
794: }
795:
796: }
797:
798: void
1.26 augustss 799: uaudio_add_selector(struct uaudio_softc *sc, usb_descriptor_t *v,
800: usb_descriptor_t **dps)
1.1 augustss 801: {
1.4 augustss 802: #ifdef UAUDIO_DEBUG
1.1 augustss 803: struct usb_audio_selector_unit *d =
804: (struct usb_audio_selector_unit *)v;
805:
806: DPRINTFN(2,("uaudio_add_selector: bUnitId=%d bNrInPins=%d\n",
807: d->bUnitId, d->bNrInPins));
808: #endif
809: printf("uaudio_add_selector: NOT IMPLEMENTED\n");
810: }
811:
812: void
1.26 augustss 813: uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v,
814: usb_descriptor_t **dps)
1.1 augustss 815: {
816: struct usb_audio_feature_unit *d = (struct usb_audio_feature_unit *)v;
817: uByte *ctls = d->bmaControls;
818: int ctlsize = d->bControlSize;
819: int nchan = (d->bLength - 7) / ctlsize;
820: int srcId = d->bSourceId;
821: u_int fumask, mmask, cmask;
822: struct mixerctl mix;
823: int chan, ctl, i, unit;
824:
825: #define GET(i) (ctls[(i)*ctlsize] | \
826: (ctlsize > 1 ? ctls[(i)*ctlsize+1] << 8 : 0))
827:
828: mmask = GET(0);
829: /* Figure out what we can control */
830: for (cmask = 0, chan = 1; chan < nchan; chan++) {
831: DPRINTFN(9,("uaudio_add_feature: chan=%d mask=%x\n",
832: chan, GET(chan)));
833: cmask |= GET(chan);
834: }
835:
836: DPRINTFN(1,("uaudio_add_feature: bUnitId=%d bSourceId=%d, "
1.56 kent 837: "%d channels, mmask=0x%04x, cmask=0x%04x\n",
1.1 augustss 838: d->bUnitId, srcId, nchan, mmask, cmask));
839:
840: if (nchan > MIX_MAX_CHAN)
841: nchan = MIX_MAX_CHAN;
842: unit = d->bUnitId;
843: mix.wIndex = MAKE(unit, sc->sc_ac_iface);
844: for (ctl = MUTE_CONTROL; ctl < LOUDNESS_CONTROL; ctl++) {
845: fumask = FU_MASK(ctl);
846: DPRINTFN(4,("uaudio_add_feature: ctl=%d fumask=0x%04x\n",
847: ctl, fumask));
848: if (mmask & fumask) {
849: mix.nchan = 1;
850: mix.wValue[0] = MAKE(ctl, 0);
851: } else if (cmask & fumask) {
852: mix.nchan = nchan - 1;
853: for (i = 1; i < nchan; i++) {
854: if (GET(i) & fumask)
855: mix.wValue[i-1] = MAKE(ctl, i);
856: else
857: mix.wValue[i-1] = -1;
858: }
859: } else {
860: continue;
861: }
862: #undef GET
1.63 augustss 863: mix.class = UAC_OUTPUT; /* XXX we don't really know this */
1.1 augustss 864: switch (ctl) {
865: case MUTE_CONTROL:
866: mix.type = MIX_ON_OFF;
1.63 augustss 867: mix.ctlunit = "";
868: uaudio_mixer_alias_ctl(sc, &mix, AudioNmute);
1.70 itojun 869: snprintf(mix.ctlname, sizeof(mix.ctlname),
870: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
871: AudioNmute);
1.1 augustss 872: break;
873: case VOLUME_CONTROL:
874: mix.type = MIX_SIGNED_16;
1.63 augustss 875: mix.ctlunit = AudioNvolume;
876: uaudio_mixer_alias_ctl(sc, &mix, AudioNmaster);
1.70 itojun 877: snprintf(mix.ctlname, sizeof(mix.ctlname),
878: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
879: AudioNmaster);
1.1 augustss 880: break;
881: case BASS_CONTROL:
882: mix.type = MIX_SIGNED_8;
1.63 augustss 883: mix.ctlunit = AudioNbass;
884: uaudio_mixer_alias_ctl(sc, &mix, AudioNbass);
1.70 itojun 885: snprintf(mix.ctlname, sizeof(mix.ctlname),
886: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
887: AudioNbass);
1.1 augustss 888: break;
889: case MID_CONTROL:
890: mix.type = MIX_SIGNED_8;
1.63 augustss 891: mix.ctlunit = AudioNmid;
1.70 itojun 892: snprintf(mix.ctlname, sizeof(mix.ctlname),
893: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
894: AudioNmid);
1.1 augustss 895: break;
896: case TREBLE_CONTROL:
897: mix.type = MIX_SIGNED_8;
1.63 augustss 898: mix.ctlunit = AudioNtreble;
899: uaudio_mixer_alias_ctl(sc, &mix, AudioNtreble);
1.70 itojun 900: snprintf(mix.ctlname, sizeof(mix.ctlname),
901: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
902: AudioNtreble);
1.1 augustss 903: break;
904: case GRAPHIC_EQUALIZER_CONTROL:
1.7 augustss 905: continue; /* XXX don't add anything */
1.1 augustss 906: break;
907: case AGC_CONTROL:
908: mix.type = MIX_ON_OFF;
1.70 itojun 909: snprintf(mix.ctlname, sizeof(mix.ctlname),
910: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
911: AudioNagc);
1.1 augustss 912: mix.ctlunit = "";
913: break;
914: case DELAY_CONTROL:
915: mix.type = MIX_UNSIGNED_16;
1.70 itojun 916: snprintf(mix.ctlname, sizeof(mix.ctlname),
917: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
918: AudioNdelay);
1.1 augustss 919: mix.ctlunit = "4 ms";
920: break;
921: case BASS_BOOST_CONTROL:
922: mix.type = MIX_ON_OFF;
1.70 itojun 923: snprintf(mix.ctlname, sizeof(mix.ctlname),
924: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
925: AudioNbassboost);
1.1 augustss 926: mix.ctlunit = "";
927: break;
928: case LOUDNESS_CONTROL:
929: mix.type = MIX_ON_OFF;
1.70 itojun 930: snprintf(mix.ctlname, sizeof(mix.ctlname),
931: "fea%d-%s-%s", unit, uaudio_id_name(sc, dps, srcId),
932: AudioNloudness);
1.1 augustss 933: mix.ctlunit = "";
934: break;
935: }
936: uaudio_mixer_add_ctl(sc, &mix);
937: }
938: }
939:
940: void
1.26 augustss 941: uaudio_add_processing_updown(struct uaudio_softc *sc, usb_descriptor_t *v,
942: usb_descriptor_t **dps)
1.16 augustss 943: {
1.56 kent 944: struct usb_audio_processing_unit *d =
1.16 augustss 945: (struct usb_audio_processing_unit *)v;
946: struct usb_audio_processing_unit_1 *d1 =
947: (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
948: struct usb_audio_processing_unit_updown *ud =
949: (struct usb_audio_processing_unit_updown *)
950: &d1->bmControls[d1->bControlSize];
951: struct mixerctl mix;
952: int i;
953:
954: DPRINTFN(2,("uaudio_add_processing_updown: bUnitId=%d bNrModes=%d\n",
955: d->bUnitId, ud->bNrModes));
956:
957: if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) {
958: DPRINTF(("uaudio_add_processing_updown: no mode select\n"));
959: return;
960: }
961:
962: mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
963: mix.nchan = 1;
964: mix.wValue[0] = MAKE(UD_MODE_SELECT_CONTROL, 0);
965: mix.class = -1;
966: mix.type = MIX_ON_OFF; /* XXX */
967: mix.ctlunit = "";
1.70 itojun 968: snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d-mode", d->bUnitId);
1.16 augustss 969:
970: for (i = 0; i < ud->bNrModes; i++) {
971: DPRINTFN(2,("uaudio_add_processing_updown: i=%d bm=0x%x\n",
972: i, UGETW(ud->waModes[i])));
973: /* XXX */
974: }
975: uaudio_mixer_add_ctl(sc, &mix);
976: }
977:
978: void
1.26 augustss 979: uaudio_add_processing(struct uaudio_softc *sc, usb_descriptor_t *v,
980: usb_descriptor_t **dps)
1.1 augustss 981: {
1.56 kent 982: struct usb_audio_processing_unit *d =
1.15 augustss 983: (struct usb_audio_processing_unit *)v;
984: struct usb_audio_processing_unit_1 *d1 =
985: (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins];
986: int ptype = UGETW(d->wProcessType);
987: struct mixerctl mix;
988:
989: DPRINTFN(2,("uaudio_add_processing: wProcessType=%d bUnitId=%d "
990: "bNrInPins=%d\n", ptype, d->bUnitId, d->bNrInPins));
991:
992: if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) {
993: mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
994: mix.nchan = 1;
995: mix.wValue[0] = MAKE(XX_ENABLE_CONTROL, 0);
996: mix.class = -1;
997: mix.type = MIX_ON_OFF;
998: mix.ctlunit = "";
1.70 itojun 999: snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d.%d-enable",
1000: d->bUnitId, ptype);
1.15 augustss 1001: uaudio_mixer_add_ctl(sc, &mix);
1002: }
1.1 augustss 1003:
1.15 augustss 1004: switch(ptype) {
1005: case UPDOWNMIX_PROCESS:
1.16 augustss 1006: uaudio_add_processing_updown(sc, v, dps);
1007: break;
1.15 augustss 1008: case DOLBY_PROLOGIC_PROCESS:
1009: case P3D_STEREO_EXTENDER_PROCESS:
1010: case REVERBATION_PROCESS:
1011: case CHORUS_PROCESS:
1012: case DYN_RANGE_COMP_PROCESS:
1013: default:
1014: #ifdef UAUDIO_DEBUG
1015: printf("uaudio_add_processing: unit %d, type=%d not impl.\n",
1016: d->bUnitId, ptype);
1.1 augustss 1017: #endif
1.15 augustss 1018: break;
1019: }
1.1 augustss 1020: }
1021:
1022: void
1.26 augustss 1023: uaudio_add_extension(struct uaudio_softc *sc, usb_descriptor_t *v,
1024: usb_descriptor_t **dps)
1.1 augustss 1025: {
1.56 kent 1026: struct usb_audio_extension_unit *d =
1.1 augustss 1027: (struct usb_audio_extension_unit *)v;
1028: struct usb_audio_extension_unit_1 *d1 =
1029: (struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins];
1030: struct mixerctl mix;
1031:
1032: DPRINTFN(2,("uaudio_add_extension: bUnitId=%d bNrInPins=%d\n",
1033: d->bUnitId, d->bNrInPins));
1.28 augustss 1034:
1.31 augustss 1035: if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_XU)
1.28 augustss 1036: return;
1.1 augustss 1037:
1.15 augustss 1038: if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) {
1.1 augustss 1039: mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface);
1040: mix.nchan = 1;
1041: mix.wValue[0] = MAKE(UA_EXT_ENABLE, 0);
1042: mix.class = -1;
1043: mix.type = MIX_ON_OFF;
1044: mix.ctlunit = "";
1.70 itojun 1045: snprintf(mix.ctlname, sizeof(mix.ctlname), "ext%d-enable",
1046: d->bUnitId);
1.1 augustss 1047: uaudio_mixer_add_ctl(sc, &mix);
1048: }
1049: }
1050:
1051: usbd_status
1.26 augustss 1052: uaudio_identify(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
1.1 augustss 1053: {
1.9 augustss 1054: usbd_status err;
1.1 augustss 1055:
1.9 augustss 1056: err = uaudio_identify_ac(sc, cdesc);
1057: if (err)
1058: return (err);
1.1 augustss 1059: return (uaudio_identify_as(sc, cdesc));
1060: }
1061:
1062: void
1.26 augustss 1063: uaudio_add_alt(struct uaudio_softc *sc, struct as_info *ai)
1.1 augustss 1064: {
1.42 christos 1065: size_t len = sizeof(*ai) * (sc->sc_nalts + 1);
1.47 jdolecek 1066: struct as_info *nai = (sc->sc_nalts == 0) ?
1.42 christos 1067: malloc(len, M_USBDEV, M_NOWAIT) :
1068: realloc(sc->sc_alts, len, M_USBDEV, M_NOWAIT);
1069:
1070: if (nai == NULL) {
1.1 augustss 1071: printf("uaudio_add_alt: no memory\n");
1072: return;
1073: }
1.42 christos 1074:
1075: sc->sc_alts = nai;
1.1 augustss 1076: DPRINTFN(2,("uaudio_add_alt: adding alt=%d, enc=%d\n",
1077: ai->alt, ai->encoding));
1078: sc->sc_alts[sc->sc_nalts++] = *ai;
1079: }
1080:
1081: usbd_status
1.26 augustss 1082: uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp,
1083: int size, usb_interface_descriptor_t *id)
1.1 augustss 1084: #define offs (*offsp)
1085: {
1086: struct usb_audio_streaming_interface_descriptor *asid;
1087: struct usb_audio_streaming_type1_descriptor *asf1d;
1088: usb_endpoint_descriptor_audio_t *ed;
1089: struct usb_audio_streaming_endpoint_descriptor *sed;
1090: int format, chan, prec, enc;
1.5 augustss 1091: int dir, type;
1.1 augustss 1092: struct as_info ai;
1093:
1094: asid = (void *)(buf + offs);
1095: if (asid->bDescriptorType != UDESC_CS_INTERFACE ||
1096: asid->bDescriptorSubtype != AS_GENERAL)
1097: return (USBD_INVAL);
1098: offs += asid->bLength;
1099: if (offs > size)
1100: return (USBD_INVAL);
1101: asf1d = (void *)(buf + offs);
1102: if (asf1d->bDescriptorType != UDESC_CS_INTERFACE ||
1103: asf1d->bDescriptorSubtype != FORMAT_TYPE)
1104: return (USBD_INVAL);
1105: offs += asf1d->bLength;
1106: if (offs > size)
1107: return (USBD_INVAL);
1108:
1.3 augustss 1109: if (asf1d->bFormatType != FORMAT_TYPE_I) {
1110: printf("%s: ignored setting with type %d format\n",
1111: USBDEVNAME(sc->sc_dev), UGETW(asid->wFormatTag));
1112: return (USBD_NORMAL_COMPLETION);
1113: }
1114:
1.1 augustss 1115: ed = (void *)(buf + offs);
1116: if (ed->bDescriptorType != UDESC_ENDPOINT)
1117: return (USBD_INVAL);
1.5 augustss 1118: DPRINTF(("uaudio_process_as: endpoint bLength=%d bDescriptorType=%d "
1119: "bEndpointAddress=%d bmAttributes=0x%x wMaxPacketSize=%d "
1120: "bInterval=%d bRefresh=%d bSynchAddress=%d\n",
1121: ed->bLength, ed->bDescriptorType, ed->bEndpointAddress,
1122: ed->bmAttributes, UGETW(ed->wMaxPacketSize),
1123: ed->bInterval, ed->bRefresh, ed->bSynchAddress));
1.1 augustss 1124: offs += ed->bLength;
1125: if (offs > size)
1126: return (USBD_INVAL);
1.5 augustss 1127: if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
1.1 augustss 1128: return (USBD_INVAL);
1.5 augustss 1129:
1130: dir = UE_GET_DIR(ed->bEndpointAddress);
1131: type = UE_GET_ISO_TYPE(ed->bmAttributes);
1.31 augustss 1132: if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_INP_ASYNC) &&
1133: dir == UE_DIR_IN && type == UE_ISO_ADAPT)
1134: type = UE_ISO_ASYNC;
1135:
1.40 augustss 1136: /* We can't handle endpoints that need a sync pipe yet. */
1.5 augustss 1137: if (dir == UE_DIR_IN ? type == UE_ISO_ADAPT : type == UE_ISO_ASYNC) {
1.30 augustss 1138: printf("%s: ignored %sput endpoint of type %s\n",
1.1 augustss 1139: USBDEVNAME(sc->sc_dev),
1.5 augustss 1140: dir == UE_DIR_IN ? "in" : "out",
1.32 augustss 1141: dir == UE_DIR_IN ? "adaptive" : "async");
1.1 augustss 1142: return (USBD_NORMAL_COMPLETION);
1143: }
1.56 kent 1144:
1.1 augustss 1145: sed = (void *)(buf + offs);
1146: if (sed->bDescriptorType != UDESC_CS_ENDPOINT ||
1147: sed->bDescriptorSubtype != AS_GENERAL)
1148: return (USBD_INVAL);
1149: offs += sed->bLength;
1150: if (offs > size)
1151: return (USBD_INVAL);
1.56 kent 1152:
1.3 augustss 1153: format = UGETW(asid->wFormatTag);
1.1 augustss 1154: chan = asf1d->bNrChannels;
1155: prec = asf1d->bBitResolution;
1.51 kent 1156: if (prec != 8 && prec != 16 && prec != 24) {
1.1 augustss 1157: printf("%s: ignored setting with precision %d\n",
1158: USBDEVNAME(sc->sc_dev), prec);
1159: return (USBD_NORMAL_COMPLETION);
1160: }
1161: switch (format) {
1.3 augustss 1162: case UA_FMT_PCM:
1.51 kent 1163: if (prec == 8) {
1164: sc->sc_altflags |= HAS_8;
1165: } else if (prec == 16) {
1166: sc->sc_altflags |= HAS_16;
1167: } else if (prec == 24) {
1168: sc->sc_altflags |= HAS_24;
1169: }
1.5 augustss 1170: enc = AUDIO_ENCODING_SLINEAR_LE;
1.1 augustss 1171: break;
1.3 augustss 1172: case UA_FMT_PCM8:
1.5 augustss 1173: enc = AUDIO_ENCODING_ULINEAR_LE;
1.1 augustss 1174: sc->sc_altflags |= HAS_8U;
1175: break;
1.3 augustss 1176: case UA_FMT_ALAW:
1.5 augustss 1177: enc = AUDIO_ENCODING_ALAW;
1.1 augustss 1178: sc->sc_altflags |= HAS_ALAW;
1179: break;
1.3 augustss 1180: case UA_FMT_MULAW:
1.5 augustss 1181: enc = AUDIO_ENCODING_ULAW;
1.1 augustss 1182: sc->sc_altflags |= HAS_MULAW;
1183: break;
1184: default:
1185: printf("%s: ignored setting with format %d\n",
1186: USBDEVNAME(sc->sc_dev), format);
1187: return (USBD_NORMAL_COMPLETION);
1188: }
1.50 kent 1189: DPRINTFN(1, ("uaudio_process_as: alt=%d enc=%d chan=%d prec=%d\n",
1190: id->bAlternateSetting, enc, chan, prec));
1.1 augustss 1191: ai.alt = id->bAlternateSetting;
1192: ai.encoding = enc;
1.50 kent 1193: ai.attributes = sed->bmAttributes;
1.1 augustss 1194: ai.idesc = id;
1195: ai.edesc = ed;
1196: ai.asf1desc = asf1d;
1.50 kent 1197: ai.sc_busy = 0;
1.1 augustss 1198: uaudio_add_alt(sc, &ai);
1.50 kent 1199: #ifdef UAUDIO_DEBUG
1200: {
1201: int j;
1202: if (asf1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
1203: DPRINTFN(1, ("uaudio_process_as: rate=%d-%d\n",
1204: UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)));
1205: } else {
1.51 kent 1206: DPRINTFN(1, ("uaudio_process_as: "));
1.50 kent 1207: for (j = 0; j < asf1d->bSamFreqType; j++)
1208: DPRINTFN(1, (" %d", UA_GETSAMP(asf1d, j)));
1209: DPRINTFN(1, ("\n"));
1210: }
1211: if (ai.attributes & UA_SED_FREQ_CONTROL)
1.51 kent 1212: DPRINTFN(1, ("uaudio_process_as: FREQ_CONTROL\n"));
1.50 kent 1213: if (ai.attributes & UA_SED_PITCH_CONTROL)
1.51 kent 1214: DPRINTFN(1, ("uaudio_process_as: PITCH_CONTROL\n"));
1.50 kent 1215: }
1216: #endif
1.47 jdolecek 1217: sc->sc_mode |= (dir == UE_DIR_OUT) ? AUMODE_PLAY : AUMODE_RECORD;
1218:
1.1 augustss 1219: return (USBD_NORMAL_COMPLETION);
1220: }
1221: #undef offs
1.56 kent 1222:
1.1 augustss 1223: usbd_status
1.26 augustss 1224: uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
1.1 augustss 1225: {
1226: usb_interface_descriptor_t *id;
1227: char *buf;
1228: int size, offs;
1229:
1230: size = UGETW(cdesc->wTotalLength);
1231: buf = (char *)cdesc;
1232:
1233: /* Locate the AudioStreaming interface descriptor. */
1234: offs = 0;
1.19 augustss 1235: id = uaudio_find_iface(buf, size, &offs, UISUBCLASS_AUDIOSTREAM);
1.9 augustss 1236: if (id == NULL)
1.1 augustss 1237: return (USBD_INVAL);
1238:
1239: /* Loop through all the alternate settings. */
1240: while (offs <= size) {
1.37 mycroft 1241: DPRINTFN(2, ("uaudio_identify: interface %d\n",
1242: id->bInterfaceNumber));
1.1 augustss 1243: switch (id->bNumEndpoints) {
1244: case 0:
1245: DPRINTFN(2, ("uaudio_identify: AS null alt=%d\n",
1246: id->bAlternateSetting));
1247: sc->sc_nullalt = id->bAlternateSetting;
1248: break;
1249: case 1:
1.64 simonb 1250: uaudio_process_as(sc, buf, &offs, size, id);
1.1 augustss 1251: break;
1252: default:
1.35 mycroft 1253: #ifdef UAUDIO_DEBUG
1.1 augustss 1254: printf("%s: ignored audio interface with %d "
1255: "endpoints\n",
1256: USBDEVNAME(sc->sc_dev), id->bNumEndpoints);
1257: #endif
1258: break;
1259: }
1.19 augustss 1260: id = uaudio_find_iface(buf, size, &offs,UISUBCLASS_AUDIOSTREAM);
1.9 augustss 1261: if (id == NULL)
1.1 augustss 1262: break;
1263: }
1264: if (offs > size)
1265: return (USBD_INVAL);
1266: DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts));
1.47 jdolecek 1267:
1268: if ((sc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD)) == 0) {
1.56 kent 1269: printf("%s: no usable endpoint found\n",
1.5 augustss 1270: USBDEVNAME(sc->sc_dev));
1271: return (USBD_INVAL);
1272: }
1.47 jdolecek 1273:
1.1 augustss 1274: return (USBD_NORMAL_COMPLETION);
1275: }
1276:
1277: usbd_status
1.26 augustss 1278: uaudio_identify_ac(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
1.1 augustss 1279: {
1280: usb_interface_descriptor_t *id;
1281: struct usb_audio_control_descriptor *acdp;
1282: usb_descriptor_t *dp, *dps[256];
1283: char *buf, *ibuf, *ibufend;
1284: int size, offs, aclen, ndps, i;
1285:
1286: size = UGETW(cdesc->wTotalLength);
1287: buf = (char *)cdesc;
1288:
1289: /* Locate the AudioControl interface descriptor. */
1290: offs = 0;
1.19 augustss 1291: id = uaudio_find_iface(buf, size, &offs, UISUBCLASS_AUDIOCONTROL);
1.14 augustss 1292: if (id == NULL)
1.1 augustss 1293: return (USBD_INVAL);
1294: if (offs + sizeof *acdp > size)
1295: return (USBD_INVAL);
1296: sc->sc_ac_iface = id->bInterfaceNumber;
1297: DPRINTFN(2,("uaudio_identify: AC interface is %d\n", sc->sc_ac_iface));
1298:
1299: /* A class-specific AC interface header should follow. */
1300: ibuf = buf + offs;
1301: acdp = (struct usb_audio_control_descriptor *)ibuf;
1302: if (acdp->bDescriptorType != UDESC_CS_INTERFACE ||
1303: acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)
1304: return (USBD_INVAL);
1305: aclen = UGETW(acdp->wTotalLength);
1306: if (offs + aclen > size)
1307: return (USBD_INVAL);
1.5 augustss 1308:
1.1 augustss 1309: if (!(usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_BAD_ADC) &&
1310: UGETW(acdp->bcdADC) != UAUDIO_VERSION)
1311: return (USBD_INVAL);
1312:
1.7 augustss 1313: sc->sc_audio_rev = UGETW(acdp->bcdADC);
1.1 augustss 1314: DPRINTFN(2,("uaudio_identify: found AC header, vers=%03x, len=%d\n",
1.7 augustss 1315: sc->sc_audio_rev, aclen));
1.1 augustss 1316:
1317: sc->sc_nullalt = -1;
1318:
1319: /* Scan through all the AC specific descriptors */
1320: ibufend = ibuf + aclen;
1321: dp = (usb_descriptor_t *)ibuf;
1322: ndps = 0;
1323: memset(dps, 0, sizeof dps);
1324: for (;;) {
1325: ibuf += dp->bLength;
1326: if (ibuf >= ibufend)
1327: break;
1328: dp = (usb_descriptor_t *)ibuf;
1329: if (ibuf + dp->bLength > ibufend)
1330: return (USBD_INVAL);
1331: if (dp->bDescriptorType != UDESC_CS_INTERFACE) {
1332: printf("uaudio_identify: skip desc type=0x%02x\n",
1333: dp->bDescriptorType);
1334: continue;
1335: }
1336: i = ((struct usb_audio_input_terminal *)dp)->bTerminalId;
1337: dps[i] = dp;
1338: if (i > ndps)
1339: ndps = i;
1340: }
1341: ndps++;
1342:
1343: for (i = 0; i < ndps; i++) {
1344: dp = dps[i];
1.14 augustss 1345: if (dp == NULL)
1.1 augustss 1346: continue;
1.56 kent 1347: DPRINTF(("uaudio_identify: subtype=%d\n",
1.1 augustss 1348: dp->bDescriptorSubtype));
1349: switch (dp->bDescriptorSubtype) {
1350: case UDESCSUB_AC_HEADER:
1351: printf("uaudio_identify: unexpected AC header\n");
1352: break;
1353: case UDESCSUB_AC_INPUT:
1354: uaudio_add_input(sc, dp, dps);
1355: break;
1356: case UDESCSUB_AC_OUTPUT:
1357: uaudio_add_output(sc, dp, dps);
1358: break;
1359: case UDESCSUB_AC_MIXER:
1360: uaudio_add_mixer(sc, dp, dps);
1361: break;
1362: case UDESCSUB_AC_SELECTOR:
1363: uaudio_add_selector(sc, dp, dps);
1364: break;
1365: case UDESCSUB_AC_FEATURE:
1366: uaudio_add_feature(sc, dp, dps);
1367: break;
1368: case UDESCSUB_AC_PROCESSING:
1369: uaudio_add_processing(sc, dp, dps);
1370: break;
1371: case UDESCSUB_AC_EXTENSION:
1372: uaudio_add_extension(sc, dp, dps);
1373: break;
1374: default:
1375: printf("uaudio_identify: bad AC desc subtype=0x%02x\n",
1376: dp->bDescriptorSubtype);
1377: break;
1378: }
1379: }
1380: return (USBD_NORMAL_COMPLETION);
1381: }
1382:
1383: int
1.26 augustss 1384: uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi)
1.1 augustss 1385: {
1386: struct uaudio_softc *sc = addr;
1387: struct mixerctl *mc;
1388: int n, nctls;
1389:
1390: DPRINTFN(2,("uaudio_query_devinfo: index=%d\n", mi->index));
1391: if (sc->sc_dying)
1392: return (EIO);
1.56 kent 1393:
1.1 augustss 1394: n = mi->index;
1395: nctls = sc->sc_nctls;
1396:
1.63 augustss 1397: switch (n) {
1398: case UAC_OUTPUT:
1399: mi->type = AUDIO_MIXER_CLASS;
1400: mi->mixer_class = UAC_OUTPUT;
1401: mi->next = mi->prev = AUDIO_MIXER_LAST;
1.71 itojun 1402: strlcpy(mi->label.name, AudioCoutputs, sizeof(mi->label.name));
1.63 augustss 1403: return (0);
1404: case UAC_INPUT:
1405: mi->type = AUDIO_MIXER_CLASS;
1406: mi->mixer_class = UAC_INPUT;
1407: mi->next = mi->prev = AUDIO_MIXER_LAST;
1.71 itojun 1408: strlcpy(mi->label.name, AudioCinputs, sizeof(mi->label.name));
1.63 augustss 1409: return (0);
1410: case UAC_EQUAL:
1411: mi->type = AUDIO_MIXER_CLASS;
1412: mi->mixer_class = UAC_EQUAL;
1413: mi->next = mi->prev = AUDIO_MIXER_LAST;
1.71 itojun 1414: strlcpy(mi->label.name, AudioCequalization,
1415: sizeof(mi->label.name));
1.63 augustss 1416: return (0);
1417: default:
1418: break;
1.1 augustss 1419: }
1.63 augustss 1420:
1421: n -= UAC_NCLASSES;
1422: if (n < 0 || n >= nctls)
1423: return (ENXIO);
1424:
1.1 augustss 1425: mc = &sc->sc_ctls[n];
1.71 itojun 1426: strlcpy(mi->label.name, mc->ctlname, sizeof(mi->label.name));
1.1 augustss 1427: mi->mixer_class = mc->class;
1428: mi->next = mi->prev = AUDIO_MIXER_LAST; /* XXX */
1429: switch (mc->type) {
1430: case MIX_ON_OFF:
1431: mi->type = AUDIO_MIXER_ENUM;
1432: mi->un.e.num_mem = 2;
1.71 itojun 1433: strlcpy(mi->un.e.member[0].label.name, AudioNoff,
1434: sizeof(mi->un.e.member[0].label.name));
1.1 augustss 1435: mi->un.e.member[0].ord = 0;
1.71 itojun 1436: strlcpy(mi->un.e.member[1].label.name, AudioNon,
1437: sizeof(mi->un.e.member[1].label.name));
1.1 augustss 1438: mi->un.e.member[1].ord = 1;
1439: break;
1440: default:
1441: mi->type = AUDIO_MIXER_VALUE;
1442: strncpy(mi->un.v.units.name, mc->ctlunit, MAX_AUDIO_DEV_LEN);
1443: mi->un.v.num_channels = mc->nchan;
1.33 augustss 1444: mi->un.v.delta = mc->delta;
1.1 augustss 1445: break;
1446: }
1447: return (0);
1448: }
1449:
1450: int
1.26 augustss 1451: uaudio_open(void *addr, int flags)
1.1 augustss 1452: {
1453: struct uaudio_softc *sc = addr;
1454:
1.56 kent 1455: DPRINTF(("uaudio_open: sc=%p\n", sc));
1.1 augustss 1456: if (sc->sc_dying)
1457: return (EIO);
1458:
1.47 jdolecek 1459: if (sc->sc_mode == 0)
1.5 augustss 1460: return (ENXIO);
1461:
1.47 jdolecek 1462: if (flags & FREAD) {
1463: if ((sc->sc_mode & AUMODE_RECORD) == 0)
1.49 simonb 1464: return (EACCES);
1.47 jdolecek 1465: sc->sc_recchan.intr = NULL;
1466: }
1.1 augustss 1467:
1.47 jdolecek 1468: if (flags & FWRITE) {
1469: if ((sc->sc_mode & AUMODE_PLAY) == 0)
1470: return (EACCES);
1471: sc->sc_playchan.intr = NULL;
1472: }
1.1 augustss 1473:
1.56 kent 1474: return (0);
1.1 augustss 1475: }
1476:
1477: /*
1478: * Close function is called at splaudio().
1479: */
1480: void
1.26 augustss 1481: uaudio_close(void *addr)
1.1 augustss 1482: {
1483: struct uaudio_softc *sc = addr;
1484:
1485: DPRINTF(("uaudio_close: sc=%p\n", sc));
1486: uaudio_halt_in_dma(sc);
1487: uaudio_halt_out_dma(sc);
1488:
1.47 jdolecek 1489: sc->sc_playchan.intr = sc->sc_recchan.intr = NULL;
1.1 augustss 1490: }
1491:
1492: int
1.26 augustss 1493: uaudio_drain(void *addr)
1.1 augustss 1494: {
1495: struct uaudio_softc *sc = addr;
1496:
1497: usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
1498:
1499: return (0);
1500: }
1501:
1502: int
1.26 augustss 1503: uaudio_halt_out_dma(void *addr)
1.1 augustss 1504: {
1505: struct uaudio_softc *sc = addr;
1506:
1507: DPRINTF(("uaudio_halt_out_dma: enter\n"));
1.47 jdolecek 1508: if (sc->sc_playchan.pipe != NULL) {
1509: uaudio_chan_close(sc, &sc->sc_playchan);
1510: sc->sc_playchan.pipe = NULL;
1511: uaudio_chan_free_buffers(sc, &sc->sc_playchan);
1.1 augustss 1512: }
1.56 kent 1513: return (0);
1.1 augustss 1514: }
1515:
1516: int
1.26 augustss 1517: uaudio_halt_in_dma(void *addr)
1.1 augustss 1518: {
1519: struct uaudio_softc *sc = addr;
1520:
1521: DPRINTF(("uaudio_halt_in_dma: enter\n"));
1.47 jdolecek 1522: if (sc->sc_recchan.pipe != NULL) {
1523: uaudio_chan_close(sc, &sc->sc_recchan);
1524: sc->sc_recchan.pipe = NULL;
1525: uaudio_chan_free_buffers(sc, &sc->sc_recchan);
1.5 augustss 1526: }
1.56 kent 1527: return (0);
1.1 augustss 1528: }
1529:
1530: int
1.26 augustss 1531: uaudio_getdev(void *addr, struct audio_device *retp)
1.1 augustss 1532: {
1533: struct uaudio_softc *sc = addr;
1534:
1535: DPRINTF(("uaudio_mixer_getdev:\n"));
1536: if (sc->sc_dying)
1537: return (EIO);
1.56 kent 1538:
1.1 augustss 1539: *retp = uaudio_device;
1.56 kent 1540: return (0);
1.1 augustss 1541: }
1542:
1543: /*
1544: * Make sure the block size is large enough to hold all outstanding transfers.
1545: */
1546: int
1.26 augustss 1547: uaudio_round_blocksize(void *addr, int blk)
1.1 augustss 1548: {
1549: struct uaudio_softc *sc = addr;
1550: int bpf;
1551:
1.54 kent 1552: DPRINTF(("uaudio_round_blocksize: p.bpf=%d r.bpf=%d\n",
1.56 kent 1553: sc->sc_playchan.bytes_per_frame,
1554: sc->sc_recchan.bytes_per_frame));
1.47 jdolecek 1555: if (sc->sc_playchan.bytes_per_frame > sc->sc_recchan.bytes_per_frame) {
1556: bpf = sc->sc_playchan.bytes_per_frame
1557: + sc->sc_playchan.sample_size;
1558: } else {
1559: bpf = sc->sc_recchan.bytes_per_frame
1560: + sc->sc_recchan.sample_size;
1561: }
1.1 augustss 1562: /* XXX */
1563: bpf *= UAUDIO_NFRAMES * UAUDIO_NCHANBUFS;
1564:
1565: bpf = (bpf + 15) &~ 15;
1566:
1567: if (blk < bpf)
1568: blk = bpf;
1569:
1.5 augustss 1570: #ifdef DIAGNOSTIC
1571: if (blk <= 0) {
1572: printf("uaudio_round_blocksize: blk=%d\n", blk);
1573: blk = 512;
1574: }
1575: #endif
1576:
1.1 augustss 1577: DPRINTFN(1,("uaudio_round_blocksize: blk=%d\n", blk));
1578: return (blk);
1579: }
1580:
1581: int
1.26 augustss 1582: uaudio_get_props(void *addr)
1.1 augustss 1583: {
1.47 jdolecek 1584: return (AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT);
1.1 augustss 1585:
1586: }
1587:
1588: int
1.27 augustss 1589: uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
1.26 augustss 1590: int wIndex, int len)
1.1 augustss 1591: {
1592: usb_device_request_t req;
1593: u_int8_t data[4];
1.9 augustss 1594: usbd_status err;
1.1 augustss 1595: int val;
1596:
1597: if (wValue == -1)
1598: return (0);
1599:
1600: req.bmRequestType = type;
1601: req.bRequest = which;
1602: USETW(req.wValue, wValue);
1603: USETW(req.wIndex, wIndex);
1604: USETW(req.wLength, len);
1605: DPRINTFN(2,("uaudio_get: type=0x%02x req=0x%02x wValue=0x%04x "
1.56 kent 1606: "wIndex=0x%04x len=%d\n",
1.1 augustss 1607: type, which, wValue, wIndex, len));
1.47 jdolecek 1608: err = usbd_do_request(sc->sc_udev, &req, data);
1.9 augustss 1609: if (err) {
1.20 augustss 1610: DPRINTF(("uaudio_get: err=%s\n", usbd_errstr(err)));
1.1 augustss 1611: return (-1);
1612: }
1613: switch (len) {
1614: case 1:
1615: val = data[0];
1616: break;
1617: case 2:
1618: val = data[0] | (data[1] << 8);
1619: break;
1620: default:
1621: DPRINTF(("uaudio_get: bad length=%d\n", len));
1622: return (-1);
1623: }
1624: DPRINTFN(2,("uaudio_get: val=%d\n", val));
1625: return (val);
1626: }
1627:
1628: void
1.27 augustss 1629: uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
1.26 augustss 1630: int wIndex, int len, int val)
1.1 augustss 1631: {
1632: usb_device_request_t req;
1633: u_int8_t data[4];
1.9 augustss 1634: usbd_status err;
1.1 augustss 1635:
1636: if (wValue == -1)
1637: return;
1638:
1639: req.bmRequestType = type;
1640: req.bRequest = which;
1641: USETW(req.wValue, wValue);
1642: USETW(req.wIndex, wIndex);
1643: USETW(req.wLength, len);
1644: switch (len) {
1645: case 1:
1646: data[0] = val;
1647: break;
1648: case 2:
1649: data[0] = val;
1650: data[1] = val >> 8;
1651: break;
1652: default:
1653: return;
1654: }
1655: DPRINTFN(2,("uaudio_set: type=0x%02x req=0x%02x wValue=0x%04x "
1.56 kent 1656: "wIndex=0x%04x len=%d, val=%d\n",
1.1 augustss 1657: type, which, wValue, wIndex, len, val & 0xffff));
1.47 jdolecek 1658: err = usbd_do_request(sc->sc_udev, &req, data);
1.4 augustss 1659: #ifdef UAUDIO_DEBUG
1.12 augustss 1660: if (err)
1.9 augustss 1661: DPRINTF(("uaudio_set: err=%d\n", err));
1.1 augustss 1662: #endif
1663: }
1664:
1665: int
1.26 augustss 1666: uaudio_signext(int type, int val)
1.1 augustss 1667: {
1668: if (!MIX_UNSIGNED(type)) {
1669: if (MIX_SIZE(type) == 2)
1670: val = (int16_t)val;
1671: else
1672: val = (int8_t)val;
1673: }
1674: return (val);
1675: }
1676:
1677: int
1.26 augustss 1678: uaudio_value2bsd(struct mixerctl *mc, int val)
1.1 augustss 1679: {
1680: DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ",
1681: mc->type, val, mc->minval, mc->maxval));
1682: if (mc->type == MIX_ON_OFF)
1.47 jdolecek 1683: val = (val != 0);
1.1 augustss 1684: else
1.69 wiz 1685: val = ((uaudio_signext(mc->type, val) - mc->minval) * 255
1.34 augustss 1686: + mc->mul/2) / mc->mul;
1.1 augustss 1687: DPRINTFN(5, ("val'=%d\n", val));
1688: return (val);
1689: }
1690:
1691: int
1.26 augustss 1692: uaudio_bsd2value(struct mixerctl *mc, int val)
1.1 augustss 1693: {
1694: DPRINTFN(5,("uaudio_bsd2value: type=%03x val=%d min=%d max=%d ",
1695: mc->type, val, mc->minval, mc->maxval));
1696: if (mc->type == MIX_ON_OFF)
1.47 jdolecek 1697: val = (val != 0);
1.1 augustss 1698: else
1.69 wiz 1699: val = (val + mc->delta/2) * mc->mul / 255 + mc->minval;
1.1 augustss 1700: DPRINTFN(5, ("val'=%d\n", val));
1701: return (val);
1702: }
1703:
1704: int
1.56 kent 1705: uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
1.26 augustss 1706: int chan)
1.1 augustss 1707: {
1708: int val;
1709:
1710: DPRINTFN(5,("uaudio_ctl_get: which=%d chan=%d\n", which, chan));
1711: val = uaudio_get(sc, which, UT_READ_CLASS_INTERFACE, mc->wValue[chan],
1712: mc->wIndex, MIX_SIZE(mc->type));
1713: return (uaudio_value2bsd(mc, val));
1714: }
1715:
1716: void
1.26 augustss 1717: uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
1718: int chan, int val)
1.1 augustss 1719: {
1720: val = uaudio_bsd2value(mc, val);
1721: uaudio_set(sc, which, UT_WRITE_CLASS_INTERFACE, mc->wValue[chan],
1722: mc->wIndex, MIX_SIZE(mc->type), val);
1723: }
1724:
1725: int
1.26 augustss 1726: uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1.1 augustss 1727: {
1728: struct uaudio_softc *sc = addr;
1729: struct mixerctl *mc;
1730: int i, n, vals[MIX_MAX_CHAN], val;
1731:
1732: DPRINTFN(2,("uaudio_mixer_get_port: index=%d\n", cp->dev));
1733:
1734: if (sc->sc_dying)
1735: return (EIO);
1.56 kent 1736:
1.63 augustss 1737: n = cp->dev - UAC_NCLASSES;
1.1 augustss 1738: if (n < 0 || n >= sc->sc_nctls)
1739: return (ENXIO);
1740: mc = &sc->sc_ctls[n];
1741:
1742: if (mc->type == MIX_ON_OFF) {
1743: if (cp->type != AUDIO_MIXER_ENUM)
1744: return (EINVAL);
1745: cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0);
1746: } else {
1747: if (cp->type != AUDIO_MIXER_VALUE)
1748: return (EINVAL);
1749: if (cp->un.value.num_channels != 1 &&
1750: cp->un.value.num_channels != mc->nchan)
1751: return (EINVAL);
1752: for (i = 0; i < mc->nchan; i++)
1753: vals[i] = uaudio_ctl_get(sc, GET_CUR, mc, i);
1754: if (cp->un.value.num_channels == 1 && mc->nchan != 1) {
1755: for (val = 0, i = 0; i < mc->nchan; i++)
1756: val += vals[i];
1757: vals[0] = val / mc->nchan;
1758: }
1759: for (i = 0; i < cp->un.value.num_channels; i++)
1760: cp->un.value.level[i] = vals[i];
1761: }
1762:
1763: return (0);
1764: }
1.56 kent 1765:
1.1 augustss 1766: int
1.26 augustss 1767: uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1.1 augustss 1768: {
1769: struct uaudio_softc *sc = addr;
1770: struct mixerctl *mc;
1771: int i, n, vals[MIX_MAX_CHAN];
1772:
1773: DPRINTFN(2,("uaudio_mixer_set_port: index = %d\n", cp->dev));
1774: if (sc->sc_dying)
1775: return (EIO);
1.56 kent 1776:
1.63 augustss 1777: n = cp->dev - UAC_NCLASSES;
1.1 augustss 1778: if (n < 0 || n >= sc->sc_nctls)
1779: return (ENXIO);
1780: mc = &sc->sc_ctls[n];
1781:
1782: if (mc->type == MIX_ON_OFF) {
1783: if (cp->type != AUDIO_MIXER_ENUM)
1784: return (EINVAL);
1785: uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord);
1786: } else {
1787: if (cp->type != AUDIO_MIXER_VALUE)
1788: return (EINVAL);
1789: if (cp->un.value.num_channels == 1)
1790: for (i = 0; i < mc->nchan; i++)
1791: vals[i] = cp->un.value.level[0];
1792: else if (cp->un.value.num_channels == mc->nchan)
1793: for (i = 0; i < mc->nchan; i++)
1794: vals[i] = cp->un.value.level[i];
1795: else
1796: return (EINVAL);
1797: for (i = 0; i < mc->nchan; i++)
1798: uaudio_ctl_set(sc, SET_CUR, mc, i, vals[i]);
1799: }
1800: return (0);
1801: }
1802:
1803: int
1.26 augustss 1804: uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
1805: void (*intr)(void *), void *arg,
1806: struct audio_params *param)
1.1 augustss 1807: {
1808: struct uaudio_softc *sc = addr;
1.47 jdolecek 1809: struct chan *ch = &sc->sc_recchan;
1.9 augustss 1810: usbd_status err;
1.5 augustss 1811: int i, s;
1.1 augustss 1812:
1813: if (sc->sc_dying)
1814: return (EIO);
1815:
1.5 augustss 1816: DPRINTFN(3,("uaudio_trigger_input: sc=%p start=%p end=%p "
1.1 augustss 1817: "blksize=%d\n", sc, start, end, blksize));
1818:
1.54 kent 1819: uaudio_chan_set_param(ch, start, end, blksize);
1.5 augustss 1820: DPRINTFN(3,("uaudio_trigger_input: sample_size=%d bytes/frame=%d "
1821: "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
1822: ch->fraction));
1823:
1.9 augustss 1824: err = uaudio_chan_alloc_buffers(sc, ch);
1825: if (err)
1.5 augustss 1826: return (EIO);
1827:
1.9 augustss 1828: err = uaudio_chan_open(sc, ch);
1829: if (err) {
1.5 augustss 1830: uaudio_chan_free_buffers(sc, ch);
1831: return (EIO);
1832: }
1833:
1.47 jdolecek 1834: ch->intr = intr;
1835: ch->arg = arg;
1.5 augustss 1836:
1837: s = splusb();
1.22 augustss 1838: for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
1.5 augustss 1839: uaudio_chan_rtransfer(ch);
1840: splx(s);
1841:
1.56 kent 1842: return (0);
1.1 augustss 1843: }
1.56 kent 1844:
1.1 augustss 1845: int
1.26 augustss 1846: uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
1847: void (*intr)(void *), void *arg,
1848: struct audio_params *param)
1.1 augustss 1849: {
1850: struct uaudio_softc *sc = addr;
1.47 jdolecek 1851: struct chan *ch = &sc->sc_playchan;
1.9 augustss 1852: usbd_status err;
1.1 augustss 1853: int i, s;
1854:
1855: if (sc->sc_dying)
1856: return (EIO);
1857:
1858: DPRINTFN(3,("uaudio_trigger_output: sc=%p start=%p end=%p "
1859: "blksize=%d\n", sc, start, end, blksize));
1860:
1.54 kent 1861: uaudio_chan_set_param(ch, start, end, blksize);
1.1 augustss 1862: DPRINTFN(3,("uaudio_trigger_output: sample_size=%d bytes/frame=%d "
1863: "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
1864: ch->fraction));
1865:
1.9 augustss 1866: err = uaudio_chan_alloc_buffers(sc, ch);
1867: if (err)
1.1 augustss 1868: return (EIO);
1869:
1.9 augustss 1870: err = uaudio_chan_open(sc, ch);
1871: if (err) {
1.1 augustss 1872: uaudio_chan_free_buffers(sc, ch);
1873: return (EIO);
1874: }
1875:
1.47 jdolecek 1876: ch->intr = intr;
1877: ch->arg = arg;
1.1 augustss 1878:
1879: s = splusb();
1.22 augustss 1880: for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
1.5 augustss 1881: uaudio_chan_ptransfer(ch);
1.1 augustss 1882: splx(s);
1883:
1.56 kent 1884: return (0);
1.1 augustss 1885: }
1886:
1887: /* Set up a pipe for a channel. */
1888: usbd_status
1.26 augustss 1889: uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
1.1 augustss 1890: {
1.47 jdolecek 1891: struct as_info *as = &sc->sc_alts[ch->altidx];
1.1 augustss 1892: int endpt = as->edesc->bEndpointAddress;
1.9 augustss 1893: usbd_status err;
1.1 augustss 1894:
1.56 kent 1895: DPRINTF(("uaudio_chan_open: endpt=0x%02x, speed=%d, alt=%d\n",
1.1 augustss 1896: endpt, ch->sample_rate, as->alt));
1897:
1898: /* Set alternate interface corresponding to the mode. */
1.37 mycroft 1899: err = usbd_set_interface(as->ifaceh, as->alt);
1.9 augustss 1900: if (err)
1901: return (err);
1.1 augustss 1902:
1903: /* Some devices do not support this request, so ignore errors. */
1.4 augustss 1904: #ifdef UAUDIO_DEBUG
1.9 augustss 1905: err = uaudio_set_speed(sc, endpt, ch->sample_rate);
1906: if (err)
1907: DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n",
1908: usbd_errstr(err)));
1.1 augustss 1909: #else
1910: (void)uaudio_set_speed(sc, endpt, ch->sample_rate);
1911: #endif
1912:
1.47 jdolecek 1913: DPRINTF(("uaudio_chan_open: create pipe to 0x%02x\n", endpt));
1.37 mycroft 1914: err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->pipe);
1.9 augustss 1915: return (err);
1.1 augustss 1916: }
1917:
1918: void
1.26 augustss 1919: uaudio_chan_close(struct uaudio_softc *sc, struct chan *ch)
1.1 augustss 1920: {
1.47 jdolecek 1921: struct as_info *as = &sc->sc_alts[ch->altidx];
1.37 mycroft 1922:
1.58 kent 1923: as->sc_busy = 0;
1.1 augustss 1924: if (sc->sc_nullalt >= 0) {
1.47 jdolecek 1925: DPRINTF(("uaudio_chan_close: set null alt=%d\n",
1.1 augustss 1926: sc->sc_nullalt));
1.37 mycroft 1927: usbd_set_interface(as->ifaceh, sc->sc_nullalt);
1.1 augustss 1928: }
1929: usbd_abort_pipe(ch->pipe);
1930: usbd_close_pipe(ch->pipe);
1931: }
1932:
1933: usbd_status
1.26 augustss 1934: uaudio_chan_alloc_buffers(struct uaudio_softc *sc, struct chan *ch)
1.1 augustss 1935: {
1.9 augustss 1936: usbd_xfer_handle xfer;
1.1 augustss 1937: void *buf;
1938: int i, size;
1939:
1940: size = (ch->bytes_per_frame + ch->sample_size) * UAUDIO_NFRAMES;
1941: for (i = 0; i < UAUDIO_NCHANBUFS; i++) {
1.11 augustss 1942: xfer = usbd_alloc_xfer(sc->sc_udev);
1.9 augustss 1943: if (xfer == 0)
1.1 augustss 1944: goto bad;
1.9 augustss 1945: ch->chanbufs[i].xfer = xfer;
1946: buf = usbd_alloc_buffer(xfer, size);
1.1 augustss 1947: if (buf == 0) {
1948: i++;
1949: goto bad;
1950: }
1951: ch->chanbufs[i].buffer = buf;
1952: ch->chanbufs[i].chan = ch;
1953: }
1954:
1955: return (USBD_NORMAL_COMPLETION);
1956:
1957: bad:
1958: while (--i >= 0)
1959: /* implicit buffer free */
1.11 augustss 1960: usbd_free_xfer(ch->chanbufs[i].xfer);
1.1 augustss 1961: return (USBD_NOMEM);
1962: }
1963:
1964: void
1.26 augustss 1965: uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch)
1.1 augustss 1966: {
1967: int i;
1968:
1969: for (i = 0; i < UAUDIO_NCHANBUFS; i++)
1.11 augustss 1970: usbd_free_xfer(ch->chanbufs[i].xfer);
1.1 augustss 1971: }
1972:
1973: /* Called at splusb() */
1974: void
1.26 augustss 1975: uaudio_chan_ptransfer(struct chan *ch)
1.1 augustss 1976: {
1977: struct chanbuf *cb;
1978: int i, n, size, residue, total;
1979:
1.8 augustss 1980: if (ch->sc->sc_dying)
1981: return;
1982:
1.1 augustss 1983: /* Pick the next channel buffer. */
1984: cb = &ch->chanbufs[ch->curchanbuf];
1985: if (++ch->curchanbuf >= UAUDIO_NCHANBUFS)
1986: ch->curchanbuf = 0;
1987:
1988: /* Compute the size of each frame in the next transfer. */
1989: residue = ch->residue;
1990: total = 0;
1991: for (i = 0; i < UAUDIO_NFRAMES; i++) {
1992: size = ch->bytes_per_frame;
1993: residue += ch->fraction;
1994: if (residue >= USB_FRAMES_PER_SECOND) {
1.47 jdolecek 1995: if ((ch->sc->sc_altflags & UA_NOFRAC) == 0)
1.31 augustss 1996: size += ch->sample_size;
1.1 augustss 1997: residue -= USB_FRAMES_PER_SECOND;
1998: }
1999: cb->sizes[i] = size;
2000: total += size;
2001: }
2002: ch->residue = residue;
2003: cb->size = total;
2004:
1.56 kent 2005: /*
1.1 augustss 2006: * Transfer data from upper layer buffer to channel buffer, taking
2007: * care of wrapping the upper layer buffer.
2008: */
2009: n = min(total, ch->end - ch->cur);
2010: memcpy(cb->buffer, ch->cur, n);
2011: ch->cur += n;
2012: if (ch->cur >= ch->end)
2013: ch->cur = ch->start;
2014: if (total > n) {
2015: total -= n;
2016: memcpy(cb->buffer + n, ch->cur, total);
2017: ch->cur += total;
2018: }
2019:
1.4 augustss 2020: #ifdef UAUDIO_DEBUG
1.1 augustss 2021: if (uaudiodebug > 8) {
1.5 augustss 2022: DPRINTF(("uaudio_chan_ptransfer: buffer=%p, residue=0.%03d\n",
1.1 augustss 2023: cb->buffer, ch->residue));
2024: for (i = 0; i < UAUDIO_NFRAMES; i++) {
2025: DPRINTF((" [%d] length %d\n", i, cb->sizes[i]));
2026: }
2027: }
2028: #endif
2029:
1.9 augustss 2030: DPRINTFN(5,("uaudio_chan_transfer: ptransfer xfer=%p\n", cb->xfer));
1.1 augustss 2031: /* Fill the request */
1.56 kent 2032: usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
2033: UAUDIO_NFRAMES, USBD_NO_COPY,
1.11 augustss 2034: uaudio_chan_pintr);
1.1 augustss 2035:
1.9 augustss 2036: (void)usbd_transfer(cb->xfer);
1.1 augustss 2037: }
2038:
2039: void
1.26 augustss 2040: uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
2041: usbd_status status)
1.1 augustss 2042: {
2043: struct chanbuf *cb = priv;
2044: struct chan *ch = cb->chan;
2045: u_int32_t count;
2046: int s;
2047:
2048: /* Return if we are aborting. */
2049: if (status == USBD_CANCELLED)
2050: return;
2051:
1.18 augustss 2052: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1.5 augustss 2053: DPRINTFN(5,("uaudio_chan_pintr: count=%d, transferred=%d\n",
2054: count, ch->transferred));
2055: #ifdef DIAGNOSTIC
2056: if (count != cb->size) {
2057: printf("uaudio_chan_pintr: count(%d) != size(%d)\n",
2058: count, cb->size);
2059: }
2060: #endif
2061:
2062: ch->transferred += cb->size;
2063: s = splaudio();
1.1 augustss 2064: /* Call back to upper layer */
1.5 augustss 2065: while (ch->transferred >= ch->blksize) {
2066: ch->transferred -= ch->blksize;
1.56 kent 2067: DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n",
1.5 augustss 2068: ch->intr, ch->arg));
2069: ch->intr(ch->arg);
2070: }
2071: splx(s);
2072:
2073: /* start next transfer */
2074: uaudio_chan_ptransfer(ch);
2075: }
2076:
2077: /* Called at splusb() */
2078: void
1.26 augustss 2079: uaudio_chan_rtransfer(struct chan *ch)
1.5 augustss 2080: {
2081: struct chanbuf *cb;
2082: int i, size, residue, total;
1.8 augustss 2083:
2084: if (ch->sc->sc_dying)
2085: return;
1.5 augustss 2086:
2087: /* Pick the next channel buffer. */
2088: cb = &ch->chanbufs[ch->curchanbuf];
2089: if (++ch->curchanbuf >= UAUDIO_NCHANBUFS)
2090: ch->curchanbuf = 0;
2091:
2092: /* Compute the size of each frame in the next transfer. */
2093: residue = ch->residue;
2094: total = 0;
2095: for (i = 0; i < UAUDIO_NFRAMES; i++) {
2096: size = ch->bytes_per_frame;
2097: cb->sizes[i] = size;
1.62 toshii 2098: cb->offsets[i] = total;
1.5 augustss 2099: total += size;
2100: }
2101: ch->residue = residue;
2102: cb->size = total;
2103:
2104: #ifdef UAUDIO_DEBUG
2105: if (uaudiodebug > 8) {
2106: DPRINTF(("uaudio_chan_rtransfer: buffer=%p, residue=0.%03d\n",
2107: cb->buffer, ch->residue));
2108: for (i = 0; i < UAUDIO_NFRAMES; i++) {
2109: DPRINTF((" [%d] length %d\n", i, cb->sizes[i]));
2110: }
2111: }
2112: #endif
2113:
1.9 augustss 2114: DPRINTFN(5,("uaudio_chan_rtransfer: transfer xfer=%p\n", cb->xfer));
1.5 augustss 2115: /* Fill the request */
1.56 kent 2116: usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes,
2117: UAUDIO_NFRAMES, USBD_NO_COPY,
1.11 augustss 2118: uaudio_chan_rintr);
1.5 augustss 2119:
1.9 augustss 2120: (void)usbd_transfer(cb->xfer);
1.5 augustss 2121: }
2122:
2123: void
1.26 augustss 2124: uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
2125: usbd_status status)
1.5 augustss 2126: {
2127: struct chanbuf *cb = priv;
2128: struct chan *ch = cb->chan;
2129: u_int32_t count;
1.62 toshii 2130: int s, i, n, frsize;
1.5 augustss 2131:
2132: /* Return if we are aborting. */
2133: if (status == USBD_CANCELLED)
2134: return;
2135:
1.18 augustss 2136: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1.5 augustss 2137: DPRINTFN(5,("uaudio_chan_rintr: count=%d, transferred=%d\n",
1.1 augustss 2138: count, ch->transferred));
1.31 augustss 2139:
1.62 toshii 2140: /* count < cb->size is normal for asynchronous source */
1.1 augustss 2141: #ifdef DIAGNOSTIC
1.62 toshii 2142: if (count > cb->size) {
2143: printf("uaudio_chan_rintr: count(%d) > size(%d)\n",
1.1 augustss 2144: count, cb->size);
2145: }
2146: #endif
2147:
1.56 kent 2148: /*
1.5 augustss 2149: * Transfer data from channel buffer to upper layer buffer, taking
2150: * care of wrapping the upper layer buffer.
2151: */
1.62 toshii 2152: for(i = 0; i < UAUDIO_NFRAMES; i++) {
2153: frsize = cb->sizes[i];
2154: n = min(frsize, ch->end - ch->cur);
2155: memcpy(ch->cur, cb->buffer + cb->offsets[i], n);
2156: ch->cur += n;
2157: if (ch->cur >= ch->end)
2158: ch->cur = ch->start;
2159: if (frsize > n) {
2160: memcpy(ch->cur, cb->buffer + cb->offsets[i] + n,
2161: frsize - n);
2162: ch->cur += frsize - n;
2163: }
1.5 augustss 2164: }
2165:
2166: /* Call back to upper layer */
1.62 toshii 2167: ch->transferred += count;
1.1 augustss 2168: s = splaudio();
2169: while (ch->transferred >= ch->blksize) {
2170: ch->transferred -= ch->blksize;
1.56 kent 2171: DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n",
1.1 augustss 2172: ch->intr, ch->arg));
2173: ch->intr(ch->arg);
2174: }
2175: splx(s);
2176:
2177: /* start next transfer */
1.5 augustss 2178: uaudio_chan_rtransfer(ch);
1.1 augustss 2179: }
2180:
2181: void
1.65 toshii 2182: uaudio_chan_init(struct chan *ch, int altidx, const struct audio_params *param,
2183: int maxpktsize)
1.1 augustss 2184: {
2185: int samples_per_frame, sample_size;
2186:
1.54 kent 2187: ch->altidx = altidx;
1.50 kent 2188: sample_size = param->precision * param->factor * param->hw_channels / 8;
2189: samples_per_frame = param->hw_sample_rate / USB_FRAMES_PER_SECOND;
1.1 augustss 2190: ch->sample_size = sample_size;
1.50 kent 2191: ch->sample_rate = param->hw_sample_rate;
1.65 toshii 2192: if (maxpktsize == 0) {
2193: ch->fraction = param->hw_sample_rate % USB_FRAMES_PER_SECOND;
2194: ch->bytes_per_frame = samples_per_frame * sample_size;
2195: } else {
2196: ch->fraction = 0;
2197: ch->bytes_per_frame = maxpktsize;
2198: }
1.1 augustss 2199: ch->residue = 0;
1.54 kent 2200: }
1.1 augustss 2201:
1.54 kent 2202: void
2203: uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize)
2204: {
1.1 augustss 2205: ch->start = start;
2206: ch->end = end;
2207: ch->cur = start;
2208: ch->blksize = blksize;
2209: ch->transferred = 0;
2210:
2211: ch->curchanbuf = 0;
2212: }
2213:
1.50 kent 2214: void
2215: uaudio_get_minmax_rates(int nalts, const struct as_info *alts,
2216: const struct audio_params *p, int mode,
2217: u_long *min, u_long *max)
2218: {
2219: int i, j;
2220: struct usb_audio_streaming_type1_descriptor *a1d;
2221:
2222: *min = ULONG_MAX;
2223: *max = 0;
2224: for (i = 0; i < nalts; i++) {
2225: a1d = alts[i].asf1desc;
2226: if (alts[i].sc_busy)
2227: continue;
2228: if (p->hw_channels != a1d->bNrChannels)
2229: continue;
2230: if (p->hw_precision != a1d->bBitResolution)
2231: continue;
2232: if (p->hw_encoding != alts[i].encoding)
2233: continue;
2234: if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
2235: continue;
2236: if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
2237: DPRINTFN(2,("uaudio_get_minmax_rates: cont %d-%d\n",
2238: UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
2239: if (UA_SAMP_LO(a1d) < *min)
2240: *min = UA_SAMP_LO(a1d);
2241: if (UA_SAMP_HI(a1d) > *max)
2242: *max = UA_SAMP_HI(a1d);
2243: } else {
2244: for (j = 0; j < a1d->bSamFreqType; j++) {
2245: DPRINTFN(2,("uaudio_get_minmax_rates: disc #%d: %d\n",
2246: j, UA_GETSAMP(a1d, j)));
2247: if (UA_GETSAMP(a1d, j) < *min)
2248: *min = UA_GETSAMP(a1d, j);
2249: if (UA_GETSAMP(a1d, j) > *max)
2250: *max = UA_GETSAMP(a1d, j);
2251: }
2252: }
2253: }
2254: }
2255:
2256: int
2257: uaudio_match_alt_sub(int nalts, const struct as_info *alts,
2258: const struct audio_params *p, int mode, u_long rate)
2259: {
2260: int i, j;
2261: struct usb_audio_streaming_type1_descriptor *a1d;
2262:
1.53 kent 2263: DPRINTF(("uaudio_match_alt_sub: search for %luHz %dch\n",
1.50 kent 2264: rate, p->hw_channels));
2265: for (i = 0; i < nalts; i++) {
2266: a1d = alts[i].asf1desc;
2267: if (alts[i].sc_busy)
2268: continue;
2269: if (p->hw_channels != a1d->bNrChannels)
2270: continue;
2271: if (p->hw_precision != a1d->bBitResolution)
2272: continue;
2273: if (p->hw_encoding != alts[i].encoding)
2274: continue;
2275: if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
2276: continue;
2277: if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
2278: DPRINTFN(2,("uaudio_match_alt_sub: cont %d-%d\n",
2279: UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
1.66 jdolecek 2280: if (UA_SAMP_LO(a1d) <= rate && rate <= UA_SAMP_HI(a1d))
1.50 kent 2281: return i;
2282: } else {
2283: for (j = 0; j < a1d->bSamFreqType; j++) {
2284: DPRINTFN(2,("uaudio_match_alt_sub: disc #%d: %d\n",
2285: j, UA_GETSAMP(a1d, j)));
2286: /* XXX allow for some slack */
2287: if (UA_GETSAMP(a1d, j) == rate)
2288: return i;
2289: }
2290: }
2291: }
2292: return -1;
2293: }
2294:
2295: int
1.53 kent 2296: uaudio_match_alt_chan(int nalts, const struct as_info *alts,
2297: struct audio_params *p, int mode)
1.50 kent 2298: {
2299: int i, n;
2300: u_long min, max;
2301: u_long rate;
2302:
2303: /* Exact match */
1.53 kent 2304: DPRINTF(("uaudio_match_alt_chan: examine %ldHz %dch %dbit.\n",
2305: p->sample_rate, p->hw_channels, p->hw_precision));
1.50 kent 2306: i = uaudio_match_alt_sub(nalts, alts, p, mode, p->sample_rate);
2307: if (i >= 0)
2308: return i;
2309:
2310: uaudio_get_minmax_rates(nalts, alts, p, mode, &min, &max);
1.53 kent 2311: DPRINTF(("uaudio_match_alt_chan: min=%lu max=%lu\n", min, max));
1.50 kent 2312: if (max <= 0)
2313: return -1;
2314: /* Search for biggers */
2315: n = 2;
2316: while ((rate = p->sample_rate * n++) <= max) {
2317: i = uaudio_match_alt_sub(nalts, alts, p, mode, rate);
2318: if (i >= 0) {
2319: p->hw_sample_rate = rate;
2320: return i;
2321: }
2322: }
2323: if (p->sample_rate >= min) {
2324: i = uaudio_match_alt_sub(nalts, alts, p, mode, max);
2325: if (i >= 0) {
2326: p->hw_sample_rate = max;
2327: return i;
2328: }
2329: } else {
2330: i = uaudio_match_alt_sub(nalts, alts, p, mode, min);
2331: if (i >= 0) {
2332: p->hw_sample_rate = min;
2333: return i;
2334: }
2335: }
1.53 kent 2336: return -1;
2337: }
2338:
2339: int
2340: uaudio_match_alt(int nalts, const struct as_info *alts,
2341: struct audio_params *p, int mode)
2342: {
2343: int i, n;
1.50 kent 2344:
1.53 kent 2345: mode = mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN;
2346: i = uaudio_match_alt_chan(nalts, alts, p, mode);
2347: if (i >= 0)
2348: return i;
2349:
2350: for (n = p->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
2351: p->hw_channels = n;
2352: i = uaudio_match_alt_chan(nalts, alts, p, mode);
2353: if (i >= 0)
2354: return i;
2355: }
2356:
2357: if (p->channels != 2)
2358: return -1;
2359: p->hw_channels = 1;
2360: return uaudio_match_alt_chan(nalts, alts, p, mode);
1.50 kent 2361: }
2362:
1.1 augustss 2363: int
1.26 augustss 2364: uaudio_set_params(void *addr, int setmode, int usemode,
1.38 mycroft 2365: struct audio_params *play, struct audio_params *rec)
1.1 augustss 2366: {
2367: struct uaudio_softc *sc = addr;
2368: int flags = sc->sc_altflags;
1.50 kent 2369: int factor;
2370: int enc, i;
1.47 jdolecek 2371: int paltidx=-1, raltidx=-1;
1.38 mycroft 2372: void (*swcode)(void *, u_char *buf, int cnt);
2373: struct audio_params *p;
2374: int mode;
1.1 augustss 2375:
2376: if (sc->sc_dying)
2377: return (EIO);
2378:
1.61 kristerw 2379: if ((usemode == AUMODE_RECORD && sc->sc_recchan.pipe != NULL)
2380: || (usemode == AUMODE_PLAY && sc->sc_playchan.pipe != NULL))
1.1 augustss 2381: return (EBUSY);
2382:
1.72 ! mycroft 2383: if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1)
1.47 jdolecek 2384: sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 0;
1.72 ! mycroft 2385: if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1)
1.47 jdolecek 2386: sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 0;
2387:
1.38 mycroft 2388: for (mode = AUMODE_RECORD; mode != -1;
2389: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
1.72 ! mycroft 2390: if (usemode & mode) {
! 2391: if (mode == AUMODE_PLAY) {
! 2392: paltidx = i;
! 2393: sc->sc_alts[i].sc_busy = 1;
! 2394: } else {
! 2395: raltidx = i;
! 2396: sc->sc_alts[i].sc_busy = 1;
! 2397: }
! 2398: }
! 2399:
1.38 mycroft 2400: if ((setmode & mode) == 0)
2401: continue;
1.56 kent 2402:
1.47 jdolecek 2403: if ((sc->sc_mode & mode) == 0)
1.38 mycroft 2404: continue;
2405:
1.47 jdolecek 2406: p = (mode == AUMODE_PLAY) ? play : rec;
1.38 mycroft 2407:
2408: factor = 1;
2409: swcode = 0;
2410: enc = p->encoding;
2411: switch (enc) {
2412: case AUDIO_ENCODING_SLINEAR_BE:
1.52 kent 2413: /* FALLTHROUGH */
2414: case AUDIO_ENCODING_SLINEAR_LE:
2415: if (enc == AUDIO_ENCODING_SLINEAR_BE
2416: && p->precision == 16 && (flags & HAS_16)) {
1.38 mycroft 2417: swcode = swap_bytes;
1.37 mycroft 2418: enc = AUDIO_ENCODING_SLINEAR_LE;
1.52 kent 2419: } else if (p->precision == 8) {
2420: if (flags & HAS_8) {
2421: /* No conversion */
2422: } else if (flags & HAS_8U) {
2423: swcode = change_sign8;
2424: enc = AUDIO_ENCODING_ULINEAR_LE;
2425: } else if (flags & HAS_16) {
2426: factor = 2;
2427: p->hw_precision = 16;
2428: if (mode == AUMODE_PLAY)
2429: swcode = linear8_to_linear16_le;
2430: else
2431: swcode = linear16_to_linear8_le;
2432: }
1.38 mycroft 2433: }
2434: break;
2435: case AUDIO_ENCODING_ULINEAR_BE:
1.52 kent 2436: /* FALLTHROUGH */
2437: case AUDIO_ENCODING_ULINEAR_LE:
1.38 mycroft 2438: if (p->precision == 16) {
1.52 kent 2439: if (enc == AUDIO_ENCODING_ULINEAR_LE)
2440: swcode = change_sign16_le;
2441: else if (mode == AUMODE_PLAY)
1.38 mycroft 2442: swcode = swap_bytes_change_sign16_le;
2443: else
2444: swcode = change_sign16_swap_bytes_le;
1.1 augustss 2445: enc = AUDIO_ENCODING_SLINEAR_LE;
1.52 kent 2446: } else if (p->precision == 8) {
2447: if (flags & HAS_8U) {
2448: /* No conversion */
2449: } else if (flags & HAS_8) {
2450: swcode = change_sign8;
2451: enc = AUDIO_ENCODING_SLINEAR_LE;
2452: } else if (flags & HAS_16) {
2453: factor = 2;
2454: p->hw_precision = 16;
2455: enc = AUDIO_ENCODING_SLINEAR_LE;
2456: if (mode == AUMODE_PLAY)
2457: swcode = ulinear8_to_slinear16_le;
2458: else
2459: swcode = slinear16_to_ulinear8_le;
2460: }
1.38 mycroft 2461: }
2462: break;
2463: case AUDIO_ENCODING_ULAW:
1.45 kent 2464: if (flags & HAS_MULAW)
2465: break;
1.48 kent 2466: if (flags & HAS_16) {
2467: if (mode == AUMODE_PLAY)
2468: swcode = mulaw_to_slinear16_le;
2469: else
2470: swcode = slinear16_to_mulaw_le;
2471: factor = 2;
2472: enc = AUDIO_ENCODING_SLINEAR_LE;
1.50 kent 2473: p->hw_precision = 16;
1.48 kent 2474: } else if (flags & HAS_8U) {
1.45 kent 2475: if (mode == AUMODE_PLAY)
2476: swcode = mulaw_to_ulinear8;
2477: else
2478: swcode = ulinear8_to_mulaw;
2479: enc = AUDIO_ENCODING_ULINEAR_LE;
2480: } else if (flags & HAS_8) {
2481: if (mode == AUMODE_PLAY)
2482: swcode = mulaw_to_slinear8;
2483: else
2484: swcode = slinear8_to_mulaw;
2485: enc = AUDIO_ENCODING_SLINEAR_LE;
2486: } else
2487: return (EINVAL);
1.38 mycroft 2488: break;
2489: case AUDIO_ENCODING_ALAW:
1.46 kent 2490: if (flags & HAS_ALAW)
2491: break;
2492: if (mode == AUMODE_PLAY && (flags & HAS_16)) {
2493: swcode = alaw_to_slinear16_le;
2494: factor = 2;
2495: enc = AUDIO_ENCODING_SLINEAR_LE;
1.50 kent 2496: p->hw_precision = 16;
1.46 kent 2497: } else if (flags & HAS_8U) {
2498: if (mode == AUMODE_PLAY)
2499: swcode = alaw_to_ulinear8;
2500: else
2501: swcode = ulinear8_to_alaw;
2502: enc = AUDIO_ENCODING_ULINEAR_LE;
2503: } else if (flags & HAS_8) {
2504: if (mode == AUMODE_PLAY)
2505: swcode = alaw_to_slinear8;
2506: else
2507: swcode = slinear8_to_alaw;
2508: enc = AUDIO_ENCODING_SLINEAR_LE;
2509: } else
2510: return (EINVAL);
1.38 mycroft 2511: break;
2512: default:
2513: return (EINVAL);
1.1 augustss 2514: }
1.38 mycroft 2515: /* XXX do some other conversions... */
2516:
2517: DPRINTF(("uaudio_set_params: chan=%d prec=%d enc=%d rate=%ld\n",
1.50 kent 2518: p->channels, p->hw_precision, enc, p->sample_rate));
1.38 mycroft 2519:
1.50 kent 2520: p->hw_encoding = enc;
2521: i = uaudio_match_alt(sc->sc_nalts, sc->sc_alts, p, mode);
2522: if (i < 0)
2523: return (EINVAL);
1.38 mycroft 2524:
2525: p->sw_code = swcode;
2526: p->factor = factor;
1.1 augustss 2527: }
2528:
1.54 kent 2529: if ((usemode & AUMODE_PLAY) /*&& paltidx != sc->sc_playchan.altidx*/) {
1.47 jdolecek 2530: /* XXX abort transfer if currently happening? */
1.65 toshii 2531: uaudio_chan_init(&sc->sc_playchan, paltidx, play, 0);
1.47 jdolecek 2532: }
1.54 kent 2533: if ((usemode & AUMODE_RECORD) /*&& raltidx != sc->sc_recchan.altidx*/) {
1.47 jdolecek 2534: /* XXX abort transfer if currently happening? */
1.65 toshii 2535: uaudio_chan_init(&sc->sc_recchan, raltidx, rec,
2536: UGETW(sc->sc_alts[raltidx].edesc->wMaxPacketSize));
1.47 jdolecek 2537: }
2538:
1.56 kent 2539: DPRINTF(("uaudio_set_params: use altidx=p%d/r%d, altno=p%d/r%d\n",
2540: sc->sc_playchan.altidx, sc->sc_recchan.altidx,
1.47 jdolecek 2541: (sc->sc_playchan.altidx >= 0)
2542: ?sc->sc_alts[sc->sc_playchan.altidx].idesc->bAlternateSetting
2543: : -1,
2544: (sc->sc_recchan.altidx >= 0)
2545: ? sc->sc_alts[sc->sc_recchan.altidx].idesc->bAlternateSetting
2546: : -1));
1.56 kent 2547:
1.38 mycroft 2548: return (0);
1.1 augustss 2549: }
2550:
2551: usbd_status
1.26 augustss 2552: uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
1.1 augustss 2553: {
2554: usb_device_request_t req;
2555: u_int8_t data[3];
2556:
2557: DPRINTFN(5,("uaudio_set_speed: endpt=%d speed=%u\n", endpt, speed));
2558: req.bmRequestType = UT_WRITE_CLASS_ENDPOINT;
2559: req.bRequest = SET_CUR;
2560: USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0);
2561: USETW(req.wIndex, endpt);
2562: USETW(req.wLength, 3);
2563: data[0] = speed;
2564: data[1] = speed >> 8;
2565: data[2] = speed >> 16;
2566:
1.47 jdolecek 2567: return (usbd_do_request(sc->sc_udev, &req, data));
1.1 augustss 2568: }
CVSweb <webmaster@jp.NetBSD.org>