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