Date: Mon, 20 Dec 2004 03:41:57 +0900 (JST) From: Kazuhito HONDA <kazuhito@ph.noda.tus.ac.jp> To: FreeBSD-gnats-submit@FreeBSD.org Cc: kazuhito@ph.noda.tus.ac.jp Subject: kern/75274: Updating of USB audio codes (uaudio*.*) along recent NetBSD's Message-ID: <20041220.034157.846933450.kazuhito@ph.noda.tus.ac.jp> Resent-Message-ID: <200412191850.iBJIoMaH001389@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 75274 >Category: kern >Synopsis: Updating of USB audio codes (uaudio*.*) along recent NetBSD's >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Dec 19 18:50:22 GMT 2004 >Closed-Date: >Last-Modified: >Originator: Kazuhito HONDA >Release: FreeBSD 6.0-CURRENT i386 >Organization: >Environment: System: FreeBSD kaoru 6.0-CURRENT FreeBSD 6.0-CURRENT #191: Mon Dec 20 02:28:37 JST 2004 root@kaoru:/usr/obj/src/sys/i386/compile/KAORU.6.0B.0 i386 USB audio device: Sound Blaster Digital Music (SBDM, Creative Labs.) >Description: Codes for USB audio in FreeBSD have several problems. 1. Only one volume controllor even if the device has many volume controllor 2. Can't select a sound source for recording 3. Can't record 4. play in wrong sampling rate For solving these problems, especially 1. 2., It is convenient to update FreeBSD uaudio codes along recent NetBSD uaudio codes. Unfortunately USB audio device doesn't play if you don't set correct sampling rate of USB audio device after updating. But, before updating, USB audio device play in wrong sampling rate for sound source if source sampling rate is not equal to device sampling rate. I expect that the formaer is better. >How-To-Repeat: >Fix: This patch is very long. So I expect that the code check will be very hard. I recommend that the checker will compare the patched files with recent NetBSD's files, and compare its difference with the difference between old FreeBSD files and old NetBSD files. --- F_41-91.diff begins here --- --- src/sys/dev/sound/usb/uaudio.c Mon Dec 20 01:48:43 2004 +++ src/sys/dev/sound/usb/uaudio-91.c Mon Dec 20 02:42:53 2004 @@ -1,5 +1,5 @@ -/* $NetBSD: uaudio.c,v 1.41 2001/01/23 14:04:13 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/sound/usb/uaudio.c,v 1.7 2002/08/25 01:32:22 bde Exp $: */ +/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudio-91.c,v $: */ /* * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -39,11 +39,16 @@ */ /* - * USB audio specs: http://www.usb.org/developers/data/devclass/audio10.pdf - * http://www.usb.org/developers/data/devclass/frmts10.pdf - * http://www.usb.org/developers/data/devclass/termt10.pdf + * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf + * http://www.usb.org/developers/devclass_docs/frmts10.pdf + * http://www.usb.org/developers/devclass_docs/termt10.pdf */ +#include <sys/cdefs.h> +#if defined(__NetBSD__) || defined(__OpenBSD__) +__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $"); +#endif + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -66,11 +71,14 @@ #include <sys/conf.h> #endif #include <sys/poll.h> +#if defined(__FreeBSD__) #include <sys/sysctl.h> +#endif #if defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/audioio.h> #include <dev/audio_if.h> +#include <dev/audiovar.h> #include <dev/mulaw.h> #include <dev/auconv.h> #elif defined(__FreeBSD__) @@ -83,23 +91,39 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usb_quirks.h> +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include <dev/usb/uaudioreg.h> +#elif defined(__FreeBSD__) #include <dev/sound/usb/uaudioreg.h> #include <dev/sound/usb/uaudio.h> +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) +/* #define UAUDIO_DEBUG */ +#else +/* #define USB_DEBUG */ +#endif +/* #define UAUDIO_MULTIPLE_ENDPOINTS */ #ifdef USB_DEBUG -#define DPRINTF(x) if (uaudiodebug) logprintf x -#define DPRINTFN(n,x) if (uaudiodebug>(n)) logprintf x +#define DPRINTF(x) do { if (uaudiodebug) logprintf x; } while (0) +#define DPRINTFN(n,x) do { if (uaudiodebug>(n)) logprintf x; } while (0) int uaudiodebug = 0; +#if defined(__FreeBSD__) SYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, &uaudiodebug, 0, "uaudio debug level"); +#endif #else #define DPRINTF(x) #define DPRINTFN(n,x) #endif #define UAUDIO_NCHANBUFS 6 /* number of outstanding request */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +#define UAUDIO_NFRAMES 10 /* ms of sound in each request */ +#elif defined(__FreeBSD__) #define UAUDIO_NFRAMES 20 /* ms of sound in each request */ +#endif #define MIX_MAX_CHAN 8 @@ -112,6 +136,7 @@ struct mixerctl { #define MIX_SIGNED_16 2 #define MIX_UNSIGNED_16 3 #define MIX_SIGNED_8 4 +#define MIX_SELECTOR 5 #define MIX_SIZE(n) ((n) == MIX_SIGNED_16 || (n) == MIX_UNSIGNED_16 ? 2 : 1) #define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) int minval, maxval; @@ -130,22 +155,26 @@ struct mixerctl { struct as_info { u_int8_t alt; u_int8_t encoding; + u_int8_t attributes; /* Copy of bmAttributes of + * usb_audio_streaming_endpoint_descriptor + */ usbd_interface_handle ifaceh; - usb_interface_descriptor_t *idesc; - usb_endpoint_descriptor_audio_t *edesc; - struct usb_audio_streaming_type1_descriptor *asf1desc; + const usb_interface_descriptor_t *idesc; + const usb_endpoint_descriptor_audio_t *edesc; + const usb_endpoint_descriptor_audio_t *edesc1; + const struct usb_audio_streaming_type1_descriptor *asf1desc; + int sc_busy; /* currently used */ }; struct chan { - int terminal; /* terminal id */ #if defined(__NetBSD__) || defined(__OpenBSD__) - void (*intr)(void *); /* dma completion intr handler */ + void (*intr)(void *); /* DMA completion intr handler */ void *arg; /* arg for intr() */ #else struct pcm_channel *pcm_ch; #endif usbd_pipe_handle pipe; - int dir; /* direction */ + usbd_pipe_handle sync_pipe; u_int sample_size; u_int sample_rate; @@ -159,15 +188,16 @@ struct chan { int blksize; /* chunk size to report up */ int transferred; /* transferred bytes not reported up */ - char nofrac; /* don't do sample rate adjustment */ + int altidx; /* currently used altidx */ int curchanbuf; struct chanbuf { - struct chan *chan; + struct chan *chan; usbd_xfer_handle xfer; - u_char *buffer; - u_int16_t sizes[UAUDIO_NFRAMES]; - u_int16_t size; + u_char *buffer; + u_int16_t sizes[UAUDIO_NFRAMES]; + u_int16_t offsets[UAUDIO_NFRAMES]; + u_int16_t size; } chanbufs[UAUDIO_NCHANBUFS]; struct uaudio_softc *sc; /* our softc */ @@ -179,151 +209,194 @@ struct chan { }; struct uaudio_softc { - USBBASEDEVICE sc_dev; /* base device */ + USBBASEDEVICE sc_dev; /* base device */ usbd_device_handle sc_udev; /* USB device */ - - char sc_dead; /* The device is dead -- kill it */ - - int sc_ac_iface; /* Audio Control interface */ + int sc_ac_iface; /* Audio Control interface */ usbd_interface_handle sc_ac_ifaceh; + struct chan sc_playchan; /* play channel */ + struct chan sc_recchan; /* record channel */ + int sc_nullalt; + int sc_audio_rev; + struct as_info *sc_alts; /* alternate settings */ + int sc_nalts; /* # of alternate settings */ + int sc_altflags; +#define HAS_8 0x01 +#define HAS_16 0x02 +#define HAS_8U 0x04 +#define HAS_ALAW 0x08 +#define HAS_MULAW 0x10 +#define UA_NOFRAC 0x20 /* don't do sample rate adjustment */ +#define HAS_24 0x40 + int sc_mode; /* play/record capability */ + struct mixerctl *sc_ctls; /* mixer controls */ + int sc_nctls; /* # of mixer controls */ + device_ptr_t sc_audiodev; + char sc_dying; +}; - struct chan sc_chan; - - int sc_curaltidx; - - int sc_nullalt; - - int sc_audio_rev; - - struct as_info *sc_alts; - int sc_nalts; - int sc_props; - - int sc_altflags; -#define HAS_8 0x01 -#define HAS_16 0x02 -#define HAS_8U 0x04 -#define HAS_ALAW 0x08 -#define HAS_MULAW 0x10 - - struct mixerctl *sc_ctls; - int sc_nctls; +struct terminal_list { + int size; + uint16_t terminals[1]; +}; +#define TERMINAL_LIST_SIZE(N) (offsetof(struct terminal_list, terminals) \ + + sizeof(uint16_t) * (N)) - device_ptr_t sc_audiodev; - char sc_dying; +struct io_terminal { + union { + const usb_descriptor_t *desc; + const struct usb_audio_input_terminal *it; + const struct usb_audio_output_terminal *ot; + const struct usb_audio_mixer_unit *mu; + const struct usb_audio_selector_unit *su; + const struct usb_audio_feature_unit *fu; + const struct usb_audio_processing_unit *pu; + const struct usb_audio_extension_unit *eu; + } d; + int inputs_size; + struct terminal_list **inputs; /* list of source input terminals */ + struct terminal_list *output; /* list of destination output terminals */ + int direct; /* directly connected to an output terminal */ }; -#define UAC_OUTPUT 0 -#define UAC_INPUT 1 -#define UAC_EQUAL 2 +#define UAC_OUTPUT 0 +#define UAC_INPUT 1 +#define UAC_EQUAL 2 +#define UAC_RECORD 3 +#define UAC_NCLASSES 4 +#if !defined(__FreeBSD__) +#ifdef USB_DEBUG +Static const char *uac_names[] = { + AudioCoutputs, AudioCinputs, AudioCequalization, AudioCrecord, +}; +#endif +#endif -Static usbd_status uaudio_identify_ac(struct uaudio_softc *sc, - usb_config_descriptor_t *cdesc); -Static usbd_status uaudio_identify_as(struct uaudio_softc *sc, - usb_config_descriptor_t *cdesc); -Static usbd_status uaudio_process_as(struct uaudio_softc *sc, - char *buf, int *offsp, int size, - usb_interface_descriptor_t *id); +Static usbd_status uaudio_identify_ac + (struct uaudio_softc *, const usb_config_descriptor_t *); +Static usbd_status uaudio_identify_as + (struct uaudio_softc *, const usb_config_descriptor_t *); +Static usbd_status uaudio_process_as + (struct uaudio_softc *, const char *, int *, int, + const usb_interface_descriptor_t *); -Static void uaudio_add_alt(struct uaudio_softc *sc, - struct as_info *ai); +Static void uaudio_add_alt(struct uaudio_softc *, const struct as_info *); -Static usb_interface_descriptor_t *uaudio_find_iface(char *buf, - int size, int *offsp, int subtype); +Static const usb_interface_descriptor_t *uaudio_find_iface + (const char *, int, int *, int); -Static void uaudio_mixer_add_ctl(struct uaudio_softc *sc, - struct mixerctl *mp); +Static void uaudio_mixer_add_ctl(struct uaudio_softc *, struct mixerctl *); #if defined(__NetBSD__) || defined(__OpenBSD__) -Static char *uaudio_id_name(struct uaudio_softc *sc, - usb_descriptor_t **dps, int id); +Static char *uaudio_id_name + (struct uaudio_softc *, const struct io_terminal *, int); #endif -Static struct usb_audio_cluster uaudio_get_cluster(int id, - usb_descriptor_t **dps); -Static void uaudio_add_input(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_output(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_mixer(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_selector(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_feature(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_processing_updown(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_processing(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static void uaudio_add_extension(struct uaudio_softc *sc, - usb_descriptor_t *v, usb_descriptor_t **dps); -Static usbd_status uaudio_identify(struct uaudio_softc *sc, - usb_config_descriptor_t *cdesc); +#ifdef USB_DEBUG +Static void uaudio_dump_cluster(const struct usb_audio_cluster *); +#endif +Static struct usb_audio_cluster uaudio_get_cluster + (int, const struct io_terminal *); +Static void uaudio_add_input + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_output + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_mixer + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_selector + (struct uaudio_softc *, const struct io_terminal *, int); +#ifdef USB_DEBUG +Static const char *uaudio_get_terminal_name(int); +#endif +#if !defined(__FreeBSD__) +Static int uaudio_determine_class + (const struct io_terminal *, struct mixerctl *); +Static const char *uaudio_feature_name + (const struct io_terminal *, struct mixerctl *); +#endif +Static void uaudio_add_feature + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_processing_updown + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_processing + (struct uaudio_softc *, const struct io_terminal *, int); +Static void uaudio_add_extension + (struct uaudio_softc *, const struct io_terminal *, int); +Static struct terminal_list *uaudio_merge_terminal_list + (const struct io_terminal *); +Static struct terminal_list *uaudio_io_terminaltype + (int, struct io_terminal *, int); +Static usbd_status uaudio_identify + (struct uaudio_softc *, const usb_config_descriptor_t *); -Static int uaudio_signext(int type, int val); +Static int uaudio_signext(int, int); #if defined(__NetBSD__) || defined(__OpenBSD__) -Static int uaudio_value2bsd(struct mixerctl *mc, int val); +Static int uaudio_value2bsd(struct mixerctl *, int); #endif -Static int uaudio_bsd2value(struct mixerctl *mc, int val); -Static int uaudio_get(struct uaudio_softc *sc, int type, - int which, int wValue, int wIndex, int len); +Static int uaudio_bsd2value(struct mixerctl *, int); +Static int uaudio_get(struct uaudio_softc *, int, int, int, int, int); #if defined(__NetBSD__) || defined(__OpenBSD__) -Static int uaudio_ctl_get(struct uaudio_softc *sc, int which, - struct mixerctl *mc, int chan); +Static int uaudio_ctl_get + (struct uaudio_softc *, int, struct mixerctl *, int); #endif -Static void uaudio_set(struct uaudio_softc *sc, int type, - int which, int wValue, int wIndex, int l, int v); -Static void uaudio_ctl_set(struct uaudio_softc *sc, int which, - struct mixerctl *mc, int chan, int val); +Static void uaudio_set + (struct uaudio_softc *, int, int, int, int, int, int); +Static void uaudio_ctl_set + (struct uaudio_softc *, int, struct mixerctl *, int, int); -Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, u_int); +Static usbd_status uaudio_set_speed(struct uaudio_softc *, int, u_int); -Static usbd_status uaudio_chan_open(struct uaudio_softc *sc, - struct chan *ch); -Static void uaudio_chan_close(struct uaudio_softc *sc, - struct chan *ch); -Static usbd_status uaudio_chan_alloc_buffers(struct uaudio_softc *, - struct chan *); -Static void uaudio_chan_free_buffers(struct uaudio_softc *, - struct chan *); +Static usbd_status uaudio_chan_open(struct uaudio_softc *, struct chan *); +Static void uaudio_chan_close(struct uaudio_softc *, struct chan *); +Static usbd_status uaudio_chan_alloc_buffers + (struct uaudio_softc *, struct chan *); +Static void uaudio_chan_free_buffers(struct uaudio_softc *, struct chan *); #if defined(__NetBSD__) || defined(__OpenBSD__) -Static void uaudio_chan_set_param(struct chan *ch, - struct audio_params *param, u_char *start, - u_char *end, int blksize); +Static void uaudio_chan_init + (struct chan *, int, const struct audio_params *, int); +Static void uaudio_chan_set_param(struct chan *, u_char *, u_char *, int); #endif -Static void uaudio_chan_ptransfer(struct chan *ch); -Static void uaudio_chan_pintr(usbd_xfer_handle xfer, - usbd_private_handle priv, usbd_status status); +Static void uaudio_chan_ptransfer(struct chan *); +Static void uaudio_chan_pintr + (usbd_xfer_handle, usbd_private_handle, usbd_status); -Static void uaudio_chan_rtransfer(struct chan *ch); -Static void uaudio_chan_rintr(usbd_xfer_handle xfer, - usbd_private_handle priv, usbd_status status); +Static void uaudio_chan_rtransfer(struct chan *); +Static void uaudio_chan_rintr + (usbd_xfer_handle, usbd_private_handle, usbd_status); #if defined(__NetBSD__) || defined(__OpenBSD__) -Static int uaudio_open(void *, int); -Static void uaudio_close(void *); -Static int uaudio_drain(void *); -Static int uaudio_query_encoding(void *, struct audio_encoding *); -Static int uaudio_set_params(void *, int, int, - struct audio_params *, struct audio_params *); -Static int uaudio_round_blocksize(void *, int); -Static int uaudio_trigger_output(void *, void *, void *, - int, void (*)(void *), void *, - struct audio_params *); -Static int uaudio_trigger_input (void *, void *, void *, - int, void (*)(void *), void *, - struct audio_params *); -Static int uaudio_halt_in_dma(void *); -Static int uaudio_halt_out_dma(void *); -Static int uaudio_getdev(void *, struct audio_device *); -Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *); -Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *); -Static int uaudio_query_devinfo(void *, mixer_devinfo_t *); -Static int uaudio_get_props(void *); +Static int uaudio_open(void *, int); +Static void uaudio_close(void *); +Static int uaudio_drain(void *); +Static int uaudio_query_encoding(void *, struct audio_encoding *); +Static void uaudio_get_minmax_rates + (int, const struct as_info *, const struct audio_params *, + int, u_long *, u_long *); +Static int uaudio_match_alt_sub + (int, const struct as_info *, const struct audio_params *, int, u_long); +Static int uaudio_match_alt_chan + (int, const struct as_info *, struct audio_params *, int); +Static int uaudio_match_alt + (int, const struct as_info *, struct audio_params *, int); +Static int uaudio_set_params + (void *, int, int, struct audio_params *, struct audio_params *); +Static int uaudio_round_blocksize(void *, int); +Static int uaudio_trigger_output + (void *, void *, void *, int, void (*)(void *), void *, + struct audio_params *); +Static int uaudio_trigger_input + (void *, void *, void *, int, void (*)(void *), void *, + struct audio_params *); +Static int uaudio_halt_in_dma(void *); +Static int uaudio_halt_out_dma(void *); +Static int uaudio_getdev(void *, struct audio_device *); +Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *); +Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *); +Static int uaudio_query_devinfo(void *, mixer_devinfo_t *); +Static int uaudio_get_props(void *); -Static struct audio_hw_if uaudio_hw_if = { +Static const struct audio_hw_if uaudio_hw_if = { uaudio_open, uaudio_close, uaudio_drain, @@ -350,6 +423,7 @@ Static struct audio_hw_if uaudio_hw_if = uaudio_get_props, uaudio_trigger_output, uaudio_trigger_input, + NULL, }; Static struct audio_device uaudio_device = { @@ -360,7 +434,7 @@ Static struct audio_device uaudio_device #elif defined(__FreeBSD__) Static int audio_attach_mi(device_t); -Static void uaudio_init_params(struct uaudio_softc * sc, struct chan *ch); +Static int uaudio_init_params(struct uaudio_softc * sc, struct chan *ch, int mode); /* for NetBSD compatibirity */ #define AUMODE_PLAY 0x01 @@ -397,13 +471,13 @@ USB_MATCH(uaudio) { USB_MATCH_START(uaudio, uaa); usb_interface_descriptor_t *id; - + if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); /* Trigger on the control interface. */ - if (id == NULL || + if (id == NULL || id->bInterfaceClass != UICLASS_AUDIO || id->bInterfaceSubClass != UISUBCLASS_AUDIOCONTROL || (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_AUDIO)) @@ -421,8 +495,12 @@ USB_ATTACH(uaudio) usbd_status err; int i, j, found; +#if defined(__FreeBSD__) usbd_devinfo(uaa->device, 0, devinfo); USB_ATTACH_SETUP; +#else + usbd_devinfo(uaa->device, 0, devinfo, sizeof(devinfo)); +#endif #if !defined(__FreeBSD__) printf(": %s\n", devinfo); @@ -475,10 +553,12 @@ USB_ATTACH(uaudio) printf("%s: audio rev %d.%02x\n", USBDEVNAME(sc->sc_dev), sc->sc_audio_rev >> 8, sc->sc_audio_rev & 0xff); - sc->sc_chan.sc = sc; + sc->sc_playchan.sc = sc->sc_recchan.sc = sc; + sc->sc_playchan.altidx = -1; + sc->sc_recchan.altidx = -1; if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_FRAC) - sc->sc_chan.nofrac = 1; + sc->sc_altflags |= UA_NOFRAC; #ifndef USB_DEBUG if (bootverbose) @@ -566,7 +646,7 @@ USB_DETACH(uaudio) #endif #if defined(__NetBSD__) || defined(__OpenBSD__) -int +Static int uaudio_query_encoding(void *addr, struct audio_encoding *fp) { struct uaudio_softc *sc = addr; @@ -575,56 +655,56 @@ uaudio_query_encoding(void *addr, struct if (sc->sc_dying) return (EIO); - + if (sc->sc_nalts == 0 || flags == 0) return (ENXIO); idx = fp->index; switch (idx) { case 0: - strcpy(fp->name, AudioEulinear); + strlcpy(fp->name, AudioEulinear, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_ULINEAR; fp->precision = 8; fp->flags = flags&HAS_8U ? 0 : AUDIO_ENCODINGFLAG_EMULATED; return (0); case 1: - strcpy(fp->name, AudioEmulaw); + strlcpy(fp->name, AudioEmulaw, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_ULAW; fp->precision = 8; fp->flags = flags&HAS_MULAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED; return (0); case 2: - strcpy(fp->name, AudioEalaw); + strlcpy(fp->name, AudioEalaw, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_ALAW; fp->precision = 8; fp->flags = flags&HAS_ALAW ? 0 : AUDIO_ENCODINGFLAG_EMULATED; return (0); case 3: - strcpy(fp->name, AudioEslinear); + strlcpy(fp->name, AudioEslinear, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_SLINEAR; fp->precision = 8; fp->flags = flags&HAS_8 ? 0 : AUDIO_ENCODINGFLAG_EMULATED; return (0); - case 4: - strcpy(fp->name, AudioEslinear_le); + case 4: + strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_SLINEAR_LE; fp->precision = 16; fp->flags = 0; return (0); case 5: - strcpy(fp->name, AudioEulinear_le); + strlcpy(fp->name, AudioEulinear_le, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_ULINEAR_LE; fp->precision = 16; fp->flags = AUDIO_ENCODINGFLAG_EMULATED; return (0); case 6: - strcpy(fp->name, AudioEslinear_be); + strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_SLINEAR_BE; fp->precision = 16; fp->flags = AUDIO_ENCODINGFLAG_EMULATED; return (0); case 7: - strcpy(fp->name, AudioEulinear_be); + strlcpy(fp->name, AudioEulinear_be, sizeof(fp->name)); fp->encoding = AUDIO_ENCODING_ULINEAR_BE; fp->precision = 16; fp->flags = AUDIO_ENCODINGFLAG_EMULATED; @@ -635,13 +715,13 @@ uaudio_query_encoding(void *addr, struct } #endif -usb_interface_descriptor_t * -uaudio_find_iface(char *buf, int size, int *offsp, int subtype) +Static const usb_interface_descriptor_t * +uaudio_find_iface(const char *buf, int size, int *offsp, int subtype) { - usb_interface_descriptor_t *d; + const usb_interface_descriptor_t *d; while (*offsp < size) { - d = (void *)(buf + *offsp); + d = (const void *)(buf + *offsp); *offsp += d->bLength; if (d->bDescriptorType == UDESC_INTERFACE && d->bInterfaceClass == UICLASS_AUDIO && @@ -651,29 +731,47 @@ uaudio_find_iface(char *buf, int size, i return (NULL); } -void +Static void uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc) { int res; - size_t len = sizeof(*mc) * (sc->sc_nctls + 1); - struct mixerctl *nmc = sc->sc_nctls == 0 ? - malloc(len, M_USBDEV, M_NOWAIT) : - realloc(sc->sc_ctls, len, M_USBDEV, M_NOWAIT); + size_t len; + struct mixerctl *nmc; - if(nmc == NULL){ +#if !defined(__FreeBSD__) + if (mc->class < UAC_NCLASSES) { + DPRINTF(("%s: adding %s.%s\n", + __func__, uac_names[mc->class], mc->ctlname)); + } else { + DPRINTF(("%s: adding %s\n", __func__, mc->ctlname)); + } +#endif + len = sizeof(*mc) * (sc->sc_nctls + 1); + nmc = malloc(len, M_USBDEV, M_NOWAIT); + if (nmc == NULL) { printf("uaudio_mixer_add_ctl: no memory\n"); return; } + /* Copy old data, if there was any */ + if (sc->sc_nctls != 0) { + memcpy(nmc, sc->sc_ctls, sizeof(*mc) * (sc->sc_nctls)); + free(sc->sc_ctls, M_USBDEV); + } sc->sc_ctls = nmc; mc->delta = 0; - if (mc->type != MIX_ON_OFF) { + if (mc->type == MIX_ON_OFF) { + mc->minval = 0; + mc->maxval = 1; + } else if (mc->type == MIX_SELECTOR) { + ; + } else { /* Determine min and max values. */ - mc->minval = uaudio_signext(mc->type, - uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE, - mc->wValue[0], mc->wIndex, + mc->minval = uaudio_signext(mc->type, + uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE, + mc->wValue[0], mc->wIndex, MIX_SIZE(mc->type))); - mc->maxval = 1 + uaudio_signext(mc->type, + mc->maxval = 1 + uaudio_signext(mc->type, uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE, mc->wValue[0], mc->wIndex, MIX_SIZE(mc->type))); @@ -684,10 +782,7 @@ uaudio_mixer_add_ctl(struct uaudio_softc mc->wValue[0], mc->wIndex, MIX_SIZE(mc->type)); if (res > 0) - mc->delta = (res * 256 + mc->mul/2) / mc->mul; - } else { - mc->minval = 0; - mc->maxval = 1; + mc->delta = (res * 255 + mc->mul/2) / mc->mul; } sc->sc_ctls[sc->sc_nctls++] = *mc; @@ -714,67 +809,80 @@ uaudio_mixer_add_ctl(struct uaudio_softc } #if defined(__NetBSD__) || defined(__OpenBSD__) -char * -uaudio_id_name(struct uaudio_softc *sc, usb_descriptor_t **dps, int id) +Static char * +uaudio_id_name(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { static char buf[32]; - sprintf(buf, "i%d", id); + snprintf(buf, sizeof(buf), "i%d", id); return (buf); } #endif -struct usb_audio_cluster -uaudio_get_cluster(int id, usb_descriptor_t **dps) +#ifdef USB_DEBUG +Static void +uaudio_dump_cluster(const struct usb_audio_cluster *cl) +{ + static const char *channel_names[16] = { + "LEFT", "RIGHT", "CENTER", "LFE", + "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER", + "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP", + "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", + }; + int cc, i, first; + + cc = UGETW(cl->wChannelConfig); + logprintf("cluster: bNrChannels=%u wChannelConfig=0x%.4x", + cl->bNrChannels, cc); + first = TRUE; + for (i = 0; cc != 0; i++) { + if (cc & 1) { + logprintf("%c%s", first ? '<' : ',', channel_names[i]); + first = FALSE; + } + cc = cc >> 1; + } + logprintf("> iChannelNames=%u", cl->iChannelNames); +} +#endif + +Static struct usb_audio_cluster +uaudio_get_cluster(int id, const struct io_terminal *iot) { struct usb_audio_cluster r; - usb_descriptor_t *dp; + const usb_descriptor_t *dp; int i; for (i = 0; i < 25; i++) { /* avoid infinite loops */ - dp = dps[id]; + dp = iot[id].d.desc; if (dp == 0) goto bad; switch (dp->bDescriptorSubtype) { case UDESCSUB_AC_INPUT: -#define p ((struct usb_audio_input_terminal *)dp) - r.bNrChannels = p->bNrChannels; - USETW(r.wChannelConfig, UGETW(p->wChannelConfig)); - r.iChannelNames = p->iChannelNames; -#undef p + r.bNrChannels = iot[id].d.it->bNrChannels; + USETW(r.wChannelConfig, UGETW(iot[id].d.it->wChannelConfig)); + r.iChannelNames = iot[id].d.it->iChannelNames; return (r); case UDESCSUB_AC_OUTPUT: -#define p ((struct usb_audio_output_terminal *)dp) - id = p->bSourceId; -#undef p + id = iot[id].d.ot->bSourceId; break; case UDESCSUB_AC_MIXER: -#define p ((struct usb_audio_mixer_unit *)dp) - r = *(struct usb_audio_cluster *) - &p->baSourceId[p->bNrInPins]; -#undef p + r = *(const struct usb_audio_cluster *) + &iot[id].d.mu->baSourceId[iot[id].d.mu->bNrInPins]; return (r); case UDESCSUB_AC_SELECTOR: /* XXX This is not really right */ -#define p ((struct usb_audio_selector_unit *)dp) - id = p->baSourceId[0]; -#undef p + id = iot[id].d.su->baSourceId[0]; break; case UDESCSUB_AC_FEATURE: -#define p ((struct usb_audio_feature_unit *)dp) - id = p->bSourceId; -#undef p + id = iot[id].d.fu->bSourceId; break; case UDESCSUB_AC_PROCESSING: -#define p ((struct usb_audio_processing_unit *)dp) - r = *(struct usb_audio_cluster *) - &p->baSourceId[p->bNrInPins]; -#undef p + r = *(const struct usb_audio_cluster *) + &iot[id].d.pu->baSourceId[iot[id].d.pu->bNrInPins]; return (r); case UDESCSUB_AC_EXTENSION: -#define p ((struct usb_audio_extension_unit *)dp) - r = *(struct usb_audio_cluster *) - &p->baSourceId[p->bNrInPins]; -#undef p + r = *(const struct usb_audio_cluster *) + &iot[id].d.eu->baSourceId[iot[id].d.eu->bNrInPins]; return (r); default: goto bad; @@ -787,13 +895,11 @@ uaudio_get_cluster(int id, usb_descripto } -void -uaudio_add_input(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_input(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { #ifdef USB_DEBUG - struct usb_audio_input_terminal *d = - (struct usb_audio_input_terminal *)v; + const struct usb_audio_input_terminal *d = iot[id].d.it; DPRINTFN(2,("uaudio_add_input: bTerminalId=%d wTerminalType=0x%04x " "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d " @@ -804,13 +910,11 @@ uaudio_add_input(struct uaudio_softc *sc #endif } -void -uaudio_add_output(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_output(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { #ifdef USB_DEBUG - struct usb_audio_output_terminal *d = - (struct usb_audio_output_terminal *)v; + const struct usb_audio_output_terminal *d = iot[id].d.ot; DPRINTFN(2,("uaudio_add_output: bTerminalId=%d wTerminalType=0x%04x " "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n", @@ -819,33 +923,32 @@ uaudio_add_output(struct uaudio_softc *s #endif } -void -uaudio_add_mixer(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_mixer(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { - struct usb_audio_mixer_unit *d = (struct usb_audio_mixer_unit *)v; - struct usb_audio_mixer_unit_1 *d1; + const struct usb_audio_mixer_unit *d = iot[id].d.mu; + const struct usb_audio_mixer_unit_1 *d1; int c, chs, ichs, ochs, i, o, bno, p, mo, mc, k; - uByte *bm; + const uByte *bm; struct mixerctl mix; DPRINTFN(2,("uaudio_add_mixer: bUnitId=%d bNrInPins=%d\n", d->bUnitId, d->bNrInPins)); - + /* Compute the number of input channels */ ichs = 0; for (i = 0; i < d->bNrInPins; i++) - ichs += uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels; + ichs += uaudio_get_cluster(d->baSourceId[i], iot).bNrChannels; /* and the number of output channels */ - d1 = (struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins]; + d1 = (const struct usb_audio_mixer_unit_1 *)&d->baSourceId[d->bNrInPins]; ochs = d1->bNrChannels; DPRINTFN(2,("uaudio_add_mixer: ichs=%d ochs=%d\n", ichs, ochs)); bm = d1->bmControls; mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface); #if !defined(__FreeBSD__) - mix.class = -1; + uaudio_determine_class(&iot[id], &mix); #endif mix.type = MIX_SIGNED_16; #if !defined(__FreeBSD__) /* XXXXX */ @@ -854,7 +957,7 @@ uaudio_add_mixer(struct uaudio_softc *sc #define BIT(bno) ((bm[bno / 8] >> (7 - bno % 8)) & 1) for (p = i = 0; i < d->bNrInPins; i++) { - chs = uaudio_get_cluster(d->baSourceId[i], dps).bNrChannels; + chs = uaudio_get_cluster(d->baSourceId[i], iot).bNrChannels; mc = 0; for (c = 0; c < chs; c++) { mo = 0; @@ -872,12 +975,13 @@ uaudio_add_mixer(struct uaudio_softc *sc for (o = 0; o < ochs; o++) { bno = (p + c) * ochs + o; if (BIT(bno)) - mix.wValue[k++] = + mix.wValue[k++] = MAKE(p+c+1, o+1); } #if !defined(__FreeBSD__) - sprintf(mix.ctlname, "mix%d-%s", d->bUnitId, - uaudio_id_name(sc, dps, d->baSourceId[i])); + snprintf(mix.ctlname, sizeof(mix.ctlname), "mix%d-%s", + d->bUnitId, uaudio_id_name(sc, iot, + d->baSourceId[i])); #endif mix.nchan = chs; uaudio_mixer_add_ctl(sc, &mix); @@ -890,34 +994,286 @@ uaudio_add_mixer(struct uaudio_softc *sc } -void -uaudio_add_selector(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_selector(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { -#ifdef USB_DEBUG - struct usb_audio_selector_unit *d = - (struct usb_audio_selector_unit *)v; +#if !defined(__FreeBSD__) || defined(USB_DEBUG) + const struct usb_audio_selector_unit *d = iot[id].d.su; +#endif +#if !defined(__FreeBSD__) + struct mixerctl mix; + int i, wp; +#endif DPRINTFN(2,("uaudio_add_selector: bUnitId=%d bNrInPins=%d\n", d->bUnitId, d->bNrInPins)); -#endif +#if defined(__FreeBSD__) printf("uaudio_add_selector: NOT IMPLEMENTED\n"); +#else + mix.wIndex = MAKE(d->bUnitId, sc->sc_ac_iface); + mix.wValue[0] = MAKE(0, 0); + uaudio_determine_class(&iot[id], &mix); + mix.nchan = 1; + mix.type = MIX_SELECTOR; + mix.ctlunit = ""; + mix.minval = 1; + mix.maxval = d->bNrInPins; + mix.mul = mix.maxval - mix.minval; + wp = snprintf(mix.ctlname, MAX_AUDIO_DEV_LEN, "sel%d-", d->bUnitId); + for (i = 1; i <= d->bNrInPins; i++) { + wp += snprintf(mix.ctlname + wp, MAX_AUDIO_DEV_LEN - wp, + "i%d", d->baSourceId[i - 1]); + if (wp > MAX_AUDIO_DEV_LEN - 1) + break; + } + uaudio_mixer_add_ctl(sc, &mix); +#endif } -void -uaudio_add_feature(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +#ifdef USB_DEBUG +Static const char * +uaudio_get_terminal_name(int terminal_type) { - struct usb_audio_feature_unit *d = (struct usb_audio_feature_unit *)v; + static char buf[100]; + + switch (terminal_type) { + /* USB terminal types */ + case UAT_UNDEFINED: return "UAT_UNDEFINED"; + case UAT_STREAM: return "UAT_STREAM"; + case UAT_VENDOR: return "UAT_VENDOR"; + /* input terminal types */ + case UATI_UNDEFINED: return "UATI_UNDEFINED"; + case UATI_MICROPHONE: return "UATI_MICROPHONE"; + case UATI_DESKMICROPHONE: return "UATI_DESKMICROPHONE"; + case UATI_PERSONALMICROPHONE: return "UATI_PERSONALMICROPHONE"; + case UATI_OMNIMICROPHONE: return "UATI_OMNIMICROPHONE"; + case UATI_MICROPHONEARRAY: return "UATI_MICROPHONEARRAY"; + case UATI_PROCMICROPHONEARR: return "UATI_PROCMICROPHONEARR"; + /* output terminal types */ + case UATO_UNDEFINED: return "UATO_UNDEFINED"; + case UATO_SPEAKER: return "UATO_SPEAKER"; + case UATO_HEADPHONES: return "UATO_HEADPHONES"; + case UATO_DISPLAYAUDIO: return "UATO_DISPLAYAUDIO"; + case UATO_DESKTOPSPEAKER: return "UATO_DESKTOPSPEAKER"; + case UATO_ROOMSPEAKER: return "UATO_ROOMSPEAKER"; + case UATO_COMMSPEAKER: return "UATO_COMMSPEAKER"; + case UATO_SUBWOOFER: return "UATO_SUBWOOFER"; + /* bidir terminal types */ + case UATB_UNDEFINED: return "UATB_UNDEFINED"; + case UATB_HANDSET: return "UATB_HANDSET"; + case UATB_HEADSET: return "UATB_HEADSET"; + case UATB_SPEAKERPHONE: return "UATB_SPEAKERPHONE"; + case UATB_SPEAKERPHONEESUP: return "UATB_SPEAKERPHONEESUP"; + case UATB_SPEAKERPHONEECANC: return "UATB_SPEAKERPHONEECANC"; + /* telephony terminal types */ + case UATT_UNDEFINED: return "UATT_UNDEFINED"; + case UATT_PHONELINE: return "UATT_PHONELINE"; + case UATT_TELEPHONE: return "UATT_TELEPHONE"; + case UATT_DOWNLINEPHONE: return "UATT_DOWNLINEPHONE"; + /* external terminal types */ + case UATE_UNDEFINED: return "UATE_UNDEFINED"; + case UATE_ANALOGCONN: return "UATE_ANALOGCONN"; + case UATE_LINECONN: return "UATE_LINECONN"; + case UATE_LEGACYCONN: return "UATE_LEGACYCONN"; + case UATE_DIGITALAUIFC: return "UATE_DIGITALAUIFC"; + case UATE_SPDIF: return "UATE_SPDIF"; + case UATE_1394DA: return "UATE_1394DA"; + case UATE_1394DV: return "UATE_1394DV"; + /* embedded function terminal types */ + case UATF_UNDEFINED: return "UATF_UNDEFINED"; + case UATF_CALIBNOISE: return "UATF_CALIBNOISE"; + case UATF_EQUNOISE: return "UATF_EQUNOISE"; + case UATF_CDPLAYER: return "UATF_CDPLAYER"; + case UATF_DAT: return "UATF_DAT"; + case UATF_DCC: return "UATF_DCC"; + case UATF_MINIDISK: return "UATF_MINIDISK"; + case UATF_ANALOGTAPE: return "UATF_ANALOGTAPE"; + case UATF_PHONOGRAPH: return "UATF_PHONOGRAPH"; + case UATF_VCRAUDIO: return "UATF_VCRAUDIO"; + case UATF_VIDEODISCAUDIO: return "UATF_VIDEODISCAUDIO"; + case UATF_DVDAUDIO: return "UATF_DVDAUDIO"; + case UATF_TVTUNERAUDIO: return "UATF_TVTUNERAUDIO"; + case UATF_SATELLITE: return "UATF_SATELLITE"; + case UATF_CABLETUNER: return "UATF_CABLETUNER"; + case UATF_DSS: return "UATF_DSS"; + case UATF_RADIORECV: return "UATF_RADIORECV"; + case UATF_RADIOXMIT: return "UATF_RADIOXMIT"; + case UATF_MULTITRACK: return "UATF_MULTITRACK"; + case UATF_SYNTHESIZER: return "UATF_SYNTHESIZER"; + default: + snprintf(buf, sizeof(buf), "unknown type (0x%.4x)", terminal_type); + return buf; + } +} +#endif + +#if !defined(__FreeBSD__) +Static int +uaudio_determine_class(const struct io_terminal *iot, struct mixerctl *mix) +{ + int terminal_type; + + if (iot == NULL || iot->output == NULL) { + mix->class = UAC_OUTPUT; + return 0; + } + terminal_type = 0; + if (iot->output->size == 1) + terminal_type = iot->output->terminals[0]; + /* + * If the only output terminal is USB, + * the class is UAC_RECORD. + */ + if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { + mix->class = UAC_RECORD; + if (iot->inputs_size == 1 + && iot->inputs[0] != NULL + && iot->inputs[0]->size == 1) + return iot->inputs[0]->terminals[0]; + else + return 0; + } + /* + * If the ultimate destination of the unit is just one output + * terminal and the unit is connected to the output terminal + * directly, the class is UAC_OUTPUT. + */ + if (terminal_type != 0 && iot->direct) { + mix->class = UAC_OUTPUT; + return terminal_type; + } + /* + * If the unit is connected to just one input terminal, + * the class is UAC_INPUT. + */ + if (iot->inputs_size == 1 && iot->inputs[0] != NULL + && iot->inputs[0]->size == 1) { + mix->class = UAC_INPUT; + return iot->inputs[0]->terminals[0]; + } + /* + * Otherwise, the class is UAC_OUTPUT. + */ + mix->class = UAC_OUTPUT; + return terminal_type; +} + +Static const char * +uaudio_feature_name(const struct io_terminal *iot, struct mixerctl *mix) +{ + int terminal_type; + + terminal_type = uaudio_determine_class(iot, mix); + if (mix->class == UAC_RECORD && terminal_type == 0) + return AudioNmixerout; + DPRINTF(("%s: terminal_type=%s\n", __func__, + uaudio_get_terminal_name(terminal_type))); + switch (terminal_type) { + case UAT_STREAM: + return AudioNdac; + + case UATI_MICROPHONE: + case UATI_DESKMICROPHONE: + case UATI_PERSONALMICROPHONE: + case UATI_OMNIMICROPHONE: + case UATI_MICROPHONEARRAY: + case UATI_PROCMICROPHONEARR: + return AudioNmicrophone; + + case UATO_SPEAKER: + case UATO_DESKTOPSPEAKER: + case UATO_ROOMSPEAKER: + case UATO_COMMSPEAKER: + return AudioNspeaker; + + case UATO_HEADPHONES: + return AudioNheadphone; + + case UATO_SUBWOOFER: + return AudioNlfe; + + /* telephony terminal types */ + case UATT_UNDEFINED: + case UATT_PHONELINE: + case UATT_TELEPHONE: + case UATT_DOWNLINEPHONE: + return "phone"; + + case UATE_ANALOGCONN: + case UATE_LINECONN: + case UATE_LEGACYCONN: + return AudioNline; + + case UATE_DIGITALAUIFC: + case UATE_SPDIF: + case UATE_1394DA: + case UATE_1394DV: + return AudioNaux; + + case UATF_CDPLAYER: + return AudioNcd; + + case UATF_SYNTHESIZER: + return AudioNfmsynth; + + case UATF_VIDEODISCAUDIO: + case UATF_DVDAUDIO: + case UATF_TVTUNERAUDIO: + return AudioNvideo; + + case UAT_UNDEFINED: + case UAT_VENDOR: + case UATI_UNDEFINED: +/* output terminal types */ + case UATO_UNDEFINED: + case UATO_DISPLAYAUDIO: +/* bidir terminal types */ + case UATB_UNDEFINED: + case UATB_HANDSET: + case UATB_HEADSET: + case UATB_SPEAKERPHONE: + case UATB_SPEAKERPHONEESUP: + case UATB_SPEAKERPHONEECANC: +/* external terminal types */ + case UATE_UNDEFINED: +/* embedded function terminal types */ + case UATF_UNDEFINED: + case UATF_CALIBNOISE: + case UATF_EQUNOISE: + case UATF_DAT: + case UATF_DCC: + case UATF_MINIDISK: + case UATF_ANALOGTAPE: + case UATF_PHONOGRAPH: + case UATF_VCRAUDIO: + case UATF_SATELLITE: + case UATF_CABLETUNER: + case UATF_DSS: + case UATF_RADIORECV: + case UATF_RADIOXMIT: + case UATF_MULTITRACK: + case 0xffff: + default: + DPRINTF(("%s: 'master' for 0x%.4x\n", __func__, terminal_type)); + return AudioNmaster; + } + return AudioNmaster; +} +#endif + +Static void +uaudio_add_feature(struct uaudio_softc *sc, const struct io_terminal *iot, int id) +{ + const struct usb_audio_feature_unit *d = iot[id].d.fu; uByte *ctls = d->bmaControls; int ctlsize = d->bControlSize; int nchan = (d->bLength - 7) / ctlsize; -#if !defined(__FreeBSD__) - int srcId = d->bSourceId; -#endif u_int fumask, mmask, cmask; struct mixerctl mix; int chan, ctl, i, unit; +#if !defined(__FreeBSD__) + const char *mixername; +#endif #define GET(i) (ctls[(i)*ctlsize] | \ (ctlsize > 1 ? ctls[(i)*ctlsize+1] << 8 : 0)) @@ -931,9 +1287,9 @@ uaudio_add_feature(struct uaudio_softc * } #if !defined(__FreeBSD__) - DPRINTFN(1,("uaudio_add_feature: bUnitId=%d bSourceId=%d, " - "%d channels, mmask=0x%04x, cmask=0x%04x\n", - d->bUnitId, srcId, nchan, mmask, cmask)); + DPRINTFN(1,("uaudio_add_feature: bUnitId=%d, " + "%d channels, mmask=0x%04x, cmask=0x%04x\n", + d->bUnitId, nchan, mmask, cmask)); #endif if (nchan > MIX_MAX_CHAN) @@ -961,7 +1317,7 @@ uaudio_add_feature(struct uaudio_softc * #undef GET #if !defined(__FreeBSD__) - mix.class = -1; /* XXX */ + mixername = uaudio_feature_name(&iot[id], &mix); #endif switch (ctl) { case MUTE_CONTROL: @@ -969,10 +1325,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_NRDEVICES; #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNmute); mix.ctlunit = ""; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNmute); #endif break; case VOLUME_CONTROL: @@ -981,10 +1336,8 @@ uaudio_add_feature(struct uaudio_softc * /* mix.ctl = SOUND_MIXER_VOLUME; */ mix.ctl = SOUND_MIXER_PCM; #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNmaster); mix.ctlunit = AudioNvolume; + strlcpy(mix.ctlname, mixername, sizeof(mix.ctlname)); #endif break; case BASS_CONTROL: @@ -992,10 +1345,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_BASS; #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNbass); mix.ctlunit = AudioNbass; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNbass); #endif break; case MID_CONTROL: @@ -1003,10 +1355,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNmid); mix.ctlunit = AudioNmid; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNmid); #endif break; case TREBLE_CONTROL: @@ -1014,10 +1365,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_TREBLE; #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNtreble); mix.ctlunit = AudioNtreble; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNtreble); #endif break; case GRAPHIC_EQUALIZER_CONTROL: @@ -1028,10 +1378,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNagc); mix.ctlunit = ""; + snprintf(mix.ctlname, sizeof(mix.ctlname), "%s.%s", + mixername, AudioNagc); #endif break; case DELAY_CONTROL: @@ -1039,10 +1388,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNdelay); mix.ctlunit = "4 ms"; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNdelay); #endif break; case BASS_BOOST_CONTROL: @@ -1050,10 +1398,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNbassboost); mix.ctlunit = ""; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNbassboost); #endif break; case LOUDNESS_CONTROL: @@ -1061,10 +1408,9 @@ uaudio_add_feature(struct uaudio_softc * #if defined(__FreeBSD__) mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ #else - sprintf(mix.ctlname, "fea%d-%s-%s", unit, - uaudio_id_name(sc, dps, srcId), - AudioNloudness); mix.ctlunit = ""; + snprintf(mix.ctlname, sizeof(mix.ctlname), + "%s.%s", mixername, AudioNloudness); #endif break; } @@ -1072,16 +1418,15 @@ uaudio_add_feature(struct uaudio_softc * } } -void -uaudio_add_processing_updown(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_processing_updown(struct uaudio_softc *sc, + const struct io_terminal *iot, int id) { - struct usb_audio_processing_unit *d = - (struct usb_audio_processing_unit *)v; - struct usb_audio_processing_unit_1 *d1 = - (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins]; - struct usb_audio_processing_unit_updown *ud = - (struct usb_audio_processing_unit_updown *) + const struct usb_audio_processing_unit *d = iot[id].d.pu; + const struct usb_audio_processing_unit_1 *d1 = + (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins]; + const struct usb_audio_processing_unit_updown *ud = + (const struct usb_audio_processing_unit_updown *) &d1->bmControls[d1->bControlSize]; struct mixerctl mix; int i; @@ -1098,12 +1443,12 @@ uaudio_add_processing_updown(struct uaud mix.nchan = 1; mix.wValue[0] = MAKE(UD_MODE_SELECT_CONTROL, 0); #if !defined(__FreeBSD__) - mix.class = -1; + uaudio_determine_class(&iot[id], &mix); #endif mix.type = MIX_ON_OFF; /* XXX */ #if !defined(__FreeBSD__) mix.ctlunit = ""; - sprintf(mix.ctlname, "pro%d-mode", d->bUnitId); + snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d-mode", d->bUnitId); #endif for (i = 0; i < ud->bNrModes; i++) { @@ -1114,14 +1459,12 @@ uaudio_add_processing_updown(struct uaud uaudio_mixer_add_ctl(sc, &mix); } -void -uaudio_add_processing(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_processing(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { - struct usb_audio_processing_unit *d = - (struct usb_audio_processing_unit *)v; - struct usb_audio_processing_unit_1 *d1 = - (struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins]; + const struct usb_audio_processing_unit *d = iot[id].d.pu; + const struct usb_audio_processing_unit_1 *d1 = + (const struct usb_audio_processing_unit_1 *)&d->baSourceId[d->bNrInPins]; int ptype = UGETW(d->wProcessType); struct mixerctl mix; @@ -1133,19 +1476,20 @@ uaudio_add_processing(struct uaudio_soft mix.nchan = 1; mix.wValue[0] = MAKE(XX_ENABLE_CONTROL, 0); #if !defined(__FreeBSD__) - mix.class = -1; + uaudio_determine_class(&iot[id], &mix); #endif mix.type = MIX_ON_OFF; #if !defined(__FreeBSD__) mix.ctlunit = ""; - sprintf(mix.ctlname, "pro%d.%d-enable", d->bUnitId, ptype); + snprintf(mix.ctlname, sizeof(mix.ctlname), "pro%d.%d-enable", + d->bUnitId, ptype); #endif uaudio_mixer_add_ctl(sc, &mix); } switch(ptype) { case UPDOWNMIX_PROCESS: - uaudio_add_processing_updown(sc, v, dps); + uaudio_add_processing_updown(sc, iot, id); break; case DOLBY_PROLOGIC_PROCESS: case P3D_STEREO_EXTENDER_PROCESS: @@ -1161,14 +1505,12 @@ uaudio_add_processing(struct uaudio_soft } } -void -uaudio_add_extension(struct uaudio_softc *sc, usb_descriptor_t *v, - usb_descriptor_t **dps) +Static void +uaudio_add_extension(struct uaudio_softc *sc, const struct io_terminal *iot, int id) { - struct usb_audio_extension_unit *d = - (struct usb_audio_extension_unit *)v; - struct usb_audio_extension_unit_1 *d1 = - (struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins]; + const struct usb_audio_extension_unit *d = iot[id].d.eu; + const struct usb_audio_extension_unit_1 *d1 = + (const struct usb_audio_extension_unit_1 *)&d->baSourceId[d->bNrInPins]; struct mixerctl mix; DPRINTFN(2,("uaudio_add_extension: bUnitId=%d bNrInPins=%d\n", @@ -1182,19 +1524,206 @@ uaudio_add_extension(struct uaudio_softc mix.nchan = 1; mix.wValue[0] = MAKE(UA_EXT_ENABLE, 0); #if !defined(__FreeBSD__) - mix.class = -1; + uaudio_determine_class(&iot[id], &mix); #endif mix.type = MIX_ON_OFF; #if !defined(__FreeBSD__) mix.ctlunit = ""; - sprintf(mix.ctlname, "ext%d-enable", d->bUnitId); + snprintf(mix.ctlname, sizeof(mix.ctlname), "ext%d-enable", + d->bUnitId); #endif uaudio_mixer_add_ctl(sc, &mix); } } -usbd_status -uaudio_identify(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc) +Static struct terminal_list* +uaudio_merge_terminal_list(const struct io_terminal *iot) +{ + struct terminal_list *tml; + uint16_t *ptm; + int i, len; + + len = 0; + if (iot->inputs == NULL) + return NULL; + for (i = 0; i < iot->inputs_size; i++) { + if (iot->inputs[i] != NULL) + len += iot->inputs[i]->size; + } + tml = malloc(TERMINAL_LIST_SIZE(len), M_TEMP, M_NOWAIT); + if (tml == NULL) { + printf("uaudio_merge_terminal_list: no memory\n"); + return NULL; + } + tml->size = 0; + ptm = tml->terminals; + for (i = 0; i < iot->inputs_size; i++) { + if (iot->inputs[i] == NULL) + continue; + if (iot->inputs[i]->size > len) + break; + memcpy(ptm, iot->inputs[i]->terminals, + iot->inputs[i]->size * sizeof(uint16_t)); + tml->size += iot->inputs[i]->size; + ptm += iot->inputs[i]->size; + len -= iot->inputs[i]->size; + } + return tml; +} + +Static struct terminal_list * +uaudio_io_terminaltype(int outtype, struct io_terminal *iot, int id) +{ + struct terminal_list *tml; + struct io_terminal *it; + int src_id, i; + + it = &iot[id]; + if (it->output != NULL) { + /* already has outtype? */ + for (i = 0; i < it->output->size; i++) + if (it->output->terminals[i] == outtype) + return uaudio_merge_terminal_list(it); + tml = malloc(TERMINAL_LIST_SIZE(it->output->size + 1), + M_TEMP, M_NOWAIT); + if (tml == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return uaudio_merge_terminal_list(it); + } + memcpy(tml, it->output, TERMINAL_LIST_SIZE(it->output->size)); + tml->terminals[it->output->size] = outtype; + tml->size++; + free(it->output, M_TEMP); + it->output = tml; + if (it->inputs != NULL) { + for (i = 0; i < it->inputs_size; i++) + if (it->inputs[i] != NULL) + free(it->inputs[i], M_TEMP); + free(it->inputs, M_TEMP); + } + it->inputs_size = 0; + it->inputs = NULL; + } else { /* end `iot[id] != NULL' */ + it->inputs_size = 0; + it->inputs = NULL; + it->output = malloc(TERMINAL_LIST_SIZE(1), M_TEMP, M_NOWAIT); + if (it->output == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + it->output->terminals[0] = outtype; + it->output->size = 1; + it->direct = FALSE; + } + + switch (it->d.desc->bDescriptorSubtype) { + case UDESCSUB_AC_INPUT: + it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + tml = malloc(TERMINAL_LIST_SIZE(1), M_TEMP, M_NOWAIT); + if (tml == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + free(it->inputs, M_TEMP); + it->inputs = NULL; + return NULL; + } + it->inputs[0] = tml; + tml->terminals[0] = UGETW(it->d.it->wTerminalType); + tml->size = 1; + it->inputs_size = 1; + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_FEATURE: + src_id = it->d.fu->bSourceId; + it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return uaudio_io_terminaltype(outtype, iot, src_id); + } + it->inputs[0] = uaudio_io_terminaltype(outtype, iot, src_id); + it->inputs_size = 1; + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_OUTPUT: + it->inputs = malloc(sizeof(struct terminal_list *), M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + src_id = it->d.ot->bSourceId; + it->inputs[0] = uaudio_io_terminaltype(outtype, iot, src_id); + it->inputs_size = 1; + iot[src_id].direct = TRUE; + return NULL; + case UDESCSUB_AC_MIXER: + it->inputs_size = 0; + it->inputs = malloc(sizeof(struct terminal_list *) + * it->d.mu->bNrInPins, M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + for (i = 0; i < it->d.mu->bNrInPins; i++) { + src_id = it->d.mu->baSourceId[i]; + it->inputs[i] = uaudio_io_terminaltype(outtype, iot, + src_id); + it->inputs_size++; + } + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_SELECTOR: + it->inputs_size = 0; + it->inputs = malloc(sizeof(struct terminal_list *) + * it->d.su->bNrInPins, M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + for (i = 0; i < it->d.su->bNrInPins; i++) { + src_id = it->d.su->baSourceId[i]; + it->inputs[i] = uaudio_io_terminaltype(outtype, iot, + src_id); + it->inputs_size++; + } + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_PROCESSING: + it->inputs_size = 0; + it->inputs = malloc(sizeof(struct terminal_list *) + * it->d.pu->bNrInPins, M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + for (i = 0; i < it->d.pu->bNrInPins; i++) { + src_id = it->d.pu->baSourceId[i]; + it->inputs[i] = uaudio_io_terminaltype(outtype, iot, + src_id); + it->inputs_size++; + } + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_EXTENSION: + it->inputs_size = 0; + it->inputs = malloc(sizeof(struct terminal_list *) + * it->d.eu->bNrInPins, M_TEMP, M_NOWAIT); + if (it->inputs == NULL) { + printf("uaudio_io_terminaltype: no memory\n"); + return NULL; + } + for (i = 0; i < it->d.eu->bNrInPins; i++) { + src_id = it->d.eu->baSourceId[i]; + it->inputs[i] = uaudio_io_terminaltype(outtype, iot, + src_id); + it->inputs_size++; + } + return uaudio_merge_terminal_list(it); + case UDESCSUB_AC_HEADER: + default: + return NULL; + } +} + +Static usbd_status +uaudio_identify(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc) { usbd_status err; @@ -1204,46 +1733,55 @@ uaudio_identify(struct uaudio_softc *sc, return (uaudio_identify_as(sc, cdesc)); } -void -uaudio_add_alt(struct uaudio_softc *sc, struct as_info *ai) +Static void +uaudio_add_alt(struct uaudio_softc *sc, const struct as_info *ai) { - size_t len = sizeof(*ai) * (sc->sc_nalts + 1); - struct as_info *nai = sc->sc_nalts == 0 ? - malloc(len, M_USBDEV, M_NOWAIT) : - realloc(sc->sc_alts, len, M_USBDEV, M_NOWAIT); + size_t len; + struct as_info *nai; + len = sizeof(*ai) * (sc->sc_nalts + 1); + nai = malloc(len, M_USBDEV, M_NOWAIT); if (nai == NULL) { printf("uaudio_add_alt: no memory\n"); return; } - + /* Copy old data, if there was any */ + if (sc->sc_nalts != 0) { + memcpy(nai, sc->sc_alts, sizeof(*ai) * (sc->sc_nalts)); + free(sc->sc_alts, M_USBDEV); + } sc->sc_alts = nai; DPRINTFN(2,("uaudio_add_alt: adding alt=%d, enc=%d\n", ai->alt, ai->encoding)); sc->sc_alts[sc->sc_nalts++] = *ai; } -usbd_status -uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp, - int size, usb_interface_descriptor_t *id) +Static usbd_status +uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp, + int size, const usb_interface_descriptor_t *id) #define offs (*offsp) { - struct usb_audio_streaming_interface_descriptor *asid; - struct usb_audio_streaming_type1_descriptor *asf1d; - usb_endpoint_descriptor_audio_t *ed; - struct usb_audio_streaming_endpoint_descriptor *sed; + const struct usb_audio_streaming_interface_descriptor *asid; + const struct usb_audio_streaming_type1_descriptor *asf1d; + const usb_endpoint_descriptor_audio_t *ed; + const usb_endpoint_descriptor_audio_t *epdesc1; + const struct usb_audio_streaming_endpoint_descriptor *sed; int format, chan, prec, enc; - int dir, type; + int dir, type, sync; struct as_info ai; + const char *format_str; - asid = (void *)(buf + offs); + asid = (const void *)(buf + offs); if (asid->bDescriptorType != UDESC_CS_INTERFACE || asid->bDescriptorSubtype != AS_GENERAL) return (USBD_INVAL); + DPRINTF(("uaudio_process_as: asid: bTerminakLink=%d wFormatTag=%d\n", + asid->bTerminalLink, UGETW(asid->wFormatTag))); offs += asid->bLength; if (offs > size) return (USBD_INVAL); - asf1d = (void *)(buf + offs); + + asf1d = (const void *)(buf + offs); if (asf1d->bDescriptorType != UDESC_CS_INTERFACE || asf1d->bDescriptorSubtype != FORMAT_TYPE) return (USBD_INVAL); @@ -1257,10 +1795,10 @@ uaudio_process_as(struct uaudio_softc *s return (USBD_NORMAL_COMPLETION); } - ed = (void *)(buf + offs); + ed = (const void *)(buf + offs); if (ed->bDescriptorType != UDESC_ENDPOINT) return (USBD_INVAL); - DPRINTF(("uaudio_process_as: endpoint bLength=%d bDescriptorType=%d " + DPRINTF(("uaudio_process_as: endpoint[0] bLength=%d bDescriptorType=%d " "bEndpointAddress=%d bmAttributes=0x%x wMaxPacketSize=%d " "bInterval=%d bRefresh=%d bSynchAddress=%d\n", ed->bLength, ed->bDescriptorType, ed->bEndpointAddress, @@ -1279,78 +1817,166 @@ uaudio_process_as(struct uaudio_softc *s type = UE_ISO_ASYNC; /* We can't handle endpoints that need a sync pipe yet. */ - if (dir == UE_DIR_IN ? type == UE_ISO_ADAPT : type == UE_ISO_ASYNC) { - printf("%s: ignored %sput endpoint of type %s\n", - USBDEVNAME(sc->sc_dev), - dir == UE_DIR_IN ? "in" : "out", - dir == UE_DIR_IN ? "adaptive" : "async"); + sync = FALSE; + if (dir == UE_DIR_IN && type == UE_ISO_ADAPT) { + sync = TRUE; +#ifndef UAUDIO_MULTIPLE_ENDPOINTS + printf("%s: ignored input endpoint of type adaptive\n", + USBDEVNAME(sc->sc_dev)); return (USBD_NORMAL_COMPLETION); +#endif } - - sed = (void *)(buf + offs); + if (dir != UE_DIR_IN && type == UE_ISO_ASYNC) { + sync = TRUE; +#ifndef UAUDIO_MULTIPLE_ENDPOINTS + printf("%s: ignored output endpoint of type async\n", + USBDEVNAME(sc->sc_dev)); + return (USBD_NORMAL_COMPLETION); +#endif + } + + sed = (const void *)(buf + offs); if (sed->bDescriptorType != UDESC_CS_ENDPOINT || sed->bDescriptorSubtype != AS_GENERAL) return (USBD_INVAL); + DPRINTF((" streadming_endpoint: offset=%d bLength=%d\n", offs, sed->bLength)); offs += sed->bLength; if (offs > size) return (USBD_INVAL); - + + if (sync && id->bNumEndpoints <= 1) { + printf("%s: a sync-pipe endpoint but no other endpoint\n", + USBDEVNAME(sc->sc_dev)); + return USBD_INVAL; + } + if (!sync && id->bNumEndpoints > 1) { + printf("%s: non sync-pipe endpoint but multiple endpoints\n", + USBDEVNAME(sc->sc_dev)); + return USBD_INVAL; + } + epdesc1 = NULL; + if (id->bNumEndpoints > 1) { + epdesc1 = (const void*)(buf + offs); + if (epdesc1->bDescriptorType != UDESC_ENDPOINT) + return USBD_INVAL; + DPRINTF(("uaudio_process_as: endpoint[1] bLength=%d " + "bDescriptorType=%d bEndpointAddress=%d " + "bmAttributes=0x%x wMaxPacketSize=%d bInterval=%d " + "bRefresh=%d bSynchAddress=%d\n", + epdesc1->bLength, epdesc1->bDescriptorType, + epdesc1->bEndpointAddress, epdesc1->bmAttributes, + UGETW(epdesc1->wMaxPacketSize), epdesc1->bInterval, + epdesc1->bRefresh, epdesc1->bSynchAddress)); + offs += epdesc1->bLength; + if (offs > size) + return USBD_INVAL; + if (epdesc1->bSynchAddress != 0) { + printf("%s: invalid endpoint: bSynchAddress=0\n", + USBDEVNAME(sc->sc_dev)); + return USBD_INVAL; + } + if (UE_GET_XFERTYPE(epdesc1->bmAttributes) != UE_ISOCHRONOUS) { + printf("%s: invalid endpoint: bmAttributes=0x%x\n", + USBDEVNAME(sc->sc_dev), epdesc1->bmAttributes); + return USBD_INVAL; + } + if (epdesc1->bEndpointAddress != ed->bSynchAddress) { + printf("%s: invalid endpoint addresses: " + "ep[0]->bSynchAddress=0x%x " + "ep[1]->bEndpointAddress=0x%x\n", + USBDEVNAME(sc->sc_dev), ed->bSynchAddress, + epdesc1->bEndpointAddress); + return USBD_INVAL; + } + /* UE_GET_ADDR(epdesc1->bEndpointAddress), and epdesc1->bRefresh */ + } + format = UGETW(asid->wFormatTag); chan = asf1d->bNrChannels; prec = asf1d->bBitResolution; - if (prec != 8 && prec != 16) { -#ifdef USB_DEBUG + if (prec != 8 && prec != 16 && prec != 24) { printf("%s: ignored setting with precision %d\n", USBDEVNAME(sc->sc_dev), prec); -#endif return (USBD_NORMAL_COMPLETION); } switch (format) { case UA_FMT_PCM: - sc->sc_altflags |= prec == 8 ? HAS_8 : HAS_16; + if (prec == 8) { + sc->sc_altflags |= HAS_8; + } else if (prec == 16) { + sc->sc_altflags |= HAS_16; + } else if (prec == 24) { + sc->sc_altflags |= HAS_24; + } enc = AUDIO_ENCODING_SLINEAR_LE; + format_str = "pcm"; break; case UA_FMT_PCM8: enc = AUDIO_ENCODING_ULINEAR_LE; sc->sc_altflags |= HAS_8U; + format_str = "pcm8"; break; case UA_FMT_ALAW: enc = AUDIO_ENCODING_ALAW; sc->sc_altflags |= HAS_ALAW; + format_str = "alaw"; break; case UA_FMT_MULAW: enc = AUDIO_ENCODING_ULAW; sc->sc_altflags |= HAS_MULAW; + format_str = "mulaw"; break; + case UA_FMT_IEEE_FLOAT: default: printf("%s: ignored setting with format %d\n", USBDEVNAME(sc->sc_dev), format); return (USBD_NORMAL_COMPLETION); } - DPRINTFN(1,("uaudio_identify: alt=%d enc=%d chan=%d prec=%d\n", - id->bAlternateSetting, enc, chan, prec)); +#ifdef USB_DEBUG + printf("%s: %s: %dch, %d/%dbit, %s,", USBDEVNAME(sc->sc_dev), + dir == UE_DIR_IN ? "recording" : "playback", + chan, prec, asf1d->bSubFrameSize * 8, format_str); + if (asf1d->bSamFreqType == UA_SAMP_CONTNUOUS) { + printf(" %d-%dHz\n", UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)); + } else { + int r; + printf(" %d", UA_GETSAMP(asf1d, 0)); + for (r = 1; r < asf1d->bSamFreqType; r++) + printf(",%d", UA_GETSAMP(asf1d, r)); + printf("Hz\n"); + } +#endif ai.alt = id->bAlternateSetting; ai.encoding = enc; + ai.attributes = sed->bmAttributes; ai.idesc = id; ai.edesc = ed; + ai.edesc1 = epdesc1; ai.asf1desc = asf1d; + ai.sc_busy = 0; uaudio_add_alt(sc, &ai); - sc->sc_chan.terminal = asid->bTerminalLink; /* XXX */ - sc->sc_chan.dir |= dir == UE_DIR_OUT ? AUMODE_PLAY : AUMODE_RECORD; +#ifdef USB_DEBUG + if (ai.attributes & UA_SED_FREQ_CONTROL) + DPRINTFN(1, ("uaudio_process_as: FREQ_CONTROL\n")); + if (ai.attributes & UA_SED_PITCH_CONTROL) + DPRINTFN(1, ("uaudio_process_as: PITCH_CONTROL\n")); +#endif + sc->sc_mode |= (dir == UE_DIR_OUT) ? AUMODE_PLAY : AUMODE_RECORD; + return (USBD_NORMAL_COMPLETION); } #undef offs - -usbd_status -uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc) + +Static usbd_status +uaudio_identify_as(struct uaudio_softc *sc, + const usb_config_descriptor_t *cdesc) { - usb_interface_descriptor_t *id; - usbd_status err; - char *buf; + const usb_interface_descriptor_t *id; + const char *buf; int size, offs; size = UGETW(cdesc->wTotalLength); - buf = (char *)cdesc; + buf = (const char *)cdesc; /* Locate the AudioStreaming interface descriptor. */ offs = 0; @@ -1358,13 +1984,10 @@ uaudio_identify_as(struct uaudio_softc * if (id == NULL) return (USBD_INVAL); - sc->sc_chan.terminal = -1; - sc->sc_chan.dir = 0; - /* Loop through all the alternate settings. */ while (offs <= size) { - DPRINTFN(2, ("uaudio_identify: interface %d\n", - id->bInterfaceNumber)); + DPRINTFN(2, ("uaudio_identify: interface=%d offset=%d\n", + id->bInterfaceNumber, offs)); switch (id->bNumEndpoints) { case 0: DPRINTFN(2, ("uaudio_identify: AS null alt=%d\n", @@ -1372,14 +1995,15 @@ uaudio_identify_as(struct uaudio_softc * sc->sc_nullalt = id->bAlternateSetting; break; case 1: - err = uaudio_process_as(sc, buf, &offs, size, id); +#ifdef UAUDIO_MULTIPLE_ENDPOINTS + case 2: +#endif + uaudio_process_as(sc, buf, &offs, size, id); break; default: -#ifdef USB_DEBUG printf("%s: ignored audio interface with %d " "endpoints\n", USBDEVNAME(sc->sc_dev), id->bNumEndpoints); -#endif break; } id = uaudio_find_iface(buf, size, &offs,UISUBCLASS_AUDIOSTREAM); @@ -1389,30 +2013,30 @@ uaudio_identify_as(struct uaudio_softc * if (offs > size) return (USBD_INVAL); DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts)); - if (sc->sc_chan.terminal < 0) { - printf("%s: no useable endpoint found\n", + + if (sc->sc_mode == 0) { + printf("%s: no usable endpoint found\n", USBDEVNAME(sc->sc_dev)); return (USBD_INVAL); } -#ifndef NO_RECORDING - if (sc->sc_chan.dir == (AUMODE_PLAY | AUMODE_RECORD)) - sc->sc_props |= AUDIO_PROP_FULLDUPLEX; -#endif return (USBD_NORMAL_COMPLETION); } -usbd_status -uaudio_identify_ac(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc) +Static usbd_status +uaudio_identify_ac(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc) { - usb_interface_descriptor_t *id; - struct usb_audio_control_descriptor *acdp; - usb_descriptor_t *dp, *dps[256]; - char *buf, *ibuf, *ibufend; - int size, offs, aclen, ndps, i; + struct io_terminal* iot; + const usb_interface_descriptor_t *id; + const struct usb_audio_control_descriptor *acdp; + const usb_descriptor_t *dp; + const struct usb_audio_output_terminal *pot; + struct terminal_list *tml; + const char *buf, *ibuf, *ibufend; + int size, offs, aclen, ndps, i, j; size = UGETW(cdesc->wTotalLength); - buf = (char *)cdesc; + buf = (const char *)cdesc; /* Locate the AudioControl interface descriptor. */ offs = 0; @@ -1422,11 +2046,11 @@ uaudio_identify_ac(struct uaudio_softc * if (offs + sizeof *acdp > size) return (USBD_INVAL); sc->sc_ac_iface = id->bInterfaceNumber; - DPRINTFN(2,("uaudio_identify: AC interface is %d\n", sc->sc_ac_iface)); + DPRINTFN(2,("uaudio_identify_ac: AC interface is %d\n", sc->sc_ac_iface)); /* A class-specific AC interface header should follow. */ ibuf = buf + offs; - acdp = (struct usb_audio_control_descriptor *)ibuf; + acdp = (const struct usb_audio_control_descriptor *)ibuf; if (acdp->bDescriptorType != UDESC_CS_INTERFACE || acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER) return (USBD_INVAL); @@ -1439,127 +2063,266 @@ uaudio_identify_ac(struct uaudio_softc * return (USBD_INVAL); sc->sc_audio_rev = UGETW(acdp->bcdADC); - DPRINTFN(2,("uaudio_identify: found AC header, vers=%03x, len=%d\n", + DPRINTFN(2,("uaudio_identify_ac: found AC header, vers=%03x, len=%d\n", sc->sc_audio_rev, aclen)); sc->sc_nullalt = -1; /* Scan through all the AC specific descriptors */ ibufend = ibuf + aclen; - dp = (usb_descriptor_t *)ibuf; + dp = (const usb_descriptor_t *)ibuf; ndps = 0; - memset(dps, 0, sizeof dps); + iot = malloc(sizeof(struct io_terminal) * 256, M_TEMP, M_NOWAIT | M_ZERO); + if (iot == NULL) { + printf("%s: no memory\n", __func__); + return USBD_NOMEM; + } for (;;) { ibuf += dp->bLength; if (ibuf >= ibufend) break; - dp = (usb_descriptor_t *)ibuf; + dp = (const usb_descriptor_t *)ibuf; if (ibuf + dp->bLength > ibufend) return (USBD_INVAL); if (dp->bDescriptorType != UDESC_CS_INTERFACE) { - printf("uaudio_identify: skip desc type=0x%02x\n", + printf("uaudio_identify_ac: skip desc type=0x%02x\n", dp->bDescriptorType); continue; } - i = ((struct usb_audio_input_terminal *)dp)->bTerminalId; - dps[i] = dp; + i = ((const struct usb_audio_input_terminal *)dp)->bTerminalId; + iot[i].d.desc = dp; if (i > ndps) ndps = i; } ndps++; + /* construct io_terminal */ for (i = 0; i < ndps; i++) { - dp = dps[i]; + dp = iot[i].d.desc; if (dp == NULL) continue; - DPRINTF(("uaudio_identify: subtype=%d\n", - dp->bDescriptorSubtype)); + if (dp->bDescriptorSubtype != UDESCSUB_AC_OUTPUT) + continue; + pot = iot[i].d.ot; + tml = uaudio_io_terminaltype(UGETW(pot->wTerminalType), iot, i); + if (tml != NULL) + free(tml, M_TEMP); + } + +#ifdef USB_DEBUG + for (i = 0; i < 256; i++) { + struct usb_audio_cluster cluster; + + if (iot[i].d.desc == NULL) + continue; + logprintf("id %d:\t", i); + switch (iot[i].d.desc->bDescriptorSubtype) { + case UDESCSUB_AC_INPUT: + logprintf("AC_INPUT type=%s\n", uaudio_get_terminal_name + (UGETW(iot[i].d.it->wTerminalType))); + logprintf("\t"); + cluster = uaudio_get_cluster(i, iot); + uaudio_dump_cluster(&cluster); + logprintf("\n"); + break; + case UDESCSUB_AC_OUTPUT: + logprintf("AC_OUTPUT type=%s ", uaudio_get_terminal_name + (UGETW(iot[i].d.ot->wTerminalType))); + logprintf("src=%d\n", iot[i].d.ot->bSourceId); + break; + case UDESCSUB_AC_MIXER: + logprintf("AC_MIXER src="); + for (j = 0; j < iot[i].d.mu->bNrInPins; j++) + logprintf("%d ", iot[i].d.mu->baSourceId[j]); + logprintf("\n\t"); + cluster = uaudio_get_cluster(i, iot); + uaudio_dump_cluster(&cluster); + logprintf("\n"); + break; + case UDESCSUB_AC_SELECTOR: + logprintf("AC_SELECTOR src="); + for (j = 0; j < iot[i].d.su->bNrInPins; j++) + logprintf("%d ", iot[i].d.su->baSourceId[j]); + logprintf("\n"); + break; + case UDESCSUB_AC_FEATURE: + logprintf("AC_FEATURE src=%d\n", iot[i].d.fu->bSourceId); + break; + case UDESCSUB_AC_PROCESSING: + logprintf("AC_PROCESSING src="); + for (j = 0; j < iot[i].d.pu->bNrInPins; j++) + logprintf("%d ", iot[i].d.pu->baSourceId[j]); + logprintf("\n\t"); + cluster = uaudio_get_cluster(i, iot); + uaudio_dump_cluster(&cluster); + logprintf("\n"); + break; + case UDESCSUB_AC_EXTENSION: + logprintf("AC_EXTENSION src="); + for (j = 0; j < iot[i].d.eu->bNrInPins; j++) + logprintf("%d ", iot[i].d.eu->baSourceId[j]); + logprintf("\n\t"); + cluster = uaudio_get_cluster(i, iot); + uaudio_dump_cluster(&cluster); + logprintf("\n"); + break; + default: + logprintf("unknown audio control (subtype=%d)\n", + iot[i].d.desc->bDescriptorSubtype); + } + for (j = 0; j < iot[i].inputs_size; j++) { + int k; + logprintf("\tinput%d: ", j); + tml = iot[i].inputs[j]; + if (tml == NULL) { + logprintf("NULL\n"); + continue; + } + for (k = 0; k < tml->size; k++) + logprintf("%s ", uaudio_get_terminal_name + (tml->terminals[k])); + logprintf("\n"); + } + logprintf("\toutput: "); + tml = iot[i].output; + for (j = 0; j < tml->size; j++) + logprintf("%s ", uaudio_get_terminal_name(tml->terminals[j])); + logprintf("\n"); + } +#endif + + for (i = 0; i < ndps; i++) { + dp = iot[i].d.desc; + if (dp == NULL) + continue; + DPRINTF(("uaudio_identify_ac: id=%d subtype=%d\n", + i, dp->bDescriptorSubtype)); switch (dp->bDescriptorSubtype) { case UDESCSUB_AC_HEADER: - printf("uaudio_identify: unexpected AC header\n"); + printf("uaudio_identify_ac: unexpected AC header\n"); break; case UDESCSUB_AC_INPUT: - uaudio_add_input(sc, dp, dps); + uaudio_add_input(sc, iot, i); break; case UDESCSUB_AC_OUTPUT: - uaudio_add_output(sc, dp, dps); + uaudio_add_output(sc, iot, i); break; case UDESCSUB_AC_MIXER: - uaudio_add_mixer(sc, dp, dps); + uaudio_add_mixer(sc, iot, i); break; case UDESCSUB_AC_SELECTOR: - uaudio_add_selector(sc, dp, dps); + uaudio_add_selector(sc, iot, i); break; case UDESCSUB_AC_FEATURE: - uaudio_add_feature(sc, dp, dps); + uaudio_add_feature(sc, iot, i); break; case UDESCSUB_AC_PROCESSING: - uaudio_add_processing(sc, dp, dps); + uaudio_add_processing(sc, iot, i); break; case UDESCSUB_AC_EXTENSION: - uaudio_add_extension(sc, dp, dps); + uaudio_add_extension(sc, iot, i); break; default: - printf("uaudio_identify: bad AC desc subtype=0x%02x\n", + printf("uaudio_identify_ac: bad AC desc subtype=0x%02x\n", dp->bDescriptorSubtype); break; } } + + /* delete io_terminal */ + for (i = 0; i < 256; i++) { + if (iot[i].d.desc == NULL) + continue; + if (iot[i].inputs != NULL) { + for (j = 0; j < iot[i].inputs_size; j++) { + if (iot[i].inputs[j] != NULL) + free(iot[i].inputs[j], M_TEMP); + } + free(iot[i].inputs, M_TEMP); + } + if (iot[i].output != NULL) + free(iot[i].output, M_TEMP); + iot[i].d.desc = NULL; + } + free(iot, M_TEMP); + return (USBD_NORMAL_COMPLETION); } #if defined(__NetBSD__) || defined(__OpenBSD__) -int +Static int uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi) { struct uaudio_softc *sc = addr; struct mixerctl *mc; - int n, nctls; + int n, nctls, i; DPRINTFN(2,("uaudio_query_devinfo: index=%d\n", mi->index)); if (sc->sc_dying) return (EIO); - + n = mi->index; nctls = sc->sc_nctls; - if (n < 0 || n >= nctls) { - switch (n - nctls) { - case UAC_OUTPUT: - mi->type = AUDIO_MIXER_CLASS; - mi->mixer_class = nctls + UAC_OUTPUT; - mi->next = mi->prev = AUDIO_MIXER_LAST; - strcpy(mi->label.name, AudioCoutputs); - return (0); - case UAC_INPUT: - mi->type = AUDIO_MIXER_CLASS; - mi->mixer_class = nctls + UAC_INPUT; - mi->next = mi->prev = AUDIO_MIXER_LAST; - strcpy(mi->label.name, AudioCinputs); - return (0); - case UAC_EQUAL: - mi->type = AUDIO_MIXER_CLASS; - mi->mixer_class = nctls + UAC_EQUAL; - mi->next = mi->prev = AUDIO_MIXER_LAST; - strcpy(mi->label.name, AudioCequalization); - return (0); - default: - return (ENXIO); - } + switch (n) { + case UAC_OUTPUT: + mi->type = AUDIO_MIXER_CLASS; + mi->mixer_class = UAC_OUTPUT; + mi->next = mi->prev = AUDIO_MIXER_LAST; + strlcpy(mi->label.name, AudioCoutputs, sizeof(mi->label.name)); + return (0); + case UAC_INPUT: + mi->type = AUDIO_MIXER_CLASS; + mi->mixer_class = UAC_INPUT; + mi->next = mi->prev = AUDIO_MIXER_LAST; + strlcpy(mi->label.name, AudioCinputs, sizeof(mi->label.name)); + return (0); + case UAC_EQUAL: + mi->type = AUDIO_MIXER_CLASS; + mi->mixer_class = UAC_EQUAL; + mi->next = mi->prev = AUDIO_MIXER_LAST; + strlcpy(mi->label.name, AudioCequalization, + sizeof(mi->label.name)); + return (0); + case UAC_RECORD: + mi->type = AUDIO_MIXER_CLASS; + mi->mixer_class = UAC_RECORD; + mi->next = mi->prev = AUDIO_MIXER_LAST; + strlcpy(mi->label.name, AudioCrecord, sizeof(mi->label.name)); + return 0; + default: + break; } + + n -= UAC_NCLASSES; + if (n < 0 || n >= nctls) + return (ENXIO); + mc = &sc->sc_ctls[n]; - strncpy(mi->label.name, mc->ctlname, MAX_AUDIO_DEV_LEN); + strlcpy(mi->label.name, mc->ctlname, sizeof(mi->label.name)); mi->mixer_class = mc->class; mi->next = mi->prev = AUDIO_MIXER_LAST; /* XXX */ switch (mc->type) { case MIX_ON_OFF: mi->type = AUDIO_MIXER_ENUM; mi->un.e.num_mem = 2; - strcpy(mi->un.e.member[0].label.name, AudioNoff); + strlcpy(mi->un.e.member[0].label.name, AudioNoff, + sizeof(mi->un.e.member[0].label.name)); mi->un.e.member[0].ord = 0; - strcpy(mi->un.e.member[1].label.name, AudioNon); + strlcpy(mi->un.e.member[1].label.name, AudioNon, + sizeof(mi->un.e.member[1].label.name)); mi->un.e.member[1].ord = 1; break; + case MIX_SELECTOR: + mi->type = AUDIO_MIXER_ENUM; + mi->un.e.num_mem = mc->maxval - mc->minval + 1; + for (i = 0; i <= mc->maxval - mc->minval; i++) { + snprintf(mi->un.e.member[i].label.name, + sizeof(mi->un.e.member[i].label.name), + "%d", i + mc->minval); + mi->un.e.member[i].ord = i + mc->minval; + } + break; default: mi->type = AUDIO_MIXER_VALUE; strncpy(mi->un.v.units.name, mc->ctlunit, MAX_AUDIO_DEV_LEN); @@ -1570,60 +2333,42 @@ uaudio_query_devinfo(void *addr, mixer_d return (0); } -int +Static int uaudio_open(void *addr, int flags) { struct uaudio_softc *sc = addr; - DPRINTF(("uaudio_open: sc=%p\n", sc)); + DPRINTF(("uaudio_open: sc=%p\n", sc)); if (sc->sc_dying) return (EIO); - if (sc->sc_chan.terminal < 0) - return (ENXIO); - - if ((flags & FREAD) && !(sc->sc_chan.dir & AUMODE_RECORD)) + if ((flags & FWRITE) && !(sc->sc_mode & AUMODE_PLAY)) return (EACCES); - if ((flags & FWRITE) && !(sc->sc_chan.dir & AUMODE_PLAY)) + if ((flags & FREAD) && !(sc->sc_mode & AUMODE_RECORD)) return (EACCES); - sc->sc_chan.intr = 0; - - return (0); + return (0); } /* * Close function is called at splaudio(). */ -void +Static void uaudio_close(void *addr) { - struct uaudio_softc *sc = addr; - - if (sc->sc_dying) - return (EIO); - - DPRINTF(("uaudio_close: sc=%p\n", sc)); - uaudio_halt_in_dma(sc); - uaudio_halt_out_dma(sc); - - sc->sc_chan.intr = 0; } -int +Static int uaudio_drain(void *addr) { struct uaudio_softc *sc = addr; - if (sc->sc_dying) - return (EIO); - usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES); return (0); } -int +Static int uaudio_halt_out_dma(void *addr) { struct uaudio_softc *sc = addr; @@ -1632,29 +2377,31 @@ uaudio_halt_out_dma(void *addr) return (EIO); DPRINTF(("uaudio_halt_out_dma: enter\n")); - if (sc->sc_chan.pipe != NULL) { - uaudio_chan_close(sc, &sc->sc_chan); - sc->sc_chan.pipe = 0; - uaudio_chan_free_buffers(sc, &sc->sc_chan); + if (sc->sc_playchan.pipe != NULL) { + uaudio_chan_close(sc, &sc->sc_playchan); + sc->sc_playchan.pipe = NULL; + uaudio_chan_free_buffers(sc, &sc->sc_playchan); + sc->sc_playchan.intr = NULL; } - return (0); + return (0); } -int +Static int uaudio_halt_in_dma(void *addr) { struct uaudio_softc *sc = addr; DPRINTF(("uaudio_halt_in_dma: enter\n")); - if (sc->sc_chan.pipe != NULL) { - uaudio_chan_close(sc, &sc->sc_chan); - sc->sc_chan.pipe = 0; - uaudio_chan_free_buffers(sc, &sc->sc_chan); + if (sc->sc_recchan.pipe != NULL) { + uaudio_chan_close(sc, &sc->sc_recchan); + sc->sc_recchan.pipe = NULL; + uaudio_chan_free_buffers(sc, &sc->sc_recchan); + sc->sc_recchan.intr = NULL; } - return (0); + return (0); } -int +Static int uaudio_getdev(void *addr, struct audio_device *retp) { struct uaudio_softc *sc = addr; @@ -1662,24 +2409,30 @@ uaudio_getdev(void *addr, struct audio_d DPRINTF(("uaudio_mixer_getdev:\n")); if (sc->sc_dying) return (EIO); - + *retp = uaudio_device; - return (0); + return (0); } /* * Make sure the block size is large enough to hold all outstanding transfers. */ -int +Static int uaudio_round_blocksize(void *addr, int blk) { struct uaudio_softc *sc = addr; int bpf; - if (sc->sc_dying) - return (EIO); - - bpf = sc->sc_chan.bytes_per_frame + sc->sc_chan.sample_size; + DPRINTF(("uaudio_round_blocksize: p.bpf=%d r.bpf=%d\n", + sc->sc_playchan.bytes_per_frame, + sc->sc_recchan.bytes_per_frame)); + if (sc->sc_playchan.bytes_per_frame > sc->sc_recchan.bytes_per_frame) { + bpf = sc->sc_playchan.bytes_per_frame + + sc->sc_playchan.sample_size; + } else { + bpf = sc->sc_recchan.bytes_per_frame + + sc->sc_recchan.sample_size; + } /* XXX */ bpf *= UAUDIO_NFRAMES * UAUDIO_NCHANBUFS; @@ -1699,17 +2452,15 @@ uaudio_round_blocksize(void *addr, int b return (blk); } -int +Static int uaudio_get_props(void *addr) { - struct uaudio_softc *sc = addr; + return (AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT); - return (sc->sc_props); } #endif /* NetBSD or OpenBSD */ - -int +Static int uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue, int wIndex, int len) { @@ -1718,8 +2469,10 @@ uaudio_get(struct uaudio_softc *sc, int usbd_status err; int val; +#if defined(__FreeBSD__) if (sc->sc_dying) return (EIO); +#endif if (wValue == -1) return (0); @@ -1730,9 +2483,9 @@ uaudio_get(struct uaudio_softc *sc, int USETW(req.wIndex, wIndex); USETW(req.wLength, len); DPRINTFN(2,("uaudio_get: type=0x%02x req=0x%02x wValue=0x%04x " - "wIndex=0x%04x len=%d\n", + "wIndex=0x%04x len=%d\n", type, which, wValue, wIndex, len)); - err = usbd_do_request(sc->sc_udev, &req, &data); + err = usbd_do_request(sc->sc_udev, &req, data); if (err) { DPRINTF(("uaudio_get: err=%s\n", usbd_errstr(err))); return (-1); @@ -1752,7 +2505,7 @@ uaudio_get(struct uaudio_softc *sc, int return (val); } -void +Static void uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue, int wIndex, int len, int val) { @@ -1760,8 +2513,10 @@ uaudio_set(struct uaudio_softc *sc, int u_int8_t data[4]; usbd_status err; +#if defined(__FreeBSD__) if (sc->sc_dying) return; +#endif if (wValue == -1) return; @@ -1783,16 +2538,16 @@ uaudio_set(struct uaudio_softc *sc, int return; } DPRINTFN(2,("uaudio_set: type=0x%02x req=0x%02x wValue=0x%04x " - "wIndex=0x%04x len=%d, val=%d\n", + "wIndex=0x%04x len=%d, val=%d\n", type, which, wValue, wIndex, len, val & 0xffff)); - err = usbd_do_request(sc->sc_udev, &req, &data); + err = usbd_do_request(sc->sc_udev, &req, data); #ifdef USB_DEBUG if (err) DPRINTF(("uaudio_set: err=%d\n", err)); #endif } -int +Static int uaudio_signext(int type, int val) { if (!MIX_UNSIGNED(type)) { @@ -1805,15 +2560,18 @@ uaudio_signext(int type, int val) } #if defined(__NetBSD__) || defined(__OpenBSD__) -int +Static int uaudio_value2bsd(struct mixerctl *mc, int val) { DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ", mc->type, val, mc->minval, mc->maxval)); - if (mc->type == MIX_ON_OFF) - val = val != 0; - else - val = ((uaudio_signext(mc->type, val) - mc->minval) * 256 + if (mc->type == MIX_ON_OFF) { + val = (val != 0); + } else if (mc->type == MIX_SELECTOR) { + if (val < mc->minval || val > mc->maxval) + val = mc->minval; + } else + val = ((uaudio_signext(mc->type, val) - mc->minval) * 255 + mc->mul/2) / mc->mul; DPRINTFN(5, ("val'=%d\n", val)); return (val); @@ -1825,17 +2583,20 @@ uaudio_bsd2value(struct mixerctl *mc, in { DPRINTFN(5,("uaudio_bsd2value: type=%03x val=%d min=%d max=%d ", mc->type, val, mc->minval, mc->maxval)); - if (mc->type == MIX_ON_OFF) - val = val != 0; - else - val = (val + mc->delta/2) * mc->mul / 256 + mc->minval; + if (mc->type == MIX_ON_OFF) { + val = (val != 0); + } else if (mc->type == MIX_SELECTOR) { + if (val < mc->minval || val > mc->maxval) + val = mc->minval; + } else + val = (val + mc->delta/2) * mc->mul / 255 + mc->minval; DPRINTFN(5, ("val'=%d\n", val)); return (val); } #if defined(__NetBSD__) || defined(__OpenBSD__) -int -uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc, +Static int +uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc, int chan) { int val; @@ -1847,7 +2608,7 @@ uaudio_ctl_get(struct uaudio_softc *sc, } #endif -void +Static void uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc, int chan, int val) { @@ -1857,7 +2618,7 @@ uaudio_ctl_set(struct uaudio_softc *sc, } #if defined(__NetBSD__) || defined(__OpenBSD__) -int +Static int uaudio_mixer_get_port(void *addr, mixer_ctrl_t *cp) { struct uaudio_softc *sc = addr; @@ -1868,8 +2629,8 @@ uaudio_mixer_get_port(void *addr, mixer_ if (sc->sc_dying) return (EIO); - - n = cp->dev; + + n = cp->dev - UAC_NCLASSES; if (n < 0 || n >= sc->sc_nctls) return (ENXIO); mc = &sc->sc_ctls[n]; @@ -1878,6 +2639,10 @@ uaudio_mixer_get_port(void *addr, mixer_ if (cp->type != AUDIO_MIXER_ENUM) return (EINVAL); cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0); + } else if (mc->type == MIX_SELECTOR) { + if (cp->type != AUDIO_MIXER_ENUM) + return (EINVAL); + cp->un.ord = uaudio_ctl_get(sc, GET_CUR, mc, 0); } else { if (cp->type != AUDIO_MIXER_VALUE) return (EINVAL); @@ -1897,8 +2662,8 @@ uaudio_mixer_get_port(void *addr, mixer_ return (0); } - -int + +Static int uaudio_mixer_set_port(void *addr, mixer_ctrl_t *cp) { struct uaudio_softc *sc = addr; @@ -1908,8 +2673,8 @@ uaudio_mixer_set_port(void *addr, mixer_ DPRINTFN(2,("uaudio_mixer_set_port: index = %d\n", cp->dev)); if (sc->sc_dying) return (EIO); - - n = cp->dev; + + n = cp->dev - UAC_NCLASSES; if (n < 0 || n >= sc->sc_nctls) return (ENXIO); mc = &sc->sc_ctls[n]; @@ -1918,6 +2683,10 @@ uaudio_mixer_set_port(void *addr, mixer_ if (cp->type != AUDIO_MIXER_ENUM) return (EINVAL); uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord); + } else if (mc->type == MIX_SELECTOR) { + if (cp->type != AUDIO_MIXER_ENUM) + return (EINVAL); + uaudio_ctl_set(sc, SET_CUR, mc, 0, cp->un.ord); } else { if (cp->type != AUDIO_MIXER_VALUE) return (EINVAL); @@ -1935,13 +2704,13 @@ uaudio_mixer_set_port(void *addr, mixer_ return (0); } -int +Static int uaudio_trigger_input(void *addr, void *start, void *end, int blksize, void (*intr)(void *), void *arg, struct audio_params *param) { struct uaudio_softc *sc = addr; - struct chan *ch = &sc->sc_chan; + struct chan *ch = &sc->sc_recchan; usbd_status err; int i, s; @@ -1951,7 +2720,7 @@ uaudio_trigger_input(void *addr, void *s DPRINTFN(3,("uaudio_trigger_input: sc=%p start=%p end=%p " "blksize=%d\n", sc, start, end, blksize)); - uaudio_chan_set_param(ch, param, start, end, blksize); + uaudio_chan_set_param(ch, start, end, blksize); DPRINTFN(3,("uaudio_trigger_input: sample_size=%d bytes/frame=%d " "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame, ch->fraction)); @@ -1966,24 +2735,24 @@ uaudio_trigger_input(void *addr, void *s return (EIO); } - sc->sc_chan.intr = intr; - sc->sc_chan.arg = arg; + ch->intr = intr; + ch->arg = arg; s = splusb(); for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */ uaudio_chan_rtransfer(ch); splx(s); - return (0); + return (0); } - -int + +Static int uaudio_trigger_output(void *addr, void *start, void *end, int blksize, void (*intr)(void *), void *arg, struct audio_params *param) { struct uaudio_softc *sc = addr; - struct chan *ch = &sc->sc_chan; + struct chan *ch = &sc->sc_playchan; usbd_status err; int i, s; @@ -1993,7 +2762,7 @@ uaudio_trigger_output(void *addr, void * DPRINTFN(3,("uaudio_trigger_output: sc=%p start=%p end=%p " "blksize=%d\n", sc, start, end, blksize)); - uaudio_chan_set_param(ch, param, start, end, blksize); + uaudio_chan_set_param(ch, start, end, blksize); DPRINTFN(3,("uaudio_trigger_output: sample_size=%d bytes/frame=%d " "fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame, ch->fraction)); @@ -2008,30 +2777,32 @@ uaudio_trigger_output(void *addr, void * return (EIO); } - sc->sc_chan.intr = intr; - sc->sc_chan.arg = arg; + ch->intr = intr; + ch->arg = arg; s = splusb(); for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */ uaudio_chan_ptransfer(ch); splx(s); - return (0); + return (0); } #endif /* NetBSD or OpenBSD */ /* Set up a pipe for a channel. */ -usbd_status +Static usbd_status uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch) { - struct as_info *as = &sc->sc_alts[sc->sc_curaltidx]; + struct as_info *as = &sc->sc_alts[ch->altidx]; int endpt = as->edesc->bEndpointAddress; usbd_status err; +#if defined(__FreeBSD__) if (sc->sc_dying) return (EIO); +#endif - DPRINTF(("uaudio_open_chan: endpt=0x%02x, speed=%d, alt=%d\n", + DPRINTF(("uaudio_chan_open: endpt=0x%02x, speed=%d, alt=%d\n", endpt, ch->sample_rate, as->alt)); /* Set alternate interface corresponding to the mode. */ @@ -2039,39 +2810,59 @@ uaudio_chan_open(struct uaudio_softc *sc if (err) return (err); - /* Some devices do not support this request, so ignore errors. */ -#ifdef USB_DEBUG - err = uaudio_set_speed(sc, endpt, ch->sample_rate); - if (err) - DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n", - usbd_errstr(err))); -#else - (void)uaudio_set_speed(sc, endpt, ch->sample_rate); -#endif + /* + * If just one sampling rate is supported, + * no need to call uaudio_set_speed(). + * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request. + */ + if (as->asf1desc->bSamFreqType != 1) { + err = uaudio_set_speed(sc, endpt, ch->sample_rate); + if (err) + DPRINTF(("uaudio_chan_open: set_speed failed err=%s\n", + usbd_errstr(err))); + } - DPRINTF(("uaudio_open_chan: create pipe to 0x%02x\n", endpt)); + ch->pipe = 0; + ch->sync_pipe = 0; + DPRINTF(("uaudio_chan_open: create pipe to 0x%02x\n", endpt)); err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->pipe); - return (err); + if (err) + return err; + if (as->edesc1 != NULL) { + endpt = as->edesc1->bEndpointAddress; + DPRINTF(("uaudio_chan_open: create sync-pipe to 0x%02x\n", endpt)); + err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->sync_pipe); + } + return err; } -void +Static void uaudio_chan_close(struct uaudio_softc *sc, struct chan *ch) { - struct as_info *as = &sc->sc_alts[sc->sc_curaltidx]; + struct as_info *as = &sc->sc_alts[ch->altidx]; +#if defined(__FreeBSD__) if (sc->sc_dying) return ; +#endif + as->sc_busy = 0; if (sc->sc_nullalt >= 0) { - DPRINTF(("uaudio_close_chan: set null alt=%d\n", + DPRINTF(("uaudio_chan_close: set null alt=%d\n", sc->sc_nullalt)); usbd_set_interface(as->ifaceh, sc->sc_nullalt); } - usbd_abort_pipe(ch->pipe); - usbd_close_pipe(ch->pipe); + if (ch->pipe) { + usbd_abort_pipe(ch->pipe); + usbd_close_pipe(ch->pipe); + } + if (ch->sync_pipe) { + usbd_abort_pipe(ch->sync_pipe); + usbd_close_pipe(ch->sync_pipe); + } } -usbd_status +Static usbd_status uaudio_chan_alloc_buffers(struct uaudio_softc *sc, struct chan *ch) { usbd_xfer_handle xfer; @@ -2102,7 +2893,7 @@ bad: return (USBD_NOMEM); } -void +Static void uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch) { int i; @@ -2112,7 +2903,7 @@ uaudio_chan_free_buffers(struct uaudio_s } /* Called at splusb() */ -void +Static void uaudio_chan_ptransfer(struct chan *ch) { struct chanbuf *cb; @@ -2133,7 +2924,7 @@ uaudio_chan_ptransfer(struct chan *ch) size = ch->bytes_per_frame; residue += ch->fraction; if (residue >= USB_FRAMES_PER_SECOND) { - if (!ch->nofrac) + if ((ch->sc->sc_altflags & UA_NOFRAC) == 0) size += ch->sample_size; residue -= USB_FRAMES_PER_SECOND; } @@ -2143,7 +2934,7 @@ uaudio_chan_ptransfer(struct chan *ch) ch->residue = residue; cb->size = total; - /* + /* * Transfer data from upper layer buffer to channel buffer, taking * care of wrapping the upper layer buffer. */ @@ -2170,14 +2961,14 @@ uaudio_chan_ptransfer(struct chan *ch) DPRINTFN(5,("uaudio_chan_transfer: ptransfer xfer=%p\n", cb->xfer)); /* Fill the request */ - usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes, - UAUDIO_NFRAMES, USBD_NO_COPY, + usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes, + UAUDIO_NFRAMES, USBD_NO_COPY, uaudio_chan_pintr); (void)usbd_transfer(cb->xfer); } -void +Static void uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { @@ -2211,7 +3002,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, /* Call back to upper layer */ while (ch->transferred >= ch->blksize) { ch->transferred -= ch->blksize; - DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n", + DPRINTFN(5,("uaudio_chan_pintr: call %p(%p)\n", ch->intr, ch->arg)); ch->intr(ch->arg); } @@ -2223,7 +3014,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, } /* Called at splusb() */ -void +Static void uaudio_chan_rtransfer(struct chan *ch) { struct chanbuf *cb; @@ -2242,13 +3033,8 @@ uaudio_chan_rtransfer(struct chan *ch) total = 0; for (i = 0; i < UAUDIO_NFRAMES; i++) { size = ch->bytes_per_frame; - residue += ch->fraction; - if (residue >= USB_FRAMES_PER_SECOND) { - if (!ch->nofrac) - size += ch->sample_size; - residue -= USB_FRAMES_PER_SECOND; - } cb->sizes[i] = size; + cb->offsets[i] = total; total += size; } ch->residue = residue; @@ -2266,21 +3052,21 @@ uaudio_chan_rtransfer(struct chan *ch) DPRINTFN(5,("uaudio_chan_rtransfer: transfer xfer=%p\n", cb->xfer)); /* Fill the request */ - usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes, - UAUDIO_NFRAMES, USBD_NO_COPY, + usbd_setup_isoc_xfer(cb->xfer, ch->pipe, cb, cb->sizes, + UAUDIO_NFRAMES, USBD_NO_COPY, uaudio_chan_rintr); (void)usbd_transfer(cb->xfer); } -void +Static void uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct chanbuf *cb = priv; struct chan *ch = cb->chan; u_int32_t count; - int s, n; + int s, i, n, frsize; /* Return if we are aborting. */ if (status == USBD_CANCELLED) @@ -2290,36 +3076,34 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, DPRINTFN(5,("uaudio_chan_rintr: count=%d, transferred=%d\n", count, ch->transferred)); - if (count < cb->size) { - /* if the device fails to keep up, copy last byte */ - u_char b = count ? cb->buffer[count-1] : 0; - while (count < cb->size) - cb->buffer[count++] = b; - } - + /* count < cb->size is normal for asynchronous source */ #ifdef DIAGNOSTIC - if (count != cb->size) { - printf("uaudio_chan_rintr: count(%d) != size(%d)\n", + if (count > cb->size) { + printf("uaudio_chan_rintr: count(%d) > size(%d)\n", count, cb->size); } #endif - /* + /* * Transfer data from channel buffer to upper layer buffer, taking * care of wrapping the upper layer buffer. */ - n = min(count, ch->end - ch->cur); - memcpy(ch->cur, cb->buffer, n); - ch->cur += n; - if (ch->cur >= ch->end) - ch->cur = ch->start; - if (count > n) { - memcpy(ch->cur, cb->buffer + n, count - n); - ch->cur += count - n; + for(i = 0; i < UAUDIO_NFRAMES; i++) { + frsize = cb->sizes[i]; + n = min(frsize, ch->end - ch->cur); + memcpy(ch->cur, cb->buffer + cb->offsets[i], n); + ch->cur += n; + if (ch->cur >= ch->end) + ch->cur = ch->start; + if (frsize > n) { + memcpy(ch->cur, cb->buffer + cb->offsets[i] + n, + frsize - n); + ch->cur += frsize - n; + } } /* Call back to upper layer */ - ch->transferred += cb->size; + ch->transferred += count; #if defined(__FreeBSD__) s = spltty(); chn_intr(ch->pcm_ch); @@ -2328,7 +3112,7 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, s = splaudio(); while (ch->transferred >= ch->blksize) { ch->transferred -= ch->blksize; - DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n", + DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n", ch->intr, ch->arg)); ch->intr(ch->arg); } @@ -2340,20 +3124,30 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, } #if defined(__NetBSD__) || defined(__OpenBSD__) -void -uaudio_chan_set_param(struct chan *ch, struct audio_params *param, - u_char *start, u_char *end, int blksize) +Static void +uaudio_chan_init(struct chan *ch, int altidx, const struct audio_params *param, + int maxpktsize) { int samples_per_frame, sample_size; - sample_size = param->precision * param->channels / 8; - samples_per_frame = param->sample_rate / USB_FRAMES_PER_SECOND; - ch->fraction = param->sample_rate % USB_FRAMES_PER_SECOND; + ch->altidx = altidx; + sample_size = param->precision * param->factor * param->hw_channels / 8; + samples_per_frame = param->hw_sample_rate / USB_FRAMES_PER_SECOND; ch->sample_size = sample_size; - ch->sample_rate = param->sample_rate; - ch->bytes_per_frame = samples_per_frame * sample_size; + ch->sample_rate = param->hw_sample_rate; + if (maxpktsize == 0) { + ch->fraction = param->hw_sample_rate % USB_FRAMES_PER_SECOND; + ch->bytes_per_frame = samples_per_frame * sample_size; + } else { + ch->fraction = 0; + ch->bytes_per_frame = maxpktsize; + } ch->residue = 0; +} +Static void +uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize) +{ ch->start = start; ch->end = end; ch->cur = start; @@ -2363,14 +3157,164 @@ uaudio_chan_set_param(struct chan *ch, s ch->curchanbuf = 0; } -int +Static void +uaudio_get_minmax_rates(int nalts, const struct as_info *alts, + const struct audio_params *p, int mode, + u_long *min, u_long *max) +{ + const struct usb_audio_streaming_type1_descriptor *a1d; + int i, j; + + *min = ULONG_MAX; + *max = 0; + for (i = 0; i < nalts; i++) { + a1d = alts[i].asf1desc; + if (alts[i].sc_busy) + continue; + if (p->hw_channels != a1d->bNrChannels) + continue; + if (p->hw_precision != a1d->bBitResolution) + continue; + if (p->hw_encoding != alts[i].encoding) + continue; + if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress)) + continue; + if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) { + DPRINTFN(2,("uaudio_get_minmax_rates: cont %d-%d\n", + UA_SAMP_LO(a1d), UA_SAMP_HI(a1d))); + if (UA_SAMP_LO(a1d) < *min) + *min = UA_SAMP_LO(a1d); + if (UA_SAMP_HI(a1d) > *max) + *max = UA_SAMP_HI(a1d); + } else { + for (j = 0; j < a1d->bSamFreqType; j++) { + DPRINTFN(2,("uaudio_get_minmax_rates: disc #%d: %d\n", + j, UA_GETSAMP(a1d, j))); + if (UA_GETSAMP(a1d, j) < *min) + *min = UA_GETSAMP(a1d, j); + if (UA_GETSAMP(a1d, j) > *max) + *max = UA_GETSAMP(a1d, j); + } + } + } +} + +Static int +uaudio_match_alt_sub(int nalts, const struct as_info *alts, + const struct audio_params *p, int mode, u_long rate) +{ + const struct usb_audio_streaming_type1_descriptor *a1d; + int i, j; + + DPRINTF(("uaudio_match_alt_sub: search for %luHz %dch\n", + rate, p->hw_channels)); + for (i = 0; i < nalts; i++) { + a1d = alts[i].asf1desc; + if (alts[i].sc_busy) + continue; + if (p->hw_channels != a1d->bNrChannels) + continue; + if (p->hw_precision != a1d->bBitResolution) + continue; + if (p->hw_encoding != alts[i].encoding) + continue; + if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress)) + continue; + if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) { + DPRINTFN(3,("uaudio_match_alt_sub: cont %d-%d\n", + UA_SAMP_LO(a1d), UA_SAMP_HI(a1d))); + if (UA_SAMP_LO(a1d) <= rate && rate <= UA_SAMP_HI(a1d)) + return i; + } else { + for (j = 0; j < a1d->bSamFreqType; j++) { + DPRINTFN(3,("uaudio_match_alt_sub: disc #%d: %d\n", + j, UA_GETSAMP(a1d, j))); + /* XXX allow for some slack */ + if (UA_GETSAMP(a1d, j) == rate) + return i; + } + } + } + return -1; +} + +Static int +uaudio_match_alt_chan(int nalts, const struct as_info *alts, + struct audio_params *p, int mode) +{ + int i, n; + u_long min, max; + u_long rate; + + /* Exact match */ + DPRINTF(("uaudio_match_alt_chan: examine %ldHz %dch %dbit.\n", + p->sample_rate, p->hw_channels, p->hw_precision)); + i = uaudio_match_alt_sub(nalts, alts, p, mode, p->sample_rate); + if (i >= 0) + return i; + + uaudio_get_minmax_rates(nalts, alts, p, mode, &min, &max); + DPRINTF(("uaudio_match_alt_chan: min=%lu max=%lu\n", min, max)); + if (max <= 0) + return -1; + /* Search for biggers */ + n = 2; + while ((rate = p->sample_rate * n++) <= max) { + i = uaudio_match_alt_sub(nalts, alts, p, mode, rate); + if (i >= 0) { + p->hw_sample_rate = rate; + return i; + } + } + if (p->sample_rate >= min) { + i = uaudio_match_alt_sub(nalts, alts, p, mode, max); + if (i >= 0) { + p->hw_sample_rate = max; + return i; + } + } else { + i = uaudio_match_alt_sub(nalts, alts, p, mode, min); + if (i >= 0) { + p->hw_sample_rate = min; + return i; + } + } + return -1; +} + +Static int +uaudio_match_alt(int nalts, const struct as_info *alts, + struct audio_params *p, int mode) +{ + int i, n; + + mode = mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN; + i = uaudio_match_alt_chan(nalts, alts, p, mode); + if (i >= 0) + return i; + + for (n = p->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) { + p->hw_channels = n; + i = uaudio_match_alt_chan(nalts, alts, p, mode); + if (i >= 0) + return i; + } + + if (p->channels != 2) + return -1; + p->hw_channels = 1; + return uaudio_match_alt_chan(nalts, alts, p, mode); +} + +Static int uaudio_set_params(void *addr, int setmode, int usemode, struct audio_params *play, struct audio_params *rec) { struct uaudio_softc *sc = addr; int flags = sc->sc_altflags; int factor; - int enc, i, j; + int enc, i; + int paltidx=-1, raltidx=-1; void (*swcode)(void *, u_char *buf, int cnt); struct audio_params *p; int mode; @@ -2378,156 +3322,181 @@ uaudio_set_params(void *addr, int setmod if (sc->sc_dying) return (EIO); - if (sc->sc_chan.pipe != NULL) + if (((usemode & AUMODE_PLAY) && sc->sc_playchan.pipe != NULL) || + ((usemode & AUMODE_RECORD) && sc->sc_recchan.pipe != NULL)) return (EBUSY); + if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1) + sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 0; + if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1) + sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 0; + + /* Some uaudio devices are unidirectional. Don't try to find a + matching mode for the unsupported direction. */ + setmode &= sc->sc_mode; + for (mode = AUMODE_RECORD; mode != -1; mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { if ((setmode & mode) == 0) continue; - if ((sc->sc_chan.dir & mode) == 0) - continue; - p = mode == AUMODE_PLAY ? play : rec; + p = (mode == AUMODE_PLAY) ? play : rec; factor = 1; swcode = 0; enc = p->encoding; switch (enc) { case AUDIO_ENCODING_SLINEAR_BE: - if (p->precision == 16) { + /* FALLTHROUGH */ + case AUDIO_ENCODING_SLINEAR_LE: + if (enc == AUDIO_ENCODING_SLINEAR_BE + && p->precision == 16 && (flags & HAS_16)) { swcode = swap_bytes; enc = AUDIO_ENCODING_SLINEAR_LE; - } else if (p->precision == 8 && !(flags & HAS_8)) { - swcode = change_sign8; - enc = AUDIO_ENCODING_ULINEAR_LE; - } - break; - case AUDIO_ENCODING_SLINEAR_LE: - if (p->precision == 8 && !(flags & HAS_8)) { - swcode = change_sign8; - enc = AUDIO_ENCODING_ULINEAR_LE; + } else if (p->precision == 8) { + if (flags & HAS_8) { + /* No conversion */ + } else if (flags & HAS_8U) { + swcode = change_sign8; + enc = AUDIO_ENCODING_ULINEAR_LE; + } else if (flags & HAS_16) { + factor = 2; + p->hw_precision = 16; + if (mode == AUMODE_PLAY) + swcode = linear8_to_linear16_le; + else + swcode = linear16_to_linear8_le; + } } break; case AUDIO_ENCODING_ULINEAR_BE: + /* FALLTHROUGH */ + case AUDIO_ENCODING_ULINEAR_LE: if (p->precision == 16) { - if (mode == AUMODE_PLAY) + if (enc == AUDIO_ENCODING_ULINEAR_LE) + swcode = change_sign16_le; + else if (mode == AUMODE_PLAY) swcode = swap_bytes_change_sign16_le; else swcode = change_sign16_swap_bytes_le; enc = AUDIO_ENCODING_SLINEAR_LE; - } else if (p->precision == 8 && !(flags & HAS_8U)) { - swcode = change_sign8; - enc = AUDIO_ENCODING_SLINEAR_LE; - } - break; - case AUDIO_ENCODING_ULINEAR_LE: - if (p->precision == 16) { - swcode = change_sign16_le; - enc = AUDIO_ENCODING_SLINEAR_LE; - } else if (p->precision == 8 && !(flags & HAS_8U)) { - swcode = change_sign8; - enc = AUDIO_ENCODING_SLINEAR_LE; - } - break; - case AUDIO_ENCODING_ULAW: - if (!(flags & HAS_MULAW)) { - if (mode == AUMODE_PLAY && - (flags & HAS_16)) { - swcode = mulaw_to_slinear16_le; - factor = 2; - enc = AUDIO_ENCODING_SLINEAR_LE; - } else if (flags & HAS_8U) { - if (mode == AUMODE_PLAY) - swcode = mulaw_to_ulinear8; - else - swcode = ulinear8_to_mulaw; - enc = AUDIO_ENCODING_ULINEAR_LE; + } else if (p->precision == 8) { + if (flags & HAS_8U) { + /* No conversion */ } else if (flags & HAS_8) { - if (mode == AUMODE_PLAY) - swcode = mulaw_to_slinear8; - else - swcode = slinear8_to_mulaw; + swcode = change_sign8; enc = AUDIO_ENCODING_SLINEAR_LE; - } else - return (EINVAL); - } - break; - case AUDIO_ENCODING_ALAW: - if (!(flags & HAS_ALAW)) { - if (mode == AUMODE_PLAY && - (flags & HAS_16)) { - swcode = alaw_to_slinear16_le; + } else if (flags & HAS_16) { factor = 2; + p->hw_precision = 16; enc = AUDIO_ENCODING_SLINEAR_LE; - } else if (flags & HAS_8U) { if (mode == AUMODE_PLAY) - swcode = alaw_to_ulinear8; - else - swcode = ulinear8_to_alaw; - enc = AUDIO_ENCODING_ULINEAR_LE; - } else if (flags & HAS_8) { - if (mode == AUMODE_PLAY) - swcode = alaw_to_slinear8; + swcode = ulinear8_to_slinear16_le; else - swcode = slinear8_to_alaw; - enc = AUDIO_ENCODING_SLINEAR_LE; - } else - return (EINVAL); + swcode = slinear16_to_ulinear8_le; + } } break; + case AUDIO_ENCODING_ULAW: + if (flags & HAS_MULAW) + break; + if (flags & HAS_16) { + if (mode == AUMODE_PLAY) + swcode = mulaw_to_slinear16_le; + else + swcode = slinear16_to_mulaw_le; + factor = 2; + enc = AUDIO_ENCODING_SLINEAR_LE; + p->hw_precision = 16; + } else if (flags & HAS_8U) { + if (mode == AUMODE_PLAY) + swcode = mulaw_to_ulinear8; + else + swcode = ulinear8_to_mulaw; + enc = AUDIO_ENCODING_ULINEAR_LE; + } else if (flags & HAS_8) { + if (mode == AUMODE_PLAY) + swcode = mulaw_to_slinear8; + else + swcode = slinear8_to_mulaw; + enc = AUDIO_ENCODING_SLINEAR_LE; + } else + return (EINVAL); + break; + case AUDIO_ENCODING_ALAW: + if (flags & HAS_ALAW) + break; + if (mode == AUMODE_PLAY && (flags & HAS_16)) { + swcode = alaw_to_slinear16_le; + factor = 2; + enc = AUDIO_ENCODING_SLINEAR_LE; + p->hw_precision = 16; + } else if (flags & HAS_8U) { + if (mode == AUMODE_PLAY) + swcode = alaw_to_ulinear8; + else + swcode = ulinear8_to_alaw; + enc = AUDIO_ENCODING_ULINEAR_LE; + } else if (flags & HAS_8) { + if (mode == AUMODE_PLAY) + swcode = alaw_to_slinear8; + else + swcode = slinear8_to_alaw; + enc = AUDIO_ENCODING_SLINEAR_LE; + } else + return (EINVAL); + break; default: return (EINVAL); } /* XXX do some other conversions... */ DPRINTF(("uaudio_set_params: chan=%d prec=%d enc=%d rate=%ld\n", - p->channels, p->precision, enc, p->sample_rate)); + p->channels, p->hw_precision, enc, p->sample_rate)); - for (i = 0; i < sc->sc_nalts; i++) { - struct usb_audio_streaming_type1_descriptor *a1d = - sc->sc_alts[i].asf1desc; - if (p->channels == a1d->bNrChannels && - p->precision == a1d->bBitResolution && - enc == sc->sc_alts[i].encoding && - (mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN) == - UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress)) { - if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) { - DPRINTFN(2,("uaudio_set_params: cont %d-%d\n", - UA_SAMP_LO(a1d), UA_SAMP_HI(a1d))); - if (UA_SAMP_LO(a1d) < p->sample_rate && - p->sample_rate < UA_SAMP_HI(a1d)) - goto found; - } else { - for (j = 0; j < a1d->bSamFreqType; j++) { - DPRINTFN(2,("uaudio_set_params: disc #" - "%d: %d\n", j, UA_GETSAMP(a1d, j))); - /* XXX allow for some slack */ - if (UA_GETSAMP(a1d, j) == - p->sample_rate) - goto found; - } - } - } - } - return (EINVAL); + p->hw_encoding = enc; + i = uaudio_match_alt(sc->sc_nalts, sc->sc_alts, p, mode); + if (i < 0) + return (EINVAL); - found: p->sw_code = swcode; p->factor = factor; - if (usemode == mode) - sc->sc_curaltidx = i; + + if (mode == AUMODE_PLAY) + paltidx = i; + else + raltidx = i; } - DPRINTF(("uaudio_set_params: use altidx=%d, altno=%d\n", - sc->sc_curaltidx, - sc->sc_alts[sc->sc_curaltidx].idesc->bAlternateSetting)); - + if ((setmode & AUMODE_PLAY)) { + /* XXX abort transfer if currently happening? */ + uaudio_chan_init(&sc->sc_playchan, paltidx, play, 0); + } + if ((setmode & AUMODE_RECORD)) { + /* XXX abort transfer if currently happening? */ + uaudio_chan_init(&sc->sc_recchan, raltidx, rec, + UGETW(sc->sc_alts[raltidx].edesc->wMaxPacketSize)); + } + + if ((usemode & AUMODE_PLAY) && sc->sc_playchan.altidx != -1) + sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 1; + if ((usemode & AUMODE_RECORD) && sc->sc_recchan.altidx != -1) + sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 1; + + DPRINTF(("uaudio_set_params: use altidx=p%d/r%d, altno=p%d/r%d\n", + sc->sc_playchan.altidx, sc->sc_recchan.altidx, + (sc->sc_playchan.altidx >= 0) + ?sc->sc_alts[sc->sc_playchan.altidx].idesc->bAlternateSetting + : -1, + (sc->sc_recchan.altidx >= 0) + ? sc->sc_alts[sc->sc_recchan.altidx].idesc->bAlternateSetting + : -1)); + return (0); } #endif /* NetBSD or OpenBSD */ -usbd_status +Static usbd_status uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed) { usb_device_request_t req; @@ -2543,14 +3512,14 @@ uaudio_set_speed(struct uaudio_softc *sc data[1] = speed >> 8; data[2] = speed >> 16; - return (usbd_do_request(sc->sc_udev, &req, &data)); + return (usbd_do_request(sc->sc_udev, &req, data)); } #if defined(__FreeBSD__) /************************************************************/ -void -uaudio_init_params(struct uaudio_softc *sc, struct chan *ch) +int +uaudio_init_params(struct uaudio_softc *sc, struct chan *ch, int mode) { int i, j, enc; int samples_per_frame, sample_size; @@ -2601,12 +3570,13 @@ uaudio_init_params(struct uaudio_softc * } /* for (mode = ...... */ +/*But this function is used for output only */ for (i = 0; i < sc->sc_nalts; i++) { - struct usb_audio_streaming_type1_descriptor *a1d = + const struct usb_audio_streaming_type1_descriptor *a1d = sc->sc_alts[i].asf1desc; if (ch->channels == a1d->bNrChannels && ch->precision == a1d->bBitResolution && -#if 1 +#if 0 enc == sc->sc_alts[i].encoding) { #else enc == sc->sc_alts[i].encoding && @@ -2618,7 +3588,10 @@ uaudio_init_params(struct uaudio_softc * UA_SAMP_LO(a1d), UA_SAMP_HI(a1d))); if (UA_SAMP_LO(a1d) < ch->sample_rate && ch->sample_rate < UA_SAMP_HI(a1d)) { - sc->sc_curaltidx = i; + if (mode == AUMODE_PLAY) + sc->sc_playchan.altidx = i; + else + sc->sc_recchan.altidx = i; goto found; } } else { @@ -2628,7 +3601,10 @@ uaudio_init_params(struct uaudio_softc * /* XXX allow for some slack */ if (UA_GETSAMP(a1d, j) == ch->sample_rate) { - sc->sc_curaltidx = i; + if (mode == AUMODE_PLAY) + sc->sc_playchan.altidx = i; + else + sc->sc_recchan.altidx = i; goto found; } } @@ -2636,6 +3612,8 @@ uaudio_init_params(struct uaudio_softc * } } /* return (EINVAL); */ + printf("uaudio: This device can't play in rate=%d.\n", ch->sample_rate); + return (-1); found: #if 0 /* XXX */ @@ -2656,6 +3634,7 @@ uaudio_init_params(struct uaudio_softc * ch->cur = ch->start; ch->transferred = 0; ch->curchanbuf = 0; + return (0); } void @@ -2666,7 +3645,7 @@ uaudio_query_formats(device_t dev, u_int u_int32_t fmt; struct uaudio_softc *sc; - struct usb_audio_streaming_type1_descriptor *a1d; + const struct usb_audio_streaming_type1_descriptor *a1d; sc = device_get_softc(dev); @@ -2739,13 +3718,20 @@ uaudio_query_formats(device_t dev, u_int void uaudio_chan_set_param_pcm_dma_buff(device_t dev, u_char *start, u_char *end, - struct pcm_channel *pc) + struct pcm_channel *pc, int dir) { struct uaudio_softc *sc; struct chan *ch; sc = device_get_softc(dev); - ch = &sc->sc_chan; +#ifndef NO_RECORDING + if (dir == PCMDIR_PLAY) + ch = &sc->sc_playchan; + else + ch = &sc->sc_recchan; +#else + ch = &sc->sc_playchan; +#endif ch->start = start; ch->end = end; @@ -2756,13 +3742,20 @@ uaudio_chan_set_param_pcm_dma_buff(devic } void -uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize) +uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir) { struct uaudio_softc *sc; struct chan *ch; sc = device_get_softc(dev); - ch = &sc->sc_chan; +#ifndef NO_RECORDING + if (dir == PCMDIR_PLAY) + ch = &sc->sc_playchan; + else + ch = &sc->sc_recchan; +#else + ch = &sc->sc_playchan; +#endif ch->blksize = blocksize; @@ -2770,13 +3763,20 @@ uaudio_chan_set_param_blocksize(device_t } void -uaudio_chan_set_param_speed(device_t dev, u_int32_t speed) +uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir) { struct uaudio_softc *sc; struct chan *ch; sc = device_get_softc(dev); - ch = &sc->sc_chan; +#ifndef NO_RECORDING + if (dir == PCMDIR_PLAY) + ch = &sc->sc_playchan; + else + ch = &sc->sc_recchan; +#else + ch = &sc->sc_playchan; +#endif ch->sample_rate = speed; @@ -2784,14 +3784,21 @@ uaudio_chan_set_param_speed(device_t dev } int -uaudio_chan_getptr(device_t dev) +uaudio_chan_getptr(device_t dev, int dir) { struct uaudio_softc *sc; struct chan *ch; int ptr; sc = device_get_softc(dev); - ch = &sc->sc_chan; +#ifndef NO_RECORDING + if (dir == PCMDIR_PLAY) + ch = &sc->sc_playchan; + else + ch = &sc->sc_recchan; +#else + ch = &sc->sc_playchan; +#endif ptr = ch->cur - ch->start; @@ -2799,13 +3806,20 @@ uaudio_chan_getptr(device_t dev) } void -uaudio_chan_set_param_format(device_t dev, u_int32_t format) +uaudio_chan_set_param_format(device_t dev, u_int32_t format, int dir) { struct uaudio_softc *sc; struct chan *ch; sc = device_get_softc(dev); - ch = &sc->sc_chan; +#ifndef NO_RECORDING + if (dir == PCMDIR_PLAY) + ch = &sc->sc_playchan; + else + ch = &sc->sc_recchan; +#else + ch = &sc->sc_playchan; +#endif ch->format = format; @@ -2820,14 +3834,14 @@ uaudio_halt_out_dma(device_t dev) sc = device_get_softc(dev); DPRINTF(("uaudio_halt_out_dma: enter\n")); - if (sc->sc_chan.pipe != NULL) { - uaudio_chan_close(sc, &sc->sc_chan); - sc->sc_chan.pipe = 0; - uaudio_chan_free_buffers(sc, &sc->sc_chan); + if (sc->sc_playchan.pipe != NULL) { + uaudio_chan_close(sc, &sc->sc_playchan); + sc->sc_playchan.pipe = 0; + uaudio_chan_free_buffers(sc, &sc->sc_playchan); } return (0); } - + int uaudio_trigger_output(device_t dev) { @@ -2837,12 +3851,13 @@ uaudio_trigger_output(device_t dev) int i, s; sc = device_get_softc(dev); - ch = &sc->sc_chan; + ch = &sc->sc_playchan; if (sc->sc_dying) return (EIO); - uaudio_init_params(sc, ch); + if (uaudio_init_params(sc, ch, AUMODE_PLAY)) + return (EIO); err = uaudio_chan_alloc_buffers(sc, ch); if (err) --- src/sys/dev/sound/usb/uaudio.h Mon Dec 20 01:48:43 2004 +++ src/sys/dev/sound/usb/uaudio-91.h Mon Dec 20 01:56:58 2004 @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/dev/sound/usb/uaudio.h,v 1.1 2002/07/21 17:28:50 nsayer Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudio-91.h,v $ */ /* * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org> @@ -30,7 +30,7 @@ /* Defined in uaudio.c, used in uaudio_pcm,c */ void uaudio_chan_set_param_pcm_dma_buff(device_t dev, u_char *start, - u_char *end, struct pcm_channel *pc); + u_char *end, struct pcm_channel *pc, int dir); int uaudio_trigger_output(device_t dev); int uaudio_halt_out_dma(device_t dev); #ifndef NO_RECORDING @@ -38,12 +38,11 @@ int uaudio_trigger_input(device_t dev); int uaudio_halt_in_dma(device_t dev); #endif void uaudio_chan_set_param(device_t, u_char *, u_char *); -void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize); -void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed); -void uaudio_chan_set_param_format(device_t dev, u_int32_t format); -int uaudio_chan_getptr(device_t dev); +void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir); +void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir); +void uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir); +int uaudio_chan_getptr(device_t dev, int); void uaudio_mixer_set(device_t dev, unsigned type, unsigned left, unsigned right); u_int32_t uaudio_query_mix_info(device_t dev); void uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt); - --- src/sys/dev/sound/usb/uaudioreg.h Mon Dec 20 01:48:43 2004 +++ src/sys/dev/sound/usb/uaudioreg-91.h Mon Dec 20 01:57:15 2004 @@ -1,5 +1,5 @@ -/* $NetBSD: uaudioreg.h,v 1.7 2000/12/28 00:29:58 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/sound/usb/uaudioreg.h,v 1.2 2002/11/06 21:37:21 joe Exp $ */ +/* $NetBSD: uaudioreg.h,v 1.12 2004/11/05 19:08:29 kent Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudioreg-91.h,v $ */ /* * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -40,7 +40,6 @@ #define UAUDIO_VERSION 0x100 -#define UDESC_CS_DEVICE 0x21 #define UDESC_CS_CONFIG 0x22 #define UDESC_CS_STRING 0x23 #define UDESC_CS_INTERFACE 0x24 @@ -63,7 +62,7 @@ typedef struct { uByte bmAttributes; uWord wMaxPacketSize; uByte bInterval; - /* + /* * The following two entries are only used by the Audio Class. * And according to the specs the Audio Class is the only one * allowed to extend the endpoint descriptor. @@ -98,6 +97,9 @@ struct usb_audio_streaming_endpoint_desc uByte bDescriptorType; uByte bDescriptorSubtype; uByte bmAttributes; +#define UA_SED_FREQ_CONTROL 0x01 +#define UA_SED_PITCH_CONTROL 0x02 +#define UA_SED_MAXPACKETSONLY 0x80 uByte bLockDelayUnits; uWord wLockDelay; } UPACKED; @@ -121,9 +123,29 @@ struct usb_audio_streaming_type1_descrip struct usb_audio_cluster { uByte bNrChannels; uWord wChannelConfig; +#define UA_CHANNEL_LEFT 0x0001 +#define UA_CHANNEL_RIGHT 0x0002 +#define UA_CHANNEL_CENTER 0x0004 +#define UA_CHANNEL_LFE 0x0008 +#define UA_CHANNEL_L_SURROUND 0x0010 +#define UA_CHANNEL_R_SURROUND 0x0020 +#define UA_CHANNEL_L_CENTER 0x0040 +#define UA_CHANNEL_R_CENTER 0x0080 +#define UA_CHANNEL_SURROUND 0x0100 +#define UA_CHANNEL_L_SIDE 0x0200 +#define UA_CHANNEL_R_SIDE 0x0400 +#define UA_CHANNEL_TOP 0x0800 uByte iChannelNames; } UPACKED; +/* Shared by all units and terminals */ +struct usb_audio_unit { + uByte bLength; + uByte bDescriptorType; + uByte bDescriptorSubtype; + uByte bUnitId; +}; + /* UDESCSUB_AC_INPUT */ struct usb_audio_input_terminal { uByte bLength; @@ -340,8 +362,11 @@ struct usb_audio_extension_unit_1 { #define UA_FMT_IEEE_FLOAT 3 #define UA_FMT_ALAW 4 #define UA_FMT_MULAW 5 +#define UA_FMT_MPEG 0x1001 +#define UA_FMT_AC3 0x1002 -#define SAMPLING_FREQ_CONTROL 0x01 +#define SAMPLING_FREQ_CONTROL 0x01 +#define PITCH_CONTROL 0x02 #define FORMAT_TYPE_UNDEFINED 0 #define FORMAT_TYPE_I 1 @@ -377,4 +402,3 @@ struct usb_audio_extension_unit_1 { #define DR_THRESHOLD_CONTROL 4 #define DR_ATTACK_TIME_CONTROL 5 #define DR_RELEASE_TIME_CONTROL 6 - --- src/sys/dev/sound/usb/uaudio_pcm.c Mon Dec 20 01:48:43 2004 +++ src/sys/dev/sound/usb/uaudio_pcm-91.c Mon Dec 20 01:57:07 2004 @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/dev/sound/usb/uaudio_pcm.c,v 1.5 2004/07/16 03:58:57 tanimura Exp $ */ +/* $FreeBSD: src/sys/dev/sound/usb/uaudio_pcm-91.c,v $ */ /* * Copyright (c) 2000-2002 Hiroyuki Aizu <aizu@navi.org> @@ -89,7 +89,7 @@ ua_chan_init(kobj_t obj, void *devinfo, buf = end = sndbuf_getbuf(b); end += sndbuf_getsize(b); - uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel); + uaudio_chan_set_param_pcm_dma_buff(pa_dev, buf, end, ch->channel, dir); ch->dir = dir; #ifndef NO_RECORDING @@ -113,7 +113,7 @@ ua_chan_setformat(kobj_t obj, void *data ua = ch->parent; pa_dev = device_get_parent(ua->sc_dev); - uaudio_chan_set_param_format(pa_dev, format); + uaudio_chan_set_param_format(pa_dev, format, ch->dir); ch->fmt = format; return 0; @@ -130,7 +130,7 @@ ua_chan_setspeed(kobj_t obj, void *data, ua = ch->parent; pa_dev = device_get_parent(ua->sc_dev); - uaudio_chan_set_param_speed(pa_dev, speed); + uaudio_chan_set_param_speed(pa_dev, speed, ch->dir); return ch->spd; } @@ -151,7 +151,7 @@ ua_chan_setblocksize(kobj_t obj, void *d /* XXXXX */ ua = ch->parent; pa_dev = device_get_parent(ua->sc_dev); - uaudio_chan_set_param_blocksize(pa_dev, blocksize); + uaudio_chan_set_param_blocksize(pa_dev, blocksize, ch->dir); return ch->blksz; } @@ -198,7 +198,7 @@ ua_chan_getptr(kobj_t obj, void *data) ua = ch->parent; pa_dev = device_get_parent(ua->sc_dev); - return uaudio_chan_getptr(pa_dev); + return uaudio_chan_getptr(pa_dev, ch->dir); } static struct pcmchan_caps * --- F_41-91.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20041220.034157.846933450.kazuhito>