diff options
Diffstat (limited to 'sound/usb')
44 files changed, 5688 insertions, 4757 deletions
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index c570ae3e6d5..44d6d2ec964 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -22,8 +22,7 @@ config SND_USB_AUDIO  	  will be called snd-usb-audio.  config SND_USB_UA101 -	tristate "Edirol UA-101/UA-1000 driver (EXPERIMENTAL)" -	depends on EXPERIMENTAL +	tristate "Edirol UA-101/UA-1000 driver"  	select SND_PCM  	select SND_RAWMIDI  	help @@ -65,6 +64,7 @@ config SND_USB_CAIAQ  	    * Native Instruments Audio 8 DJ  	    * Native Instruments Guitar Rig Session I/O  	    * Native Instruments Guitar Rig mobile +	    * Native Instruments Traktor Kontrol X1  	   To compile this driver as a module, choose M here: the module  	   will be called snd-usb-caiaq. diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 5bf64aef955..e7ac7f493a8 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -2,14 +2,24 @@  # Makefile for ALSA  # -snd-usb-audio-objs := usbaudio.o usbmixer.o -snd-usb-lib-objs := usbmidi.o -snd-ua101-objs := ua101.o +snd-usb-audio-objs := 	card.o \ +			mixer.o \ +			mixer_quirks.o \ +			proc.o \ +			quirks.o \ +			format.o \ +			endpoint.o \ +			urb.o \ +			pcm.o \ +			helper.o + +snd-usbmidi-lib-objs := midi.o  # Toplevel Module Dependency -obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o -obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o -obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o -obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o +obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usbmidi-lib.o + +obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o +obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o +obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o -obj-$(CONFIG_SND) += usx2y/ caiaq/ +obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 86b2c3b92df..4328cad6c3a 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -17,6 +17,7 @@  */  #include <linux/spinlock.h> +#include <linux/slab.h>  #include <linux/init.h>  #include <linux/usb.h>  #include <sound/core.h> diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 537102ba6b9..36ed703a741 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol,  	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);  	int pos = kcontrol->private_value;  	int is_intval = pos & CNT_INTVAL; -	unsigned int id = dev->chip.usb_id; +	int maxval = 63;  	uinfo->count = 1;  	pos &= ~CNT_INTVAL; -	if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) -		&& (pos == 0)) { -		/* current input mode of A8DJ */ -		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -		uinfo->value.integer.min = 0; -		uinfo->value.integer.max = 2; -		return 0; -	} +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): +		if (pos == 0) { +			/* current input mode of A8DJ */ +			uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +			uinfo->value.integer.min = 0; +			uinfo->value.integer.max = 2; +			return 0; +		} +		break; -	if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ) -		&& (pos == 0)) { -		/* current input mode of A4DJ */ -		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -		uinfo->value.integer.min = 0; -		uinfo->value.integer.max = 1; -		return 0; +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): +		if (pos == 0) { +			/* current input mode of A4DJ */ +			uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +			uinfo->value.integer.min = 0; +			uinfo->value.integer.max = 1; +			return 0; +		} +		break; + +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		maxval = 127; +		break;  	}  	if (is_intval) {  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;  		uinfo->value.integer.min = 0; -		uinfo->value.integer.max = 64; +		uinfo->value.integer.max = maxval;  	} else {  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;  		uinfo->value.integer.min = 0; @@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol,  	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);  	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);  	int pos = kcontrol->private_value; +	unsigned char cmd = EP1_CMD_WRITE_IO; -	if (dev->chip.usb_id == -		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {  		/* A4DJ has only one control */  		/* do not expose hardware input mode 0 */  		dev->control_state[0] = ucontrol->value.integer.value[0] + 1; @@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol,  		return 1;  	} +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		cmd = EP1_CMD_DIMM_LEDS; +		break; +	} +  	if (pos & CNT_INTVAL) {  		dev->control_state[pos & ~CNT_INTVAL]  			= ucontrol->value.integer.value[0]; -		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, +		snd_usb_caiaq_send_command(dev, cmd,  				dev->control_state, sizeof(dev->control_state));  	} else {  		if (ucontrol->value.integer.value[0]) @@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol,  		else  			dev->control_state[pos / 8] &= ~(1 << (pos % 8)); -		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, +		snd_usb_caiaq_send_command(dev, cmd,  				dev->control_state, sizeof(dev->control_state));  	} @@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = {  	{ "Current input mode",	0 | CNT_INTVAL 	}  }; +static struct caiaq_controller kontrolx1_controller[] = { +	{ "LED FX A: ON",		7 | CNT_INTVAL	}, +	{ "LED FX A: 1",		6 | CNT_INTVAL	}, +	{ "LED FX A: 2",		5 | CNT_INTVAL	}, +	{ "LED FX A: 3",		4 | CNT_INTVAL	}, +	{ "LED FX B: ON",		3 | CNT_INTVAL	}, +	{ "LED FX B: 1",		2 | CNT_INTVAL	}, +	{ "LED FX B: 2",		1 | CNT_INTVAL	}, +	{ "LED FX B: 3",		0 | CNT_INTVAL	}, + +	{ "LED Hotcue",			28 | CNT_INTVAL	}, +	{ "LED Shift (white)",		29 | CNT_INTVAL	}, +	{ "LED Shift (green)",		30 | CNT_INTVAL	}, + +	{ "LED Deck A: FX1",		24 | CNT_INTVAL	}, +	{ "LED Deck A: FX2",		25 | CNT_INTVAL	}, +	{ "LED Deck A: IN",		17 | CNT_INTVAL	}, +	{ "LED Deck A: OUT",		16 | CNT_INTVAL	}, +	{ "LED Deck A: < BEAT",		19 | CNT_INTVAL	}, +	{ "LED Deck A: BEAT >",		18 | CNT_INTVAL	}, +	{ "LED Deck A: CUE/ABS",	21 | CNT_INTVAL	}, +	{ "LED Deck A: CUP/REL",	20 | CNT_INTVAL	}, +	{ "LED Deck A: PLAY",		23 | CNT_INTVAL	}, +	{ "LED Deck A: SYNC",		22 | CNT_INTVAL	}, + +	{ "LED Deck B: FX1",		26 | CNT_INTVAL	}, +	{ "LED Deck B: FX2",		27 | CNT_INTVAL	}, +	{ "LED Deck B: IN",		15 | CNT_INTVAL	}, +	{ "LED Deck B: OUT",		14 | CNT_INTVAL	}, +	{ "LED Deck B: < BEAT",		13 | CNT_INTVAL	}, +	{ "LED Deck B: BEAT >",		12 | CNT_INTVAL	}, +	{ "LED Deck B: CUE/ABS",	11 | CNT_INTVAL	}, +	{ "LED Deck B: CUP/REL",	10 | CNT_INTVAL	}, +	{ "LED Deck B: PLAY",		9  | CNT_INTVAL	}, +	{ "LED Deck B: SYNC",		8  | CNT_INTVAL	}, +}; +  static int __devinit add_controls(struct caiaq_controller *c, int num,  				  struct snd_usb_caiaqdev *dev)  { @@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)  		ret = add_controls(a8dj_controller,  			ARRAY_SIZE(a8dj_controller), dev);  		break; +  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):  		ret = add_controls(a4dj_controller,  			ARRAY_SIZE(a4dj_controller), dev);  		break; + +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		ret = add_controls(kontrolx1_controller, +			ARRAY_SIZE(kontrolx1_controller), dev); +		break;  	}  	return ret; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index a3f02dd9744..80527182767 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -23,6 +23,7 @@  #include <linux/interrupt.h>  #include <linux/module.h>  #include <linux/init.h> +#include <linux/gfp.h>  #include <linux/usb.h>  #include <sound/initval.h>  #include <sound/core.h> @@ -46,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"  			 "{Native Instruments, Audio 4 DJ},"  			 "{Native Instruments, Audio 8 DJ},"  			 "{Native Instruments, Session I/O}," -			 "{Native Instruments, GuitarRig mobile}"); +			 "{Native Instruments, GuitarRig mobile}" +			 "{Native Instruments, Traktor Kontrol X1}");  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */  static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -127,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = {  		.idVendor =     USB_VID_NATIVEINSTRUMENTS,  		.idProduct =    USB_PID_AUDIO2DJ  	}, +	{ +		.match_flags =  USB_DEVICE_ID_MATCH_DEVICE, +		.idVendor =     USB_VID_NATIVEINSTRUMENTS, +		.idProduct =    USB_PID_TRAKTORKONTROLX1 +	},  	{ /* terminator */ }  }; diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index 44e3edf88be..f1117ecc84f 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -5,18 +5,20 @@  #define USB_VID_NATIVEINSTRUMENTS 0x17cc -#define USB_PID_RIGKONTROL2	0x1969 -#define USB_PID_RIGKONTROL3	0x1940 -#define USB_PID_KORECONTROLLER	0x4711 -#define USB_PID_KORECONTROLLER2	0x4712 -#define USB_PID_AK1		0x0815 -#define USB_PID_AUDIO2DJ	0x041c -#define USB_PID_AUDIO4DJ	0x0839 -#define USB_PID_AUDIO8DJ	0x1978 -#define USB_PID_SESSIONIO	0x1915 -#define USB_PID_GUITARRIGMOBILE	0x0d8d +#define USB_PID_RIGKONTROL2		0x1969 +#define USB_PID_RIGKONTROL3		0x1940 +#define USB_PID_KORECONTROLLER		0x4711 +#define USB_PID_KORECONTROLLER2		0x4712 +#define USB_PID_AK1			0x0815 +#define USB_PID_AUDIO2DJ		0x041c +#define USB_PID_AUDIO4DJ		0x0839 +#define USB_PID_AUDIO8DJ		0x1978 +#define USB_PID_SESSIONIO		0x1915 +#define USB_PID_GUITARRIGMOBILE		0x0d8d +#define USB_PID_TRAKTORKONTROLX1	0x2305  #define EP1_BUFSIZE 64 +#define EP4_BUFSIZE 512  #define CAIAQ_USB_STR_LEN 0xff  #define MAX_STREAMS 32 @@ -104,6 +106,8 @@ struct snd_usb_caiaqdev {  	struct input_dev *input_dev;  	char phys[64];			/* physical device path */  	unsigned short keycode[64]; +	struct urb *ep4_in_urb; +	unsigned char ep4_in_buf[EP4_BUFSIZE];  #endif  	/* ALSA */ diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index a48d309bd94..8bbfbfd4c65 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -16,9 +16,11 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  */ +#include <linux/gfp.h>  #include <linux/init.h>  #include <linux/usb.h>  #include <linux/usb/input.h> +#include <sound/core.h>  #include <sound/pcm.h>  #include "device.h" @@ -65,6 +67,8 @@ static unsigned short keycode_kore[] = {  	KEY_BRL_DOT5  }; +#define KONTROLX1_INPUTS 40 +  #define DEG90		(range / 2)  #define DEG180		(range)  #define DEG270		(DEG90 + DEG180) @@ -162,6 +166,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,  		input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);  		input_sync(input_dev);  		break; +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8)  | buf[9]); +		input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8)  | buf[5]); +		input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); +		input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8)  | buf[3]); +		input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]); +		input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8)  | buf[1]); +		input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); +		input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8)  | buf[7]); +		input_sync(input_dev); +		break;  	}  } @@ -201,7 +216,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,  }  static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, -				    char *buf, unsigned int len) +				    unsigned char *buf, unsigned int len)  {  	struct input_dev *input_dev = dev->input_dev;  	unsigned short *keycode = input_dev->keycode; @@ -218,15 +233,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,  		input_report_key(input_dev, keycode[i],  				 buf[i / 8] & (1 << (i % 8))); -	if (dev->chip.usb_id == -		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || -	    dev->chip.usb_id == -		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2)) +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):  		input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); +		break; +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		/* rotary encoders */ +		input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf); +		input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4); +		input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf); +		input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4); +		break; +	}  	input_sync(input_dev);  } +static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) +{ +	struct snd_usb_caiaqdev *dev = urb->context; +	unsigned char *buf = urb->transfer_buffer; +	int ret; + +	if (urb->status || !dev || urb != dev->ep4_in_urb) +		return; + +	if (urb->actual_length < 24) +		goto requeue; + +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		if (buf[0] & 0x3) +			snd_caiaq_input_read_io(dev, buf + 1, 7); + +		if (buf[0] & 0x4) +			snd_caiaq_input_read_analog(dev, buf + 8, 16); + +		break; +	} + +requeue: +	dev->ep4_in_urb->actual_length = 0; +	ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC); +	if (ret < 0) +		log("unable to submit urb. OOM!?\n"); +} + +static int snd_usb_caiaq_input_open(struct input_dev *idev) +{ +	struct snd_usb_caiaqdev *dev = input_get_drvdata(idev); + +	if (!dev) +		return -EINVAL; + +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) +			return -EIO; +		break; +	} + +	return 0; +} + +static void snd_usb_caiaq_input_close(struct input_dev *idev) +{ +	struct snd_usb_caiaqdev *dev = input_get_drvdata(idev); + +	if (!dev) +		return; + +	switch (dev->chip.usb_id) { +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		usb_kill_urb(dev->ep4_in_urb); +		break; +	} +} +  void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,  				  char *buf,  				  unsigned int len) @@ -251,7 +335,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  {  	struct usb_device *usb_dev = dev->chip.dev;  	struct input_dev *input; -	int i, ret; +	int i, ret = 0;  	input = input_allocate_device();  	if (!input) @@ -265,7 +349,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  	usb_to_input_id(usb_dev, &input->id);  	input->dev.parent = &usb_dev->dev; -        switch (dev->chip.usb_id) { +	input_set_drvdata(input, dev); + +	switch (dev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):  		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  		input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | @@ -326,25 +412,72 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  		input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);  		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);  		break; +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): +		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +		input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | +				   BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | +				   BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | +				   BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | +				   BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | +				   BIT_MASK(ABS_Z); +		input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); +		BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS); +		for (i = 0; i < KONTROLX1_INPUTS; i++) +			dev->keycode[i] = BTN_MISC + i; +		input->keycodemax = KONTROLX1_INPUTS; + +		/* analog potentiometers */ +		input_set_abs_params(input, ABS_HAT0X, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT0Y, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT1X, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT1Y, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT2X, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT2Y, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT3X, 0, 4096, 0, 10); +		input_set_abs_params(input, ABS_HAT3Y, 0, 4096, 0, 10); + +		/* rotary encoders */ +		input_set_abs_params(input, ABS_X, 0, 0xf, 0, 1); +		input_set_abs_params(input, ABS_Y, 0, 0xf, 0, 1); +		input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1); +		input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1); + +		dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!dev->ep4_in_urb) { +			ret = -ENOMEM; +			goto exit_free_idev; +		} + +		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, +				  usb_rcvbulkpipe(usb_dev, 0x4), +				  dev->ep4_in_buf, EP4_BUFSIZE, +				  snd_usb_caiaq_ep4_reply_dispatch, dev); + +		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); + +		break;  	default:  		/* no input methods supported on this device */ -		input_free_device(input); -		return 0; +		goto exit_free_idev;  	} +	input->open = snd_usb_caiaq_input_open; +	input->close = snd_usb_caiaq_input_close;  	input->keycode = dev->keycode;  	input->keycodesize = sizeof(unsigned short);  	for (i = 0; i < input->keycodemax; i++)  		__set_bit(dev->keycode[i], input->keybit);  	ret = input_register_device(input); -	if (ret < 0) { -		input_free_device(input); -		return ret; -	} +	if (ret < 0) +		goto exit_free_idev;  	dev->input_dev = input;  	return 0; + +exit_free_idev: +	input_free_device(input); +	return ret;  }  void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) @@ -352,6 +485,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)  	if (!dev || !dev->input_dev)  		return; +	usb_kill_urb(dev->ep4_in_urb); +	usb_free_urb(dev->ep4_in_urb); +	dev->ep4_in_urb = NULL; +  	input_unregister_device(dev->input_dev);  	dev->input_dev = NULL;  } diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c index 538e8c00d31..2f218c77fff 100644 --- a/sound/usb/caiaq/midi.c +++ b/sound/usb/caiaq/midi.c @@ -17,6 +17,7 @@  */  #include <linux/usb.h> +#include <linux/gfp.h>  #include <sound/rawmidi.h>  #include <sound/core.h>  #include <sound/pcm.h> diff --git a/sound/usb/card.c b/sound/usb/card.c new file mode 100644 index 00000000000..da1346bd485 --- /dev/null +++ b/sound/usb/card.c @@ -0,0 +1,652 @@ +/* + *   (Tentative) USB Audio Driver for ALSA + * + *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + *   Many codes borrowed from audio.c by + *	    Alan Cox (alan@lxorguk.ukuu.org.uk) + *	    Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + * + *  NOTES: + * + *   - async unlink should be used for avoiding the sleep inside lock. + *     2.4.22 usb-uhci seems buggy for async unlinking and results in + *     oops.  in such a cse, pass async_unlink=0 option. + *   - the linked URBs would be preferred but not used so far because of + *     the instability of unlinking. + *   - type II is not supported properly.  there is no device which supports + *     this type *correctly*.  SB extigy looks as if it supports, but it's + *     indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). + */ + + +#include <linux/bitops.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/usb.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> + +#include "usbaudio.h" +#include "card.h" +#include "midi.h" +#include "mixer.h" +#include "proc.h" +#include "quirks.h" +#include "endpoint.h" +#include "helper.h" +#include "debug.h" +#include "pcm.h" +#include "urb.h" +#include "format.h" + +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); +MODULE_DESCRIPTION("USB Audio"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}"); + + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ +/* Vendor/product IDs for this card */ +static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; +static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; +static int nrpacks = 8;		/* max. number of packets per urb */ +static int async_unlink = 1; +static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ +static int ignore_ctl_error; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for the USB audio adapter."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable USB audio adapter."); +module_param_array(vid, int, NULL, 0444); +MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device."); +module_param_array(pid, int, NULL, 0444); +MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); +module_param(nrpacks, int, 0644); +MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); +module_param(async_unlink, bool, 0444); +MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); +module_param_array(device_setup, int, NULL, 0444); +MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); +module_param(ignore_ctl_error, bool, 0444); +MODULE_PARM_DESC(ignore_ctl_error, +		 "Ignore errors from USB controller for mixer interfaces."); + +/* + * we keep the snd_usb_audio_t instances by ourselves for merging + * the all interfaces on the same card as one sound device. + */ + +static DEFINE_MUTEX(register_mutex); +static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; +static struct usb_driver usb_audio_driver; + +/* + * disconnect streams + * called from snd_usb_audio_disconnect() + */ +static void snd_usb_stream_disconnect(struct list_head *head) +{ +	int idx; +	struct snd_usb_stream *as; +	struct snd_usb_substream *subs; + +	as = list_entry(head, struct snd_usb_stream, list); +	for (idx = 0; idx < 2; idx++) { +		subs = &as->substream[idx]; +		if (!subs->num_formats) +			return; +		snd_usb_release_substream_urbs(subs, 1); +		subs->interface = -1; +	} +} + +static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface) +{ +	struct usb_device *dev = chip->dev; +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	struct usb_interface *iface = usb_ifnum_to_if(dev, interface); + +	if (!iface) { +		snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", +			   dev->devnum, ctrlif, interface); +		return -EINVAL; +	} + +	if (usb_interface_claimed(iface)) { +		snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", +						dev->devnum, ctrlif, interface); +		return -EINVAL; +	} + +	alts = &iface->altsetting[0]; +	altsd = get_iface_desc(alts); +	if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || +	     altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && +	    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { +		int err = snd_usbmidi_create(chip->card, iface, +					     &chip->midi_list, NULL); +		if (err < 0) { +			snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", +						dev->devnum, ctrlif, interface); +			return -EINVAL; +		} +		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); + +		return 0; +	} + +	if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && +	     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || +	    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) { +		snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", +					dev->devnum, ctrlif, interface, altsd->bInterfaceClass); +		/* skip non-supported classes */ +		return -EINVAL; +	} + +	if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { +		snd_printk(KERN_ERR "low speed audio streaming not supported\n"); +		return -EINVAL; +	} + +	if (! snd_usb_parse_audio_endpoints(chip, interface)) { +		usb_set_interface(dev, interface, 0); /* reset the current interface */ +		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); +		return -EINVAL; +	} + +	return 0; +} + +/* + * parse audio control descriptor and create pcm/midi streams + */ +static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) +{ +	struct usb_device *dev = chip->dev; +	struct usb_host_interface *host_iface; +	struct usb_interface_descriptor *altsd; +	void *control_header; +	int i, protocol; + +	/* find audiocontrol interface */ +	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; +	control_header = snd_usb_find_csint_desc(host_iface->extra, +						 host_iface->extralen, +						 NULL, UAC_HEADER); +	altsd = get_iface_desc(host_iface); +	protocol = altsd->bInterfaceProtocol; + +	if (!control_header) { +		snd_printk(KERN_ERR "cannot find UAC_HEADER\n"); +		return -EINVAL; +	} + +	switch (protocol) { +	case UAC_VERSION_1: { +		struct uac_ac_header_descriptor_v1 *h1 = control_header; + +		if (!h1->bInCollection) { +			snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); +			return -EINVAL; +		} + +		if (h1->bLength < sizeof(*h1) + h1->bInCollection) { +			snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n"); +			return -EINVAL; +		} + +		for (i = 0; i < h1->bInCollection; i++) +			snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]); + +		break; +	} + +	case UAC_VERSION_2: { +		struct uac_clock_source_descriptor *cs; +		struct usb_interface_assoc_descriptor *assoc = +			usb_ifnum_to_if(dev, ctrlif)->intf_assoc; + +		if (!assoc) { +			snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); +			return -EINVAL; +		} + +		/* FIXME: for now, we expect there is at least one clock source +		 * descriptor and we always take the first one. +		 * We should properly support devices with multiple clock sources, +		 * clock selectors and sample rate conversion units. */ + +		cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, +						NULL, UAC2_CLOCK_SOURCE); + +		if (!cs) { +			snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); +			return -EINVAL; +		} + +		chip->clock_id = cs->bClockID; + +		for (i = 0; i < assoc->bInterfaceCount; i++) { +			int intf = assoc->bFirstInterface + i; + +			if (intf != ctrlif) +				snd_usb_create_stream(chip, ctrlif, intf); +		} + +		break; +	} + +	default: +		snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); +		return -EINVAL; +	} + +	return 0; +} + +/* + * free the chip instance + * + * here we have to do not much, since pcm and controls are already freed + * + */ + +static int snd_usb_audio_free(struct snd_usb_audio *chip) +{ +	kfree(chip); +	return 0; +} + +static int snd_usb_audio_dev_free(struct snd_device *device) +{ +	struct snd_usb_audio *chip = device->device_data; +	return snd_usb_audio_free(chip); +} + + +/* + * create a chip instance and set its names. + */ +static int snd_usb_audio_create(struct usb_device *dev, int idx, +				const struct snd_usb_audio_quirk *quirk, +				struct snd_usb_audio **rchip) +{ +	struct snd_card *card; +	struct snd_usb_audio *chip; +	int err, len; +	char component[14]; +	static struct snd_device_ops ops = { +		.dev_free =	snd_usb_audio_dev_free, +	}; + +	*rchip = NULL; + +	if (snd_usb_get_speed(dev) != USB_SPEED_LOW && +	    snd_usb_get_speed(dev) != USB_SPEED_FULL && +	    snd_usb_get_speed(dev) != USB_SPEED_HIGH) { +		snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); +		return -ENXIO; +	} + +	err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card); +	if (err < 0) { +		snd_printk(KERN_ERR "cannot create card instance %d\n", idx); +		return err; +	} + +	chip = kzalloc(sizeof(*chip), GFP_KERNEL); +	if (! chip) { +		snd_card_free(card); +		return -ENOMEM; +	} + +	chip->index = idx; +	chip->dev = dev; +	chip->card = card; +	chip->setup = device_setup[idx]; +	chip->nrpacks = nrpacks; +	chip->async_unlink = async_unlink; + +	chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), +			      le16_to_cpu(dev->descriptor.idProduct)); +	INIT_LIST_HEAD(&chip->pcm_list); +	INIT_LIST_HEAD(&chip->midi_list); +	INIT_LIST_HEAD(&chip->mixer_list); + +	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { +		snd_usb_audio_free(chip); +		snd_card_free(card); +		return err; +	} + +	strcpy(card->driver, "USB-Audio"); +	sprintf(component, "USB%04x:%04x", +		USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); +	snd_component_add(card, component); + +	/* retrieve the device string as shortname */ +	if (quirk && quirk->product_name) { +		strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); +	} else { +		if (!dev->descriptor.iProduct || +		    usb_string(dev, dev->descriptor.iProduct, +		    card->shortname, sizeof(card->shortname)) <= 0) { +			/* no name available from anywhere, so use ID */ +			sprintf(card->shortname, "USB Device %#04x:%#04x", +				USB_ID_VENDOR(chip->usb_id), +				USB_ID_PRODUCT(chip->usb_id)); +		} +	} + +	/* retrieve the vendor and device strings as longname */ +	if (quirk && quirk->vendor_name) { +		len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); +	} else { +		if (dev->descriptor.iManufacturer) +			len = usb_string(dev, dev->descriptor.iManufacturer, +					 card->longname, sizeof(card->longname)); +		else +			len = 0; +		/* we don't really care if there isn't any vendor string */ +	} +	if (len > 0) +		strlcat(card->longname, " ", sizeof(card->longname)); + +	strlcat(card->longname, card->shortname, sizeof(card->longname)); + +	len = strlcat(card->longname, " at ", sizeof(card->longname)); + +	if (len < sizeof(card->longname)) +		usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); + +	strlcat(card->longname, +		snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : +		snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : +		", high speed", +		sizeof(card->longname)); + +	snd_usb_audio_create_proc(chip); + +	*rchip = chip; +	return 0; +} + +/* + * probe the active usb device + * + * note that this can be called multiple times per a device, when it + * includes multiple audio control interfaces. + * + * thus we check the usb device pointer and creates the card instance + * only at the first time.  the successive calls of this function will + * append the pcm interface to the corresponding card. + */ +static void *snd_usb_audio_probe(struct usb_device *dev, +				 struct usb_interface *intf, +				 const struct usb_device_id *usb_id) +{ +	const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info; +	int i, err; +	struct snd_usb_audio *chip; +	struct usb_host_interface *alts; +	int ifnum; +	u32 id; + +	alts = &intf->altsetting[0]; +	ifnum = get_iface_desc(alts)->bInterfaceNumber; +	id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), +		    le16_to_cpu(dev->descriptor.idProduct)); +	if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) +		goto __err_val; + +	if (snd_usb_apply_boot_quirk(dev, intf, quirk) < 0) +		goto __err_val; + +	/* +	 * found a config.  now register to ALSA +	 */ + +	/* check whether it's already registered */ +	chip = NULL; +	mutex_lock(®ister_mutex); +	for (i = 0; i < SNDRV_CARDS; i++) { +		if (usb_chip[i] && usb_chip[i]->dev == dev) { +			if (usb_chip[i]->shutdown) { +				snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n"); +				goto __error; +			} +			chip = usb_chip[i]; +			break; +		} +	} +	if (! chip) { +		/* it's a fresh one. +		 * now look for an empty slot and create a new card instance +		 */ +		for (i = 0; i < SNDRV_CARDS; i++) +			if (enable[i] && ! usb_chip[i] && +			    (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && +			    (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { +				if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { +					goto __error; +				} +				snd_card_set_dev(chip->card, &intf->dev); +				break; +			} +		if (!chip) { +			printk(KERN_ERR "no available usb audio device\n"); +			goto __error; +		} +	} + +	chip->txfr_quirk = 0; +	err = 1; /* continue */ +	if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { +		/* need some special handlings */ +		if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) +			goto __error; +	} + +	if (err > 0) { +		/* create normal USB audio interfaces */ +		if (snd_usb_create_streams(chip, ifnum) < 0 || +		    snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) { +			goto __error; +		} +	} + +	/* we are allowed to call snd_card_register() many times */ +	if (snd_card_register(chip->card) < 0) { +		goto __error; +	} + +	usb_chip[chip->index] = chip; +	chip->num_interfaces++; +	mutex_unlock(®ister_mutex); +	return chip; + + __error: +	if (chip && !chip->num_interfaces) +		snd_card_free(chip->card); +	mutex_unlock(®ister_mutex); + __err_val: +	return NULL; +} + +/* + * we need to take care of counter, since disconnection can be called also + * many times as well as usb_audio_probe(). + */ +static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) +{ +	struct snd_usb_audio *chip; +	struct snd_card *card; +	struct list_head *p; + +	if (ptr == (void *)-1L) +		return; + +	chip = ptr; +	card = chip->card; +	mutex_lock(®ister_mutex); +	chip->shutdown = 1; +	chip->num_interfaces--; +	if (chip->num_interfaces <= 0) { +		snd_card_disconnect(card); +		/* release the pcm resources */ +		list_for_each(p, &chip->pcm_list) { +			snd_usb_stream_disconnect(p); +		} +		/* release the midi resources */ +		list_for_each(p, &chip->midi_list) { +			snd_usbmidi_disconnect(p); +		} +		/* release mixer resources */ +		list_for_each(p, &chip->mixer_list) { +			snd_usb_mixer_disconnect(p); +		} +		usb_chip[chip->index] = NULL; +		mutex_unlock(®ister_mutex); +		snd_card_free_when_closed(card); +	} else { +		mutex_unlock(®ister_mutex); +	} +} + +/* + * new 2.5 USB kernel API + */ +static int usb_audio_probe(struct usb_interface *intf, +			   const struct usb_device_id *id) +{ +	void *chip; +	chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id); +	if (chip) { +		usb_set_intfdata(intf, chip); +		return 0; +	} else +		return -EIO; +} + +static void usb_audio_disconnect(struct usb_interface *intf) +{ +	snd_usb_audio_disconnect(interface_to_usbdev(intf), +				 usb_get_intfdata(intf)); +} + +#ifdef CONFIG_PM +static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) +{ +	struct snd_usb_audio *chip = usb_get_intfdata(intf); +	struct list_head *p; +	struct snd_usb_stream *as; + +	if (chip == (void *)-1L) +		return 0; + +	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); +	if (!chip->num_suspended_intf++) { +		list_for_each(p, &chip->pcm_list) { +			as = list_entry(p, struct snd_usb_stream, list); +			snd_pcm_suspend_all(as->pcm); +		} +	} + +	return 0; +} + +static int usb_audio_resume(struct usb_interface *intf) +{ +	struct snd_usb_audio *chip = usb_get_intfdata(intf); + +	if (chip == (void *)-1L) +		return 0; +	if (--chip->num_suspended_intf) +		return 0; +	/* +	 * ALSA leaves material resumption to user space +	 * we just notify +	 */ + +	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + +	return 0; +} +#else +#define usb_audio_suspend	NULL +#define usb_audio_resume	NULL +#endif		/* CONFIG_PM */ + +static struct usb_device_id usb_audio_ids [] = { +#include "quirks-table.h" +    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), +      .bInterfaceClass = USB_CLASS_AUDIO, +      .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL }, +    { }						/* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, usb_audio_ids); + +/* + * entry point for linux usb interface + */ + +static struct usb_driver usb_audio_driver = { +	.name =		"snd-usb-audio", +	.probe =	usb_audio_probe, +	.disconnect =	usb_audio_disconnect, +	.suspend =	usb_audio_suspend, +	.resume =	usb_audio_resume, +	.id_table =	usb_audio_ids, +}; + +static int __init snd_usb_audio_init(void) +{ +	if (nrpacks < 1 || nrpacks > MAX_PACKS) { +		printk(KERN_WARNING "invalid nrpacks value.\n"); +		return -EINVAL; +	} +	return usb_register(&usb_audio_driver); +} + +static void __exit snd_usb_audio_cleanup(void) +{ +	usb_deregister(&usb_audio_driver); +} + +module_init(snd_usb_audio_init); +module_exit(snd_usb_audio_cleanup); diff --git a/sound/usb/card.h b/sound/usb/card.h new file mode 100644 index 00000000000..ed92420c109 --- /dev/null +++ b/sound/usb/card.h @@ -0,0 +1,105 @@ +#ifndef __USBAUDIO_CARD_H +#define __USBAUDIO_CARD_H + +#define MAX_PACKS	20 +#define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */ +#define MAX_URBS	8 +#define SYNC_URBS	4	/* always four urbs for sync */ +#define MAX_QUEUE	24	/* try not to exceed this queue length, in ms */ + +struct audioformat { +	struct list_head list; +	u64 formats;			/* ALSA format bits */ +	unsigned int channels;		/* # channels */ +	unsigned int fmt_type;		/* USB audio format type (1-3) */ +	unsigned int frame_size;	/* samples per frame for non-audio */ +	int iface;			/* interface number */ +	unsigned char altsetting;	/* corresponding alternate setting */ +	unsigned char altset_idx;	/* array index of altenate setting */ +	unsigned char attributes;	/* corresponding attributes of cs endpoint */ +	unsigned char endpoint;		/* endpoint */ +	unsigned char ep_attr;		/* endpoint attributes */ +	unsigned char datainterval;	/* log_2 of data packet interval */ +	unsigned int maxpacksize;	/* max. packet size */ +	unsigned int rates;		/* rate bitmasks */ +	unsigned int rate_min, rate_max;	/* min/max rates */ +	unsigned int nr_rates;		/* number of rate table entries */ +	unsigned int *rate_table;	/* rate table */ +}; + +struct snd_usb_substream; + +struct snd_urb_ctx { +	struct urb *urb; +	unsigned int buffer_size;	/* size of data buffer, if data URB */ +	struct snd_usb_substream *subs; +	int index;	/* index for urb array */ +	int packets;	/* number of packets per urb */ +}; + +struct snd_urb_ops { +	int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); +	int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); +	int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); +	int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); +}; + +struct snd_usb_substream { +	struct snd_usb_stream *stream; +	struct usb_device *dev; +	struct snd_pcm_substream *pcm_substream; +	int direction;	/* playback or capture */ +	int interface;	/* current interface */ +	int endpoint;	/* assigned endpoint */ +	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */ +	unsigned int cur_rate;		/* current rate (for hw_params callback) */ +	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */ +	unsigned int altset_idx;     /* USB data format: index of alternate setting */ +	unsigned int datapipe;   /* the data i/o pipe */ +	unsigned int syncpipe;   /* 1 - async out or adaptive in */ +	unsigned int datainterval;	/* log_2 of data packet interval */ +	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */ +	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */ +	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */ +	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */ +	unsigned int phase;      /* phase accumulator */ +	unsigned int maxpacksize;	/* max packet size in bytes */ +	unsigned int maxframesize;	/* max packet size in frames */ +	unsigned int curpacksize;	/* current packet size in bytes (for capture) */ +	unsigned int curframesize;	/* current packet size in frames (for capture) */ +	unsigned int fill_max: 1;	/* fill max packet size always */ +	unsigned int txfr_quirk:1;	/* allow sub-frame alignment */ +	unsigned int fmt_type;		/* USB audio format type (1-3) */ + +	unsigned int running: 1;	/* running status */ + +	unsigned int hwptr_done;	/* processed byte position in the buffer */ +	unsigned int transfer_done;		/* processed frames since last period update */ +	unsigned long active_mask;	/* bitmask of active urbs */ +	unsigned long unlink_mask;	/* bitmask of unlinked urbs */ + +	unsigned int nurbs;			/* # urbs */ +	struct snd_urb_ctx dataurb[MAX_URBS];	/* data urb table */ +	struct snd_urb_ctx syncurb[SYNC_URBS];	/* sync urb table */ +	char *syncbuf;				/* sync buffer for all sync URBs */ +	dma_addr_t sync_dma;			/* DMA address of syncbuf */ + +	u64 formats;			/* format bitmasks (all or'ed) */ +	unsigned int num_formats;		/* number of supported audio formats (list) */ +	struct list_head fmt_list;	/* format list */ +	struct snd_pcm_hw_constraint_list rate_list;	/* limited rates */ +	spinlock_t lock; + +	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */ +}; + +struct snd_usb_stream { +	struct snd_usb_audio *chip; +	struct snd_pcm *pcm; +	int pcm_index; +	unsigned int fmt_type;		/* USB audio format type (1-3) */ +	struct snd_usb_substream substream[2]; +	struct list_head list; +}; + +#endif /* __USBAUDIO_CARD_H */ diff --git a/sound/usb/debug.h b/sound/usb/debug.h new file mode 100644 index 00000000000..343ec2d9ee6 --- /dev/null +++ b/sound/usb/debug.h @@ -0,0 +1,15 @@ +#ifndef __USBAUDIO_DEBUG_H +#define __USBAUDIO_DEBUG_H + +/* + * h/w constraints + */ + +#ifdef HW_CONST_DEBUG +#define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) +#else +#define hwc_debug(fmt, args...) /**/ +#endif + +#endif /* __USBAUDIO_DEBUG_H */ + diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c new file mode 100644 index 00000000000..ef07a6d0dd5 --- /dev/null +++ b/sound/usb/endpoint.c @@ -0,0 +1,362 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "usbaudio.h" +#include "card.h" +#include "proc.h" +#include "quirks.h" +#include "endpoint.h" +#include "urb.h" +#include "pcm.h" +#include "helper.h" +#include "format.h" + +/* + * free a substream + */ +static void free_substream(struct snd_usb_substream *subs) +{ +	struct list_head *p, *n; + +	if (!subs->num_formats) +		return; /* not initialized */ +	list_for_each_safe(p, n, &subs->fmt_list) { +		struct audioformat *fp = list_entry(p, struct audioformat, list); +		kfree(fp->rate_table); +		kfree(fp); +	} +	kfree(subs->rate_list.list); +} + + +/* + * free a usb stream instance + */ +static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) +{ +	free_substream(&stream->substream[0]); +	free_substream(&stream->substream[1]); +	list_del(&stream->list); +	kfree(stream); +} + +static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) +{ +	struct snd_usb_stream *stream = pcm->private_data; +	if (stream) { +		stream->pcm = NULL; +		snd_usb_audio_stream_free(stream); +	} +} + + +/* + * add this endpoint to the chip instance. + * if a stream with the same endpoint already exists, append to it. + * if not, create a new pcm stream. + */ +int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) +{ +	struct list_head *p; +	struct snd_usb_stream *as; +	struct snd_usb_substream *subs; +	struct snd_pcm *pcm; +	int err; + +	list_for_each(p, &chip->pcm_list) { +		as = list_entry(p, struct snd_usb_stream, list); +		if (as->fmt_type != fp->fmt_type) +			continue; +		subs = &as->substream[stream]; +		if (!subs->endpoint) +			continue; +		if (subs->endpoint == fp->endpoint) { +			list_add_tail(&fp->list, &subs->fmt_list); +			subs->num_formats++; +			subs->formats |= fp->formats; +			return 0; +		} +	} +	/* look for an empty stream */ +	list_for_each(p, &chip->pcm_list) { +		as = list_entry(p, struct snd_usb_stream, list); +		if (as->fmt_type != fp->fmt_type) +			continue; +		subs = &as->substream[stream]; +		if (subs->endpoint) +			continue; +		err = snd_pcm_new_stream(as->pcm, stream, 1); +		if (err < 0) +			return err; +		snd_usb_init_substream(as, stream, fp); +		return 0; +	} + +	/* create a new pcm */ +	as = kzalloc(sizeof(*as), GFP_KERNEL); +	if (!as) +		return -ENOMEM; +	as->pcm_index = chip->pcm_devs; +	as->chip = chip; +	as->fmt_type = fp->fmt_type; +	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, +			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, +			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, +			  &pcm); +	if (err < 0) { +		kfree(as); +		return err; +	} +	as->pcm = pcm; +	pcm->private_data = as; +	pcm->private_free = snd_usb_audio_pcm_free; +	pcm->info_flags = 0; +	if (chip->pcm_devs > 0) +		sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); +	else +		strcpy(pcm->name, "USB Audio"); + +	snd_usb_init_substream(as, stream, fp); + +	list_add(&as->list, &chip->pcm_list); +	chip->pcm_devs++; + +	snd_usb_proc_pcm_format_add(as); + +	return 0; +} + +int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) +{ +	struct usb_device *dev; +	struct usb_interface *iface; +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	int i, altno, err, stream; +	int format = 0, num_channels = 0; +	struct audioformat *fp = NULL; +	unsigned char *fmt, *csep; +	int num, protocol; + +	dev = chip->dev; + +	/* parse the interface's altsettings */ +	iface = usb_ifnum_to_if(dev, iface_no); + +	num = iface->num_altsetting; + +	/* +	 * Dallas DS4201 workaround: It presents 5 altsettings, but the last +	 * one misses syncpipe, and does not produce any sound. +	 */ +	if (chip->usb_id == USB_ID(0x04fa, 0x4201)) +		num = 4; + +	for (i = 0; i < num; i++) { +		alts = &iface->altsetting[i]; +		altsd = get_iface_desc(alts); +		protocol = altsd->bInterfaceProtocol; +		/* skip invalid one */ +		if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && +		     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || +		    (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && +		     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || +		    altsd->bNumEndpoints < 1 || +		    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) +			continue; +		/* must be isochronous */ +		if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != +		    USB_ENDPOINT_XFER_ISOC) +			continue; +		/* check direction */ +		stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? +			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; +		altno = altsd->bAlternateSetting; + +		if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) +			continue; + +		/* get audio formats */ +		switch (protocol) { +		case UAC_VERSION_1: { +			struct uac_as_header_descriptor_v1 *as = +				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + +			if (!as) { +				snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", +					   dev->devnum, iface_no, altno); +				continue; +			} + +			if (as->bLength < sizeof(*as)) { +				snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", +					   dev->devnum, iface_no, altno); +				continue; +			} + +			format = le16_to_cpu(as->wFormatTag); /* remember the format value */ +			break; +		} + +		case UAC_VERSION_2: { +			struct uac_as_header_descriptor_v2 *as = +				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + +			if (!as) { +				snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", +					   dev->devnum, iface_no, altno); +				continue; +			} + +			if (as->bLength < sizeof(*as)) { +				snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", +					   dev->devnum, iface_no, altno); +				continue; +			} + +			num_channels = as->bNrChannels; +			format = le32_to_cpu(as->bmFormats); + +			break; +		} + +		default: +			snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", +				   dev->devnum, iface_no, altno, protocol); +			continue; +		} + +		/* get format type */ +		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); +		if (!fmt) { +			snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", +				   dev->devnum, iface_no, altno); +			continue; +		} +		if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) || +		    ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) { +			snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", +				   dev->devnum, iface_no, altno); +			continue; +		} + +		/* +		 * Blue Microphones workaround: The last altsetting is identical +		 * with the previous one, except for a larger packet size, but +		 * is actually a mislabeled two-channel setting; ignore it. +		 */ +		if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && +		    fp && fp->altsetting == 1 && fp->channels == 1 && +		    fp->formats == SNDRV_PCM_FMTBIT_S16_LE && +		    protocol == UAC_VERSION_1 && +		    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == +							fp->maxpacksize * 2) +			continue; + +		csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); +		/* Creamware Noah has this descriptor after the 2nd endpoint */ +		if (!csep && altsd->bNumEndpoints >= 2) +			csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); +		if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) { +			snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" +				   " class specific endpoint descriptor\n", +				   dev->devnum, iface_no, altno); +			csep = NULL; +		} + +		fp = kzalloc(sizeof(*fp), GFP_KERNEL); +		if (! fp) { +			snd_printk(KERN_ERR "cannot malloc\n"); +			return -ENOMEM; +		} + +		fp->iface = iface_no; +		fp->altsetting = altno; +		fp->altset_idx = i; +		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; +		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; +		fp->datainterval = snd_usb_parse_datainterval(chip, alts); +		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +		/* num_channels is only set for v2 interfaces */ +		fp->channels = num_channels; +		if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) +			fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) +					* (fp->maxpacksize & 0x7ff); +		fp->attributes = csep ? csep[3] : 0; + +		/* some quirks for attributes here */ + +		switch (chip->usb_id) { +		case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ +			/* Optoplay sets the sample rate attribute although +			 * it seems not supporting it in fact. +			 */ +			fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; +			break; +		case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ +		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ +		case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ +		case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ +			/* doesn't set the sample rate attribute, but supports it */ +			fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; +			break; +		case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ +		case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is +						an older model 77d:223) */ +		/* +		 * plantronics headset and Griffin iMic have set adaptive-in +		 * although it's really not... +		 */ +			fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; +			if (stream == SNDRV_PCM_STREAM_PLAYBACK) +				fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; +			else +				fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; +			break; +		} + +		/* ok, let's parse further... */ +		if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { +			kfree(fp->rate_table); +			kfree(fp); +			continue; +		} + +		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); +		err = snd_usb_add_audio_endpoint(chip, stream, fp); +		if (err < 0) { +			kfree(fp->rate_table); +			kfree(fp); +			return err; +		} +		/* try to set the interface... */ +		usb_set_interface(chip->dev, iface_no, altno); +		snd_usb_init_pitch(chip, iface_no, alts, fp); +		snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); +	} +	return 0; +} + diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h new file mode 100644 index 00000000000..64dd0db023b --- /dev/null +++ b/sound/usb/endpoint.h @@ -0,0 +1,11 @@ +#ifndef __USBAUDIO_ENDPOINT_H +#define __USBAUDIO_ENDPOINT_H + +int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, +				  int iface_no); + +int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, +			       int stream, +			       struct audioformat *fp); + +#endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c new file mode 100644 index 00000000000..b87cf87c4e7 --- /dev/null +++ b/sound/usb/format.c @@ -0,0 +1,432 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "usbaudio.h" +#include "card.h" +#include "quirks.h" +#include "helper.h" +#include "debug.h" + +/* + * parse the audio format type I descriptor + * and returns the corresponding pcm format + * + * @dev: usb device + * @fp: audioformat record + * @format: the format tag (wFormatTag) + * @fmt: the format type descriptor + */ +static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, +				     struct audioformat *fp, +				     int format, void *_fmt, +				     int protocol) +{ +	int sample_width, sample_bytes; +	u64 pcm_formats; + +	switch (protocol) { +	case UAC_VERSION_1: { +		struct uac_format_type_i_discrete_descriptor *fmt = _fmt; +		sample_width = fmt->bBitResolution; +		sample_bytes = fmt->bSubframeSize; +		format = 1 << format; +		break; +	} + +	case UAC_VERSION_2: { +		struct uac_format_type_i_ext_descriptor *fmt = _fmt; +		sample_width = fmt->bBitResolution; +		sample_bytes = fmt->bSubslotSize; +		format <<= 1; +		break; +	} + +	default: +		return -EINVAL; +	} + +	pcm_formats = 0; + +	if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) { +		/* some devices don't define this correctly... */ +		snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", +			    chip->dev->devnum, fp->iface, fp->altsetting); +		format = 1 << UAC_FORMAT_TYPE_I_PCM; +	} +	if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) { +		if (sample_width > sample_bytes * 8) { +			snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", +				   chip->dev->devnum, fp->iface, fp->altsetting, +				   sample_width, sample_bytes); +		} +		/* check the format byte size */ +		switch (sample_bytes) { +		case 1: +			pcm_formats |= SNDRV_PCM_FMTBIT_S8; +			break; +		case 2: +			if (snd_usb_is_big_endian_format(chip, fp)) +				pcm_formats |= SNDRV_PCM_FMTBIT_S16_BE; /* grrr, big endian!! */ +			else +				pcm_formats |= SNDRV_PCM_FMTBIT_S16_LE; +			break; +		case 3: +			if (snd_usb_is_big_endian_format(chip, fp)) +				pcm_formats |= SNDRV_PCM_FMTBIT_S24_3BE; /* grrr, big endian!! */ +			else +				pcm_formats |= SNDRV_PCM_FMTBIT_S24_3LE; +			break; +		case 4: +			pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE; +			break; +		default: +			snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", +				   chip->dev->devnum, fp->iface, fp->altsetting, +				   sample_width, sample_bytes); +			break; +		} +	} +	if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) { +		/* Dallas DS4201 workaround: it advertises U8 format, but really +		   supports S8. */ +		if (chip->usb_id == USB_ID(0x04fa, 0x4201)) +			pcm_formats |= SNDRV_PCM_FMTBIT_S8; +		else +			pcm_formats |= SNDRV_PCM_FMTBIT_U8; +	} +	if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) { +		pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; +	} +	if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) { +		pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW; +	} +	if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) { +		pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW; +	} +	if (format & ~0x3f) { +		snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n", +			   chip->dev->devnum, fp->iface, fp->altsetting, format); +	} +	return pcm_formats; +} + + +/* + * parse the format descriptor and stores the possible sample rates + * on the audioformat table (audio class v1). + * + * @dev: usb device + * @fp: audioformat record + * @fmt: the format descriptor + * @offset: the start offset of descriptor pointing the rate type + *          (7 for type I and II, 8 for type II) + */ +static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audioformat *fp, +				       unsigned char *fmt, int offset) +{ +	int nr_rates = fmt[offset]; + +	if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { +		snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", +				   chip->dev->devnum, fp->iface, fp->altsetting); +		return -1; +	} + +	if (nr_rates) { +		/* +		 * build the rate table and bitmap flags +		 */ +		int r, idx; + +		fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); +		if (fp->rate_table == NULL) { +			snd_printk(KERN_ERR "cannot malloc\n"); +			return -1; +		} + +		fp->nr_rates = 0; +		fp->rate_min = fp->rate_max = 0; +		for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { +			unsigned int rate = combine_triple(&fmt[idx]); +			if (!rate) +				continue; +			/* C-Media CM6501 mislabels its 96 kHz altsetting */ +			if (rate == 48000 && nr_rates == 1 && +			    (chip->usb_id == USB_ID(0x0d8c, 0x0201) || +			     chip->usb_id == USB_ID(0x0d8c, 0x0102)) && +			    fp->altsetting == 5 && fp->maxpacksize == 392) +				rate = 96000; +			/* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ +			if (rate == 16000 && chip->usb_id == USB_ID(0x041e, 0x4068)) +				rate = 8000; + +			fp->rate_table[fp->nr_rates] = rate; +			if (!fp->rate_min || rate < fp->rate_min) +				fp->rate_min = rate; +			if (!fp->rate_max || rate > fp->rate_max) +				fp->rate_max = rate; +			fp->rates |= snd_pcm_rate_to_rate_bit(rate); +			fp->nr_rates++; +		} +		if (!fp->nr_rates) { +			hwc_debug("All rates were zero. Skipping format!\n"); +			return -1; +		} +	} else { +		/* continuous rates */ +		fp->rates = SNDRV_PCM_RATE_CONTINUOUS; +		fp->rate_min = combine_triple(&fmt[offset + 1]); +		fp->rate_max = combine_triple(&fmt[offset + 4]); +	} +	return 0; +} + +/* + * parse the format descriptor and stores the possible sample rates + * on the audioformat table (audio class v2). + */ +static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, +				       struct audioformat *fp, +				       struct usb_host_interface *iface) +{ +	struct usb_device *dev = chip->dev; +	unsigned char tmp[2], *data; +	int i, nr_rates, data_size, ret = 0; + +	/* get the number of sample rates first by only fetching 2 bytes */ +	ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, +			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, +			      UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, +			      tmp, sizeof(tmp), 1000); + +	if (ret < 0) { +		snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); +		goto err; +	} + +	nr_rates = (tmp[1] << 8) | tmp[0]; +	data_size = 2 + 12 * nr_rates; +	data = kzalloc(data_size, GFP_KERNEL); +	if (!data) { +		ret = -ENOMEM; +		goto err; +	} + +	/* now get the full information */ +	ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, +			       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, +			       UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, +			       data, data_size, 1000); + +	if (ret < 0) { +		snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); +		ret = -EINVAL; +		goto err_free; +	} + +	fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); +	if (!fp->rate_table) { +		ret = -ENOMEM; +		goto err_free; +	} + +	fp->nr_rates = 0; +	fp->rate_min = fp->rate_max = 0; + +	for (i = 0; i < nr_rates; i++) { +		int rate = combine_quad(&data[2 + 12 * i]); + +		fp->rate_table[fp->nr_rates] = rate; +		if (!fp->rate_min || rate < fp->rate_min) +			fp->rate_min = rate; +		if (!fp->rate_max || rate > fp->rate_max) +			fp->rate_max = rate; +		fp->rates |= snd_pcm_rate_to_rate_bit(rate); +		fp->nr_rates++; +	} + +err_free: +	kfree(data); +err: +	return ret; +} + +/* + * parse the format type I and III descriptors + */ +static int parse_audio_format_i(struct snd_usb_audio *chip, +				struct audioformat *fp, +				int format, void *_fmt, +				struct usb_host_interface *iface) +{ +	struct usb_interface_descriptor *altsd = get_iface_desc(iface); +	struct uac_format_type_i_discrete_descriptor *fmt = _fmt; +	int protocol = altsd->bInterfaceProtocol; +	int pcm_format, ret; + +	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { +		/* FIXME: the format type is really IECxxx +		 *        but we give normal PCM format to get the existing +		 *        apps working... +		 */ +		switch (chip->usb_id) { + +		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ +			if (chip->setup == 0x00 &&  +			    fp->altsetting == 6) +				pcm_format = SNDRV_PCM_FORMAT_S16_BE; +			else +				pcm_format = SNDRV_PCM_FORMAT_S16_LE; +			break; +		default: +			pcm_format = SNDRV_PCM_FORMAT_S16_LE; +		} +		fp->formats = 1uLL << pcm_format; +	} else { +		fp->formats = parse_audio_format_i_type(chip, fp, format, +							fmt, protocol); +		if (!fp->formats) +			return -1; +	} + +	/* gather possible sample rates */ +	/* audio class v1 reports possible sample rates as part of the +	 * proprietary class specific descriptor. +	 * audio class v2 uses class specific EP0 range requests for that. +	 */ +	switch (protocol) { +	case UAC_VERSION_1: +		fp->channels = fmt->bNrChannels; +		ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7); +		break; +	case UAC_VERSION_2: +		/* fp->channels is already set in this case */ +		ret = parse_audio_format_rates_v2(chip, fp, iface); +		break; +	} + +	if (fp->channels < 1) { +		snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", +			   chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); +		return -1; +	} + +	return ret; +} + +/* + * parse the format type II descriptor + */ +static int parse_audio_format_ii(struct snd_usb_audio *chip, +				 struct audioformat *fp, +				 int format, void *_fmt, +				 struct usb_host_interface *iface) +{ +	int brate, framesize, ret; +	struct usb_interface_descriptor *altsd = get_iface_desc(iface); +	int protocol = altsd->bInterfaceProtocol; + +	switch (format) { +	case UAC_FORMAT_TYPE_II_AC3: +		/* FIXME: there is no AC3 format defined yet */ +		// fp->formats = SNDRV_PCM_FMTBIT_AC3; +		fp->formats = SNDRV_PCM_FMTBIT_U8; /* temporary hack to receive byte streams */ +		break; +	case UAC_FORMAT_TYPE_II_MPEG: +		fp->formats = SNDRV_PCM_FMTBIT_MPEG; +		break; +	default: +		snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n", +			   chip->dev->devnum, fp->iface, fp->altsetting, format); +		fp->formats = SNDRV_PCM_FMTBIT_MPEG; +		break; +	} + +	fp->channels = 1; + +	switch (protocol) { +	case UAC_VERSION_1: { +		struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; +		brate = le16_to_cpu(fmt->wMaxBitRate); +		framesize = le16_to_cpu(fmt->wSamplesPerFrame); +		snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); +		fp->frame_size = framesize; +		ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */ +		break; +	} +	case UAC_VERSION_2: { +		struct uac_format_type_ii_ext_descriptor *fmt = _fmt; +		brate = le16_to_cpu(fmt->wMaxBitRate); +		framesize = le16_to_cpu(fmt->wSamplesPerFrame); +		snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); +		fp->frame_size = framesize; +		ret = parse_audio_format_rates_v2(chip, fp, iface); +		break; +	} +	} + +	return ret; +} + +int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, +		       int format, unsigned char *fmt, int stream, +		       struct usb_host_interface *iface) +{ +	int err; + +	switch (fmt[3]) { +	case UAC_FORMAT_TYPE_I: +	case UAC_FORMAT_TYPE_III: +		err = parse_audio_format_i(chip, fp, format, fmt, iface); +		break; +	case UAC_FORMAT_TYPE_II: +		err = parse_audio_format_ii(chip, fp, format, fmt, iface); +		break; +	default: +		snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", +			   chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); +		return -1; +	} +	fp->fmt_type = fmt[3]; +	if (err < 0) +		return err; +#if 1 +	/* FIXME: temporary hack for extigy/audigy 2 nx/zs */ +	/* extigy apparently supports sample rates other than 48k +	 * but not in ordinary way.  so we enable only 48k atm. +	 */ +	if (chip->usb_id == USB_ID(0x041e, 0x3000) || +	    chip->usb_id == USB_ID(0x041e, 0x3020) || +	    chip->usb_id == USB_ID(0x041e, 0x3061)) { +		if (fmt[3] == UAC_FORMAT_TYPE_I && +		    fp->rates != SNDRV_PCM_RATE_48000 && +		    fp->rates != SNDRV_PCM_RATE_96000) +			return -1; +	} +#endif +	return 0; +} + diff --git a/sound/usb/format.h b/sound/usb/format.h new file mode 100644 index 00000000000..8298c4e8ddf --- /dev/null +++ b/sound/usb/format.h @@ -0,0 +1,8 @@ +#ifndef __USBAUDIO_FORMAT_H +#define __USBAUDIO_FORMAT_H + +int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, +			       int format, unsigned char *fmt, int stream, +			       struct usb_host_interface *iface); + +#endif /*  __USBAUDIO_FORMAT_H */ diff --git a/sound/usb/helper.c b/sound/usb/helper.c new file mode 100644 index 00000000000..d48d6f8f6ac --- /dev/null +++ b/sound/usb/helper.c @@ -0,0 +1,113 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include "usbaudio.h" +#include "helper.h" + +/* + * combine bytes and get an integer value + */ +unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size) +{ +	switch (size) { +	case 1:  return *bytes; +	case 2:  return combine_word(bytes); +	case 3:  return combine_triple(bytes); +	case 4:  return combine_quad(bytes); +	default: return 0; +	} +} + +/* + * parse descriptor buffer and return the pointer starting the given + * descriptor type. + */ +void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype) +{ +	u8 *p, *end, *next; + +	p = descstart; +	end = p + desclen; +	for (; p < end;) { +		if (p[0] < 2) +			return NULL; +		next = p + p[0]; +		if (next > end) +			return NULL; +		if (p[1] == dtype && (!after || (void *)p > after)) { +			return p; +		} +		p = next; +	} +	return NULL; +} + +/* + * find a class-specified interface descriptor with the given subtype. + */ +void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype) +{ +	unsigned char *p = after; + +	while ((p = snd_usb_find_desc(buffer, buflen, p, +				      USB_DT_CS_INTERFACE)) != NULL) { +		if (p[0] >= 3 && p[2] == dsubtype) +			return p; +	} +	return NULL; +} + +/* + * Wrapper for usb_control_msg(). + * Allocates a temp buffer to prevent dmaing from/to the stack. + */ +int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, +		    __u8 requesttype, __u16 value, __u16 index, void *data, +		    __u16 size, int timeout) +{ +	int err; +	void *buf = NULL; + +	if (size > 0) { +		buf = kmemdup(data, size, GFP_KERNEL); +		if (!buf) +			return -ENOMEM; +	} +	err = usb_control_msg(dev, pipe, request, requesttype, +			      value, index, buf, size, timeout); +	if (size > 0) { +		memcpy(data, buf, size); +		kfree(buf); +	} +	return err; +} + +unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, +					 struct usb_host_interface *alts) +{ +	if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && +	    get_endpoint(alts, 0)->bInterval >= 1 && +	    get_endpoint(alts, 0)->bInterval <= 4) +		return get_endpoint(alts, 0)->bInterval - 1; +	else +		return 0; +} + diff --git a/sound/usb/helper.h b/sound/usb/helper.h new file mode 100644 index 00000000000..a6b0e51b3a9 --- /dev/null +++ b/sound/usb/helper.h @@ -0,0 +1,32 @@ +#ifndef __USBAUDIO_HELPER_H +#define __USBAUDIO_HELPER_H + +unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size); + +void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype); +void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype); + +int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, +		    __u8 request, __u8 requesttype, __u16 value, __u16 index, +		    void *data, __u16 size, int timeout); + +unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, +					 struct usb_host_interface *alts); + +/* + * retrieve usb_interface descriptor from the host interface + * (conditional for compatibility with the older API) + */ +#ifndef get_iface_desc +#define get_iface_desc(iface)	(&(iface)->desc) +#define get_endpoint(alt,ep)	(&(alt)->endpoint[ep].desc) +#define get_ep_desc(ep)		(&(ep)->desc) +#define get_cfg_desc(cfg)	(&(cfg)->desc) +#endif + +#ifndef snd_usb_get_speed +#define snd_usb_get_speed(dev) ((dev)->speed) +#endif + + +#endif /* __USBAUDIO_HELPER_H */ diff --git a/sound/usb/usbmidi.c b/sound/usb/midi.c index 2c59afd9961..2c1558c327b 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/midi.c @@ -53,7 +53,8 @@  #include <sound/rawmidi.h>  #include <sound/asequencer.h>  #include "usbaudio.h" - +#include "midi.h" +#include "helper.h"  /*   * define this to log all USB packets @@ -986,6 +987,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)  	DEFINE_WAIT(wait);  	long timeout = msecs_to_jiffies(50); +	if (ep->umidi->disconnected) +		return;  	/*  	 * The substream buffer is empty, but some data might still be in the  	 * currently active URBs, so we have to wait for those to complete. @@ -1123,14 +1126,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,   * Frees an output endpoint.   * May be called when ep hasn't been initialized completely.   */ -static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)  {  	unsigned int i;  	for (i = 0; i < OUTPUT_URBS; ++i) -		if (ep->urbs[i].urb) +		if (ep->urbs[i].urb) {  			free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,  					    ep->max_transfer); +			ep->urbs[i].urb = NULL; +		} +} + +static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep) +{ +	snd_usbmidi_out_endpoint_clear(ep);  	kfree(ep);  } @@ -1262,15 +1272,18 @@ void snd_usbmidi_disconnect(struct list_head* p)  				usb_kill_urb(ep->out->urbs[j].urb);  			if (umidi->usb_protocol_ops->finish_out_endpoint)  				umidi->usb_protocol_ops->finish_out_endpoint(ep->out); +			ep->out->active_urbs = 0; +			if (ep->out->drain_urbs) { +				ep->out->drain_urbs = 0; +				wake_up(&ep->out->drain_wait); +			}  		}  		if (ep->in)  			for (j = 0; j < INPUT_URBS; ++j)  				usb_kill_urb(ep->in->urbs[j]);  		/* free endpoints here; later call can result in Oops */ -		if (ep->out) { -			snd_usbmidi_out_endpoint_delete(ep->out); -			ep->out = NULL; -		} +		if (ep->out) +			snd_usbmidi_out_endpoint_clear(ep->out);  		if (ep->in) {  			snd_usbmidi_in_endpoint_delete(ep->in);  			ep->in = NULL; diff --git a/sound/usb/midi.h b/sound/usb/midi.h new file mode 100644 index 00000000000..2089ec987c6 --- /dev/null +++ b/sound/usb/midi.h @@ -0,0 +1,48 @@ +#ifndef __USBMIDI_H +#define __USBMIDI_H + +/* maximum number of endpoints per interface */ +#define MIDI_MAX_ENDPOINTS 2 + +/* data for QUIRK_MIDI_FIXED_ENDPOINT */ +struct snd_usb_midi_endpoint_info { +	int8_t   out_ep;	/* ep number, 0 autodetect */ +	uint8_t  out_interval;	/* interval for interrupt endpoints */ +	int8_t   in_ep; +	uint8_t  in_interval; +	uint16_t out_cables;	/* bitmask */ +	uint16_t in_cables;	/* bitmask */ +}; + +/* for QUIRK_MIDI_YAMAHA, data is NULL */ + +/* for QUIRK_MIDI_MIDIMAN, data points to a snd_usb_midi_endpoint_info + * structure (out_cables and in_cables only) */ + +/* for QUIRK_COMPOSITE, data points to an array of snd_usb_audio_quirk + * structures, terminated with .ifnum = -1 */ + +/* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */ + +/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */ + +/* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */ + +/* for QUIRK_IGNORE_INTERFACE, data is NULL */ + +/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */ + +/* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info + * structure (out_cables and in_cables only) */ + +/* for QUIRK_MIDI_CME, data is NULL */ + +int snd_usbmidi_create(struct snd_card *card, +		       struct usb_interface *iface, +		       struct list_head *midi_list, +		       const struct snd_usb_audio_quirk *quirk); +void snd_usbmidi_input_stop(struct list_head* p); +void snd_usbmidi_input_start(struct list_head* p); +void snd_usbmidi_disconnect(struct list_head *p); + +#endif /* __USBMIDI_H */ diff --git a/sound/usb/misc/Makefile b/sound/usb/misc/Makefile new file mode 100644 index 00000000000..ccefd815893 --- /dev/null +++ b/sound/usb/misc/Makefile @@ -0,0 +1,2 @@ +snd-ua101-objs := ua101.o +obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o diff --git a/sound/usb/ua101.c b/sound/usb/misc/ua101.c index 3d458d3b996..796d8b25ee8 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/misc/ua101.c @@ -23,7 +23,8 @@  #include <sound/initval.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> -#include "usbaudio.h" +#include "../usbaudio.h" +#include "../midi.h"  MODULE_DESCRIPTION("Edirol UA-101/1000 driver");  MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); diff --git a/sound/usb/usbmixer.c b/sound/usb/mixer.c index 8e8f871b74c..21613fe0c1a 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/mixer.c @@ -33,6 +33,7 @@  #include <linux/string.h>  #include <linux/usb.h>  #include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h>  #include <sound/core.h>  #include <sound/control.h> @@ -41,60 +42,12 @@  #include <sound/tlv.h>  #include "usbaudio.h" - -/* - */ - -/* ignore error from controls - for debugging */ -/* #define IGNORE_CTL_ERROR */ - -/* - * Sound Blaster remote control configuration - * - * format of remote control data: - * Extigy:       xx 00 - * Audigy 2 NX:  06 80 xx 00 00 00 - * Live! 24-bit: 06 80 xx yy 22 83 - */ -static const struct rc_config { -	u32 usb_id; -	u8  offset; -	u8  length; -	u8  packet_length; -	u8  min_packet_length; /* minimum accepted length of the URB result */ -	u8  mute_mixer_id; -	u32 mute_code; -} rc_configs[] = { -	{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */ -	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */ -	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */ -	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */ -}; +#include "mixer.h" +#include "helper.h" +#include "mixer_quirks.h"  #define MAX_ID_ELEMS	256 -struct usb_mixer_interface { -	struct snd_usb_audio *chip; -	unsigned int ctrlif; -	struct list_head list; -	unsigned int ignore_ctl_error; -	struct urb *urb; -	/* array[MAX_ID_ELEMS], indexed by unit id */ -	struct usb_mixer_elem_info **id_elems; - -	/* Sound Blaster remote control stuff */ -	const struct rc_config *rc_cfg; -	u32 rc_code; -	wait_queue_head_t rc_waitq; -	struct urb *rc_urb; -	struct usb_ctrlrequest *rc_setup_packet; -	u8 rc_buffer[6]; - -	u8 audigy2nx_leds[3]; -	u8 xonar_u1_status; -}; - -  struct usb_audio_term {  	int id;  	int type; @@ -116,39 +69,6 @@ struct mixer_build {  	const struct usbmix_selector_map *selector_map;  }; -#define MAX_CHANNELS	10	/* max logical channels */ - -struct usb_mixer_elem_info { -	struct usb_mixer_interface *mixer; -	struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ -	struct snd_ctl_elem_id *elem_id; -	unsigned int id; -	unsigned int control;	/* CS or ICN (high byte) */ -	unsigned int cmask; /* channel mask bitmap: 0 = master */ -	int channels; -	int val_type; -	int min, max, res; -	int dBmin, dBmax; -	int cached; -	int cache_val[MAX_CHANNELS]; -	u8 initialized; -}; - - -enum { -	USB_FEATURE_NONE = 0, -	USB_FEATURE_MUTE = 1, -	USB_FEATURE_VOLUME, -	USB_FEATURE_BASS, -	USB_FEATURE_MID, -	USB_FEATURE_TREBLE, -	USB_FEATURE_GEQ, -	USB_FEATURE_AGC, -	USB_FEATURE_DELAY, -	USB_FEATURE_BASSBOOST, -	USB_FEATURE_LOUDNESS -}; -  enum {  	USB_MIXER_BOOLEAN,  	USB_MIXER_INV_BOOLEAN, @@ -213,7 +133,7 @@ enum {   * if the mixer topology is too complicated and the parsed names are   * ambiguous, add the entries in usbmixer_maps.c.   */ -#include "usbmixer_maps.c" +#include "mixer_maps.c"  static const struct usbmix_name_map *  find_map(struct mixer_build *state, int unitid, int control) @@ -278,6 +198,7 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,  /*   * find an audio control unit with the given unit id + * this doesn't return any clock related units, so they need to be handled elsewhere   */  static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit)  { @@ -286,7 +207,7 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un  	p = NULL;  	while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,  				      USB_DT_CS_INTERFACE)) != NULL) { -		if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit) +		if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit)  			return p;  	}  	return NULL; @@ -383,7 +304,7 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)   * retrieve a mixer value   */ -static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) +static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)  {  	unsigned char buf[2];  	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; @@ -405,6 +326,58 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali  	return -EINVAL;  } +static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) +{ +	unsigned char buf[14]; /* enough space for one range of 4 bytes */ +	unsigned char *val; +	int ret; +	__u8 bRequest; + +	bRequest = (request == UAC_GET_CUR) ? +		UAC2_CS_CUR : UAC2_CS_RANGE; + +	ret = snd_usb_ctl_msg(cval->mixer->chip->dev, +			      usb_rcvctrlpipe(cval->mixer->chip->dev, 0), +			      bRequest, +			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, +			      validx, cval->mixer->ctrlif | (cval->id << 8), +			      buf, sizeof(buf), 1000); + +	if (ret < 0) { +		snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", +			    request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); +		return ret; +	} + +	switch (request) { +	case UAC_GET_CUR: +		val = buf; +		break; +	case UAC_GET_MIN: +		val = buf + sizeof(__u16); +		break; +	case UAC_GET_MAX: +		val = buf + sizeof(__u16) * 2; +		break; +	case UAC_GET_RES: +		val = buf + sizeof(__u16) * 3; +		break; +	default: +		return -EINVAL; +	} + +	*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16))); + +	return 0; +} + +static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) +{ +	return (cval->mixer->protocol == UAC_VERSION_1) ? +		get_ctl_value_v1(cval, request, validx, value_ret) : +		get_ctl_value_v2(cval, request, validx, value_ret); +} +  static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value)  {  	return get_ctl_value(cval, UAC_GET_CUR, validx, value); @@ -429,8 +402,7 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,  	err = get_cur_mix_raw(cval, channel, value);  	if (err < 0) {  		if (!cval->mixer->ignore_ctl_error) -			snd_printd(KERN_ERR "cannot get current value for " -				   "control %d ch %d: err = %d\n", +			snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n",  				   cval->control, channel, err);  		return err;  	} @@ -444,11 +416,26 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,   * set a mixer value   */ -static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set) +int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, +				int request, int validx, int value_set)  {  	unsigned char buf[2]; -	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; -	int timeout = 10; +	int val_len, timeout = 10; + +	if (cval->mixer->protocol == UAC_VERSION_1) { +		val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; +	} else { /* UAC_VERSION_2 */ +		/* audio class v2 controls are always 2 bytes in size */ +		val_len = sizeof(__u16); + +		/* FIXME */ +		if (request != UAC_SET_CUR) { +			snd_printdd(KERN_WARNING "RANGE setting not yet supported\n"); +			return -EINVAL; +		} + +		request = UAC2_CS_CUR; +	}  	value_set = convert_bytes_value(cval, value_set);  	buf[0] = value_set & 0xff; @@ -468,14 +455,14 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali  static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)  { -	return set_ctl_value(cval, UAC_SET_CUR, validx, value); +	return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);  }  static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,  			     int index, int value)  {  	int err; -	err = set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, +	err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,  			    value);  	if (err < 0)  		return err; @@ -644,46 +631,65 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm   */  static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term)  { -	unsigned char *p1; +	void *p1;  	memset(term, 0, sizeof(*term));  	while ((p1 = find_audio_control_unit(state, id)) != NULL) { +		unsigned char *hdr = p1;  		term->id = id; -		switch (p1[2]) { +		switch (hdr[2]) {  		case UAC_INPUT_TERMINAL: -			term->type = combine_word(p1 + 4); -			term->channels = p1[7]; -			term->chconfig = combine_word(p1 + 8); -			term->name = p1[11]; +			if (state->mixer->protocol == UAC_VERSION_1) { +				struct uac_input_terminal_descriptor *d = p1; +				term->type = le16_to_cpu(d->wTerminalType); +				term->channels = d->bNrChannels; +				term->chconfig = le16_to_cpu(d->wChannelConfig); +				term->name = d->iTerminal; +			} else { /* UAC_VERSION_2 */ +				struct uac2_input_terminal_descriptor *d = p1; +				term->type = le16_to_cpu(d->wTerminalType); +				term->channels = d->bNrChannels; +				term->chconfig = le32_to_cpu(d->bmChannelConfig); +				term->name = d->iTerminal; +			}  			return 0; -		case UAC_FEATURE_UNIT: -			id = p1[4]; +		case UAC_FEATURE_UNIT: { +			/* the header is the same for v1 and v2 */ +			struct uac_feature_unit_descriptor *d = p1; +			id = d->bUnitID;  			break; /* continue to parse */ -		case UAC_MIXER_UNIT: -			term->type = p1[2] << 16; /* virtual type */ -			term->channels = p1[5 + p1[4]]; -			term->chconfig = combine_word(p1 + 6 + p1[4]); -			term->name = p1[p1[0] - 1]; +		} +		case UAC_MIXER_UNIT: { +			struct uac_mixer_unit_descriptor *d = p1; +			term->type = d->bDescriptorSubtype << 16; /* virtual type */ +			term->channels = uac_mixer_unit_bNrChannels(d); +			term->chconfig = uac_mixer_unit_wChannelConfig(d, state->mixer->protocol); +			term->name = uac_mixer_unit_iMixer(d);  			return 0; -		case UAC_SELECTOR_UNIT: +		} +		case UAC_SELECTOR_UNIT: { +			struct uac_selector_unit_descriptor *d = p1;  			/* call recursively to retrieve the channel info */ -			if (check_input_term(state, p1[5], term) < 0) +			if (check_input_term(state, d->baSourceID[0], term) < 0)  				return -ENODEV; -			term->type = p1[2] << 16; /* virtual type */ +			term->type = d->bDescriptorSubtype << 16; /* virtual type */  			term->id = id; -			term->name = p1[9 + p1[0] - 1]; +			term->name = uac_selector_unit_iSelector(d);  			return 0; +		}  		case UAC_PROCESSING_UNIT_V1: -		case UAC_EXTENSION_UNIT_V1: -			if (p1[6] == 1) { -				id = p1[7]; +		case UAC_EXTENSION_UNIT_V1: { +			struct uac_processing_unit_descriptor *d = p1; +			if (d->bNrInPins) { +				id = d->baSourceID[0];  				break; /* continue to parse */  			} -			term->type = p1[2] << 16; /* virtual type */ -			term->channels = p1[7 + p1[6]]; -			term->chconfig = combine_word(p1 + 8 + p1[6]); -			term->name = p1[12 + p1[6] + p1[11 + p1[6]]]; +			term->type = d->bDescriptorSubtype << 16; /* virtual type */ +			term->channels = uac_processing_unit_bNrChannels(d); +			term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol); +			term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol);  			return 0; +		}  		default:  			return -ENODEV;  		} @@ -764,7 +770,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)  			int last_valid_res = cval->res;  			while (cval->res > 1) { -				if (set_ctl_value(cval, UAC_SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0) +				if (snd_usb_mixer_set_ctl_value(cval, UAC_SET_RES, +								(cval->control << 8) | minchn, cval->res / 2) < 0)  					break;  				cval->res /= 2;  			} @@ -929,6 +936,15 @@ static struct snd_kcontrol_new usb_feature_unit_ctl = {  	.put = mixer_ctl_feature_put,  }; +/* the read-only variant */ +static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { +	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +	.name = "", /* will be filled later manually */ +	.info = mixer_ctl_feature_info, +	.get = mixer_ctl_feature_get, +	.put = NULL, +}; +  /*   * build a feature control @@ -939,20 +955,22 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)  	return strlcat(kctl->id.name, str, sizeof(kctl->id.name));  } -static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, +static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  			      unsigned int ctl_mask, int control, -			      struct usb_audio_term *iterm, int unitid) +			      struct usb_audio_term *iterm, int unitid, +			      int read_only)  { +	struct uac_feature_unit_descriptor *desc = raw_desc;  	unsigned int len = 0;  	int mapped_name = 0; -	int nameid = desc[desc[0] - 1]; +	int nameid = uac_feature_unit_iFeature(desc);  	struct snd_kcontrol *kctl;  	struct usb_mixer_elem_info *cval;  	const struct usbmix_name_map *map;  	control++; /* change from zero-based to 1-based value */ -	if (control == USB_FEATURE_GEQ) { +	if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) {  		/* FIXME: not supported yet */  		return;  	} @@ -984,7 +1002,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,  	/* get min/max values */  	get_min_max(cval, 0); -	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); +	if (read_only) +		kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); +	else +		kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); +  	if (! kctl) {  		snd_printk(KERN_ERR "cannot malloc kcontrol\n");  		kfree(cval); @@ -999,8 +1021,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,  				kctl->id.name, sizeof(kctl->id.name));  	switch (control) { -	case USB_FEATURE_MUTE: -	case USB_FEATURE_VOLUME: +	case UAC_MUTE_CONTROL: +	case UAC_VOLUME_CONTROL:  		/* determine the control name.  the rule is:  		 * - if a name id is given in descriptor, use it.  		 * - if the connected input can be determined, then use the name @@ -1027,9 +1049,9 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,  				len = append_ctl_name(kctl, " Playback");  			}  		} -		append_ctl_name(kctl, control == USB_FEATURE_MUTE ? +		append_ctl_name(kctl, control == UAC_MUTE_CONTROL ?  				" Switch" : " Volume"); -		if (control == USB_FEATURE_VOLUME) { +		if (control == UAC_VOLUME_CONTROL) {  			kctl->tlv.c = mixer_vol_tlv;  			kctl->vd[0].access |=   				SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -1094,49 +1116,92 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  	struct usb_audio_term iterm;  	unsigned int master_bits, first_ch_bits;  	int err, csize; -	struct uac_feature_unit_descriptor *ftr = _ftr; +	struct uac_feature_unit_descriptor *hdr = _ftr; +	__u8 *bmaControls; + +	if (state->mixer->protocol == UAC_VERSION_1) { +		csize = hdr->bControlSize; +		channels = (hdr->bLength - 7) / csize - 1; +		bmaControls = hdr->bmaControls; +	} else { +		struct uac2_feature_unit_descriptor *ftr = _ftr; +		csize = 4; +		channels = (hdr->bLength - 6) / 4; +		bmaControls = ftr->bmaControls; +	} -	if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) { +	if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) {  		snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid);  		return -EINVAL;  	}  	/* parse the source unit */ -	if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0) +	if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0)  		return err;  	/* determine the input source type and name */ -	if (check_input_term(state, ftr->bSourceID, &iterm) < 0) +	if (check_input_term(state, hdr->bSourceID, &iterm) < 0)  		return -EINVAL; -	channels = (ftr->bLength - 7) / csize - 1; - -	master_bits = snd_usb_combine_bytes(ftr->controls, csize); +	master_bits = snd_usb_combine_bytes(bmaControls, csize);  	/* master configuration quirks */  	switch (state->chip->usb_id) {  	case USB_ID(0x08bb, 0x2702):  		snd_printk(KERN_INFO  			   "usbmixer: master volume quirk for PCM2702 chip\n");  		/* disable non-functional volume control */ -		master_bits &= ~(1 << (USB_FEATURE_VOLUME - 1)); +		master_bits &= ~UAC_FU_VOLUME;  		break;  	}  	if (channels > 0) -		first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize); +		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);  	else  		first_ch_bits = 0; -	/* check all control types */ -	for (i = 0; i < 10; i++) { -		unsigned int ch_bits = 0; -		for (j = 0; j < channels; j++) { -			unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize); -			if (mask & (1 << i)) -				ch_bits |= (1 << j); + +	if (state->mixer->protocol == UAC_VERSION_1) { +		/* check all control types */ +		for (i = 0; i < 10; i++) { +			unsigned int ch_bits = 0; +			for (j = 0; j < channels; j++) { +				unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); +				if (mask & (1 << i)) +					ch_bits |= (1 << j); +			} +			/* audio class v1 controls are never read-only */ +			if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ +				build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, 0); +			if (master_bits & (1 << i)) +				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0); +		} +	} else { /* UAC_VERSION_2 */ +		for (i = 0; i < 30/2; i++) { +			/* From the USB Audio spec v2.0: +			   bmaControls() is a (ch+1)-element array of 4-byte bitmaps, +			   each containing a set of bit pairs. If a Control is present, +			   it must be Host readable. If a certain Control is not +			   present then the bit pair must be set to 0b00. +			   If a Control is present but read-only, the bit pair must be +			   set to 0b01. If a Control is also Host programmable, the bit +			   pair must be set to 0b11. The value 0b10 is not allowed. */ +			unsigned int ch_bits = 0; +			unsigned int ch_read_only = 0; + +			for (j = 0; j < channels; j++) { +				unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); +				if (mask & (1 << (i * 2))) { +					ch_bits |= (1 << j); +					if (~mask & (1 << ((i * 2) + 1))) +						ch_read_only |= (1 << j); +				} +			} + +			/* FIXME: the whole unit is read-only if any of the channels is marked read-only */ +			if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ +				build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); +			if (master_bits & (1 << i * 2)) +				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, +						  ~master_bits & (1 << ((i * 2) + 1)));  		} -		if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ -			build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid); -		if (master_bits & (1 << i)) -			build_feature_ctl(state, _ftr, 0, i, &iterm, unitid);  	}  	return 0; @@ -1154,13 +1219,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void   * input channel number (zero based) is given in control field instead.   */ -static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, +static void build_mixer_unit_ctl(struct mixer_build *state, +				 struct uac_mixer_unit_descriptor *desc,  				 int in_pin, int in_ch, int unitid,  				 struct usb_audio_term *iterm)  {  	struct usb_mixer_elem_info *cval; -	unsigned int input_pins = desc[4]; -	unsigned int num_outs = desc[5 + input_pins]; +	unsigned int num_outs = uac_mixer_unit_bNrChannels(desc);  	unsigned int i, len;  	struct snd_kcontrol *kctl;  	const struct usbmix_name_map *map; @@ -1178,7 +1243,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,  	cval->control = in_ch + 1; /* based on 1 */  	cval->val_type = USB_MIXER_S16;  	for (i = 0; i < num_outs; i++) { -		if (check_matrix_bitmap(desc + 9 + input_pins, in_ch, i, num_outs)) { +		if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol), in_ch, i, num_outs)) {  			cval->cmask |= (1 << i);  			cval->channels++;  		} @@ -1211,18 +1276,19 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,  /*   * parse a mixer unit   */ -static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigned char *desc) +static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *raw_desc)  { +	struct uac_mixer_unit_descriptor *desc = raw_desc;  	struct usb_audio_term iterm;  	int input_pins, num_ins, num_outs;  	int pin, ich, err; -	if (desc[0] < 11 || ! (input_pins = desc[4]) || ! (num_outs = desc[5 + input_pins])) { +	if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) {  		snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);  		return -EINVAL;  	}  	/* no bmControls field (e.g. Maya44) -> ignore */ -	if (desc[0] <= 10 + input_pins) { +	if (desc->bLength <= 10 + input_pins) {  		snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);  		return 0;  	} @@ -1230,10 +1296,10 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigne  	num_ins = 0;  	ich = 0;  	for (pin = 0; pin < input_pins; pin++) { -		err = parse_audio_unit(state, desc[5 + pin]); +		err = parse_audio_unit(state, desc->baSourceID[pin]);  		if (err < 0)  			return err; -		err = check_input_term(state, desc[5 + pin], &iterm); +		err = check_input_term(state, desc->baSourceID[pin], &iterm);  		if (err < 0)  			return err;  		num_ins += iterm.channels; @@ -1241,7 +1307,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigne  			int och, ich_has_controls = 0;  			for (och = 0; och < num_outs; ++och) { -				if (check_matrix_bitmap(desc + 9 + input_pins, +				if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol),  							ich, och, num_outs)) {  					ich_has_controls = 1;  					break; @@ -1402,9 +1468,10 @@ static struct procunit_info extunits[] = {  /*   * build a processing/extension unit   */ -static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name) +static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw_desc, struct procunit_info *list, char *name)  { -	int num_ins = dsc[6]; +	struct uac_processing_unit_descriptor *desc = raw_desc; +	int num_ins = desc->bNrInPins;  	struct usb_mixer_elem_info *cval;  	struct snd_kcontrol *kctl;  	int i, err, nameid, type, len; @@ -1419,17 +1486,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned  		0, NULL, default_value_info  	}; -	if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) { +	if (desc->bLength < 13 || desc->bLength < 13 + num_ins || +	    desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {  		snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);  		return -EINVAL;  	}  	for (i = 0; i < num_ins; i++) { -		if ((err = parse_audio_unit(state, dsc[7 + i])) < 0) +		if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)  			return err;  	} -	type = combine_word(&dsc[4]); +	type = le16_to_cpu(desc->wProcessType);  	for (info = list; info && info->type; info++)  		if (info->type == type)  			break; @@ -1437,8 +1505,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned  		info = &default_info;  	for (valinfo = info->values; valinfo->control; valinfo++) { -		/* FIXME: bitmap might be longer than 8bit */ -		if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) +		__u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol); + +		if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1))))  			continue;  		map = find_map(state, unitid, valinfo->control);  		if (check_ignored_ctl(map)) @@ -1456,9 +1525,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned  		/* get min/max values */  		if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { +			__u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);  			/* FIXME: hard-coded */  			cval->min = 1; -			cval->max = dsc[15]; +			cval->max = control_spec[0];  			cval->res = 1;  			cval->initialized = 1;  		} else { @@ -1488,7 +1558,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned  		else if (info->name)  			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));  		else { -			nameid = dsc[12 + num_ins + dsc[11 + num_ins]]; +			nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);  			len = 0;  			if (nameid)  				len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); @@ -1507,14 +1577,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned  } -static int parse_audio_processing_unit(struct mixer_build *state, int unitid, unsigned char *desc) +static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc)  { -	return build_audio_procunit(state, unitid, desc, procunits, "Processing Unit"); +	return build_audio_procunit(state, unitid, raw_desc, procunits, "Processing Unit");  } -static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) +static int parse_audio_extension_unit(struct mixer_build *state, int unitid, void *raw_desc)  { -	return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); +	/* Note that we parse extension units with processing unit descriptors. +	 * That's ok as the layout is the same */ +	return build_audio_procunit(state, unitid, raw_desc, extunits, "Extension Unit");  } @@ -1616,9 +1688,9 @@ static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl)  /*   * parse a selector unit   */ -static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsigned char *desc) +static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void *raw_desc)  { -	unsigned int num_ins = desc[4]; +	struct uac_selector_unit_descriptor *desc = raw_desc;  	unsigned int i, nameid, len;  	int err;  	struct usb_mixer_elem_info *cval; @@ -1626,17 +1698,17 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi  	const struct usbmix_name_map *map;  	char **namelist; -	if (! num_ins || desc[0] < 5 + num_ins) { +	if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {  		snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);  		return -EINVAL;  	} -	for (i = 0; i < num_ins; i++) { -		if ((err = parse_audio_unit(state, desc[5 + i])) < 0) +	for (i = 0; i < desc->bNrInPins; i++) { +		if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)  			return err;  	} -	if (num_ins == 1) /* only one ? nonsense! */ +	if (desc->bNrInPins == 1) /* only one ? nonsense! */  		return 0;  	map = find_map(state, unitid, 0); @@ -1653,18 +1725,18 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi  	cval->val_type = USB_MIXER_U8;  	cval->channels = 1;  	cval->min = 1; -	cval->max = num_ins; +	cval->max = desc->bNrInPins;  	cval->res = 1;  	cval->initialized = 1; -	namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL); +	namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);  	if (! namelist) {  		snd_printk(KERN_ERR "cannot malloc\n");  		kfree(cval);  		return -ENOMEM;  	}  #define MAX_ITEM_NAME_LEN	64 -	for (i = 0; i < num_ins; i++) { +	for (i = 0; i < desc->bNrInPins; i++) {  		struct usb_audio_term iterm;  		len = 0;  		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); @@ -1678,7 +1750,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi  		}  		len = check_mapped_selector_name(state, unitid, i, namelist[i],  						 MAX_ITEM_NAME_LEN); -		if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) +		if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0)  			len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);  		if (! len)  			sprintf(namelist[i], "Input %d", i); @@ -1694,7 +1766,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi  	kctl->private_value = (unsigned long)namelist;  	kctl->private_free = usb_mixer_selector_elem_free; -	nameid = desc[desc[0] - 1]; +	nameid = uac_selector_unit_iSelector(desc);  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));  	if (len)  		; @@ -1713,7 +1785,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi  	}  	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", -		    cval->id, kctl->id.name, num_ins); +		    cval->id, kctl->id.name, desc->bNrInPins);  	if ((err = add_control_to_empty(state, kctl)) < 0)  		return err; @@ -1748,9 +1820,17 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)  	case UAC_FEATURE_UNIT:  		return parse_audio_feature_unit(state, unitid, p1);  	case UAC_PROCESSING_UNIT_V1: -		return parse_audio_processing_unit(state, unitid, p1); +	/*   UAC2_EFFECT_UNIT has the same value */ +		if (state->mixer->protocol == UAC_VERSION_1) +			return parse_audio_processing_unit(state, unitid, p1); +		else +			return 0; /* FIXME - effect units not implemented yet */  	case UAC_EXTENSION_UNIT_V1: -		return parse_audio_extension_unit(state, unitid, p1); +	/*   UAC2_PROCESSING_UNIT_V2 has the same value */ +		if (state->mixer->protocol == UAC_VERSION_1) +			return parse_audio_extension_unit(state, unitid, p1); +		else /* UAC_VERSION_2 */ +			return parse_audio_processing_unit(state, unitid, p1);  	default:  		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);  		return -EINVAL; @@ -1783,11 +1863,11 @@ static int snd_usb_mixer_dev_free(struct snd_device *device)   */  static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)  { -	struct uac_output_terminal_descriptor_v1 *desc;  	struct mixer_build state;  	int err;  	const struct usbmix_ctl_map *map;  	struct usb_host_interface *hostif; +	void *p;  	hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];  	memset(&state, 0, sizeof(state)); @@ -1806,23 +1886,39 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)  		}  	} -	desc = NULL; -	while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) { -		if (desc->bLength < 9) -			continue; /* invalid descriptor? */ -		set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */ -		state.oterm.id = desc->bTerminalID; -		state.oterm.type = le16_to_cpu(desc->wTerminalType); -		state.oterm.name = desc->iTerminal; -		err = parse_audio_unit(&state, desc->bSourceID); -		if (err < 0) -			return err; +	p = NULL; +	while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { +		if (mixer->protocol == UAC_VERSION_1) { +			struct uac_output_terminal_descriptor_v1 *desc = p; + +			if (desc->bLength < sizeof(*desc)) +				continue; /* invalid descriptor? */ +			set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */ +			state.oterm.id = desc->bTerminalID; +			state.oterm.type = le16_to_cpu(desc->wTerminalType); +			state.oterm.name = desc->iTerminal; +			err = parse_audio_unit(&state, desc->bSourceID); +			if (err < 0) +				return err; +		} else { /* UAC_VERSION_2 */ +			struct uac2_output_terminal_descriptor *desc = p; + +			if (desc->bLength < sizeof(*desc)) +				continue; /* invalid descriptor? */ +			set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */ +			state.oterm.id = desc->bTerminalID; +			state.oterm.type = le16_to_cpu(desc->wTerminalType); +			state.oterm.name = desc->iTerminal; +			err = parse_audio_unit(&state, desc->bSourceID); +			if (err < 0) +				return err; +		}  	} +  	return 0;  } -static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, -				    int unitid) +void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)  {  	struct usb_mixer_elem_info *info; @@ -1871,34 +1967,6 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,  	}  } -static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, -					int unitid) -{ -	if (!mixer->rc_cfg) -		return; -	/* unit ids specific to Extigy/Audigy 2 NX: */ -	switch (unitid) { -	case 0: /* remote control */ -		mixer->rc_urb->dev = mixer->chip->dev; -		usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); -		break; -	case 4: /* digital in jack */ -	case 7: /* line in jacks */ -	case 19: /* speaker out jacks */ -	case 20: /* headphones out jack */ -		break; -	/* live24ext: 4 = line-in jack */ -	case 3:	/* hp-out jack (may actuate Mute) */ -		if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || -		    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) -			snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); -		break; -	default: -		snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); -		break; -	} -} -  static void snd_usb_mixer_status_complete(struct urb *urb)  {  	struct usb_mixer_interface *mixer = urb->context; @@ -1916,7 +1984,7 @@ static void snd_usb_mixer_status_complete(struct urb *urb)  			if (!(buf[0] & 0x40))  				snd_usb_mixer_notify_id(mixer, buf[1]);  			else -				snd_usb_mixer_memory_change(mixer, buf[1]); +				snd_usb_mixer_rc_memory_change(mixer, buf[1]);  		}  	}  	if (urb->status != -ENOENT && urb->status != -ECONNRESET) { @@ -1960,296 +2028,6 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)  	return 0;  } -static void snd_usb_soundblaster_remote_complete(struct urb *urb) -{ -	struct usb_mixer_interface *mixer = urb->context; -	const struct rc_config *rc = mixer->rc_cfg; -	u32 code; - -	if (urb->status < 0 || urb->actual_length < rc->min_packet_length) -		return; - -	code = mixer->rc_buffer[rc->offset]; -	if (rc->length == 2) -		code |= mixer->rc_buffer[rc->offset + 1] << 8; - -	/* the Mute button actually changes the mixer control */ -	if (code == rc->mute_code) -		snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); -	mixer->rc_code = code; -	wmb(); -	wake_up(&mixer->rc_waitq); -} - -static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, -				     long count, loff_t *offset) -{ -	struct usb_mixer_interface *mixer = hw->private_data; -	int err; -	u32 rc_code; - -	if (count != 1 && count != 4) -		return -EINVAL; -	err = wait_event_interruptible(mixer->rc_waitq, -				       (rc_code = xchg(&mixer->rc_code, 0)) != 0); -	if (err == 0) { -		if (count == 1) -			err = put_user(rc_code, buf); -		else -			err = put_user(rc_code, (u32 __user *)buf); -	} -	return err < 0 ? err : count; -} - -static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, -					    poll_table *wait) -{ -	struct usb_mixer_interface *mixer = hw->private_data; - -	poll_wait(file, &mixer->rc_waitq, wait); -	return mixer->rc_code ? POLLIN | POLLRDNORM : 0; -} - -static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) -{ -	struct snd_hwdep *hwdep; -	int err, len, i; - -	for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) -		if (rc_configs[i].usb_id == mixer->chip->usb_id) -			break; -	if (i >= ARRAY_SIZE(rc_configs)) -		return 0; -	mixer->rc_cfg = &rc_configs[i]; - -	len = mixer->rc_cfg->packet_length; -	 -	init_waitqueue_head(&mixer->rc_waitq); -	err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); -	if (err < 0) -		return err; -	snprintf(hwdep->name, sizeof(hwdep->name), -		 "%s remote control", mixer->chip->card->shortname); -	hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; -	hwdep->private_data = mixer; -	hwdep->ops.read = snd_usb_sbrc_hwdep_read; -	hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; -	hwdep->exclusive = 1; - -	mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (!mixer->rc_urb) -		return -ENOMEM; -	mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); -	if (!mixer->rc_setup_packet) { -		usb_free_urb(mixer->rc_urb); -		mixer->rc_urb = NULL; -		return -ENOMEM; -	} -	mixer->rc_setup_packet->bRequestType = -		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; -	mixer->rc_setup_packet->bRequest = UAC_GET_MEM; -	mixer->rc_setup_packet->wValue = cpu_to_le16(0); -	mixer->rc_setup_packet->wIndex = cpu_to_le16(0); -	mixer->rc_setup_packet->wLength = cpu_to_le16(len); -	usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, -			     usb_rcvctrlpipe(mixer->chip->dev, 0), -			     (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, -			     snd_usb_soundblaster_remote_complete, mixer); -	return 0; -} - -#define snd_audigy2nx_led_info		snd_ctl_boolean_mono_info - -static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ -	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); -	int index = kcontrol->private_value; - -	ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; -	return 0; -} - -static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ -	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); -	int index = kcontrol->private_value; -	int value = ucontrol->value.integer.value[0]; -	int err, changed; - -	if (value > 1) -		return -EINVAL; -	changed = value != mixer->audigy2nx_leds[index]; -	err = snd_usb_ctl_msg(mixer->chip->dev, -			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, -			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, -			      value, index + 2, NULL, 0, 100); -	if (err < 0) -		return err; -	mixer->audigy2nx_leds[index] = value; -	return changed; -} - -static struct snd_kcontrol_new snd_audigy2nx_controls[] = { -	{ -		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, -		.name = "CMSS LED Switch", -		.info = snd_audigy2nx_led_info, -		.get = snd_audigy2nx_led_get, -		.put = snd_audigy2nx_led_put, -		.private_value = 0, -	}, -	{ -		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, -		.name = "Power LED Switch", -		.info = snd_audigy2nx_led_info, -		.get = snd_audigy2nx_led_get, -		.put = snd_audigy2nx_led_put, -		.private_value = 1, -	}, -	{ -		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, -		.name = "Dolby Digital LED Switch", -		.info = snd_audigy2nx_led_info, -		.get = snd_audigy2nx_led_get, -		.put = snd_audigy2nx_led_put, -		.private_value = 2, -	}, -}; - -static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) -{ -	int i, err; - -	for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { -		if (i > 1 && /* Live24ext has 2 LEDs only */ -			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || -			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) -			break;  -		err = snd_ctl_add(mixer->chip->card, -				  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); -		if (err < 0) -			return err; -	} -	mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ -	return 0; -} - -static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, -				    struct snd_info_buffer *buffer) -{ -	static const struct sb_jack { -		int unitid; -		const char *name; -	}  jacks_audigy2nx[] = { -		{4,  "dig in "}, -		{7,  "line in"}, -		{19, "spk out"}, -		{20, "hph out"}, -		{-1, NULL} -	}, jacks_live24ext[] = { -		{4,  "line in"}, /* &1=Line, &2=Mic*/ -		{3,  "hph out"}, /* headphones */ -		{0,  "RC     "}, /* last command, 6 bytes see rc_config above */ -		{-1, NULL} -	}; -	const struct sb_jack *jacks; -	struct usb_mixer_interface *mixer = entry->private_data; -	int i, err; -	u8 buf[3]; - -	snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); -	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) -		jacks = jacks_audigy2nx; -	else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || -		 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) -		jacks = jacks_live24ext; -	else -		return; - -	for (i = 0; jacks[i].name; ++i) { -		snd_iprintf(buffer, "%s: ", jacks[i].name); -		err = snd_usb_ctl_msg(mixer->chip->dev, -				      usb_rcvctrlpipe(mixer->chip->dev, 0), -				      UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | -				      USB_RECIP_INTERFACE, 0, -				      jacks[i].unitid << 8, buf, 3, 100); -		if (err == 3 && (buf[0] == 3 || buf[0] == 6)) -			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); -		else -			snd_iprintf(buffer, "?\n"); -	} -} - -static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, -				   struct snd_ctl_elem_value *ucontrol) -{ -	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - -	ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); -	return 0; -} - -static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, -				   struct snd_ctl_elem_value *ucontrol) -{ -	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); -	u8 old_status, new_status; -	int err, changed; - -	old_status = mixer->xonar_u1_status; -	if (ucontrol->value.integer.value[0]) -		new_status = old_status | 0x02; -	else -		new_status = old_status & ~0x02; -	changed = new_status != old_status; -	err = snd_usb_ctl_msg(mixer->chip->dev, -			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, -			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, -			      50, 0, &new_status, 1, 100); -	if (err < 0) -		return err; -	mixer->xonar_u1_status = new_status; -	return changed; -} - -static struct snd_kcontrol_new snd_xonar_u1_output_switch = { -	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, -	.name = "Digital Playback Switch", -	.info = snd_ctl_boolean_mono_info, -	.get = snd_xonar_u1_switch_get, -	.put = snd_xonar_u1_switch_put, -}; - -static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) -{ -	int err; - -	err = snd_ctl_add(mixer->chip->card, -			  snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); -	if (err < 0) -		return err; -	mixer->xonar_u1_status = 0x05; -	return 0; -} - -void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, -			       unsigned char samplerate_id) -{ -	struct usb_mixer_interface *mixer; -	struct usb_mixer_elem_info *cval; -	int unitid = 12; /* SamleRate ExtensionUnit ID */ - -	list_for_each_entry(mixer, &chip->mixer_list, list) { -		cval = mixer->id_elems[unitid]; -		if (cval) { -			set_cur_ctl_value(cval, cval->control << 8, -					  samplerate_id); -			snd_usb_mixer_notify_id(mixer, unitid); -		} -		break; -	} -} -  int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,  			 int ignore_error)  { @@ -2259,7 +2037,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,  	struct usb_mixer_interface *mixer;  	struct snd_info_entry *entry;  	struct usb_host_interface *host_iface; -	int err, protocol; +	int err;  	strcpy(chip->card->mixername, "USB Mixer"); @@ -2277,38 +2055,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,  	}  	host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; -	protocol = host_iface->desc.bInterfaceProtocol; - -	/* FIXME! */ -	if (protocol != UAC_VERSION_1) { -		snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n", -					protocol); -		return 0; -	} +	mixer->protocol = get_iface_desc(host_iface)->bInterfaceProtocol;  	if ((err = snd_usb_mixer_controls(mixer)) < 0 ||  	    (err = snd_usb_mixer_status_create(mixer)) < 0)  		goto _error; -	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) -		goto _error; - -	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || -	    mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || -	    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { -		if ((err = snd_audigy2nx_controls_create(mixer)) < 0) -			goto _error; -		if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) -			snd_info_set_text_ops(entry, mixer, -					      snd_audigy2nx_proc_read); -	} - -	if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || -	    mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { -		err = snd_xonar_u1_controls_create(mixer); -		if (err < 0) -			goto _error; -	} +	snd_usb_mixer_apply_create_quirk(mixer);  	err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);  	if (err < 0) @@ -2329,7 +2082,7 @@ _error:  void snd_usb_mixer_disconnect(struct list_head *p)  {  	struct usb_mixer_interface *mixer; -	 +  	mixer = list_entry(p, struct usb_mixer_interface, list);  	usb_kill_urb(mixer->urb);  	usb_kill_urb(mixer->rc_urb); diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h new file mode 100644 index 00000000000..130123854a6 --- /dev/null +++ b/sound/usb/mixer.h @@ -0,0 +1,55 @@ +#ifndef __USBMIXER_H +#define __USBMIXER_H + +struct usb_mixer_interface { +	struct snd_usb_audio *chip; +	unsigned int ctrlif; +	struct list_head list; +	unsigned int ignore_ctl_error; +	struct urb *urb; +	/* array[MAX_ID_ELEMS], indexed by unit id */ +	struct usb_mixer_elem_info **id_elems; + +	/* the usb audio specification version this interface complies to */ +	int protocol; + +	/* Sound Blaster remote control stuff */ +	const struct rc_config *rc_cfg; +	u32 rc_code; +	wait_queue_head_t rc_waitq; +	struct urb *rc_urb; +	struct usb_ctrlrequest *rc_setup_packet; +	u8 rc_buffer[6]; + +	u8 audigy2nx_leds[3]; +	u8 xonar_u1_status; +}; + +#define MAX_CHANNELS	10	/* max logical channels */ + +struct usb_mixer_elem_info { +	struct usb_mixer_interface *mixer; +	struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ +	struct snd_ctl_elem_id *elem_id; +	unsigned int id; +	unsigned int control;	/* CS or ICN (high byte) */ +	unsigned int cmask; /* channel mask bitmap: 0 = master */ +	int channels; +	int val_type; +	int min, max, res; +	int dBmin, dBmax; +	int cached; +	int cache_val[MAX_CHANNELS]; +	u8 initialized; +}; + +int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, +			 int ignore_error); +void snd_usb_mixer_disconnect(struct list_head *p); + +void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); + +int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, +				int request, int validx, int value_set); + +#endif /* __USBMIXER_H */ diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/mixer_maps.c index 79e903a6086..d93fc89beba 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = {  	/* 16: MU (w/o controls) */  	{ 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */  	{ 17, "Channel Routing", 2 },	/* PU: mode select */ -	{ 18, "Tone Control - Bass", USB_FEATURE_BASS }, /* FU */ -	{ 18, "Tone Control - Treble", USB_FEATURE_TREBLE }, /* FU */ +	{ 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */ +	{ 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */  	{ 18, "Master Playback" }, /* FU; others */  	/* 19: OT speaker */  	/* 20: OT headphone */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c new file mode 100644 index 00000000000..e7df1e5e3f2 --- /dev/null +++ b/sound/usb/mixer_quirks.c @@ -0,0 +1,412 @@ +/* + *   USB Audio Driver for ALSA + * + *   Quirks and vendor-specific extensions for mixer interfaces + * + *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + *   Many codes borrowed from audio.c by + *	    Alan Cox (alan@lxorguk.ukuu.org.uk) + *	    Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> + +#include <sound/core.h> +#include <sound/control.h> +#include <sound/hwdep.h> +#include <sound/info.h> + +#include "usbaudio.h" +#include "mixer.h" +#include "mixer_quirks.h" +#include "helper.h" + +/* + * Sound Blaster remote control configuration + * + * format of remote control data: + * Extigy:       xx 00 + * Audigy 2 NX:  06 80 xx 00 00 00 + * Live! 24-bit: 06 80 xx yy 22 83 + */ +static const struct rc_config { +	u32 usb_id; +	u8  offset; +	u8  length; +	u8  packet_length; +	u8  min_packet_length; /* minimum accepted length of the URB result */ +	u8  mute_mixer_id; +	u32 mute_code; +} rc_configs[] = { +	{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */ +	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */ +	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */ +	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */ +}; + +static void snd_usb_soundblaster_remote_complete(struct urb *urb) +{ +	struct usb_mixer_interface *mixer = urb->context; +	const struct rc_config *rc = mixer->rc_cfg; +	u32 code; + +	if (urb->status < 0 || urb->actual_length < rc->min_packet_length) +		return; + +	code = mixer->rc_buffer[rc->offset]; +	if (rc->length == 2) +		code |= mixer->rc_buffer[rc->offset + 1] << 8; + +	/* the Mute button actually changes the mixer control */ +	if (code == rc->mute_code) +		snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); +	mixer->rc_code = code; +	wmb(); +	wake_up(&mixer->rc_waitq); +} + +static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, +				     long count, loff_t *offset) +{ +	struct usb_mixer_interface *mixer = hw->private_data; +	int err; +	u32 rc_code; + +	if (count != 1 && count != 4) +		return -EINVAL; +	err = wait_event_interruptible(mixer->rc_waitq, +				       (rc_code = xchg(&mixer->rc_code, 0)) != 0); +	if (err == 0) { +		if (count == 1) +			err = put_user(rc_code, buf); +		else +			err = put_user(rc_code, (u32 __user *)buf); +	} +	return err < 0 ? err : count; +} + +static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, +					    poll_table *wait) +{ +	struct usb_mixer_interface *mixer = hw->private_data; + +	poll_wait(file, &mixer->rc_waitq, wait); +	return mixer->rc_code ? POLLIN | POLLRDNORM : 0; +} + +static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) +{ +	struct snd_hwdep *hwdep; +	int err, len, i; + +	for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) +		if (rc_configs[i].usb_id == mixer->chip->usb_id) +			break; +	if (i >= ARRAY_SIZE(rc_configs)) +		return 0; +	mixer->rc_cfg = &rc_configs[i]; + +	len = mixer->rc_cfg->packet_length; + +	init_waitqueue_head(&mixer->rc_waitq); +	err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); +	if (err < 0) +		return err; +	snprintf(hwdep->name, sizeof(hwdep->name), +		 "%s remote control", mixer->chip->card->shortname); +	hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; +	hwdep->private_data = mixer; +	hwdep->ops.read = snd_usb_sbrc_hwdep_read; +	hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; +	hwdep->exclusive = 1; + +	mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!mixer->rc_urb) +		return -ENOMEM; +	mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); +	if (!mixer->rc_setup_packet) { +		usb_free_urb(mixer->rc_urb); +		mixer->rc_urb = NULL; +		return -ENOMEM; +	} +	mixer->rc_setup_packet->bRequestType = +		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; +	mixer->rc_setup_packet->bRequest = UAC_GET_MEM; +	mixer->rc_setup_packet->wValue = cpu_to_le16(0); +	mixer->rc_setup_packet->wIndex = cpu_to_le16(0); +	mixer->rc_setup_packet->wLength = cpu_to_le16(len); +	usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, +			     usb_rcvctrlpipe(mixer->chip->dev, 0), +			     (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, +			     snd_usb_soundblaster_remote_complete, mixer); +	return 0; +} + +#define snd_audigy2nx_led_info		snd_ctl_boolean_mono_info + +static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	int index = kcontrol->private_value; + +	ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; +	return 0; +} + +static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	int index = kcontrol->private_value; +	int value = ucontrol->value.integer.value[0]; +	int err, changed; + +	if (value > 1) +		return -EINVAL; +	changed = value != mixer->audigy2nx_leds[index]; +	err = snd_usb_ctl_msg(mixer->chip->dev, +			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, +			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			      value, index + 2, NULL, 0, 100); +	if (err < 0) +		return err; +	mixer->audigy2nx_leds[index] = value; +	return changed; +} + +static struct snd_kcontrol_new snd_audigy2nx_controls[] = { +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "CMSS LED Switch", +		.info = snd_audigy2nx_led_info, +		.get = snd_audigy2nx_led_get, +		.put = snd_audigy2nx_led_put, +		.private_value = 0, +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Power LED Switch", +		.info = snd_audigy2nx_led_info, +		.get = snd_audigy2nx_led_get, +		.put = snd_audigy2nx_led_put, +		.private_value = 1, +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Dolby Digital LED Switch", +		.info = snd_audigy2nx_led_info, +		.get = snd_audigy2nx_led_get, +		.put = snd_audigy2nx_led_put, +		.private_value = 2, +	}, +}; + +static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) +{ +	int i, err; + +	for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { +		if (i > 1 && /* Live24ext has 2 LEDs only */ +			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || +			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) +			break;  +		err = snd_ctl_add(mixer->chip->card, +				  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); +		if (err < 0) +			return err; +	} +	mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ +	return 0; +} + +static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, +				    struct snd_info_buffer *buffer) +{ +	static const struct sb_jack { +		int unitid; +		const char *name; +	}  jacks_audigy2nx[] = { +		{4,  "dig in "}, +		{7,  "line in"}, +		{19, "spk out"}, +		{20, "hph out"}, +		{-1, NULL} +	}, jacks_live24ext[] = { +		{4,  "line in"}, /* &1=Line, &2=Mic*/ +		{3,  "hph out"}, /* headphones */ +		{0,  "RC     "}, /* last command, 6 bytes see rc_config above */ +		{-1, NULL} +	}; +	const struct sb_jack *jacks; +	struct usb_mixer_interface *mixer = entry->private_data; +	int i, err; +	u8 buf[3]; + +	snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); +	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) +		jacks = jacks_audigy2nx; +	else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || +		 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) +		jacks = jacks_live24ext; +	else +		return; + +	for (i = 0; jacks[i].name; ++i) { +		snd_iprintf(buffer, "%s: ", jacks[i].name); +		err = snd_usb_ctl_msg(mixer->chip->dev, +				      usb_rcvctrlpipe(mixer->chip->dev, 0), +				      UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | +				      USB_RECIP_INTERFACE, 0, +				      jacks[i].unitid << 8, buf, 3, 100); +		if (err == 3 && (buf[0] == 3 || buf[0] == 6)) +			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); +		else +			snd_iprintf(buffer, "?\n"); +	} +} + +static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, +				   struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + +	ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); +	return 0; +} + +static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, +				   struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	u8 old_status, new_status; +	int err, changed; + +	old_status = mixer->xonar_u1_status; +	if (ucontrol->value.integer.value[0]) +		new_status = old_status | 0x02; +	else +		new_status = old_status & ~0x02; +	changed = new_status != old_status; +	err = snd_usb_ctl_msg(mixer->chip->dev, +			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, +			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			      50, 0, &new_status, 1, 100); +	if (err < 0) +		return err; +	mixer->xonar_u1_status = new_status; +	return changed; +} + +static struct snd_kcontrol_new snd_xonar_u1_output_switch = { +	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +	.name = "Digital Playback Switch", +	.info = snd_ctl_boolean_mono_info, +	.get = snd_xonar_u1_switch_get, +	.put = snd_xonar_u1_switch_put, +}; + +static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) +{ +	int err; + +	err = snd_ctl_add(mixer->chip->card, +			  snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); +	if (err < 0) +		return err; +	mixer->xonar_u1_status = 0x05; +	return 0; +} + +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, +			       unsigned char samplerate_id) +{ +	struct usb_mixer_interface *mixer; +	struct usb_mixer_elem_info *cval; +	int unitid = 12; /* SamleRate ExtensionUnit ID */ + +	list_for_each_entry(mixer, &chip->mixer_list, list) { +		cval = mixer->id_elems[unitid]; +		if (cval) { +			snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, +						    cval->control << 8, +						    samplerate_id); +			snd_usb_mixer_notify_id(mixer, unitid); +		} +		break; +	} +} + +int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) +{ +	int err; +	struct snd_info_entry *entry; + +	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) +		return err; + +	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || +	    mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || +	    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { +		if ((err = snd_audigy2nx_controls_create(mixer)) < 0) +			return err; +		if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) +			snd_info_set_text_ops(entry, mixer, +					      snd_audigy2nx_proc_read); +	} + +	if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || +	    mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { +		err = snd_xonar_u1_controls_create(mixer); +		if (err < 0) +			return err; +	} + +	return 0; +} + +void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, +				    int unitid) +{ +	if (!mixer->rc_cfg) +		return; +	/* unit ids specific to Extigy/Audigy 2 NX: */ +	switch (unitid) { +	case 0: /* remote control */ +		mixer->rc_urb->dev = mixer->chip->dev; +		usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); +		break; +	case 4: /* digital in jack */ +	case 7: /* line in jacks */ +	case 19: /* speaker out jacks */ +	case 20: /* headphones out jack */ +		break; +	/* live24ext: 4 = line-in jack */ +	case 3:	/* hp-out jack (may actuate Mute) */ +		if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || +		    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) +			snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); +		break; +	default: +		snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); +		break; +	} +} + diff --git a/sound/usb/mixer_quirks.h b/sound/usb/mixer_quirks.h new file mode 100644 index 00000000000..bdbfab09381 --- /dev/null +++ b/sound/usb/mixer_quirks.h @@ -0,0 +1,13 @@ +#ifndef SND_USB_MIXER_QUIRKS_H +#define SND_USB_MIXER_QUIRKS_H + +int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer); + +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, +			       unsigned char samplerate_id); + +void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, +				    int unitid); + +#endif /* SND_USB_MIXER_QUIRKS_H */ + diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c new file mode 100644 index 00000000000..2bf0d77d176 --- /dev/null +++ b/sound/usb/pcm.c @@ -0,0 +1,935 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> + +#include "usbaudio.h" +#include "card.h" +#include "quirks.h" +#include "debug.h" +#include "urb.h" +#include "helper.h" +#include "pcm.h" + +/* + * return the current pcm pointer.  just based on the hwptr_done value. + */ +static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) +{ +	struct snd_usb_substream *subs; +	unsigned int hwptr_done; + +	subs = (struct snd_usb_substream *)substream->runtime->private_data; +	spin_lock(&subs->lock); +	hwptr_done = subs->hwptr_done; +	spin_unlock(&subs->lock); +	return hwptr_done / (substream->runtime->frame_bits >> 3); +} + +/* + * find a matching audio format + */ +static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, +				       unsigned int rate, unsigned int channels) +{ +	struct list_head *p; +	struct audioformat *found = NULL; +	int cur_attr = 0, attr; + +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		fp = list_entry(p, struct audioformat, list); +		if (!(fp->formats & (1uLL << format))) +			continue; +		if (fp->channels != channels) +			continue; +		if (rate < fp->rate_min || rate > fp->rate_max) +			continue; +		if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { +			unsigned int i; +			for (i = 0; i < fp->nr_rates; i++) +				if (fp->rate_table[i] == rate) +					break; +			if (i >= fp->nr_rates) +				continue; +		} +		attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; +		if (! found) { +			found = fp; +			cur_attr = attr; +			continue; +		} +		/* avoid async out and adaptive in if the other method +		 * supports the same format. +		 * this is a workaround for the case like +		 * M-audio audiophile USB. +		 */ +		if (attr != cur_attr) { +			if ((attr == USB_ENDPOINT_SYNC_ASYNC && +			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || +			    (attr == USB_ENDPOINT_SYNC_ADAPTIVE && +			     subs->direction == SNDRV_PCM_STREAM_CAPTURE)) +				continue; +			if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC && +			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || +			    (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE && +			     subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { +				found = fp; +				cur_attr = attr; +				continue; +			} +		} +		/* find the format with the largest max. packet size */ +		if (fp->maxpacksize > found->maxpacksize) { +			found = fp; +			cur_attr = attr; +		} +	} +	return found; +} + +static int init_pitch_v1(struct snd_usb_audio *chip, int iface, +			 struct usb_host_interface *alts, +			 struct audioformat *fmt) +{ +	struct usb_device *dev = chip->dev; +	unsigned int ep; +	unsigned char data[1]; +	int err; + +	ep = get_endpoint(alts, 0)->bEndpointAddress; + +	/* if endpoint doesn't have pitch control, bail out */ +	if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL)) +		return 0; + +	data[0] = 1; +	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, +				   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, +				   UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, +				   data, sizeof(data), 1000)) < 0) { +		snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", +			   dev->devnum, iface, ep); +		return err; +	} + +	return 0; +} + +/* + * initialize the picth control and sample rate + */ +int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, +		       struct usb_host_interface *alts, +		       struct audioformat *fmt) +{ +	struct usb_interface_descriptor *altsd = get_iface_desc(alts); + +	switch (altsd->bInterfaceProtocol) { +	case UAC_VERSION_1: +		return init_pitch_v1(chip, iface, alts, fmt); + +	case UAC_VERSION_2: +		/* not implemented yet */ +		return 0; +	} + +	return -EINVAL; +} + +static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, +			      struct usb_host_interface *alts, +			      struct audioformat *fmt, int rate) +{ +	struct usb_device *dev = chip->dev; +	unsigned int ep; +	unsigned char data[3]; +	int err, crate; + +	ep = get_endpoint(alts, 0)->bEndpointAddress; +	/* if endpoint doesn't have sampling rate control, bail out */ +	if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { +		snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", +				   dev->devnum, iface, fmt->altsetting); +		return 0; +	} + +	data[0] = rate; +	data[1] = rate >> 8; +	data[2] = rate >> 16; +	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, +				   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, +				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, +				   data, sizeof(data), 1000)) < 0) { +		snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", +			   dev->devnum, iface, fmt->altsetting, rate, ep); +		return err; +	} +	if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, +				   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, +				   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, +				   data, sizeof(data), 1000)) < 0) { +		snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", +			   dev->devnum, iface, fmt->altsetting, ep); +		return 0; /* some devices don't support reading */ +	} +	crate = data[0] | (data[1] << 8) | (data[2] << 16); +	if (crate != rate) { +		snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); +		// runtime->rate = crate; +	} + +	return 0; +} + +static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, +			      struct usb_host_interface *alts, +			      struct audioformat *fmt, int rate) +{ +	struct usb_device *dev = chip->dev; +	unsigned char data[4]; +	int err, crate; + +	data[0] = rate; +	data[1] = rate >> 8; +	data[2] = rate >> 16; +	data[3] = rate >> 24; +	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, +				   USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, +				   UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, +				   data, sizeof(data), 1000)) < 0) { +		snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", +			   dev->devnum, iface, fmt->altsetting, rate); +		return err; +	} +	if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, +				   USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, +				   UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, +				   data, sizeof(data), 1000)) < 0) { +		snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", +			   dev->devnum, iface, fmt->altsetting); +		return err; +	} +	crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +	if (crate != rate) +		snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); + +	return 0; +} + +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, +			     struct usb_host_interface *alts, +			     struct audioformat *fmt, int rate) +{ +	struct usb_interface_descriptor *altsd = get_iface_desc(alts); + +	switch (altsd->bInterfaceProtocol) { +	case UAC_VERSION_1: +		return set_sample_rate_v1(chip, iface, alts, fmt, rate); + +	case UAC_VERSION_2: +		return set_sample_rate_v2(chip, iface, alts, fmt, rate); +	} + +	return -EINVAL; +} + +/* + * find a matching format and set up the interface + */ +static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) +{ +	struct usb_device *dev = subs->dev; +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	struct usb_interface *iface; +	unsigned int ep, attr; +	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; +	int err; + +	iface = usb_ifnum_to_if(dev, fmt->iface); +	if (WARN_ON(!iface)) +		return -EINVAL; +	alts = &iface->altsetting[fmt->altset_idx]; +	altsd = get_iface_desc(alts); +	if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) +		return -EINVAL; + +	if (fmt == subs->cur_audiofmt) +		return 0; + +	/* close the old interface */ +	if (subs->interface >= 0 && subs->interface != fmt->iface) { +		if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { +			snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", +				dev->devnum, fmt->iface, fmt->altsetting); +			return -EIO; +		} +		subs->interface = -1; +		subs->altset_idx = 0; +	} + +	/* set interface */ +	if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) { +		if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) { +			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", +				   dev->devnum, fmt->iface, fmt->altsetting); +			return -EIO; +		} +		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); +		subs->interface = fmt->iface; +		subs->altset_idx = fmt->altset_idx; +	} + +	/* create a data pipe */ +	ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK; +	if (is_playback) +		subs->datapipe = usb_sndisocpipe(dev, ep); +	else +		subs->datapipe = usb_rcvisocpipe(dev, ep); +	subs->datainterval = fmt->datainterval; +	subs->syncpipe = subs->syncinterval = 0; +	subs->maxpacksize = fmt->maxpacksize; +	subs->fill_max = 0; + +	/* we need a sync pipe in async OUT or adaptive IN mode */ +	/* check the number of EP, since some devices have broken +	 * descriptors which fool us.  if it has only one EP, +	 * assume it as adaptive-out or sync-in. +	 */ +	attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; +	if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || +	     (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && +	    altsd->bNumEndpoints >= 2) { +		/* check sync-pipe endpoint */ +		/* ... and check descriptor size before accessing bSynchAddress +		   because there is a version of the SB Audigy 2 NX firmware lacking +		   the audio fields in the endpoint descriptors */ +		if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || +		    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && +		     get_endpoint(alts, 1)->bSynchAddress != 0)) { +			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", +				   dev->devnum, fmt->iface, fmt->altsetting); +			return -EINVAL; +		} +		ep = get_endpoint(alts, 1)->bEndpointAddress; +		if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && +		    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || +		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { +			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", +				   dev->devnum, fmt->iface, fmt->altsetting); +			return -EINVAL; +		} +		ep &= USB_ENDPOINT_NUMBER_MASK; +		if (is_playback) +			subs->syncpipe = usb_rcvisocpipe(dev, ep); +		else +			subs->syncpipe = usb_sndisocpipe(dev, ep); +		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && +		    get_endpoint(alts, 1)->bRefresh >= 1 && +		    get_endpoint(alts, 1)->bRefresh <= 9) +			subs->syncinterval = get_endpoint(alts, 1)->bRefresh; +		else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) +			subs->syncinterval = 1; +		else if (get_endpoint(alts, 1)->bInterval >= 1 && +			 get_endpoint(alts, 1)->bInterval <= 16) +			subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; +		else +			subs->syncinterval = 3; +	} + +	/* always fill max packet size */ +	if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) +		subs->fill_max = 1; + +	if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) +		return err; + +	subs->cur_audiofmt = fmt; + +	snd_usb_set_format_quirk(subs, fmt); + +#if 0 +	printk(KERN_DEBUG +	       "setting done: format = %d, rate = %d..%d, channels = %d\n", +	       fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels); +	printk(KERN_DEBUG +	       "  datapipe = 0x%0x, syncpipe = 0x%0x\n", +	       subs->datapipe, subs->syncpipe); +#endif + +	return 0; +} + +/* + * hw_params callback + * + * allocate a buffer and set the given audio format. + * + * so far we use a physically linear buffer although packetize transfer + * doesn't need a continuous area. + * if sg buffer is supported on the later version of alsa, we'll follow + * that. + */ +static int snd_usb_hw_params(struct snd_pcm_substream *substream, +			     struct snd_pcm_hw_params *hw_params) +{ +	struct snd_usb_substream *subs = substream->runtime->private_data; +	struct audioformat *fmt; +	unsigned int channels, rate, format; +	int ret, changed; + +	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, +					       params_buffer_bytes(hw_params)); +	if (ret < 0) +		return ret; + +	format = params_format(hw_params); +	rate = params_rate(hw_params); +	channels = params_channels(hw_params); +	fmt = find_format(subs, format, rate, channels); +	if (!fmt) { +		snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", +			   format, rate, channels); +		return -EINVAL; +	} + +	changed = subs->cur_audiofmt != fmt || +		subs->period_bytes != params_period_bytes(hw_params) || +		subs->cur_rate != rate; +	if ((ret = set_format(subs, fmt)) < 0) +		return ret; + +	if (subs->cur_rate != rate) { +		struct usb_host_interface *alts; +		struct usb_interface *iface; +		iface = usb_ifnum_to_if(subs->dev, fmt->iface); +		alts = &iface->altsetting[fmt->altset_idx]; +		ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate); +		if (ret < 0) +			return ret; +		subs->cur_rate = rate; +	} + +	if (changed) { +		/* format changed */ +		snd_usb_release_substream_urbs(subs, 0); +		/* influenced: period_bytes, channels, rate, format, */ +		ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params), +						  params_rate(hw_params), +						  snd_pcm_format_physical_width(params_format(hw_params)) * +							params_channels(hw_params)); +	} + +	return ret; +} + +/* + * hw_free callback + * + * reset the audio format and release the buffer + */ +static int snd_usb_hw_free(struct snd_pcm_substream *substream) +{ +	struct snd_usb_substream *subs = substream->runtime->private_data; + +	subs->cur_audiofmt = NULL; +	subs->cur_rate = 0; +	subs->period_bytes = 0; +	if (!subs->stream->chip->shutdown) +		snd_usb_release_substream_urbs(subs, 0); +	return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +/* + * prepare callback + * + * only a few subtle things... + */ +static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	struct snd_usb_substream *subs = runtime->private_data; + +	if (! subs->cur_audiofmt) { +		snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); +		return -ENXIO; +	} + +	/* some unit conversions in runtime */ +	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); +	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); + +	/* reset the pointer */ +	subs->hwptr_done = 0; +	subs->transfer_done = 0; +	subs->phase = 0; +	runtime->delay = 0; + +	return snd_usb_substream_prepare(subs, runtime); +} + +static struct snd_pcm_hardware snd_usb_hardware = +{ +	.info =			SNDRV_PCM_INFO_MMAP | +				SNDRV_PCM_INFO_MMAP_VALID | +				SNDRV_PCM_INFO_BATCH | +				SNDRV_PCM_INFO_INTERLEAVED | +				SNDRV_PCM_INFO_BLOCK_TRANSFER | +				SNDRV_PCM_INFO_PAUSE, +	.buffer_bytes_max =	1024 * 1024, +	.period_bytes_min =	64, +	.period_bytes_max =	512 * 1024, +	.periods_min =		2, +	.periods_max =		1024, +}; + +static int hw_check_valid_format(struct snd_usb_substream *subs, +				 struct snd_pcm_hw_params *params, +				 struct audioformat *fp) +{ +	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); +	struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); +	struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); +	struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); +	struct snd_mask check_fmts; +	unsigned int ptime; + +	/* check the format */ +	snd_mask_none(&check_fmts); +	check_fmts.bits[0] = (u32)fp->formats; +	check_fmts.bits[1] = (u32)(fp->formats >> 32); +	snd_mask_intersect(&check_fmts, fmts); +	if (snd_mask_empty(&check_fmts)) { +		hwc_debug("   > check: no supported format %d\n", fp->format); +		return 0; +	} +	/* check the channels */ +	if (fp->channels < ct->min || fp->channels > ct->max) { +		hwc_debug("   > check: no valid channels %d (%d/%d)\n", fp->channels, ct->min, ct->max); +		return 0; +	} +	/* check the rate is within the range */ +	if (fp->rate_min > it->max || (fp->rate_min == it->max && it->openmax)) { +		hwc_debug("   > check: rate_min %d > max %d\n", fp->rate_min, it->max); +		return 0; +	} +	if (fp->rate_max < it->min || (fp->rate_max == it->min && it->openmin)) { +		hwc_debug("   > check: rate_max %d < min %d\n", fp->rate_max, it->min); +		return 0; +	} +	/* check whether the period time is >= the data packet interval */ +	if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { +		ptime = 125 * (1 << fp->datainterval); +		if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { +			hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max); +			return 0; +		} +	} +	return 1; +} + +static int hw_rule_rate(struct snd_pcm_hw_params *params, +			struct snd_pcm_hw_rule *rule) +{ +	struct snd_usb_substream *subs = rule->private; +	struct list_head *p; +	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); +	unsigned int rmin, rmax; +	int changed; + +	hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max); +	changed = 0; +	rmin = rmax = 0; +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		fp = list_entry(p, struct audioformat, list); +		if (!hw_check_valid_format(subs, params, fp)) +			continue; +		if (changed++) { +			if (rmin > fp->rate_min) +				rmin = fp->rate_min; +			if (rmax < fp->rate_max) +				rmax = fp->rate_max; +		} else { +			rmin = fp->rate_min; +			rmax = fp->rate_max; +		} +	} + +	if (!changed) { +		hwc_debug("  --> get empty\n"); +		it->empty = 1; +		return -EINVAL; +	} + +	changed = 0; +	if (it->min < rmin) { +		it->min = rmin; +		it->openmin = 0; +		changed = 1; +	} +	if (it->max > rmax) { +		it->max = rmax; +		it->openmax = 0; +		changed = 1; +	} +	if (snd_interval_checkempty(it)) { +		it->empty = 1; +		return -EINVAL; +	} +	hwc_debug("  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); +	return changed; +} + + +static int hw_rule_channels(struct snd_pcm_hw_params *params, +			    struct snd_pcm_hw_rule *rule) +{ +	struct snd_usb_substream *subs = rule->private; +	struct list_head *p; +	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); +	unsigned int rmin, rmax; +	int changed; + +	hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max); +	changed = 0; +	rmin = rmax = 0; +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		fp = list_entry(p, struct audioformat, list); +		if (!hw_check_valid_format(subs, params, fp)) +			continue; +		if (changed++) { +			if (rmin > fp->channels) +				rmin = fp->channels; +			if (rmax < fp->channels) +				rmax = fp->channels; +		} else { +			rmin = fp->channels; +			rmax = fp->channels; +		} +	} + +	if (!changed) { +		hwc_debug("  --> get empty\n"); +		it->empty = 1; +		return -EINVAL; +	} + +	changed = 0; +	if (it->min < rmin) { +		it->min = rmin; +		it->openmin = 0; +		changed = 1; +	} +	if (it->max > rmax) { +		it->max = rmax; +		it->openmax = 0; +		changed = 1; +	} +	if (snd_interval_checkempty(it)) { +		it->empty = 1; +		return -EINVAL; +	} +	hwc_debug("  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); +	return changed; +} + +static int hw_rule_format(struct snd_pcm_hw_params *params, +			  struct snd_pcm_hw_rule *rule) +{ +	struct snd_usb_substream *subs = rule->private; +	struct list_head *p; +	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); +	u64 fbits; +	u32 oldbits[2]; +	int changed; + +	hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]); +	fbits = 0; +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		fp = list_entry(p, struct audioformat, list); +		if (!hw_check_valid_format(subs, params, fp)) +			continue; +		fbits |= fp->formats; +	} + +	oldbits[0] = fmt->bits[0]; +	oldbits[1] = fmt->bits[1]; +	fmt->bits[0] &= (u32)fbits; +	fmt->bits[1] &= (u32)(fbits >> 32); +	if (!fmt->bits[0] && !fmt->bits[1]) { +		hwc_debug("  --> get empty\n"); +		return -EINVAL; +	} +	changed = (oldbits[0] != fmt->bits[0] || oldbits[1] != fmt->bits[1]); +	hwc_debug("  --> %x:%x (changed = %d)\n", fmt->bits[0], fmt->bits[1], changed); +	return changed; +} + +static int hw_rule_period_time(struct snd_pcm_hw_params *params, +			       struct snd_pcm_hw_rule *rule) +{ +	struct snd_usb_substream *subs = rule->private; +	struct audioformat *fp; +	struct snd_interval *it; +	unsigned char min_datainterval; +	unsigned int pmin; +	int changed; + +	it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); +	hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); +	min_datainterval = 0xff; +	list_for_each_entry(fp, &subs->fmt_list, list) { +		if (!hw_check_valid_format(subs, params, fp)) +			continue; +		min_datainterval = min(min_datainterval, fp->datainterval); +	} +	if (min_datainterval == 0xff) { +		hwc_debug("  --> get emtpy\n"); +		it->empty = 1; +		return -EINVAL; +	} +	pmin = 125 * (1 << min_datainterval); +	changed = 0; +	if (it->min < pmin) { +		it->min = pmin; +		it->openmin = 0; +		changed = 1; +	} +	if (snd_interval_checkempty(it)) { +		it->empty = 1; +		return -EINVAL; +	} +	hwc_debug("  --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); +	return changed; +} + +/* + *  If the device supports unusual bit rates, does the request meet these? + */ +static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, +				  struct snd_usb_substream *subs) +{ +	struct audioformat *fp; +	int count = 0, needs_knot = 0; +	int err; + +	list_for_each_entry(fp, &subs->fmt_list, list) { +		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) +			return 0; +		count += fp->nr_rates; +		if (fp->rates & SNDRV_PCM_RATE_KNOT) +			needs_knot = 1; +	} +	if (!needs_knot) +		return 0; + +	subs->rate_list.count = count; +	subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); +	subs->rate_list.mask = 0; +	count = 0; +	list_for_each_entry(fp, &subs->fmt_list, list) { +		int i; +		for (i = 0; i < fp->nr_rates; i++) +			subs->rate_list.list[count++] = fp->rate_table[i]; +	} +	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, +					 &subs->rate_list); +	if (err < 0) +		return err; + +	return 0; +} + + +/* + * set up the runtime hardware information. + */ + +static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) +{ +	struct list_head *p; +	unsigned int pt, ptmin; +	int param_period_time_if_needed; +	int err; + +	runtime->hw.formats = subs->formats; + +	runtime->hw.rate_min = 0x7fffffff; +	runtime->hw.rate_max = 0; +	runtime->hw.channels_min = 256; +	runtime->hw.channels_max = 0; +	runtime->hw.rates = 0; +	ptmin = UINT_MAX; +	/* check min/max rates and channels */ +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		fp = list_entry(p, struct audioformat, list); +		runtime->hw.rates |= fp->rates; +		if (runtime->hw.rate_min > fp->rate_min) +			runtime->hw.rate_min = fp->rate_min; +		if (runtime->hw.rate_max < fp->rate_max) +			runtime->hw.rate_max = fp->rate_max; +		if (runtime->hw.channels_min > fp->channels) +			runtime->hw.channels_min = fp->channels; +		if (runtime->hw.channels_max < fp->channels) +			runtime->hw.channels_max = fp->channels; +		if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) { +			/* FIXME: there might be more than one audio formats... */ +			runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = +				fp->frame_size; +		} +		pt = 125 * (1 << fp->datainterval); +		ptmin = min(ptmin, pt); +	} + +	param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; +	if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) +		/* full speed devices have fixed data packet interval */ +		ptmin = 1000; +	if (ptmin == 1000) +		/* if period time doesn't go below 1 ms, no rules needed */ +		param_period_time_if_needed = -1; +	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, +				     ptmin, UINT_MAX); + +	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, +				       hw_rule_rate, subs, +				       SNDRV_PCM_HW_PARAM_FORMAT, +				       SNDRV_PCM_HW_PARAM_CHANNELS, +				       param_period_time_if_needed, +				       -1)) < 0) +		return err; +	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, +				       hw_rule_channels, subs, +				       SNDRV_PCM_HW_PARAM_FORMAT, +				       SNDRV_PCM_HW_PARAM_RATE, +				       param_period_time_if_needed, +				       -1)) < 0) +		return err; +	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, +				       hw_rule_format, subs, +				       SNDRV_PCM_HW_PARAM_RATE, +				       SNDRV_PCM_HW_PARAM_CHANNELS, +				       param_period_time_if_needed, +				       -1)) < 0) +		return err; +	if (param_period_time_if_needed >= 0) { +		err = snd_pcm_hw_rule_add(runtime, 0, +					  SNDRV_PCM_HW_PARAM_PERIOD_TIME, +					  hw_rule_period_time, subs, +					  SNDRV_PCM_HW_PARAM_FORMAT, +					  SNDRV_PCM_HW_PARAM_CHANNELS, +					  SNDRV_PCM_HW_PARAM_RATE, +					  -1); +		if (err < 0) +			return err; +	} +	if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) +		return err; +	return 0; +} + +static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) +{ +	struct snd_usb_stream *as = snd_pcm_substream_chip(substream); +	struct snd_pcm_runtime *runtime = substream->runtime; +	struct snd_usb_substream *subs = &as->substream[direction]; + +	subs->interface = -1; +	subs->altset_idx = 0; +	runtime->hw = snd_usb_hardware; +	runtime->private_data = subs; +	subs->pcm_substream = substream; +	return setup_hw_info(runtime, subs); +} + +static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) +{ +	struct snd_usb_stream *as = snd_pcm_substream_chip(substream); +	struct snd_usb_substream *subs = &as->substream[direction]; + +	if (!as->chip->shutdown && subs->interface >= 0) { +		usb_set_interface(subs->dev, subs->interface, 0); +		subs->interface = -1; +	} +	subs->pcm_substream = NULL; +	return 0; +} + +static int snd_usb_playback_open(struct snd_pcm_substream *substream) +{ +	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); +} + +static int snd_usb_playback_close(struct snd_pcm_substream *substream) +{ +	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK); +} + +static int snd_usb_capture_open(struct snd_pcm_substream *substream) +{ +	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); +} + +static int snd_usb_capture_close(struct snd_pcm_substream *substream) +{ +	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); +} + +static struct snd_pcm_ops snd_usb_playback_ops = { +	.open =		snd_usb_playback_open, +	.close =	snd_usb_playback_close, +	.ioctl =	snd_pcm_lib_ioctl, +	.hw_params =	snd_usb_hw_params, +	.hw_free =	snd_usb_hw_free, +	.prepare =	snd_usb_pcm_prepare, +	.trigger =	snd_usb_substream_playback_trigger, +	.pointer =	snd_usb_pcm_pointer, +	.page =		snd_pcm_lib_get_vmalloc_page, +	.mmap =		snd_pcm_lib_mmap_vmalloc, +}; + +static struct snd_pcm_ops snd_usb_capture_ops = { +	.open =		snd_usb_capture_open, +	.close =	snd_usb_capture_close, +	.ioctl =	snd_pcm_lib_ioctl, +	.hw_params =	snd_usb_hw_params, +	.hw_free =	snd_usb_hw_free, +	.prepare =	snd_usb_pcm_prepare, +	.trigger =	snd_usb_substream_capture_trigger, +	.pointer =	snd_usb_pcm_pointer, +	.page =		snd_pcm_lib_get_vmalloc_page, +	.mmap =		snd_pcm_lib_mmap_vmalloc, +}; + +void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) +{ +	snd_pcm_set_ops(pcm, stream, +			stream == SNDRV_PCM_STREAM_PLAYBACK ? +			&snd_usb_playback_ops : &snd_usb_capture_ops); +} diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h new file mode 100644 index 00000000000..1c931b68f3b --- /dev/null +++ b/sound/usb/pcm.h @@ -0,0 +1,14 @@ +#ifndef __USBAUDIO_PCM_H +#define __USBAUDIO_PCM_H + +void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); + +int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, +		       struct usb_host_interface *alts, +		       struct audioformat *fmt); + +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, +			     struct usb_host_interface *alts, +			     struct audioformat *fmt, int rate); + +#endif /* __USBAUDIO_PCM_H */ diff --git a/sound/usb/proc.c b/sound/usb/proc.c new file mode 100644 index 00000000000..f5e3f356b95 --- /dev/null +++ b/sound/usb/proc.c @@ -0,0 +1,168 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/init.h> +#include <linux/usb.h> + +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> + +#include "usbaudio.h" +#include "helper.h" +#include "card.h" +#include "proc.h" + +/* convert our full speed USB rate into sampling rate in Hz */ +static inline unsigned get_full_speed_hz(unsigned int usb_rate) +{ +	return (usb_rate * 125 + (1 << 12)) >> 13; +} + +/* convert our high speed USB rate into sampling rate in Hz */ +static inline unsigned get_high_speed_hz(unsigned int usb_rate) +{ +	return (usb_rate * 125 + (1 << 9)) >> 10; +} + +/* + * common proc files to show the usb device info + */ +static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +{ +	struct snd_usb_audio *chip = entry->private_data; +	if (!chip->shutdown) +		snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); +} + +static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +{ +	struct snd_usb_audio *chip = entry->private_data; +	if (!chip->shutdown) +		snd_iprintf(buffer, "%04x:%04x\n",  +			    USB_ID_VENDOR(chip->usb_id), +			    USB_ID_PRODUCT(chip->usb_id)); +} + +void snd_usb_audio_create_proc(struct snd_usb_audio *chip) +{ +	struct snd_info_entry *entry; +	if (!snd_card_proc_new(chip->card, "usbbus", &entry)) +		snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); +	if (!snd_card_proc_new(chip->card, "usbid", &entry)) +		snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); +} + +/* + * proc interface for list the supported pcm formats + */ +static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) +{ +	struct list_head *p; +	static char *sync_types[4] = { +		"NONE", "ASYNC", "ADAPTIVE", "SYNC" +	}; + +	list_for_each(p, &subs->fmt_list) { +		struct audioformat *fp; +		snd_pcm_format_t fmt; +		fp = list_entry(p, struct audioformat, list); +		snd_iprintf(buffer, "  Interface %d\n", fp->iface); +		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting); +		snd_iprintf(buffer, "    Format:"); +		for (fmt = 0; fmt <= SNDRV_PCM_FORMAT_LAST; ++fmt) +			if (fp->formats & (1uLL << fmt)) +				snd_iprintf(buffer, " %s", +					    snd_pcm_format_name(fmt)); +		snd_iprintf(buffer, "\n"); +		snd_iprintf(buffer, "    Channels: %d\n", fp->channels); +		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n", +			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK, +			    fp->endpoint & USB_DIR_IN ? "IN" : "OUT", +			    sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]); +		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { +			snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n", +				    fp->rate_min, fp->rate_max); +		} else { +			unsigned int i; +			snd_iprintf(buffer, "    Rates: "); +			for (i = 0; i < fp->nr_rates; i++) { +				if (i > 0) +					snd_iprintf(buffer, ", "); +				snd_iprintf(buffer, "%d", fp->rate_table[i]); +			} +			snd_iprintf(buffer, "\n"); +		} +		if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) +			snd_iprintf(buffer, "    Data packet interval: %d us\n", +				    125 * (1 << fp->datainterval)); +		// snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize); +		// snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes); +	} +} + +static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) +{ +	if (subs->running) { +		unsigned int i; +		snd_iprintf(buffer, "  Status: Running\n"); +		snd_iprintf(buffer, "    Interface = %d\n", subs->interface); +		snd_iprintf(buffer, "    Altset = %d\n", subs->altset_idx); +		snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs); +		for (i = 0; i < subs->nurbs; i++) +			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); +		snd_iprintf(buffer, "]\n"); +		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize); +		snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n", +			    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL +			    ? get_full_speed_hz(subs->freqm) +			    : get_high_speed_hz(subs->freqm), +			    subs->freqm >> 16, subs->freqm & 0xffff); +	} else { +		snd_iprintf(buffer, "  Status: Stop\n"); +	} +} + +static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +{ +	struct snd_usb_stream *stream = entry->private_data; + +	snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name); + +	if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) { +		snd_iprintf(buffer, "\nPlayback:\n"); +		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); +		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); +	} +	if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) { +		snd_iprintf(buffer, "\nCapture:\n"); +		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); +		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); +	} +} + +void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream) +{ +	struct snd_info_entry *entry; +	char name[32]; +	struct snd_card *card = stream->chip->card; + +	sprintf(name, "stream%d", stream->pcm_index); +	if (!snd_card_proc_new(card, name, &entry)) +		snd_info_set_text_ops(entry, stream, proc_pcm_format_read); +} + diff --git a/sound/usb/proc.h b/sound/usb/proc.h new file mode 100644 index 00000000000..a45b765e4cf --- /dev/null +++ b/sound/usb/proc.h @@ -0,0 +1,8 @@ +#ifndef __USBAUDIO_PROC_H +#define __USBAUDIO_PROC_H + +void snd_usb_audio_create_proc(struct snd_usb_audio *chip); +void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream); + +#endif /* __USBAUDIO_PROC_H */ + diff --git a/sound/usb/usbquirks.h b/sound/usb/quirks-table.h index 2b426c1fd0e..91ddef31bcb 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/quirks-table.h @@ -279,7 +279,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 0,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S16_LE, +					.formats = SNDRV_PCM_FMTBIT_S16_LE,  					.channels = 4,  					.iface = 0,  					.altsetting = 1, @@ -296,7 +296,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 1,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S16_LE, +					.formats = SNDRV_PCM_FMTBIT_S16_LE,  					.channels = 2,  					.iface = 1,  					.altsetting = 1, @@ -580,7 +580,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 0,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S24_3LE, +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,  					.channels = 2,  					.iface = 0,  					.altsetting = 1, @@ -597,7 +597,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 1,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S24_3LE, +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,  					.channels = 2,  					.iface = 1,  					.altsetting = 1, @@ -793,7 +793,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 1,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S24_3LE, +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,  					.channels = 2,  					.iface = 1,  					.altsetting = 1, @@ -810,7 +810,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 2,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = & (const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S24_3LE, +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,  					.channels = 2,  					.iface = 2,  					.altsetting = 1, @@ -1826,6 +1826,60 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, +{ +	USB_DEVICE(0x0763, 0x2080), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "M-Audio", */ +		/* .product_name = "Fast Track Ultra 8", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = & (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			/* interface 3 (MIDI) is standard compliant */ +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	USB_DEVICE(0x0763, 0x2081), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "M-Audio", */ +		/* .product_name = "Fast Track Ultra 8R", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = & (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			/* interface 3 (MIDI) is standard compliant */ +			{ +				.ifnum = -1 +			} +		} +	} +},  /* Casio devices */  { @@ -2203,7 +2257,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				.ifnum = 1,  				.type = QUIRK_AUDIO_FIXED_ENDPOINT,  				.data = &(const struct audioformat) { -					.format = SNDRV_PCM_FORMAT_S24_3BE, +					.formats = SNDRV_PCM_FMTBIT_S24_3BE,  					.channels = 2,  					.iface = 1,  					.altsetting = 1, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c new file mode 100644 index 00000000000..136e5b4cf6d --- /dev/null +++ b/sound/usb/quirks.c @@ -0,0 +1,594 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> + +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> + +#include "usbaudio.h" +#include "card.h" +#include "mixer.h" +#include "mixer_quirks.h" +#include "midi.h" +#include "quirks.h" +#include "helper.h" +#include "endpoint.h" +#include "pcm.h" + +/* + * handle the quirks for the contained interfaces + */ +static int create_composite_quirk(struct snd_usb_audio *chip, +				  struct usb_interface *iface, +				  struct usb_driver *driver, +				  const struct snd_usb_audio_quirk *quirk) +{ +	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber; +	int err; + +	for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { +		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum); +		if (!iface) +			continue; +		if (quirk->ifnum != probed_ifnum && +		    usb_interface_claimed(iface)) +			continue; +		err = snd_usb_create_quirk(chip, iface, driver, quirk); +		if (err < 0) +			return err; +		if (quirk->ifnum != probed_ifnum) +			usb_driver_claim_interface(driver, iface, (void *)-1L); +	} +	return 0; +} + +static int ignore_interface_quirk(struct snd_usb_audio *chip, +				  struct usb_interface *iface, +				  struct usb_driver *driver, +				  const struct snd_usb_audio_quirk *quirk) +{ +	return 0; +} + + +/* + * Allow alignment on audio sub-slot (channel samples) rather than + * on audio slots (audio frames) + */ +static int create_align_transfer_quirk(struct snd_usb_audio *chip, +				       struct usb_interface *iface, +				       struct usb_driver *driver, +				       const struct snd_usb_audio_quirk *quirk) +{ +	chip->txfr_quirk = 1; +	return 1;	/* Continue with creating streams and mixer */ +} + +static int create_any_midi_quirk(struct snd_usb_audio *chip, +				 struct usb_interface *intf, +				 struct usb_driver *driver, +				 const struct snd_usb_audio_quirk *quirk) +{ +	return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + +/* + * create a stream for an interface with proper descriptors + */ +static int create_standard_audio_quirk(struct snd_usb_audio *chip, +				       struct usb_interface *iface, +				       struct usb_driver *driver, +				       const struct snd_usb_audio_quirk *quirk) +{ +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	int err; + +	alts = &iface->altsetting[0]; +	altsd = get_iface_desc(alts); +	err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber); +	if (err < 0) { +		snd_printk(KERN_ERR "cannot setup if %d: error %d\n", +			   altsd->bInterfaceNumber, err); +		return err; +	} +	/* reset the current interface */ +	usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); +	return 0; +} + +/* + * create a stream for an endpoint/altsetting without proper descriptors + */ +static int create_fixed_stream_quirk(struct snd_usb_audio *chip, +				     struct usb_interface *iface, +				     struct usb_driver *driver, +				     const struct snd_usb_audio_quirk *quirk) +{ +	struct audioformat *fp; +	struct usb_host_interface *alts; +	int stream, err; +	unsigned *rate_table = NULL; + +	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); +	if (! fp) { +		snd_printk(KERN_ERR "cannot memdup\n"); +		return -ENOMEM; +	} +	if (fp->nr_rates > 0) { +		rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); +		if (!rate_table) { +			kfree(fp); +			return -ENOMEM; +		} +		memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates); +		fp->rate_table = rate_table; +	} + +	stream = (fp->endpoint & USB_DIR_IN) +		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; +	err = snd_usb_add_audio_endpoint(chip, stream, fp); +	if (err < 0) { +		kfree(fp); +		kfree(rate_table); +		return err; +	} +	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber || +	    fp->altset_idx >= iface->num_altsetting) { +		kfree(fp); +		kfree(rate_table); +		return -EINVAL; +	} +	alts = &iface->altsetting[fp->altset_idx]; +	fp->datainterval = snd_usb_parse_datainterval(chip, alts); +	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +	usb_set_interface(chip->dev, fp->iface, 0); +	snd_usb_init_pitch(chip, fp->iface, alts, fp); +	snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max); +	return 0; +} + +/* + * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.   + * The only way to detect the sample rate is by looking at wMaxPacketSize. + */ +static int create_uaxx_quirk(struct snd_usb_audio *chip, +			     struct usb_interface *iface, +			     struct usb_driver *driver, +			     const struct snd_usb_audio_quirk *quirk) +{ +	static const struct audioformat ua_format = { +		.formats = SNDRV_PCM_FMTBIT_S24_3LE, +		.channels = 2, +		.fmt_type = UAC_FORMAT_TYPE_I, +		.altsetting = 1, +		.altset_idx = 1, +		.rates = SNDRV_PCM_RATE_CONTINUOUS, +	}; +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	struct audioformat *fp; +	int stream, err; + +	/* both PCM and MIDI interfaces have 2 or more altsettings */ +	if (iface->num_altsetting < 2) +		return -ENXIO; +	alts = &iface->altsetting[1]; +	altsd = get_iface_desc(alts); + +	if (altsd->bNumEndpoints == 2) { +		static const struct snd_usb_midi_endpoint_info ua700_ep = { +			.out_cables = 0x0003, +			.in_cables  = 0x0003 +		}; +		static const struct snd_usb_audio_quirk ua700_quirk = { +			.type = QUIRK_MIDI_FIXED_ENDPOINT, +			.data = &ua700_ep +		}; +		static const struct snd_usb_midi_endpoint_info uaxx_ep = { +			.out_cables = 0x0001, +			.in_cables  = 0x0001 +		}; +		static const struct snd_usb_audio_quirk uaxx_quirk = { +			.type = QUIRK_MIDI_FIXED_ENDPOINT, +			.data = &uaxx_ep +		}; +		const struct snd_usb_audio_quirk *quirk = +			chip->usb_id == USB_ID(0x0582, 0x002b) +			? &ua700_quirk : &uaxx_quirk; +		return snd_usbmidi_create(chip->card, iface, +					  &chip->midi_list, quirk); +	} + +	if (altsd->bNumEndpoints != 1) +		return -ENXIO; + +	fp = kmalloc(sizeof(*fp), GFP_KERNEL); +	if (!fp) +		return -ENOMEM; +	memcpy(fp, &ua_format, sizeof(*fp)); + +	fp->iface = altsd->bInterfaceNumber; +	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; +	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; +	fp->datainterval = 0; +	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + +	switch (fp->maxpacksize) { +	case 0x120: +		fp->rate_max = fp->rate_min = 44100; +		break; +	case 0x138: +	case 0x140: +		fp->rate_max = fp->rate_min = 48000; +		break; +	case 0x258: +	case 0x260: +		fp->rate_max = fp->rate_min = 96000; +		break; +	default: +		snd_printk(KERN_ERR "unknown sample rate\n"); +		kfree(fp); +		return -ENXIO; +	} + +	stream = (fp->endpoint & USB_DIR_IN) +		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; +	err = snd_usb_add_audio_endpoint(chip, stream, fp); +	if (err < 0) { +		kfree(fp); +		return err; +	} +	usb_set_interface(chip->dev, fp->iface, 0); +	return 0; +} + +/* + * audio-interface quirks + * + * returns zero if no standard audio/MIDI parsing is needed. + * returns a postive value if standard audio/midi interfaces are parsed + * after this. + * returns a negative value at error. + */ +int snd_usb_create_quirk(struct snd_usb_audio *chip, +			 struct usb_interface *iface, +			 struct usb_driver *driver, +			 const struct snd_usb_audio_quirk *quirk) +{ +	typedef int (*quirk_func_t)(struct snd_usb_audio *, +				    struct usb_interface *, +				    struct usb_driver *, +				    const struct snd_usb_audio_quirk *); +	static const quirk_func_t quirk_funcs[] = { +		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, +		[QUIRK_COMPOSITE] = create_composite_quirk, +		[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, +		[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, +		[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, +		[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, +		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk, +		[QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, +		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, +		[QUIRK_MIDI_CME] = create_any_midi_quirk, +		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, +		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, +		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, +		[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk +	}; + +	if (quirk->type < QUIRK_TYPE_COUNT) { +		return quirk_funcs[quirk->type](chip, iface, driver, quirk); +	} else { +		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); +		return -ENXIO; +	} +} + +/* + * boot quirks + */ + +#define EXTIGY_FIRMWARE_SIZE_OLD 794 +#define EXTIGY_FIRMWARE_SIZE_NEW 483 + +static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf) +{ +	struct usb_host_config *config = dev->actconfig; +	int err; + +	if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD || +	    le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) { +		snd_printdd("sending Extigy boot sequence...\n"); +		/* Send message to force it to reconnect with full interface. */ +		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0), +				      0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000); +		if (err < 0) snd_printdd("error sending boot message: %d\n", err); +		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, +				&dev->descriptor, sizeof(dev->descriptor)); +		config = dev->actconfig; +		if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err); +		err = usb_reset_configuration(dev); +		if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err); +		snd_printdd("extigy_boot: new boot length = %d\n", +			    le16_to_cpu(get_cfg_desc(config)->wTotalLength)); +		return -ENODEV; /* quit this anyway */ +	} +	return 0; +} + +static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) +{ +	u8 buf = 1; + +	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, +			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			0, 0, &buf, 1, 1000); +	if (buf == 0) { +		snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, +				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +				1, 2000, NULL, 0, 1000); +		return -ENODEV; +	} +	return 0; +} + +/* + * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely + * documented in the device's data sheet. + */ +static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value) +{ +	u8 buf[4]; +	buf[0] = 0x20; +	buf[1] = value & 0xff; +	buf[2] = (value >> 8) & 0xff; +	buf[3] = reg; +	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, +			       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, +			       0, 0, &buf, 4, 1000); +} + +static int snd_usb_cm106_boot_quirk(struct usb_device *dev) +{ +	/* +	 * Enable line-out driver mode, set headphone source to front +	 * channels, enable stereo mic. +	 */ +	return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); +} + +/* + * C-Media CM6206 is based on CM106 with two additional + * registers that are not documented in the data sheet. + * Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) +{ +	int err, reg; +	int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; + +	for (reg = 0; reg < ARRAY_SIZE(val); reg++) { +		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); +		if (err < 0) +			return err; +	} + +	return err; +} + +/* + * This call will put the synth in "USB send" mode, i.e it will send MIDI + * messages through USB (this is disabled at startup). The synth will + * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB + * sign on its LCD. Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) +{ +	int err, actual_length; + +	/* "midi send" enable */ +	static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; + +	void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); +	if (!buf) +		return -ENOMEM; +	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf, +			ARRAY_SIZE(seq), &actual_length, 1000); +	kfree(buf); +	if (err < 0) +		return err; + +	return 0; +} + +/* + * Setup quirks + */ +#define AUDIOPHILE_SET			0x01 /* if set, parse device_setup */ +#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */ +#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */ +#define AUDIOPHILE_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */ +#define AUDIOPHILE_SET_DI		0x10 /* if set, enable Digital Input */ +#define AUDIOPHILE_SET_MASK		0x1F /* bit mask for setup value */ +#define AUDIOPHILE_SET_24B_48K_DI	0x19 /* value for 24bits+48KHz+Digital Input */ +#define AUDIOPHILE_SET_24B_48K_NOTDI	0x09 /* value for 24bits+48KHz+No Digital Input */ +#define AUDIOPHILE_SET_16B_48K_DI	0x11 /* value for 16bits+48KHz+Digital Input */ +#define AUDIOPHILE_SET_16B_48K_NOTDI	0x01 /* value for 16bits+48KHz+No Digital Input */ + +static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, +					 int iface, +					 int altno) +{ +	/* Reset ALL ifaces to 0 altsetting. +	 * Call it for every possible altsetting of every interface. +	 */ +	usb_set_interface(chip->dev, iface, 0); + +	if (chip->setup & AUDIOPHILE_SET) { +		if ((chip->setup & AUDIOPHILE_SET_DTS) +		    && altno != 6) +			return 1; /* skip this altsetting */ +		if ((chip->setup & AUDIOPHILE_SET_96K) +		    && altno != 1) +			return 1; /* skip this altsetting */ +		if ((chip->setup & AUDIOPHILE_SET_MASK) == +		    AUDIOPHILE_SET_24B_48K_DI && altno != 2) +			return 1; /* skip this altsetting */ +		if ((chip->setup & AUDIOPHILE_SET_MASK) == +		    AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3) +			return 1; /* skip this altsetting */ +		if ((chip->setup & AUDIOPHILE_SET_MASK) == +		    AUDIOPHILE_SET_16B_48K_DI && altno != 4) +			return 1; /* skip this altsetting */ +		if ((chip->setup & AUDIOPHILE_SET_MASK) == +		    AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5) +			return 1; /* skip this altsetting */ +	} + +	return 0; /* keep this altsetting */ +} + +int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip, +				  int iface, +				  int altno) +{ +	/* audiophile usb: skip altsets incompatible with device_setup */ +	if (chip->usb_id == USB_ID(0x0763, 0x2003)) +		return audiophile_skip_setting_quirk(chip, iface, altno); + +	return 0; +} + +int snd_usb_apply_boot_quirk(struct usb_device *dev, +			     struct usb_interface *intf, +			     const struct snd_usb_audio_quirk *quirk) +{ +	u32 id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), +			le16_to_cpu(dev->descriptor.idProduct)); + +	/* SB Extigy needs special boot-up sequence */ +	/* if more models come, this will go to the quirk list. */ +	if (id == USB_ID(0x041e, 0x3000)) +		return snd_usb_extigy_boot_quirk(dev, intf); + +	/* SB Audigy 2 NX needs its own boot-up magic, too */ +	if (id == USB_ID(0x041e, 0x3020)) +		return snd_usb_audigy2nx_boot_quirk(dev); + +	/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */ +	if (id == USB_ID(0x10f5, 0x0200)) +		return snd_usb_cm106_boot_quirk(dev); + +	/* C-Media CM6206 / CM106-Like Sound Device */ +	if (id == USB_ID(0x0d8c, 0x0102)) +		return snd_usb_cm6206_boot_quirk(dev); + +	/* Access Music VirusTI Desktop */ +	if (id == USB_ID(0x133e, 0x0815)) +		return snd_usb_accessmusic_boot_quirk(dev); + +	return 0; +} + +/* + * check if the device uses big-endian samples + */ +int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp) +{ +	switch (chip->usb_id) { +	case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ +		if (fp->endpoint & USB_DIR_IN) +			return 1; +		break; +	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ +		if (chip->setup == 0x00 || +		    fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3) +			return 1; +	} +	return 0; +} + +/* + * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, + * not for interface. + */ + +enum { +	EMU_QUIRK_SR_44100HZ = 0, +	EMU_QUIRK_SR_48000HZ, +	EMU_QUIRK_SR_88200HZ, +	EMU_QUIRK_SR_96000HZ, +	EMU_QUIRK_SR_176400HZ, +	EMU_QUIRK_SR_192000HZ +}; + +static void set_format_emu_quirk(struct snd_usb_substream *subs, +				 struct audioformat *fmt) +{ +	unsigned char emu_samplerate_id = 0; + +	/* When capture is active +	 * sample rate shouldn't be changed +	 * by playback substream +	 */ +	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { +		if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) +			return; +	} + +	switch (fmt->rate_min) { +	case 48000: +		emu_samplerate_id = EMU_QUIRK_SR_48000HZ; +		break; +	case 88200: +		emu_samplerate_id = EMU_QUIRK_SR_88200HZ; +		break; +	case 96000: +		emu_samplerate_id = EMU_QUIRK_SR_96000HZ; +		break; +	case 176400: +		emu_samplerate_id = EMU_QUIRK_SR_176400HZ; +		break; +	case 192000: +		emu_samplerate_id = EMU_QUIRK_SR_192000HZ; +		break; +	default: +		emu_samplerate_id = EMU_QUIRK_SR_44100HZ; +		break; +	} +	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +} + +void snd_usb_set_format_quirk(struct snd_usb_substream *subs, +			      struct audioformat *fmt) +{ +	switch (subs->stream->chip->usb_id) { +	case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ +	case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ +	case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ +		set_format_emu_quirk(subs, fmt); +		break; +	} +} + diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h new file mode 100644 index 00000000000..03e5e94098c --- /dev/null +++ b/sound/usb/quirks.h @@ -0,0 +1,23 @@ +#ifndef __USBAUDIO_QUIRKS_H +#define __USBAUDIO_QUIRKS_H + +int snd_usb_create_quirk(struct snd_usb_audio *chip, +			 struct usb_interface *iface, +			 struct usb_driver *driver, +			 const struct snd_usb_audio_quirk *quirk); + +int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip, +				  int iface, +				  int altno); + +int snd_usb_apply_boot_quirk(struct usb_device *dev, +			     struct usb_interface *intf, +			     const struct snd_usb_audio_quirk *quirk); + +void snd_usb_set_format_quirk(struct snd_usb_substream *subs, +			      struct audioformat *fmt); + +int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, +				 struct audioformat *fp); + +#endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/urb.c b/sound/usb/urb.c new file mode 100644 index 00000000000..5570a2ba573 --- /dev/null +++ b/sound/usb/urb.c @@ -0,0 +1,995 @@ +/* + *   This program is free software; you can redistribute it and/or modify + *   it under the terms of the GNU General Public License as published by + *   the Free Software Foundation; either version 2 of the License, or + *   (at your option) any later version. + * + *   This program is distributed in the hope that it will be useful, + *   but WITHOUT ANY WARRANTY; without even the implied warranty of + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *   GNU General Public License for more details. + * + *   You should have received a copy of the GNU General Public License + *   along with this program; if not, write to the Free Software + *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "usbaudio.h" +#include "helper.h" +#include "card.h" +#include "urb.h" +#include "pcm.h" + +/* + * convert a sampling rate into our full speed format (fs/1000 in Q16.16) + * this will overflow at approx 524 kHz + */ +static inline unsigned get_usb_full_speed_rate(unsigned int rate) +{ +	return ((rate << 13) + 62) / 125; +} + +/* + * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) + * this will overflow at approx 4 MHz + */ +static inline unsigned get_usb_high_speed_rate(unsigned int rate) +{ +	return ((rate << 10) + 62) / 125; +} + +/* + * unlink active urbs. + */ +static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) +{ +	struct snd_usb_audio *chip = subs->stream->chip; +	unsigned int i; +	int async; + +	subs->running = 0; + +	if (!force && subs->stream->chip->shutdown) /* to be sure... */ +		return -EBADFD; + +	async = !can_sleep && chip->async_unlink; + +	if (!async && in_interrupt()) +		return 0; + +	for (i = 0; i < subs->nurbs; i++) { +		if (test_bit(i, &subs->active_mask)) { +			if (!test_and_set_bit(i, &subs->unlink_mask)) { +				struct urb *u = subs->dataurb[i].urb; +				if (async) +					usb_unlink_urb(u); +				else +					usb_kill_urb(u); +			} +		} +	} +	if (subs->syncpipe) { +		for (i = 0; i < SYNC_URBS; i++) { +			if (test_bit(i+16, &subs->active_mask)) { +				if (!test_and_set_bit(i+16, &subs->unlink_mask)) { +					struct urb *u = subs->syncurb[i].urb; +					if (async) +						usb_unlink_urb(u); +					else +						usb_kill_urb(u); +				} +			} +		} +	} +	return 0; +} + + +/* + * release a urb data + */ +static void release_urb_ctx(struct snd_urb_ctx *u) +{ +	if (u->urb) { +		if (u->buffer_size) +			usb_buffer_free(u->subs->dev, u->buffer_size, +					u->urb->transfer_buffer, +					u->urb->transfer_dma); +		usb_free_urb(u->urb); +		u->urb = NULL; +	} +} + +/* + *  wait until all urbs are processed. + */ +static int wait_clear_urbs(struct snd_usb_substream *subs) +{ +	unsigned long end_time = jiffies + msecs_to_jiffies(1000); +	unsigned int i; +	int alive; + +	do { +		alive = 0; +		for (i = 0; i < subs->nurbs; i++) { +			if (test_bit(i, &subs->active_mask)) +				alive++; +		} +		if (subs->syncpipe) { +			for (i = 0; i < SYNC_URBS; i++) { +				if (test_bit(i + 16, &subs->active_mask)) +					alive++; +			} +		} +		if (! alive) +			break; +		schedule_timeout_uninterruptible(1); +	} while (time_before(jiffies, end_time)); +	if (alive) +		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); +	return 0; +} + +/* + * release a substream + */ +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) +{ +	int i; + +	/* stop urbs (to be sure) */ +	deactivate_urbs(subs, force, 1); +	wait_clear_urbs(subs); + +	for (i = 0; i < MAX_URBS; i++) +		release_urb_ctx(&subs->dataurb[i]); +	for (i = 0; i < SYNC_URBS; i++) +		release_urb_ctx(&subs->syncurb[i]); +	usb_buffer_free(subs->dev, SYNC_URBS * 4, +			subs->syncbuf, subs->sync_dma); +	subs->syncbuf = NULL; +	subs->nurbs = 0; +} + +/* + * complete callback from data urb + */ +static void snd_complete_urb(struct urb *urb) +{ +	struct snd_urb_ctx *ctx = urb->context; +	struct snd_usb_substream *subs = ctx->subs; +	struct snd_pcm_substream *substream = ctx->subs->pcm_substream; +	int err = 0; + +	if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || +	    !subs->running || /* can be stopped during retire callback */ +	    (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || +	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { +		clear_bit(ctx->index, &subs->active_mask); +		if (err < 0) { +			snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); +			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); +		} +	} +} + + +/* + * complete callback from sync urb + */ +static void snd_complete_sync_urb(struct urb *urb) +{ +	struct snd_urb_ctx *ctx = urb->context; +	struct snd_usb_substream *subs = ctx->subs; +	struct snd_pcm_substream *substream = ctx->subs->pcm_substream; +	int err = 0; + +	if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || +	    !subs->running || /* can be stopped during retire callback */ +	    (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || +	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { +		clear_bit(ctx->index + 16, &subs->active_mask); +		if (err < 0) { +			snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); +			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); +		} +	} +} + + +/* + * initialize a substream for plaback/capture + */ +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, +				unsigned int period_bytes, +				unsigned int rate, +				unsigned int frame_bits) +{ +	unsigned int maxsize, i; +	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; +	unsigned int urb_packs, total_packs, packs_per_ms; +	struct snd_usb_audio *chip = subs->stream->chip; + +	/* calculate the frequency in 16.16 format */ +	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) +		subs->freqn = get_usb_full_speed_rate(rate); +	else +		subs->freqn = get_usb_high_speed_rate(rate); +	subs->freqm = subs->freqn; +	/* calculate max. frequency */ +	if (subs->maxpacksize) { +		/* whatever fits into a max. size packet */ +		maxsize = subs->maxpacksize; +		subs->freqmax = (maxsize / (frame_bits >> 3)) +				<< (16 - subs->datainterval); +	} else { +		/* no max. packet size: just take 25% higher than nominal */ +		subs->freqmax = subs->freqn + (subs->freqn >> 2); +		maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) +				>> (16 - subs->datainterval); +	} +	subs->phase = 0; + +	if (subs->fill_max) +		subs->curpacksize = subs->maxpacksize; +	else +		subs->curpacksize = maxsize; + +	if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) +		packs_per_ms = 8 >> subs->datainterval; +	else +		packs_per_ms = 1; + +	if (is_playback) { +		urb_packs = max(chip->nrpacks, 1); +		urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); +	} else +		urb_packs = 1; +	urb_packs *= packs_per_ms; +	if (subs->syncpipe) +		urb_packs = min(urb_packs, 1U << subs->syncinterval); + +	/* decide how many packets to be used */ +	if (is_playback) { +		unsigned int minsize, maxpacks; +		/* determine how small a packet can be */ +		minsize = (subs->freqn >> (16 - subs->datainterval)) +			  * (frame_bits >> 3); +		/* with sync from device, assume it can be 12% lower */ +		if (subs->syncpipe) +			minsize -= minsize >> 3; +		minsize = max(minsize, 1u); +		total_packs = (period_bytes + minsize - 1) / minsize; +		/* we need at least two URBs for queueing */ +		if (total_packs < 2) { +			total_packs = 2; +		} else { +			/* and we don't want too long a queue either */ +			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); +			total_packs = min(total_packs, maxpacks); +		} +	} else { +		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) +			urb_packs >>= 1; +		total_packs = MAX_URBS * urb_packs; +	} +	subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; +	if (subs->nurbs > MAX_URBS) { +		/* too much... */ +		subs->nurbs = MAX_URBS; +		total_packs = MAX_URBS * urb_packs; +	} else if (subs->nurbs < 2) { +		/* too little - we need at least two packets +		 * to ensure contiguous playback/capture +		 */ +		subs->nurbs = 2; +	} + +	/* allocate and initialize data urbs */ +	for (i = 0; i < subs->nurbs; i++) { +		struct snd_urb_ctx *u = &subs->dataurb[i]; +		u->index = i; +		u->subs = subs; +		u->packets = (i + 1) * total_packs / subs->nurbs +			- i * total_packs / subs->nurbs; +		u->buffer_size = maxsize * u->packets; +		if (subs->fmt_type == UAC_FORMAT_TYPE_II) +			u->packets++; /* for transfer delimiter */ +		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); +		if (!u->urb) +			goto out_of_memory; +		u->urb->transfer_buffer = +			usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL, +					 &u->urb->transfer_dma); +		if (!u->urb->transfer_buffer) +			goto out_of_memory; +		u->urb->pipe = subs->datapipe; +		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; +		u->urb->interval = 1 << subs->datainterval; +		u->urb->context = u; +		u->urb->complete = snd_complete_urb; +	} + +	if (subs->syncpipe) { +		/* allocate and initialize sync urbs */ +		subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4, +						 GFP_KERNEL, &subs->sync_dma); +		if (!subs->syncbuf) +			goto out_of_memory; +		for (i = 0; i < SYNC_URBS; i++) { +			struct snd_urb_ctx *u = &subs->syncurb[i]; +			u->index = i; +			u->subs = subs; +			u->packets = 1; +			u->urb = usb_alloc_urb(1, GFP_KERNEL); +			if (!u->urb) +				goto out_of_memory; +			u->urb->transfer_buffer = subs->syncbuf + i * 4; +			u->urb->transfer_dma = subs->sync_dma + i * 4; +			u->urb->transfer_buffer_length = 4; +			u->urb->pipe = subs->syncpipe; +			u->urb->transfer_flags = URB_ISO_ASAP | +						 URB_NO_TRANSFER_DMA_MAP; +			u->urb->number_of_packets = 1; +			u->urb->interval = 1 << subs->syncinterval; +			u->urb->context = u; +			u->urb->complete = snd_complete_sync_urb; +		} +	} +	return 0; + +out_of_memory: +	snd_usb_release_substream_urbs(subs, 0); +	return -ENOMEM; +} + +/* + * prepare urb for full speed capture sync pipe + * + * fill the length and offset of each urb descriptor. + * the fixed 10.14 frequency is passed through the pipe. + */ +static int prepare_capture_sync_urb(struct snd_usb_substream *subs, +				    struct snd_pcm_runtime *runtime, +				    struct urb *urb) +{ +	unsigned char *cp = urb->transfer_buffer; +	struct snd_urb_ctx *ctx = urb->context; + +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	urb->iso_frame_desc[0].length = 3; +	urb->iso_frame_desc[0].offset = 0; +	cp[0] = subs->freqn >> 2; +	cp[1] = subs->freqn >> 10; +	cp[2] = subs->freqn >> 18; +	return 0; +} + +/* + * prepare urb for high speed capture sync pipe + * + * fill the length and offset of each urb descriptor. + * the fixed 12.13 frequency is passed as 16.16 through the pipe. + */ +static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, +				       struct snd_pcm_runtime *runtime, +				       struct urb *urb) +{ +	unsigned char *cp = urb->transfer_buffer; +	struct snd_urb_ctx *ctx = urb->context; + +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	urb->iso_frame_desc[0].length = 4; +	urb->iso_frame_desc[0].offset = 0; +	cp[0] = subs->freqn; +	cp[1] = subs->freqn >> 8; +	cp[2] = subs->freqn >> 16; +	cp[3] = subs->freqn >> 24; +	return 0; +} + +/* + * process after capture sync complete + * - nothing to do + */ +static int retire_capture_sync_urb(struct snd_usb_substream *subs, +				   struct snd_pcm_runtime *runtime, +				   struct urb *urb) +{ +	return 0; +} + +/* + * prepare urb for capture data pipe + * + * fill the offset and length of each descriptor. + * + * we use a temporary buffer to write the captured data. + * since the length of written data is determined by host, we cannot + * write onto the pcm buffer directly...  the data is thus copied + * later at complete callback to the global buffer. + */ +static int prepare_capture_urb(struct snd_usb_substream *subs, +			       struct snd_pcm_runtime *runtime, +			       struct urb *urb) +{ +	int i, offs; +	struct snd_urb_ctx *ctx = urb->context; + +	offs = 0; +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	for (i = 0; i < ctx->packets; i++) { +		urb->iso_frame_desc[i].offset = offs; +		urb->iso_frame_desc[i].length = subs->curpacksize; +		offs += subs->curpacksize; +	} +	urb->transfer_buffer_length = offs; +	urb->number_of_packets = ctx->packets; +	return 0; +} + +/* + * process after capture complete + * + * copy the data from each desctiptor to the pcm buffer, and + * update the current position. + */ +static int retire_capture_urb(struct snd_usb_substream *subs, +			      struct snd_pcm_runtime *runtime, +			      struct urb *urb) +{ +	unsigned long flags; +	unsigned char *cp; +	int i; +	unsigned int stride, frames, bytes, oldptr; +	int period_elapsed = 0; + +	stride = runtime->frame_bits >> 3; + +	for (i = 0; i < urb->number_of_packets; i++) { +		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; +		if (urb->iso_frame_desc[i].status) { +			snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); +			// continue; +		} +		bytes = urb->iso_frame_desc[i].actual_length; +		frames = bytes / stride; +		if (!subs->txfr_quirk) +			bytes = frames * stride; +		if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE +			int oldbytes = bytes; +#endif +			bytes = frames * stride; +			snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", +							oldbytes, bytes); +		} +		/* update the current pointer */ +		spin_lock_irqsave(&subs->lock, flags); +		oldptr = subs->hwptr_done; +		subs->hwptr_done += bytes; +		if (subs->hwptr_done >= runtime->buffer_size * stride) +			subs->hwptr_done -= runtime->buffer_size * stride; +		frames = (bytes + (oldptr % stride)) / stride; +		subs->transfer_done += frames; +		if (subs->transfer_done >= runtime->period_size) { +			subs->transfer_done -= runtime->period_size; +			period_elapsed = 1; +		} +		spin_unlock_irqrestore(&subs->lock, flags); +		/* copy a data chunk */ +		if (oldptr + bytes > runtime->buffer_size * stride) { +			unsigned int bytes1 = +					runtime->buffer_size * stride - oldptr; +			memcpy(runtime->dma_area + oldptr, cp, bytes1); +			memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); +		} else { +			memcpy(runtime->dma_area + oldptr, cp, bytes); +		} +	} +	if (period_elapsed) +		snd_pcm_period_elapsed(subs->pcm_substream); +	return 0; +} + +/* + * Process after capture complete when paused.  Nothing to do. + */ +static int retire_paused_capture_urb(struct snd_usb_substream *subs, +				     struct snd_pcm_runtime *runtime, +				     struct urb *urb) +{ +	return 0; +} + + +/* + * prepare urb for full speed playback sync pipe + * + * set up the offset and length to receive the current frequency. + */ + +static int prepare_playback_sync_urb(struct snd_usb_substream *subs, +				     struct snd_pcm_runtime *runtime, +				     struct urb *urb) +{ +	struct snd_urb_ctx *ctx = urb->context; + +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	urb->iso_frame_desc[0].length = 3; +	urb->iso_frame_desc[0].offset = 0; +	return 0; +} + +/* + * prepare urb for high speed playback sync pipe + * + * set up the offset and length to receive the current frequency. + */ + +static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, +					struct snd_pcm_runtime *runtime, +					struct urb *urb) +{ +	struct snd_urb_ctx *ctx = urb->context; + +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	urb->iso_frame_desc[0].length = 4; +	urb->iso_frame_desc[0].offset = 0; +	return 0; +} + +/* + * process after full speed playback sync complete + * + * retrieve the current 10.14 frequency from pipe, and set it. + * the value is referred in prepare_playback_urb(). + */ +static int retire_playback_sync_urb(struct snd_usb_substream *subs, +				    struct snd_pcm_runtime *runtime, +				    struct urb *urb) +{ +	unsigned int f; +	unsigned long flags; + +	if (urb->iso_frame_desc[0].status == 0 && +	    urb->iso_frame_desc[0].actual_length == 3) { +		f = combine_triple((u8*)urb->transfer_buffer) << 2; +		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { +			spin_lock_irqsave(&subs->lock, flags); +			subs->freqm = f; +			spin_unlock_irqrestore(&subs->lock, flags); +		} +	} + +	return 0; +} + +/* + * process after high speed playback sync complete + * + * retrieve the current 12.13 frequency from pipe, and set it. + * the value is referred in prepare_playback_urb(). + */ +static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs, +				       struct snd_pcm_runtime *runtime, +				       struct urb *urb) +{ +	unsigned int f; +	unsigned long flags; + +	if (urb->iso_frame_desc[0].status == 0 && +	    urb->iso_frame_desc[0].actual_length == 4) { +		f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; +		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { +			spin_lock_irqsave(&subs->lock, flags); +			subs->freqm = f; +			spin_unlock_irqrestore(&subs->lock, flags); +		} +	} + +	return 0; +} + +/* + * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete + * + * These devices return the number of samples per packet instead of the number + * of samples per microframe. + */ +static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs, +					   struct snd_pcm_runtime *runtime, +					   struct urb *urb) +{ +	unsigned int f; +	unsigned long flags; + +	if (urb->iso_frame_desc[0].status == 0 && +	    urb->iso_frame_desc[0].actual_length == 4) { +		f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; +		f >>= subs->datainterval; +		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { +			spin_lock_irqsave(&subs->lock, flags); +			subs->freqm = f; +			spin_unlock_irqrestore(&subs->lock, flags); +		} +	} + +	return 0; +} + +/* determine the number of frames in the next packet */ +static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) +{ +	if (subs->fill_max) +		return subs->maxframesize; +	else { +		subs->phase = (subs->phase & 0xffff) +			+ (subs->freqm << subs->datainterval); +		return min(subs->phase >> 16, subs->maxframesize); +	} +} + +/* + * Prepare urb for streaming before playback starts or when paused. + * + * We don't have any data, so we send silence. + */ +static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, +				       struct snd_pcm_runtime *runtime, +				       struct urb *urb) +{ +	unsigned int i, offs, counts; +	struct snd_urb_ctx *ctx = urb->context; +	int stride = runtime->frame_bits >> 3; + +	offs = 0; +	urb->dev = ctx->subs->dev; +	for (i = 0; i < ctx->packets; ++i) { +		counts = snd_usb_audio_next_packet_size(subs); +		urb->iso_frame_desc[i].offset = offs * stride; +		urb->iso_frame_desc[i].length = counts * stride; +		offs += counts; +	} +	urb->number_of_packets = ctx->packets; +	urb->transfer_buffer_length = offs * stride; +	memset(urb->transfer_buffer, +	       runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, +	       offs * stride); +	return 0; +} + +/* + * prepare urb for playback data pipe + * + * Since a URB can handle only a single linear buffer, we must use double + * buffering when the data to be transferred overflows the buffer boundary. + * To avoid inconsistencies when updating hwptr_done, we use double buffering + * for all URBs. + */ +static int prepare_playback_urb(struct snd_usb_substream *subs, +				struct snd_pcm_runtime *runtime, +				struct urb *urb) +{ +	int i, stride; +	unsigned int counts, frames, bytes; +	unsigned long flags; +	int period_elapsed = 0; +	struct snd_urb_ctx *ctx = urb->context; + +	stride = runtime->frame_bits >> 3; + +	frames = 0; +	urb->dev = ctx->subs->dev; /* we need to set this at each time */ +	urb->number_of_packets = 0; +	spin_lock_irqsave(&subs->lock, flags); +	for (i = 0; i < ctx->packets; i++) { +		counts = snd_usb_audio_next_packet_size(subs); +		/* set up descriptor */ +		urb->iso_frame_desc[i].offset = frames * stride; +		urb->iso_frame_desc[i].length = counts * stride; +		frames += counts; +		urb->number_of_packets++; +		subs->transfer_done += counts; +		if (subs->transfer_done >= runtime->period_size) { +			subs->transfer_done -= runtime->period_size; +			period_elapsed = 1; +			if (subs->fmt_type == UAC_FORMAT_TYPE_II) { +				if (subs->transfer_done > 0) { +					/* FIXME: fill-max mode is not +					 * supported yet */ +					frames -= subs->transfer_done; +					counts -= subs->transfer_done; +					urb->iso_frame_desc[i].length = +						counts * stride; +					subs->transfer_done = 0; +				} +				i++; +				if (i < ctx->packets) { +					/* add a transfer delimiter */ +					urb->iso_frame_desc[i].offset = +						frames * stride; +					urb->iso_frame_desc[i].length = 0; +					urb->number_of_packets++; +				} +				break; +			} +		} +		if (period_elapsed) /* finish at the period boundary */ +			break; +	} +	bytes = frames * stride; +	if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { +		/* err, the transferred area goes over buffer boundary. */ +		unsigned int bytes1 = +			runtime->buffer_size * stride - subs->hwptr_done; +		memcpy(urb->transfer_buffer, +		       runtime->dma_area + subs->hwptr_done, bytes1); +		memcpy(urb->transfer_buffer + bytes1, +		       runtime->dma_area, bytes - bytes1); +	} else { +		memcpy(urb->transfer_buffer, +		       runtime->dma_area + subs->hwptr_done, bytes); +	} +	subs->hwptr_done += bytes; +	if (subs->hwptr_done >= runtime->buffer_size * stride) +		subs->hwptr_done -= runtime->buffer_size * stride; +	runtime->delay += frames; +	spin_unlock_irqrestore(&subs->lock, flags); +	urb->transfer_buffer_length = bytes; +	if (period_elapsed) +		snd_pcm_period_elapsed(subs->pcm_substream); +	return 0; +} + +/* + * process after playback data complete + * - decrease the delay count again + */ +static int retire_playback_urb(struct snd_usb_substream *subs, +			       struct snd_pcm_runtime *runtime, +			       struct urb *urb) +{ +	unsigned long flags; +	int stride = runtime->frame_bits >> 3; +	int processed = urb->transfer_buffer_length / stride; + +	spin_lock_irqsave(&subs->lock, flags); +	if (processed > runtime->delay) +		runtime->delay = 0; +	else +		runtime->delay -= processed; +	spin_unlock_irqrestore(&subs->lock, flags); +	return 0; +} + +static const char *usb_error_string(int err) +{ +	switch (err) { +	case -ENODEV: +		return "no device"; +	case -ENOENT: +		return "endpoint not enabled"; +	case -EPIPE: +		return "endpoint stalled"; +	case -ENOSPC: +		return "not enough bandwidth"; +	case -ESHUTDOWN: +		return "device disabled"; +	case -EHOSTUNREACH: +		return "device suspended"; +	case -EINVAL: +	case -EAGAIN: +	case -EFBIG: +	case -EMSGSIZE: +		return "internal error"; +	default: +		return "unknown error"; +	} +} + +/* + * set up and start data/sync urbs + */ +static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) +{ +	unsigned int i; +	int err; + +	if (subs->stream->chip->shutdown) +		return -EBADFD; + +	for (i = 0; i < subs->nurbs; i++) { +		if (snd_BUG_ON(!subs->dataurb[i].urb)) +			return -EINVAL; +		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { +			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i); +			goto __error; +		} +	} +	if (subs->syncpipe) { +		for (i = 0; i < SYNC_URBS; i++) { +			if (snd_BUG_ON(!subs->syncurb[i].urb)) +				return -EINVAL; +			if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) { +				snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i); +				goto __error; +			} +		} +	} + +	subs->active_mask = 0; +	subs->unlink_mask = 0; +	subs->running = 1; +	for (i = 0; i < subs->nurbs; i++) { +		err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC); +		if (err < 0) { +			snd_printk(KERN_ERR "cannot submit datapipe " +				   "for urb %d, error %d: %s\n", +				   i, err, usb_error_string(err)); +			goto __error; +		} +		set_bit(i, &subs->active_mask); +	} +	if (subs->syncpipe) { +		for (i = 0; i < SYNC_URBS; i++) { +			err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC); +			if (err < 0) { +				snd_printk(KERN_ERR "cannot submit syncpipe " +					   "for urb %d, error %d: %s\n", +					   i, err, usb_error_string(err)); +				goto __error; +			} +			set_bit(i + 16, &subs->active_mask); +		} +	} +	return 0; + + __error: +	// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); +	deactivate_urbs(subs, 0, 0); +	return -EPIPE; +} + + +/* + */ +static struct snd_urb_ops audio_urb_ops[2] = { +	{ +		.prepare =	prepare_nodata_playback_urb, +		.retire =	retire_playback_urb, +		.prepare_sync =	prepare_playback_sync_urb, +		.retire_sync =	retire_playback_sync_urb, +	}, +	{ +		.prepare =	prepare_capture_urb, +		.retire =	retire_capture_urb, +		.prepare_sync =	prepare_capture_sync_urb, +		.retire_sync =	retire_capture_sync_urb, +	}, +}; + +static struct snd_urb_ops audio_urb_ops_high_speed[2] = { +	{ +		.prepare =	prepare_nodata_playback_urb, +		.retire =	retire_playback_urb, +		.prepare_sync =	prepare_playback_sync_urb_hs, +		.retire_sync =	retire_playback_sync_urb_hs, +	}, +	{ +		.prepare =	prepare_capture_urb, +		.retire =	retire_capture_urb, +		.prepare_sync =	prepare_capture_sync_urb_hs, +		.retire_sync =	retire_capture_sync_urb, +	}, +}; + +/* + * initialize the substream instance. + */ + +void snd_usb_init_substream(struct snd_usb_stream *as, +			    int stream, struct audioformat *fp) +{ +	struct snd_usb_substream *subs = &as->substream[stream]; + +	INIT_LIST_HEAD(&subs->fmt_list); +	spin_lock_init(&subs->lock); + +	subs->stream = as; +	subs->direction = stream; +	subs->dev = as->chip->dev; +	subs->txfr_quirk = as->chip->txfr_quirk; +	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { +		subs->ops = audio_urb_ops[stream]; +	} else { +		subs->ops = audio_urb_ops_high_speed[stream]; +		switch (as->chip->usb_id) { +		case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ +		case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ +		case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ +			subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; +			break; +		case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8  */ +		case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ +			subs->ops.prepare_sync = prepare_playback_sync_urb; +			subs->ops.retire_sync = retire_playback_sync_urb; +			break; +		} +	} + +	snd_usb_set_pcm_ops(as->pcm, stream); + +	list_add_tail(&fp->list, &subs->fmt_list); +	subs->formats |= fp->formats; +	subs->endpoint = fp->endpoint; +	subs->num_formats++; +	subs->fmt_type = fp->fmt_type; +} + +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ +	struct snd_usb_substream *subs = substream->runtime->private_data; + +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_START: +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		subs->ops.prepare = prepare_playback_urb; +		return 0; +	case SNDRV_PCM_TRIGGER_STOP: +		return deactivate_urbs(subs, 0, 0); +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		subs->ops.prepare = prepare_nodata_playback_urb; +		return 0; +	} + +	return -EINVAL; +} + +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ +	struct snd_usb_substream *subs = substream->runtime->private_data; + +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_START: +		subs->ops.retire = retire_capture_urb; +		return start_urbs(subs, substream->runtime); +	case SNDRV_PCM_TRIGGER_STOP: +		return deactivate_urbs(subs, 0, 0); +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		subs->ops.retire = retire_paused_capture_urb; +		return 0; +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		subs->ops.retire = retire_capture_urb; +		return 0; +	} + +	return -EINVAL; +} + +int snd_usb_substream_prepare(struct snd_usb_substream *subs, +			      struct snd_pcm_runtime *runtime) +{ +	/* clear urbs (to be sure) */ +	deactivate_urbs(subs, 0, 1); +	wait_clear_urbs(subs); + +	/* for playback, submit the URBs now; otherwise, the first hwptr_done +	 * updates for all URBs would happen at the same time when starting */ +	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { +		subs->ops.prepare = prepare_nodata_playback_urb; +		return start_urbs(subs, runtime); +	} + +	return 0; +} + diff --git a/sound/usb/urb.h b/sound/usb/urb.h new file mode 100644 index 00000000000..888da38079c --- /dev/null +++ b/sound/usb/urb.h @@ -0,0 +1,21 @@ +#ifndef __USBAUDIO_URB_H +#define __USBAUDIO_URB_H + +void snd_usb_init_substream(struct snd_usb_stream *as, +			    int stream, +			    struct audioformat *fp); + +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, +				unsigned int period_bytes, +				unsigned int rate, +				unsigned int frame_bits); + +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); + +int snd_usb_substream_prepare(struct snd_usb_substream *subs, +			      struct snd_pcm_runtime *runtime); + +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd); + +#endif /* __USBAUDIO_URB_H */ diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c deleted file mode 100644 index 11b0826b8fe..00000000000 --- a/sound/usb/usbaudio.c +++ /dev/null @@ -1,4050 +0,0 @@ -/* - *   (Tentative) USB Audio Driver for ALSA - * - *   Main and PCM part - * - *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> - * - *   Many codes borrowed from audio.c by - *	    Alan Cox (alan@lxorguk.ukuu.org.uk) - *	    Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * - *   This program is free software; you can redistribute it and/or modify - *   it under the terms of the GNU General Public License as published by - *   the Free Software Foundation; either version 2 of the License, or - *   (at your option) any later version. - * - *   This program is distributed in the hope that it will be useful, - *   but WITHOUT ANY WARRANTY; without even the implied warranty of - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - *   GNU General Public License for more details. - * - *   You should have received a copy of the GNU General Public License - *   along with this program; if not, write to the Free Software - *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - * - * - *  NOTES: - * - *   - async unlink should be used for avoiding the sleep inside lock. - *     2.4.22 usb-uhci seems buggy for async unlinking and results in - *     oops.  in such a cse, pass async_unlink=0 option. - *   - the linked URBs would be preferred but not used so far because of - *     the instability of unlinking. - *   - type II is not supported properly.  there is no device which supports - *     this type *correctly*.  SB extigy looks as if it supports, but it's - *     indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). - */ - - -#include <linux/bitops.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/usb.h> -#include <linux/moduleparam.h> -#include <linux/mutex.h> -#include <linux/usb/audio.h> -#include <linux/usb/ch9.h> - -#include <sound/core.h> -#include <sound/info.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> - -#include "usbaudio.h" - - -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); -MODULE_DESCRIPTION("USB Audio"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}"); - - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ -/* Vendor/product IDs for this card */ -static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; -static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; -static int nrpacks = 8;		/* max. number of packets per urb */ -static int async_unlink = 1; -static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ -static int ignore_ctl_error; - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for the USB audio adapter."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable USB audio adapter."); -module_param_array(vid, int, NULL, 0444); -MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device."); -module_param_array(pid, int, NULL, 0444); -MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); -module_param(nrpacks, int, 0644); -MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); -module_param(async_unlink, bool, 0444); -MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); -module_param_array(device_setup, int, NULL, 0444); -MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); -module_param(ignore_ctl_error, bool, 0444); -MODULE_PARM_DESC(ignore_ctl_error, -		 "Ignore errors from USB controller for mixer interfaces."); - -/* - * debug the h/w constraints - */ -/* #define HW_CONST_DEBUG */ - - -/* - * - */ - -#define MAX_PACKS	20 -#define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */ -#define MAX_URBS	8 -#define SYNC_URBS	4	/* always four urbs for sync */ -#define MAX_QUEUE	24	/* try not to exceed this queue length, in ms */ - -struct audioformat { -	struct list_head list; -	snd_pcm_format_t format;	/* format type */ -	unsigned int channels;		/* # channels */ -	unsigned int fmt_type;		/* USB audio format type (1-3) */ -	unsigned int frame_size;	/* samples per frame for non-audio */ -	int iface;			/* interface number */ -	unsigned char altsetting;	/* corresponding alternate setting */ -	unsigned char altset_idx;	/* array index of altenate setting */ -	unsigned char attributes;	/* corresponding attributes of cs endpoint */ -	unsigned char endpoint;		/* endpoint */ -	unsigned char ep_attr;		/* endpoint attributes */ -	unsigned char datainterval;	/* log_2 of data packet interval */ -	unsigned int maxpacksize;	/* max. packet size */ -	unsigned int rates;		/* rate bitmasks */ -	unsigned int rate_min, rate_max;	/* min/max rates */ -	unsigned int nr_rates;		/* number of rate table entries */ -	unsigned int *rate_table;	/* rate table */ -}; - -struct snd_usb_substream; - -struct snd_urb_ctx { -	struct urb *urb; -	unsigned int buffer_size;	/* size of data buffer, if data URB */ -	struct snd_usb_substream *subs; -	int index;	/* index for urb array */ -	int packets;	/* number of packets per urb */ -}; - -struct snd_urb_ops { -	int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); -	int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); -	int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); -	int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); -}; - -struct snd_usb_substream { -	struct snd_usb_stream *stream; -	struct usb_device *dev; -	struct snd_pcm_substream *pcm_substream; -	int direction;	/* playback or capture */ -	int interface;	/* current interface */ -	int endpoint;	/* assigned endpoint */ -	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */ -	unsigned int cur_rate;		/* current rate (for hw_params callback) */ -	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */ -	unsigned int format;     /* USB data format */ -	unsigned int datapipe;   /* the data i/o pipe */ -	unsigned int syncpipe;   /* 1 - async out or adaptive in */ -	unsigned int datainterval;	/* log_2 of data packet interval */ -	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */ -	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */ -	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */ -	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */ -	unsigned int phase;      /* phase accumulator */ -	unsigned int maxpacksize;	/* max packet size in bytes */ -	unsigned int maxframesize;	/* max packet size in frames */ -	unsigned int curpacksize;	/* current packet size in bytes (for capture) */ -	unsigned int curframesize;	/* current packet size in frames (for capture) */ -	unsigned int fill_max: 1;	/* fill max packet size always */ -	unsigned int txfr_quirk:1;	/* allow sub-frame alignment */ -	unsigned int fmt_type;		/* USB audio format type (1-3) */ - -	unsigned int running: 1;	/* running status */ - -	unsigned int hwptr_done;	/* processed byte position in the buffer */ -	unsigned int transfer_done;		/* processed frames since last period update */ -	unsigned long active_mask;	/* bitmask of active urbs */ -	unsigned long unlink_mask;	/* bitmask of unlinked urbs */ - -	unsigned int nurbs;			/* # urbs */ -	struct snd_urb_ctx dataurb[MAX_URBS];	/* data urb table */ -	struct snd_urb_ctx syncurb[SYNC_URBS];	/* sync urb table */ -	char *syncbuf;				/* sync buffer for all sync URBs */ -	dma_addr_t sync_dma;			/* DMA address of syncbuf */ - -	u64 formats;			/* format bitmasks (all or'ed) */ -	unsigned int num_formats;		/* number of supported audio formats (list) */ -	struct list_head fmt_list;	/* format list */ -	struct snd_pcm_hw_constraint_list rate_list;	/* limited rates */ -	spinlock_t lock; - -	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */ -}; - - -struct snd_usb_stream { -	struct snd_usb_audio *chip; -	struct snd_pcm *pcm; -	int pcm_index; -	unsigned int fmt_type;		/* USB audio format type (1-3) */ -	struct snd_usb_substream substream[2]; -	struct list_head list; -}; - - -/* - * we keep the snd_usb_audio_t instances by ourselves for merging - * the all interfaces on the same card as one sound device. - */ - -static DEFINE_MUTEX(register_mutex); -static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; - - -/* - * convert a sampling rate into our full speed format (fs/1000 in Q16.16) - * this will overflow at approx 524 kHz - */ -static inline unsigned get_usb_full_speed_rate(unsigned int rate) -{ -	return ((rate << 13) + 62) / 125; -} - -/* - * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) - * this will overflow at approx 4 MHz - */ -static inline unsigned get_usb_high_speed_rate(unsigned int rate) -{ -	return ((rate << 10) + 62) / 125; -} - -/* convert our full speed USB rate into sampling rate in Hz */ -static inline unsigned get_full_speed_hz(unsigned int usb_rate) -{ -	return (usb_rate * 125 + (1 << 12)) >> 13; -} - -/* convert our high speed USB rate into sampling rate in Hz */ -static inline unsigned get_high_speed_hz(unsigned int usb_rate) -{ -	return (usb_rate * 125 + (1 << 9)) >> 10; -} - - -/* - * prepare urb for full speed capture sync pipe - * - * fill the length and offset of each urb descriptor. - * the fixed 10.14 frequency is passed through the pipe. - */ -static int prepare_capture_sync_urb(struct snd_usb_substream *subs, -				    struct snd_pcm_runtime *runtime, -				    struct urb *urb) -{ -	unsigned char *cp = urb->transfer_buffer; -	struct snd_urb_ctx *ctx = urb->context; - -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	urb->iso_frame_desc[0].length = 3; -	urb->iso_frame_desc[0].offset = 0; -	cp[0] = subs->freqn >> 2; -	cp[1] = subs->freqn >> 10; -	cp[2] = subs->freqn >> 18; -	return 0; -} - -/* - * prepare urb for high speed capture sync pipe - * - * fill the length and offset of each urb descriptor. - * the fixed 12.13 frequency is passed as 16.16 through the pipe. - */ -static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, -				       struct snd_pcm_runtime *runtime, -				       struct urb *urb) -{ -	unsigned char *cp = urb->transfer_buffer; -	struct snd_urb_ctx *ctx = urb->context; - -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	urb->iso_frame_desc[0].length = 4; -	urb->iso_frame_desc[0].offset = 0; -	cp[0] = subs->freqn; -	cp[1] = subs->freqn >> 8; -	cp[2] = subs->freqn >> 16; -	cp[3] = subs->freqn >> 24; -	return 0; -} - -/* - * process after capture sync complete - * - nothing to do - */ -static int retire_capture_sync_urb(struct snd_usb_substream *subs, -				   struct snd_pcm_runtime *runtime, -				   struct urb *urb) -{ -	return 0; -} - -/* - * prepare urb for capture data pipe - * - * fill the offset and length of each descriptor. - * - * we use a temporary buffer to write the captured data. - * since the length of written data is determined by host, we cannot - * write onto the pcm buffer directly...  the data is thus copied - * later at complete callback to the global buffer. - */ -static int prepare_capture_urb(struct snd_usb_substream *subs, -			       struct snd_pcm_runtime *runtime, -			       struct urb *urb) -{ -	int i, offs; -	struct snd_urb_ctx *ctx = urb->context; - -	offs = 0; -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	for (i = 0; i < ctx->packets; i++) { -		urb->iso_frame_desc[i].offset = offs; -		urb->iso_frame_desc[i].length = subs->curpacksize; -		offs += subs->curpacksize; -	} -	urb->transfer_buffer_length = offs; -	urb->number_of_packets = ctx->packets; -	return 0; -} - -/* - * process after capture complete - * - * copy the data from each desctiptor to the pcm buffer, and - * update the current position. - */ -static int retire_capture_urb(struct snd_usb_substream *subs, -			      struct snd_pcm_runtime *runtime, -			      struct urb *urb) -{ -	unsigned long flags; -	unsigned char *cp; -	int i; -	unsigned int stride, frames, bytes, oldptr; -	int period_elapsed = 0; - -	stride = runtime->frame_bits >> 3; - -	for (i = 0; i < urb->number_of_packets; i++) { -		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; -		if (urb->iso_frame_desc[i].status) { -			snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); -			// continue; -		} -		bytes = urb->iso_frame_desc[i].actual_length; -		frames = bytes / stride; -		if (!subs->txfr_quirk) -			bytes = frames * stride; -		if (bytes % (runtime->sample_bits >> 3) != 0) { -#ifdef CONFIG_SND_DEBUG_VERBOSE -			int oldbytes = bytes; -#endif -			bytes = frames * stride; -			snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", -							oldbytes, bytes); -		} -		/* update the current pointer */ -		spin_lock_irqsave(&subs->lock, flags); -		oldptr = subs->hwptr_done; -		subs->hwptr_done += bytes; -		if (subs->hwptr_done >= runtime->buffer_size * stride) -			subs->hwptr_done -= runtime->buffer_size * stride; -		frames = (bytes + (oldptr % stride)) / stride; -		subs->transfer_done += frames; -		if (subs->transfer_done >= runtime->period_size) { -			subs->transfer_done -= runtime->period_size; -			period_elapsed = 1; -		} -		spin_unlock_irqrestore(&subs->lock, flags); -		/* copy a data chunk */ -		if (oldptr + bytes > runtime->buffer_size * stride) { -			unsigned int bytes1 = -					runtime->buffer_size * stride - oldptr; -			memcpy(runtime->dma_area + oldptr, cp, bytes1); -			memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); -		} else { -			memcpy(runtime->dma_area + oldptr, cp, bytes); -		} -	} -	if (period_elapsed) -		snd_pcm_period_elapsed(subs->pcm_substream); -	return 0; -} - -/* - * Process after capture complete when paused.  Nothing to do. - */ -static int retire_paused_capture_urb(struct snd_usb_substream *subs, -				     struct snd_pcm_runtime *runtime, -				     struct urb *urb) -{ -	return 0; -} - - -/* - * prepare urb for full speed playback sync pipe - * - * set up the offset and length to receive the current frequency. - */ - -static int prepare_playback_sync_urb(struct snd_usb_substream *subs, -				     struct snd_pcm_runtime *runtime, -				     struct urb *urb) -{ -	struct snd_urb_ctx *ctx = urb->context; - -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	urb->iso_frame_desc[0].length = 3; -	urb->iso_frame_desc[0].offset = 0; -	return 0; -} - -/* - * prepare urb for high speed playback sync pipe - * - * set up the offset and length to receive the current frequency. - */ - -static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, -					struct snd_pcm_runtime *runtime, -					struct urb *urb) -{ -	struct snd_urb_ctx *ctx = urb->context; - -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	urb->iso_frame_desc[0].length = 4; -	urb->iso_frame_desc[0].offset = 0; -	return 0; -} - -/* - * process after full speed playback sync complete - * - * retrieve the current 10.14 frequency from pipe, and set it. - * the value is referred in prepare_playback_urb(). - */ -static int retire_playback_sync_urb(struct snd_usb_substream *subs, -				    struct snd_pcm_runtime *runtime, -				    struct urb *urb) -{ -	unsigned int f; -	unsigned long flags; - -	if (urb->iso_frame_desc[0].status == 0 && -	    urb->iso_frame_desc[0].actual_length == 3) { -		f = combine_triple((u8*)urb->transfer_buffer) << 2; -		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { -			spin_lock_irqsave(&subs->lock, flags); -			subs->freqm = f; -			spin_unlock_irqrestore(&subs->lock, flags); -		} -	} - -	return 0; -} - -/* - * process after high speed playback sync complete - * - * retrieve the current 12.13 frequency from pipe, and set it. - * the value is referred in prepare_playback_urb(). - */ -static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs, -				       struct snd_pcm_runtime *runtime, -				       struct urb *urb) -{ -	unsigned int f; -	unsigned long flags; - -	if (urb->iso_frame_desc[0].status == 0 && -	    urb->iso_frame_desc[0].actual_length == 4) { -		f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; -		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { -			spin_lock_irqsave(&subs->lock, flags); -			subs->freqm = f; -			spin_unlock_irqrestore(&subs->lock, flags); -		} -	} - -	return 0; -} - -/* - * process after E-Mu 0202/0404/Tracker Pre high speed playback sync complete - * - * These devices return the number of samples per packet instead of the number - * of samples per microframe. - */ -static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs, -					   struct snd_pcm_runtime *runtime, -					   struct urb *urb) -{ -	unsigned int f; -	unsigned long flags; - -	if (urb->iso_frame_desc[0].status == 0 && -	    urb->iso_frame_desc[0].actual_length == 4) { -		f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; -		f >>= subs->datainterval; -		if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { -			spin_lock_irqsave(&subs->lock, flags); -			subs->freqm = f; -			spin_unlock_irqrestore(&subs->lock, flags); -		} -	} - -	return 0; -} - -/* determine the number of frames in the next packet */ -static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) -{ -	if (subs->fill_max) -		return subs->maxframesize; -	else { -		subs->phase = (subs->phase & 0xffff) -			+ (subs->freqm << subs->datainterval); -		return min(subs->phase >> 16, subs->maxframesize); -	} -} - -/* - * Prepare urb for streaming before playback starts or when paused. - * - * We don't have any data, so we send silence. - */ -static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, -				       struct snd_pcm_runtime *runtime, -				       struct urb *urb) -{ -	unsigned int i, offs, counts; -	struct snd_urb_ctx *ctx = urb->context; -	int stride = runtime->frame_bits >> 3; - -	offs = 0; -	urb->dev = ctx->subs->dev; -	for (i = 0; i < ctx->packets; ++i) { -		counts = snd_usb_audio_next_packet_size(subs); -		urb->iso_frame_desc[i].offset = offs * stride; -		urb->iso_frame_desc[i].length = counts * stride; -		offs += counts; -	} -	urb->number_of_packets = ctx->packets; -	urb->transfer_buffer_length = offs * stride; -	memset(urb->transfer_buffer, -	       subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, -	       offs * stride); -	return 0; -} - -/* - * prepare urb for playback data pipe - * - * Since a URB can handle only a single linear buffer, we must use double - * buffering when the data to be transferred overflows the buffer boundary. - * To avoid inconsistencies when updating hwptr_done, we use double buffering - * for all URBs. - */ -static int prepare_playback_urb(struct snd_usb_substream *subs, -				struct snd_pcm_runtime *runtime, -				struct urb *urb) -{ -	int i, stride; -	unsigned int counts, frames, bytes; -	unsigned long flags; -	int period_elapsed = 0; -	struct snd_urb_ctx *ctx = urb->context; - -	stride = runtime->frame_bits >> 3; - -	frames = 0; -	urb->dev = ctx->subs->dev; /* we need to set this at each time */ -	urb->number_of_packets = 0; -	spin_lock_irqsave(&subs->lock, flags); -	for (i = 0; i < ctx->packets; i++) { -		counts = snd_usb_audio_next_packet_size(subs); -		/* set up descriptor */ -		urb->iso_frame_desc[i].offset = frames * stride; -		urb->iso_frame_desc[i].length = counts * stride; -		frames += counts; -		urb->number_of_packets++; -		subs->transfer_done += counts; -		if (subs->transfer_done >= runtime->period_size) { -			subs->transfer_done -= runtime->period_size; -			period_elapsed = 1; -			if (subs->fmt_type == UAC_FORMAT_TYPE_II) { -				if (subs->transfer_done > 0) { -					/* FIXME: fill-max mode is not -					 * supported yet */ -					frames -= subs->transfer_done; -					counts -= subs->transfer_done; -					urb->iso_frame_desc[i].length = -						counts * stride; -					subs->transfer_done = 0; -				} -				i++; -				if (i < ctx->packets) { -					/* add a transfer delimiter */ -					urb->iso_frame_desc[i].offset = -						frames * stride; -					urb->iso_frame_desc[i].length = 0; -					urb->number_of_packets++; -				} -				break; -			} - 		} -		if (period_elapsed) /* finish at the period boundary */ -			break; -	} -	bytes = frames * stride; -	if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { -		/* err, the transferred area goes over buffer boundary. */ -		unsigned int bytes1 = -			runtime->buffer_size * stride - subs->hwptr_done; -		memcpy(urb->transfer_buffer, -		       runtime->dma_area + subs->hwptr_done, bytes1); -		memcpy(urb->transfer_buffer + bytes1, -		       runtime->dma_area, bytes - bytes1); -	} else { -		memcpy(urb->transfer_buffer, -		       runtime->dma_area + subs->hwptr_done, bytes); -	} -	subs->hwptr_done += bytes; -	if (subs->hwptr_done >= runtime->buffer_size * stride) -		subs->hwptr_done -= runtime->buffer_size * stride; -	runtime->delay += frames; -	spin_unlock_irqrestore(&subs->lock, flags); -	urb->transfer_buffer_length = bytes; -	if (period_elapsed) -		snd_pcm_period_elapsed(subs->pcm_substream); -	return 0; -} - -/* - * process after playback data complete - * - decrease the delay count again - */ -static int retire_playback_urb(struct snd_usb_substream *subs, -			       struct snd_pcm_runtime *runtime, -			       struct urb *urb) -{ -	unsigned long flags; -	int stride = runtime->frame_bits >> 3; -	int processed = urb->transfer_buffer_length / stride; - -	spin_lock_irqsave(&subs->lock, flags); -	if (processed > runtime->delay) -		runtime->delay = 0; -	else -		runtime->delay -= processed; -	spin_unlock_irqrestore(&subs->lock, flags); -	return 0; -} - - -/* - */ -static struct snd_urb_ops audio_urb_ops[2] = { -	{ -		.prepare =	prepare_nodata_playback_urb, -		.retire =	retire_playback_urb, -		.prepare_sync =	prepare_playback_sync_urb, -		.retire_sync =	retire_playback_sync_urb, -	}, -	{ -		.prepare =	prepare_capture_urb, -		.retire =	retire_capture_urb, -		.prepare_sync =	prepare_capture_sync_urb, -		.retire_sync =	retire_capture_sync_urb, -	}, -}; - -static struct snd_urb_ops audio_urb_ops_high_speed[2] = { -	{ -		.prepare =	prepare_nodata_playback_urb, -		.retire =	retire_playback_urb, -		.prepare_sync =	prepare_playback_sync_urb_hs, -		.retire_sync =	retire_playback_sync_urb_hs, -	}, -	{ -		.prepare =	prepare_capture_urb, -		.retire =	retire_capture_urb, -		.prepare_sync =	prepare_capture_sync_urb_hs, -		.retire_sync =	retire_capture_sync_urb, -	}, -}; - -/* - * complete callback from data urb - */ -static void snd_complete_urb(struct urb *urb) -{ -	struct snd_urb_ctx *ctx = urb->context; -	struct snd_usb_substream *subs = ctx->subs; -	struct snd_pcm_substream *substream = ctx->subs->pcm_substream; -	int err = 0; - -	if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || -	    !subs->running || /* can be stopped during retire callback */ -	    (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || -	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { -		clear_bit(ctx->index, &subs->active_mask); -		if (err < 0) { -			snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); -			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); -		} -	} -} - - -/* - * complete callback from sync urb - */ -static void snd_complete_sync_urb(struct urb *urb) -{ -	struct snd_urb_ctx *ctx = urb->context; -	struct snd_usb_substream *subs = ctx->subs; -	struct snd_pcm_substream *substream = ctx->subs->pcm_substream; -	int err = 0; - -	if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || -	    !subs->running || /* can be stopped during retire callback */ -	    (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || -	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { -		clear_bit(ctx->index + 16, &subs->active_mask); -		if (err < 0) { -			snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); -			snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); -		} -	} -} - - -/* - * unlink active urbs. - */ -static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) -{ -	unsigned int i; -	int async; - -	subs->running = 0; - -	if (!force && subs->stream->chip->shutdown) /* to be sure... */ -		return -EBADFD; - -	async = !can_sleep && async_unlink; - -	if (!async && in_interrupt()) -		return 0; - -	for (i = 0; i < subs->nurbs; i++) { -		if (test_bit(i, &subs->active_mask)) { -			if (!test_and_set_bit(i, &subs->unlink_mask)) { -				struct urb *u = subs->dataurb[i].urb; -				if (async) -					usb_unlink_urb(u); -				else -					usb_kill_urb(u); -			} -		} -	} -	if (subs->syncpipe) { -		for (i = 0; i < SYNC_URBS; i++) { -			if (test_bit(i+16, &subs->active_mask)) { -				if (!test_and_set_bit(i+16, &subs->unlink_mask)) { -					struct urb *u = subs->syncurb[i].urb; -					if (async) -						usb_unlink_urb(u); -					else -						usb_kill_urb(u); -				} -			} -		} -	} -	return 0; -} - - -static const char *usb_error_string(int err) -{ -	switch (err) { -	case -ENODEV: -		return "no device"; -	case -ENOENT: -		return "endpoint not enabled"; -	case -EPIPE: -		return "endpoint stalled"; -	case -ENOSPC: -		return "not enough bandwidth"; -	case -ESHUTDOWN: -		return "device disabled"; -	case -EHOSTUNREACH: -		return "device suspended"; -	case -EINVAL: -	case -EAGAIN: -	case -EFBIG: -	case -EMSGSIZE: -		return "internal error"; -	default: -		return "unknown error"; -	} -} - -/* - * set up and start data/sync urbs - */ -static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) -{ -	unsigned int i; -	int err; - -	if (subs->stream->chip->shutdown) -		return -EBADFD; - -	for (i = 0; i < subs->nurbs; i++) { -		if (snd_BUG_ON(!subs->dataurb[i].urb)) -			return -EINVAL; -		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { -			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i); -			goto __error; -		} -	} -	if (subs->syncpipe) { -		for (i = 0; i < SYNC_URBS; i++) { -			if (snd_BUG_ON(!subs->syncurb[i].urb)) -				return -EINVAL; -			if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) { -				snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i); -				goto __error; -			} -		} -	} - -	subs->active_mask = 0; -	subs->unlink_mask = 0; -	subs->running = 1; -	for (i = 0; i < subs->nurbs; i++) { -		err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC); -		if (err < 0) { -			snd_printk(KERN_ERR "cannot submit datapipe " -				   "for urb %d, error %d: %s\n", -				   i, err, usb_error_string(err)); -			goto __error; -		} -		set_bit(i, &subs->active_mask); -	} -	if (subs->syncpipe) { -		for (i = 0; i < SYNC_URBS; i++) { -			err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC); -			if (err < 0) { -				snd_printk(KERN_ERR "cannot submit syncpipe " -					   "for urb %d, error %d: %s\n", -					   i, err, usb_error_string(err)); -				goto __error; -			} -			set_bit(i + 16, &subs->active_mask); -		} -	} -	return 0; - - __error: -	// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); -	deactivate_urbs(subs, 0, 0); -	return -EPIPE; -} - - -/* - *  wait until all urbs are processed. - */ -static int wait_clear_urbs(struct snd_usb_substream *subs) -{ -	unsigned long end_time = jiffies + msecs_to_jiffies(1000); -	unsigned int i; -	int alive; - -	do { -		alive = 0; -		for (i = 0; i < subs->nurbs; i++) { -			if (test_bit(i, &subs->active_mask)) -				alive++; -		} -		if (subs->syncpipe) { -			for (i = 0; i < SYNC_URBS; i++) { -				if (test_bit(i + 16, &subs->active_mask)) -					alive++; -			} -		} -		if (! alive) -			break; -		schedule_timeout_uninterruptible(1); -	} while (time_before(jiffies, end_time)); -	if (alive) -		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); -	return 0; -} - - -/* - * return the current pcm pointer.  just based on the hwptr_done value. - */ -static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) -{ -	struct snd_usb_substream *subs; -	unsigned int hwptr_done; -	 -	subs = (struct snd_usb_substream *)substream->runtime->private_data; -	spin_lock(&subs->lock); -	hwptr_done = subs->hwptr_done; -	spin_unlock(&subs->lock); -	return hwptr_done / (substream->runtime->frame_bits >> 3); -} - - -/* - * start/stop playback substream - */ -static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream, -					int cmd) -{ -	struct snd_usb_substream *subs = substream->runtime->private_data; - -	switch (cmd) { -	case SNDRV_PCM_TRIGGER_START: -	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		subs->ops.prepare = prepare_playback_urb; -		return 0; -	case SNDRV_PCM_TRIGGER_STOP: -		return deactivate_urbs(subs, 0, 0); -	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		subs->ops.prepare = prepare_nodata_playback_urb; -		return 0; -	default: -		return -EINVAL; -	} -} - -/* - * start/stop capture substream - */ -static int snd_usb_pcm_capture_trigger(struct snd_pcm_substream *substream, -				       int cmd) -{ -	struct snd_usb_substream *subs = substream->runtime->private_data; - -	switch (cmd) { -	case SNDRV_PCM_TRIGGER_START: -		subs->ops.retire = retire_capture_urb; -		return start_urbs(subs, substream->runtime); -	case SNDRV_PCM_TRIGGER_STOP: -		return deactivate_urbs(subs, 0, 0); -	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		subs->ops.retire = retire_paused_capture_urb; -		return 0; -	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		subs->ops.retire = retire_capture_urb; -		return 0; -	default: -		return -EINVAL; -	} -} - - -/* - * release a urb data - */ -static void release_urb_ctx(struct snd_urb_ctx *u) -{ -	if (u->urb) { -		if (u->buffer_size) -			usb_buffer_free(u->subs->dev, u->buffer_size, -					u->urb->transfer_buffer, -					u->urb->transfer_dma); -		usb_free_urb(u->urb); -		u->urb = NULL; -	} -} - -/* - * release a substream - */ -static void release_substream_urbs(struct snd_usb_substream *subs, int force) -{ -	int i; - -	/* stop urbs (to be sure) */ -	deactivate_urbs(subs, force, 1); -	wait_clear_urbs(subs); - -	for (i = 0; i < MAX_URBS; i++) -		release_urb_ctx(&subs->dataurb[i]); -	for (i = 0; i < SYNC_URBS; i++) -		release_urb_ctx(&subs->syncurb[i]); -	usb_buffer_free(subs->dev, SYNC_URBS * 4, -			subs->syncbuf, subs->sync_dma); -	subs->syncbuf = NULL; -	subs->nurbs = 0; -} - -/* - * initialize a substream for plaback/capture - */ -static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes, -			       unsigned int rate, unsigned int frame_bits) -{ -	unsigned int maxsize, i; -	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; -	unsigned int urb_packs, total_packs, packs_per_ms; - -	/* calculate the frequency in 16.16 format */ -	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) -		subs->freqn = get_usb_full_speed_rate(rate); -	else -		subs->freqn = get_usb_high_speed_rate(rate); -	subs->freqm = subs->freqn; -	/* calculate max. frequency */ -	if (subs->maxpacksize) { -		/* whatever fits into a max. size packet */ -		maxsize = subs->maxpacksize; -		subs->freqmax = (maxsize / (frame_bits >> 3)) -				<< (16 - subs->datainterval); -	} else { -		/* no max. packet size: just take 25% higher than nominal */ -		subs->freqmax = subs->freqn + (subs->freqn >> 2); -		maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) -				>> (16 - subs->datainterval); -	} -	subs->phase = 0; - -	if (subs->fill_max) -		subs->curpacksize = subs->maxpacksize; -	else -		subs->curpacksize = maxsize; - -	if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) -		packs_per_ms = 8 >> subs->datainterval; -	else -		packs_per_ms = 1; - -	if (is_playback) { -		urb_packs = max(nrpacks, 1); -		urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); -	} else -		urb_packs = 1; -	urb_packs *= packs_per_ms; -	if (subs->syncpipe) -		urb_packs = min(urb_packs, 1U << subs->syncinterval); - -	/* decide how many packets to be used */ -	if (is_playback) { -		unsigned int minsize, maxpacks; -		/* determine how small a packet can be */ -		minsize = (subs->freqn >> (16 - subs->datainterval)) -			  * (frame_bits >> 3); -		/* with sync from device, assume it can be 12% lower */ -		if (subs->syncpipe) -			minsize -= minsize >> 3; -		minsize = max(minsize, 1u); -		total_packs = (period_bytes + minsize - 1) / minsize; -		/* we need at least two URBs for queueing */ -		if (total_packs < 2) { -			total_packs = 2; -		} else { -			/* and we don't want too long a queue either */ -			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); -			total_packs = min(total_packs, maxpacks); -		} -	} else { -		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) -			urb_packs >>= 1; -		total_packs = MAX_URBS * urb_packs; -	} -	subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; -	if (subs->nurbs > MAX_URBS) { -		/* too much... */ -		subs->nurbs = MAX_URBS; -		total_packs = MAX_URBS * urb_packs; -	} else if (subs->nurbs < 2) { -		/* too little - we need at least two packets -		 * to ensure contiguous playback/capture -		 */ -		subs->nurbs = 2; -	} - -	/* allocate and initialize data urbs */ -	for (i = 0; i < subs->nurbs; i++) { -		struct snd_urb_ctx *u = &subs->dataurb[i]; -		u->index = i; -		u->subs = subs; -		u->packets = (i + 1) * total_packs / subs->nurbs -			- i * total_packs / subs->nurbs; -		u->buffer_size = maxsize * u->packets; -		if (subs->fmt_type == UAC_FORMAT_TYPE_II) -			u->packets++; /* for transfer delimiter */ -		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); -		if (!u->urb) -			goto out_of_memory; -		u->urb->transfer_buffer = -			usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL, -					 &u->urb->transfer_dma); -		if (!u->urb->transfer_buffer) -			goto out_of_memory; -		u->urb->pipe = subs->datapipe; -		u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; -		u->urb->interval = 1 << subs->datainterval; -		u->urb->context = u; -		u->urb->complete = snd_complete_urb; -	} - -	if (subs->syncpipe) { -		/* allocate and initialize sync urbs */ -		subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4, -						 GFP_KERNEL, &subs->sync_dma); -		if (!subs->syncbuf) -			goto out_of_memory; -		for (i = 0; i < SYNC_URBS; i++) { -			struct snd_urb_ctx *u = &subs->syncurb[i]; -			u->index = i; -			u->subs = subs; -			u->packets = 1; -			u->urb = usb_alloc_urb(1, GFP_KERNEL); -			if (!u->urb) -				goto out_of_memory; -			u->urb->transfer_buffer = subs->syncbuf + i * 4; -			u->urb->transfer_dma = subs->sync_dma + i * 4; -			u->urb->transfer_buffer_length = 4; -			u->urb->pipe = subs->syncpipe; -			u->urb->transfer_flags = URB_ISO_ASAP | -						 URB_NO_TRANSFER_DMA_MAP; -			u->urb->number_of_packets = 1; -			u->urb->interval = 1 << subs->syncinterval; -			u->urb->context = u; -			u->urb->complete = snd_complete_sync_urb; -		} -	} -	return 0; - -out_of_memory: -	release_substream_urbs(subs, 0); -	return -ENOMEM; -} - - -/* - * find a matching audio format - */ -static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, -				       unsigned int rate, unsigned int channels) -{ -	struct list_head *p; -	struct audioformat *found = NULL; -	int cur_attr = 0, attr; - -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		if (fp->format != format || fp->channels != channels) -			continue; -		if (rate < fp->rate_min || rate > fp->rate_max) -			continue; -		if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { -			unsigned int i; -			for (i = 0; i < fp->nr_rates; i++) -				if (fp->rate_table[i] == rate) -					break; -			if (i >= fp->nr_rates) -				continue; -		} -		attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; -		if (! found) { -			found = fp; -			cur_attr = attr; -			continue; -		} -		/* avoid async out and adaptive in if the other method -		 * supports the same format. -		 * this is a workaround for the case like -		 * M-audio audiophile USB. -		 */ -		if (attr != cur_attr) { -			if ((attr == USB_ENDPOINT_SYNC_ASYNC && -			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || -			    (attr == USB_ENDPOINT_SYNC_ADAPTIVE && -			     subs->direction == SNDRV_PCM_STREAM_CAPTURE)) -				continue; -			if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC && -			     subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || -			    (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE && -			     subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { -				found = fp; -				cur_attr = attr; -				continue; -			} -		} -		/* find the format with the largest max. packet size */ -		if (fp->maxpacksize > found->maxpacksize) { -			found = fp; -			cur_attr = attr; -		} -	} -	return found; -} - - -/* - * initialize the picth control and sample rate - */ -static int init_usb_pitch(struct usb_device *dev, int iface, -			  struct usb_host_interface *alts, -			  struct audioformat *fmt) -{ -	unsigned int ep; -	unsigned char data[1]; -	int err; - -	ep = get_endpoint(alts, 0)->bEndpointAddress; -	/* if endpoint has pitch control, enable it */ -	if (fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL) { -		data[0] = 1; -		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, -					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, -					   UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { -			snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", -				   dev->devnum, iface, ep); -			return err; -		} -	} -	return 0; -} - -static int init_usb_sample_rate(struct usb_device *dev, int iface, -				struct usb_host_interface *alts, -				struct audioformat *fmt, int rate) -{ -	unsigned int ep; -	unsigned char data[3]; -	int err; - -	ep = get_endpoint(alts, 0)->bEndpointAddress; -	/* if endpoint has sampling rate control, set it */ -	if (fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE) { -		int crate; -		data[0] = rate; -		data[1] = rate >> 8; -		data[2] = rate >> 16; -		if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, -					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, -					   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { -			snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", -				   dev->devnum, iface, fmt->altsetting, rate, ep); -			return err; -		} -		if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, -					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, -					   UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { -			snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", -				   dev->devnum, iface, fmt->altsetting, ep); -			return 0; /* some devices don't support reading */ -		} -		crate = data[0] | (data[1] << 8) | (data[2] << 16); -		if (crate != rate) { -			snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); -			// runtime->rate = crate; -		} -	} -	return 0; -} - -/* - * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, - * not for interface. - */ -static void set_format_emu_quirk(struct snd_usb_substream *subs, -				 struct audioformat *fmt) -{ -	unsigned char emu_samplerate_id = 0; - -	/* When capture is active -	 * sample rate shouldn't be changed -	 * by playback substream -	 */ -	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { -		if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) -			return; -	} - -	switch (fmt->rate_min) { -	case 48000: -		emu_samplerate_id = EMU_QUIRK_SR_48000HZ; -		break; -	case 88200: -		emu_samplerate_id = EMU_QUIRK_SR_88200HZ; -		break; -	case 96000: -		emu_samplerate_id = EMU_QUIRK_SR_96000HZ; -		break; -	case 176400: -		emu_samplerate_id = EMU_QUIRK_SR_176400HZ; -		break; -	case 192000: -		emu_samplerate_id = EMU_QUIRK_SR_192000HZ; -		break; -	default: -		emu_samplerate_id = EMU_QUIRK_SR_44100HZ; -		break; -	} -	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); -} - -/* - * find a matching format and set up the interface - */ -static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) -{ -	struct usb_device *dev = subs->dev; -	struct usb_host_interface *alts; -	struct usb_interface_descriptor *altsd; -	struct usb_interface *iface; -	unsigned int ep, attr; -	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; -	int err; - -	iface = usb_ifnum_to_if(dev, fmt->iface); -	if (WARN_ON(!iface)) -		return -EINVAL; -	alts = &iface->altsetting[fmt->altset_idx]; -	altsd = get_iface_desc(alts); -	if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) -		return -EINVAL; - -	if (fmt == subs->cur_audiofmt) -		return 0; - -	/* close the old interface */ -	if (subs->interface >= 0 && subs->interface != fmt->iface) { -		if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { -			snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", -				dev->devnum, fmt->iface, fmt->altsetting); -			return -EIO; -		} -		subs->interface = -1; -		subs->format = 0; -	} - -	/* set interface */ -	if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) { -		if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) { -			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", -				   dev->devnum, fmt->iface, fmt->altsetting); -			return -EIO; -		} -		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); -		subs->interface = fmt->iface; -		subs->format = fmt->altset_idx; -	} - -	/* create a data pipe */ -	ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK; -	if (is_playback) -		subs->datapipe = usb_sndisocpipe(dev, ep); -	else -		subs->datapipe = usb_rcvisocpipe(dev, ep); -	subs->datainterval = fmt->datainterval; -	subs->syncpipe = subs->syncinterval = 0; -	subs->maxpacksize = fmt->maxpacksize; -	subs->fill_max = 0; - -	/* we need a sync pipe in async OUT or adaptive IN mode */ -	/* check the number of EP, since some devices have broken -	 * descriptors which fool us.  if it has only one EP, -	 * assume it as adaptive-out or sync-in. -	 */ -	attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; -	if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || -	     (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && -	    altsd->bNumEndpoints >= 2) { -		/* check sync-pipe endpoint */ -		/* ... and check descriptor size before accessing bSynchAddress -		   because there is a version of the SB Audigy 2 NX firmware lacking -		   the audio fields in the endpoint descriptors */ -		if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || -		    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && -		     get_endpoint(alts, 1)->bSynchAddress != 0)) { -			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", -				   dev->devnum, fmt->iface, fmt->altsetting); -			return -EINVAL; -		} -		ep = get_endpoint(alts, 1)->bEndpointAddress; -		if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && -		    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || -		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { -			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", -				   dev->devnum, fmt->iface, fmt->altsetting); -			return -EINVAL; -		} -		ep &= USB_ENDPOINT_NUMBER_MASK; -		if (is_playback) -			subs->syncpipe = usb_rcvisocpipe(dev, ep); -		else -			subs->syncpipe = usb_sndisocpipe(dev, ep); -		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && -		    get_endpoint(alts, 1)->bRefresh >= 1 && -		    get_endpoint(alts, 1)->bRefresh <= 9) -			subs->syncinterval = get_endpoint(alts, 1)->bRefresh; -		else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) -			subs->syncinterval = 1; -		else if (get_endpoint(alts, 1)->bInterval >= 1 && -			 get_endpoint(alts, 1)->bInterval <= 16) -			subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; -		else -			subs->syncinterval = 3; -	} - -	/* always fill max packet size */ -	if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) -		subs->fill_max = 1; - -	if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) -		return err; - -	subs->cur_audiofmt = fmt; - -	switch (subs->stream->chip->usb_id) { -	case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ -	case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ -	case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ -		set_format_emu_quirk(subs, fmt); -		break; -	} - -#if 0 -	printk(KERN_DEBUG -	       "setting done: format = %d, rate = %d..%d, channels = %d\n", -	       fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels); -	printk(KERN_DEBUG -	       "  datapipe = 0x%0x, syncpipe = 0x%0x\n", -	       subs->datapipe, subs->syncpipe); -#endif - -	return 0; -} - -/* - * hw_params callback - * - * allocate a buffer and set the given audio format. - * - * so far we use a physically linear buffer although packetize transfer - * doesn't need a continuous area. - * if sg buffer is supported on the later version of alsa, we'll follow - * that. - */ -static int snd_usb_hw_params(struct snd_pcm_substream *substream, -			     struct snd_pcm_hw_params *hw_params) -{ -	struct snd_usb_substream *subs = substream->runtime->private_data; -	struct audioformat *fmt; -	unsigned int channels, rate, format; -	int ret, changed; - -	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, -					       params_buffer_bytes(hw_params)); -	if (ret < 0) -		return ret; - -	format = params_format(hw_params); -	rate = params_rate(hw_params); -	channels = params_channels(hw_params); -	fmt = find_format(subs, format, rate, channels); -	if (!fmt) { -		snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", -			   format, rate, channels); -		return -EINVAL; -	} - -	changed = subs->cur_audiofmt != fmt || -		subs->period_bytes != params_period_bytes(hw_params) || -		subs->cur_rate != rate; -	if ((ret = set_format(subs, fmt)) < 0) -		return ret; - -	if (subs->cur_rate != rate) { -		struct usb_host_interface *alts; -		struct usb_interface *iface; -		iface = usb_ifnum_to_if(subs->dev, fmt->iface); -		alts = &iface->altsetting[fmt->altset_idx]; -		ret = init_usb_sample_rate(subs->dev, subs->interface, alts, fmt, rate); -		if (ret < 0) -			return ret; -		subs->cur_rate = rate; -	} - -	if (changed) { -		/* format changed */ -		release_substream_urbs(subs, 0); -		/* influenced: period_bytes, channels, rate, format, */ -		ret = init_substream_urbs(subs, params_period_bytes(hw_params), -					  params_rate(hw_params), -					  snd_pcm_format_physical_width(params_format(hw_params)) * params_channels(hw_params)); -	} - -	return ret; -} - -/* - * hw_free callback - * - * reset the audio format and release the buffer - */ -static int snd_usb_hw_free(struct snd_pcm_substream *substream) -{ -	struct snd_usb_substream *subs = substream->runtime->private_data; - -	subs->cur_audiofmt = NULL; -	subs->cur_rate = 0; -	subs->period_bytes = 0; -	if (!subs->stream->chip->shutdown) -		release_substream_urbs(subs, 0); -	return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -/* - * prepare callback - * - * only a few subtle things... - */ -static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) -{ -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct snd_usb_substream *subs = runtime->private_data; - -	if (! subs->cur_audiofmt) { -		snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); -		return -ENXIO; -	} - -	/* some unit conversions in runtime */ -	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); -	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); - -	/* reset the pointer */ -	subs->hwptr_done = 0; -	subs->transfer_done = 0; -	subs->phase = 0; -	runtime->delay = 0; - -	/* clear urbs (to be sure) */ -	deactivate_urbs(subs, 0, 1); -	wait_clear_urbs(subs); - -	/* for playback, submit the URBs now; otherwise, the first hwptr_done -	 * updates for all URBs would happen at the same time when starting */ -	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { -		subs->ops.prepare = prepare_nodata_playback_urb; -		return start_urbs(subs, runtime); -	} else -		return 0; -} - -static struct snd_pcm_hardware snd_usb_hardware = -{ -	.info =			SNDRV_PCM_INFO_MMAP | -				SNDRV_PCM_INFO_MMAP_VALID | -				SNDRV_PCM_INFO_BATCH | -				SNDRV_PCM_INFO_INTERLEAVED | -				SNDRV_PCM_INFO_BLOCK_TRANSFER | -				SNDRV_PCM_INFO_PAUSE, -	.buffer_bytes_max =	1024 * 1024, -	.period_bytes_min =	64, -	.period_bytes_max =	512 * 1024, -	.periods_min =		2, -	.periods_max =		1024, -}; - -/* - * h/w constraints - */ - -#ifdef HW_CONST_DEBUG -#define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -#define hwc_debug(fmt, args...) /**/ -#endif - -static int hw_check_valid_format(struct snd_usb_substream *subs, -				 struct snd_pcm_hw_params *params, -				 struct audioformat *fp) -{ -	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); -	struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); -	struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); -	struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); -	unsigned int ptime; - -	/* check the format */ -	if (!snd_mask_test(fmts, fp->format)) { -		hwc_debug("   > check: no supported format %d\n", fp->format); -		return 0; -	} -	/* check the channels */ -	if (fp->channels < ct->min || fp->channels > ct->max) { -		hwc_debug("   > check: no valid channels %d (%d/%d)\n", fp->channels, ct->min, ct->max); -		return 0; -	} -	/* check the rate is within the range */ -	if (fp->rate_min > it->max || (fp->rate_min == it->max && it->openmax)) { -		hwc_debug("   > check: rate_min %d > max %d\n", fp->rate_min, it->max); -		return 0; -	} -	if (fp->rate_max < it->min || (fp->rate_max == it->min && it->openmin)) { -		hwc_debug("   > check: rate_max %d < min %d\n", fp->rate_max, it->min); -		return 0; -	} -	/* check whether the period time is >= the data packet interval */ -	if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { -		ptime = 125 * (1 << fp->datainterval); -		if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { -			hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max); -			return 0; -		} -	} -	return 1; -} - -static int hw_rule_rate(struct snd_pcm_hw_params *params, -			struct snd_pcm_hw_rule *rule) -{ -	struct snd_usb_substream *subs = rule->private; -	struct list_head *p; -	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); -	unsigned int rmin, rmax; -	int changed; - -	hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max); -	changed = 0; -	rmin = rmax = 0; -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		if (!hw_check_valid_format(subs, params, fp)) -			continue; -		if (changed++) { -			if (rmin > fp->rate_min) -				rmin = fp->rate_min; -			if (rmax < fp->rate_max) -				rmax = fp->rate_max; -		} else { -			rmin = fp->rate_min; -			rmax = fp->rate_max; -		} -	} - -	if (!changed) { -		hwc_debug("  --> get empty\n"); -		it->empty = 1; -		return -EINVAL; -	} - -	changed = 0; -	if (it->min < rmin) { -		it->min = rmin; -		it->openmin = 0; -		changed = 1; -	} -	if (it->max > rmax) { -		it->max = rmax; -		it->openmax = 0; -		changed = 1; -	} -	if (snd_interval_checkempty(it)) { -		it->empty = 1; -		return -EINVAL; -	} -	hwc_debug("  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); -	return changed; -} - - -static int hw_rule_channels(struct snd_pcm_hw_params *params, -			    struct snd_pcm_hw_rule *rule) -{ -	struct snd_usb_substream *subs = rule->private; -	struct list_head *p; -	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); -	unsigned int rmin, rmax; -	int changed; - -	hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max); -	changed = 0; -	rmin = rmax = 0; -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		if (!hw_check_valid_format(subs, params, fp)) -			continue; -		if (changed++) { -			if (rmin > fp->channels) -				rmin = fp->channels; -			if (rmax < fp->channels) -				rmax = fp->channels; -		} else { -			rmin = fp->channels; -			rmax = fp->channels; -		} -	} - -	if (!changed) { -		hwc_debug("  --> get empty\n"); -		it->empty = 1; -		return -EINVAL; -	} - -	changed = 0; -	if (it->min < rmin) { -		it->min = rmin; -		it->openmin = 0; -		changed = 1; -	} -	if (it->max > rmax) { -		it->max = rmax; -		it->openmax = 0; -		changed = 1; -	} -	if (snd_interval_checkempty(it)) { -		it->empty = 1; -		return -EINVAL; -	} -	hwc_debug("  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); -	return changed; -} - -static int hw_rule_format(struct snd_pcm_hw_params *params, -			  struct snd_pcm_hw_rule *rule) -{ -	struct snd_usb_substream *subs = rule->private; -	struct list_head *p; -	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); -	u64 fbits; -	u32 oldbits[2]; -	int changed; - -	hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]); -	fbits = 0; -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		if (!hw_check_valid_format(subs, params, fp)) -			continue; -		fbits |= (1ULL << fp->format); -	} - -	oldbits[0] = fmt->bits[0]; -	oldbits[1] = fmt->bits[1]; -	fmt->bits[0] &= (u32)fbits; -	fmt->bits[1] &= (u32)(fbits >> 32); -	if (!fmt->bits[0] && !fmt->bits[1]) { -		hwc_debug("  --> get empty\n"); -		return -EINVAL; -	} -	changed = (oldbits[0] != fmt->bits[0] || oldbits[1] != fmt->bits[1]); -	hwc_debug("  --> %x:%x (changed = %d)\n", fmt->bits[0], fmt->bits[1], changed); -	return changed; -} - -static int hw_rule_period_time(struct snd_pcm_hw_params *params, -			       struct snd_pcm_hw_rule *rule) -{ -	struct snd_usb_substream *subs = rule->private; -	struct audioformat *fp; -	struct snd_interval *it; -	unsigned char min_datainterval; -	unsigned int pmin; -	int changed; - -	it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); -	hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); -	min_datainterval = 0xff; -	list_for_each_entry(fp, &subs->fmt_list, list) { -		if (!hw_check_valid_format(subs, params, fp)) -			continue; -		min_datainterval = min(min_datainterval, fp->datainterval); -	} -	if (min_datainterval == 0xff) { -		hwc_debug("  --> get emtpy\n"); -		it->empty = 1; -		return -EINVAL; -	} -	pmin = 125 * (1 << min_datainterval); -	changed = 0; -	if (it->min < pmin) { -		it->min = pmin; -		it->openmin = 0; -		changed = 1; -	} -	if (snd_interval_checkempty(it)) { -		it->empty = 1; -		return -EINVAL; -	} -	hwc_debug("  --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); -	return changed; -} - -/* - *  If the device supports unusual bit rates, does the request meet these? - */ -static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, -				  struct snd_usb_substream *subs) -{ -	struct audioformat *fp; -	int count = 0, needs_knot = 0; -	int err; - -	list_for_each_entry(fp, &subs->fmt_list, list) { -		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) -			return 0; -		count += fp->nr_rates; -		if (fp->rates & SNDRV_PCM_RATE_KNOT) -			needs_knot = 1; -	} -	if (!needs_knot) -		return 0; - -	subs->rate_list.count = count; -	subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); -	subs->rate_list.mask = 0; -	count = 0; -	list_for_each_entry(fp, &subs->fmt_list, list) { -		int i; -		for (i = 0; i < fp->nr_rates; i++) -			subs->rate_list.list[count++] = fp->rate_table[i]; -	} -	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -					 &subs->rate_list); -	if (err < 0) -		return err; - -	return 0; -} - - -/* - * set up the runtime hardware information. - */ - -static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) -{ -	struct list_head *p; -	unsigned int pt, ptmin; -	int param_period_time_if_needed; -	int err; - -	runtime->hw.formats = subs->formats; - -	runtime->hw.rate_min = 0x7fffffff; -	runtime->hw.rate_max = 0; -	runtime->hw.channels_min = 256; -	runtime->hw.channels_max = 0; -	runtime->hw.rates = 0; -	ptmin = UINT_MAX; -	/* check min/max rates and channels */ -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		runtime->hw.rates |= fp->rates; -		if (runtime->hw.rate_min > fp->rate_min) -			runtime->hw.rate_min = fp->rate_min; -		if (runtime->hw.rate_max < fp->rate_max) -			runtime->hw.rate_max = fp->rate_max; -		if (runtime->hw.channels_min > fp->channels) -			runtime->hw.channels_min = fp->channels; -		if (runtime->hw.channels_max < fp->channels) -			runtime->hw.channels_max = fp->channels; -		if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) { -			/* FIXME: there might be more than one audio formats... */ -			runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = -				fp->frame_size; -		} -		pt = 125 * (1 << fp->datainterval); -		ptmin = min(ptmin, pt); -	} - -	param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; -	if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) -		/* full speed devices have fixed data packet interval */ -		ptmin = 1000; -	if (ptmin == 1000) -		/* if period time doesn't go below 1 ms, no rules needed */ -		param_period_time_if_needed = -1; -	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -				     ptmin, UINT_MAX); - -	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -				       hw_rule_rate, subs, -				       SNDRV_PCM_HW_PARAM_FORMAT, -				       SNDRV_PCM_HW_PARAM_CHANNELS, -				       param_period_time_if_needed, -				       -1)) < 0) -		return err; -	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, -				       hw_rule_channels, subs, -				       SNDRV_PCM_HW_PARAM_FORMAT, -				       SNDRV_PCM_HW_PARAM_RATE, -				       param_period_time_if_needed, -				       -1)) < 0) -		return err; -	if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, -				       hw_rule_format, subs, -				       SNDRV_PCM_HW_PARAM_RATE, -				       SNDRV_PCM_HW_PARAM_CHANNELS, -				       param_period_time_if_needed, -				       -1)) < 0) -		return err; -	if (param_period_time_if_needed >= 0) { -		err = snd_pcm_hw_rule_add(runtime, 0, -					  SNDRV_PCM_HW_PARAM_PERIOD_TIME, -					  hw_rule_period_time, subs, -					  SNDRV_PCM_HW_PARAM_FORMAT, -					  SNDRV_PCM_HW_PARAM_CHANNELS, -					  SNDRV_PCM_HW_PARAM_RATE, -					  -1); -		if (err < 0) -			return err; -	} -	if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) -		return err; -	return 0; -} - -static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) -{ -	struct snd_usb_stream *as = snd_pcm_substream_chip(substream); -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct snd_usb_substream *subs = &as->substream[direction]; - -	subs->interface = -1; -	subs->format = 0; -	runtime->hw = snd_usb_hardware; -	runtime->private_data = subs; -	subs->pcm_substream = substream; -	return setup_hw_info(runtime, subs); -} - -static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) -{ -	struct snd_usb_stream *as = snd_pcm_substream_chip(substream); -	struct snd_usb_substream *subs = &as->substream[direction]; - -	if (!as->chip->shutdown && subs->interface >= 0) { -		usb_set_interface(subs->dev, subs->interface, 0); -		subs->interface = -1; -	} -	subs->pcm_substream = NULL; -	return 0; -} - -static int snd_usb_playback_open(struct snd_pcm_substream *substream) -{ -	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); -} - -static int snd_usb_playback_close(struct snd_pcm_substream *substream) -{ -	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK); -} - -static int snd_usb_capture_open(struct snd_pcm_substream *substream) -{ -	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); -} - -static int snd_usb_capture_close(struct snd_pcm_substream *substream) -{ -	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); -} - -static struct snd_pcm_ops snd_usb_playback_ops = { -	.open =		snd_usb_playback_open, -	.close =	snd_usb_playback_close, -	.ioctl =	snd_pcm_lib_ioctl, -	.hw_params =	snd_usb_hw_params, -	.hw_free =	snd_usb_hw_free, -	.prepare =	snd_usb_pcm_prepare, -	.trigger =	snd_usb_pcm_playback_trigger, -	.pointer =	snd_usb_pcm_pointer, -	.page =		snd_pcm_lib_get_vmalloc_page, -	.mmap =		snd_pcm_lib_mmap_vmalloc, -}; - -static struct snd_pcm_ops snd_usb_capture_ops = { -	.open =		snd_usb_capture_open, -	.close =	snd_usb_capture_close, -	.ioctl =	snd_pcm_lib_ioctl, -	.hw_params =	snd_usb_hw_params, -	.hw_free =	snd_usb_hw_free, -	.prepare =	snd_usb_pcm_prepare, -	.trigger =	snd_usb_pcm_capture_trigger, -	.pointer =	snd_usb_pcm_pointer, -	.page =		snd_pcm_lib_get_vmalloc_page, -	.mmap =		snd_pcm_lib_mmap_vmalloc, -}; - - - -/* - * helper functions - */ - -/* - * combine bytes and get an integer value - */ -unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size) -{ -	switch (size) { -	case 1:  return *bytes; -	case 2:  return combine_word(bytes); -	case 3:  return combine_triple(bytes); -	case 4:  return combine_quad(bytes); -	default: return 0; -	} -} - -/* - * parse descriptor buffer and return the pointer starting the given - * descriptor type. - */ -void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype) -{ -	u8 *p, *end, *next; - -	p = descstart; -	end = p + desclen; -	for (; p < end;) { -		if (p[0] < 2) -			return NULL; -		next = p + p[0]; -		if (next > end) -			return NULL; -		if (p[1] == dtype && (!after || (void *)p > after)) { -			return p; -		} -		p = next; -	} -	return NULL; -} - -/* - * find a class-specified interface descriptor with the given subtype. - */ -void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype) -{ -	unsigned char *p = after; - -	while ((p = snd_usb_find_desc(buffer, buflen, p, -				      USB_DT_CS_INTERFACE)) != NULL) { -		if (p[0] >= 3 && p[2] == dsubtype) -			return p; -	} -	return NULL; -} - -/* - * Wrapper for usb_control_msg(). - * Allocates a temp buffer to prevent dmaing from/to the stack. - */ -int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, -		    __u8 requesttype, __u16 value, __u16 index, void *data, -		    __u16 size, int timeout) -{ -	int err; -	void *buf = NULL; - -	if (size > 0) { -		buf = kmemdup(data, size, GFP_KERNEL); -		if (!buf) -			return -ENOMEM; -	} -	err = usb_control_msg(dev, pipe, request, requesttype, -			      value, index, buf, size, timeout); -	if (size > 0) { -		memcpy(data, buf, size); -		kfree(buf); -	} -	return err; -} - - -/* - * entry point for linux usb interface - */ - -static int usb_audio_probe(struct usb_interface *intf, -			   const struct usb_device_id *id); -static void usb_audio_disconnect(struct usb_interface *intf); - -#ifdef CONFIG_PM -static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message); -static int usb_audio_resume(struct usb_interface *intf); -#else -#define usb_audio_suspend NULL -#define usb_audio_resume NULL -#endif - -static struct usb_device_id usb_audio_ids [] = { -#include "usbquirks.h" -    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), -      .bInterfaceClass = USB_CLASS_AUDIO, -      .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL }, -    { }						/* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_audio_ids); - -static struct usb_driver usb_audio_driver = { -	.name =		"snd-usb-audio", -	.probe =	usb_audio_probe, -	.disconnect =	usb_audio_disconnect, -	.suspend =	usb_audio_suspend, -	.resume =	usb_audio_resume, -	.id_table =	usb_audio_ids, -}; - - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS) - -/* - * proc interface for list the supported pcm formats - */ -static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) -{ -	struct list_head *p; -	static char *sync_types[4] = { -		"NONE", "ASYNC", "ADAPTIVE", "SYNC" -	}; - -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; -		fp = list_entry(p, struct audioformat, list); -		snd_iprintf(buffer, "  Interface %d\n", fp->iface); -		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting); -		snd_iprintf(buffer, "    Format: %s\n", -			    snd_pcm_format_name(fp->format)); -		snd_iprintf(buffer, "    Channels: %d\n", fp->channels); -		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n", -			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK, -			    fp->endpoint & USB_DIR_IN ? "IN" : "OUT", -			    sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]); -		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { -			snd_iprintf(buffer, "    Rates: %d - %d (continuous)\n", -				    fp->rate_min, fp->rate_max); -		} else { -			unsigned int i; -			snd_iprintf(buffer, "    Rates: "); -			for (i = 0; i < fp->nr_rates; i++) { -				if (i > 0) -					snd_iprintf(buffer, ", "); -				snd_iprintf(buffer, "%d", fp->rate_table[i]); -			} -			snd_iprintf(buffer, "\n"); -		} -		if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) -			snd_iprintf(buffer, "    Data packet interval: %d us\n", -				    125 * (1 << fp->datainterval)); -		// snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize); -		// snd_iprintf(buffer, "    EP Attribute = %#x\n", fp->attributes); -	} -} - -static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) -{ -	if (subs->running) { -		unsigned int i; -		snd_iprintf(buffer, "  Status: Running\n"); -		snd_iprintf(buffer, "    Interface = %d\n", subs->interface); -		snd_iprintf(buffer, "    Altset = %d\n", subs->format); -		snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs); -		for (i = 0; i < subs->nurbs; i++) -			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); -		snd_iprintf(buffer, "]\n"); -		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize); -		snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n", -			    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL -			    ? get_full_speed_hz(subs->freqm) -			    : get_high_speed_hz(subs->freqm), -			    subs->freqm >> 16, subs->freqm & 0xffff); -	} else { -		snd_iprintf(buffer, "  Status: Stop\n"); -	} -} - -static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -{ -	struct snd_usb_stream *stream = entry->private_data; - -	snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name); - -	if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) { -		snd_iprintf(buffer, "\nPlayback:\n"); -		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); -		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); -	} -	if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) { -		snd_iprintf(buffer, "\nCapture:\n"); -		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); -		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); -	} -} - -static void proc_pcm_format_add(struct snd_usb_stream *stream) -{ -	struct snd_info_entry *entry; -	char name[32]; -	struct snd_card *card = stream->chip->card; - -	sprintf(name, "stream%d", stream->pcm_index); -	if (!snd_card_proc_new(card, name, &entry)) -		snd_info_set_text_ops(entry, stream, proc_pcm_format_read); -} - -#else - -static inline void proc_pcm_format_add(struct snd_usb_stream *stream) -{ -} - -#endif - -/* - * initialize the substream instance. - */ - -static void init_substream(struct snd_usb_stream *as, int stream, struct audioformat *fp) -{ -	struct snd_usb_substream *subs = &as->substream[stream]; - -	INIT_LIST_HEAD(&subs->fmt_list); -	spin_lock_init(&subs->lock); - -	subs->stream = as; -	subs->direction = stream; -	subs->dev = as->chip->dev; -	subs->txfr_quirk = as->chip->txfr_quirk; -	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { -		subs->ops = audio_urb_ops[stream]; -	} else { -		subs->ops = audio_urb_ops_high_speed[stream]; -		switch (as->chip->usb_id) { -		case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ -		case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ -		case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ -			subs->ops.retire_sync = retire_playback_sync_urb_hs_emu; -			break; -		} -	} -	snd_pcm_set_ops(as->pcm, stream, -			stream == SNDRV_PCM_STREAM_PLAYBACK ? -			&snd_usb_playback_ops : &snd_usb_capture_ops); - -	list_add_tail(&fp->list, &subs->fmt_list); -	subs->formats |= 1ULL << fp->format; -	subs->endpoint = fp->endpoint; -	subs->num_formats++; -	subs->fmt_type = fp->fmt_type; -} - - -/* - * free a substream - */ -static void free_substream(struct snd_usb_substream *subs) -{ -	struct list_head *p, *n; - -	if (!subs->num_formats) -		return; /* not initialized */ -	list_for_each_safe(p, n, &subs->fmt_list) { -		struct audioformat *fp = list_entry(p, struct audioformat, list); -		kfree(fp->rate_table); -		kfree(fp); -	} -	kfree(subs->rate_list.list); -} - - -/* - * free a usb stream instance - */ -static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) -{ -	free_substream(&stream->substream[0]); -	free_substream(&stream->substream[1]); -	list_del(&stream->list); -	kfree(stream); -} - -static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) -{ -	struct snd_usb_stream *stream = pcm->private_data; -	if (stream) { -		stream->pcm = NULL; -		snd_usb_audio_stream_free(stream); -	} -} - - -/* - * add this endpoint to the chip instance. - * if a stream with the same endpoint already exists, append to it. - * if not, create a new pcm stream. - */ -static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) -{ -	struct list_head *p; -	struct snd_usb_stream *as; -	struct snd_usb_substream *subs; -	struct snd_pcm *pcm; -	int err; - -	list_for_each(p, &chip->pcm_list) { -		as = list_entry(p, struct snd_usb_stream, list); -		if (as->fmt_type != fp->fmt_type) -			continue; -		subs = &as->substream[stream]; -		if (!subs->endpoint) -			continue; -		if (subs->endpoint == fp->endpoint) { -			list_add_tail(&fp->list, &subs->fmt_list); -			subs->num_formats++; -			subs->formats |= 1ULL << fp->format; -			return 0; -		} -	} -	/* look for an empty stream */ -	list_for_each(p, &chip->pcm_list) { -		as = list_entry(p, struct snd_usb_stream, list); -		if (as->fmt_type != fp->fmt_type) -			continue; -		subs = &as->substream[stream]; -		if (subs->endpoint) -			continue; -		err = snd_pcm_new_stream(as->pcm, stream, 1); -		if (err < 0) -			return err; -		init_substream(as, stream, fp); -		return 0; -	} - -	/* create a new pcm */ -	as = kzalloc(sizeof(*as), GFP_KERNEL); -	if (!as) -		return -ENOMEM; -	as->pcm_index = chip->pcm_devs; -	as->chip = chip; -	as->fmt_type = fp->fmt_type; -	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, -			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, -			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, -			  &pcm); -	if (err < 0) { -		kfree(as); -		return err; -	} -	as->pcm = pcm; -	pcm->private_data = as; -	pcm->private_free = snd_usb_audio_pcm_free; -	pcm->info_flags = 0; -	if (chip->pcm_devs > 0) -		sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); -	else -		strcpy(pcm->name, "USB Audio"); - -	init_substream(as, stream, fp); - -	list_add(&as->list, &chip->pcm_list); -	chip->pcm_devs++; - -	proc_pcm_format_add(as); - -	return 0; -} - - -/* - * check if the device uses big-endian samples - */ -static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp) -{ -	switch (chip->usb_id) { -	case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ -		if (fp->endpoint & USB_DIR_IN) -			return 1; -		break; -	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ -		if (device_setup[chip->index] == 0x00 || -		    fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3) -			return 1; -	} -	return 0; -} - -/* - * parse the audio format type I descriptor - * and returns the corresponding pcm format - * - * @dev: usb device - * @fp: audioformat record - * @format: the format tag (wFormatTag) - * @fmt: the format type descriptor - */ -static int parse_audio_format_i_type(struct snd_usb_audio *chip, -				     struct audioformat *fp, -				     int format, void *_fmt, -				     int protocol) -{ -	int pcm_format, i; -	int sample_width, sample_bytes; - -	switch (protocol) { -	case UAC_VERSION_1: { -		struct uac_format_type_i_discrete_descriptor *fmt = _fmt; -		sample_width = fmt->bBitResolution; -		sample_bytes = fmt->bSubframeSize; -		break; -	} - -	case UAC_VERSION_2: { -		struct uac_format_type_i_ext_descriptor *fmt = _fmt; -		sample_width = fmt->bBitResolution; -		sample_bytes = fmt->bSubslotSize; - -		/* -		 * FIXME -		 * USB audio class v2 devices specify a bitmap of possible -		 * audio formats rather than one fix value. For now, we just -		 * pick one of them and report that as the only possible -		 * value for this setting. -		 * The bit allocation map is in fact compatible to the -		 * wFormatTag of the v1 AS streaming descriptors, which is why -		 * we can simply map the matrix. -		 */ - -		for (i = 0; i < 5; i++) -			if (format & (1UL << i)) { -				format = i + 1; -				break; -			} - -		break; -	} - -	default: -		return -EINVAL; -	} - -	/* FIXME: correct endianess and sign? */ -	pcm_format = -1; - -	switch (format) { -	case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */ -		snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", -			    chip->dev->devnum, fp->iface, fp->altsetting); -		/* fall-through */ -	case UAC_FORMAT_TYPE_I_PCM: -		if (sample_width > sample_bytes * 8) { -			snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", -				   chip->dev->devnum, fp->iface, fp->altsetting, -				   sample_width, sample_bytes); -		} -		/* check the format byte size */ -		switch (sample_bytes) { -		case 1: -			pcm_format = SNDRV_PCM_FORMAT_S8; -			break; -		case 2: -			if (is_big_endian_format(chip, fp)) -				pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ -			else -				pcm_format = SNDRV_PCM_FORMAT_S16_LE; -			break; -		case 3: -			if (is_big_endian_format(chip, fp)) -				pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ -			else -				pcm_format = SNDRV_PCM_FORMAT_S24_3LE; -			break; -		case 4: -			pcm_format = SNDRV_PCM_FORMAT_S32_LE; -			break; -		default: -			snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", -				   chip->dev->devnum, fp->iface, fp->altsetting, -				   sample_width, sample_bytes); -			break; -		} -		break; -	case UAC_FORMAT_TYPE_I_PCM8: -		pcm_format = SNDRV_PCM_FORMAT_U8; - -		/* Dallas DS4201 workaround: it advertises U8 format, but really -		   supports S8. */ -		if (chip->usb_id == USB_ID(0x04fa, 0x4201)) -			pcm_format = SNDRV_PCM_FORMAT_S8; -		break; -	case UAC_FORMAT_TYPE_I_IEEE_FLOAT: -		pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; -		break; -	case UAC_FORMAT_TYPE_I_ALAW: -		pcm_format = SNDRV_PCM_FORMAT_A_LAW; -		break; -	case UAC_FORMAT_TYPE_I_MULAW: -		pcm_format = SNDRV_PCM_FORMAT_MU_LAW; -		break; -	default: -		snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, format); -		break; -	} -	return pcm_format; -} - - -/* - * parse the format descriptor and stores the possible sample rates - * on the audioformat table (audio class v1). - * - * @dev: usb device - * @fp: audioformat record - * @fmt: the format descriptor - * @offset: the start offset of descriptor pointing the rate type - *          (7 for type I and II, 8 for type II) - */ -static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audioformat *fp, -				       unsigned char *fmt, int offset) -{ -	int nr_rates = fmt[offset]; - -	if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { -		snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", -				   chip->dev->devnum, fp->iface, fp->altsetting); -		return -1; -	} - -	if (nr_rates) { -		/* -		 * build the rate table and bitmap flags -		 */ -		int r, idx; - -		fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); -		if (fp->rate_table == NULL) { -			snd_printk(KERN_ERR "cannot malloc\n"); -			return -1; -		} - -		fp->nr_rates = 0; -		fp->rate_min = fp->rate_max = 0; -		for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { -			unsigned int rate = combine_triple(&fmt[idx]); -			if (!rate) -				continue; -			/* C-Media CM6501 mislabels its 96 kHz altsetting */ -			if (rate == 48000 && nr_rates == 1 && -			    (chip->usb_id == USB_ID(0x0d8c, 0x0201) || -			     chip->usb_id == USB_ID(0x0d8c, 0x0102)) && -			    fp->altsetting == 5 && fp->maxpacksize == 392) -				rate = 96000; -			/* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ -			if (rate == 16000 && chip->usb_id == USB_ID(0x041e, 0x4068)) -				rate = 8000; -			fp->rate_table[fp->nr_rates] = rate; -			if (!fp->rate_min || rate < fp->rate_min) -				fp->rate_min = rate; -			if (!fp->rate_max || rate > fp->rate_max) -				fp->rate_max = rate; -			fp->rates |= snd_pcm_rate_to_rate_bit(rate); -			fp->nr_rates++; -		} -		if (!fp->nr_rates) { -			hwc_debug("All rates were zero. Skipping format!\n"); -			return -1; -		} -	} else { -		/* continuous rates */ -		fp->rates = SNDRV_PCM_RATE_CONTINUOUS; -		fp->rate_min = combine_triple(&fmt[offset + 1]); -		fp->rate_max = combine_triple(&fmt[offset + 4]); -	} -	return 0; -} - -/* - * parse the format descriptor and stores the possible sample rates - * on the audioformat table (audio class v2). - */ -static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, -				       struct audioformat *fp, -				       struct usb_host_interface *iface) -{ -	struct usb_device *dev = chip->dev; -	unsigned char tmp[2], *data; -	int i, nr_rates, data_size, ret = 0; - -	/* get the number of sample rates first by only fetching 2 bytes */ -	ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, -			       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, -			       0x0100, chip->clock_id << 8, tmp, sizeof(tmp), 1000); - -	if (ret < 0) { -		snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); -		goto err; -	} - -	nr_rates = (tmp[1] << 8) | tmp[0]; -	data_size = 2 + 12 * nr_rates; -	data = kzalloc(data_size, GFP_KERNEL); -	if (!data) { -		ret = -ENOMEM; -		goto err; -	} - -	/* now get the full information */ -	ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, -			       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, -			       0x0100, chip->clock_id << 8, data, data_size, 1000); - -	if (ret < 0) { -		snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); -		ret = -EINVAL; -		goto err_free; -	} - -	fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); -	if (!fp->rate_table) { -		ret = -ENOMEM; -		goto err_free; -	} - -	fp->nr_rates = 0; -	fp->rate_min = fp->rate_max = 0; - -	for (i = 0; i < nr_rates; i++) { -		int rate = combine_quad(&data[2 + 12 * i]); - -		fp->rate_table[fp->nr_rates] = rate; -		if (!fp->rate_min || rate < fp->rate_min) -			fp->rate_min = rate; -		if (!fp->rate_max || rate > fp->rate_max) -			fp->rate_max = rate; -		fp->rates |= snd_pcm_rate_to_rate_bit(rate); -		fp->nr_rates++; -	} - -err_free: -	kfree(data); -err: -	return ret; -} - -/* - * parse the format type I and III descriptors - */ -static int parse_audio_format_i(struct snd_usb_audio *chip, -				struct audioformat *fp, -				int format, void *_fmt, -				struct usb_host_interface *iface) -{ -	struct usb_interface_descriptor *altsd = get_iface_desc(iface); -	struct uac_format_type_i_discrete_descriptor *fmt = _fmt; -	int protocol = altsd->bInterfaceProtocol; -	int pcm_format, ret; - -	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { -		/* FIXME: the format type is really IECxxx -		 *        but we give normal PCM format to get the existing -		 *        apps working... -		 */ -		switch (chip->usb_id) { - -		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ -			if (device_setup[chip->index] == 0x00 &&  -			    fp->altsetting == 6) -				pcm_format = SNDRV_PCM_FORMAT_S16_BE; -			else -				pcm_format = SNDRV_PCM_FORMAT_S16_LE; -			break; -		default: -			pcm_format = SNDRV_PCM_FORMAT_S16_LE; -		} -	} else { -		pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol); -		if (pcm_format < 0) -			return -1; -	} - -	fp->format = pcm_format; - -	/* gather possible sample rates */ -	/* audio class v1 reports possible sample rates as part of the -	 * proprietary class specific descriptor. -	 * audio class v2 uses class specific EP0 range requests for that. -	 */ -	switch (protocol) { -	case UAC_VERSION_1: -		fp->channels = fmt->bNrChannels; -		ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7); -		break; -	case UAC_VERSION_2: -		/* fp->channels is already set in this case */ -		ret = parse_audio_format_rates_v2(chip, fp, iface); -		break; -	} - -	if (fp->channels < 1) { -		snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); -		return -1; -	} - -	return ret; -} - -/* - * parse the format type II descriptor - */ -static int parse_audio_format_ii(struct snd_usb_audio *chip, -				 struct audioformat *fp, -				 int format, void *_fmt, -				 struct usb_host_interface *iface) -{ -	int brate, framesize, ret; -	struct usb_interface_descriptor *altsd = get_iface_desc(iface); -	int protocol = altsd->bInterfaceProtocol; - -	switch (format) { -	case UAC_FORMAT_TYPE_II_AC3: -		/* FIXME: there is no AC3 format defined yet */ -		// fp->format = SNDRV_PCM_FORMAT_AC3; -		fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ -		break; -	case UAC_FORMAT_TYPE_II_MPEG: -		fp->format = SNDRV_PCM_FORMAT_MPEG; -		break; -	default: -		snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, format); -		fp->format = SNDRV_PCM_FORMAT_MPEG; -		break; -	} - -	fp->channels = 1; - -	switch (protocol) { -	case UAC_VERSION_1: { -		struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; -		brate = le16_to_cpu(fmt->wMaxBitRate); -		framesize = le16_to_cpu(fmt->wSamplesPerFrame); -		snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); -		fp->frame_size = framesize; -		ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */ -		break; -	} -	case UAC_VERSION_2: { -		struct uac_format_type_ii_ext_descriptor *fmt = _fmt; -		brate = le16_to_cpu(fmt->wMaxBitRate); -		framesize = le16_to_cpu(fmt->wSamplesPerFrame); -		snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); -		fp->frame_size = framesize; -		ret = parse_audio_format_rates_v2(chip, fp, iface); -		break; -	} -	} - -	return ret; -} - -static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, -			      int format, unsigned char *fmt, int stream, -			      struct usb_host_interface *iface) -{ -	int err; - -	switch (fmt[3]) { -	case UAC_FORMAT_TYPE_I: -	case UAC_FORMAT_TYPE_III: -		err = parse_audio_format_i(chip, fp, format, fmt, iface); -		break; -	case UAC_FORMAT_TYPE_II: -		err = parse_audio_format_ii(chip, fp, format, fmt, iface); -		break; -	default: -		snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); -		return -1; -	} -	fp->fmt_type = fmt[3]; -	if (err < 0) -		return err; -#if 1 -	/* FIXME: temporary hack for extigy/audigy 2 nx/zs */ -	/* extigy apparently supports sample rates other than 48k -	 * but not in ordinary way.  so we enable only 48k atm. -	 */ -	if (chip->usb_id == USB_ID(0x041e, 0x3000) || -	    chip->usb_id == USB_ID(0x041e, 0x3020) || -	    chip->usb_id == USB_ID(0x041e, 0x3061)) { -		if (fmt[3] == UAC_FORMAT_TYPE_I && -		    fp->rates != SNDRV_PCM_RATE_48000 && -		    fp->rates != SNDRV_PCM_RATE_96000) -			return -1; -	} -#endif -	return 0; -} - -static unsigned char parse_datainterval(struct snd_usb_audio *chip, -					struct usb_host_interface *alts) -{ -	if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && -	    get_endpoint(alts, 0)->bInterval >= 1 && -	    get_endpoint(alts, 0)->bInterval <= 4) -		return get_endpoint(alts, 0)->bInterval - 1; -	else -		return 0; -} - -static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, -					 int iface, int altno); -static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) -{ -	struct usb_device *dev; -	struct usb_interface *iface; -	struct usb_host_interface *alts; -	struct usb_interface_descriptor *altsd; -	int i, altno, err, stream; -	int format = 0, num_channels = 0; -	struct audioformat *fp = NULL; -	unsigned char *fmt, *csep; -	int num, protocol; - -	dev = chip->dev; - -	/* parse the interface's altsettings */ -	iface = usb_ifnum_to_if(dev, iface_no); - -	num = iface->num_altsetting; - -	/* -	 * Dallas DS4201 workaround: It presents 5 altsettings, but the last -	 * one misses syncpipe, and does not produce any sound. -	 */ -	if (chip->usb_id == USB_ID(0x04fa, 0x4201)) -		num = 4; - -	for (i = 0; i < num; i++) { -		alts = &iface->altsetting[i]; -		altsd = get_iface_desc(alts); -		protocol = altsd->bInterfaceProtocol; -		/* skip invalid one */ -		if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && -		     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || -		    (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && -		     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || -		    altsd->bNumEndpoints < 1 || -		    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) -			continue; -		/* must be isochronous */ -		if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != -		    USB_ENDPOINT_XFER_ISOC) -			continue; -		/* check direction */ -		stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? -			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; -		altno = altsd->bAlternateSetting; -	 -		/* audiophile usb: skip altsets incompatible with device_setup -		 */ -		if (chip->usb_id == USB_ID(0x0763, 0x2003) &&  -		    audiophile_skip_setting_quirk(chip, iface_no, altno)) -			continue; - -		/* get audio formats */ -		switch (protocol) { -		case UAC_VERSION_1: { -			struct uac_as_header_descriptor_v1 *as = -				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - -			if (!as) { -				snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", -					   dev->devnum, iface_no, altno); -				continue; -			} - -			if (as->bLength < sizeof(*as)) { -				snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", -					   dev->devnum, iface_no, altno); -				continue; -			} - -			format = le16_to_cpu(as->wFormatTag); /* remember the format value */ -			break; -		} - -		case UAC_VERSION_2: { -			struct uac_as_header_descriptor_v2 *as = -				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - -			if (!as) { -				snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", -					   dev->devnum, iface_no, altno); -				continue; -			} - -			if (as->bLength < sizeof(*as)) { -				snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", -					   dev->devnum, iface_no, altno); -				continue; -			} - -			num_channels = as->bNrChannels; -			format = le32_to_cpu(as->bmFormats); - -			break; -		} - -		default: -			snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", -				   dev->devnum, iface_no, altno, protocol); -			continue; -		} - -		/* get format type */ -		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); -		if (!fmt) { -			snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", -				   dev->devnum, iface_no, altno); -			continue; -		} -		if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) || -		    ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) { -			snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", -				   dev->devnum, iface_no, altno); -			continue; -		} - -		/* -		 * Blue Microphones workaround: The last altsetting is identical -		 * with the previous one, except for a larger packet size, but -		 * is actually a mislabeled two-channel setting; ignore it. -		 */ -		if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && -		    fp && fp->altsetting == 1 && fp->channels == 1 && -		    fp->format == SNDRV_PCM_FORMAT_S16_LE && -		    protocol == UAC_VERSION_1 && -		    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == -							fp->maxpacksize * 2) -			continue; - -		csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); -		/* Creamware Noah has this descriptor after the 2nd endpoint */ -		if (!csep && altsd->bNumEndpoints >= 2) -			csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); -		if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) { -			snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" -				   " class specific endpoint descriptor\n", -				   dev->devnum, iface_no, altno); -			csep = NULL; -		} - -		fp = kzalloc(sizeof(*fp), GFP_KERNEL); -		if (! fp) { -			snd_printk(KERN_ERR "cannot malloc\n"); -			return -ENOMEM; -		} - -		fp->iface = iface_no; -		fp->altsetting = altno; -		fp->altset_idx = i; -		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; -		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; -		fp->datainterval = parse_datainterval(chip, alts); -		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); -		/* num_channels is only set for v2 interfaces */ -		fp->channels = num_channels; -		if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) -			fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) -					* (fp->maxpacksize & 0x7ff); -		fp->attributes = csep ? csep[3] : 0; - -		/* some quirks for attributes here */ - -		switch (chip->usb_id) { -		case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ -			/* Optoplay sets the sample rate attribute although -			 * it seems not supporting it in fact. -			 */ -			fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; -			break; -		case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ -		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ -			/* doesn't set the sample rate attribute, but supports it */ -			fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; -			break; -		case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ -		case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is -						an older model 77d:223) */ -		/* -		 * plantronics headset and Griffin iMic have set adaptive-in -		 * although it's really not... -		 */ -			fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; -			if (stream == SNDRV_PCM_STREAM_PLAYBACK) -				fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; -			else -				fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; -			break; -		} - -		/* ok, let's parse further... */ -		if (parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { -			kfree(fp->rate_table); -			kfree(fp); -			continue; -		} - -		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); -		err = add_audio_endpoint(chip, stream, fp); -		if (err < 0) { -			kfree(fp->rate_table); -			kfree(fp); -			return err; -		} -		/* try to set the interface... */ -		usb_set_interface(chip->dev, iface_no, altno); -		init_usb_pitch(chip->dev, iface_no, alts, fp); -		init_usb_sample_rate(chip->dev, iface_no, alts, fp, fp->rate_max); -	} -	return 0; -} - - -/* - * disconnect streams - * called from snd_usb_audio_disconnect() - */ -static void snd_usb_stream_disconnect(struct list_head *head) -{ -	int idx; -	struct snd_usb_stream *as; -	struct snd_usb_substream *subs; - -	as = list_entry(head, struct snd_usb_stream, list); -	for (idx = 0; idx < 2; idx++) { -		subs = &as->substream[idx]; -		if (!subs->num_formats) -			return; -		release_substream_urbs(subs, 1); -		subs->interface = -1; -	} -} - -static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface) -{ -	struct usb_device *dev = chip->dev; -	struct usb_host_interface *alts; -	struct usb_interface_descriptor *altsd; -	struct usb_interface *iface = usb_ifnum_to_if(dev, interface); - -	if (!iface) { -		snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", -			   dev->devnum, ctrlif, interface); -		return -EINVAL; -	} - -	if (usb_interface_claimed(iface)) { -		snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", -						dev->devnum, ctrlif, interface); -		return -EINVAL; -	} - -	alts = &iface->altsetting[0]; -	altsd = get_iface_desc(alts); -	if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || -	     altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && -	    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { -		int err = snd_usbmidi_create(chip->card, iface, -					     &chip->midi_list, NULL); -		if (err < 0) { -			snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", -						dev->devnum, ctrlif, interface); -			return -EINVAL; -		} -		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); - -		return 0; -	} - -	if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && -	     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || -	    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) { -		snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", -					dev->devnum, ctrlif, interface, altsd->bInterfaceClass); -		/* skip non-supported classes */ -		return -EINVAL; -	} - -	if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { -		snd_printk(KERN_ERR "low speed audio streaming not supported\n"); -		return -EINVAL; -	} - -	if (! parse_audio_endpoints(chip, interface)) { -		usb_set_interface(dev, interface, 0); /* reset the current interface */ -		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); -		return -EINVAL; -	} - -	return 0; -} - -/* - * parse audio control descriptor and create pcm/midi streams - */ -static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) -{ -	struct usb_device *dev = chip->dev; -	struct usb_host_interface *host_iface; -	struct usb_interface_descriptor *altsd; -	void *control_header; -	int i, protocol; - -	/* find audiocontrol interface */ -	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; -	control_header = snd_usb_find_csint_desc(host_iface->extra, -						 host_iface->extralen, -						 NULL, UAC_HEADER); -	altsd = get_iface_desc(host_iface); -	protocol = altsd->bInterfaceProtocol; - -	if (!control_header) { -		snd_printk(KERN_ERR "cannot find UAC_HEADER\n"); -		return -EINVAL; -	} - -	switch (protocol) { -	case UAC_VERSION_1: { -		struct uac_ac_header_descriptor_v1 *h1 = control_header; - -		if (!h1->bInCollection) { -			snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); -			return -EINVAL; -		} - -		if (h1->bLength < sizeof(*h1) + h1->bInCollection) { -			snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n"); -			return -EINVAL; -		} - -		for (i = 0; i < h1->bInCollection; i++) -			snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]); - -		break; -	} - -	case UAC_VERSION_2: { -		struct uac_clock_source_descriptor *cs; -		struct usb_interface_assoc_descriptor *assoc = -			usb_ifnum_to_if(dev, ctrlif)->intf_assoc; - -		if (!assoc) { -			snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); -			return -EINVAL; -		} - -		/* FIXME: for now, we expect there is at least one clock source -		 * descriptor and we always take the first one. -		 * We should properly support devices with multiple clock sources, -		 * clock selectors and sample rate conversion units. */ - -		cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, -						NULL, UAC_CLOCK_SOURCE); - -		if (!cs) { -			snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); -			return -EINVAL; -		} - -		chip->clock_id = cs->bClockID; - -		for (i = 0; i < assoc->bInterfaceCount; i++) { -			int intf = assoc->bFirstInterface + i; - -			if (intf != ctrlif) -				snd_usb_create_stream(chip, ctrlif, intf); -		} - -		break; -	} - -	default: -		snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); -		return -EINVAL; -	} - -	return 0; -} - -/* - * create a stream for an endpoint/altsetting without proper descriptors - */ -static int create_fixed_stream_quirk(struct snd_usb_audio *chip, -				     struct usb_interface *iface, -				     const struct snd_usb_audio_quirk *quirk) -{ -	struct audioformat *fp; -	struct usb_host_interface *alts; -	int stream, err; -	unsigned *rate_table = NULL; - -	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); -	if (! fp) { -		snd_printk(KERN_ERR "cannot memdup\n"); -		return -ENOMEM; -	} -	if (fp->nr_rates > 0) { -		rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); -		if (!rate_table) { -			kfree(fp); -			return -ENOMEM; -		} -		memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates); -		fp->rate_table = rate_table; -	} - -	stream = (fp->endpoint & USB_DIR_IN) -		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; -	err = add_audio_endpoint(chip, stream, fp); -	if (err < 0) { -		kfree(fp); -		kfree(rate_table); -		return err; -	} -	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber || -	    fp->altset_idx >= iface->num_altsetting) { -		kfree(fp); -		kfree(rate_table); -		return -EINVAL; -	} -	alts = &iface->altsetting[fp->altset_idx]; -	fp->datainterval = parse_datainterval(chip, alts); -	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); -	usb_set_interface(chip->dev, fp->iface, 0); -	init_usb_pitch(chip->dev, fp->iface, alts, fp); -	init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max); -	return 0; -} - -/* - * create a stream for an interface with proper descriptors - */ -static int create_standard_audio_quirk(struct snd_usb_audio *chip, -				       struct usb_interface *iface, -				       const struct snd_usb_audio_quirk *quirk) -{ -	struct usb_host_interface *alts; -	struct usb_interface_descriptor *altsd; -	int err; - -	alts = &iface->altsetting[0]; -	altsd = get_iface_desc(alts); -	err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); -	if (err < 0) { -		snd_printk(KERN_ERR "cannot setup if %d: error %d\n", -			   altsd->bInterfaceNumber, err); -		return err; -	} -	/* reset the current interface */ -	usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); -	return 0; -} - -/* - * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.   - * The only way to detect the sample rate is by looking at wMaxPacketSize. - */ -static int create_uaxx_quirk(struct snd_usb_audio *chip, -			      struct usb_interface *iface, -			      const struct snd_usb_audio_quirk *quirk) -{ -	static const struct audioformat ua_format = { -		.format = SNDRV_PCM_FORMAT_S24_3LE, -		.channels = 2, -		.fmt_type = UAC_FORMAT_TYPE_I, -		.altsetting = 1, -		.altset_idx = 1, -		.rates = SNDRV_PCM_RATE_CONTINUOUS, -	}; -	struct usb_host_interface *alts; -	struct usb_interface_descriptor *altsd; -	struct audioformat *fp; -	int stream, err; - -	/* both PCM and MIDI interfaces have 2 or more altsettings */ -	if (iface->num_altsetting < 2) -		return -ENXIO; -	alts = &iface->altsetting[1]; -	altsd = get_iface_desc(alts); - -	if (altsd->bNumEndpoints == 2) { -		static const struct snd_usb_midi_endpoint_info ua700_ep = { -			.out_cables = 0x0003, -			.in_cables  = 0x0003 -		}; -		static const struct snd_usb_audio_quirk ua700_quirk = { -			.type = QUIRK_MIDI_FIXED_ENDPOINT, -			.data = &ua700_ep -		}; -		static const struct snd_usb_midi_endpoint_info uaxx_ep = { -			.out_cables = 0x0001, -			.in_cables  = 0x0001 -		}; -		static const struct snd_usb_audio_quirk uaxx_quirk = { -			.type = QUIRK_MIDI_FIXED_ENDPOINT, -			.data = &uaxx_ep -		}; -		const struct snd_usb_audio_quirk *quirk = -			chip->usb_id == USB_ID(0x0582, 0x002b) -			? &ua700_quirk : &uaxx_quirk; -		return snd_usbmidi_create(chip->card, iface, -					  &chip->midi_list, quirk); -	} - -	if (altsd->bNumEndpoints != 1) -		return -ENXIO; - -	fp = kmalloc(sizeof(*fp), GFP_KERNEL); -	if (!fp) -		return -ENOMEM; -	memcpy(fp, &ua_format, sizeof(*fp)); - -	fp->iface = altsd->bInterfaceNumber; -	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; -	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; -	fp->datainterval = 0; -	fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - -	switch (fp->maxpacksize) { -	case 0x120: -		fp->rate_max = fp->rate_min = 44100; -		break; -	case 0x138: -	case 0x140: -		fp->rate_max = fp->rate_min = 48000; -		break; -	case 0x258: -	case 0x260: -		fp->rate_max = fp->rate_min = 96000; -		break; -	default: -		snd_printk(KERN_ERR "unknown sample rate\n"); -		kfree(fp); -		return -ENXIO; -	} - -	stream = (fp->endpoint & USB_DIR_IN) -		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; -	err = add_audio_endpoint(chip, stream, fp); -	if (err < 0) { -		kfree(fp); -		return err; -	} -	usb_set_interface(chip->dev, fp->iface, 0); -	return 0; -} - -static int snd_usb_create_quirk(struct snd_usb_audio *chip, -				struct usb_interface *iface, -				const struct snd_usb_audio_quirk *quirk); - -/* - * handle the quirks for the contained interfaces - */ -static int create_composite_quirk(struct snd_usb_audio *chip, -				  struct usb_interface *iface, -				  const struct snd_usb_audio_quirk *quirk) -{ -	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber; -	int err; - -	for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { -		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum); -		if (!iface) -			continue; -		if (quirk->ifnum != probed_ifnum && -		    usb_interface_claimed(iface)) -			continue; -		err = snd_usb_create_quirk(chip, iface, quirk); -		if (err < 0) -			return err; -		if (quirk->ifnum != probed_ifnum) -			usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); -	} -	return 0; -} - -static int ignore_interface_quirk(struct snd_usb_audio *chip, -				  struct usb_interface *iface, -				  const struct snd_usb_audio_quirk *quirk) -{ -	return 0; -} - -/* - * Allow alignment on audio sub-slot (channel samples) rather than - * on audio slots (audio frames) - */ -static int create_align_transfer_quirk(struct snd_usb_audio *chip, -				  struct usb_interface *iface, -				  const struct snd_usb_audio_quirk *quirk) -{ -	chip->txfr_quirk = 1; -	return 1;	/* Continue with creating streams and mixer */ -} - - -/* - * boot quirks - */ - -#define EXTIGY_FIRMWARE_SIZE_OLD 794 -#define EXTIGY_FIRMWARE_SIZE_NEW 483 - -static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf) -{ -	struct usb_host_config *config = dev->actconfig; -	int err; - -	if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD || -	    le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) { -		snd_printdd("sending Extigy boot sequence...\n"); -		/* Send message to force it to reconnect with full interface. */ -		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0), -				      0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000); -		if (err < 0) snd_printdd("error sending boot message: %d\n", err); -		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, -				&dev->descriptor, sizeof(dev->descriptor)); -		config = dev->actconfig; -		if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err); -		err = usb_reset_configuration(dev); -		if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err); -		snd_printdd("extigy_boot: new boot length = %d\n", -			    le16_to_cpu(get_cfg_desc(config)->wTotalLength)); -		return -ENODEV; /* quit this anyway */ -	} -	return 0; -} - -static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) -{ -	u8 buf = 1; - -	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, -			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, -			0, 0, &buf, 1, 1000); -	if (buf == 0) { -		snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, -				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, -				1, 2000, NULL, 0, 1000); -		return -ENODEV; -	} -	return 0; -} - -/* - * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely - * documented in the device's data sheet. - */ -static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value) -{ -	u8 buf[4]; -	buf[0] = 0x20; -	buf[1] = value & 0xff; -	buf[2] = (value >> 8) & 0xff; -	buf[3] = reg; -	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, -			       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, -			       0, 0, &buf, 4, 1000); -} - -static int snd_usb_cm106_boot_quirk(struct usb_device *dev) -{ -	/* -	 * Enable line-out driver mode, set headphone source to front -	 * channels, enable stereo mic. -	 */ -	return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); -} - -/* - * C-Media CM6206 is based on CM106 with two additional - * registers that are not documented in the data sheet. - * Values here are chosen based on sniffing USB traffic - * under Windows. - */ -static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) -{ -	int err, reg; -	int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; - -	for (reg = 0; reg < ARRAY_SIZE(val); reg++) { -		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); -		if (err < 0) -			return err; -	} - -	return err; -} - -/* - * This call will put the synth in "USB send" mode, i.e it will send MIDI - * messages through USB (this is disabled at startup). The synth will - * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB - * sign on its LCD. Values here are chosen based on sniffing USB traffic - * under Windows. - */ -static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) -{ -	int err, actual_length; - -	/* "midi send" enable */ -	static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; - -	void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); -	if (!buf) -		return -ENOMEM; -	err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf, -			ARRAY_SIZE(seq), &actual_length, 1000); -	kfree(buf); -	if (err < 0) -		return err; - -	return 0; -} - -/* - * Setup quirks - */ -#define AUDIOPHILE_SET			0x01 /* if set, parse device_setup */ -#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */ -#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */ -#define AUDIOPHILE_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */ -#define AUDIOPHILE_SET_DI		0x10 /* if set, enable Digital Input */ -#define AUDIOPHILE_SET_MASK		0x1F /* bit mask for setup value */ -#define AUDIOPHILE_SET_24B_48K_DI	0x19 /* value for 24bits+48KHz+Digital Input */ -#define AUDIOPHILE_SET_24B_48K_NOTDI	0x09 /* value for 24bits+48KHz+No Digital Input */ -#define AUDIOPHILE_SET_16B_48K_DI	0x11 /* value for 16bits+48KHz+Digital Input */ -#define AUDIOPHILE_SET_16B_48K_NOTDI	0x01 /* value for 16bits+48KHz+No Digital Input */ - -static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, -					 int iface, int altno) -{ -	/* Reset ALL ifaces to 0 altsetting. -	 * Call it for every possible altsetting of every interface. -	 */ -	usb_set_interface(chip->dev, iface, 0); - -	if (device_setup[chip->index] & AUDIOPHILE_SET) { -		if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS) -		    && altno != 6) -			return 1; /* skip this altsetting */ -		if ((device_setup[chip->index] & AUDIOPHILE_SET_96K) -		    && altno != 1) -			return 1; /* skip this altsetting */ -		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_24B_48K_DI && altno != 2) -			return 1; /* skip this altsetting */ -		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3) -			return 1; /* skip this altsetting */ -		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_16B_48K_DI && altno != 4) -			return 1; /* skip this altsetting */ -		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5) -			return 1; /* skip this altsetting */ -	}	 -	return 0; /* keep this altsetting */ -} - -static int create_any_midi_quirk(struct snd_usb_audio *chip, -				 struct usb_interface *intf, -				 const struct snd_usb_audio_quirk *quirk) -{ -	return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); -} - -/* - * audio-interface quirks - * - * returns zero if no standard audio/MIDI parsing is needed. - * returns a postive value if standard audio/midi interfaces are parsed - * after this. - * returns a negative value at error. - */ -static int snd_usb_create_quirk(struct snd_usb_audio *chip, -				struct usb_interface *iface, -				const struct snd_usb_audio_quirk *quirk) -{ -	typedef int (*quirk_func_t)(struct snd_usb_audio *, struct usb_interface *, -				    const struct snd_usb_audio_quirk *); -	static const quirk_func_t quirk_funcs[] = { -		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, -		[QUIRK_COMPOSITE] = create_composite_quirk, -		[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, -		[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, -		[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, -		[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, -		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk, -		[QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, -		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, -		[QUIRK_MIDI_CME] = create_any_midi_quirk, -		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, -		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, -		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, -		[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk -	}; - -	if (quirk->type < QUIRK_TYPE_COUNT) { -		return quirk_funcs[quirk->type](chip, iface, quirk); -	} else { -		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); -		return -ENXIO; -	} -} - - -/* - * common proc files to show the usb device info - */ -static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -{ -	struct snd_usb_audio *chip = entry->private_data; -	if (!chip->shutdown) -		snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); -} - -static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -{ -	struct snd_usb_audio *chip = entry->private_data; -	if (!chip->shutdown) -		snd_iprintf(buffer, "%04x:%04x\n",  -			    USB_ID_VENDOR(chip->usb_id), -			    USB_ID_PRODUCT(chip->usb_id)); -} - -static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) -{ -	struct snd_info_entry *entry; -	if (!snd_card_proc_new(chip->card, "usbbus", &entry)) -		snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); -	if (!snd_card_proc_new(chip->card, "usbid", &entry)) -		snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); -} - -/* - * free the chip instance - * - * here we have to do not much, since pcm and controls are already freed - * - */ - -static int snd_usb_audio_free(struct snd_usb_audio *chip) -{ -	kfree(chip); -	return 0; -} - -static int snd_usb_audio_dev_free(struct snd_device *device) -{ -	struct snd_usb_audio *chip = device->device_data; -	return snd_usb_audio_free(chip); -} - - -/* - * create a chip instance and set its names. - */ -static int snd_usb_audio_create(struct usb_device *dev, int idx, -				const struct snd_usb_audio_quirk *quirk, -				struct snd_usb_audio **rchip) -{ -	struct snd_card *card; -	struct snd_usb_audio *chip; -	int err, len; -	char component[14]; -	static struct snd_device_ops ops = { -		.dev_free =	snd_usb_audio_dev_free, -	}; - -	*rchip = NULL; - -	if (snd_usb_get_speed(dev) != USB_SPEED_LOW && -	    snd_usb_get_speed(dev) != USB_SPEED_FULL && -	    snd_usb_get_speed(dev) != USB_SPEED_HIGH) { -		snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); -		return -ENXIO; -	} - -	err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card); -	if (err < 0) { -		snd_printk(KERN_ERR "cannot create card instance %d\n", idx); -		return err; -	} - -	chip = kzalloc(sizeof(*chip), GFP_KERNEL); -	if (! chip) { -		snd_card_free(card); -		return -ENOMEM; -	} - -	chip->index = idx; -	chip->dev = dev; -	chip->card = card; -	chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), -			      le16_to_cpu(dev->descriptor.idProduct)); -	INIT_LIST_HEAD(&chip->pcm_list); -	INIT_LIST_HEAD(&chip->midi_list); -	INIT_LIST_HEAD(&chip->mixer_list); - -	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { -		snd_usb_audio_free(chip); -		snd_card_free(card); -		return err; -	} - -	strcpy(card->driver, "USB-Audio"); -	sprintf(component, "USB%04x:%04x", -		USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); -	snd_component_add(card, component); - -	/* retrieve the device string as shortname */ - 	if (quirk && quirk->product_name) { -		strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); -	} else { -		if (!dev->descriptor.iProduct || -		    usb_string(dev, dev->descriptor.iProduct, -      			       card->shortname, sizeof(card->shortname)) <= 0) { -			/* no name available from anywhere, so use ID */ -			sprintf(card->shortname, "USB Device %#04x:%#04x", -				USB_ID_VENDOR(chip->usb_id), -				USB_ID_PRODUCT(chip->usb_id)); -		} -	} - -	/* retrieve the vendor and device strings as longname */ -	if (quirk && quirk->vendor_name) { -		len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); -	} else { -		if (dev->descriptor.iManufacturer) -			len = usb_string(dev, dev->descriptor.iManufacturer, -					 card->longname, sizeof(card->longname)); -		else -			len = 0; -		/* we don't really care if there isn't any vendor string */ -	} -	if (len > 0) -		strlcat(card->longname, " ", sizeof(card->longname)); - -	strlcat(card->longname, card->shortname, sizeof(card->longname)); - -	len = strlcat(card->longname, " at ", sizeof(card->longname)); - -	if (len < sizeof(card->longname)) -		usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); - -	strlcat(card->longname, -		snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : -		snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : -		", high speed", -		sizeof(card->longname)); - -	snd_usb_audio_create_proc(chip); - -	*rchip = chip; -	return 0; -} - - -/* - * probe the active usb device - * - * note that this can be called multiple times per a device, when it - * includes multiple audio control interfaces. - * - * thus we check the usb device pointer and creates the card instance - * only at the first time.  the successive calls of this function will - * append the pcm interface to the corresponding card. - */ -static void *snd_usb_audio_probe(struct usb_device *dev, -				 struct usb_interface *intf, -				 const struct usb_device_id *usb_id) -{ -	const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info; -	int i, err; -	struct snd_usb_audio *chip; -	struct usb_host_interface *alts; -	int ifnum; -	u32 id; - -	alts = &intf->altsetting[0]; -	ifnum = get_iface_desc(alts)->bInterfaceNumber; -	id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), -		    le16_to_cpu(dev->descriptor.idProduct)); -	if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) -		goto __err_val; - -	/* SB Extigy needs special boot-up sequence */ -	/* if more models come, this will go to the quirk list. */ -	if (id == USB_ID(0x041e, 0x3000)) { -		if (snd_usb_extigy_boot_quirk(dev, intf) < 0) -			goto __err_val; -	} -	/* SB Audigy 2 NX needs its own boot-up magic, too */ -	if (id == USB_ID(0x041e, 0x3020)) { -		if (snd_usb_audigy2nx_boot_quirk(dev) < 0) -			goto __err_val; -	} - -	/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */ -	if (id == USB_ID(0x10f5, 0x0200)) { -		if (snd_usb_cm106_boot_quirk(dev) < 0) -			goto __err_val; -	} - -	/* C-Media CM6206 / CM106-Like Sound Device */ -	if (id == USB_ID(0x0d8c, 0x0102)) { -		if (snd_usb_cm6206_boot_quirk(dev) < 0) -			goto __err_val; -	} - -	/* Access Music VirusTI Desktop */ -	if (id == USB_ID(0x133e, 0x0815)) { -		if (snd_usb_accessmusic_boot_quirk(dev) < 0) -			goto __err_val; -	} - -	/* -	 * found a config.  now register to ALSA -	 */ - -	/* check whether it's already registered */ -	chip = NULL; -	mutex_lock(®ister_mutex); -	for (i = 0; i < SNDRV_CARDS; i++) { -		if (usb_chip[i] && usb_chip[i]->dev == dev) { -			if (usb_chip[i]->shutdown) { -				snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n"); -				goto __error; -			} -			chip = usb_chip[i]; -			break; -		} -	} -	if (! chip) { -		/* it's a fresh one. -		 * now look for an empty slot and create a new card instance -		 */ -		for (i = 0; i < SNDRV_CARDS; i++) -			if (enable[i] && ! usb_chip[i] && -			    (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && -			    (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { -				if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { -					goto __error; -				} -				snd_card_set_dev(chip->card, &intf->dev); -				break; -			} -		if (!chip) { -			printk(KERN_ERR "no available usb audio device\n"); -			goto __error; -		} -	} - -	chip->txfr_quirk = 0; -	err = 1; /* continue */ -	if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { -		/* need some special handlings */ -		if ((err = snd_usb_create_quirk(chip, intf, quirk)) < 0) -			goto __error; -	} - -	if (err > 0) { -		/* create normal USB audio interfaces */ -		if (snd_usb_create_streams(chip, ifnum) < 0 || -		    snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) { -			goto __error; -		} -	} - -	/* we are allowed to call snd_card_register() many times */ -	if (snd_card_register(chip->card) < 0) { -		goto __error; -	} - -	usb_chip[chip->index] = chip; -	chip->num_interfaces++; -	mutex_unlock(®ister_mutex); -	return chip; - - __error: -	if (chip && !chip->num_interfaces) -		snd_card_free(chip->card); -	mutex_unlock(®ister_mutex); - __err_val: -	return NULL; -} - -/* - * we need to take care of counter, since disconnection can be called also - * many times as well as usb_audio_probe(). - */ -static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) -{ -	struct snd_usb_audio *chip; -	struct snd_card *card; -	struct list_head *p; - -	if (ptr == (void *)-1L) -		return; - -	chip = ptr; -	card = chip->card; -	mutex_lock(®ister_mutex); -	chip->shutdown = 1; -	chip->num_interfaces--; -	if (chip->num_interfaces <= 0) { -		snd_card_disconnect(card); -		/* release the pcm resources */ -		list_for_each(p, &chip->pcm_list) { -			snd_usb_stream_disconnect(p); -		} -		/* release the midi resources */ -		list_for_each(p, &chip->midi_list) { -			snd_usbmidi_disconnect(p); -		} -		/* release mixer resources */ -		list_for_each(p, &chip->mixer_list) { -			snd_usb_mixer_disconnect(p); -		} -		usb_chip[chip->index] = NULL; -		mutex_unlock(®ister_mutex); -		snd_card_free_when_closed(card); -	} else { -		mutex_unlock(®ister_mutex); -	} -} - -/* - * new 2.5 USB kernel API - */ -static int usb_audio_probe(struct usb_interface *intf, -			   const struct usb_device_id *id) -{ -	void *chip; -	chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id); -	if (chip) { -		usb_set_intfdata(intf, chip); -		return 0; -	} else -		return -EIO; -} - -static void usb_audio_disconnect(struct usb_interface *intf) -{ -	snd_usb_audio_disconnect(interface_to_usbdev(intf), -				 usb_get_intfdata(intf)); -} - -#ifdef CONFIG_PM -static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) -{ -	struct snd_usb_audio *chip = usb_get_intfdata(intf); -	struct list_head *p; -	struct snd_usb_stream *as; - -	if (chip == (void *)-1L) -		return 0; - -	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); -	if (!chip->num_suspended_intf++) { -		list_for_each(p, &chip->pcm_list) { -			as = list_entry(p, struct snd_usb_stream, list); -			snd_pcm_suspend_all(as->pcm); -		} -	} - -	return 0; -} - -static int usb_audio_resume(struct usb_interface *intf) -{ -	struct snd_usb_audio *chip = usb_get_intfdata(intf); - -	if (chip == (void *)-1L) -		return 0; -	if (--chip->num_suspended_intf) -		return 0; -	/* -	 * ALSA leaves material resumption to user space -	 * we just notify -	 */ - -	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); - -	return 0; -} -#endif		/* CONFIG_PM */ - -static int __init snd_usb_audio_init(void) -{ -	if (nrpacks < 1 || nrpacks > MAX_PACKS) { -		printk(KERN_WARNING "invalid nrpacks value.\n"); -		return -EINVAL; -	} -	return usb_register(&usb_audio_driver); -} - - -static void __exit snd_usb_audio_cleanup(void) -{ -	usb_deregister(&usb_audio_driver); -} - -module_init(snd_usb_audio_init); -module_exit(snd_usb_audio_cleanup); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 42c299cbf63..d679e72a3e5 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -21,15 +21,13 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   */ -/* maximum number of endpoints per interface */ -#define MIDI_MAX_ENDPOINTS 2 -  /* handling of USB vendor/product ID pairs as 32-bit numbers */  #define USB_ID(vendor, product) (((vendor) << 16) | (product))  #define USB_ID_VENDOR(id) ((id) >> 16)  #define USB_ID_PRODUCT(id) ((u16)(id))  /* + *   */  struct snd_usb_audio { @@ -51,6 +49,10 @@ struct snd_usb_audio {  	struct list_head midi_list;	/* list of midi interfaces */  	struct list_head mixer_list;	/* list of mixer interfaces */ + +	int setup;			/* from the 'device_setup' module param */ +	int nrpacks;			/* from the 'nrpacks' module param */ +	int async_unlink;		/* from the 'async_unlink' module param */  };  /* @@ -89,93 +91,8 @@ struct snd_usb_audio_quirk {  	const void *data;  }; -/* data for QUIRK_MIDI_FIXED_ENDPOINT */ -struct snd_usb_midi_endpoint_info { -	int8_t   out_ep;	/* ep number, 0 autodetect */ -	uint8_t  out_interval;	/* interval for interrupt endpoints */ -	int8_t   in_ep;	 -	uint8_t  in_interval; -	uint16_t out_cables;	/* bitmask */ -	uint16_t in_cables;	/* bitmask */ -}; - -/* for QUIRK_MIDI_YAMAHA, data is NULL */ - -/* for QUIRK_MIDI_MIDIMAN, data points to a snd_usb_midi_endpoint_info - * structure (out_cables and in_cables only) */ - -/* for QUIRK_COMPOSITE, data points to an array of snd_usb_audio_quirk - * structures, terminated with .ifnum = -1 */ - -/* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */ - -/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */ - -/* for QUIRK_AUDIO_EDIROL_UAXX, data is NULL */ - -/* for QUIRK_IGNORE_INTERFACE, data is NULL */ - -/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */ - -/* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info - * structure (out_cables and in_cables only) */ - -/* for QUIRK_MIDI_CME, data is NULL */ - -/* - */ - -/*E-mu USB samplerate control quirk*/ -enum { -	EMU_QUIRK_SR_44100HZ = 0, -	EMU_QUIRK_SR_48000HZ, -	EMU_QUIRK_SR_88200HZ, -	EMU_QUIRK_SR_96000HZ, -	EMU_QUIRK_SR_176400HZ, -	EMU_QUIRK_SR_192000HZ -}; -  #define combine_word(s)    ((*(s)) | ((unsigned int)(s)[1] << 8))  #define combine_triple(s)  (combine_word(s) | ((unsigned int)(s)[2] << 16))  #define combine_quad(s)    (combine_triple(s) | ((unsigned int)(s)[3] << 24)) -unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size); - -void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype); -void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype); - -int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, -		    __u8 request, __u8 requesttype, __u16 value, __u16 index, -		    void *data, __u16 size, int timeout); - -int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, -			 int ignore_error); -void snd_usb_mixer_disconnect(struct list_head *p); - -int snd_usbmidi_create(struct snd_card *card, -		       struct usb_interface *iface, -		       struct list_head *midi_list, -		       const struct snd_usb_audio_quirk *quirk); -void snd_usbmidi_input_stop(struct list_head* p); -void snd_usbmidi_input_start(struct list_head* p); -void snd_usbmidi_disconnect(struct list_head *p); - -void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, -			unsigned char samplerate_id); - -/* - * retrieve usb_interface descriptor from the host interface - * (conditional for compatibility with the older API) - */ -#ifndef get_iface_desc -#define get_iface_desc(iface)	(&(iface)->desc) -#define get_endpoint(alt,ep)	(&(alt)->endpoint[ep].desc) -#define get_ep_desc(ep)		(&(ep)->desc) -#define get_cfg_desc(cfg)	(&(cfg)->desc) -#endif - -#ifndef snd_usb_get_speed -#define snd_usb_get_speed(dev) ((dev)->speed) -#endif -  #endif /* __USBAUDIO_H */ diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 44deb21b177..6ef68e42138 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -16,6 +16,7 @@   * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */ +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/audio.h>  #include <sound/core.h> @@ -25,6 +26,7 @@  #define MODNAME "US122L"  #include "usb_stream.c"  #include "../usbaudio.h" +#include "../midi.h"  #include "us122l.h"  MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>"); diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 1879b72c40f..04aafb43a13 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -21,6 +21,7 @@   */  #include <linux/interrupt.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <sound/core.h>  #include <sound/memalloc.h> diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 12ae0340adc..c400ade3ff0 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -17,6 +17,7 @@   */  #include <linux/usb.h> +#include <linux/gfp.h>  #include "usb_stream.h" diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index c42350eed2e..cbd37f2c76d 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -133,6 +133,7 @@  #include <linux/init.h>  #include <linux/module.h>  #include <linux/moduleparam.h> +#include <linux/slab.h>  #include <linux/interrupt.h>  #include <linux/usb.h>  #include <sound/core.h> diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 1d174cea352..e43c0a86441 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -1,6 +1,7 @@  #ifndef USBUSX2Y_H  #define USBUSX2Y_H  #include "../usbaudio.h" +#include "../midi.h"  #include "usbus428ctldefs.h"   #define NRURBS	        2	 diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 74a67a85aa8..5d37d1ccf81 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -32,6 +32,7 @@  #include <linux/interrupt.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <sound/core.h>  #include <sound/info.h> diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 9ed6c3956ca..2a528e56afd 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -51,6 +51,7 @@  */  #include <linux/delay.h> +#include <linux/gfp.h>  #include "usbusx2yaudio.c"  #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)  |