diff options
Diffstat (limited to 'sound/usb')
69 files changed, 12528 insertions, 3246 deletions
diff --git a/sound/usb/6fire/Makefile b/sound/usb/6fire/Makefile new file mode 100644 index 00000000000..dfce6ec5351 --- /dev/null +++ b/sound/usb/6fire/Makefile @@ -0,0 +1,3 @@ +snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o +obj-$(CONFIG_SND_USB_6FIRE) += snd-usb-6fire.o + diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c new file mode 100644 index 00000000000..dcddfc354ba --- /dev/null +++ b/sound/usb/6fire/chip.c @@ -0,0 +1,219 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Main routines and module definitions. + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#include "chip.h" +#include "firmware.h" +#include "pcm.h" +#include "control.h" +#include "comm.h" +#include "midi.h" + +#include <linux/moduleparam.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/gfp.h> +#include <sound/initval.h> + +MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>"); +MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */ +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */ +static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for the 6fire sound device"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for the 6fire sound device."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable the 6fire sound device."); + +static DEFINE_MUTEX(register_mutex); + +static void usb6fire_chip_abort(struct sfire_chip *chip) +{ +	if (chip) { +		if (chip->pcm) +			usb6fire_pcm_abort(chip); +		if (chip->midi) +			usb6fire_midi_abort(chip); +		if (chip->comm) +			usb6fire_comm_abort(chip); +		if (chip->control) +			usb6fire_control_abort(chip); +		if (chip->card) { +			snd_card_disconnect(chip->card); +			snd_card_free_when_closed(chip->card); +			chip->card = NULL; +		} +	} +} + +static void usb6fire_chip_destroy(struct sfire_chip *chip) +{ +	if (chip) { +		if (chip->pcm) +			usb6fire_pcm_destroy(chip); +		if (chip->midi) +			usb6fire_midi_destroy(chip); +		if (chip->comm) +			usb6fire_comm_destroy(chip); +		if (chip->control) +			usb6fire_control_destroy(chip); +		if (chip->card) +			snd_card_free(chip->card); +	} +} + +static int usb6fire_chip_probe(struct usb_interface *intf, +			       const struct usb_device_id *usb_id) +{ +	int ret; +	int i; +	struct sfire_chip *chip = NULL; +	struct usb_device *device = interface_to_usbdev(intf); +	int regidx = -1; /* index in module parameter array */ +	struct snd_card *card = NULL; + +	/* look if we already serve this card and return if so */ +	mutex_lock(®ister_mutex); +	for (i = 0; i < SNDRV_CARDS; i++) { +		if (devices[i] == device) { +			if (chips[i]) +				chips[i]->intf_count++; +			usb_set_intfdata(intf, chips[i]); +			mutex_unlock(®ister_mutex); +			return 0; +		} else if (!devices[i] && regidx < 0) +			regidx = i; +	} +	if (regidx < 0) { +		mutex_unlock(®ister_mutex); +		dev_err(&intf->dev, "too many cards registered.\n"); +		return -ENODEV; +	} +	devices[regidx] = device; +	mutex_unlock(®ister_mutex); + +	/* check, if firmware is present on device, upload it if not */ +	ret = usb6fire_fw_init(intf); +	if (ret < 0) +		return ret; +	else if (ret == FW_NOT_READY) /* firmware update performed */ +		return 0; + +	/* if we are here, card can be registered in alsa. */ +	if (usb_set_interface(device, 0, 0) != 0) { +		dev_err(&intf->dev, "can't set first interface.\n"); +		return -EIO; +	} +	ret = snd_card_new(&intf->dev, index[regidx], id[regidx], +			   THIS_MODULE, sizeof(struct sfire_chip), &card); +	if (ret < 0) { +		dev_err(&intf->dev, "cannot create alsa card.\n"); +		return ret; +	} +	strcpy(card->driver, "6FireUSB"); +	strcpy(card->shortname, "TerraTec DMX6FireUSB"); +	sprintf(card->longname, "%s at %d:%d", card->shortname, +			device->bus->busnum, device->devnum); + +	chip = card->private_data; +	chips[regidx] = chip; +	chip->dev = device; +	chip->regidx = regidx; +	chip->intf_count = 1; +	chip->card = card; + +	ret = usb6fire_comm_init(chip); +	if (ret < 0) { +		usb6fire_chip_destroy(chip); +		return ret; +	} + +	ret = usb6fire_midi_init(chip); +	if (ret < 0) { +		usb6fire_chip_destroy(chip); +		return ret; +	} + +	ret = usb6fire_pcm_init(chip); +	if (ret < 0) { +		usb6fire_chip_destroy(chip); +		return ret; +	} + +	ret = usb6fire_control_init(chip); +	if (ret < 0) { +		usb6fire_chip_destroy(chip); +		return ret; +	} + +	ret = snd_card_register(card); +	if (ret < 0) { +		dev_err(&intf->dev, "cannot register card."); +		usb6fire_chip_destroy(chip); +		return ret; +	} +	usb_set_intfdata(intf, chip); +	return 0; +} + +static void usb6fire_chip_disconnect(struct usb_interface *intf) +{ +	struct sfire_chip *chip; +	struct snd_card *card; + +	chip = usb_get_intfdata(intf); +	if (chip) { /* if !chip, fw upload has been performed */ +		card = chip->card; +		chip->intf_count--; +		if (!chip->intf_count) { +			mutex_lock(®ister_mutex); +			devices[chip->regidx] = NULL; +			chips[chip->regidx] = NULL; +			mutex_unlock(®ister_mutex); + +			chip->shutdown = true; +			usb6fire_chip_abort(chip); +			usb6fire_chip_destroy(chip); +		} +	} +} + +static struct usb_device_id device_table[] = { +	{ +		.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +		.idVendor = 0x0ccd, +		.idProduct = 0x0080 +	}, +	{} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +static struct usb_driver usb_driver = { +	.name = "snd-usb-6fire", +	.probe = usb6fire_chip_probe, +	.disconnect = usb6fire_chip_disconnect, +	.id_table = device_table, +}; + +module_usb_driver(usb_driver); diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h new file mode 100644 index 00000000000..bde02d105a5 --- /dev/null +++ b/sound/usb/6fire/chip.h @@ -0,0 +1,31 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ +#ifndef USB6FIRE_CHIP_H +#define USB6FIRE_CHIP_H + +#include "common.h" + +struct sfire_chip { +	struct usb_device *dev; +	struct snd_card *card; +	int intf_count; /* number of registered interfaces */ +	int regidx; /* index in module parameter arrays */ +	bool shutdown; + +	struct midi_runtime *midi; +	struct pcm_runtime *pcm; +	struct control_runtime *control; +	struct comm_runtime *comm; +}; +#endif /* USB6FIRE_CHIP_H */ + diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c new file mode 100644 index 00000000000..161215d78d9 --- /dev/null +++ b/sound/usb/6fire/comm.c @@ -0,0 +1,204 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Device communications + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#include "comm.h" +#include "chip.h" +#include "midi.h" + +enum { +	COMM_EP = 1, +	COMM_FPGA_EP = 2 +}; + +static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb, +		u8 *buffer, void *context, void(*handler)(struct urb *urb)) +{ +	usb_init_urb(urb); +	urb->transfer_buffer = buffer; +	urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP); +	urb->complete = handler; +	urb->context = context; +	urb->interval = 1; +	urb->dev = rt->chip->dev; +} + +static void usb6fire_comm_receiver_handler(struct urb *urb) +{ +	struct comm_runtime *rt = urb->context; +	struct midi_runtime *midi_rt = rt->chip->midi; + +	if (!urb->status) { +		if (rt->receiver_buffer[0] == 0x10) /* midi in event */ +			if (midi_rt) +				midi_rt->in_received(midi_rt, +						rt->receiver_buffer + 2, +						rt->receiver_buffer[1]); +	} + +	if (!rt->chip->shutdown) { +		urb->status = 0; +		urb->actual_length = 0; +		if (usb_submit_urb(urb, GFP_ATOMIC) < 0) +			dev_warn(&urb->dev->dev, +					"comm data receiver aborted.\n"); +	} +} + +static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request, +		u8 reg, u8 vl, u8 vh) +{ +	buffer[0] = 0x01; +	buffer[2] = request; +	buffer[3] = id; +	switch (request) { +	case 0x02: +		buffer[1] = 0x05; /* length (starting at buffer[2]) */ +		buffer[4] = reg; +		buffer[5] = vl; +		buffer[6] = vh; +		break; + +	case 0x12: +		buffer[1] = 0x0b; /* length (starting at buffer[2]) */ +		buffer[4] = 0x00; +		buffer[5] = 0x18; +		buffer[6] = 0x05; +		buffer[7] = 0x00; +		buffer[8] = 0x01; +		buffer[9] = 0x00; +		buffer[10] = 0x9e; +		buffer[11] = reg; +		buffer[12] = vl; +		break; + +	case 0x20: +	case 0x21: +	case 0x22: +		buffer[1] = 0x04; +		buffer[4] = reg; +		buffer[5] = vl; +		break; +	} +} + +static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev) +{ +	int ret; +	int actual_len; + +	ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP), +			buffer, buffer[1] + 2, &actual_len, HZ); +	if (ret < 0) +		return ret; +	else if (actual_len != buffer[1] + 2) +		return -EIO; +	return 0; +} + +static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request, +		u8 reg, u8 value) +{ +	u8 *buffer; +	int ret; + +	/* 13: maximum length of message */ +	buffer = kmalloc(13, GFP_KERNEL); +	if (!buffer) +		return -ENOMEM; + +	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00); +	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); + +	kfree(buffer); +	return ret; +} + +static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, +		u8 reg, u8 vl, u8 vh) +{ +	u8 *buffer; +	int ret; + +	/* 13: maximum length of message */ +	buffer = kmalloc(13, GFP_KERNEL); +	if (!buffer) +		return -ENOMEM; + +	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh); +	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev); + +	kfree(buffer); +	return ret; +} + +int usb6fire_comm_init(struct sfire_chip *chip) +{ +	struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), +			GFP_KERNEL); +	struct urb *urb; +	int ret; + +	if (!rt) +		return -ENOMEM; + +	rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); +	if (!rt->receiver_buffer) { +		kfree(rt); +		return -ENOMEM; +	} + +	urb = &rt->receiver; +	rt->serial = 1; +	rt->chip = chip; +	usb_init_urb(urb); +	rt->init_urb = usb6fire_comm_init_urb; +	rt->write8 = usb6fire_comm_write8; +	rt->write16 = usb6fire_comm_write16; + +	/* submit an urb that receives communication data from device */ +	urb->transfer_buffer = rt->receiver_buffer; +	urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE; +	urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP); +	urb->dev = chip->dev; +	urb->complete = usb6fire_comm_receiver_handler; +	urb->context = rt; +	urb->interval = 1; +	ret = usb_submit_urb(urb, GFP_KERNEL); +	if (ret < 0) { +		kfree(rt->receiver_buffer); +		kfree(rt); +		dev_err(&chip->dev->dev, "cannot create comm data receiver."); +		return ret; +	} +	chip->comm = rt; +	return 0; +} + +void usb6fire_comm_abort(struct sfire_chip *chip) +{ +	struct comm_runtime *rt = chip->comm; + +	if (rt) +		usb_poison_urb(&rt->receiver); +} + +void usb6fire_comm_destroy(struct sfire_chip *chip) +{ +	struct comm_runtime *rt = chip->comm; + +	kfree(rt->receiver_buffer); +	kfree(rt); +	chip->comm = NULL; +} diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h new file mode 100644 index 00000000000..780d5ed8e5d --- /dev/null +++ b/sound/usb/6fire/comm.h @@ -0,0 +1,43 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ +#ifndef USB6FIRE_COMM_H +#define USB6FIRE_COMM_H + +#include "common.h" + +enum /* settings for comm */ +{ +	COMM_RECEIVER_BUFSIZE = 64, +}; + +struct comm_runtime { +	struct sfire_chip *chip; + +	struct urb receiver; +	u8 *receiver_buffer; + +	u8 serial; /* urb serial */ + +	void (*init_urb)(struct comm_runtime *rt, struct urb *urb, u8 *buffer, +			void *context, void(*handler)(struct urb *urb)); +	/* writes control data to the device */ +	int (*write8)(struct comm_runtime *rt, u8 request, u8 reg, u8 value); +	int (*write16)(struct comm_runtime *rt, u8 request, u8 reg, +			u8 vh, u8 vl); +}; + +int usb6fire_comm_init(struct sfire_chip *chip); +void usb6fire_comm_abort(struct sfire_chip *chip); +void usb6fire_comm_destroy(struct sfire_chip *chip); +#endif /* USB6FIRE_COMM_H */ + diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h new file mode 100644 index 00000000000..b6eb03ed1c2 --- /dev/null +++ b/sound/usb/6fire/common.h @@ -0,0 +1,29 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#ifndef USB6FIRE_COMMON_H +#define USB6FIRE_COMMON_H + +#include <linux/slab.h> +#include <linux/usb.h> +#include <sound/core.h> + +#define PREFIX "6fire: " + +struct sfire_chip; +struct midi_runtime; +struct pcm_runtime; +struct control_runtime; +struct comm_runtime; +#endif /* USB6FIRE_COMMON_H */ + diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c new file mode 100644 index 00000000000..184e3987ac2 --- /dev/null +++ b/sound/usb/6fire/control.c @@ -0,0 +1,635 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Mixer control + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * Thanks to: + * - Holger Ruckdeschel: he found out how to control individual channel + *   volumes and introduced mute switch + * + * 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. + */ + +#include <linux/interrupt.h> +#include <sound/control.h> +#include <sound/tlv.h> + +#include "control.h" +#include "comm.h" +#include "chip.h" + +static char *opt_coax_texts[2] = { "Optical", "Coax" }; +static char *line_phono_texts[2] = { "Line", "Phono" }; + +/* + * data that needs to be sent to device. sets up card internal stuff. + * values dumped from windows driver and filtered by trial'n'error. + */ +static const struct { +	u8 type; +	u8 reg; +	u8 value; +} +init_data[] = { +	{ 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 }, +	{ 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 }, +	{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, +	{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, +	{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, +	{ 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, +	{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, +	{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, +	{ 0 } /* TERMINATING ENTRY */ +}; + +static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; +/* values to write to soundcard register for all samplerates */ +static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; +static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; + +static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); +static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500); + +enum { +	DIGITAL_THRU_ONLY_SAMPLERATE = 3 +}; + +static void usb6fire_control_output_vol_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; +	int i; + +	if (comm_rt) +		for (i = 0; i < 6; i++) +			if (!(rt->ovol_updated & (1 << i))) { +				comm_rt->write8(comm_rt, 0x12, 0x0f + i, +					180 - rt->output_vol[i]); +				rt->ovol_updated |= 1 << i; +			} +} + +static void usb6fire_control_output_mute_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; + +	if (comm_rt) +		comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); +} + +static void usb6fire_control_input_vol_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; +	int i; + +	if (comm_rt) +		for (i = 0; i < 2; i++) +			if (!(rt->ivol_updated & (1 << i))) { +				comm_rt->write8(comm_rt, 0x12, 0x1c + i, +					rt->input_vol[i] & 0x3f); +				rt->ivol_updated |= 1 << i; +			} +} + +static void usb6fire_control_line_phono_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; +	if (comm_rt) { +		comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch); +		comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch); +	} +} + +static void usb6fire_control_opt_coax_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; +	if (comm_rt) { +		comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch); +		comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch); +	} +} + +static int usb6fire_control_set_rate(struct control_runtime *rt, int rate) +{ +	int ret; +	struct usb_device *device = rt->chip->dev; +	struct comm_runtime *comm_rt = rt->chip->comm; + +	if (rate < 0 || rate >= CONTROL_N_RATES) +		return -EINVAL; + +	ret = usb_set_interface(device, 1, rates_altsetting[rate]); +	if (ret < 0) +		return ret; + +	/* set soundcard clock */ +	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate], +			rates_6fire_vh[rate]); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int usb6fire_control_set_channels( +	struct control_runtime *rt, int n_analog_out, +	int n_analog_in, bool spdif_out, bool spdif_in) +{ +	int ret; +	struct comm_runtime *comm_rt = rt->chip->comm; + +	/* enable analog inputs and outputs +	 * (one bit per stereo-channel) */ +	ret = comm_rt->write16(comm_rt, 0x02, 0x02, +			(1 << (n_analog_out / 2)) - 1, +			(1 << (n_analog_in / 2)) - 1); +	if (ret < 0) +		return ret; + +	/* disable digital inputs and outputs */ +	/* TODO: use spdif_x to enable/disable digital channels */ +	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int usb6fire_control_streaming_update(struct control_runtime *rt) +{ +	struct comm_runtime *comm_rt = rt->chip->comm; + +	if (comm_rt) { +		if (!rt->usb_streaming && rt->digital_thru_switch) +			usb6fire_control_set_rate(rt, +				DIGITAL_THRU_ONLY_SAMPLERATE); +		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, +			(rt->usb_streaming ? 0x01 : 0x00) | +			(rt->digital_thru_switch ? 0x08 : 0x00)); +	} +	return -EINVAL; +} + +static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_info *uinfo) +{ +	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +	uinfo->count = 2; +	uinfo->value.integer.min = 0; +	uinfo->value.integer.max = 180; +	return 0; +} + +static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	unsigned int ch = kcontrol->private_value; +	int changed = 0; + +	if (ch > 4) { +		dev_err(&rt->chip->dev->dev, +			"Invalid channel in volume control."); +		return -EINVAL; +	} + +	if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { +		rt->output_vol[ch] = ucontrol->value.integer.value[0]; +		rt->ovol_updated &= ~(1 << ch); +		changed = 1; +	} +	if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { +		rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; +		rt->ovol_updated &= ~(2 << ch); +		changed = 1; +	} + +	if (changed) +		usb6fire_control_output_vol_update(rt); + +	return changed; +} + +static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	unsigned int ch = kcontrol->private_value; + +	if (ch > 4) { +		dev_err(&rt->chip->dev->dev, +			"Invalid channel in volume control."); +		return -EINVAL; +	} + +	ucontrol->value.integer.value[0] = rt->output_vol[ch]; +	ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; +	return 0; +} + +static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	unsigned int ch = kcontrol->private_value; +	u8 old = rt->output_mute; +	u8 value = 0; + +	if (ch > 4) { +		dev_err(&rt->chip->dev->dev, +			"Invalid channel in volume control."); +		return -EINVAL; +	} + +	rt->output_mute &= ~(3 << ch); +	if (ucontrol->value.integer.value[0]) +		value |= 1; +	if (ucontrol->value.integer.value[1]) +		value |= 2; +	rt->output_mute |= value << ch; + +	if (rt->output_mute != old) +		usb6fire_control_output_mute_update(rt); + +	return rt->output_mute != old; +} + +static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	unsigned int ch = kcontrol->private_value; +	u8 value = rt->output_mute >> ch; + +	if (ch > 4) { +		dev_err(&rt->chip->dev->dev, +			"Invalid channel in volume control."); +		return -EINVAL; +	} + +	ucontrol->value.integer.value[0] = 1 & value; +	value >>= 1; +	ucontrol->value.integer.value[1] = 1 & value; + +	return 0; +} + +static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_info *uinfo) +{ +	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +	uinfo->count = 2; +	uinfo->value.integer.min = 0; +	uinfo->value.integer.max = 30; +	return 0; +} + +static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	int changed = 0; + +	if (rt->input_vol[0] != ucontrol->value.integer.value[0]) { +		rt->input_vol[0] = ucontrol->value.integer.value[0] - 15; +		rt->ivol_updated &= ~(1 << 0); +		changed = 1; +	} +	if (rt->input_vol[1] != ucontrol->value.integer.value[1]) { +		rt->input_vol[1] = ucontrol->value.integer.value[1] - 15; +		rt->ivol_updated &= ~(1 << 1); +		changed = 1; +	} + +	if (changed) +		usb6fire_control_input_vol_update(rt); + +	return changed; +} + +static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + +	ucontrol->value.integer.value[0] = rt->input_vol[0] + 15; +	ucontrol->value.integer.value[1] = rt->input_vol[1] + 15; + +	return 0; +} + +static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_info *uinfo) +{ +	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; +	uinfo->count = 1; +	uinfo->value.enumerated.items = 2; +	if (uinfo->value.enumerated.item > 1) +		uinfo->value.enumerated.item = 1; +	strcpy(uinfo->value.enumerated.name, +			line_phono_texts[uinfo->value.enumerated.item]); +	return 0; +} + +static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	int changed = 0; +	if (rt->line_phono_switch != ucontrol->value.integer.value[0]) { +		rt->line_phono_switch = ucontrol->value.integer.value[0]; +		usb6fire_control_line_phono_update(rt); +		changed = 1; +	} +	return changed; +} + +static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	ucontrol->value.integer.value[0] = rt->line_phono_switch; +	return 0; +} + +static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_info *uinfo) +{ +	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; +	uinfo->count = 1; +	uinfo->value.enumerated.items = 2; +	if (uinfo->value.enumerated.item > 1) +		uinfo->value.enumerated.item = 1; +	strcpy(uinfo->value.enumerated.name, +			opt_coax_texts[uinfo->value.enumerated.item]); +	return 0; +} + +static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	int changed = 0; + +	if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) { +		rt->opt_coax_switch = ucontrol->value.enumerated.item[0]; +		usb6fire_control_opt_coax_update(rt); +		changed = 1; +	} +	return changed; +} + +static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	ucontrol->value.enumerated.item[0] = rt->opt_coax_switch; +	return 0; +} + +static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	int changed = 0; + +	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) { +		rt->digital_thru_switch = ucontrol->value.integer.value[0]; +		usb6fire_control_streaming_update(rt); +		changed = 1; +	} +	return changed; +} + +static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct control_runtime *rt = snd_kcontrol_chip(kcontrol); +	ucontrol->value.integer.value[0] = rt->digital_thru_switch; +	return 0; +} + +static struct snd_kcontrol_new vol_elements[] = { +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Volume", +		.index = 0, +		.private_value = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | +			SNDRV_CTL_ELEM_ACCESS_TLV_READ, +		.info = usb6fire_control_output_vol_info, +		.get = usb6fire_control_output_vol_get, +		.put = usb6fire_control_output_vol_put, +		.tlv = { .p = tlv_output } +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Volume", +		.index = 1, +		.private_value = 2, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | +			SNDRV_CTL_ELEM_ACCESS_TLV_READ, +		.info = usb6fire_control_output_vol_info, +		.get = usb6fire_control_output_vol_get, +		.put = usb6fire_control_output_vol_put, +		.tlv = { .p = tlv_output } +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Volume", +		.index = 2, +		.private_value = 4, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | +			SNDRV_CTL_ELEM_ACCESS_TLV_READ, +		.info = usb6fire_control_output_vol_info, +		.get = usb6fire_control_output_vol_get, +		.put = usb6fire_control_output_vol_put, +		.tlv = { .p = tlv_output } +	}, +	{} +}; + +static struct snd_kcontrol_new mute_elements[] = { +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Switch", +		.index = 0, +		.private_value = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = snd_ctl_boolean_stereo_info, +		.get = usb6fire_control_output_mute_get, +		.put = usb6fire_control_output_mute_put, +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Switch", +		.index = 1, +		.private_value = 2, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = snd_ctl_boolean_stereo_info, +		.get = usb6fire_control_output_mute_get, +		.put = usb6fire_control_output_mute_put, +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Playback Switch", +		.index = 2, +		.private_value = 4, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = snd_ctl_boolean_stereo_info, +		.get = usb6fire_control_output_mute_get, +		.put = usb6fire_control_output_mute_put, +	}, +	{} +}; + +static struct snd_kcontrol_new elements[] = { +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Line/Phono Capture Route", +		.index = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = usb6fire_control_line_phono_info, +		.get = usb6fire_control_line_phono_get, +		.put = usb6fire_control_line_phono_put +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Opt/Coax Capture Route", +		.index = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = usb6fire_control_opt_coax_info, +		.get = usb6fire_control_opt_coax_get, +		.put = usb6fire_control_opt_coax_put +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Digital Thru Playback Route", +		.index = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = snd_ctl_boolean_mono_info, +		.get = usb6fire_control_digital_thru_get, +		.put = usb6fire_control_digital_thru_put +	}, +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Analog Capture Volume", +		.index = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | +			SNDRV_CTL_ELEM_ACCESS_TLV_READ, +		.info = usb6fire_control_input_vol_info, +		.get = usb6fire_control_input_vol_get, +		.put = usb6fire_control_input_vol_put, +		.tlv = { .p = tlv_input } +	}, +	{} +}; + +static int usb6fire_control_add_virtual( +	struct control_runtime *rt, +	struct snd_card *card, +	char *name, +	struct snd_kcontrol_new *elems) +{ +	int ret; +	int i; +	struct snd_kcontrol *vmaster = +		snd_ctl_make_virtual_master(name, tlv_output); +	struct snd_kcontrol *control; + +	if (!vmaster) +		return -ENOMEM; +	ret = snd_ctl_add(card, vmaster); +	if (ret < 0) +		return ret; + +	i = 0; +	while (elems[i].name) { +		control = snd_ctl_new1(&elems[i], rt); +		if (!control) +			return -ENOMEM; +		ret = snd_ctl_add(card, control); +		if (ret < 0) +			return ret; +		ret = snd_ctl_add_slave(vmaster, control); +		if (ret < 0) +			return ret; +		i++; +	} +	return 0; +} + +int usb6fire_control_init(struct sfire_chip *chip) +{ +	int i; +	int ret; +	struct control_runtime *rt = kzalloc(sizeof(struct control_runtime), +			GFP_KERNEL); +	struct comm_runtime *comm_rt = chip->comm; + +	if (!rt) +		return -ENOMEM; + +	rt->chip = chip; +	rt->update_streaming = usb6fire_control_streaming_update; +	rt->set_rate = usb6fire_control_set_rate; +	rt->set_channels = usb6fire_control_set_channels; + +	i = 0; +	while (init_data[i].type) { +		comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg, +				init_data[i].value); +		i++; +	} + +	usb6fire_control_opt_coax_update(rt); +	usb6fire_control_line_phono_update(rt); +	usb6fire_control_output_vol_update(rt); +	usb6fire_control_output_mute_update(rt); +	usb6fire_control_input_vol_update(rt); +	usb6fire_control_streaming_update(rt); + +	ret = usb6fire_control_add_virtual(rt, chip->card, +		"Master Playback Volume", vol_elements); +	if (ret) { +		dev_err(&chip->dev->dev, "cannot add control.\n"); +		kfree(rt); +		return ret; +	} +	ret = usb6fire_control_add_virtual(rt, chip->card, +		"Master Playback Switch", mute_elements); +	if (ret) { +		dev_err(&chip->dev->dev, "cannot add control.\n"); +		kfree(rt); +		return ret; +	} + +	i = 0; +	while (elements[i].name) { +		ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); +		if (ret < 0) { +			kfree(rt); +			dev_err(&chip->dev->dev, "cannot add control.\n"); +			return ret; +		} +		i++; +	} + +	chip->control = rt; +	return 0; +} + +void usb6fire_control_abort(struct sfire_chip *chip) +{} + +void usb6fire_control_destroy(struct sfire_chip *chip) +{ +	kfree(chip->control); +	chip->control = NULL; +} diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h new file mode 100644 index 00000000000..5a40ba14348 --- /dev/null +++ b/sound/usb/6fire/control.h @@ -0,0 +1,57 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#ifndef USB6FIRE_CONTROL_H +#define USB6FIRE_CONTROL_H + +#include "common.h" + +enum { +	CONTROL_MAX_ELEMENTS = 32 +}; + +enum { +	CONTROL_RATE_44KHZ, +	CONTROL_RATE_48KHZ, +	CONTROL_RATE_88KHZ, +	CONTROL_RATE_96KHZ, +	CONTROL_RATE_176KHZ, +	CONTROL_RATE_192KHZ, +	CONTROL_N_RATES +}; + +struct control_runtime { +	int (*update_streaming)(struct control_runtime *rt); +	int (*set_rate)(struct control_runtime *rt, int rate); +	int (*set_channels)(struct control_runtime *rt, int n_analog_out, +		int n_analog_in, bool spdif_out, bool spdif_in); + +	struct sfire_chip *chip; + +	struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; +	bool opt_coax_switch; +	bool line_phono_switch; +	bool digital_thru_switch; +	bool usb_streaming; +	u8 output_vol[6]; +	u8 ovol_updated; +	u8 output_mute; +	s8 input_vol[2]; +	u8 ivol_updated; +}; + +int usb6fire_control_init(struct sfire_chip *chip); +void usb6fire_control_abort(struct sfire_chip *chip); +void usb6fire_control_destroy(struct sfire_chip *chip); +#endif /* USB6FIRE_CONTROL_H */ + diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c new file mode 100644 index 00000000000..3b02e54b8f6 --- /dev/null +++ b/sound/usb/6fire/firmware.c @@ -0,0 +1,421 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Firmware loader + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/bitrev.h> +#include <linux/kernel.h> + +#include "firmware.h" +#include "chip.h" + +MODULE_FIRMWARE("6fire/dmx6firel2.ihx"); +MODULE_FIRMWARE("6fire/dmx6fireap.ihx"); +MODULE_FIRMWARE("6fire/dmx6firecf.bin"); + +enum { +	FPGA_BUFSIZE = 512, FPGA_EP = 2 +}; + +/* + * wMaxPacketSize of pcm endpoints. + * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c + * fpp: frames per isopacket + * + * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init + */ +static const u8 ep_w_max_packet_size[] = { +	0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */ +	0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/ +	0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ +}; + +static const u8 known_fw_versions[][2] = { +	{ 0x03, 0x01 } +}; + +struct ihex_record { +	u16 address; +	u8 len; +	u8 data[256]; +	char error; /* true if an error occurred parsing this record */ + +	u8 max_len; /* maximum record length in whole ihex */ + +	/* private */ +	const char *txt_data; +	unsigned int txt_length; +	unsigned int txt_offset; /* current position in txt_data */ +}; + +static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) +{ +	u8 val = 0; +	int hval; + +	hval = hex_to_bin(data[0]); +	if (hval >= 0) +		val |= (hval << 4); + +	hval = hex_to_bin(data[1]); +	if (hval >= 0) +		val |= hval; + +	*crc += val; +	return val; +} + +/* + * returns true if record is available, false otherwise. + * iff an error occurred, false will be returned and record->error will be true. + */ +static bool usb6fire_fw_ihex_next_record(struct ihex_record *record) +{ +	u8 crc = 0; +	u8 type; +	int i; + +	record->error = false; + +	/* find begin of record (marked by a colon) */ +	while (record->txt_offset < record->txt_length +			&& record->txt_data[record->txt_offset] != ':') +		record->txt_offset++; +	if (record->txt_offset == record->txt_length) +		return false; + +	/* number of characters needed for len, addr and type entries */ +	record->txt_offset++; +	if (record->txt_offset + 8 > record->txt_length) { +		record->error = true; +		return false; +	} + +	record->len = usb6fire_fw_ihex_hex(record->txt_data + +			record->txt_offset, &crc); +	record->txt_offset += 2; +	record->address = usb6fire_fw_ihex_hex(record->txt_data + +			record->txt_offset, &crc) << 8; +	record->txt_offset += 2; +	record->address |= usb6fire_fw_ihex_hex(record->txt_data + +			record->txt_offset, &crc); +	record->txt_offset += 2; +	type = usb6fire_fw_ihex_hex(record->txt_data + +			record->txt_offset, &crc); +	record->txt_offset += 2; + +	/* number of characters needed for data and crc entries */ +	if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) { +		record->error = true; +		return false; +	} +	for (i = 0; i < record->len; i++) { +		record->data[i] = usb6fire_fw_ihex_hex(record->txt_data +				+ record->txt_offset, &crc); +		record->txt_offset += 2; +	} +	usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc); +	if (crc) { +		record->error = true; +		return false; +	} + +	if (type == 1 || !record->len) /* eof */ +		return false; +	else if (type == 0) +		return true; +	else { +		record->error = true; +		return false; +	} +} + +static int usb6fire_fw_ihex_init(const struct firmware *fw, +		struct ihex_record *record) +{ +	record->txt_data = fw->data; +	record->txt_length = fw->size; +	record->txt_offset = 0; +	record->max_len = 0; +	/* read all records, if loop ends, record->error indicates, +	 * whether ihex is valid. */ +	while (usb6fire_fw_ihex_next_record(record)) +		record->max_len = max(record->len, record->max_len); +	if (record->error) +		return -EINVAL; +	record->txt_offset = 0; +	return 0; +} + +static int usb6fire_fw_ezusb_write(struct usb_device *device, +		int type, int value, char *data, int len) +{ +	int ret; + +	ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +			value, 0, data, len, HZ); +	if (ret < 0) +		return ret; +	else if (ret != len) +		return -EIO; +	return 0; +} + +static int usb6fire_fw_ezusb_read(struct usb_device *device, +		int type, int value, char *data, int len) +{ +	int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type, +			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, +			0, data, len, HZ); +	if (ret < 0) +		return ret; +	else if (ret != len) +		return -EIO; +	return 0; +} + +static int usb6fire_fw_fpga_write(struct usb_device *device, +		char *data, int len) +{ +	int actual_len; +	int ret; + +	ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len, +			&actual_len, HZ); +	if (ret < 0) +		return ret; +	else if (actual_len != len) +		return -EIO; +	return 0; +} + +static int usb6fire_fw_ezusb_upload( +		struct usb_interface *intf, const char *fwname, +		unsigned int postaddr, u8 *postdata, unsigned int postlen) +{ +	int ret; +	u8 data; +	struct usb_device *device = interface_to_usbdev(intf); +	const struct firmware *fw = NULL; +	struct ihex_record *rec = kmalloc(sizeof(struct ihex_record), +			GFP_KERNEL); + +	if (!rec) +		return -ENOMEM; + +	ret = request_firmware(&fw, fwname, &device->dev); +	if (ret < 0) { +		kfree(rec); +		dev_err(&intf->dev, +			"error requesting ezusb firmware %s.\n", fwname); +		return ret; +	} +	ret = usb6fire_fw_ihex_init(fw, rec); +	if (ret < 0) { +		kfree(rec); +		release_firmware(fw); +		dev_err(&intf->dev, +			"error validating ezusb firmware %s.\n", fwname); +		return ret; +	} +	/* upload firmware image */ +	data = 0x01; /* stop ezusb cpu */ +	ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); +	if (ret < 0) { +		kfree(rec); +		release_firmware(fw); +		dev_err(&intf->dev, +			"unable to upload ezusb firmware %s: begin message.\n", +			fwname); +		return ret; +	} + +	while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */ +		ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address, +				rec->data, rec->len); +		if (ret < 0) { +			kfree(rec); +			release_firmware(fw); +			dev_err(&intf->dev, +				"unable to upload ezusb firmware %s: data urb.\n", +				fwname); +			return ret; +		} +	} + +	release_firmware(fw); +	kfree(rec); +	if (postdata) { /* write data after firmware has been uploaded */ +		ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr, +				postdata, postlen); +		if (ret < 0) { +			dev_err(&intf->dev, +				"unable to upload ezusb firmware %s: post urb.\n", +				fwname); +			return ret; +		} +	} + +	data = 0x00; /* resume ezusb cpu */ +	ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); +	if (ret < 0) { +		dev_err(&intf->dev, +			"unable to upload ezusb firmware %s: end message.\n", +			fwname); +		return ret; +	} +	return 0; +} + +static int usb6fire_fw_fpga_upload( +		struct usb_interface *intf, const char *fwname) +{ +	int ret; +	int i; +	struct usb_device *device = interface_to_usbdev(intf); +	u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL); +	const char *c; +	const char *end; +	const struct firmware *fw; + +	if (!buffer) +		return -ENOMEM; + +	ret = request_firmware(&fw, fwname, &device->dev); +	if (ret < 0) { +		dev_err(&intf->dev, "unable to get fpga firmware %s.\n", +				fwname); +		kfree(buffer); +		return -EIO; +	} + +	c = fw->data; +	end = fw->data + fw->size; + +	ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0); +	if (ret < 0) { +		kfree(buffer); +		release_firmware(fw); +		dev_err(&intf->dev, +			"unable to upload fpga firmware: begin urb.\n"); +		return ret; +	} + +	while (c != end) { +		for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) +			buffer[i] = byte_rev_table[(u8) *c]; + +		ret = usb6fire_fw_fpga_write(device, buffer, i); +		if (ret < 0) { +			release_firmware(fw); +			kfree(buffer); +			dev_err(&intf->dev, +				"unable to upload fpga firmware: fw urb.\n"); +			return ret; +		} +	} +	release_firmware(fw); +	kfree(buffer); + +	ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0); +	if (ret < 0) { +		dev_err(&intf->dev, +			"unable to upload fpga firmware: end urb.\n"); +		return ret; +	} +	return 0; +} + +/* check, if the firmware version the devices has currently loaded + * is known by this driver. 'version' needs to have 4 bytes version + * info data. */ +static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++) +		if (!memcmp(version, known_fw_versions + i, 2)) +			return 0; + +	dev_err(&intf->dev, "invalid fimware version in device: %4ph. " +			"please reconnect to power. if this failure " +			"still happens, check your firmware installation.", +			version); +	return -EINVAL; +} + +int usb6fire_fw_init(struct usb_interface *intf) +{ +	int i; +	int ret; +	struct usb_device *device = interface_to_usbdev(intf); +	/* buffer: 8 receiving bytes from device and +	 * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */ +	u8 buffer[12]; + +	ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8); +	if (ret < 0) { +		dev_err(&intf->dev, +			"unable to receive device firmware state.\n"); +		return ret; +	} +	if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) { +		dev_err(&intf->dev, +			"unknown device firmware state received from device:"); +		for (i = 0; i < 8; i++) +			printk(KERN_CONT "%02x ", buffer[i]); +		printk(KERN_CONT "\n"); +		return -EIO; +	} +	/* do we need fpga loader ezusb firmware? */ +	if (buffer[3] == 0x01) { +		ret = usb6fire_fw_ezusb_upload(intf, +				"6fire/dmx6firel2.ihx", 0, NULL, 0); +		if (ret < 0) +			return ret; +		return FW_NOT_READY; +	} +	/* do we need fpga firmware and application ezusb firmware? */ +	else if (buffer[3] == 0x02) { +		ret = usb6fire_fw_check(intf, buffer + 4); +		if (ret < 0) +			return ret; +		ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); +		if (ret < 0) +			return ret; +		memcpy(buffer, ep_w_max_packet_size, +				sizeof(ep_w_max_packet_size)); +		ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx", +				0x0003,	buffer, sizeof(ep_w_max_packet_size)); +		if (ret < 0) +			return ret; +		return FW_NOT_READY; +	} +	/* all fw loaded? */ +	else if (buffer[3] == 0x03) +		return usb6fire_fw_check(intf, buffer + 4); +	/* unknown data? */ +	else { +		dev_err(&intf->dev, +			"unknown device firmware state received from device: "); +		for (i = 0; i < 8; i++) +			printk(KERN_CONT "%02x ", buffer[i]); +		printk(KERN_CONT "\n"); +		return -EIO; +	} +	return 0; +} + diff --git a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h new file mode 100644 index 00000000000..c109c4f75ab --- /dev/null +++ b/sound/usb/6fire/firmware.h @@ -0,0 +1,27 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author: Torsten Schenk + * Created: Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#ifndef USB6FIRE_FIRMWARE_H +#define USB6FIRE_FIRMWARE_H + +#include "common.h" + +enum /* firmware state of device */ +{ +	FW_READY = 0, +	FW_NOT_READY = 1 +}; + +int usb6fire_fw_init(struct usb_interface *intf); +#endif /* USB6FIRE_FIRMWARE_H */ + diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c new file mode 100644 index 00000000000..3d410969553 --- /dev/null +++ b/sound/usb/6fire/midi.c @@ -0,0 +1,218 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Rawmidi driver + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#include <sound/rawmidi.h> + +#include "midi.h" +#include "chip.h" +#include "comm.h" + +enum { +	MIDI_BUFSIZE = 64 +}; + +static void usb6fire_midi_out_handler(struct urb *urb) +{ +	struct midi_runtime *rt = urb->context; +	int ret; +	unsigned long flags; + +	spin_lock_irqsave(&rt->out_lock, flags); + +	if (rt->out) { +		ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4, +				MIDI_BUFSIZE - 4); +		if (ret > 0) { /* more data available, send next packet */ +			rt->out_buffer[1] = ret + 2; +			rt->out_buffer[3] = rt->out_serial++; +			urb->transfer_buffer_length = ret + 4; + +			ret = usb_submit_urb(urb, GFP_ATOMIC); +			if (ret < 0) +				dev_err(&urb->dev->dev, +					"midi out urb submit failed: %d\n", +					ret); +		} else /* no more data to transmit */ +			rt->out = NULL; +	} +	spin_unlock_irqrestore(&rt->out_lock, flags); +} + +static void usb6fire_midi_in_received( +		struct midi_runtime *rt, u8 *data, int length) +{ +	unsigned long flags; + +	spin_lock_irqsave(&rt->in_lock, flags); +	if (rt->in) +		snd_rawmidi_receive(rt->in, data, length); +	spin_unlock_irqrestore(&rt->in_lock, flags); +} + +static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub) +{ +	return 0; +} + +static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub) +{ +	return 0; +} + +static void usb6fire_midi_out_trigger( +		struct snd_rawmidi_substream *alsa_sub, int up) +{ +	struct midi_runtime *rt = alsa_sub->rmidi->private_data; +	struct urb *urb = &rt->out_urb; +	__s8 ret; +	unsigned long flags; + +	spin_lock_irqsave(&rt->out_lock, flags); +	if (up) { /* start transfer */ +		if (rt->out) { /* we are already transmitting so just return */ +			spin_unlock_irqrestore(&rt->out_lock, flags); +			return; +		} + +		ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4, +				MIDI_BUFSIZE - 4); +		if (ret > 0) { +			rt->out_buffer[1] = ret + 2; +			rt->out_buffer[3] = rt->out_serial++; +			urb->transfer_buffer_length = ret + 4; + +			ret = usb_submit_urb(urb, GFP_ATOMIC); +			if (ret < 0) +				dev_err(&urb->dev->dev, +					"midi out urb submit failed: %d\n", +					ret); +			else +				rt->out = alsa_sub; +		} +	} else if (rt->out == alsa_sub) +		rt->out = NULL; +	spin_unlock_irqrestore(&rt->out_lock, flags); +} + +static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub) +{ +	struct midi_runtime *rt = alsa_sub->rmidi->private_data; +	int retry = 0; + +	while (rt->out && retry++ < 100) +		msleep(10); +} + +static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub) +{ +	return 0; +} + +static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub) +{ +	return 0; +} + +static void usb6fire_midi_in_trigger( +		struct snd_rawmidi_substream *alsa_sub, int up) +{ +	struct midi_runtime *rt = alsa_sub->rmidi->private_data; +	unsigned long flags; + +	spin_lock_irqsave(&rt->in_lock, flags); +	if (up) +		rt->in = alsa_sub; +	else +		rt->in = NULL; +	spin_unlock_irqrestore(&rt->in_lock, flags); +} + +static struct snd_rawmidi_ops out_ops = { +	.open = usb6fire_midi_out_open, +	.close = usb6fire_midi_out_close, +	.trigger = usb6fire_midi_out_trigger, +	.drain = usb6fire_midi_out_drain +}; + +static struct snd_rawmidi_ops in_ops = { +	.open = usb6fire_midi_in_open, +	.close = usb6fire_midi_in_close, +	.trigger = usb6fire_midi_in_trigger +}; + +int usb6fire_midi_init(struct sfire_chip *chip) +{ +	int ret; +	struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime), +			GFP_KERNEL); +	struct comm_runtime *comm_rt = chip->comm; + +	if (!rt) +		return -ENOMEM; + +	rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL); +	if (!rt->out_buffer) { +		kfree(rt); +		return -ENOMEM; +	} + +	rt->chip = chip; +	rt->in_received = usb6fire_midi_in_received; +	rt->out_buffer[0] = 0x80; /* 'send midi' command */ +	rt->out_buffer[1] = 0x00; /* size of data */ +	rt->out_buffer[2] = 0x00; /* always 0 */ +	spin_lock_init(&rt->in_lock); +	spin_lock_init(&rt->out_lock); + +	comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt, +			usb6fire_midi_out_handler); + +	ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance); +	if (ret < 0) { +		kfree(rt->out_buffer); +		kfree(rt); +		dev_err(&chip->dev->dev, "unable to create midi.\n"); +		return ret; +	} +	rt->instance->private_data = rt; +	strcpy(rt->instance->name, "DMX6FireUSB MIDI"); +	rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | +			SNDRV_RAWMIDI_INFO_INPUT | +			SNDRV_RAWMIDI_INFO_DUPLEX; +	snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT, +			&out_ops); +	snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT, +			&in_ops); + +	chip->midi = rt; +	return 0; +} + +void usb6fire_midi_abort(struct sfire_chip *chip) +{ +	struct midi_runtime *rt = chip->midi; + +	if (rt) +		usb_poison_urb(&rt->out_urb); +} + +void usb6fire_midi_destroy(struct sfire_chip *chip) +{ +	struct midi_runtime *rt = chip->midi; + +	kfree(rt->out_buffer); +	kfree(rt); +	chip->midi = NULL; +} diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h new file mode 100644 index 00000000000..84851b9f555 --- /dev/null +++ b/sound/usb/6fire/midi.h @@ -0,0 +1,41 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#ifndef USB6FIRE_MIDI_H +#define USB6FIRE_MIDI_H + +#include "common.h" + +struct midi_runtime { +	struct sfire_chip *chip; +	struct snd_rawmidi *instance; + +	struct snd_rawmidi_substream *in; +	char in_active; + +	spinlock_t in_lock; +	spinlock_t out_lock; +	struct snd_rawmidi_substream *out; +	struct urb out_urb; +	u8 out_serial; /* serial number of out packet */ +	u8 *out_buffer; +	int buffer_offset; + +	void (*in_received)(struct midi_runtime *rt, u8 *data, int length); +}; + +int usb6fire_midi_init(struct sfire_chip *chip); +void usb6fire_midi_abort(struct sfire_chip *chip); +void usb6fire_midi_destroy(struct sfire_chip *chip); +#endif /* USB6FIRE_MIDI_H */ + diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c new file mode 100644 index 00000000000..ba40489b2de --- /dev/null +++ b/sound/usb/6fire/pcm.c @@ -0,0 +1,717 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * PCM driver + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#include "pcm.h" +#include "chip.h" +#include "comm.h" +#include "control.h" + +enum { +	OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 +}; + +/* keep next two synced with + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE + * and CONTROL_RATE_XXX in control.h */ +static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; +static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; +static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; +static const int rates_alsaid[] = { +	SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, +	SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, +	SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; + +enum { /* settings for pcm */ +	OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 +}; + +enum { /* pcm streaming states */ +	STREAM_DISABLED, /* no pcm streaming */ +	STREAM_STARTING, /* pcm streaming requested, waiting to become ready */ +	STREAM_RUNNING, /* pcm streaming running */ +	STREAM_STOPPING +}; + +static const struct snd_pcm_hardware pcm_hw = { +	.info = SNDRV_PCM_INFO_MMAP | +		SNDRV_PCM_INFO_INTERLEAVED | +		SNDRV_PCM_INFO_BLOCK_TRANSFER | +		SNDRV_PCM_INFO_MMAP_VALID | +		SNDRV_PCM_INFO_BATCH, + +	.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + +	.rates = SNDRV_PCM_RATE_44100 | +		SNDRV_PCM_RATE_48000 | +		SNDRV_PCM_RATE_88200 | +		SNDRV_PCM_RATE_96000 | +		SNDRV_PCM_RATE_176400 | +		SNDRV_PCM_RATE_192000, + +	.rate_min = 44100, +	.rate_max = 192000, +	.channels_min = 1, +	.channels_max = 0, /* set in pcm_open, depending on capture/playback */ +	.buffer_bytes_max = MAX_BUFSIZE, +	.period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4), +	.period_bytes_max = MAX_BUFSIZE, +	.periods_min = 2, +	.periods_max = 1024 +}; + +static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) +{ +	int ret; +	struct control_runtime *ctrl_rt = rt->chip->control; + +	ctrl_rt->usb_streaming = false; +	ret = ctrl_rt->update_streaming(ctrl_rt); +	if (ret < 0) { +		dev_err(&rt->chip->dev->dev, +			"error stopping streaming while setting samplerate %d.\n", +			rates[rt->rate]); +		return ret; +	} + +	ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); +	if (ret < 0) { +		dev_err(&rt->chip->dev->dev, +			"error setting samplerate %d.\n", +			rates[rt->rate]); +		return ret; +	} + +	ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, +			false, false); +	if (ret < 0) { +		dev_err(&rt->chip->dev->dev, +			"error initializing channels while setting samplerate %d.\n", +			rates[rt->rate]); +		return ret; +	} + +	ctrl_rt->usb_streaming = true; +	ret = ctrl_rt->update_streaming(ctrl_rt); +	if (ret < 0) { +		dev_err(&rt->chip->dev->dev, +			"error starting streaming while setting samplerate %d.\n", +			rates[rt->rate]); +		return ret; +	} + +	rt->in_n_analog = IN_N_CHANNELS; +	rt->out_n_analog = OUT_N_CHANNELS; +	rt->in_packet_size = rates_in_packet_size[rt->rate]; +	rt->out_packet_size = rates_out_packet_size[rt->rate]; +	return 0; +} + +static struct pcm_substream *usb6fire_pcm_get_substream( +		struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); + +	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) +		return &rt->playback; +	else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) +		return &rt->capture; +	dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n"); +	return NULL; +} + +/* call with stream_mutex locked */ +static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) +{ +	int i; +	struct control_runtime *ctrl_rt = rt->chip->control; + +	if (rt->stream_state != STREAM_DISABLED) { + +		rt->stream_state = STREAM_STOPPING; + +		for (i = 0; i < PCM_N_URBS; i++) { +			usb_kill_urb(&rt->in_urbs[i].instance); +			usb_kill_urb(&rt->out_urbs[i].instance); +		} +		ctrl_rt->usb_streaming = false; +		ctrl_rt->update_streaming(ctrl_rt); +		rt->stream_state = STREAM_DISABLED; +	} +} + +/* call with stream_mutex locked */ +static int usb6fire_pcm_stream_start(struct pcm_runtime *rt) +{ +	int ret; +	int i; +	int k; +	struct usb_iso_packet_descriptor *packet; + +	if (rt->stream_state == STREAM_DISABLED) { +		/* submit our in urbs */ +		rt->stream_wait_cond = false; +		rt->stream_state = STREAM_STARTING; +		for (i = 0; i < PCM_N_URBS; i++) { +			for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) { +				packet = &rt->in_urbs[i].packets[k]; +				packet->offset = k * rt->in_packet_size; +				packet->length = rt->in_packet_size; +				packet->actual_length = 0; +				packet->status = 0; +			} +			ret = usb_submit_urb(&rt->in_urbs[i].instance, +					GFP_ATOMIC); +			if (ret) { +				usb6fire_pcm_stream_stop(rt); +				return ret; +			} +		} + +		/* wait for first out urb to return (sent in in urb handler) */ +		wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, +				HZ); +		if (rt->stream_wait_cond) +			rt->stream_state = STREAM_RUNNING; +		else { +			usb6fire_pcm_stream_stop(rt); +			return -EIO; +		} +	} +	return 0; +} + +/* call with substream locked */ +static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) +{ +	int i; +	int frame; +	int frame_count; +	unsigned int total_length = 0; +	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); +	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; +	u32 *src = NULL; +	u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off +			* (alsa_rt->frame_bits >> 3)); +	u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size +			* (alsa_rt->frame_bits >> 3)); +	int bytes_per_frame = alsa_rt->channels << 2; + +	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { +		/* at least 4 header bytes for valid packet. +		 * after that: 32 bits per sample for analog channels */ +		if (urb->packets[i].actual_length > 4) +			frame_count = (urb->packets[i].actual_length - 4) +					/ (rt->in_n_analog << 2); +		else +			frame_count = 0; + +		if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) +			src = (u32 *) (urb->buffer + total_length); +		else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) +			src = (u32 *) (urb->buffer - 1 + total_length); +		else +			return; +		src++; /* skip leading 4 bytes of every packet */ +		total_length += urb->packets[i].length; +		for (frame = 0; frame < frame_count; frame++) { +			memcpy(dest, src, bytes_per_frame); +			dest += alsa_rt->channels; +			src += rt->in_n_analog; +			sub->dma_off++; +			sub->period_off++; +			if (dest == dest_end) { +				sub->dma_off = 0; +				dest = (u32 *) alsa_rt->dma_area; +			} +		} +	} +} + +/* call with substream locked */ +static void usb6fire_pcm_playback(struct pcm_substream *sub, +		struct pcm_urb *urb) +{ +	int i; +	int frame; +	int frame_count; +	struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); +	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; +	u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off +			* (alsa_rt->frame_bits >> 3)); +	u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size +			* (alsa_rt->frame_bits >> 3)); +	u32 *dest; +	int bytes_per_frame = alsa_rt->channels << 2; + +	if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) +		dest = (u32 *) (urb->buffer - 1); +	else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) +		dest = (u32 *) (urb->buffer); +	else { +		dev_err(&rt->chip->dev->dev, "Unknown sample format."); +		return; +	} + +	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { +		/* at least 4 header bytes for valid packet. +		 * after that: 32 bits per sample for analog channels */ +		if (urb->packets[i].length > 4) +			frame_count = (urb->packets[i].length - 4) +					/ (rt->out_n_analog << 2); +		else +			frame_count = 0; +		dest++; /* skip leading 4 bytes of every frame */ +		for (frame = 0; frame < frame_count; frame++) { +			memcpy(dest, src, bytes_per_frame); +			src += alsa_rt->channels; +			dest += rt->out_n_analog; +			sub->dma_off++; +			sub->period_off++; +			if (src == src_end) { +				src = (u32 *) alsa_rt->dma_area; +				sub->dma_off = 0; +			} +		} +	} +} + +static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) +{ +	struct pcm_urb *in_urb = usb_urb->context; +	struct pcm_urb *out_urb = in_urb->peer; +	struct pcm_runtime *rt = in_urb->chip->pcm; +	struct pcm_substream *sub; +	unsigned long flags; +	int total_length = 0; +	int frame_count; +	int frame; +	int channel; +	int i; +	u8 *dest; + +	if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING) +		return; +	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) +		if (in_urb->packets[i].status) { +			rt->panic = true; +			return; +		} + +	if (rt->stream_state == STREAM_DISABLED) { +		dev_err(&rt->chip->dev->dev, +			"internal error: stream disabled in in-urb handler.\n"); +		return; +	} + +	/* receive our capture data */ +	sub = &rt->capture; +	spin_lock_irqsave(&sub->lock, flags); +	if (sub->active) { +		usb6fire_pcm_capture(sub, in_urb); +		if (sub->period_off >= sub->instance->runtime->period_size) { +			sub->period_off %= sub->instance->runtime->period_size; +			spin_unlock_irqrestore(&sub->lock, flags); +			snd_pcm_period_elapsed(sub->instance); +		} else +			spin_unlock_irqrestore(&sub->lock, flags); +	} else +		spin_unlock_irqrestore(&sub->lock, flags); + +	/* setup out urb structure */ +	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { +		out_urb->packets[i].offset = total_length; +		out_urb->packets[i].length = (in_urb->packets[i].actual_length +				- 4) / (rt->in_n_analog << 2) +				* (rt->out_n_analog << 2) + 4; +		out_urb->packets[i].status = 0; +		total_length += out_urb->packets[i].length; +	} +	memset(out_urb->buffer, 0, total_length); + +	/* now send our playback data (if a free out urb was found) */ +	sub = &rt->playback; +	spin_lock_irqsave(&sub->lock, flags); +	if (sub->active) { +		usb6fire_pcm_playback(sub, out_urb); +		if (sub->period_off >= sub->instance->runtime->period_size) { +			sub->period_off %= sub->instance->runtime->period_size; +			spin_unlock_irqrestore(&sub->lock, flags); +			snd_pcm_period_elapsed(sub->instance); +		} else +			spin_unlock_irqrestore(&sub->lock, flags); +	} else +		spin_unlock_irqrestore(&sub->lock, flags); + +	/* setup the 4th byte of each sample (0x40 for analog channels) */ +	dest = out_urb->buffer; +	for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) +		if (out_urb->packets[i].length >= 4) { +			frame_count = (out_urb->packets[i].length - 4) +					/ (rt->out_n_analog << 2); +			*(dest++) = 0xaa; +			*(dest++) = 0xaa; +			*(dest++) = frame_count; +			*(dest++) = 0x00; +			for (frame = 0; frame < frame_count; frame++) +				for (channel = 0; +						channel < rt->out_n_analog; +						channel++) { +					dest += 3; /* skip sample data */ +					*(dest++) = 0x40; +				} +		} +	usb_submit_urb(&out_urb->instance, GFP_ATOMIC); +	usb_submit_urb(&in_urb->instance, GFP_ATOMIC); +} + +static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb) +{ +	struct pcm_urb *urb = usb_urb->context; +	struct pcm_runtime *rt = urb->chip->pcm; + +	if (rt->stream_state == STREAM_STARTING) { +		rt->stream_wait_cond = true; +		wake_up(&rt->stream_wait_queue); +	} +} + +static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = NULL; +	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; + +	if (rt->panic) +		return -EPIPE; + +	mutex_lock(&rt->stream_mutex); +	alsa_rt->hw = pcm_hw; + +	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) { +		if (rt->rate < ARRAY_SIZE(rates)) +			alsa_rt->hw.rates = rates_alsaid[rt->rate]; +		alsa_rt->hw.channels_max = OUT_N_CHANNELS; +		sub = &rt->playback; +	} else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) { +		if (rt->rate < ARRAY_SIZE(rates)) +			alsa_rt->hw.rates = rates_alsaid[rt->rate]; +		alsa_rt->hw.channels_max = IN_N_CHANNELS; +		sub = &rt->capture; +	} + +	if (!sub) { +		mutex_unlock(&rt->stream_mutex); +		dev_err(&rt->chip->dev->dev, "invalid stream type.\n"); +		return -EINVAL; +	} + +	sub->instance = alsa_sub; +	sub->active = false; +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); +	unsigned long flags; + +	if (rt->panic) +		return 0; + +	mutex_lock(&rt->stream_mutex); +	if (sub) { +		/* deactivate substream */ +		spin_lock_irqsave(&sub->lock, flags); +		sub->instance = NULL; +		sub->active = false; +		spin_unlock_irqrestore(&sub->lock, flags); + +		/* all substreams closed? if so, stop streaming */ +		if (!rt->playback.instance && !rt->capture.instance) { +			usb6fire_pcm_stream_stop(rt); +			rt->rate = ARRAY_SIZE(rates); +		} +	} +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub, +		struct snd_pcm_hw_params *hw_params) +{ +	return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub, +						params_buffer_bytes(hw_params)); +} + +static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub) +{ +	return snd_pcm_lib_free_vmalloc_buffer(alsa_sub); +} + +static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); +	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; +	int ret; + +	if (rt->panic) +		return -EPIPE; +	if (!sub) +		return -ENODEV; + +	mutex_lock(&rt->stream_mutex); +	sub->dma_off = 0; +	sub->period_off = 0; + +	if (rt->stream_state == STREAM_DISABLED) { +		for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) +			if (alsa_rt->rate == rates[rt->rate]) +				break; +		if (rt->rate == ARRAY_SIZE(rates)) { +			mutex_unlock(&rt->stream_mutex); +			dev_err(&rt->chip->dev->dev, +				"invalid rate %d in prepare.\n", +				alsa_rt->rate); +			return -EINVAL; +		} + +		ret = usb6fire_pcm_set_rate(rt); +		if (ret) { +			mutex_unlock(&rt->stream_mutex); +			return ret; +		} +		ret = usb6fire_pcm_stream_start(rt); +		if (ret) { +			mutex_unlock(&rt->stream_mutex); +			dev_err(&rt->chip->dev->dev, +				"could not start pcm stream.\n"); +			return ret; +		} +	} +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) +{ +	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	unsigned long flags; + +	if (rt->panic) +		return -EPIPE; +	if (!sub) +		return -ENODEV; + +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_START: +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		spin_lock_irqsave(&sub->lock, flags); +		sub->active = true; +		spin_unlock_irqrestore(&sub->lock, flags); +		return 0; + +	case SNDRV_PCM_TRIGGER_STOP: +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		spin_lock_irqsave(&sub->lock, flags); +		sub->active = false; +		spin_unlock_irqrestore(&sub->lock, flags); +		return 0; + +	default: +		return -EINVAL; +	} +} + +static snd_pcm_uframes_t usb6fire_pcm_pointer( +		struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	unsigned long flags; +	snd_pcm_uframes_t ret; + +	if (rt->panic || !sub) +		return SNDRV_PCM_POS_XRUN; + +	spin_lock_irqsave(&sub->lock, flags); +	ret = sub->dma_off; +	spin_unlock_irqrestore(&sub->lock, flags); +	return ret; +} + +static struct snd_pcm_ops pcm_ops = { +	.open = usb6fire_pcm_open, +	.close = usb6fire_pcm_close, +	.ioctl = snd_pcm_lib_ioctl, +	.hw_params = usb6fire_pcm_hw_params, +	.hw_free = usb6fire_pcm_hw_free, +	.prepare = usb6fire_pcm_prepare, +	.trigger = usb6fire_pcm_trigger, +	.pointer = usb6fire_pcm_pointer, +	.page = snd_pcm_lib_get_vmalloc_page, +	.mmap = snd_pcm_lib_mmap_vmalloc, +}; + +static void usb6fire_pcm_init_urb(struct pcm_urb *urb, +				  struct sfire_chip *chip, bool in, int ep, +				  void (*handler)(struct urb *)) +{ +	urb->chip = chip; +	usb_init_urb(&urb->instance); +	urb->instance.transfer_buffer = urb->buffer; +	urb->instance.transfer_buffer_length = +			PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE; +	urb->instance.dev = chip->dev; +	urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep) +			: usb_sndisocpipe(chip->dev, ep); +	urb->instance.interval = 1; +	urb->instance.complete = handler; +	urb->instance.context = urb; +	urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; +} + +static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) +{ +	int i; + +	for (i = 0; i < PCM_N_URBS; i++) { +		rt->out_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB +				* PCM_MAX_PACKET_SIZE, GFP_KERNEL); +		if (!rt->out_urbs[i].buffer) +			return -ENOMEM; +		rt->in_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB +				* PCM_MAX_PACKET_SIZE, GFP_KERNEL); +		if (!rt->in_urbs[i].buffer) +			return -ENOMEM; +	} +	return 0; +} + +static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt) +{ +	int i; + +	for (i = 0; i < PCM_N_URBS; i++) { +		kfree(rt->out_urbs[i].buffer); +		kfree(rt->in_urbs[i].buffer); +	} +} + +int usb6fire_pcm_init(struct sfire_chip *chip) +{ +	int i; +	int ret; +	struct snd_pcm *pcm; +	struct pcm_runtime *rt = +			kzalloc(sizeof(struct pcm_runtime), GFP_KERNEL); + +	if (!rt) +		return -ENOMEM; + +	ret = usb6fire_pcm_buffers_init(rt); +	if (ret) { +		usb6fire_pcm_buffers_destroy(rt); +		kfree(rt); +		return ret; +	} + +	rt->chip = chip; +	rt->stream_state = STREAM_DISABLED; +	rt->rate = ARRAY_SIZE(rates); +	init_waitqueue_head(&rt->stream_wait_queue); +	mutex_init(&rt->stream_mutex); + +	spin_lock_init(&rt->playback.lock); +	spin_lock_init(&rt->capture.lock); + +	for (i = 0; i < PCM_N_URBS; i++) { +		usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, +				usb6fire_pcm_in_urb_handler); +		usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, +				usb6fire_pcm_out_urb_handler); + +		rt->in_urbs[i].peer = &rt->out_urbs[i]; +		rt->out_urbs[i].peer = &rt->in_urbs[i]; +	} + +	ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm); +	if (ret < 0) { +		usb6fire_pcm_buffers_destroy(rt); +		kfree(rt); +		dev_err(&chip->dev->dev, "cannot create pcm instance.\n"); +		return ret; +	} + +	pcm->private_data = rt; +	strcpy(pcm->name, "DMX 6Fire USB"); +	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); +	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); + +	if (ret) { +		usb6fire_pcm_buffers_destroy(rt); +		kfree(rt); +		dev_err(&chip->dev->dev, +			"error preallocating pcm buffers.\n"); +		return ret; +	} +	rt->instance = pcm; + +	chip->pcm = rt; +	return 0; +} + +void usb6fire_pcm_abort(struct sfire_chip *chip) +{ +	struct pcm_runtime *rt = chip->pcm; +	unsigned long flags; +	int i; + +	if (rt) { +		rt->panic = true; + +		if (rt->playback.instance) { +			snd_pcm_stream_lock_irqsave(rt->playback.instance, flags); +			snd_pcm_stop(rt->playback.instance, +					SNDRV_PCM_STATE_XRUN); +			snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags); +		} + +		if (rt->capture.instance) { +			snd_pcm_stream_lock_irqsave(rt->capture.instance, flags); +			snd_pcm_stop(rt->capture.instance, +					SNDRV_PCM_STATE_XRUN); +			snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags); +		} + +		for (i = 0; i < PCM_N_URBS; i++) { +			usb_poison_urb(&rt->in_urbs[i].instance); +			usb_poison_urb(&rt->out_urbs[i].instance); +		} + +	} +} + +void usb6fire_pcm_destroy(struct sfire_chip *chip) +{ +	struct pcm_runtime *rt = chip->pcm; + +	usb6fire_pcm_buffers_destroy(rt); +	kfree(rt); +	chip->pcm = NULL; +} diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h new file mode 100644 index 00000000000..f5779d6182c --- /dev/null +++ b/sound/usb/6fire/pcm.h @@ -0,0 +1,75 @@ +/* + * Linux driver for TerraTec DMX 6Fire USB + * + * Author:	Torsten Schenk <torsten.schenk@zoho.com> + * Created:	Jan 01, 2011 + * Copyright:	(C) Torsten Schenk + * + * 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. + */ + +#ifndef USB6FIRE_PCM_H +#define USB6FIRE_PCM_H + +#include <sound/pcm.h> +#include <linux/mutex.h> + +#include "common.h" + +enum /* settings for pcm */ +{ +	/* maximum of EP_W_MAX_PACKET_SIZE[] (see firmware.c) */ +	PCM_N_URBS = 16, PCM_N_PACKETS_PER_URB = 8, PCM_MAX_PACKET_SIZE = 604 +}; + +struct pcm_urb { +	struct sfire_chip *chip; + +	/* BEGIN DO NOT SEPARATE */ +	struct urb instance; +	struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB]; +	/* END DO NOT SEPARATE */ +	u8 *buffer; + +	struct pcm_urb *peer; +}; + +struct pcm_substream { +	spinlock_t lock; +	struct snd_pcm_substream *instance; + +	bool active; + +	snd_pcm_uframes_t dma_off; /* current position in alsa dma_area */ +	snd_pcm_uframes_t period_off; /* current position in current period */ +}; + +struct pcm_runtime { +	struct sfire_chip *chip; +	struct snd_pcm *instance; + +	struct pcm_substream playback; +	struct pcm_substream capture; +	bool panic; /* if set driver won't do anymore pcm on device */ + +	struct pcm_urb in_urbs[PCM_N_URBS]; +	struct pcm_urb out_urbs[PCM_N_URBS]; +	int in_packet_size; +	int out_packet_size; +	int in_n_analog; /* number of analog channels soundcard sends */ +	int out_n_analog; /* number of analog channels soundcard receives */ + +	struct mutex stream_mutex; +	u8 stream_state; /* one of STREAM_XXX (pcm.c) */ +	u8 rate; /* one of PCM_RATE_XXX */ +	wait_queue_head_t stream_wait_queue; +	bool stream_wait_cond; +}; + +int usb6fire_pcm_init(struct sfire_chip *chip); +void usb6fire_pcm_abort(struct sfire_chip *chip); +void usb6fire_pcm_destroy(struct sfire_chip *chip); +#endif /* USB6FIRE_PCM_H */ diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 112984f4080..d393153c474 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -14,6 +14,7 @@ config SND_USB_AUDIO  	select SND_HWDEP  	select SND_RAWMIDI  	select SND_PCM +	select BITREVERSE  	help  	  Say Y here to include support for USB audio and USB MIDI  	  devices. @@ -62,10 +63,12 @@ config SND_USB_CAIAQ  	    * Native Instruments Audio 2 DJ  	    * Native Instruments Audio 4 DJ  	    * Native Instruments Audio 8 DJ +	    * Native Instruments Traktor Audio 2  	    * Native Instruments Guitar Rig Session I/O  	    * Native Instruments Guitar Rig mobile  	    * Native Instruments Traktor Kontrol X1  	    * Native Instruments Traktor Kontrol S4 +	    * Native Instruments Maschine Controller  	   To compile this driver as a module, choose M here: the module  	   will be called snd-usb-caiaq. @@ -84,10 +87,11 @@ config SND_USB_CAIAQ_INPUT  	   * Native Instruments Kore Controller 2  	   * Native Instruments Audio Kontrol 1  	   * Native Instruments Traktor Kontrol S4 +	   * Native Instruments Maschine Controller  config SND_USB_US122L  	tristate "Tascam US-122L USB driver" -	depends on X86 && EXPERIMENTAL +	depends on X86  	select SND_HWDEP  	select SND_RAWMIDI  	help @@ -97,5 +101,64 @@ config SND_USB_US122L  	  To compile this driver as a module, choose M here: the module  	  will be called snd-usb-us122l. +config SND_USB_6FIRE +        tristate "TerraTec DMX 6Fire USB" +        select FW_LOADER +        select BITREVERSE +        select SND_RAWMIDI +        select SND_PCM +        select SND_VMASTER +        help +          Say Y here to include support for TerraTec 6fire DMX USB interface. + +          You will need firmware files in order to be able to use the device +          after it has been coldstarted. An install script for the firmware +          and further help can be found at +          http://sixfireusb.sourceforge.net + +config SND_USB_HIFACE +        tristate "M2Tech hiFace USB-SPDIF driver" +        select SND_PCM +        help +	  Select this option to include support for M2Tech hiFace USB-SPDIF +	  interface. + +	  This driver supports the original M2Tech hiFace and some other +	  compatible devices. The supported products are: + +	    * M2Tech Young +	    * M2Tech hiFace +	    * M2Tech North Star +	    * M2Tech W4S Young +	    * M2Tech Corrson +	    * M2Tech AUDIA +	    * M2Tech SL Audio +	    * M2Tech Empirical +	    * M2Tech Rockna +	    * M2Tech Pathos +	    * M2Tech Metronome +	    * M2Tech CAD +	    * M2Tech Audio Esclusive +	    * M2Tech Rotel +	    * M2Tech Eeaudio +	    * The Chord Company CHORD +	    * AVA Group A/S Vitus + +	  To compile this driver as a module, choose M here: the module +	  will be called snd-usb-hiface. + +config SND_BCD2000 +	tristate "Behringer BCD2000 MIDI driver" +	select SND_RAWMIDI +	help +	  Say Y here to include MIDI support for the Behringer BCD2000 DJ +	  controller. + +	  Audio support is still work-in-progress at +	  https://github.com/anyc/snd-usb-bcd2000 + +	  To compile this driver as a module, choose M here: the module +	  will be called snd-bcd2000. +  endif	# SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 1e362bf8834..2b92f0dcbc4 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -3,16 +3,16 @@  #  snd-usb-audio-objs := 	card.o \ +			clock.o \ +			endpoint.o \ +			format.o \ +			helper.o \  			mixer.o \  			mixer_quirks.o \ +			pcm.o \  			proc.o \  			quirks.o \ -			format.o \ -			endpoint.o \ -			urb.o \ -			pcm.o \ -			helper.o \ -			clock.o +			stream.o  snd-usbmidi-lib-objs := midi.o @@ -23,4 +23,4 @@ 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) += misc/ usx2y/ caiaq/ +obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ diff --git a/sound/usb/bcd2000/Makefile b/sound/usb/bcd2000/Makefile new file mode 100644 index 00000000000..f09ccc0af6f --- /dev/null +++ b/sound/usb/bcd2000/Makefile @@ -0,0 +1,3 @@ +snd-bcd2000-y := bcd2000.o + +obj-$(CONFIG_SND_BCD2000) += snd-bcd2000.o
\ No newline at end of file diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c new file mode 100644 index 00000000000..820d6ca8c45 --- /dev/null +++ b/sound/usb/bcd2000/bcd2000.c @@ -0,0 +1,461 @@ +/* + * Behringer BCD2000 driver + * + *   Copyright (C) 2014 Mario Kicherer (dev@kicherer.org) + * + *   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. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/bitmap.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> + +#define PREFIX "snd-bcd2000: " +#define BUFSIZE 64 + +static struct usb_device_id id_table[] = { +	{ USB_DEVICE(0x1397, 0x00bd) }, +	{ }, +}; + +static unsigned char device_cmd_prefix[] = {0x03, 0x00}; + +static unsigned char bcd2000_init_sequence[] = { +	0x07, 0x00, 0x00, 0x00, 0x78, 0x48, 0x1c, 0x81, +	0xc4, 0x00, 0x00, 0x00, 0x5e, 0x53, 0x4a, 0xf7, +	0x18, 0xfa, 0x11, 0xff, 0x6c, 0xf3, 0x90, 0xff, +	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +	0x18, 0xfa, 0x11, 0xff, 0x14, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0xf2, 0x34, 0x4a, 0xf7, +	0x18, 0xfa, 0x11, 0xff +}; + +struct bcd2000 { +	struct usb_device *dev; +	struct snd_card *card; +	struct usb_interface *intf; +	int card_index; + +	int midi_out_active; +	struct snd_rawmidi *rmidi; +	struct snd_rawmidi_substream *midi_receive_substream; +	struct snd_rawmidi_substream *midi_out_substream; + +	unsigned char midi_in_buf[BUFSIZE]; +	unsigned char midi_out_buf[BUFSIZE]; + +	struct urb *midi_out_urb; +	struct urb *midi_in_urb; + +	struct usb_anchor anchor; +}; + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; + +static DEFINE_MUTEX(devices_mutex); +DECLARE_BITMAP(devices_used, SNDRV_CARDS); +static struct usb_driver bcd2000_driver; + +#ifdef CONFIG_SND_DEBUG +static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len) +{ +	print_hex_dump(KERN_DEBUG, prefix, +			DUMP_PREFIX_NONE, 16, 1, +			buf, len, false); +} +#else +static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len) {} +#endif + +static int bcd2000_midi_input_open(struct snd_rawmidi_substream *substream) +{ +	return 0; +} + +static int bcd2000_midi_input_close(struct snd_rawmidi_substream *substream) +{ +	return 0; +} + +/* (de)register midi substream from client */ +static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream, +						int up) +{ +	struct bcd2000 *bcd2k = substream->rmidi->private_data; +	bcd2k->midi_receive_substream = up ? substream : NULL; +} + +static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k, +				const unsigned char *buf, unsigned int buf_len) +{ +	unsigned int payload_length, tocopy; +	struct snd_rawmidi_substream *midi_receive_substream; + +	midi_receive_substream = ACCESS_ONCE(bcd2k->midi_receive_substream); +	if (!midi_receive_substream) +		return; + +	bcd2000_dump_buffer(PREFIX "received from device: ", buf, buf_len); + +	if (buf_len < 2) +		return; + +	payload_length = buf[0]; + +	/* ignore packets without payload */ +	if (payload_length == 0) +		return; + +	tocopy = min(payload_length, buf_len-1); + +	bcd2000_dump_buffer(PREFIX "sending to userspace: ", +					&buf[1], tocopy); + +	snd_rawmidi_receive(midi_receive_substream, +					&buf[1], tocopy); +} + +static void bcd2000_midi_send(struct bcd2000 *bcd2k) +{ +	int len, ret; +	struct snd_rawmidi_substream *midi_out_substream; + +	BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE); + +	midi_out_substream = ACCESS_ONCE(bcd2k->midi_out_substream); +	if (!midi_out_substream) +		return; + +	/* copy command prefix bytes */ +	memcpy(bcd2k->midi_out_buf, device_cmd_prefix, +		sizeof(device_cmd_prefix)); + +	/* +	 * get MIDI packet and leave space for command prefix +	 * and payload length +	 */ +	len = snd_rawmidi_transmit(midi_out_substream, +				bcd2k->midi_out_buf + 3, BUFSIZE - 3); + +	if (len < 0) +		dev_err(&bcd2k->dev->dev, "%s: snd_rawmidi_transmit error %d\n", +				__func__, len); + +	if (len <= 0) +		return; + +	/* set payload length */ +	bcd2k->midi_out_buf[2] = len; +	bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE; + +	bcd2000_dump_buffer(PREFIX "sending to device: ", +			bcd2k->midi_out_buf, len+3); + +	/* send packet to the BCD2000 */ +	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC); +	if (ret < 0) +		dev_err(&bcd2k->dev->dev, PREFIX +			"%s (%p): usb_submit_urb() failed, ret=%d, len=%d\n", +			__func__, midi_out_substream, ret, len); +	else +		bcd2k->midi_out_active = 1; +} + +static int bcd2000_midi_output_open(struct snd_rawmidi_substream *substream) +{ +	return 0; +} + +static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream) +{ +	struct bcd2000 *bcd2k = substream->rmidi->private_data; + +	if (bcd2k->midi_out_active) { +		usb_kill_urb(bcd2k->midi_out_urb); +		bcd2k->midi_out_active = 0; +	} + +	return 0; +} + +/* (de)register midi substream from client */ +static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream, +						int up) +{ +	struct bcd2000 *bcd2k = substream->rmidi->private_data; + +	if (up) { +		bcd2k->midi_out_substream = substream; +		/* check if there is data userspace wants to send */ +		if (!bcd2k->midi_out_active) +			bcd2000_midi_send(bcd2k); +	} else { +		bcd2k->midi_out_substream = NULL; +	} +} + +static void bcd2000_output_complete(struct urb *urb) +{ +	struct bcd2000 *bcd2k = urb->context; + +	bcd2k->midi_out_active = 0; + +	if (urb->status) +		dev_warn(&urb->dev->dev, +			PREFIX "output urb->status: %d\n", urb->status); + +	if (urb->status == -ESHUTDOWN) +		return; + +	/* check if there is more data userspace wants to send */ +	bcd2000_midi_send(bcd2k); +} + +static void bcd2000_input_complete(struct urb *urb) +{ +	int ret; +	struct bcd2000 *bcd2k = urb->context; + +	if (urb->status) +		dev_warn(&urb->dev->dev, +			PREFIX "input urb->status: %i\n", urb->status); + +	if (!bcd2k || urb->status == -ESHUTDOWN) +		return; + +	if (urb->actual_length > 0) +		bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer, +					urb->actual_length); + +	/* return URB to device */ +	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_ATOMIC); +	if (ret < 0) +		dev_err(&bcd2k->dev->dev, PREFIX +			"%s: usb_submit_urb() failed, ret=%d\n", +			__func__, ret); +} + +static struct snd_rawmidi_ops bcd2000_midi_output = { +	.open =    bcd2000_midi_output_open, +	.close =   bcd2000_midi_output_close, +	.trigger = bcd2000_midi_output_trigger, +}; + +static struct snd_rawmidi_ops bcd2000_midi_input = { +	.open =    bcd2000_midi_input_open, +	.close =   bcd2000_midi_input_close, +	.trigger = bcd2000_midi_input_trigger, +}; + +static void bcd2000_init_device(struct bcd2000 *bcd2k) +{ +	int ret; + +	init_usb_anchor(&bcd2k->anchor); +	usb_anchor_urb(bcd2k->midi_out_urb, &bcd2k->anchor); +	usb_anchor_urb(bcd2k->midi_in_urb, &bcd2k->anchor); + +	/* copy init sequence into buffer */ +	memcpy(bcd2k->midi_out_buf, bcd2000_init_sequence, 52); +	bcd2k->midi_out_urb->transfer_buffer_length = 52; + +	/* submit sequence */ +	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_KERNEL); +	if (ret < 0) +		dev_err(&bcd2k->dev->dev, PREFIX +			"%s: usb_submit_urb() out failed, ret=%d: ", +			__func__, ret); +	else +		bcd2k->midi_out_active = 1; + +	/* pass URB to device to enable button and controller events */ +	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_KERNEL); +	if (ret < 0) +		dev_err(&bcd2k->dev->dev, PREFIX +			"%s: usb_submit_urb() in failed, ret=%d: ", +			__func__, ret); + +	/* ensure initialization is finished */ +	usb_wait_anchor_empty_timeout(&bcd2k->anchor, 1000); +} + +static int bcd2000_init_midi(struct bcd2000 *bcd2k) +{ +	int ret; +	struct snd_rawmidi *rmidi; + +	ret = snd_rawmidi_new(bcd2k->card, bcd2k->card->shortname, 0, +					1, /* output */ +					1, /* input */ +					&rmidi); + +	if (ret < 0) +		return ret; + +	strlcpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name)); + +	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX; +	rmidi->private_data = bcd2k; + +	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; +	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, +					&bcd2000_midi_output); + +	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; +	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, +					&bcd2000_midi_input); + +	bcd2k->rmidi = rmidi; + +	bcd2k->midi_in_urb = usb_alloc_urb(0, GFP_KERNEL); +	bcd2k->midi_out_urb = usb_alloc_urb(0, GFP_KERNEL); + +	if (!bcd2k->midi_in_urb || !bcd2k->midi_out_urb) { +		dev_err(&bcd2k->dev->dev, PREFIX "usb_alloc_urb failed\n"); +		return -ENOMEM; +	} + +	usb_fill_int_urb(bcd2k->midi_in_urb, bcd2k->dev, +				usb_rcvintpipe(bcd2k->dev, 0x81), +				bcd2k->midi_in_buf, BUFSIZE, +				bcd2000_input_complete, bcd2k, 1); + +	usb_fill_int_urb(bcd2k->midi_out_urb, bcd2k->dev, +				usb_sndintpipe(bcd2k->dev, 0x1), +				bcd2k->midi_out_buf, BUFSIZE, +				bcd2000_output_complete, bcd2k, 1); + +	bcd2000_init_device(bcd2k); + +	return 0; +} + +static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k, +						struct usb_interface *interface) +{ +	/* usb_kill_urb not necessary, urb is aborted automatically */ + +	usb_free_urb(bcd2k->midi_out_urb); +	usb_free_urb(bcd2k->midi_in_urb); + +	if (bcd2k->intf) { +		usb_set_intfdata(bcd2k->intf, NULL); +		bcd2k->intf = NULL; +	} +} + +static int bcd2000_probe(struct usb_interface *interface, +				const struct usb_device_id *usb_id) +{ +	struct snd_card *card; +	struct bcd2000 *bcd2k; +	unsigned int card_index; +	char usb_path[32]; +	int err; + +	mutex_lock(&devices_mutex); + +	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) +		if (!test_bit(card_index, devices_used)) +			break; + +	if (card_index >= SNDRV_CARDS) { +		mutex_unlock(&devices_mutex); +		return -ENOENT; +	} + +	err = snd_card_new(&interface->dev, index[card_index], id[card_index], +			THIS_MODULE, sizeof(*bcd2k), &card); +	if (err < 0) { +		mutex_unlock(&devices_mutex); +		return err; +	} + +	bcd2k = card->private_data; +	bcd2k->dev = interface_to_usbdev(interface); +	bcd2k->card = card; +	bcd2k->card_index = card_index; +	bcd2k->intf = interface; + +	snd_card_set_dev(card, &interface->dev); + +	strncpy(card->driver, "snd-bcd2000", sizeof(card->driver)); +	strncpy(card->shortname, "BCD2000", sizeof(card->shortname)); +	usb_make_path(bcd2k->dev, usb_path, sizeof(usb_path)); +	snprintf(bcd2k->card->longname, sizeof(bcd2k->card->longname), +		    "Behringer BCD2000 at %s", +			usb_path); + +	err = bcd2000_init_midi(bcd2k); +	if (err < 0) +		goto probe_error; + +	err = snd_card_register(card); +	if (err < 0) +		goto probe_error; + +	usb_set_intfdata(interface, bcd2k); +	set_bit(card_index, devices_used); + +	mutex_unlock(&devices_mutex); +	return 0; + +probe_error: +	dev_info(&bcd2k->dev->dev, PREFIX "error during probing"); +	bcd2000_free_usb_related_resources(bcd2k, interface); +	snd_card_free(card); +	mutex_unlock(&devices_mutex); +	return err; +} + +static void bcd2000_disconnect(struct usb_interface *interface) +{ +	struct bcd2000 *bcd2k = usb_get_intfdata(interface); + +	if (!bcd2k) +		return; + +	mutex_lock(&devices_mutex); + +	/* make sure that userspace cannot create new requests */ +	snd_card_disconnect(bcd2k->card); + +	bcd2000_free_usb_related_resources(bcd2k, interface); + +	clear_bit(bcd2k->card_index, devices_used); + +	snd_card_free_when_closed(bcd2k->card); + +	mutex_unlock(&devices_mutex); +} + +static struct usb_driver bcd2000_driver = { +	.name =		"snd-bcd2000", +	.probe =	bcd2000_probe, +	.disconnect =	bcd2000_disconnect, +	.id_table =	id_table, +}; + +module_usb_driver(bcd2000_driver); + +MODULE_DEVICE_TABLE(usb, id_table); +MODULE_AUTHOR("Mario Kicherer, dev@kicherer.org"); +MODULE_DESCRIPTION("Behringer BCD2000 driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 68b97477577..7103b0908d1 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -16,6 +16,7 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  */ +#include <linux/device.h>  #include <linux/spinlock.h>  #include <linux/slab.h>  #include <linux/init.h> @@ -39,8 +40,8 @@  #define ENDPOINT_CAPTURE	2  #define ENDPOINT_PLAYBACK	6 -#define MAKE_CHECKBYTE(dev,stream,i) \ -	(stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) +#define MAKE_CHECKBYTE(cdev,stream,i) \ +	(stream << 1) | (~(i / (cdev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)  static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {  	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -60,32 +61,32 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {  };  static void -activate_substream(struct snd_usb_caiaqdev *dev, +activate_substream(struct snd_usb_caiaqdev *cdev,  	           struct snd_pcm_substream *sub)  { -	spin_lock(&dev->spinlock); +	spin_lock(&cdev->spinlock);  	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) -		dev->sub_playback[sub->number] = sub; +		cdev->sub_playback[sub->number] = sub;  	else -		dev->sub_capture[sub->number] = sub; +		cdev->sub_capture[sub->number] = sub; -	spin_unlock(&dev->spinlock); +	spin_unlock(&cdev->spinlock);  }  static void -deactivate_substream(struct snd_usb_caiaqdev *dev, +deactivate_substream(struct snd_usb_caiaqdev *cdev,  		     struct snd_pcm_substream *sub)  {  	unsigned long flags; -	spin_lock_irqsave(&dev->spinlock, flags); +	spin_lock_irqsave(&cdev->spinlock, flags);  	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) -		dev->sub_playback[sub->number] = NULL; +		cdev->sub_playback[sub->number] = NULL;  	else -		dev->sub_capture[sub->number] = NULL; +		cdev->sub_capture[sub->number] = NULL; -	spin_unlock_irqrestore(&dev->spinlock, flags); +	spin_unlock_irqrestore(&cdev->spinlock, flags);  }  static int @@ -98,28 +99,30 @@ all_substreams_zero(struct snd_pcm_substream **subs)  	return 1;  } -static int stream_start(struct snd_usb_caiaqdev *dev) +static int stream_start(struct snd_usb_caiaqdev *cdev)  {  	int i, ret; +	struct device *dev = caiaqdev_to_dev(cdev); -	debug("%s(%p)\n", __func__, dev); +	dev_dbg(dev, "%s(%p)\n", __func__, cdev); -	if (dev->streaming) +	if (cdev->streaming)  		return -EINVAL; -	memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); -	memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); -	dev->input_panic = 0; -	dev->output_panic = 0; -	dev->first_packet = 4; -	dev->streaming = 1; -	dev->warned = 0; +	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback)); +	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture)); +	cdev->input_panic = 0; +	cdev->output_panic = 0; +	cdev->first_packet = 4; +	cdev->streaming = 1; +	cdev->warned = 0;  	for (i = 0; i < N_URBS; i++) { -		ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC); +		ret = usb_submit_urb(cdev->data_urbs_in[i], GFP_ATOMIC);  		if (ret) { -			log("unable to trigger read #%d! (ret %d)\n", i, ret); -			dev->streaming = 0; +			dev_err(dev, "unable to trigger read #%d! (ret %d)\n", +				i, ret); +			cdev->streaming = 0;  			return -EPIPE;  		}  	} @@ -127,42 +130,51 @@ static int stream_start(struct snd_usb_caiaqdev *dev)  	return 0;  } -static void stream_stop(struct snd_usb_caiaqdev *dev) +static void stream_stop(struct snd_usb_caiaqdev *cdev)  {  	int i; +	struct device *dev = caiaqdev_to_dev(cdev); -	debug("%s(%p)\n", __func__, dev); -	if (!dev->streaming) +	dev_dbg(dev, "%s(%p)\n", __func__, cdev); +	if (!cdev->streaming)  		return; -	dev->streaming = 0; +	cdev->streaming = 0;  	for (i = 0; i < N_URBS; i++) { -		usb_kill_urb(dev->data_urbs_in[i]); -		usb_kill_urb(dev->data_urbs_out[i]); +		usb_kill_urb(cdev->data_urbs_in[i]); + +		if (test_bit(i, &cdev->outurb_active_mask)) +			usb_kill_urb(cdev->data_urbs_out[i]);  	} + +	cdev->outurb_active_mask = 0;  }  static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)  { -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); -	debug("%s(%p)\n", __func__, substream); -	substream->runtime->hw = dev->pcm_info; +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream); +	struct device *dev = caiaqdev_to_dev(cdev); + +	dev_dbg(dev, "%s(%p)\n", __func__, substream); +	substream->runtime->hw = cdev->pcm_info;  	snd_pcm_limit_hw_rates(substream->runtime); +  	return 0;  }  static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)  { -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream); +	struct device *dev = caiaqdev_to_dev(cdev); -	debug("%s(%p)\n", __func__, substream); -	if (all_substreams_zero(dev->sub_playback) && -	    all_substreams_zero(dev->sub_capture)) { +	dev_dbg(dev, "%s(%p)\n", __func__, substream); +	if (all_substreams_zero(cdev->sub_playback) && +	    all_substreams_zero(cdev->sub_capture)) {  		/* when the last client has stopped streaming,  		 * all sample rates are allowed again */ -		stream_stop(dev); -		dev->pcm_info.rates = dev->samplerates; +		stream_stop(cdev); +		cdev->pcm_info.rates = cdev->samplerates;  	}  	return 0; @@ -171,16 +183,15 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)  static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,  				       struct snd_pcm_hw_params *hw_params)  { -	debug("%s(%p)\n", __func__, sub); -	return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); +	return snd_pcm_lib_alloc_vmalloc_buffer(sub, +						params_buffer_bytes(hw_params));  }  static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)  { -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); -	debug("%s(%p)\n", __func__, sub); -	deactivate_substream(dev, sub); -	return snd_pcm_lib_free_pages(sub); +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); +	deactivate_substream(cdev, sub); +	return snd_pcm_lib_free_vmalloc_buffer(sub);  }  /* this should probably go upstream */ @@ -195,15 +206,16 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)  {  	int bytes_per_sample, bpp, ret, i;  	int index = substream->number; -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);  	struct snd_pcm_runtime *runtime = substream->runtime; +	struct device *dev = caiaqdev_to_dev(cdev); -	debug("%s(%p)\n", __func__, substream); +	dev_dbg(dev, "%s(%p)\n", __func__, substream);  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {  		int out_pos; -		switch (dev->spec.data_alignment) { +		switch (cdev->spec.data_alignment) {  		case 0:  		case 2:  			out_pos = BYTES_PER_SAMPLE + 1; @@ -214,12 +226,12 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)  			break;  		} -		dev->period_out_count[index] = out_pos; -		dev->audio_out_buf_pos[index] = out_pos; +		cdev->period_out_count[index] = out_pos; +		cdev->audio_out_buf_pos[index] = out_pos;  	} else {  		int in_pos; -		switch (dev->spec.data_alignment) { +		switch (cdev->spec.data_alignment) {  		case 0:  			in_pos = BYTES_PER_SAMPLE + 2;  			break; @@ -232,44 +244,44 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)  			break;  		} -		dev->period_in_count[index] = in_pos; -		dev->audio_in_buf_pos[index] = in_pos; +		cdev->period_in_count[index] = in_pos; +		cdev->audio_in_buf_pos[index] = in_pos;  	} -	if (dev->streaming) +	if (cdev->streaming)  		return 0;  	/* the first client that opens a stream defines the sample rate  	 * setting for all subsequent calls, until the last client closed. */  	for (i=0; i < ARRAY_SIZE(rates); i++)  		if (runtime->rate == rates[i]) -			dev->pcm_info.rates = 1 << i; +			cdev->pcm_info.rates = 1 << i;  	snd_pcm_limit_hw_rates(runtime);  	bytes_per_sample = BYTES_PER_SAMPLE; -	if (dev->spec.data_alignment >= 2) +	if (cdev->spec.data_alignment >= 2)  		bytes_per_sample++;  	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) -		* bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams; +		* bytes_per_sample * CHANNELS_PER_STREAM * cdev->n_streams;  	if (bpp > MAX_ENDPOINT_SIZE)  		bpp = MAX_ENDPOINT_SIZE; -	ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate, +	ret = snd_usb_caiaq_set_audio_params(cdev, runtime->rate,  					     runtime->sample_bits, bpp);  	if (ret)  		return ret; -	ret = stream_start(dev); +	ret = stream_start(cdev);  	if (ret)  		return ret; -	dev->output_running = 0; -	wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ); -	if (!dev->output_running) { -		stream_stop(dev); +	cdev->output_running = 0; +	wait_event_timeout(cdev->prepare_wait_queue, cdev->output_running, HZ); +	if (!cdev->output_running) { +		stream_stop(cdev);  		return -EPIPE;  	} @@ -278,18 +290,19 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)  static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)  { -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub); +	struct device *dev = caiaqdev_to_dev(cdev); -	debug("%s(%p) cmd %d\n", __func__, sub, cmd); +	dev_dbg(dev, "%s(%p) cmd %d\n", __func__, sub, cmd);  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		activate_substream(dev, sub); +		activate_substream(cdev, sub);  		break;  	case SNDRV_PCM_TRIGGER_STOP:  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		deactivate_substream(dev, sub); +		deactivate_substream(cdev, sub);  		break;  	default:  		return -EINVAL; @@ -302,22 +315,25 @@ static snd_pcm_uframes_t  snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)  {  	int index = sub->number; -	struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); +	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);  	snd_pcm_uframes_t ptr; -	spin_lock(&dev->spinlock); +	spin_lock(&cdev->spinlock); -	if (dev->input_panic || dev->output_panic) +	if (cdev->input_panic || cdev->output_panic) {  		ptr = SNDRV_PCM_POS_XRUN; +		goto unlock; +	}  	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)  		ptr = bytes_to_frames(sub->runtime, -					dev->audio_out_buf_pos[index]); +					cdev->audio_out_buf_pos[index]);  	else  		ptr = bytes_to_frames(sub->runtime, -					dev->audio_in_buf_pos[index]); +					cdev->audio_in_buf_pos[index]); -	spin_unlock(&dev->spinlock); +unlock: +	spin_unlock(&cdev->spinlock);  	return ptr;  } @@ -330,24 +346,26 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {  	.hw_free =	snd_usb_caiaq_pcm_hw_free,  	.prepare =	snd_usb_caiaq_pcm_prepare,  	.trigger =	snd_usb_caiaq_pcm_trigger, -	.pointer =	snd_usb_caiaq_pcm_pointer +	.pointer =	snd_usb_caiaq_pcm_pointer, +	.page =		snd_pcm_lib_get_vmalloc_page, +	.mmap =		snd_pcm_lib_mmap_vmalloc,  }; -static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, +static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,  				      struct snd_pcm_substream **subs)  {  	int stream, pb, *cnt;  	struct snd_pcm_substream *sub; -	for (stream = 0; stream < dev->n_streams; stream++) { +	for (stream = 0; stream < cdev->n_streams; stream++) {  		sub = subs[stream];  		if (!sub)  			continue;  		pb = snd_pcm_lib_period_bytes(sub);  		cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ? -					&dev->period_out_count[stream] : -					&dev->period_in_count[stream]; +					&cdev->period_out_count[stream] : +					&cdev->period_in_count[stream];  		if (*cnt >= pb) {  			snd_pcm_period_elapsed(sub); @@ -356,7 +374,7 @@ static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev,  	}  } -static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev, +static void read_in_urb_mode0(struct snd_usb_caiaqdev *cdev,  			      const struct urb *urb,  			      const struct usb_iso_packet_descriptor *iso)  { @@ -364,27 +382,27 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,  	struct snd_pcm_substream *sub;  	int stream, i; -	if (all_substreams_zero(dev->sub_capture)) +	if (all_substreams_zero(cdev->sub_capture))  		return;  	for (i = 0; i < iso->actual_length;) { -		for (stream = 0; stream < dev->n_streams; stream++, i++) { -			sub = dev->sub_capture[stream]; +		for (stream = 0; stream < cdev->n_streams; stream++, i++) { +			sub = cdev->sub_capture[stream];  			if (sub) {  				struct snd_pcm_runtime *rt = sub->runtime;  				char *audio_buf = rt->dma_area;  				int sz = frames_to_bytes(rt, rt->buffer_size); -				audio_buf[dev->audio_in_buf_pos[stream]++] +				audio_buf[cdev->audio_in_buf_pos[stream]++]  					= usb_buf[i]; -				dev->period_in_count[stream]++; -				if (dev->audio_in_buf_pos[stream] == sz) -					dev->audio_in_buf_pos[stream] = 0; +				cdev->period_in_count[stream]++; +				if (cdev->audio_in_buf_pos[stream] == sz) +					cdev->audio_in_buf_pos[stream] = 0;  			}  		}  	}  } -static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, +static void read_in_urb_mode2(struct snd_usb_caiaqdev *cdev,  			      const struct urb *urb,  			      const struct usb_iso_packet_descriptor *iso)  { @@ -394,48 +412,49 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,  	int stream, i;  	for (i = 0; i < iso->actual_length;) { -		if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { +		if (i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {  			for (stream = 0; -			     stream < dev->n_streams; +			     stream < cdev->n_streams;  			     stream++, i++) { -				if (dev->first_packet) +				if (cdev->first_packet)  					continue; -				check_byte = MAKE_CHECKBYTE(dev, stream, i); +				check_byte = MAKE_CHECKBYTE(cdev, stream, i);  				if ((usb_buf[i] & 0x3f) != check_byte) -					dev->input_panic = 1; +					cdev->input_panic = 1;  				if (usb_buf[i] & 0x80) -					dev->output_panic = 1; +					cdev->output_panic = 1;  			}  		} -		dev->first_packet = 0; +		cdev->first_packet = 0; -		for (stream = 0; stream < dev->n_streams; stream++, i++) { -			sub = dev->sub_capture[stream]; -			if (dev->input_panic) +		for (stream = 0; stream < cdev->n_streams; stream++, i++) { +			sub = cdev->sub_capture[stream]; +			if (cdev->input_panic)  				usb_buf[i] = 0;  			if (sub) {  				struct snd_pcm_runtime *rt = sub->runtime;  				char *audio_buf = rt->dma_area;  				int sz = frames_to_bytes(rt, rt->buffer_size); -				audio_buf[dev->audio_in_buf_pos[stream]++] = +				audio_buf[cdev->audio_in_buf_pos[stream]++] =  					usb_buf[i]; -				dev->period_in_count[stream]++; -				if (dev->audio_in_buf_pos[stream] == sz) -					dev->audio_in_buf_pos[stream] = 0; +				cdev->period_in_count[stream]++; +				if (cdev->audio_in_buf_pos[stream] == sz) +					cdev->audio_in_buf_pos[stream] = 0;  			}  		}  	}  } -static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, +static void read_in_urb_mode3(struct snd_usb_caiaqdev *cdev,  			      const struct urb *urb,  			      const struct usb_iso_packet_descriptor *iso)  {  	unsigned char *usb_buf = urb->transfer_buffer + iso->offset; +	struct device *dev = caiaqdev_to_dev(cdev);  	int stream, i;  	/* paranoia check */ @@ -443,12 +462,12 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,  		return;  	for (i = 0; i < iso->actual_length;) { -		for (stream = 0; stream < dev->n_streams; stream++) { -			struct snd_pcm_substream *sub = dev->sub_capture[stream]; +		for (stream = 0; stream < cdev->n_streams; stream++) { +			struct snd_pcm_substream *sub = cdev->sub_capture[stream];  			char *audio_buf = NULL;  			int c, n, sz = 0; -			if (sub && !dev->input_panic) { +			if (sub && !cdev->input_panic) {  				struct snd_pcm_runtime *rt = sub->runtime;  				audio_buf = rt->dma_area;  				sz = frames_to_bytes(rt, rt->buffer_size); @@ -458,23 +477,23 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,  				/* 3 audio data bytes, followed by 1 check byte */  				if (audio_buf) {  					for (n = 0; n < BYTES_PER_SAMPLE; n++) { -						audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; +						audio_buf[cdev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; -						if (dev->audio_in_buf_pos[stream] == sz) -							dev->audio_in_buf_pos[stream] = 0; +						if (cdev->audio_in_buf_pos[stream] == sz) +							cdev->audio_in_buf_pos[stream] = 0;  					} -					dev->period_in_count[stream] += BYTES_PER_SAMPLE; +					cdev->period_in_count[stream] += BYTES_PER_SAMPLE;  				}  				i += BYTES_PER_SAMPLE;  				if (usb_buf[i] != ((stream << 1) | c) && -				    !dev->first_packet) { -					if (!dev->input_panic) -						printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", -							((stream << 1) | c), usb_buf[i], c, stream, i); -					dev->input_panic = 1; +				    !cdev->first_packet) { +					if (!cdev->input_panic) +						dev_warn(dev, " EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", +							 ((stream << 1) | c), usb_buf[i], c, stream, i); +					cdev->input_panic = 1;  				}  				i++; @@ -482,41 +501,43 @@ static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,  		}  	} -	if (dev->first_packet > 0) -		dev->first_packet--; +	if (cdev->first_packet > 0) +		cdev->first_packet--;  } -static void read_in_urb(struct snd_usb_caiaqdev *dev, +static void read_in_urb(struct snd_usb_caiaqdev *cdev,  			const struct urb *urb,  			const struct usb_iso_packet_descriptor *iso)  { -	if (!dev->streaming) +	struct device *dev = caiaqdev_to_dev(cdev); + +	if (!cdev->streaming)  		return; -	if (iso->actual_length < dev->bpp) +	if (iso->actual_length < cdev->bpp)  		return; -	switch (dev->spec.data_alignment) { +	switch (cdev->spec.data_alignment) {  	case 0: -		read_in_urb_mode0(dev, urb, iso); +		read_in_urb_mode0(cdev, urb, iso);  		break;  	case 2: -		read_in_urb_mode2(dev, urb, iso); +		read_in_urb_mode2(cdev, urb, iso);  		break;  	case 3: -		read_in_urb_mode3(dev, urb, iso); +		read_in_urb_mode3(cdev, urb, iso);  		break;  	} -	if ((dev->input_panic || dev->output_panic) && !dev->warned) { -		debug("streaming error detected %s %s\n", -				dev->input_panic ? "(input)" : "", -				dev->output_panic ? "(output)" : ""); -		dev->warned = 1; +	if ((cdev->input_panic || cdev->output_panic) && !cdev->warned) { +		dev_warn(dev, "streaming error detected %s %s\n", +				cdev->input_panic ? "(input)" : "", +				cdev->output_panic ? "(output)" : ""); +		cdev->warned = 1;  	}  } -static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, +static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *cdev,  				struct urb *urb,  				const struct usb_iso_packet_descriptor *iso)  { @@ -525,32 +546,32 @@ static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,  	int stream, i;  	for (i = 0; i < iso->length;) { -		for (stream = 0; stream < dev->n_streams; stream++, i++) { -			sub = dev->sub_playback[stream]; +		for (stream = 0; stream < cdev->n_streams; stream++, i++) { +			sub = cdev->sub_playback[stream];  			if (sub) {  				struct snd_pcm_runtime *rt = sub->runtime;  				char *audio_buf = rt->dma_area;  				int sz = frames_to_bytes(rt, rt->buffer_size);  				usb_buf[i] = -					audio_buf[dev->audio_out_buf_pos[stream]]; -				dev->period_out_count[stream]++; -				dev->audio_out_buf_pos[stream]++; -				if (dev->audio_out_buf_pos[stream] == sz) -					dev->audio_out_buf_pos[stream] = 0; +					audio_buf[cdev->audio_out_buf_pos[stream]]; +				cdev->period_out_count[stream]++; +				cdev->audio_out_buf_pos[stream]++; +				if (cdev->audio_out_buf_pos[stream] == sz) +					cdev->audio_out_buf_pos[stream] = 0;  			} else  				usb_buf[i] = 0;  		}  		/* fill in the check bytes */ -		if (dev->spec.data_alignment == 2 && -		    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == -		        (dev->n_streams * CHANNELS_PER_STREAM)) -			for (stream = 0; stream < dev->n_streams; stream++, i++) -				usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); +		if (cdev->spec.data_alignment == 2 && +		    i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == +		        (cdev->n_streams * CHANNELS_PER_STREAM)) +			for (stream = 0; stream < cdev->n_streams; stream++, i++) +				usb_buf[i] = MAKE_CHECKBYTE(cdev, stream, i);  	}  } -static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, +static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *cdev,  				struct urb *urb,  				const struct usb_iso_packet_descriptor *iso)  { @@ -558,8 +579,8 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,  	int stream, i;  	for (i = 0; i < iso->length;) { -		for (stream = 0; stream < dev->n_streams; stream++) { -			struct snd_pcm_substream *sub = dev->sub_playback[stream]; +		for (stream = 0; stream < cdev->n_streams; stream++) { +			struct snd_pcm_substream *sub = cdev->sub_playback[stream];  			char *audio_buf = NULL;  			int c, n, sz = 0; @@ -572,17 +593,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,  			for (c = 0; c < CHANNELS_PER_STREAM; c++) {  				for (n = 0; n < BYTES_PER_SAMPLE; n++) {  					if (audio_buf) { -						usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; +						usb_buf[i+n] = audio_buf[cdev->audio_out_buf_pos[stream]++]; -						if (dev->audio_out_buf_pos[stream] == sz) -							dev->audio_out_buf_pos[stream] = 0; +						if (cdev->audio_out_buf_pos[stream] == sz) +							cdev->audio_out_buf_pos[stream] = 0;  					} else {  						usb_buf[i+n] = 0;  					}  				}  				if (audio_buf) -					dev->period_out_count[stream] += BYTES_PER_SAMPLE; +					cdev->period_out_count[stream] += BYTES_PER_SAMPLE;  				i += BYTES_PER_SAMPLE; @@ -593,17 +614,17 @@ static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,  	}  } -static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, +static inline void fill_out_urb(struct snd_usb_caiaqdev *cdev,  				struct urb *urb,  				const struct usb_iso_packet_descriptor *iso)  { -	switch (dev->spec.data_alignment) { +	switch (cdev->spec.data_alignment) {  	case 0:  	case 2: -		fill_out_urb_mode_0(dev, urb, iso); +		fill_out_urb_mode_0(cdev, urb, iso);  		break;  	case 3: -		fill_out_urb_mode_3(dev, urb, iso); +		fill_out_urb_mode_3(cdev, urb, iso);  		break;  	}  } @@ -611,19 +632,32 @@ static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,  static void read_completed(struct urb *urb)  {  	struct snd_usb_caiaq_cb_info *info = urb->context; -	struct snd_usb_caiaqdev *dev; -	struct urb *out; -	int frame, len, send_it = 0, outframe = 0; +	struct snd_usb_caiaqdev *cdev; +	struct device *dev; +	struct urb *out = NULL; +	int i, frame, len, send_it = 0, outframe = 0; +	size_t offset = 0;  	if (urb->status || !info)  		return; -	dev = info->dev; +	cdev = info->cdev; +	dev = caiaqdev_to_dev(cdev); -	if (!dev->streaming) +	if (!cdev->streaming)  		return; -	out = dev->data_urbs_out[info->index]; +	/* find an unused output urb that is unused */ +	for (i = 0; i < N_URBS; i++) +		if (test_and_set_bit(i, &cdev->outurb_active_mask) == 0) { +			out = cdev->data_urbs_out[i]; +			break; +		} + +	if (!out) { +		dev_err(dev, "Unable to find an output urb to use\n"); +		goto requeue; +	}  	/* read the recently received packet and send back one which has  	 * the same layout */ @@ -634,15 +668,16 @@ static void read_completed(struct urb *urb)  		len = urb->iso_frame_desc[outframe].actual_length;  		out->iso_frame_desc[outframe].length = len;  		out->iso_frame_desc[outframe].actual_length = 0; -		out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; +		out->iso_frame_desc[outframe].offset = offset; +		offset += len;  		if (len > 0) { -			spin_lock(&dev->spinlock); -			fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); -			read_in_urb(dev, urb, &urb->iso_frame_desc[frame]); -			spin_unlock(&dev->spinlock); -			check_for_elapsed_periods(dev, dev->sub_playback); -			check_for_elapsed_periods(dev, dev->sub_capture); +			spin_lock(&cdev->spinlock); +			fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); +			read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); +			spin_unlock(&cdev->spinlock); +			check_for_elapsed_periods(cdev, cdev->sub_playback); +			check_for_elapsed_periods(cdev, cdev->sub_capture);  			send_it = 1;  		} @@ -650,11 +685,14 @@ static void read_completed(struct urb *urb)  	}  	if (send_it) { -		out->number_of_packets = FRAMES_PER_URB; -		out->transfer_flags = URB_ISO_ASAP; +		out->number_of_packets = outframe;  		usb_submit_urb(out, GFP_ATOMIC); +	} else { +		struct snd_usb_caiaq_cb_info *oinfo = out->context; +		clear_bit(oinfo->index, &cdev->outurb_active_mask);  	} +requeue:  	/* re-submit inbound urb */  	for (frame = 0; frame < FRAMES_PER_URB; frame++) {  		urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; @@ -663,26 +701,28 @@ static void read_completed(struct urb *urb)  	}  	urb->number_of_packets = FRAMES_PER_URB; -	urb->transfer_flags = URB_ISO_ASAP;  	usb_submit_urb(urb, GFP_ATOMIC);  }  static void write_completed(struct urb *urb)  {  	struct snd_usb_caiaq_cb_info *info = urb->context; -	struct snd_usb_caiaqdev *dev = info->dev; +	struct snd_usb_caiaqdev *cdev = info->cdev; -	if (!dev->output_running) { -		dev->output_running = 1; -		wake_up(&dev->prepare_wait_queue); +	if (!cdev->output_running) { +		cdev->output_running = 1; +		wake_up(&cdev->prepare_wait_queue);  	} + +	clear_bit(info->index, &cdev->outurb_active_mask);  } -static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) +static struct urb **alloc_urbs(struct snd_usb_caiaqdev *cdev, int dir, int *ret)  {  	int i, frame;  	struct urb **urbs; -	struct usb_device *usb_dev = dev->chip.dev; +	struct usb_device *usb_dev = cdev->chip.dev; +	struct device *dev = caiaqdev_to_dev(cdev);  	unsigned int pipe;  	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? @@ -691,7 +731,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)  	urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL);  	if (!urbs) { -		log("unable to kmalloc() urbs, OOM!?\n"); +		dev_err(dev, "unable to kmalloc() urbs, OOM!?\n");  		*ret = -ENOMEM;  		return NULL;  	} @@ -699,7 +739,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)  	for (i = 0; i < N_URBS; i++) {  		urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL);  		if (!urbs[i]) { -			log("unable to usb_alloc_urb(), OOM!?\n"); +			dev_err(dev, "unable to usb_alloc_urb(), OOM!?\n");  			*ret = -ENOMEM;  			return urbs;  		} @@ -707,7 +747,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)  		urbs[i]->transfer_buffer =  			kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL);  		if (!urbs[i]->transfer_buffer) { -			log("unable to kmalloc() transfer buffer, OOM!?\n"); +			dev_err(dev, "unable to kmalloc() transfer buffer, OOM!?\n");  			*ret = -ENOMEM;  			return urbs;  		} @@ -724,9 +764,8 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret)  		urbs[i]->pipe = pipe;  		urbs[i]->transfer_buffer_length = FRAMES_PER_URB  						* BYTES_PER_FRAME; -		urbs[i]->context = &dev->data_cb_info[i]; +		urbs[i]->context = &cdev->data_cb_info[i];  		urbs[i]->interval = 1; -		urbs[i]->transfer_flags = URB_ISO_ASAP;  		urbs[i]->number_of_packets = FRAMES_PER_URB;  		urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ?  					read_completed : write_completed; @@ -755,106 +794,108 @@ static void free_urbs(struct urb **urbs)  	kfree(urbs);  } -int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)  {  	int i, ret; +	struct device *dev = caiaqdev_to_dev(cdev); -	dev->n_audio_in  = max(dev->spec.num_analog_audio_in, -			       dev->spec.num_digital_audio_in) / +	cdev->n_audio_in  = max(cdev->spec.num_analog_audio_in, +			       cdev->spec.num_digital_audio_in) /  				CHANNELS_PER_STREAM; -	dev->n_audio_out = max(dev->spec.num_analog_audio_out, -			       dev->spec.num_digital_audio_out) / +	cdev->n_audio_out = max(cdev->spec.num_analog_audio_out, +			       cdev->spec.num_digital_audio_out) /  				CHANNELS_PER_STREAM; -	dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); +	cdev->n_streams = max(cdev->n_audio_in, cdev->n_audio_out); -	debug("dev->n_audio_in = %d\n", dev->n_audio_in); -	debug("dev->n_audio_out = %d\n", dev->n_audio_out); -	debug("dev->n_streams = %d\n", dev->n_streams); +	dev_dbg(dev, "cdev->n_audio_in = %d\n", cdev->n_audio_in); +	dev_dbg(dev, "cdev->n_audio_out = %d\n", cdev->n_audio_out); +	dev_dbg(dev, "cdev->n_streams = %d\n", cdev->n_streams); -	if (dev->n_streams > MAX_STREAMS) { -		log("unable to initialize device, too many streams.\n"); +	if (cdev->n_streams > MAX_STREAMS) { +		dev_err(dev, "unable to initialize device, too many streams.\n");  		return -EINVAL;  	} -	ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, -			dev->n_audio_out, dev->n_audio_in, &dev->pcm); +	ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0, +			cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);  	if (ret < 0) { -		log("snd_pcm_new() returned %d\n", ret); +		dev_err(dev, "snd_pcm_new() returned %d\n", ret);  		return ret;  	} -	dev->pcm->private_data = dev; -	strcpy(dev->pcm->name, dev->product_name); +	cdev->pcm->private_data = cdev; +	strlcpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name)); -	memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); -	memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); +	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback)); +	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture)); -	memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, +	memcpy(&cdev->pcm_info, &snd_usb_caiaq_pcm_hardware,  			sizeof(snd_usb_caiaq_pcm_hardware));  	/* setup samplerates */ -	dev->samplerates = dev->pcm_info.rates; -	switch (dev->chip.usb_id) { +	cdev->samplerates = cdev->pcm_info.rates; +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE): -		dev->samplerates |= SNDRV_PCM_RATE_192000; +		cdev->samplerates |= SNDRV_PCM_RATE_192000;  		/* fall thru */  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): -		dev->samplerates |= SNDRV_PCM_RATE_88200; +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2): +		cdev->samplerates |= SNDRV_PCM_RATE_88200;  		break;  	} -	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, +	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_PLAYBACK,  				&snd_usb_caiaq_ops); -	snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, +	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,  				&snd_usb_caiaq_ops); -	snd_pcm_lib_preallocate_pages_for_all(dev->pcm, -					SNDRV_DMA_TYPE_CONTINUOUS, -					snd_dma_continuous_data(GFP_KERNEL), -					MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); - -	dev->data_cb_info = +	cdev->data_cb_info =  		kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,  					GFP_KERNEL); -	if (!dev->data_cb_info) +	if (!cdev->data_cb_info)  		return -ENOMEM; +	cdev->outurb_active_mask = 0; +	BUILD_BUG_ON(N_URBS > (sizeof(cdev->outurb_active_mask) * 8)); +  	for (i = 0; i < N_URBS; i++) { -		dev->data_cb_info[i].dev = dev; -		dev->data_cb_info[i].index = i; +		cdev->data_cb_info[i].cdev = cdev; +		cdev->data_cb_info[i].index = i;  	} -	dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); +	cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret);  	if (ret < 0) { -		kfree(dev->data_cb_info); -		free_urbs(dev->data_urbs_in); +		kfree(cdev->data_cb_info); +		free_urbs(cdev->data_urbs_in);  		return ret;  	} -	dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); +	cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret);  	if (ret < 0) { -		kfree(dev->data_cb_info); -		free_urbs(dev->data_urbs_in); -		free_urbs(dev->data_urbs_out); +		kfree(cdev->data_cb_info); +		free_urbs(cdev->data_urbs_in); +		free_urbs(cdev->data_urbs_out);  		return ret;  	}  	return 0;  } -void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev) +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)  { -	debug("%s(%p)\n", __func__, dev); -	stream_stop(dev); -	free_urbs(dev->data_urbs_in); -	free_urbs(dev->data_urbs_out); -	kfree(dev->data_cb_info); +	struct device *dev = caiaqdev_to_dev(cdev); + +	dev_dbg(dev, "%s(%p)\n", __func__, cdev); +	stream_stop(cdev); +	free_urbs(cdev->data_urbs_in); +	free_urbs(cdev->data_urbs_out); +	kfree(cdev->data_cb_info);  } diff --git a/sound/usb/caiaq/audio.h b/sound/usb/caiaq/audio.h index 8ab1f8d9529..bdf155300a8 100644 --- a/sound/usb/caiaq/audio.h +++ b/sound/usb/caiaq/audio.h @@ -1,7 +1,7 @@  #ifndef CAIAQ_AUDIO_H  #define CAIAQ_AUDIO_H -int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev); -void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev); +int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev);  #endif /* CAIAQ_AUDIO_H */ diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 00e5d0a469e..f65fc0987cf 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -17,6 +17,7 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   */ +#include <linux/device.h>  #include <linux/init.h>  #include <linux/usb.h>  #include <sound/control.h> @@ -27,12 +28,13 @@  #include "control.h"  #define CNT_INTVAL 0x10000 +#define MASCHINE_BANK_SIZE 32  static int control_info(struct snd_kcontrol *kcontrol,  			struct snd_ctl_elem_info *uinfo)  {  	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); -	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); +	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);  	int pos = kcontrol->private_value;  	int is_intval = pos & CNT_INTVAL;  	int maxval = 63; @@ -40,7 +42,7 @@ static int control_info(struct snd_kcontrol *kcontrol,  	uinfo->count = 1;  	pos &= ~CNT_INTVAL; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):  		if (pos == 0) { @@ -78,15 +80,15 @@ static int control_get(struct snd_kcontrol *kcontrol,  		       struct snd_ctl_elem_value *ucontrol)  {  	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); -	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); +	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);  	int pos = kcontrol->private_value;  	if (pos & CNT_INTVAL)  		ucontrol->value.integer.value[0] -			= dev->control_state[pos & ~CNT_INTVAL]; +			= cdev->control_state[pos & ~CNT_INTVAL];  	else  		ucontrol->value.integer.value[0] -			= !!(dev->control_state[pos / 8] & (1 << pos % 8)); +			= !!(cdev->control_state[pos / 8] & (1 << pos % 8));  	return 0;  } @@ -95,49 +97,67 @@ static int control_put(struct snd_kcontrol *kcontrol,  		       struct snd_ctl_elem_value *ucontrol)  {  	struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); -	struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); +	struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);  	int pos = kcontrol->private_value;  	int v = ucontrol->value.integer.value[0];  	unsigned char cmd = EP1_CMD_WRITE_IO; -	if (dev->chip.usb_id == +	if (cdev->chip.usb_id ==  		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))  		cmd = EP1_CMD_DIMM_LEDS; +	if (cdev->chip.usb_id == +		USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) +		cmd = EP1_CMD_DIMM_LEDS; +  	if (pos & CNT_INTVAL) {  		int i = pos & ~CNT_INTVAL; -		dev->control_state[i] = v; +		cdev->control_state[i] = v; -		if (dev->chip.usb_id == +		if (cdev->chip.usb_id ==  			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {  			int actual_len; -			dev->ep8_out_buf[0] = i; -			dev->ep8_out_buf[1] = v; +			cdev->ep8_out_buf[0] = i; +			cdev->ep8_out_buf[1] = v; -			usb_bulk_msg(dev->chip.dev, -				     usb_sndbulkpipe(dev->chip.dev, 8), -				     dev->ep8_out_buf, sizeof(dev->ep8_out_buf), +			usb_bulk_msg(cdev->chip.dev, +				     usb_sndbulkpipe(cdev->chip.dev, 8), +				     cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),  				     &actual_len, 200); +		} else if (cdev->chip.usb_id == +			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) { + +			int bank = 0; +			int offset = 0; + +			if (i >= MASCHINE_BANK_SIZE) { +				bank = 0x1e; +				offset = MASCHINE_BANK_SIZE; +			} + +			snd_usb_caiaq_send_command_bank(cdev, cmd, bank, +					cdev->control_state + offset, +					MASCHINE_BANK_SIZE);  		} else { -			snd_usb_caiaq_send_command(dev, cmd, -					dev->control_state, sizeof(dev->control_state)); +			snd_usb_caiaq_send_command(cdev, cmd, +					cdev->control_state, sizeof(cdev->control_state));  		}  	} else {  		if (v) -			dev->control_state[pos / 8] |= 1 << (pos % 8); +			cdev->control_state[pos / 8] |= 1 << (pos % 8);  		else -			dev->control_state[pos / 8] &= ~(1 << (pos % 8)); +			cdev->control_state[pos / 8] &= ~(1 << (pos % 8)); -		snd_usb_caiaq_send_command(dev, cmd, -				dev->control_state, sizeof(dev->control_state)); +		snd_usb_caiaq_send_command(cdev, cmd, +				cdev->control_state, sizeof(cdev->control_state));  	}  	return 1;  } -static struct snd_kcontrol_new kcontrol_template __devinitdata = { +static struct snd_kcontrol_new kcontrol_template = {  	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,  	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,  	.index = 0, @@ -489,8 +509,76 @@ static struct caiaq_controller kontrols4_controller[] = {  	{ "LED: FX2: Mode",			133 | CNT_INTVAL },  }; -static int __devinit add_controls(struct caiaq_controller *c, int num, -				  struct snd_usb_caiaqdev *dev) +static struct caiaq_controller maschine_controller[] = { +	{ "LED: Pad 1",				3  | CNT_INTVAL }, +	{ "LED: Pad 2",				2  | CNT_INTVAL }, +	{ "LED: Pad 3",				1  | CNT_INTVAL }, +	{ "LED: Pad 4",				0  | CNT_INTVAL }, +	{ "LED: Pad 5",				7  | CNT_INTVAL }, +	{ "LED: Pad 6",				6  | CNT_INTVAL }, +	{ "LED: Pad 7",				5  | CNT_INTVAL }, +	{ "LED: Pad 8",				4  | CNT_INTVAL }, +	{ "LED: Pad 9",				11 | CNT_INTVAL }, +	{ "LED: Pad 10",			10 | CNT_INTVAL }, +	{ "LED: Pad 11",			9  | CNT_INTVAL }, +	{ "LED: Pad 12",			8  | CNT_INTVAL }, +	{ "LED: Pad 13",			15 | CNT_INTVAL }, +	{ "LED: Pad 14",			14 | CNT_INTVAL }, +	{ "LED: Pad 15",			13 | CNT_INTVAL }, +	{ "LED: Pad 16",			12 | CNT_INTVAL }, + +	{ "LED: Mute",				16 | CNT_INTVAL }, +	{ "LED: Solo",				17 | CNT_INTVAL }, +	{ "LED: Select",			18 | CNT_INTVAL }, +	{ "LED: Duplicate",			19 | CNT_INTVAL }, +	{ "LED: Navigate",			20 | CNT_INTVAL }, +	{ "LED: Pad Mode",			21 | CNT_INTVAL }, +	{ "LED: Pattern",			22 | CNT_INTVAL }, +	{ "LED: Scene",				23 | CNT_INTVAL }, + +	{ "LED: Shift",				24 | CNT_INTVAL }, +	{ "LED: Erase",				25 | CNT_INTVAL }, +	{ "LED: Grid",				26 | CNT_INTVAL }, +	{ "LED: Right Bottom",			27 | CNT_INTVAL }, +	{ "LED: Rec",				28 | CNT_INTVAL }, +	{ "LED: Play",				29 | CNT_INTVAL }, +	{ "LED: Left Bottom",			32 | CNT_INTVAL }, +	{ "LED: Restart",			33 | CNT_INTVAL }, + +	{ "LED: Group A",			41 | CNT_INTVAL }, +	{ "LED: Group B",			40 | CNT_INTVAL }, +	{ "LED: Group C",			37 | CNT_INTVAL }, +	{ "LED: Group D",			36 | CNT_INTVAL }, +	{ "LED: Group E",			39 | CNT_INTVAL }, +	{ "LED: Group F",			38 | CNT_INTVAL }, +	{ "LED: Group G",			35 | CNT_INTVAL }, +	{ "LED: Group H",			34 | CNT_INTVAL }, + +	{ "LED: Auto Write",			42 | CNT_INTVAL }, +	{ "LED: Snap",				43 | CNT_INTVAL }, +	{ "LED: Right Top",			44 | CNT_INTVAL }, +	{ "LED: Left Top",			45 | CNT_INTVAL }, +	{ "LED: Sampling",			46 | CNT_INTVAL }, +	{ "LED: Browse",			47 | CNT_INTVAL }, +	{ "LED: Step",				48 | CNT_INTVAL }, +	{ "LED: Control",			49 | CNT_INTVAL }, + +	{ "LED: Top Button 1",			57 | CNT_INTVAL }, +	{ "LED: Top Button 2",			56 | CNT_INTVAL }, +	{ "LED: Top Button 3",			55 | CNT_INTVAL }, +	{ "LED: Top Button 4",			54 | CNT_INTVAL }, +	{ "LED: Top Button 5",			53 | CNT_INTVAL }, +	{ "LED: Top Button 6",			52 | CNT_INTVAL }, +	{ "LED: Top Button 7",			51 | CNT_INTVAL }, +	{ "LED: Top Button 8",			50 | CNT_INTVAL }, + +	{ "LED: Note Repeat",			58 | CNT_INTVAL }, + +	{ "Backlight Display",			59 | CNT_INTVAL } +}; + +static int add_controls(struct caiaq_controller *c, int num, +			struct snd_usb_caiaqdev *cdev)  {  	int i, ret;  	struct snd_kcontrol *kc; @@ -498,8 +586,8 @@ static int __devinit add_controls(struct caiaq_controller *c, int num,  	for (i = 0; i < num; i++, c++) {  		kcontrol_template.name = c->name;  		kcontrol_template.private_value = c->index; -		kc = snd_ctl_new1(&kcontrol_template, dev); -		ret = snd_ctl_add(dev->chip.card, kc); +		kc = snd_ctl_new1(&kcontrol_template, cdev); +		ret = snd_ctl_add(cdev->chip.card, kc);  		if (ret < 0)  			return ret;  	} @@ -507,50 +595,55 @@ static int __devinit add_controls(struct caiaq_controller *c, int num,  	return 0;  } -int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)  {  	int ret = 0; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):  		ret = add_controls(ak1_controller, -			ARRAY_SIZE(ak1_controller), dev); +			ARRAY_SIZE(ak1_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):  		ret = add_controls(rk2_controller, -			ARRAY_SIZE(rk2_controller), dev); +			ARRAY_SIZE(rk2_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):  		ret = add_controls(rk3_controller, -			ARRAY_SIZE(rk3_controller), dev); +			ARRAY_SIZE(rk3_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):  		ret = add_controls(kore_controller, -			ARRAY_SIZE(kore_controller), dev); +			ARRAY_SIZE(kore_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):  		ret = add_controls(a8dj_controller, -			ARRAY_SIZE(a8dj_controller), dev); +			ARRAY_SIZE(a8dj_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):  		ret = add_controls(a4dj_controller, -			ARRAY_SIZE(a4dj_controller), dev); +			ARRAY_SIZE(a4dj_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):  		ret = add_controls(kontrolx1_controller, -			ARRAY_SIZE(kontrolx1_controller), dev); +			ARRAY_SIZE(kontrolx1_controller), cdev);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):  		ret = add_controls(kontrols4_controller, -			ARRAY_SIZE(kontrols4_controller), dev); +			ARRAY_SIZE(kontrols4_controller), cdev); +		break; + +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		ret = add_controls(maschine_controller, +			ARRAY_SIZE(maschine_controller), cdev);  		break;  	} diff --git a/sound/usb/caiaq/control.h b/sound/usb/caiaq/control.h index 2e7ab1aa4fb..501c4883aef 100644 --- a/sound/usb/caiaq/control.h +++ b/sound/usb/caiaq/control.h @@ -1,6 +1,6 @@  #ifndef CAIAQ_CONTROL_H  #define CAIAQ_CONTROL_H -int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev); +int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev);  #endif /* CAIAQ_CONTROL_H */ diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 6480c3283c0..b871ba407e4 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -20,6 +20,7 @@  */  #include <linux/moduleparam.h> +#include <linux/device.h>  #include <linux/interrupt.h>  #include <linux/module.h>  #include <linux/init.h> @@ -38,23 +39,24 @@  MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");  MODULE_DESCRIPTION("caiaq USB audio");  MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," -			 "{Native Instruments, RigKontrol3}," -			 "{Native Instruments, Kore Controller}," -			 "{Native Instruments, Kore Controller 2}," -			 "{Native Instruments, Audio Kontrol 1}," -			 "{Native Instruments, Audio 2 DJ}," -			 "{Native Instruments, Audio 4 DJ}," -			 "{Native Instruments, Audio 8 DJ}," -			 "{Native Instruments, Session I/O}," -			 "{Native Instruments, GuitarRig mobile}" -			 "{Native Instruments, Traktor Kontrol X1}" -			 "{Native Instruments, Traktor Kontrol S4}"); +MODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2}," +			 "{Native Instruments,RigKontrol3}," +			 "{Native Instruments,Kore Controller}," +			 "{Native Instruments,Kore Controller 2}," +			 "{Native Instruments,Audio Kontrol 1}," +			 "{Native Instruments,Audio 2 DJ}," +			 "{Native Instruments,Audio 4 DJ}," +			 "{Native Instruments,Audio 8 DJ}," +			 "{Native Instruments,Traktor Audio 2}," +			 "{Native Instruments,Session I/O}," +			 "{Native Instruments,GuitarRig mobile}," +			 "{Native Instruments,Traktor Kontrol X1}," +			 "{Native Instruments,Traktor Kontrol S4}," +			 "{Native Instruments,Maschine Controller}}");  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 */ -static int snd_card_used[SNDRV_CARDS]; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */  module_param_array(index, int, NULL, 0444);  MODULE_PARM_DESC(index, "Index value for the caiaq sound device"); @@ -140,73 +142,84 @@ static struct usb_device_id snd_usb_id_table[] = {  		.idVendor =     USB_VID_NATIVEINSTRUMENTS,  		.idProduct =    USB_PID_TRAKTORKONTROLS4  	}, +	{ +		.match_flags =  USB_DEVICE_ID_MATCH_DEVICE, +		.idVendor =     USB_VID_NATIVEINSTRUMENTS, +		.idProduct =    USB_PID_TRAKTORAUDIO2 +	}, +	{ +		.match_flags =  USB_DEVICE_ID_MATCH_DEVICE, +		.idVendor =     USB_VID_NATIVEINSTRUMENTS, +		.idProduct =    USB_PID_MASCHINECONTROLLER +	},  	{ /* terminator */ }  };  static void usb_ep1_command_reply_dispatch (struct urb* urb)  {  	int ret; -	struct snd_usb_caiaqdev *dev = urb->context; +	struct device *dev = &urb->dev->dev; +	struct snd_usb_caiaqdev *cdev = urb->context;  	unsigned char *buf = urb->transfer_buffer; -	if (urb->status || !dev) { -		log("received EP1 urb->status = %i\n", urb->status); +	if (urb->status || !cdev) { +		dev_warn(dev, "received EP1 urb->status = %i\n", urb->status);  		return;  	}  	switch(buf[0]) {  	case EP1_CMD_GET_DEVICE_INFO: -	 	memcpy(&dev->spec, buf+1, sizeof(struct caiaq_device_spec)); -		dev->spec.fw_version = le16_to_cpu(dev->spec.fw_version); -		debug("device spec (firmware %d): audio: %d in, %d out, " +	 	memcpy(&cdev->spec, buf+1, sizeof(struct caiaq_device_spec)); +		cdev->spec.fw_version = le16_to_cpu(cdev->spec.fw_version); +		dev_dbg(dev, "device spec (firmware %d): audio: %d in, %d out, "  			"MIDI: %d in, %d out, data alignment %d\n", -			dev->spec.fw_version, -			dev->spec.num_analog_audio_in, -			dev->spec.num_analog_audio_out, -			dev->spec.num_midi_in, -			dev->spec.num_midi_out, -			dev->spec.data_alignment); - -		dev->spec_received++; -		wake_up(&dev->ep1_wait_queue); +			cdev->spec.fw_version, +			cdev->spec.num_analog_audio_in, +			cdev->spec.num_analog_audio_out, +			cdev->spec.num_midi_in, +			cdev->spec.num_midi_out, +			cdev->spec.data_alignment); + +		cdev->spec_received++; +		wake_up(&cdev->ep1_wait_queue);  		break;  	case EP1_CMD_AUDIO_PARAMS: -		dev->audio_parm_answer = buf[1]; -		wake_up(&dev->ep1_wait_queue); +		cdev->audio_parm_answer = buf[1]; +		wake_up(&cdev->ep1_wait_queue);  		break;  	case EP1_CMD_MIDI_READ: -		snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); +		snd_usb_caiaq_midi_handle_input(cdev, buf[1], buf + 3, buf[2]);  		break;  	case EP1_CMD_READ_IO: -		if (dev->chip.usb_id == +		if (cdev->chip.usb_id ==  			USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) { -			if (urb->actual_length > sizeof(dev->control_state)) -				urb->actual_length = sizeof(dev->control_state); -			memcpy(dev->control_state, buf + 1, urb->actual_length); -			wake_up(&dev->ep1_wait_queue); +			if (urb->actual_length > sizeof(cdev->control_state)) +				urb->actual_length = sizeof(cdev->control_state); +			memcpy(cdev->control_state, buf + 1, urb->actual_length); +			wake_up(&cdev->ep1_wait_queue);  			break;  		}  #ifdef CONFIG_SND_USB_CAIAQ_INPUT  	case EP1_CMD_READ_ERP:  	case EP1_CMD_READ_ANALOG: -		snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); +		snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length);  #endif  		break;  	} -	dev->ep1_in_urb.actual_length = 0; -	ret = usb_submit_urb(&dev->ep1_in_urb, GFP_ATOMIC); +	cdev->ep1_in_urb.actual_length = 0; +	ret = usb_submit_urb(&cdev->ep1_in_urb, GFP_ATOMIC);  	if (ret < 0) -		log("unable to submit urb. OOM!?\n"); +		dev_err(dev, "unable to submit urb. OOM!?\n");  } -int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, +int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,  			       unsigned char command,  			       const unsigned char *buffer,  			       int len)  {  	int actual_len; -	struct usb_device *usb_dev = dev->chip.dev; +	struct usb_device *usb_dev = cdev->chip.dev;  	if (!usb_dev)  		return -EIO; @@ -215,18 +228,44 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,  		len = EP1_BUFSIZE - 1;  	if (buffer && len > 0) -		memcpy(dev->ep1_out_buf+1, buffer, len); +		memcpy(cdev->ep1_out_buf+1, buffer, len); + +	cdev->ep1_out_buf[0] = command; +	return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), +			   cdev->ep1_out_buf, len+1, &actual_len, 200); +} + +int snd_usb_caiaq_send_command_bank(struct snd_usb_caiaqdev *cdev, +			       unsigned char command, +			       unsigned char bank, +			       const unsigned char *buffer, +			       int len) +{ +	int actual_len; +	struct usb_device *usb_dev = cdev->chip.dev; + +	if (!usb_dev) +		return -EIO; + +	if (len > EP1_BUFSIZE - 2) +		len = EP1_BUFSIZE - 2; + +	if (buffer && len > 0) +		memcpy(cdev->ep1_out_buf+2, buffer, len); + +	cdev->ep1_out_buf[0] = command; +	cdev->ep1_out_buf[1] = bank; -	dev->ep1_out_buf[0] = command;  	return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), -			   dev->ep1_out_buf, len+1, &actual_len, 200); +			   cdev->ep1_out_buf, len+2, &actual_len, 200);  } -int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, +int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev,  		   		    int rate, int depth, int bpp)  {  	int ret;  	char tmp[5]; +	struct device *dev = caiaqdev_to_dev(cdev);  	switch (rate) {  	case 44100:	tmp[0] = SAMPLERATE_44100;   break; @@ -247,49 +286,50 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,  	tmp[3] = bpp >> 8;  	tmp[4] = 1; /* packets per microframe */ -	debug("setting audio params: %d Hz, %d bits, %d bpp\n", +	dev_dbg(dev, "setting audio params: %d Hz, %d bits, %d bpp\n",  		rate, depth, bpp); -	dev->audio_parm_answer = -1; -	ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS, +	cdev->audio_parm_answer = -1; +	ret = snd_usb_caiaq_send_command(cdev, EP1_CMD_AUDIO_PARAMS,  					 tmp, sizeof(tmp));  	if (ret)  		return ret; -	if (!wait_event_timeout(dev->ep1_wait_queue, -	    dev->audio_parm_answer >= 0, HZ)) +	if (!wait_event_timeout(cdev->ep1_wait_queue, +	    cdev->audio_parm_answer >= 0, HZ))  		return -EPIPE; -	if (dev->audio_parm_answer != 1) -		debug("unable to set the device's audio params\n"); +	if (cdev->audio_parm_answer != 1) +		dev_dbg(dev, "unable to set the device's audio params\n");  	else -		dev->bpp = bpp; +		cdev->bpp = bpp; -	return dev->audio_parm_answer == 1 ? 0 : -EINVAL; +	return cdev->audio_parm_answer == 1 ? 0 : -EINVAL;  } -int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev, +int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev,  			       int digital, int analog, int erp)  {  	char tmp[3] = { digital, analog, erp }; -	return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, +	return snd_usb_caiaq_send_command(cdev, EP1_CMD_AUTO_MSG,  					  tmp, sizeof(tmp));  } -static void __devinit setup_card(struct snd_usb_caiaqdev *dev) +static void setup_card(struct snd_usb_caiaqdev *cdev)  {  	int ret;  	char val[4]; +	struct device *dev = caiaqdev_to_dev(cdev);  	/* device-specific startup specials */ -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):  		/* RigKontrol2 - display centered dash ('-') */  		val[0] = 0x00;  		val[1] = 0x00;  		val[2] = 0x01; -		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3); +		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 3);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):  		/* RigKontrol2 - display two centered dashes ('--') */ @@ -297,69 +337,69 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)  		val[1] = 0x40;  		val[2] = 0x40;  		val[3] = 0x00; -		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4); +		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 4);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):  		/* Audio Kontrol 1 - make USB-LED stop blinking */  		val[0] = 0x00; -		snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1); +		snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 1);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):  		/* Audio 8 DJ - trigger read of current settings */ -		dev->control_state[0] = 0xff; -		snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0); -		snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0); +		cdev->control_state[0] = 0xff; +		snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 0); +		snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0); -		if (!wait_event_timeout(dev->ep1_wait_queue, -					dev->control_state[0] != 0xff, HZ)) +		if (!wait_event_timeout(cdev->ep1_wait_queue, +					cdev->control_state[0] != 0xff, HZ))  			return;  		/* fix up some defaults */ -		if ((dev->control_state[1] != 2) || -		    (dev->control_state[2] != 3) || -		    (dev->control_state[4] != 2)) { -			dev->control_state[1] = 2; -			dev->control_state[2] = 3; -			dev->control_state[4] = 2; -			snd_usb_caiaq_send_command(dev, -				EP1_CMD_WRITE_IO, dev->control_state, 6); +		if ((cdev->control_state[1] != 2) || +		    (cdev->control_state[2] != 3) || +		    (cdev->control_state[4] != 2)) { +			cdev->control_state[1] = 2; +			cdev->control_state[2] = 3; +			cdev->control_state[4] = 2; +			snd_usb_caiaq_send_command(cdev, +				EP1_CMD_WRITE_IO, cdev->control_state, 6);  		}  		break;  	} -	if (dev->spec.num_analog_audio_out + -	    dev->spec.num_analog_audio_in + -	    dev->spec.num_digital_audio_out + -	    dev->spec.num_digital_audio_in > 0) { -		ret = snd_usb_caiaq_audio_init(dev); +	if (cdev->spec.num_analog_audio_out + +	    cdev->spec.num_analog_audio_in + +	    cdev->spec.num_digital_audio_out + +	    cdev->spec.num_digital_audio_in > 0) { +		ret = snd_usb_caiaq_audio_init(cdev);  		if (ret < 0) -			log("Unable to set up audio system (ret=%d)\n", ret); +			dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret);  	} -	if (dev->spec.num_midi_in + -	    dev->spec.num_midi_out > 0) { -		ret = snd_usb_caiaq_midi_init(dev); +	if (cdev->spec.num_midi_in + +	    cdev->spec.num_midi_out > 0) { +		ret = snd_usb_caiaq_midi_init(cdev);  		if (ret < 0) -			log("Unable to set up MIDI system (ret=%d)\n", ret); +			dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret);  	}  #ifdef CONFIG_SND_USB_CAIAQ_INPUT -	ret = snd_usb_caiaq_input_init(dev); +	ret = snd_usb_caiaq_input_init(cdev);  	if (ret < 0) -		log("Unable to set up input system (ret=%d)\n", ret); +		dev_err(dev, "Unable to set up input system (ret=%d)\n", ret);  #endif  	/* finally, register the card and all its sub-instances */ -	ret = snd_card_register(dev->chip.card); +	ret = snd_card_register(cdev->chip.card);  	if (ret < 0) { -		log("snd_card_register() returned %d\n", ret); -		snd_card_free(dev->chip.card); +		dev_err(dev, "snd_card_register() returned %d\n", ret); +		snd_card_free(cdev->chip.card);  	} -	ret = snd_usb_caiaq_control_init(dev); +	ret = snd_usb_caiaq_control_init(cdev);  	if (ret < 0) -		log("Unable to set up control system (ret=%d)\n", ret); +		dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);  }  static int create_card(struct usb_device *usb_dev, @@ -369,79 +409,80 @@ static int create_card(struct usb_device *usb_dev,  	int devnum;  	int err;  	struct snd_card *card; -	struct snd_usb_caiaqdev *dev; +	struct snd_usb_caiaqdev *cdev;  	for (devnum = 0; devnum < SNDRV_CARDS; devnum++) -		if (enable[devnum] && !snd_card_used[devnum]) +		if (enable[devnum])  			break;  	if (devnum >= SNDRV_CARDS)  		return -ENODEV; -	err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, -			      sizeof(struct snd_usb_caiaqdev), &card); +	err = snd_card_new(&intf->dev, +			   index[devnum], id[devnum], THIS_MODULE, +			   sizeof(struct snd_usb_caiaqdev), &card);  	if (err < 0)  		return err; -	dev = caiaqdev(card); -	dev->chip.dev = usb_dev; -	dev->chip.card = card; -	dev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), +	cdev = caiaqdev(card); +	cdev->chip.dev = usb_dev; +	cdev->chip.card = card; +	cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),  				  le16_to_cpu(usb_dev->descriptor.idProduct)); -	spin_lock_init(&dev->spinlock); -	snd_card_set_dev(card, &intf->dev); +	spin_lock_init(&cdev->spinlock);  	*cardp = card;  	return 0;  } -static int __devinit init_card(struct snd_usb_caiaqdev *dev) +static int init_card(struct snd_usb_caiaqdev *cdev)  {  	char *c, usbpath[32]; -	struct usb_device *usb_dev = dev->chip.dev; -	struct snd_card *card = dev->chip.card; +	struct usb_device *usb_dev = cdev->chip.dev; +	struct snd_card *card = cdev->chip.card; +	struct device *dev = caiaqdev_to_dev(cdev);  	int err, len;  	if (usb_set_interface(usb_dev, 0, 1) != 0) { -		log("can't set alt interface.\n"); +		dev_err(dev, "can't set alt interface.\n");  		return -EIO;  	} -	usb_init_urb(&dev->ep1_in_urb); -	usb_init_urb(&dev->midi_out_urb); +	usb_init_urb(&cdev->ep1_in_urb); +	usb_init_urb(&cdev->midi_out_urb); -	usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, +	usb_fill_bulk_urb(&cdev->ep1_in_urb, usb_dev,  			  usb_rcvbulkpipe(usb_dev, 0x1), -			  dev->ep1_in_buf, EP1_BUFSIZE, -			  usb_ep1_command_reply_dispatch, dev); +			  cdev->ep1_in_buf, EP1_BUFSIZE, +			  usb_ep1_command_reply_dispatch, cdev); -	usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, +	usb_fill_bulk_urb(&cdev->midi_out_urb, usb_dev,  			  usb_sndbulkpipe(usb_dev, 0x1), -			  dev->midi_out_buf, EP1_BUFSIZE, -			  snd_usb_caiaq_midi_output_done, dev); +			  cdev->midi_out_buf, EP1_BUFSIZE, +			  snd_usb_caiaq_midi_output_done, cdev); -	init_waitqueue_head(&dev->ep1_wait_queue); -	init_waitqueue_head(&dev->prepare_wait_queue); +	init_waitqueue_head(&cdev->ep1_wait_queue); +	init_waitqueue_head(&cdev->prepare_wait_queue); -	if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) +	if (usb_submit_urb(&cdev->ep1_in_urb, GFP_KERNEL) != 0)  		return -EIO; -	err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); +	err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);  	if (err)  		return err; -	if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ)) +	if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ))  		return -ENODEV;  	usb_string(usb_dev, usb_dev->descriptor.iManufacturer, -		   dev->vendor_name, CAIAQ_USB_STR_LEN); +		   cdev->vendor_name, CAIAQ_USB_STR_LEN);  	usb_string(usb_dev, usb_dev->descriptor.iProduct, -		   dev->product_name, CAIAQ_USB_STR_LEN); +		   cdev->product_name, CAIAQ_USB_STR_LEN);  	strlcpy(card->driver, MODNAME, sizeof(card->driver)); -	strlcpy(card->shortname, dev->product_name, sizeof(card->shortname)); -	strlcpy(card->mixername, dev->product_name, sizeof(card->mixername)); +	strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname)); +	strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername));  	/* if the id was not passed as module option, fill it with a shortened  	 * version of the product string which does not contain any @@ -461,22 +502,21 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev)  	}  	usb_make_path(usb_dev, usbpath, sizeof(usbpath)); -	snprintf(card->longname, sizeof(card->longname), -		       "%s %s (%s)", -		       dev->vendor_name, dev->product_name, usbpath); +	snprintf(card->longname, sizeof(card->longname), "%s %s (%s)", +		       cdev->vendor_name, cdev->product_name, usbpath); -	setup_card(dev); +	setup_card(cdev);  	return 0;  } -static int __devinit snd_probe(struct usb_interface *intf, +static int snd_probe(struct usb_interface *intf,  		     const struct usb_device_id *id)  {  	int ret; -	struct snd_card *card; -	struct usb_device *device = interface_to_usbdev(intf); +	struct snd_card *card = NULL; +	struct usb_device *usb_dev = interface_to_usbdev(intf); -	ret = create_card(device, intf, &card); +	ret = create_card(usb_dev, intf, &card);  	if (ret < 0)  		return ret; @@ -484,7 +524,7 @@ static int __devinit snd_probe(struct usb_interface *intf,  	usb_set_intfdata(intf, card);  	ret = init_card(caiaqdev(card));  	if (ret < 0) { -		log("unable to init card! (ret=%d)\n", ret); +		dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret);  		snd_card_free(card);  		return ret;  	} @@ -494,24 +534,25 @@ static int __devinit snd_probe(struct usb_interface *intf,  static void snd_disconnect(struct usb_interface *intf)  { -	struct snd_usb_caiaqdev *dev;  	struct snd_card *card = usb_get_intfdata(intf); - -	debug("%s(%p)\n", __func__, intf); +	struct device *dev = intf->usb_dev; +	struct snd_usb_caiaqdev *cdev;  	if (!card)  		return; -	dev = caiaqdev(card); +	cdev = caiaqdev(card); +	dev_dbg(dev, "%s(%p)\n", __func__, intf); +  	snd_card_disconnect(card);  #ifdef CONFIG_SND_USB_CAIAQ_INPUT -	snd_usb_caiaq_input_free(dev); +	snd_usb_caiaq_input_free(cdev);  #endif -	snd_usb_caiaq_audio_free(dev); +	snd_usb_caiaq_audio_free(cdev); -	usb_kill_urb(&dev->ep1_in_urb); -	usb_kill_urb(&dev->midi_out_urb); +	usb_kill_urb(&cdev->ep1_in_urb); +	usb_kill_urb(&cdev->midi_out_urb);  	snd_card_free(card);  	usb_reset_device(interface_to_usbdev(intf)); @@ -526,16 +567,4 @@ static struct usb_driver snd_usb_driver = {  	.id_table 	= snd_usb_id_table,  }; -static int __init snd_module_init(void) -{ -	return usb_register(&snd_usb_driver); -} - -static void __exit snd_module_exit(void) -{ -	usb_deregister(&snd_usb_driver); -} - -module_init(snd_module_init) -module_exit(snd_module_exit) - +module_usb_driver(snd_usb_driver); diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index e3d8a3efb35..ab0f7520a99 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -17,22 +17,15 @@  #define USB_PID_GUITARRIGMOBILE		0x0d8d  #define USB_PID_TRAKTORKONTROLX1	0x2305  #define USB_PID_TRAKTORKONTROLS4	0xbaff +#define USB_PID_TRAKTORAUDIO2		0x041d +#define USB_PID_MASCHINECONTROLLER  0x0808  #define EP1_BUFSIZE 64  #define EP4_BUFSIZE 512  #define CAIAQ_USB_STR_LEN 0xff  #define MAX_STREAMS 32 -//#define	SND_USB_CAIAQ_DEBUG -  #define MODNAME "snd-usb-caiaq" -#define log(x...) snd_printk(KERN_WARNING MODNAME" log: " x) - -#ifdef SND_USB_CAIAQ_DEBUG -#define debug(x...) snd_printk(KERN_WARNING MODNAME " debug: " x) -#else -#define debug(x...) do { } while(0) -#endif  #define EP1_CMD_GET_DEVICE_INFO	0x1  #define EP1_CMD_READ_ERP	0x2 @@ -95,6 +88,7 @@ struct snd_usb_caiaqdev {  	int input_panic, output_panic, warned;  	char *audio_in_buf, *audio_out_buf;  	unsigned int samplerates, bpp; +	unsigned long outurb_active_mask;  	struct snd_pcm_substream *sub_playback[MAX_STREAMS];  	struct snd_pcm_substream *sub_capture[MAX_STREAMS]; @@ -121,16 +115,22 @@ struct snd_usb_caiaqdev {  };  struct snd_usb_caiaq_cb_info { -	struct snd_usb_caiaqdev *dev; +	struct snd_usb_caiaqdev *cdev;  	int index;  };  #define caiaqdev(c) ((struct snd_usb_caiaqdev*)(c)->private_data) +#define caiaqdev_to_dev(d)	(d->chip.card->dev) -int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp); -int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp); -int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, +int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev, int rate, int depth, int bbp); +int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *cdev, int digital, int analog, int erp); +int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev, +			       unsigned char command, +			       const unsigned char *buffer, +			       int len); +int snd_usb_caiaq_send_command_bank(struct snd_usb_caiaqdev *cdev,  			       unsigned char command, +			       unsigned char bank,  			       const unsigned char *buffer,  			       int len); diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 4432ef7a70a..4b3fb91deec 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -16,6 +16,7 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  */ +#include <linux/device.h>  #include <linux/gfp.h>  #include <linux/init.h>  #include <linux/usb.h> @@ -30,7 +31,7 @@ static unsigned short keycode_ak1[] =  { KEY_C, KEY_B, KEY_A };  static unsigned short keycode_rk2[] =  { KEY_1, KEY_2, KEY_3, KEY_4,  					 KEY_5, KEY_6, KEY_7 };  static unsigned short keycode_rk3[] =  { KEY_1, KEY_2, KEY_3, KEY_4, -					 KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; +					 KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 };  static unsigned short keycode_kore[] = {  	KEY_FN_F1,      /* "menu"               */ @@ -67,6 +68,61 @@ static unsigned short keycode_kore[] = {  	KEY_BRL_DOT5  }; +#define MASCHINE_BUTTONS   (42) +#define MASCHINE_BUTTON(X) ((X) + BTN_MISC) +#define MASCHINE_PADS      (16) +#define MASCHINE_PAD(X)    ((X) + ABS_PRESSURE) + +static unsigned short keycode_maschine[] = { +	MASCHINE_BUTTON(40), /* mute       */ +	MASCHINE_BUTTON(39), /* solo       */ +	MASCHINE_BUTTON(38), /* select     */ +	MASCHINE_BUTTON(37), /* duplicate  */ +	MASCHINE_BUTTON(36), /* navigate   */ +	MASCHINE_BUTTON(35), /* pad mode   */ +	MASCHINE_BUTTON(34), /* pattern    */ +	MASCHINE_BUTTON(33), /* scene      */ +	KEY_RESERVED, /* spacer */ + +	MASCHINE_BUTTON(30), /* rec        */ +	MASCHINE_BUTTON(31), /* erase      */ +	MASCHINE_BUTTON(32), /* shift      */ +	MASCHINE_BUTTON(28), /* grid       */ +	MASCHINE_BUTTON(27), /* >          */ +	MASCHINE_BUTTON(26), /* <          */ +	MASCHINE_BUTTON(25), /* restart    */ + +	MASCHINE_BUTTON(21), /* E          */ +	MASCHINE_BUTTON(22), /* F          */ +	MASCHINE_BUTTON(23), /* G          */ +	MASCHINE_BUTTON(24), /* H          */ +	MASCHINE_BUTTON(20), /* D          */ +	MASCHINE_BUTTON(19), /* C          */ +	MASCHINE_BUTTON(18), /* B          */ +	MASCHINE_BUTTON(17), /* A          */ + +	MASCHINE_BUTTON(0),  /* control    */ +	MASCHINE_BUTTON(2),  /* browse     */ +	MASCHINE_BUTTON(4),  /* <          */ +	MASCHINE_BUTTON(6),  /* snap       */ +	MASCHINE_BUTTON(7),  /* autowrite  */ +	MASCHINE_BUTTON(5),  /* >          */ +	MASCHINE_BUTTON(3),  /* sampling   */ +	MASCHINE_BUTTON(1),  /* step       */ + +	MASCHINE_BUTTON(15), /* 8 softkeys */ +	MASCHINE_BUTTON(14), +	MASCHINE_BUTTON(13), +	MASCHINE_BUTTON(12), +	MASCHINE_BUTTON(11), +	MASCHINE_BUTTON(10), +	MASCHINE_BUTTON(9), +	MASCHINE_BUTTON(8), + +	MASCHINE_BUTTON(16), /* note repeat */ +	MASCHINE_BUTTON(29)  /* play        */ +}; +  #define KONTROLX1_INPUTS	(40)  #define KONTROLS4_BUTTONS	(12 * 8)  #define KONTROLS4_AXIS		(46) @@ -144,55 +200,55 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)  #undef HIGH_PEAK  #undef LOW_PEAK -static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, +static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *cdev,  					      int axis, const unsigned char *buf,  					      int offset)  { -	input_report_abs(dev->input_dev, axis, +	input_report_abs(cdev->input_dev, axis,  			 (buf[offset * 2] << 8) | buf[offset * 2 + 1]);  } -static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *cdev,  					const unsigned char *buf,  					unsigned int len)  { -	struct input_dev *input_dev = dev->input_dev; +	struct input_dev *input_dev = cdev->input_dev; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): -		snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); -		snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); -		snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); +		snd_caiaq_input_report_abs(cdev, ABS_X, buf, 2); +		snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 0); +		snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 1);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): -		snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); -		snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); -		snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); +		snd_caiaq_input_report_abs(cdev, ABS_X, buf, 0); +		snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 1); +		snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 2);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): -		snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); -		snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); -		snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); -		snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); -		snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); -		snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); -		snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); -		snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); +		snd_caiaq_input_report_abs(cdev, ABS_HAT0X, buf, 4); +		snd_caiaq_input_report_abs(cdev, ABS_HAT0Y, buf, 2); +		snd_caiaq_input_report_abs(cdev, ABS_HAT1X, buf, 6); +		snd_caiaq_input_report_abs(cdev, ABS_HAT1Y, buf, 1); +		snd_caiaq_input_report_abs(cdev, ABS_HAT2X, buf, 7); +		snd_caiaq_input_report_abs(cdev, ABS_HAT2Y, buf, 0); +		snd_caiaq_input_report_abs(cdev, ABS_HAT3X, buf, 5); +		snd_caiaq_input_report_abs(cdev, ABS_HAT3Y, buf, 3);  		break;  	}  	input_sync(input_dev);  } -static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,  				     const char *buf, unsigned int len)  { -	struct input_dev *input_dev = dev->input_dev; +	struct input_dev *input_dev = cdev->input_dev;  	int i; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):  		i = decode_erp(buf[0], buf[1]);  		input_report_abs(input_dev, ABS_X, i); @@ -218,13 +274,36 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,  		input_report_abs(input_dev, ABS_HAT3Y, i);  		input_sync(input_dev);  		break; + +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		/* 4 under the left screen */ +		input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20])); +		input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14])); +		input_report_abs(input_dev, ABS_HAT1X, decode_erp(buf[9],  buf[8])); +		input_report_abs(input_dev, ABS_HAT1Y, decode_erp(buf[3],  buf[2])); + +		/* 4 under the right screen */ +		input_report_abs(input_dev, ABS_HAT2X, decode_erp(buf[19], buf[18])); +		input_report_abs(input_dev, ABS_HAT2Y, decode_erp(buf[13], buf[12])); +		input_report_abs(input_dev, ABS_HAT3X, decode_erp(buf[7],  buf[6])); +		input_report_abs(input_dev, ABS_HAT3Y, decode_erp(buf[1],  buf[0])); + +		/* volume */ +		input_report_abs(input_dev, ABS_RX, decode_erp(buf[17], buf[16])); +		/* tempo */ +		input_report_abs(input_dev, ABS_RY, decode_erp(buf[11], buf[10])); +		/* swing */ +		input_report_abs(input_dev, ABS_RZ, decode_erp(buf[5],  buf[4])); + +		input_sync(input_dev); +		break;  	}  } -static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,  				    unsigned char *buf, unsigned int len)  { -	struct input_dev *input_dev = dev->input_dev; +	struct input_dev *input_dev = cdev->input_dev;  	unsigned short *keycode = input_dev->keycode;  	int i; @@ -239,17 +318,17 @@ 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))); -	switch (dev->chip.usb_id) { +	switch (cdev->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]); +		input_report_abs(cdev->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); +		input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf); +		input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4); +		input_report_abs(cdev->input_dev, ABS_Z, buf[6] & 0xf); +		input_report_abs(cdev->input_dev, ABS_MISC, buf[6] >> 4);  		break;  	} @@ -258,10 +337,12 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,  #define TKS4_MSGBLOCK_SIZE	16 -static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, +static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,  					const unsigned char *buf,  					unsigned int len)  { +	struct device *dev = caiaqdev_to_dev(cdev); +  	while (len) {  		unsigned int i, block_id = (buf[0] << 8) | buf[1]; @@ -269,126 +350,126 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,  		case 0:  			/* buttons */  			for (i = 0; i < KONTROLS4_BUTTONS; i++) -				input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), +				input_report_key(cdev->input_dev, KONTROLS4_BUTTON(i),  						 (buf[4 + (i / 8)] >> (i % 8)) & 1);  			break;  		case 1:  			/* left wheel */ -			input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));  			/* right wheel */ -			input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));  			/* rotary encoders */ -			input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); -			input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); +			input_report_abs(cdev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);  			break;  		case 2:  			/* Volume Fader Channel D */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(0), buf, 1);  			/* Volume Fader Channel B */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(1), buf, 2);  			/* Volume Fader Channel A */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(2), buf, 3);  			/* Volume Fader Channel C */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(3), buf, 4);  			/* Loop Volume */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(4), buf, 6);  			/* Crossfader */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(7), buf, 7);  			break;  		case 3:  			/* Tempo Fader R */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(6), buf, 3);  			/* Tempo Fader L */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(5), buf, 4);  			/* Mic Volume */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(8), buf, 6);  			/* Cue Mix */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(9), buf, 7);  			break;  		case 4:  			/* Wheel distance sensor L */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(10), buf, 1);  			/* Wheel distance sensor R */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(11), buf, 2);  			/* Channel D EQ - Filter */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(12), buf, 3);  			/* Channel D EQ - Low */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(13), buf, 4);  			/* Channel D EQ - Mid */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(14), buf, 5);  			/* Channel D EQ - Hi */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(15), buf, 6);  			/* FX2 - dry/wet */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(16), buf, 7);  			break;  		case 5:  			/* FX2 - 1 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(17), buf, 1);  			/* FX2 - 2 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(18), buf, 2);  			/* FX2 - 3 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(19), buf, 3);  			/* Channel B EQ - Filter */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(20), buf, 4);  			/* Channel B EQ - Low */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(21), buf, 5);  			/* Channel B EQ - Mid */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(22), buf, 6);  			/* Channel B EQ - Hi */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(23), buf, 7);  			break;  		case 6:  			/* Channel A EQ - Filter */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(24), buf, 1);  			/* Channel A EQ - Low */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(25), buf, 2);  			/* Channel A EQ - Mid */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(26), buf, 3);  			/* Channel A EQ - Hi */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(27), buf, 4);  			/* Channel C EQ - Filter */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(28), buf, 5);  			/* Channel C EQ - Low */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(29), buf, 6);  			/* Channel C EQ - Mid */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(30), buf, 7);  			break;  		case 7:  			/* Channel C EQ - Hi */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(31), buf, 1);  			/* FX1 - wet/dry */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(32), buf, 2);  			/* FX1 - 1 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(33), buf, 3);  			/* FX1 - 2 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(34), buf, 4);  			/* FX1 - 3 */ -			snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); +			snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(35), buf, 5);  			break;  		default: -			debug("%s(): bogus block (id %d)\n", +			dev_dbg(dev, "%s(): bogus block (id %d)\n",  				__func__, block_id);  			return;  		} @@ -397,54 +478,82 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,  		buf += TKS4_MSGBLOCK_SIZE;  	} -	input_sync(dev->input_dev); +	input_sync(cdev->input_dev); +} + +#define MASCHINE_MSGBLOCK_SIZE 2 + +static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *cdev, +					const unsigned char *buf, +					unsigned int len) +{ +	unsigned int i, pad_id; +	__le16 *pressure = (__le16 *) buf; + +	for (i = 0; i < MASCHINE_PADS; i++) { +		pad_id = le16_to_cpu(*pressure) >> 12; +		input_report_abs(cdev->input_dev, MASCHINE_PAD(pad_id), +				 le16_to_cpu(*pressure) & 0xfff); +		pressure++; +	} + +	input_sync(cdev->input_dev);  }  static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)  { -	struct snd_usb_caiaqdev *dev = urb->context; +	struct snd_usb_caiaqdev *cdev = urb->context;  	unsigned char *buf = urb->transfer_buffer; +	struct device *dev = &urb->dev->dev;  	int ret; -	if (urb->status || !dev || urb != dev->ep4_in_urb) +	if (urb->status || !cdev || urb != cdev->ep4_in_urb)  		return; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):  		if (urb->actual_length < 24)  			goto requeue;  		if (buf[0] & 0x3) -			snd_caiaq_input_read_io(dev, buf + 1, 7); +			snd_caiaq_input_read_io(cdev, buf + 1, 7);  		if (buf[0] & 0x4) -			snd_caiaq_input_read_analog(dev, buf + 8, 16); +			snd_caiaq_input_read_analog(cdev, buf + 8, 16);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): -		snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); +		snd_usb_caiaq_tks4_dispatch(cdev, buf, urb->actual_length); +		break; + +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE)) +			goto requeue; + +		snd_usb_caiaq_maschine_dispatch(cdev, buf, urb->actual_length);  		break;  	}  requeue: -	dev->ep4_in_urb->actual_length = 0; -	ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC); +	cdev->ep4_in_urb->actual_length = 0; +	ret = usb_submit_urb(cdev->ep4_in_urb, GFP_ATOMIC);  	if (ret < 0) -		log("unable to submit urb. OOM!?\n"); +		dev_err(dev, "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); +	struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev); -	if (!dev) +	if (!cdev)  		return -EINVAL; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): -		if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		if (usb_submit_urb(cdev->ep4_in_urb, GFP_KERNEL) != 0)  			return -EIO;  		break;  	} @@ -454,42 +563,43 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)  static void snd_usb_caiaq_input_close(struct input_dev *idev)  { -	struct snd_usb_caiaqdev *dev = input_get_drvdata(idev); +	struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev); -	if (!dev) +	if (!cdev)  		return; -	switch (dev->chip.usb_id) { +	switch (cdev->chip.usb_id) {  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): -		usb_kill_urb(dev->ep4_in_urb); +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		usb_kill_urb(cdev->ep4_in_urb);  		break;  	}  } -void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, +void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev,  				  char *buf,  				  unsigned int len)  { -	if (!dev->input_dev || len < 1) +	if (!cdev->input_dev || len < 1)  		return;  	switch (buf[0]) {  	case EP1_CMD_READ_ANALOG: -		snd_caiaq_input_read_analog(dev, buf + 1, len - 1); +		snd_caiaq_input_read_analog(cdev, buf + 1, len - 1);  		break;  	case EP1_CMD_READ_ERP: -		snd_caiaq_input_read_erp(dev, buf + 1, len - 1); +		snd_caiaq_input_read_erp(cdev, buf + 1, len - 1);  		break;  	case EP1_CMD_READ_IO: -		snd_caiaq_input_read_io(dev, buf + 1, len - 1); +		snd_caiaq_input_read_io(cdev, buf + 1, len - 1);  		break;  	}  } -int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)  { -	struct usb_device *usb_dev = dev->chip.dev; +	struct usb_device *usb_dev = cdev->chip.dev;  	struct input_dev *input;  	int i, ret = 0; @@ -497,49 +607,49 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  	if (!input)  		return -ENOMEM; -	usb_make_path(usb_dev, dev->phys, sizeof(dev->phys)); -	strlcat(dev->phys, "/input0", sizeof(dev->phys)); +	usb_make_path(usb_dev, cdev->phys, sizeof(cdev->phys)); +	strlcat(cdev->phys, "/input0", sizeof(cdev->phys)); -	input->name = dev->product_name; -	input->phys = dev->phys; +	input->name = cdev->product_name; +	input->phys = cdev->phys;  	usb_to_input_id(usb_dev, &input->id);  	input->dev.parent = &usb_dev->dev; -	input_set_drvdata(input, dev); +	input_set_drvdata(input, cdev); -	switch (dev->chip.usb_id) { +	switch (cdev->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) |  			BIT_MASK(ABS_Z); -		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2)); -		memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2)); +		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk2)); +		memcpy(cdev->keycode, keycode_rk2, sizeof(keycode_rk2));  		input->keycodemax = ARRAY_SIZE(keycode_rk2);  		input_set_abs_params(input, ABS_X, 0, 4096, 0, 10);  		input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);  		input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); -		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):  		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  		input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |  			BIT_MASK(ABS_Z); -		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3)); -		memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3)); +		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_rk3)); +		memcpy(cdev->keycode, keycode_rk3, sizeof(keycode_rk3));  		input->keycodemax = ARRAY_SIZE(keycode_rk3);  		input_set_abs_params(input, ABS_X, 0, 1024, 0, 10);  		input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10);  		input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); -		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 0);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):  		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  		input->absbit[0] = BIT_MASK(ABS_X); -		BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1)); -		memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1)); +		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_ak1)); +		memcpy(cdev->keycode, keycode_ak1, sizeof(keycode_ak1));  		input->keycodemax = ARRAY_SIZE(keycode_ak1);  		input_set_abs_params(input, ABS_X, 0, 999, 0, 10); -		snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); +		snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 5);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): @@ -551,8 +661,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  				   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) < sizeof(keycode_kore)); -		memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore)); +		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_kore)); +		memcpy(cdev->keycode, keycode_kore, sizeof(keycode_kore));  		input->keycodemax = ARRAY_SIZE(keycode_kore);  		input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);  		input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10); @@ -566,7 +676,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  		input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);  		input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);  		input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); -		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):  		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); @@ -577,9 +687,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  				   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); +		BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLX1_INPUTS);  		for (i = 0; i < KONTROLX1_INPUTS; i++) -			dev->keycode[i] = BTN_MISC + i; +			cdev->keycode[i] = BTN_MISC + i;  		input->keycodemax = KONTROLX1_INPUTS;  		/* analog potentiometers */ @@ -598,26 +708,26 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  		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) { +		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!cdev->ep4_in_urb) {  			ret = -ENOMEM;  			goto exit_free_idev;  		} -		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, +		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,  				  usb_rcvbulkpipe(usb_dev, 0x4), -				  dev->ep4_in_buf, EP4_BUFSIZE, -				  snd_usb_caiaq_ep4_reply_dispatch, dev); +				  cdev->ep4_in_buf, EP4_BUFSIZE, +				  snd_usb_caiaq_ep4_reply_dispatch, cdev); -		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);  		break;  	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):  		input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -		BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); +		BUILD_BUG_ON(sizeof(cdev->keycode) < KONTROLS4_BUTTONS);  		for (i = 0; i < KONTROLS4_BUTTONS; i++) -			dev->keycode[i] = KONTROLS4_BUTTON(i); +			cdev->keycode[i] = KONTROLS4_BUTTON(i);  		input->keycodemax = KONTROLS4_BUTTONS;  		for (i = 0; i < KONTROLS4_AXIS; i++) { @@ -637,19 +747,63 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  		for (i = 0; i < 9; i++)  			input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); -		dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); -		if (!dev->ep4_in_urb) { +		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!cdev->ep4_in_urb) {  			ret = -ENOMEM;  			goto exit_free_idev;  		} -		usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, +		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,  				  usb_rcvbulkpipe(usb_dev, 0x4), -				  dev->ep4_in_buf, EP4_BUFSIZE, -				  snd_usb_caiaq_ep4_reply_dispatch, dev); +				  cdev->ep4_in_buf, EP4_BUFSIZE, +				  snd_usb_caiaq_ep4_reply_dispatch, cdev); + +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5); + +		break; -		snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); +	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): +		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_RX) | BIT_MASK(ABS_RY) | +			BIT_MASK(ABS_RZ); + +		BUILD_BUG_ON(sizeof(cdev->keycode) < sizeof(keycode_maschine)); +		memcpy(cdev->keycode, keycode_maschine, sizeof(keycode_maschine)); +		input->keycodemax = ARRAY_SIZE(keycode_maschine); + +		for (i = 0; i < MASCHINE_PADS; i++) { +			input->absbit[0] |= MASCHINE_PAD(i); +			input_set_abs_params(input, MASCHINE_PAD(i), 0, 0xfff, 5, 10); +		} +		input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_RX, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_RY, 0, 999, 0, 10); +		input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10); + +		cdev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!cdev->ep4_in_urb) { +			ret = -ENOMEM; +			goto exit_free_idev; +		} + +		usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev, +				  usb_rcvbulkpipe(usb_dev, 0x4), +				  cdev->ep4_in_buf, EP4_BUFSIZE, +				  snd_usb_caiaq_ep4_reply_dispatch, cdev); + +		snd_usb_caiaq_set_auto_msg(cdev, 1, 10, 5);  		break;  	default: @@ -659,33 +813,34 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)  	input->open = snd_usb_caiaq_input_open;  	input->close = snd_usb_caiaq_input_close; -	input->keycode = dev->keycode; +	input->keycode = cdev->keycode;  	input->keycodesize = sizeof(unsigned short);  	for (i = 0; i < input->keycodemax; i++) -		__set_bit(dev->keycode[i], input->keybit); +		__set_bit(cdev->keycode[i], input->keybit); + +	cdev->input_dev = input;  	ret = input_register_device(input);  	if (ret < 0)  		goto exit_free_idev; -	dev->input_dev = input;  	return 0;  exit_free_idev:  	input_free_device(input); +	cdev->input_dev = NULL;  	return ret;  } -void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)  { -	if (!dev || !dev->input_dev) +	if (!cdev || !cdev->input_dev)  		return; -	usb_kill_urb(dev->ep4_in_urb); -	usb_free_urb(dev->ep4_in_urb); -	dev->ep4_in_urb = NULL; +	usb_kill_urb(cdev->ep4_in_urb); +	usb_free_urb(cdev->ep4_in_urb); +	cdev->ep4_in_urb = NULL; -	input_unregister_device(dev->input_dev); -	dev->input_dev = NULL; +	input_unregister_device(cdev->input_dev); +	cdev->input_dev = NULL;  } - diff --git a/sound/usb/caiaq/input.h b/sound/usb/caiaq/input.h index ced53557786..6014e2713a6 100644 --- a/sound/usb/caiaq/input.h +++ b/sound/usb/caiaq/input.h @@ -1,8 +1,8 @@  #ifndef CAIAQ_INPUT_H  #define CAIAQ_INPUT_H -void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, char *buf, unsigned int len); -int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev); -void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev); +void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len); +int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev);  #endif diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c index 2f218c77fff..2d7588461b3 100644 --- a/sound/usb/caiaq/midi.c +++ b/sound/usb/caiaq/midi.c @@ -16,6 +16,7 @@   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA  */ +#include <linux/device.h>  #include <linux/usb.h>  #include <linux/gfp.h>  #include <sound/rawmidi.h> @@ -37,12 +38,12 @@ static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substrea  static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)  { -	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; +	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data; -	if (!dev) +	if (!cdev)  		return; -	dev->midi_receive_substream = up ? substream : NULL; +	cdev->midi_receive_substream = up ? substream : NULL;  } @@ -53,49 +54,50 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea  static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)  { -	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; -	if (dev->midi_out_active) { -		usb_kill_urb(&dev->midi_out_urb); -		dev->midi_out_active = 0; +	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data; +	if (cdev->midi_out_active) { +		usb_kill_urb(&cdev->midi_out_urb); +		cdev->midi_out_active = 0;  	}  	return 0;  } -static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, +static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,  				    struct snd_rawmidi_substream *substream)  {  	int len, ret; +	struct device *dev = caiaqdev_to_dev(cdev); -	dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; -	dev->midi_out_buf[1] = 0; /* port */ -	len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, +	cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; +	cdev->midi_out_buf[1] = 0; /* port */ +	len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,  				   EP1_BUFSIZE - 3);  	if (len <= 0)  		return; -	dev->midi_out_buf[2] = len; -	dev->midi_out_urb.transfer_buffer_length = len+3; +	cdev->midi_out_buf[2] = len; +	cdev->midi_out_urb.transfer_buffer_length = len+3; -	ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); +	ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);  	if (ret < 0) -		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," -		    "ret=%d, len=%d\n", -		    substream, ret, len); +		dev_err(dev, +			"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," +			"ret=%d, len=%d\n", substream, ret, len);  	else -		dev->midi_out_active = 1; +		cdev->midi_out_active = 1;  }  static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)  { -	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; +	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;  	if (up) { -		dev->midi_out_substream = substream; -		if (!dev->midi_out_active) -			snd_usb_caiaq_midi_send(dev, substream); +		cdev->midi_out_substream = substream; +		if (!cdev->midi_out_active) +			snd_usb_caiaq_midi_send(cdev, substream);  	} else { -		dev->midi_out_substream = NULL; +		cdev->midi_out_substream = NULL;  	}  } @@ -114,13 +116,13 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =  	.trigger =      snd_usb_caiaq_midi_input_trigger,  }; -void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, +void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,  				     int port, const char *buf, int len)  { -	if (!dev->midi_receive_substream) +	if (!cdev->midi_receive_substream)  		return; -	snd_rawmidi_receive(dev->midi_receive_substream, buf, len); +	snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);  }  int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) @@ -136,7 +138,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)  	if (ret < 0)  		return ret; -	strcpy(rmidi->name, device->product_name); +	strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));  	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;  	rmidi->private_data = device; @@ -160,15 +162,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)  void snd_usb_caiaq_midi_output_done(struct urb* urb)  { -	struct snd_usb_caiaqdev *dev = urb->context; +	struct snd_usb_caiaqdev *cdev = urb->context; -	dev->midi_out_active = 0; +	cdev->midi_out_active = 0;  	if (urb->status != 0)  		return; -	if (!dev->midi_out_substream) +	if (!cdev->midi_out_substream)  		return; -	snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); +	snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);  } - diff --git a/sound/usb/caiaq/midi.h b/sound/usb/caiaq/midi.h index 380f984babc..60bf3442b28 100644 --- a/sound/usb/caiaq/midi.h +++ b/sound/usb/caiaq/midi.h @@ -1,8 +1,9 @@  #ifndef CAIAQ_MIDI_H  #define CAIAQ_MIDI_H -int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev); -void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len); +int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev, +				     int port, const char *buf, int len);  void snd_usb_caiaq_midi_output_done(struct urb *urb);  #endif /* CAIAQ_MIDI_H */ diff --git a/sound/usb/card.c b/sound/usb/card.c index 800f7cb4f25..a09e5f3519e 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -25,9 +25,6 @@   *   *  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 @@ -41,12 +38,15 @@  #include <linux/list.h>  #include <linux/slab.h>  #include <linux/string.h> +#include <linux/ctype.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 <linux/module.h> +#include <sound/control.h>  #include <sound/core.h>  #include <sound/info.h>  #include <sound/pcm.h> @@ -63,8 +63,9 @@  #include "helper.h"  #include "debug.h"  #include "pcm.h" -#include "urb.h"  #include "format.h" +#include "power.h" +#include "stream.h"  MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");  MODULE_DESCRIPTION("USB Audio"); @@ -74,14 +75,13 @@ 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 */ +static bool 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; +static bool ignore_ctl_error; +static bool autoclock = true;  module_param_array(index, int, NULL, 0444);  MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -93,15 +93,13 @@ 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."); +module_param(autoclock, bool, 0444); +MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes).");  /*   * we keep the snd_usb_audio_t instances by ourselves for merging @@ -127,8 +125,9 @@ static void snd_usb_stream_disconnect(struct list_head *head)  		subs = &as->substream[idx];  		if (!subs->num_formats)  			continue; -		snd_usb_release_substream_urbs(subs, 1);  		subs->interface = -1; +		subs->data_endpoint = NULL; +		subs->sync_endpoint = NULL;  	}  } @@ -140,27 +139,46 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int  	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); +		dev_err(&dev->dev, "%u:%d : does not exist\n", +			ctrlif, interface);  		return -EINVAL;  	} +	alts = &iface->altsetting[0]; +	altsd = get_iface_desc(alts); + +	/* +	 * Android with both accessory and audio interfaces enabled gets the +	 * interface numbers wrong. +	 */ +	if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) || +	     chip->usb_id == USB_ID(0x18d1, 0x2d05)) && +	    interface == 0 && +	    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && +	    altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) { +		interface = 2; +		iface = usb_ifnum_to_if(dev, interface); +		if (!iface) +			return -EINVAL; +		alts = &iface->altsetting[0]; +		altsd = get_iface_desc(alts); +	} +  	if (usb_interface_claimed(iface)) { -		snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", -						dev->devnum, ctrlif, interface); +		dev_dbg(&dev->dev, "%d:%d: skipping, already claimed\n", +			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); +			dev_err(&dev->dev, +				"%u:%d: cannot create sequencer device\n", +				ctrlif, interface);  			return -EINVAL;  		}  		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); @@ -171,18 +189,19 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int  	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); +		dev_dbg(&dev->dev, +			"%u:%d: skipping non-supported interface %d\n", +			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"); +		dev_err(&dev->dev, "low speed audio streaming not supported\n");  		return -EINVAL;  	} -	if (! snd_usb_parse_audio_endpoints(chip, interface)) { +	if (! snd_usb_parse_audio_interface(chip, interface)) {  		usb_set_interface(dev, interface, 0); /* reset the current interface */  		usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);  		return -EINVAL; @@ -211,26 +230,27 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)  	protocol = altsd->bInterfaceProtocol;  	if (!control_header) { -		snd_printk(KERN_ERR "cannot find UAC_HEADER\n"); +		dev_err(&dev->dev, "cannot find UAC_HEADER\n");  		return -EINVAL;  	}  	switch (protocol) {  	default: -		snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n", -			    protocol); +		dev_warn(&dev->dev, +			 "unknown interface protocol %#02x, assuming v1\n", +			 protocol);  		/* fall through */  	case UAC_VERSION_1: {  		struct uac1_ac_header_descriptor *h1 = control_header;  		if (!h1->bInCollection) { -			snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); +			dev_info(&dev->dev, "skipping empty audio interface (v1)\n");  			return -EINVAL;  		}  		if (h1->bLength < sizeof(*h1) + h1->bInCollection) { -			snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n"); +			dev_err(&dev->dev, "invalid UAC_HEADER (v1)\n");  			return -EINVAL;  		} @@ -245,7 +265,22 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)  			usb_ifnum_to_if(dev, ctrlif)->intf_assoc;  		if (!assoc) { -			snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); +			/* +			 * Firmware writers cannot count to three.  So to find +			 * the IAD on the NuForce UDH-100, also check the next +			 * interface. +			 */ +			struct usb_interface *iface = +				usb_ifnum_to_if(dev, ctrlif + 1); +			if (iface && +			    iface->intf_assoc && +			    iface->intf_assoc->bFunctionClass == USB_CLASS_AUDIO && +			    iface->intf_assoc->bFunctionProtocol == UAC_VERSION_2) +				assoc = iface->intf_assoc; +		} + +		if (!assoc) { +			dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");  			return -EINVAL;  		} @@ -272,6 +307,12 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)  static int snd_usb_audio_free(struct snd_usb_audio *chip)  { +	struct list_head *p, *n; + +	list_for_each_safe(p, n, &chip->ep_list) +		snd_usb_endpoint_free(p); + +	mutex_destroy(&chip->mutex);  	kfree(chip);  	return 0;  } @@ -282,11 +323,21 @@ static int snd_usb_audio_dev_free(struct snd_device *device)  	return snd_usb_audio_free(chip);  } +static void remove_trailing_spaces(char *str) +{ +	char *p; + +	if (!*str) +		return; +	for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--) +		*p = 0; +}  /*   * create a chip instance and set its names.   */ -static int snd_usb_audio_create(struct usb_device *dev, int idx, +static int snd_usb_audio_create(struct usb_interface *intf, +				struct usb_device *dev, int idx,  				const struct snd_usb_audio_quirk *quirk,  				struct snd_usb_audio **rchip)  { @@ -304,16 +355,18 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,  	case USB_SPEED_LOW:  	case USB_SPEED_FULL:  	case USB_SPEED_HIGH: +	case USB_SPEED_WIRELESS:  	case USB_SPEED_SUPER:  		break;  	default: -		snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); +		dev_err(&dev->dev, "unknown device speed %d\n", snd_usb_get_speed(dev));  		return -ENXIO;  	} -	err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card); +	err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, +			   0, &card);  	if (err < 0) { -		snd_printk(KERN_ERR "cannot create card instance %d\n", idx); +		dev_err(&dev->dev, "cannot create card instance %d\n", idx);  		return err;  	} @@ -323,16 +376,19 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,  		return -ENOMEM;  	} +	mutex_init(&chip->mutex); +	init_rwsem(&chip->shutdown_rwsem);  	chip->index = idx;  	chip->dev = dev;  	chip->card = card;  	chip->setup = device_setup[idx]; -	chip->nrpacks = nrpacks; -	chip->async_unlink = async_unlink; +	chip->autoclock = autoclock; +	chip->probing = 1;  	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->ep_list);  	INIT_LIST_HEAD(&chip->midi_list);  	INIT_LIST_HEAD(&chip->mixer_list); @@ -348,7 +404,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,  	snd_component_add(card, component);  	/* retrieve the device string as shortname */ -	if (quirk && quirk->product_name) { +	if (quirk && quirk->product_name && *quirk->product_name) {  		strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname));  	} else {  		if (!dev->descriptor.iProduct || @@ -360,9 +416,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,  				USB_ID_PRODUCT(chip->usb_id));  		}  	} +	remove_trailing_spaces(card->shortname);  	/* retrieve the vendor and device strings as longname */ -	if (quirk && quirk->vendor_name) { +	if (quirk && quirk->vendor_name && *quirk->vendor_name) {  		len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname));  	} else {  		if (dev->descriptor.iManufacturer) @@ -372,8 +429,11 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,  			len = 0;  		/* we don't really care if there isn't any vendor string */  	} -	if (len > 0) -		strlcat(card->longname, " ", sizeof(card->longname)); +	if (len > 0) { +		remove_trailing_spaces(card->longname); +		if (*card->longname) +			strlcat(card->longname, " ", sizeof(card->longname)); +	}  	strlcat(card->longname, card->shortname, sizeof(card->longname)); @@ -415,9 +475,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,   * 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) +static struct snd_usb_audio * +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; @@ -446,10 +507,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev,  	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"); +				dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");  				goto __error;  			}  			chip = usb_chip[i]; +			chip->probing = 1;  			break;  		}  	} @@ -461,26 +523,19 @@ static void *snd_usb_audio_probe(struct usb_device *dev,  			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) { +				if (snd_usb_audio_create(intf, dev, i, quirk, +							 &chip) < 0) {  					goto __error;  				} -				snd_card_set_dev(chip->card, &intf->dev); +				chip->pm_intf = intf;  				break;  			}  		if (!chip) { -			printk(KERN_ERR "no available usb audio device\n"); +			dev_err(&dev->dev, "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; -	} -  	/*  	 * For devices with more than one control interface, we assume the  	 * first contains the audio controls. We might need a more specific @@ -489,6 +544,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev,  	if (!chip->ctrl_intf)  		chip->ctrl_intf = alts; +	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 || @@ -504,12 +567,16 @@ static void *snd_usb_audio_probe(struct usb_device *dev,  	usb_chip[chip->index] = chip;  	chip->num_interfaces++; +	chip->probing = 0;  	mutex_unlock(®ister_mutex);  	return chip;   __error: -	if (chip && !chip->num_interfaces) -		snd_card_free(chip->card); +	if (chip) { +		if (!chip->num_interfaces) +			snd_card_free(chip->card); +		chip->probing = 0; +	}  	mutex_unlock(®ister_mutex);   __err_val:  	return NULL; @@ -519,26 +586,34 @@ static void *snd_usb_audio_probe(struct usb_device *dev,   * 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) +static void snd_usb_audio_disconnect(struct usb_device *dev, +				     struct snd_usb_audio *chip)  { -	struct snd_usb_audio *chip;  	struct snd_card *card;  	struct list_head *p; -	if (ptr == (void *)-1L) +	if (chip == (void *)-1L)  		return; -	chip = ptr;  	card = chip->card; -	mutex_lock(®ister_mutex); +	down_write(&chip->shutdown_rwsem);  	chip->shutdown = 1; +	up_write(&chip->shutdown_rwsem); + +	mutex_lock(®ister_mutex);  	chip->num_interfaces--;  	if (chip->num_interfaces <= 0) { +		struct snd_usb_endpoint *ep; +  		snd_card_disconnect(card);  		/* release the pcm resources */  		list_for_each(p, &chip->pcm_list) {  			snd_usb_stream_disconnect(p);  		} +		/* release the endpoint resources */ +		list_for_each_entry(ep, &chip->ep_list, list) { +			snd_usb_endpoint_release(ep); +		}  		/* release the midi resources */  		list_for_each(p, &chip->midi_list) {  			snd_usbmidi_disconnect(p); @@ -561,7 +636,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)  static int usb_audio_probe(struct usb_interface *intf,  			   const struct usb_device_id *id)  { -	void *chip; +	struct snd_usb_audio *chip;  	chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);  	if (chip) {  		usb_set_intfdata(intf, chip); @@ -577,46 +652,107 @@ static void usb_audio_disconnect(struct usb_interface *intf)  }  #ifdef CONFIG_PM + +int snd_usb_autoresume(struct snd_usb_audio *chip) +{ +	int err = -ENODEV; + +	down_read(&chip->shutdown_rwsem); +	if (chip->probing && chip->in_pm) +		err = 0; +	else if (!chip->shutdown) +		err = usb_autopm_get_interface(chip->pm_intf); +	up_read(&chip->shutdown_rwsem); + +	return err; +} + +void snd_usb_autosuspend(struct snd_usb_audio *chip) +{ +	down_read(&chip->shutdown_rwsem); +	if (!chip->shutdown && !chip->probing && !chip->in_pm) +		usb_autopm_put_interface(chip->pm_intf); +	up_read(&chip->shutdown_rwsem); +} +  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; +	struct usb_mixer_interface *mixer;  	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); +	if (!PMSG_IS_AUTO(message)) { +		snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); +		if (!chip->num_suspended_intf++) { +			list_for_each_entry(as, &chip->pcm_list, list) { +				snd_pcm_suspend_all(as->pcm); +				as->substream[0].need_setup_ep = +					as->substream[1].need_setup_ep = true; +			}  		} +	} else { +		/* +		 * otherwise we keep the rest of the system in the dark +		 * to keep this transparent +		 */ +		if (!chip->num_suspended_intf++) +			chip->autosuspended = 1;  	} +	if (chip->num_suspended_intf == 1) +		list_for_each_entry(mixer, &chip->mixer_list, list) +			snd_usb_mixer_suspend(mixer); +  	return 0;  } -static int usb_audio_resume(struct usb_interface *intf) +static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)  {  	struct snd_usb_audio *chip = usb_get_intfdata(intf); +	struct usb_mixer_interface *mixer; +	int err = 0;  	if (chip == (void *)-1L)  		return 0;  	if (--chip->num_suspended_intf)  		return 0; + +	chip->in_pm = 1;  	/*  	 * ALSA leaves material resumption to user space -	 * we just notify +	 * we just notify and restart the mixers  	 */ +	list_for_each_entry(mixer, &chip->mixer_list, list) { +		err = snd_usb_mixer_resume(mixer, reset_resume); +		if (err < 0) +			goto err_out; +	} -	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); +	if (!chip->autosuspended) +		snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); +	chip->autosuspended = 0; -	return 0; +err_out: +	chip->in_pm = 0; +	return err; +} + +static int usb_audio_resume(struct usb_interface *intf) +{ +	return __usb_audio_resume(intf, false); +} + +static int usb_audio_reset_resume(struct usb_interface *intf) +{ +	return __usb_audio_resume(intf, true);  }  #else  #define usb_audio_suspend	NULL  #define usb_audio_resume	NULL +#define usb_audio_reset_resume	NULL  #endif		/* CONFIG_PM */  static struct usb_device_id usb_audio_ids [] = { @@ -626,8 +762,7 @@ static struct usb_device_id usb_audio_ids [] = {        .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },      { }						/* Terminating entry */  }; - -MODULE_DEVICE_TABLE (usb, usb_audio_ids); +MODULE_DEVICE_TABLE(usb, usb_audio_ids);  /*   * entry point for linux usb interface @@ -639,22 +774,9 @@ static struct usb_driver usb_audio_driver = {  	.disconnect =	usb_audio_disconnect,  	.suspend =	usb_audio_suspend,  	.resume =	usb_audio_resume, +	.reset_resume =	usb_audio_reset_resume,  	.id_table =	usb_audio_ids, +	.supports_autosuspend = 1,  }; -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); +module_usb_driver(usb_audio_driver); diff --git a/sound/usb/card.h b/sound/usb/card.h index ae4251d5abf..97acb906acc 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -1,11 +1,12 @@  #ifndef __USBAUDIO_CARD_H  #define __USBAUDIO_CARD_H -#define MAX_PACKS	20 +#define MAX_NR_RATES	1024 +#define MAX_PACKS	6		/* per URB */  #define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */ -#define MAX_URBS	8 +#define MAX_URBS	12  #define SYNC_URBS	4	/* always four urbs for sync */ -#define MAX_QUEUE	24	/* try not to exceed this queue length, in ms */ +#define MAX_QUEUE	18	/* try not to exceed this queue length, in ms */  struct audioformat {  	struct list_head list; @@ -20,29 +21,88 @@ struct audioformat {  	unsigned char endpoint;		/* endpoint */  	unsigned char ep_attr;		/* endpoint attributes */  	unsigned char datainterval;	/* log_2 of data packet interval */ +	unsigned char protocol;		/* UAC_VERSION_1/2 */  	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 */  	unsigned char clock;		/* associated clock */ +	struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */ +	bool dsd_dop;			/* add DOP headers in case of DSD samples */ +	bool dsd_bitrev;		/* reverse the bits of each DSD sample */  };  struct snd_usb_substream; +struct snd_usb_endpoint;  struct snd_urb_ctx {  	struct urb *urb;  	unsigned int buffer_size;	/* size of data buffer, if data URB */  	struct snd_usb_substream *subs; +	struct snd_usb_endpoint *ep;  	int index;	/* index for urb array */  	int packets;	/* number of packets per urb */ +	int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */ +	struct list_head ready_list;  }; -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_endpoint { +	struct snd_usb_audio *chip; + +	int use_count; +	int ep_num;		/* the referenced endpoint number */ +	int type;		/* SND_USB_ENDPOINT_TYPE_* */ +	unsigned long flags; + +	void (*prepare_data_urb) (struct snd_usb_substream *subs, +				  struct urb *urb); +	void (*retire_data_urb) (struct snd_usb_substream *subs, +				 struct urb *urb); + +	struct snd_usb_substream *data_subs; +	struct snd_usb_endpoint *sync_master; +	struct snd_usb_endpoint *sync_slave; + +	struct snd_urb_ctx urb[MAX_URBS]; + +	struct snd_usb_packet_info { +		uint32_t packet_size[MAX_PACKS_HS]; +		int packets; +	} next_packet[MAX_URBS]; +	int next_packet_read_pos, next_packet_write_pos; +	struct list_head ready_playback_urbs; + +	unsigned int nurbs;		/* # urbs */ +	unsigned long active_mask;	/* bitmask of active urbs */ +	unsigned long unlink_mask;	/* bitmask of unlinked urbs */ +	char *syncbuf;			/* sync buffer for all sync URBs */ +	dma_addr_t sync_dma;		/* DMA address of syncbuf */ + +	unsigned int pipe;		/* the data i/o pipe */ +	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 */ +	int	   freqshift;		/* how much to shift the feedback value to get Q16.16 */ +	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 max_urb_frames;	/* max URB 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 syncmaxsize;	/* sync endpoint packet size */ +	unsigned int fill_max:1;	/* fill max packet size always */ +	unsigned int udh01_fb_quirk:1;	/* corrupted feedback data */ +	unsigned int datainterval;      /* log_2 of data packet interval */ +	unsigned int syncinterval;	/* P for adaptive mode, 0 otherwise */ +	unsigned char silence_value; +	unsigned int stride; +	int iface, altsetting; +	int skip_packets;		/* quirks for devices to ignore the first n packets +					   in a stream */ + +	spinlock_t lock; +	struct list_head list;  };  struct snd_usb_substream { @@ -53,39 +113,31 @@ struct snd_usb_substream {  	int interface;	/* current interface */  	int endpoint;	/* assigned endpoint */  	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */ +	snd_pcm_format_t pcm_format;	/* current audio format (for hw_params callback) */ +	unsigned int channels;		/* current number of channels (for hw_params callback) */ +	unsigned int channels_max;	/* max channels in the all audiofmts */  	unsigned int cur_rate;		/* current rate (for hw_params callback) */  	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */ +	unsigned int period_frames;	/* current frames per period */ +	unsigned int buffer_periods;	/* current periods per buffer */  	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 */ -	int          freqshift;  /* how much to shift the feedback value to get Q16.16 */ -	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 syncmaxsize;	/* sync endpoint packet size */ -	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 pkt_offset_adj;	/* Bytes to drop from beginning of packets (for non-compliant devices) */  	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 frame_limit;	/* limits number of packets in URB */ -	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 */ +	/* data and sync endpoints for this stream */ +	unsigned int ep_num;		/* the endpoint number */ +	struct snd_usb_endpoint *data_endpoint; +	struct snd_usb_endpoint *sync_endpoint; +	unsigned long flags; +	bool need_setup_ep;		/* (re)configure EP at prepare? */ +	unsigned int speed;		/* USB_SPEED_XXX */  	u64 formats;			/* format bitmasks (all or'ed) */  	unsigned int num_formats;		/* number of supported audio formats (list) */ @@ -93,7 +145,14 @@ struct snd_usb_substream {  	struct snd_pcm_hw_constraint_list rate_list;	/* limited rates */  	spinlock_t lock; -	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */ +	int last_frame_number;          /* stored frame number */ +	int last_delay;                 /* stored delay */ + +	struct { +		int marker; +		int channel; +		int byte_idx; +	} dsd_dop;  };  struct snd_usb_stream { diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 7754a103454..03fed6611d9 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -32,6 +32,7 @@  #include "card.h"  #include "helper.h"  #include "clock.h" +#include "quirks.h"  static struct uac_clock_source_descriptor *  	snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, @@ -91,7 +92,7 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i  			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,  			      UAC2_CX_CLOCK_SELECTOR << 8,  			      snd_usb_ctrl_intf(chip) | (selector_id << 8), -			      &buf, sizeof(buf), 1000); +			      &buf, sizeof(buf));  	if (ret < 0)  		return ret; @@ -99,29 +100,76 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i  	return buf;  } +static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, +					unsigned char pin) +{ +	int ret; + +	ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), +			      UAC2_CS_CUR, +			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, +			      UAC2_CX_CLOCK_SELECTOR << 8, +			      snd_usb_ctrl_intf(chip) | (selector_id << 8), +			      &pin, sizeof(pin)); +	if (ret < 0) +		return ret; + +	if (ret != sizeof(pin)) { +		usb_audio_err(chip, +			"setting selector (id %d) unexpected length %d\n", +			selector_id, ret); +		return -EINVAL; +	} + +	ret = uac_clock_selector_get_val(chip, selector_id); +	if (ret < 0) +		return ret; + +	if (ret != pin) { +		usb_audio_err(chip, +			"setting selector (id %d) to %x failed (current: %d)\n", +			selector_id, pin, ret); +		return -EINVAL; +	} + +	return ret; +} +  static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)  {  	int err;  	unsigned char data;  	struct usb_device *dev = chip->dev; +	struct uac_clock_source_descriptor *cs_desc = +		snd_usb_find_clock_source(chip->ctrl_intf, source_id); + +	if (!cs_desc) +		return 0; + +	/* If a clock source can't tell us whether it's valid, we assume it is */ +	if (!uac2_control_is_readable(cs_desc->bmControls, +				      UAC2_CS_CONTROL_CLOCK_VALID - 1)) +		return 1;  	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_CLOCK_VALID << 8,  			      snd_usb_ctrl_intf(chip) | (source_id << 8), -			      &data, sizeof(data), 1000); +			      &data, sizeof(data));  	if (err < 0) { -		snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", +		dev_warn(&dev->dev, +			 "%s(): cannot get clock validity for id %d\n",  			   __func__, source_id); -		return err; +		return 0;  	}  	return !!data;  }  static int __uac_clock_find_source(struct snd_usb_audio *chip, -				   int entity_id, unsigned long *visited) +				   int entity_id, unsigned long *visited, +				   bool validate)  {  	struct uac_clock_source_descriptor *source;  	struct uac_clock_selector_descriptor *selector; @@ -130,20 +178,28 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,  	entity_id &= 0xff;  	if (test_and_set_bit(entity_id, visited)) { -		snd_printk(KERN_WARNING -			"%s(): recursive clock topology detected, id %d.\n", -			__func__, entity_id); +		usb_audio_warn(chip, +			 "%s(): recursive clock topology detected, id %d.\n", +			 __func__, entity_id);  		return -EINVAL;  	}  	/* first, see if the ID we're looking for is a clock source already */  	source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); -	if (source) -		return source->bClockID; +	if (source) { +		entity_id = source->bClockID; +		if (validate && !uac_clock_source_is_valid(chip, entity_id)) { +			usb_audio_err(chip, +				"clock source %d is not valid, cannot use\n", +				entity_id); +			return -ENXIO; +		} +		return entity_id; +	}  	selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);  	if (selector) { -		int ret; +		int ret, i, cur;  		/* the entity ID we are looking for is a selector.  		 * find out what it currently selects */ @@ -154,22 +210,49 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,  		/* Selector values are one-based */  		if (ret > selector->bNrInPins || ret < 1) { -			printk(KERN_ERR +			usb_audio_err(chip,  				"%s(): selector reported illegal value, id %d, ret %d\n",  				__func__, selector->bClockID, ret);  			return -EINVAL;  		} -		return __uac_clock_find_source(chip, selector->baCSourceID[ret-1], -					       visited); +		cur = ret; +		ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1], +					       visited, validate); +		if (!validate || ret > 0 || !chip->autoclock) +			return ret; + +		/* The current clock source is invalid, try others. */ +		for (i = 1; i <= selector->bNrInPins; i++) { +			int err; + +			if (i == cur) +				continue; + +			ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1], +				visited, true); +			if (ret < 0) +				continue; + +			err = uac_clock_selector_set_val(chip, entity_id, i); +			if (err < 0) +				continue; + +			usb_audio_info(chip, +				 "found and selected valid clock source %d\n", +				 ret); +			return ret; +		} + +		return -ENXIO;  	}  	/* FIXME: multipliers only act as pass-thru element for now */  	multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);  	if (multiplier)  		return __uac_clock_find_source(chip, multiplier->bCSourceID, -						visited); +						visited, validate);  	return -EINVAL;  } @@ -185,11 +268,12 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,   *   * Returns the clock source UnitID (>=0) on success, or an error.   */ -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id) +int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, +			      bool validate)  {  	DECLARE_BITMAP(visited, 256);  	memset(visited, 0, sizeof(visited)); -	return __uac_clock_find_source(chip, entity_id, visited); +	return __uac_clock_find_source(chip, entity_id, visited, validate);  }  static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, @@ -213,76 +297,111 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,  	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); +				   data, sizeof(data))) < 0) { +		dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", +			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); +				   data, sizeof(data))) < 0) { +		dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", +			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); +		dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);  		// runtime->rate = crate;  	}  	return 0;  } +static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, +			      int altsetting, int clock) +{ +	struct usb_device *dev = chip->dev; +	__le32 data; +	int err; + +	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, +			      snd_usb_ctrl_intf(chip) | (clock << 8), +			      &data, sizeof(data)); +	if (err < 0) { +		dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d\n", +			 iface, altsetting, err); +		return 0; +	} + +	return le32_to_cpu(data); +} +  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; -	int clock = snd_usb_clock_find_source(chip, fmt->clock); +	__le32 data; +	int err, cur_rate, prev_rate; +	int clock; +	bool writeable; +	struct uac_clock_source_descriptor *cs_desc; +	clock = snd_usb_clock_find_source(chip, fmt->clock, true);  	if (clock < 0)  		return clock; -	if (!uac_clock_source_is_valid(chip, clock)) { -		/* TODO: should we try to find valid clock setups by ourself? */ -		snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", -			   dev->devnum, iface, fmt->altsetting, clock); -		return -ENXIO; -	} +	prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); +	if (prev_rate == rate) +		return 0; -	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, -				   snd_usb_ctrl_intf(chip) | (clock << 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; +	cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); +	writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1); +	if (writeable) { +		data = cpu_to_le32(rate); +		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, +				      snd_usb_ctrl_intf(chip) | (clock << 8), +				      &data, sizeof(data)); +		if (err < 0) { +			usb_audio_err(chip, +				"%d:%d: cannot set freq %d (v2): err %d\n", +				iface, fmt->altsetting, rate, err); +			return err; +		} + +		cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); +	} else { +		cur_rate = prev_rate;  	} -	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, -				   snd_usb_ctrl_intf(chip) | (clock << 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; +	if (cur_rate != rate) { +		if (!writeable) { +			usb_audio_warn(chip, +				 "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", +				 iface, fmt->altsetting, rate, cur_rate); +			return -ENXIO; +		} +		usb_audio_dbg(chip, +			"current rate %d is different from the runtime rate %d\n", +			cur_rate, rate);  	} -	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); +	/* Some devices doesn't respond to sample rate changes while the +	 * interface is active. */ +	if (rate != prev_rate) { +		usb_set_interface(dev, iface, 0); +		snd_usb_set_interface_quirk(dev); +		usb_set_interface(dev, iface, fmt->altsetting); +		snd_usb_set_interface_quirk(dev); +	}  	return 0;  } @@ -291,9 +410,7 @@ 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) { +	switch (fmt->protocol) {  	case UAC_VERSION_1:  	default:  		return set_sample_rate_v1(chip, iface, alts, fmt, rate); diff --git a/sound/usb/clock.h b/sound/usb/clock.h index 46630936d31..d592e4a2985 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -5,6 +5,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,  			     struct usb_host_interface *alts,  			     struct audioformat *fmt, int rate); -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id); +int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, +			     bool validate);  #endif /* __USBAUDIO_CLOCK_H */ diff --git a/sound/usb/debug.h b/sound/usb/debug.h index 343ec2d9ee6..58030176f00 100644 --- a/sound/usb/debug.h +++ b/sound/usb/debug.h @@ -8,7 +8,7 @@  #ifdef HW_CONST_DEBUG  #define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args)  #else -#define hwc_debug(fmt, args...) /**/ +#define hwc_debug(fmt, args...) do { } while(0)  #endif  #endif /* __USBAUDIO_DEBUG_H */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index b0ef9f50189..114e3e7ff51 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -15,434 +15,1156 @@   *   */ +#include <linux/gfp.h>  #include <linux/init.h> -#include <linux/slab.h> +#include <linux/ratelimit.h>  #include <linux/usb.h>  #include <linux/usb/audio.h> -#include <linux/usb/audio-v2.h> +#include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> +#include <sound/pcm_params.h>  #include "usbaudio.h" +#include "helper.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" -#include "clock.h" +#include "quirks.h" + +#define EP_FLAG_RUNNING		1 +#define EP_FLAG_STOPPING	2 + +/* + * snd_usb_endpoint is a model that abstracts everything related to an + * USB endpoint and its streaming. + * + * There are functions to activate and deactivate the streaming URBs and + * optional callbacks to let the pcm logic handle the actual content of the + * packets for playback and record. Thus, the bus streaming and the audio + * handlers are fully decoupled. + * + * There are two different types of endpoints in audio applications. + * + * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both + * inbound and outbound traffic. + * + * SND_USB_ENDPOINT_TYPE_SYNC endpoints are for inbound traffic only and + * expect the payload to carry Q10.14 / Q16.16 formatted sync information + * (3 or 4 bytes). + * + * Each endpoint has to be configured prior to being used by calling + * snd_usb_endpoint_set_params(). + * + * The model incorporates a reference counting, so that multiple users + * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and + * only the first user will effectively start the URBs, and only the last + * one to stop it will tear the URBs down again. + */  /* - * free a substream + * convert a sampling rate into our full speed format (fs/1000 in Q16.16) + * this will overflow at approx 524 kHz   */ -static void free_substream(struct snd_usb_substream *subs) +static inline unsigned get_usb_full_speed_rate(unsigned int rate)  { -	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); +	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; +} + +/* + * release a urb data + */ +static void release_urb_ctx(struct snd_urb_ctx *u) +{ +	if (u->buffer_size) +		usb_free_coherent(u->ep->chip->dev, u->buffer_size, +				  u->urb->transfer_buffer, +				  u->urb->transfer_dma); +	usb_free_urb(u->urb); +	u->urb = NULL; +} + +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";  	} -	kfree(subs->rate_list.list);  } +/** + * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type + * + * @ep: The snd_usb_endpoint + * + * Determine whether an endpoint is driven by an implicit feedback + * data endpoint source. + */ +int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep) +{ +	return  ep->sync_master && +		ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA && +		ep->type == SND_USB_ENDPOINT_TYPE_DATA && +		usb_pipeout(ep->pipe); +}  /* - * free a usb stream instance + * For streaming based on information derived from sync endpoints, + * prepare_outbound_urb_sizes() will call next_packet_size() to + * determine the number of samples to be sent in the next packet. + * + * For implicit feedback, next_packet_size() is unused.   */ -static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) +{ +	unsigned long flags; +	int ret; + +	if (ep->fill_max) +		return ep->maxframesize; + +	spin_lock_irqsave(&ep->lock, flags); +	ep->phase = (ep->phase & 0xffff) +		+ (ep->freqm << ep->datainterval); +	ret = min(ep->phase >> 16, ep->maxframesize); +	spin_unlock_irqrestore(&ep->lock, flags); + +	return ret; +} + +static void retire_outbound_urb(struct snd_usb_endpoint *ep, +				struct snd_urb_ctx *urb_ctx)  { -	free_substream(&stream->substream[0]); -	free_substream(&stream->substream[1]); -	list_del(&stream->list); -	kfree(stream); +	if (ep->retire_data_urb) +		ep->retire_data_urb(ep->data_subs, urb_ctx->urb);  } -static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) +static void retire_inbound_urb(struct snd_usb_endpoint *ep, +			       struct snd_urb_ctx *urb_ctx)  { -	struct snd_usb_stream *stream = pcm->private_data; -	if (stream) { -		stream->pcm = NULL; -		snd_usb_audio_stream_free(stream); +	struct urb *urb = urb_ctx->urb; + +	if (unlikely(ep->skip_packets > 0)) { +		ep->skip_packets--; +		return;  	} + +	if (ep->sync_slave) +		snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); + +	if (ep->retire_data_urb) +		ep->retire_data_urb(ep->data_subs, urb);  } +/* + * Prepare a PLAYBACK urb for submission to the bus. + */ +static void prepare_outbound_urb(struct snd_usb_endpoint *ep, +				 struct snd_urb_ctx *ctx) +{ +	int i; +	struct urb *urb = ctx->urb; +	unsigned char *cp = urb->transfer_buffer; + +	urb->dev = ep->chip->dev; /* we need to set this at each time */ + +	switch (ep->type) { +	case SND_USB_ENDPOINT_TYPE_DATA: +		if (ep->prepare_data_urb) { +			ep->prepare_data_urb(ep->data_subs, urb); +		} else { +			/* no data provider, so send silence */ +			unsigned int offs = 0; +			for (i = 0; i < ctx->packets; ++i) { +				int counts; + +				if (ctx->packet_size[i]) +					counts = ctx->packet_size[i]; +				else +					counts = snd_usb_endpoint_next_packet_size(ep); + +				urb->iso_frame_desc[i].offset = offs * ep->stride; +				urb->iso_frame_desc[i].length = counts * ep->stride; +				offs += counts; +			} + +			urb->number_of_packets = ctx->packets; +			urb->transfer_buffer_length = offs * ep->stride; +			memset(urb->transfer_buffer, ep->silence_value, +			       offs * ep->stride); +		} +		break; + +	case SND_USB_ENDPOINT_TYPE_SYNC: +		if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) { +			/* +			 * fill the length and offset of each urb descriptor. +			 * the fixed 12.13 frequency is passed as 16.16 through the pipe. +			 */ +			urb->iso_frame_desc[0].length = 4; +			urb->iso_frame_desc[0].offset = 0; +			cp[0] = ep->freqn; +			cp[1] = ep->freqn >> 8; +			cp[2] = ep->freqn >> 16; +			cp[3] = ep->freqn >> 24; +		} else { +			/* +			 * fill the length and offset of each urb descriptor. +			 * the fixed 10.14 frequency is passed through the pipe. +			 */ +			urb->iso_frame_desc[0].length = 3; +			urb->iso_frame_desc[0].offset = 0; +			cp[0] = ep->freqn >> 2; +			cp[1] = ep->freqn >> 10; +			cp[2] = ep->freqn >> 18; +		} + +		break; +	} +}  /* - * 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. + * Prepare a CAPTURE or SYNC urb for submission to the bus.   */ -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) +static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, +				       struct snd_urb_ctx *urb_ctx)  { -	struct list_head *p; -	struct snd_usb_stream *as; -	struct snd_usb_substream *subs; -	struct snd_pcm *pcm; -	int err; +	int i, offs; +	struct urb *urb = urb_ctx->urb; -	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; +	urb->dev = ep->chip->dev; /* we need to set this at each time */ + +	switch (ep->type) { +	case SND_USB_ENDPOINT_TYPE_DATA: +		offs = 0; +		for (i = 0; i < urb_ctx->packets; i++) { +			urb->iso_frame_desc[i].offset = offs; +			urb->iso_frame_desc[i].length = ep->curpacksize; +			offs += ep->curpacksize;  		} + +		urb->transfer_buffer_length = offs; +		urb->number_of_packets = urb_ctx->packets; +		break; + +	case SND_USB_ENDPOINT_TYPE_SYNC: +		urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize); +		urb->iso_frame_desc[0].offset = 0; +		break;  	} -	/* 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); +} + +/* + * Send output urbs that have been prepared previously. URBs are dequeued + * from ep->ready_playback_urbs and in case there there aren't any available + * or there are no packets that have been prepared, this function does + * nothing. + * + * The reason why the functionality of sending and preparing URBs is separated + * is that host controllers don't guarantee the order in which they return + * inbound and outbound packets to their submitters. + * + * This function is only used for implicit feedback endpoints. For endpoints + * driven by dedicated sync endpoints, URBs are immediately re-submitted + * from their completion handler. + */ +static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) +{ +	while (test_bit(EP_FLAG_RUNNING, &ep->flags)) { + +		unsigned long flags; +		struct snd_usb_packet_info *uninitialized_var(packet); +		struct snd_urb_ctx *ctx = NULL; +		struct urb *urb; +		int err, i; + +		spin_lock_irqsave(&ep->lock, flags); +		if (ep->next_packet_read_pos != ep->next_packet_write_pos) { +			packet = ep->next_packet + ep->next_packet_read_pos; +			ep->next_packet_read_pos++; +			ep->next_packet_read_pos %= MAX_URBS; + +			/* take URB out of FIFO */ +			if (!list_empty(&ep->ready_playback_urbs)) +				ctx = list_first_entry(&ep->ready_playback_urbs, +					       struct snd_urb_ctx, ready_list); +		} +		spin_unlock_irqrestore(&ep->lock, flags); + +		if (ctx == NULL) +			return; + +		list_del_init(&ctx->ready_list); +		urb = ctx->urb; + +		/* copy over the length information */ +		for (i = 0; i < packet->packets; i++) +			ctx->packet_size[i] = packet->packet_size[i]; + +		/* call the data handler to fill in playback data */ +		prepare_outbound_urb(ep, ctx); + +		err = usb_submit_urb(ctx->urb, GFP_ATOMIC);  		if (err < 0) -			return err; -		snd_usb_init_substream(as, stream, fp); -		return 0; +			usb_audio_err(ep->chip, +				"Unable to submit urb #%d: %d (urb %p)\n", +				ctx->index, err, ctx->urb); +		else +			set_bit(ctx->index, &ep->active_mask);  	} +} -	/* 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; +/* + * complete callback for urbs + */ +static void snd_complete_urb(struct urb *urb) +{ +	struct snd_urb_ctx *ctx = urb->context; +	struct snd_usb_endpoint *ep = ctx->ep; +	int err; + +	if (unlikely(urb->status == -ENOENT ||		/* unlinked */ +		     urb->status == -ENODEV ||		/* device removed */ +		     urb->status == -ECONNRESET ||	/* unlinked */ +		     urb->status == -ESHUTDOWN ||	/* device disabled */ +		     ep->chip->shutdown))		/* device disconnected */ +		goto exit_clear; + +	if (usb_pipeout(ep->pipe)) { +		retire_outbound_urb(ep, ctx); +		/* can be stopped during retire callback */ +		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) +			goto exit_clear; + +		if (snd_usb_endpoint_implicit_feedback_sink(ep)) { +			unsigned long flags; + +			spin_lock_irqsave(&ep->lock, flags); +			list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); +			spin_unlock_irqrestore(&ep->lock, flags); +			queue_pending_output_urbs(ep); + +			goto exit_clear; +		} + +		prepare_outbound_urb(ep, ctx); +	} else { +		retire_inbound_urb(ep, ctx); +		/* can be stopped during retire callback */ +		if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) +			goto exit_clear; + +		prepare_inbound_urb(ep, ctx);  	} -	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); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (err == 0) +		return; + +	usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); +	//snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + +exit_clear: +	clear_bit(ctx->index, &ep->active_mask); +} + +/** + * snd_usb_add_endpoint: Add an endpoint to an USB audio chip + * + * @chip: The chip + * @alts: The USB host interface + * @ep_num: The number of the endpoint to use + * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE + * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC + * + * If the requested endpoint has not been added to the given chip before, + * a new instance is created. Otherwise, a pointer to the previoulsy + * created instance is returned. In case of any error, NULL is returned. + * + * New endpoints will be added to chip->ep_list and must be freed by + * calling snd_usb_endpoint_free(). + */ +struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, +					      struct usb_host_interface *alts, +					      int ep_num, int direction, int type) +{ +	struct snd_usb_endpoint *ep; +	int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK; + +	if (WARN_ON(!alts)) +		return NULL; + +	mutex_lock(&chip->mutex); + +	list_for_each_entry(ep, &chip->ep_list, list) { +		if (ep->ep_num == ep_num && +		    ep->iface == alts->desc.bInterfaceNumber && +		    ep->altsetting == alts->desc.bAlternateSetting) { +			usb_audio_dbg(ep->chip, +				      "Re-using EP %x in iface %d,%d @%p\n", +					ep_num, ep->iface, ep->altsetting, ep); +			goto __exit_unlock; +		} +	} + +	usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n", +		    is_playback ? "playback" : "capture", +		    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync", +		    ep_num); + +	ep = kzalloc(sizeof(*ep), GFP_KERNEL); +	if (!ep) +		goto __exit_unlock; + +	ep->chip = chip; +	spin_lock_init(&ep->lock); +	ep->type = type; +	ep->ep_num = ep_num; +	ep->iface = alts->desc.bInterfaceNumber; +	ep->altsetting = alts->desc.bAlternateSetting; +	INIT_LIST_HEAD(&ep->ready_playback_urbs); +	ep_num &= USB_ENDPOINT_NUMBER_MASK; + +	if (is_playback) +		ep->pipe = usb_sndisocpipe(chip->dev, ep_num);  	else -		strcpy(pcm->name, "USB Audio"); +		ep->pipe = usb_rcvisocpipe(chip->dev, ep_num); + +	if (type == SND_USB_ENDPOINT_TYPE_SYNC) { +		if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && +		    get_endpoint(alts, 1)->bRefresh >= 1 && +		    get_endpoint(alts, 1)->bRefresh <= 9) +			ep->syncinterval = get_endpoint(alts, 1)->bRefresh; +		else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) +			ep->syncinterval = 1; +		else if (get_endpoint(alts, 1)->bInterval >= 1 && +			 get_endpoint(alts, 1)->bInterval <= 16) +			ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1; +		else +			ep->syncinterval = 3; -	snd_usb_init_substream(as, stream, fp); +		ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); -	list_add(&as->list, &chip->pcm_list); -	chip->pcm_devs++; +		if (chip->usb_id == USB_ID(0x0644, 0x8038) /* TEAC UD-H01 */ && +		    ep->syncmaxsize == 4) +			ep->udh01_fb_quirk = 1; +	} + +	list_add_tail(&ep->list, &chip->ep_list); + +__exit_unlock: +	mutex_unlock(&chip->mutex); + +	return ep; +} + +/* + *  wait until all urbs are processed. + */ +static int wait_clear_urbs(struct snd_usb_endpoint *ep) +{ +	unsigned long end_time = jiffies + msecs_to_jiffies(1000); +	int alive; + +	do { +		alive = bitmap_weight(&ep->active_mask, ep->nurbs); +		if (!alive) +			break; + +		schedule_timeout_uninterruptible(1); +	} while (time_before(jiffies, end_time)); -	snd_usb_proc_pcm_format_add(as); +	if (alive) +		usb_audio_err(ep->chip, +			"timeout: still %d active urbs on EP #%x\n", +			alive, ep->ep_num); +	clear_bit(EP_FLAG_STOPPING, &ep->flags);  	return 0;  } -static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, -					 struct usb_host_interface *alts, -					 int protocol, int iface_no) +/* sync the pending stop operation; + * this function itself doesn't trigger the stop operation + */ +void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)  { -	/* parsed with a v1 header here. that's ok as we only look at the -	 * header first which is the same for both versions */ -	struct uac_iso_endpoint_descriptor *csep; -	struct usb_interface_descriptor *altsd = get_iface_desc(alts); -	int attributes = 0; - -	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->bLength < 7 || -	    csep->bDescriptorSubtype != UAC_EP_GENERAL) { -		snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" -			   " class specific endpoint descriptor\n", -			   chip->dev->devnum, iface_no, -			   altsd->bAlternateSetting); -		return 0; +	if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags)) +		wait_clear_urbs(ep); +} + +/* + * unlink active urbs. + */ +static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) +{ +	unsigned int i; + +	if (!force && ep->chip->shutdown) /* to be sure... */ +		return -EBADFD; + +	clear_bit(EP_FLAG_RUNNING, &ep->flags); + +	INIT_LIST_HEAD(&ep->ready_playback_urbs); +	ep->next_packet_read_pos = 0; +	ep->next_packet_write_pos = 0; + +	for (i = 0; i < ep->nurbs; i++) { +		if (test_bit(i, &ep->active_mask)) { +			if (!test_and_set_bit(i, &ep->unlink_mask)) { +				struct urb *u = ep->urb[i].urb; +				usb_unlink_urb(u); +			} +		} +	} + +	return 0; +} + +/* + * release an endpoint's urbs + */ +static void release_urbs(struct snd_usb_endpoint *ep, int force) +{ +	int i; + +	/* route incoming urbs to nirvana */ +	ep->retire_data_urb = NULL; +	ep->prepare_data_urb = NULL; + +	/* stop urbs */ +	deactivate_urbs(ep, force); +	wait_clear_urbs(ep); + +	for (i = 0; i < ep->nurbs; i++) +		release_urb_ctx(&ep->urb[i]); + +	if (ep->syncbuf) +		usb_free_coherent(ep->chip->dev, SYNC_URBS * 4, +				  ep->syncbuf, ep->sync_dma); + +	ep->syncbuf = NULL; +	ep->nurbs = 0; +} + +/* + * configure a data endpoint + */ +static int data_ep_set_params(struct snd_usb_endpoint *ep, +			      snd_pcm_format_t pcm_format, +			      unsigned int channels, +			      unsigned int period_bytes, +			      unsigned int frames_per_period, +			      unsigned int periods_per_buffer, +			      struct audioformat *fmt, +			      struct snd_usb_endpoint *sync_ep) +{ +	unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; +	unsigned int max_packs_per_period, urbs_per_period, urb_packs; +	unsigned int max_urbs, i; +	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; + +	if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { +		/* +		 * When operating in DSD DOP mode, the size of a sample frame +		 * in hardware differs from the actual physical format width +		 * because we need to make room for the DOP markers. +		 */ +		frame_bits += channels << 3; +	} + +	ep->datainterval = fmt->datainterval; +	ep->stride = frame_bits >> 3; +	ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; + +	/* assume max. frequency is 25% higher than nominal */ +	ep->freqmax = ep->freqn + (ep->freqn >> 2); +	maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) +				>> (16 - ep->datainterval); +	/* but wMaxPacketSize might reduce this */ +	if (ep->maxpacksize && ep->maxpacksize < maxsize) { +		/* whatever fits into a max. size packet */ +		maxsize = ep->maxpacksize; +		ep->freqmax = (maxsize / (frame_bits >> 3)) +				<< (16 - ep->datainterval);  	} -	if (protocol == UAC_VERSION_1) { -		attributes = csep->bmAttributes; +	if (ep->fill_max) +		ep->curpacksize = ep->maxpacksize; +	else +		ep->curpacksize = maxsize; + +	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) { +		packs_per_ms = 8 >> ep->datainterval; +		max_packs_per_urb = MAX_PACKS_HS;  	} else { -		struct uac2_iso_endpoint_descriptor *csep2 = -			(struct uac2_iso_endpoint_descriptor *) csep; +		packs_per_ms = 1; +		max_packs_per_urb = MAX_PACKS; +	} +	if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) +		max_packs_per_urb = min(max_packs_per_urb, +					1U << sync_ep->syncinterval); +	max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); + +	/* +	 * Capture endpoints need to use small URBs because there's no way +	 * to tell in advance where the next period will end, and we don't +	 * want the next URB to complete much after the period ends. +	 * +	 * Playback endpoints with implicit sync much use the same parameters +	 * as their corresponding capture endpoint. +	 */ +	if (usb_pipein(ep->pipe) || +			snd_usb_endpoint_implicit_feedback_sink(ep)) { -		attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; +		urb_packs = packs_per_ms; +		/* +		 * Wireless devices can poll at a max rate of once per 4ms. +		 * For dataintervals less than 5, increase the packet count to +		 * allow the host controller to use bursting to fill in the +		 * gaps. +		 */ +		if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { +			int interval = ep->datainterval; +			while (interval < 5) { +				urb_packs <<= 1; +				++interval; +			} +		} +		/* make capture URBs <= 1 ms and smaller than a period */ +		urb_packs = min(max_packs_per_urb, urb_packs); +		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) +			urb_packs >>= 1; +		ep->nurbs = MAX_URBS; -		/* emulate the endpoint attributes of a v1 device */ -		if (csep2->bmControls & UAC2_CONTROL_PITCH) -			attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; +	/* +	 * Playback endpoints without implicit sync are adjusted so that +	 * a period fits as evenly as possible in the smallest number of +	 * URBs.  The total number of URBs is adjusted to the size of the +	 * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits. +	 */ +	} else { +		/* determine how small a packet can be */ +		minsize = (ep->freqn >> (16 - ep->datainterval)) * +				(frame_bits >> 3); +		/* with sync from device, assume it can be 12% lower */ +		if (sync_ep) +			minsize -= minsize >> 3; +		minsize = max(minsize, 1u); + +		/* how many packets will contain an entire ALSA period? */ +		max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize); + +		/* how many URBs will contain a period? */ +		urbs_per_period = DIV_ROUND_UP(max_packs_per_period, +				max_packs_per_urb); +		/* how many packets are needed in each URB? */ +		urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period); + +		/* limit the number of frames in a single URB */ +		ep->max_urb_frames = DIV_ROUND_UP(frames_per_period, +					urbs_per_period); + +		/* try to use enough URBs to contain an entire ALSA buffer */ +		max_urbs = min((unsigned) MAX_URBS, +				MAX_QUEUE * packs_per_ms / urb_packs); +		ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer);  	} -	return attributes; +	/* allocate and initialize data urbs */ +	for (i = 0; i < ep->nurbs; i++) { +		struct snd_urb_ctx *u = &ep->urb[i]; +		u->index = i; +		u->ep = ep; +		u->packets = urb_packs; +		u->buffer_size = maxsize * u->packets; + +		if (fmt->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_alloc_coherent(ep->chip->dev, u->buffer_size, +					   GFP_KERNEL, &u->urb->transfer_dma); +		if (!u->urb->transfer_buffer) +			goto out_of_memory; +		u->urb->pipe = ep->pipe; +		u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; +		u->urb->interval = 1 << ep->datainterval; +		u->urb->context = u; +		u->urb->complete = snd_complete_urb; +		INIT_LIST_HEAD(&u->ready_list); +	} + +	return 0; + +out_of_memory: +	release_urbs(ep, 0); +	return -ENOMEM;  } -static struct uac2_input_terminal_descriptor * -	snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, -					       int terminal_id) +/* + * configure a sync endpoint + */ +static int sync_ep_set_params(struct snd_usb_endpoint *ep)  { -	struct uac2_input_terminal_descriptor *term = NULL; +	int i; -	while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, -					       ctrl_iface->extralen, -					       term, UAC_INPUT_TERMINAL))) { -		if (term->bTerminalID == terminal_id) -			return term; +	ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4, +					 GFP_KERNEL, &ep->sync_dma); +	if (!ep->syncbuf) +		return -ENOMEM; + +	for (i = 0; i < SYNC_URBS; i++) { +		struct snd_urb_ctx *u = &ep->urb[i]; +		u->index = i; +		u->ep = ep; +		u->packets = 1; +		u->urb = usb_alloc_urb(1, GFP_KERNEL); +		if (!u->urb) +			goto out_of_memory; +		u->urb->transfer_buffer = ep->syncbuf + i * 4; +		u->urb->transfer_dma = ep->sync_dma + i * 4; +		u->urb->transfer_buffer_length = 4; +		u->urb->pipe = ep->pipe; +		u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; +		u->urb->number_of_packets = 1; +		u->urb->interval = 1 << ep->syncinterval; +		u->urb->context = u; +		u->urb->complete = snd_complete_urb;  	} -	return NULL; +	ep->nurbs = SYNC_URBS; + +	return 0; + +out_of_memory: +	release_urbs(ep, 0); +	return -ENOMEM;  } -static struct uac2_output_terminal_descriptor * -	snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, -						int terminal_id) +/** + * snd_usb_endpoint_set_params: configure an snd_usb_endpoint + * + * @ep: the snd_usb_endpoint to configure + * @pcm_format: the audio fomat. + * @channels: the number of audio channels. + * @period_bytes: the number of bytes in one alsa period. + * @period_frames: the number of frames in one alsa period. + * @buffer_periods: the number of periods in one alsa buffer. + * @rate: the frame rate. + * @fmt: the USB audio format information + * @sync_ep: the sync endpoint to use, if any + * + * Determine the number of URBs to be used on this endpoint. + * An endpoint must be configured before it can be started. + * An endpoint that is already running can not be reconfigured. + */ +int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, +				snd_pcm_format_t pcm_format, +				unsigned int channels, +				unsigned int period_bytes, +				unsigned int period_frames, +				unsigned int buffer_periods, +				unsigned int rate, +				struct audioformat *fmt, +				struct snd_usb_endpoint *sync_ep)  { -	struct uac2_output_terminal_descriptor *term = NULL; +	int err; + +	if (ep->use_count != 0) { +		usb_audio_warn(ep->chip, +			 "Unable to change format on ep #%x: already in use\n", +			 ep->ep_num); +		return -EBUSY; +	} + +	/* release old buffers, if any */ +	release_urbs(ep, 0); + +	ep->datainterval = fmt->datainterval; +	ep->maxpacksize = fmt->maxpacksize; +	ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); + +	if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) +		ep->freqn = get_usb_full_speed_rate(rate); +	else +		ep->freqn = get_usb_high_speed_rate(rate); + +	/* calculate the frequency in 16.16 format */ +	ep->freqm = ep->freqn; +	ep->freqshift = INT_MIN; + +	ep->phase = 0; -	while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, -					       ctrl_iface->extralen, -					       term, UAC_OUTPUT_TERMINAL))) { -		if (term->bTerminalID == terminal_id) -			return term; +	switch (ep->type) { +	case  SND_USB_ENDPOINT_TYPE_DATA: +		err = data_ep_set_params(ep, pcm_format, channels, +					 period_bytes, period_frames, +					 buffer_periods, fmt, sync_ep); +		break; +	case  SND_USB_ENDPOINT_TYPE_SYNC: +		err = sync_ep_set_params(ep); +		break; +	default: +		err = -EINVAL;  	} -	return NULL; +	usb_audio_dbg(ep->chip, +		"Setting params for ep #%x (type %d, %d urbs), ret=%d\n", +		ep->ep_num, ep->type, ep->nurbs, err); + +	return err;  } -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) +/** + * snd_usb_endpoint_start: start an snd_usb_endpoint + * + * @ep:		the endpoint to start + * @can_sleep:	flag indicating whether the operation is executed in + * 		non-atomic context + * + * A call to this function will increment the use count of the endpoint. + * In case it is not already running, the URBs for this endpoint will be + * submitted. Otherwise, this function does nothing. + * + * Must be balanced to calls of snd_usb_endpoint_stop(). + * + * Returns an error if the URB submission failed, 0 in all other cases. + */ +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)  { -	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; -	int num, protocol, clock = 0; -	struct uac_format_type_i_continuous_descriptor *fmt; +	int err; +	unsigned int i; -	dev = chip->dev; +	if (ep->chip->shutdown) +		return -EBADFD; -	/* parse the interface's altsettings */ -	iface = usb_ifnum_to_if(dev, iface_no); +	/* already running? */ +	if (++ep->use_count != 1) +		return 0; + +	/* just to be sure */ +	deactivate_urbs(ep, false); +	if (can_sleep) +		wait_clear_urbs(ep); + +	ep->active_mask = 0; +	ep->unlink_mask = 0; +	ep->phase = 0; -	num = iface->num_altsetting; +	snd_usb_endpoint_start_quirk(ep);  	/* -	 * Dallas DS4201 workaround: It presents 5 altsettings, but the last -	 * one misses syncpipe, and does not produce any sound. +	 * If this endpoint has a data endpoint as implicit feedback source, +	 * don't start the urbs here. Instead, mark them all as available, +	 * wait for the record urbs to return and queue the playback urbs +	 * from that context.  	 */ -	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) { -		default: -			snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", -				    dev->devnum, iface_no, altno, protocol); -			protocol = UAC_VERSION_1; -			/* fall through */ - -		case UAC_VERSION_1: { -			struct uac1_as_header_descriptor *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; -			} +	set_bit(EP_FLAG_RUNNING, &ep->flags); -			format = le16_to_cpu(as->wFormatTag); /* remember the format value */ -			break; +	if (snd_usb_endpoint_implicit_feedback_sink(ep)) { +		for (i = 0; i < ep->nurbs; i++) { +			struct snd_urb_ctx *ctx = ep->urb + i; +			list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);  		} -		case UAC_VERSION_2: { -			struct uac2_input_terminal_descriptor *input_term; -			struct uac2_output_terminal_descriptor *output_term; -			struct uac2_as_header_descriptor *as = -				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); +		return 0; +	} -			if (!as) { -				snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", -					   dev->devnum, iface_no, altno); -				continue; -			} +	for (i = 0; i < ep->nurbs; i++) { +		struct urb *urb = ep->urb[i].urb; -			if (as->bLength < sizeof(*as)) { -				snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", -					   dev->devnum, iface_no, altno); -				continue; -			} +		if (snd_BUG_ON(!urb)) +			goto __error; -			num_channels = as->bNrChannels; -			format = le32_to_cpu(as->bmFormats); +		if (usb_pipeout(ep->pipe)) { +			prepare_outbound_urb(ep, urb->context); +		} else { +			prepare_inbound_urb(ep, urb->context); +		} -			/* lookup the terminal associated to this interface -			 * to extract the clock */ -			input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, -									    as->bTerminalLink); -			if (input_term) { -				clock = input_term->bCSourceID; -				break; -			} +		err = usb_submit_urb(urb, GFP_ATOMIC); +		if (err < 0) { +			usb_audio_err(ep->chip, +				"cannot submit urb %d, error %d: %s\n", +				i, err, usb_error_string(err)); +			goto __error; +		} +		set_bit(i, &ep->active_mask); +	} -			output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, -									      as->bTerminalLink); -			if (output_term) { -				clock = output_term->bCSourceID; -				break; -			} +	return 0; -			snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", -				   dev->devnum, iface_no, altno, as->bTerminalLink); -			continue; -		} -		} +__error: +	clear_bit(EP_FLAG_RUNNING, &ep->flags); +	ep->use_count--; +	deactivate_urbs(ep, false); +	return -EPIPE; +} -		/* 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->bLength < 8)) || -		    ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) { -			snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", -				   dev->devnum, iface_no, altno); -			continue; -		} +/** + * snd_usb_endpoint_stop: stop an snd_usb_endpoint + * + * @ep: the endpoint to stop (may be NULL) + * + * A call to this function will decrement the use count of the endpoint. + * In case the last user has requested the endpoint stop, the URBs will + * actually be deactivated. + * + * Must be balanced to calls of snd_usb_endpoint_start(). + * + * The caller needs to synchronize the pending stop operation via + * snd_usb_endpoint_sync_pending_stop(). + */ +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) +{ +	if (!ep) +		return; + +	if (snd_BUG_ON(ep->use_count == 0)) +		return; + +	if (--ep->use_count == 0) { +		deactivate_urbs(ep, false); +		ep->data_subs = NULL; +		ep->sync_slave = NULL; +		ep->retire_data_urb = NULL; +		ep->prepare_data_urb = NULL; +		set_bit(EP_FLAG_STOPPING, &ep->flags); +	} +} + +/** + * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint + * + * @ep: the endpoint to deactivate + * + * If the endpoint is not currently in use, this functions will + * deactivate its associated URBs. + * + * In case of any active users, this functions does nothing. + */ +void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) +{ +	if (!ep) +		return; + +	if (ep->use_count != 0) +		return; + +	deactivate_urbs(ep, true); +	wait_clear_urbs(ep); +} + +/** + * snd_usb_endpoint_release: Tear down an snd_usb_endpoint + * + * @ep: the endpoint to release + * + * This function does not care for the endpoint's use count but will tear + * down all the streaming URBs immediately. + */ +void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) +{ +	release_urbs(ep, 1); +} + +/** + * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint + * + * @ep: the list header of the endpoint to free + * + * This free all resources of the given ep. + */ +void snd_usb_endpoint_free(struct list_head *head) +{ +	struct snd_usb_endpoint *ep; + +	ep = list_entry(head, struct snd_usb_endpoint, list); +	kfree(ep); +} + +/** + * snd_usb_handle_sync_urb: parse an USB sync packet + * + * @ep: the endpoint to handle the packet + * @sender: the sending endpoint + * @urb: the received packet + * + * This function is called from the context of an endpoint that received + * the packet and is used to let another endpoint object handle the payload. + */ +void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, +			     struct snd_usb_endpoint *sender, +			     const struct urb *urb) +{ +	int shift; +	unsigned int f; +	unsigned long flags; + +	snd_BUG_ON(ep == sender); + +	/* +	 * In case the endpoint is operating in implicit feedback mode, prepare +	 * a new outbound URB that has the same layout as the received packet +	 * and add it to the list of pending urbs. queue_pending_output_urbs() +	 * will take care of them later. +	 */ +	if (snd_usb_endpoint_implicit_feedback_sink(ep) && +	    ep->use_count != 0) { + +		/* implicit feedback case */ +		int i, bytes = 0; +		struct snd_urb_ctx *in_ctx; +		struct snd_usb_packet_info *out_packet; + +		in_ctx = urb->context; + +		/* Count overall packet size */ +		for (i = 0; i < in_ctx->packets; i++) +			if (urb->iso_frame_desc[i].status == 0) +				bytes += urb->iso_frame_desc[i].actual_length;  		/* -		 * 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. +		 * skip empty packets. At least M-Audio's Fast Track Ultra stops +		 * streaming once it received a 0-byte OUT URB  		 */ -		if (fmt->bNrChannels == 1 && -		    fmt->bSubframeSize == 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; - -		fp = kzalloc(sizeof(*fp), GFP_KERNEL); -		if (! fp) { -			snd_printk(KERN_ERR "cannot malloc\n"); -			return -ENOMEM; -		} +		if (bytes == 0) +			return; + +		spin_lock_irqsave(&ep->lock, flags); +		out_packet = ep->next_packet + ep->next_packet_write_pos; -		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 = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); -		fp->clock = clock; - -		/* 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... +		 * Iterate through the inbound packet and prepare the lengths +		 * for the output packet. The OUT packet we are about to send +		 * will have the same amount of payload bytes per stride as the +		 * IN packet we just received. Since the actual size is scaled +		 * by the stride, use the sender stride to calculate the length +		 * in case the number of channels differ between the implicitly +		 * fed-back endpoint and the synchronizing endpoint.  		 */ -			fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; -			if (stream == SNDRV_PCM_STREAM_PLAYBACK) -				fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; + +		out_packet->packets = in_ctx->packets; +		for (i = 0; i < in_ctx->packets; i++) { +			if (urb->iso_frame_desc[i].status == 0) +				out_packet->packet_size[i] = +					urb->iso_frame_desc[i].actual_length / sender->stride;  			else -				fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; -			break; +				out_packet->packet_size[i] = 0;  		} -		/* ok, let's parse further... */ -		if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { -			kfree(fp->rate_table); -			kfree(fp); -			fp = NULL; -			continue; -		} +		ep->next_packet_write_pos++; +		ep->next_packet_write_pos %= MAX_URBS; +		spin_unlock_irqrestore(&ep->lock, flags); +		queue_pending_output_urbs(ep); -		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; +		return; +	} + +	/* +	 * process after playback sync complete +	 * +	 * Full speed devices report feedback values in 10.14 format as samples +	 * per frame, high speed devices in 16.16 format as samples per +	 * microframe. +	 * +	 * Because the Audio Class 1 spec was written before USB 2.0, many high +	 * speed devices use a wrong interpretation, some others use an +	 * entirely different format. +	 * +	 * Therefore, we cannot predict what format any particular device uses +	 * and must detect it automatically. +	 */ + +	if (urb->iso_frame_desc[0].status != 0 || +	    urb->iso_frame_desc[0].actual_length < 3) +		return; + +	f = le32_to_cpup(urb->transfer_buffer); +	if (urb->iso_frame_desc[0].actual_length == 3) +		f &= 0x00ffffff; +	else +		f &= 0x0fffffff; + +	if (f == 0) +		return; + +	if (unlikely(sender->udh01_fb_quirk)) { +		/* +		 * The TEAC UD-H01 firmware sometimes changes the feedback value +		 * by +/- 0x1.0000. +		 */ +		if (f < ep->freqn - 0x8000) +			f += 0x10000; +		else if (f > ep->freqn + 0x8000) +			f -= 0x10000; +	} else if (unlikely(ep->freqshift == INT_MIN)) { +		/* +		 * The first time we see a feedback value, determine its format +		 * by shifting it left or right until it matches the nominal +		 * frequency value.  This assumes that the feedback does not +		 * differ from the nominal value more than +50% or -25%. +		 */ +		shift = 0; +		while (f < ep->freqn - ep->freqn / 4) { +			f <<= 1; +			shift++;  		} -		/* 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); +		while (f > ep->freqn + ep->freqn / 2) { +			f >>= 1; +			shift--; +		} +		ep->freqshift = shift; +	} else if (ep->freqshift >= 0) +		f <<= ep->freqshift; +	else +		f >>= -ep->freqshift; + +	if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) { +		/* +		 * If the frequency looks valid, set it. +		 * This value is referred to in prepare_playback_urb(). +		 */ +		spin_lock_irqsave(&ep->lock, flags); +		ep->freqm = f; +		spin_unlock_irqrestore(&ep->lock, flags); +	} else { +		/* +		 * Out of range; maybe the shift value is wrong. +		 * Reset it so that we autodetect again the next time. +		 */ +		ep->freqshift = INT_MIN;  	} -	return 0;  } diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 64dd0db023b..e61ee5c356a 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -1,11 +1,36 @@  #ifndef __USBAUDIO_ENDPOINT_H  #define __USBAUDIO_ENDPOINT_H -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, -				  int iface_no); +#define SND_USB_ENDPOINT_TYPE_DATA     0 +#define SND_USB_ENDPOINT_TYPE_SYNC     1 -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, -			       int stream, -			       struct audioformat *fp); +struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, +					      struct usb_host_interface *alts, +					      int ep_num, int direction, int type); + +int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, +				snd_pcm_format_t pcm_format, +				unsigned int channels, +				unsigned int period_bytes, +				unsigned int period_frames, +				unsigned int buffer_periods, +				unsigned int rate, +				struct audioformat *fmt, +				struct snd_usb_endpoint *sync_ep); + +int  snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep); +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); +int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_free(struct list_head *head); + +int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); + +void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, +			     struct snd_usb_endpoint *sender, +			     const struct urb *urb);  #endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 69148212aa7..8bcc87cf566 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -30,6 +30,7 @@  #include "helper.h"  #include "debug.h"  #include "clock.h" +#include "format.h"  /*   * parse the audio format type I descriptor @@ -42,13 +43,12 @@   */  static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  				     struct audioformat *fp, -				     int format, void *_fmt, -				     int protocol) +				     unsigned int format, void *_fmt)  {  	int sample_width, sample_bytes; -	u64 pcm_formats; +	u64 pcm_formats = 0; -	switch (protocol) { +	switch (fp->protocol) {  	case UAC_VERSION_1:  	default: {  		struct uac_format_type_i_discrete_descriptor *fmt = _fmt; @@ -62,24 +62,30 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  		struct uac_format_type_i_ext_descriptor *fmt = _fmt;  		sample_width = fmt->bBitResolution;  		sample_bytes = fmt->bSubslotSize; + +		if (format & UAC2_FORMAT_TYPE_I_RAW_DATA) +			pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL; +  		format <<= 1;  		break;  	}  	} -	pcm_formats = 0; - -	if (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED)) { +	if ((pcm_formats == 0) && +	    (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); +		usb_audio_info(chip, "%u:%d : format type 0 is detected, processed as PCM\n", +			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); +		if (chip->usb_id == USB_ID(0x0582, 0x0016) /* Edirol SD-90 */ && +		    sample_width == 24 && sample_bytes == 2) +			sample_bytes = 3; +		else if (sample_width > sample_bytes * 8) { +			usb_audio_info(chip, "%u:%d : sample bitwidth %d in over sample bytes %d\n", +				 fp->iface, fp->altsetting, +				 sample_width, sample_bytes);  		}  		/* check the format byte size */  		switch (sample_bytes) { @@ -102,9 +108,10 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  			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); +			usb_audio_info(chip, +				 "%u:%d : unsupported sample bitwidth %d in %d bytes\n", +				 fp->iface, fp->altsetting, +				 sample_width, sample_bytes);  			break;  		}  	} @@ -126,9 +133,13 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  		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); +		usb_audio_info(chip, +			 "%u:%d : unsupported format bits %#x\n", +			 fp->iface, fp->altsetting, format);  	} + +	pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes); +  	return pcm_formats;  } @@ -149,9 +160,10 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof  	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; +		usb_audio_err(chip, +			"%u:%d : invalid UAC_FORMAT_TYPE desc\n", +			fp->iface, fp->altsetting); +		return -EINVAL;  	}  	if (nr_rates) { @@ -162,8 +174,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof  		fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);  		if (fp->rate_table == NULL) { -			snd_printk(KERN_ERR "cannot malloc\n"); -			return -1; +			usb_audio_err(chip, "cannot malloc\n"); +			return -ENOMEM;  		}  		fp->nr_rates = 0; @@ -173,13 +185,17 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof  			if (!rate)  				continue;  			/* C-Media CM6501 mislabels its 96 kHz altsetting */ +			/* Terratec Aureon 7.1 USB C-Media 6206, too */  			if (rate == 48000 && nr_rates == 1 &&  			    (chip->usb_id == USB_ID(0x0d8c, 0x0201) || -			     chip->usb_id == USB_ID(0x0d8c, 0x0102)) && +			     chip->usb_id == USB_ID(0x0d8c, 0x0102) || +			     chip->usb_id == USB_ID(0x0ccd, 0x00b1)) &&  			    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)) +			/* Creative VF0420/VF0470 Live Cams report 16 kHz instead of 8kHz */ +			if (rate == 16000 && +			    (chip->usb_id == USB_ID(0x041e, 0x4064) || +			     chip->usb_id == USB_ID(0x041e, 0x4068)))  				rate = 8000;  			fp->rate_table[fp->nr_rates] = rate; @@ -192,7 +208,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof  		}  		if (!fp->nr_rates) {  			hwc_debug("All rates were zero. Skipping format!\n"); -			return -1; +			return -EINVAL;  		}  	} else {  		/* continuous rates */ @@ -209,7 +225,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof   * get to know how many sample rates we have to expect.   * Then fp->rate_table can be allocated and filled.   */ -static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets, +static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, +					struct audioformat *fp, int nr_triplets,  					const unsigned char *data)  {  	int i, nr_rates = 0; @@ -220,7 +237,7 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,  		int min = combine_quad(&data[2 + 12 * i]);  		int max = combine_quad(&data[6 + 12 * i]);  		int res = combine_quad(&data[10 + 12 * i]); -		int rate; +		unsigned int rate;  		if ((max < 0) || (min < 0) || (res < 0) || (max < min))  			continue; @@ -247,6 +264,10 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,  			fp->rates |= snd_pcm_rate_to_rate_bit(rate);  			nr_rates++; +			if (nr_rates >= MAX_NR_RATES) { +				usb_audio_err(chip, "invalid uac2 rates\n"); +				break; +			}  			/* avoid endless loop */  			if (res == 0) @@ -267,10 +288,11 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,  	struct usb_device *dev = chip->dev;  	unsigned char tmp[2], *data;  	int nr_triplets, data_size, ret = 0; -	int clock = snd_usb_clock_find_source(chip, fp->clock); +	int clock = snd_usb_clock_find_source(chip, fp->clock, false);  	if (clock < 0) { -		snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n", +		dev_err(&dev->dev, +			"%s(): unable to find clock source (clock %d)\n",  				__func__, clock);  		goto err;  	} @@ -280,10 +302,11 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,  			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,  			      UAC2_CS_CONTROL_SAM_FREQ << 8,  			      snd_usb_ctrl_intf(chip) | (clock << 8), -			      tmp, sizeof(tmp), 1000); +			      tmp, sizeof(tmp));  	if (ret < 0) { -		snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", +		dev_err(&dev->dev, +			"%s(): unable to retrieve number of sample rates (clock %d)\n",  				__func__, clock);  		goto err;  	} @@ -301,10 +324,11 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,  			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,  			      UAC2_CS_CONTROL_SAM_FREQ << 8,  			      snd_usb_ctrl_intf(chip) | (clock << 8), -			      data, data_size, 1000); +			      data, data_size);  	if (ret < 0) { -		snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", +		dev_err(&dev->dev, +			"%s(): unable to retrieve sample rate range (clock %d)\n",  				__func__, clock);  		ret = -EINVAL;  		goto err_free; @@ -315,7 +339,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,  	 * will have to deal with. */  	kfree(fp->rate_table);  	fp->rate_table = NULL; -	fp->nr_rates = parse_uac2_sample_rate_range(fp, nr_triplets, data); +	fp->nr_rates = parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);  	if (fp->nr_rates == 0) {  		/* SNDRV_PCM_RATE_CONTINUOUS */ @@ -331,7 +355,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,  	/* Call the triplet parser again, but this time, fp->rate_table is  	 * allocated, so the rates will be stored */ -	parse_uac2_sample_rate_range(fp, nr_triplets, data); +	parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);  err_free:  	kfree(data); @@ -343,13 +367,11 @@ err:   * parse the format type I and III descriptors   */  static int parse_audio_format_i(struct snd_usb_audio *chip, -				struct audioformat *fp, int format, -				struct uac_format_type_i_continuous_descriptor *fmt, -				struct usb_host_interface *iface) +				struct audioformat *fp, unsigned int format, +				struct uac_format_type_i_continuous_descriptor *fmt)  { -	struct usb_interface_descriptor *altsd = get_iface_desc(iface); -	int protocol = altsd->bInterfaceProtocol; -	int pcm_format, ret; +	snd_pcm_format_t pcm_format; +	int ret;  	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {  		/* FIXME: the format type is really IECxxx @@ -368,12 +390,11 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,  		default:  			pcm_format = SNDRV_PCM_FORMAT_S16_LE;  		} -		fp->formats = 1uLL << pcm_format; +		fp->formats = pcm_format_to_bits(pcm_format);  	} else { -		fp->formats = parse_audio_format_i_type(chip, fp, format, -							fmt, protocol); +		fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);  		if (!fp->formats) -			return -1; +			return -EINVAL;  	}  	/* gather possible sample rates */ @@ -381,11 +402,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,  	 * proprietary class specific descriptor.  	 * audio class v2 uses class specific EP0 range requests for that.  	 */ -	switch (protocol) { +	switch (fp->protocol) {  	default: -		snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, protocol); -		/* fall through */  	case UAC_VERSION_1:  		fp->channels = fmt->bNrChannels;  		ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); @@ -397,9 +415,10 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,  	}  	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; +		usb_audio_err(chip, +			"%u:%d : invalid channels %d\n", +			fp->iface, fp->altsetting, fp->channels); +		return -EINVAL;  	}  	return ret; @@ -410,12 +429,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,   */  static int parse_audio_format_ii(struct snd_usb_audio *chip,  				 struct audioformat *fp, -				 int format, void *_fmt, -				 struct usb_host_interface *iface) +				 int format, void *_fmt)  {  	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: @@ -427,24 +443,22 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  		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); +		usb_audio_info(chip, +			 "%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n", +			 fp->iface, fp->altsetting, format);  		fp->formats = SNDRV_PCM_FMTBIT_MPEG;  		break;  	}  	fp->channels = 1; -	switch (protocol) { +	switch (fp->protocol) {  	default: -		snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", -			   chip->dev->devnum, fp->iface, fp->altsetting, protocol); -		/* fall through */  	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); +		usb_audio_info(chip, "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; @@ -453,7 +467,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  		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); +		usb_audio_info(chip, "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);  		break; @@ -463,24 +477,26 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  	return ret;  } -int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, -			       int format, struct uac_format_type_i_continuous_descriptor *fmt, -			       int stream, struct usb_host_interface *iface) +int snd_usb_parse_audio_format(struct snd_usb_audio *chip, +			       struct audioformat *fp, unsigned int format, +			       struct uac_format_type_i_continuous_descriptor *fmt, +			       int stream)  {  	int err;  	switch (fmt->bFormatType) {  	case UAC_FORMAT_TYPE_I:  	case UAC_FORMAT_TYPE_III: -		err = parse_audio_format_i(chip, fp, format, fmt, iface); +		err = parse_audio_format_i(chip, fp, format, fmt);  		break;  	case UAC_FORMAT_TYPE_II: -		err = parse_audio_format_ii(chip, fp, format, fmt, iface); +		err = parse_audio_format_ii(chip, fp, format, fmt);  		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->bFormatType); +		usb_audio_info(chip, +			 "%u:%d : format type %d is not supported yet\n", +			 fp->iface, fp->altsetting, +			 fmt->bFormatType);  		return -ENOTSUPP;  	}  	fp->fmt_type = fmt->bFormatType; diff --git a/sound/usb/format.h b/sound/usb/format.h index 387924f0af8..4b8a01129f2 100644 --- a/sound/usb/format.h +++ b/sound/usb/format.h @@ -2,8 +2,8 @@  #define __USBAUDIO_FORMAT_H  int snd_usb_parse_audio_format(struct snd_usb_audio *chip, -			       struct audioformat *fp, int format, +			       struct audioformat *fp, unsigned int format,  			       struct uac_format_type_i_continuous_descriptor *fmt, -			       int stream, struct usb_host_interface *iface); +			       int stream);  #endif /*  __USBAUDIO_FORMAT_H */ diff --git a/sound/usb/helper.c b/sound/usb/helper.c index f280c1903c2..51ed1ac825f 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -21,6 +21,7 @@  #include "usbaudio.h"  #include "helper.h" +#include "quirks.h"  /*   * combine bytes and get an integer value @@ -81,22 +82,34 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, 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) +		    __u16 size)  {  	int err;  	void *buf = NULL; +	int timeout;  	if (size > 0) {  		buf = kmemdup(data, size, GFP_KERNEL);  		if (!buf)  			return -ENOMEM;  	} + +	if (requesttype & USB_DIR_IN) +		timeout = USB_CTRL_GET_TIMEOUT; +	else +		timeout = USB_CTRL_SET_TIMEOUT; +  	err = usb_control_msg(dev, pipe, request, requesttype,  			      value, index, buf, size, timeout); +  	if (size > 0) {  		memcpy(data, buf, size);  		kfree(buf);  	} + +	snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype, +			      value, index, data, size); +  	return err;  } @@ -105,6 +118,7 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,  {  	switch (snd_usb_get_speed(chip->dev)) {  	case USB_SPEED_HIGH: +	case USB_SPEED_WIRELESS:  	case USB_SPEED_SUPER:  		if (get_endpoint(alts, 0)->bInterval >= 1 &&  		    get_endpoint(alts, 0)->bInterval <= 4) diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 09bd943c43b..805c300dd00 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -8,7 +8,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub  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); +		    void *data, __u16 size);  unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,  					 struct usb_host_interface *alts); diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile new file mode 100644 index 00000000000..463b136d1d8 --- /dev/null +++ b/sound/usb/hiface/Makefile @@ -0,0 +1,2 @@ +snd-usb-hiface-objs := chip.o pcm.o +obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c new file mode 100644 index 00000000000..2670d646bda --- /dev/null +++ b/sound/usb/hiface/chip.c @@ -0,0 +1,297 @@ +/* + * Linux driver for M2Tech hiFace compatible devices + * + * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. + * + * Authors:  Michael Trimarchi <michael@amarulasolutions.com> + *           Antonio Ospite <ao2@amarulasolutions.com> + * + * The driver is based on the work done in TerraTec DMX 6Fire USB + * + * 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. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <sound/initval.h> + +#include "chip.h" +#include "pcm.h" + +MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); +MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>"); +MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{M2Tech,Young}," +			 "{M2Tech,hiFace}," +			 "{M2Tech,North Star}," +			 "{M2Tech,W4S Young}," +			 "{M2Tech,Corrson}," +			 "{M2Tech,AUDIA}," +			 "{M2Tech,SL Audio}," +			 "{M2Tech,Empirical}," +			 "{M2Tech,Rockna}," +			 "{M2Tech,Pathos}," +			 "{M2Tech,Metronome}," +			 "{M2Tech,CAD}," +			 "{M2Tech,Audio Esclusive}," +			 "{M2Tech,Rotel}," +			 "{M2Tech,Eeaudio}," +			 "{The Chord Company,CHORD}," +			 "{AVA Group A/S,Vitus}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */ +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ + +#define DRIVER_NAME "snd-usb-hiface" +#define CARD_NAME "hiFace" + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); + +static DEFINE_MUTEX(register_mutex); + +struct hiface_vendor_quirk { +	const char *device_name; +	u8 extra_freq; +}; + +static int hiface_chip_create(struct usb_interface *intf, +			      struct usb_device *device, int idx, +			      const struct hiface_vendor_quirk *quirk, +			      struct hiface_chip **rchip) +{ +	struct snd_card *card = NULL; +	struct hiface_chip *chip; +	int ret; +	int len; + +	*rchip = NULL; + +	/* if we are here, card can be registered in alsa. */ +	ret = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, +			   sizeof(*chip), &card); +	if (ret < 0) { +		dev_err(&device->dev, "cannot create alsa card.\n"); +		return ret; +	} + +	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + +	if (quirk && quirk->device_name) +		strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname)); +	else +		strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname)); + +	strlcat(card->longname, card->shortname, sizeof(card->longname)); +	len = strlcat(card->longname, " at ", sizeof(card->longname)); +	if (len < sizeof(card->longname)) +		usb_make_path(device, card->longname + len, +			      sizeof(card->longname) - len); + +	chip = card->private_data; +	chip->dev = device; +	chip->card = card; + +	*rchip = chip; +	return 0; +} + +static int hiface_chip_probe(struct usb_interface *intf, +			     const struct usb_device_id *usb_id) +{ +	const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info; +	int ret; +	int i; +	struct hiface_chip *chip; +	struct usb_device *device = interface_to_usbdev(intf); + +	ret = usb_set_interface(device, 0, 0); +	if (ret != 0) { +		dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n"); +		return -EIO; +	} + +	/* check whether the card is already registered */ +	chip = NULL; +	mutex_lock(®ister_mutex); + +	for (i = 0; i < SNDRV_CARDS; i++) +		if (enable[i]) +			break; + +	if (i >= SNDRV_CARDS) { +		dev_err(&device->dev, "no available " CARD_NAME " audio device\n"); +		ret = -ENODEV; +		goto err; +	} + +	ret = hiface_chip_create(intf, device, i, quirk, &chip); +	if (ret < 0) +		goto err; + +	ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0); +	if (ret < 0) +		goto err_chip_destroy; + +	ret = snd_card_register(chip->card); +	if (ret < 0) { +		dev_err(&device->dev, "cannot register " CARD_NAME " card\n"); +		goto err_chip_destroy; +	} + +	mutex_unlock(®ister_mutex); + +	usb_set_intfdata(intf, chip); +	return 0; + +err_chip_destroy: +	snd_card_free(chip->card); +err: +	mutex_unlock(®ister_mutex); +	return ret; +} + +static void hiface_chip_disconnect(struct usb_interface *intf) +{ +	struct hiface_chip *chip; +	struct snd_card *card; + +	chip = usb_get_intfdata(intf); +	if (!chip) +		return; + +	card = chip->card; + +	/* Make sure that the userspace cannot create new request */ +	snd_card_disconnect(card); + +	hiface_pcm_abort(chip); +	snd_card_free_when_closed(card); +} + +static const struct usb_device_id device_table[] = { +	{ +		USB_DEVICE(0x04b4, 0x0384), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Young", +			.extra_freq = 1, +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x930b), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "hiFace", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x931b), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "North Star", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x931c), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "W4S Young", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x931d), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Corrson", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x931e), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "AUDIA", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x931f), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "SL Audio", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x9320), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Empirical", +		} +	}, +	{ +		USB_DEVICE(0x04b4, 0x9321), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Rockna", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x9001), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Pathos", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x9002), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Metronome", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x9006), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "CAD", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x9008), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Audio Esclusive", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x931c), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Rotel", +		} +	}, +	{ +		USB_DEVICE(0x249c, 0x932c), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Eeaudio", +		} +	}, +	{ +		USB_DEVICE(0x245f, 0x931c), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "CHORD", +		} +	}, +	{ +		USB_DEVICE(0x25c6, 0x9002), +		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { +			.device_name = "Vitus", +		} +	}, +	{} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +static struct usb_driver hiface_usb_driver = { +	.name = DRIVER_NAME, +	.probe = hiface_chip_probe, +	.disconnect = hiface_chip_disconnect, +	.id_table = device_table, +}; + +module_usb_driver(hiface_usb_driver); diff --git a/sound/usb/hiface/chip.h b/sound/usb/hiface/chip.h new file mode 100644 index 00000000000..189a1371b7c --- /dev/null +++ b/sound/usb/hiface/chip.h @@ -0,0 +1,30 @@ +/* + * Linux driver for M2Tech hiFace compatible devices + * + * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. + * + * Authors:  Michael Trimarchi <michael@amarulasolutions.com> + *           Antonio Ospite <ao2@amarulasolutions.com> + * + * The driver is based on the work done in TerraTec DMX 6Fire USB + * + * 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. + */ + +#ifndef HIFACE_CHIP_H +#define HIFACE_CHIP_H + +#include <linux/usb.h> +#include <sound/core.h> + +struct pcm_runtime; + +struct hiface_chip { +	struct usb_device *dev; +	struct snd_card *card; +	struct pcm_runtime *pcm; +}; +#endif /* HIFACE_CHIP_H */ diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c new file mode 100644 index 00000000000..2c44139b404 --- /dev/null +++ b/sound/usb/hiface/pcm.c @@ -0,0 +1,621 @@ +/* + * Linux driver for M2Tech hiFace compatible devices + * + * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. + * + * Authors:  Michael Trimarchi <michael@amarulasolutions.com> + *           Antonio Ospite <ao2@amarulasolutions.com> + * + * The driver is based on the work done in TerraTec DMX 6Fire USB + * + * 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. + */ + +#include <linux/slab.h> +#include <sound/pcm.h> + +#include "pcm.h" +#include "chip.h" + +#define OUT_EP          0x2 +#define PCM_N_URBS      8 +#define PCM_PACKET_SIZE 4096 +#define PCM_BUFFER_SIZE (2 * PCM_N_URBS * PCM_PACKET_SIZE) + +struct pcm_urb { +	struct hiface_chip *chip; + +	struct urb instance; +	struct usb_anchor submitted; +	u8 *buffer; +}; + +struct pcm_substream { +	spinlock_t lock; +	struct snd_pcm_substream *instance; + +	bool active; +	snd_pcm_uframes_t dma_off;    /* current position in alsa dma_area */ +	snd_pcm_uframes_t period_off; /* current position in current period */ +}; + +enum { /* pcm streaming states */ +	STREAM_DISABLED, /* no pcm streaming */ +	STREAM_STARTING, /* pcm streaming requested, waiting to become ready */ +	STREAM_RUNNING,  /* pcm streaming running */ +	STREAM_STOPPING +}; + +struct pcm_runtime { +	struct hiface_chip *chip; +	struct snd_pcm *instance; + +	struct pcm_substream playback; +	bool panic; /* if set driver won't do anymore pcm on device */ + +	struct pcm_urb out_urbs[PCM_N_URBS]; + +	struct mutex stream_mutex; +	u8 stream_state; /* one of STREAM_XXX */ +	u8 extra_freq; +	wait_queue_head_t stream_wait_queue; +	bool stream_wait_cond; +}; + +static const unsigned int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000, +				      352800, 384000 }; +static const struct snd_pcm_hw_constraint_list constraints_extra_rates = { +	.count = ARRAY_SIZE(rates), +	.list = rates, +	.mask = 0, +}; + +static const struct snd_pcm_hardware pcm_hw = { +	.info = SNDRV_PCM_INFO_MMAP | +		SNDRV_PCM_INFO_INTERLEAVED | +		SNDRV_PCM_INFO_BLOCK_TRANSFER | +		SNDRV_PCM_INFO_PAUSE | +		SNDRV_PCM_INFO_MMAP_VALID | +		SNDRV_PCM_INFO_BATCH, + +	.formats = SNDRV_PCM_FMTBIT_S32_LE, + +	.rates = SNDRV_PCM_RATE_44100 | +		SNDRV_PCM_RATE_48000 | +		SNDRV_PCM_RATE_88200 | +		SNDRV_PCM_RATE_96000 | +		SNDRV_PCM_RATE_176400 | +		SNDRV_PCM_RATE_192000, + +	.rate_min = 44100, +	.rate_max = 192000, /* changes in hiface_pcm_open to support extra rates */ +	.channels_min = 2, +	.channels_max = 2, +	.buffer_bytes_max = PCM_BUFFER_SIZE, +	.period_bytes_min = PCM_PACKET_SIZE, +	.period_bytes_max = PCM_BUFFER_SIZE, +	.periods_min = 2, +	.periods_max = 1024 +}; + +/* message values used to change the sample rate */ +#define HIFACE_SET_RATE_REQUEST 0xb0 + +#define HIFACE_RATE_44100  0x43 +#define HIFACE_RATE_48000  0x4b +#define HIFACE_RATE_88200  0x42 +#define HIFACE_RATE_96000  0x4a +#define HIFACE_RATE_176400 0x40 +#define HIFACE_RATE_192000 0x48 +#define HIFACE_RATE_352800 0x58 +#define HIFACE_RATE_384000 0x68 + +static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) +{ +	struct usb_device *device = rt->chip->dev; +	u16 rate_value; +	int ret; + +	/* We are already sure that the rate is supported here thanks to +	 * ALSA constraints +	 */ +	switch (rate) { +	case 44100: +		rate_value = HIFACE_RATE_44100; +		break; +	case 48000: +		rate_value = HIFACE_RATE_48000; +		break; +	case 88200: +		rate_value = HIFACE_RATE_88200; +		break; +	case 96000: +		rate_value = HIFACE_RATE_96000; +		break; +	case 176400: +		rate_value = HIFACE_RATE_176400; +		break; +	case 192000: +		rate_value = HIFACE_RATE_192000; +		break; +	case 352800: +		rate_value = HIFACE_RATE_352800; +		break; +	case 384000: +		rate_value = HIFACE_RATE_384000; +		break; +	default: +		dev_err(&device->dev, "Unsupported rate %d\n", rate); +		return -EINVAL; +	} + +	/* +	 * USBIO: Vendor 0xb0(wValue=0x0043, wIndex=0x0000) +	 * 43 b0 43 00 00 00 00 00 +	 * USBIO: Vendor 0xb0(wValue=0x004b, wIndex=0x0000) +	 * 43 b0 4b 00 00 00 00 00 +	 * This control message doesn't have any ack from the +	 * other side +	 */ +	ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), +			      HIFACE_SET_RATE_REQUEST, +			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			      rate_value, 0, NULL, 0, 100); +	if (ret < 0) { +		dev_err(&device->dev, "Error setting samplerate %d.\n", rate); +		return ret; +	} + +	return 0; +} + +static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream +						      *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct device *device = &rt->chip->dev->dev; + +	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) +		return &rt->playback; + +	dev_err(device, "Error getting pcm substream slot.\n"); +	return NULL; +} + +/* call with stream_mutex locked */ +static void hiface_pcm_stream_stop(struct pcm_runtime *rt) +{ +	int i, time; + +	if (rt->stream_state != STREAM_DISABLED) { +		rt->stream_state = STREAM_STOPPING; + +		for (i = 0; i < PCM_N_URBS; i++) { +			time = usb_wait_anchor_empty_timeout( +					&rt->out_urbs[i].submitted, 100); +			if (!time) +				usb_kill_anchored_urbs( +					&rt->out_urbs[i].submitted); +			usb_kill_urb(&rt->out_urbs[i].instance); +		} + +		rt->stream_state = STREAM_DISABLED; +	} +} + +/* call with stream_mutex locked */ +static int hiface_pcm_stream_start(struct pcm_runtime *rt) +{ +	int ret = 0; +	int i; + +	if (rt->stream_state == STREAM_DISABLED) { + +		/* reset panic state when starting a new stream */ +		rt->panic = false; + +		/* submit our out urbs zero init */ +		rt->stream_state = STREAM_STARTING; +		for (i = 0; i < PCM_N_URBS; i++) { +			memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE); +			usb_anchor_urb(&rt->out_urbs[i].instance, +				       &rt->out_urbs[i].submitted); +			ret = usb_submit_urb(&rt->out_urbs[i].instance, +					     GFP_ATOMIC); +			if (ret) { +				hiface_pcm_stream_stop(rt); +				return ret; +			} +		} + +		/* wait for first out urb to return (sent in in urb handler) */ +		wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, +				   HZ); +		if (rt->stream_wait_cond) { +			struct device *device = &rt->chip->dev->dev; +			dev_dbg(device, "%s: Stream is running wakeup event\n", +				 __func__); +			rt->stream_state = STREAM_RUNNING; +		} else { +			hiface_pcm_stream_stop(rt); +			return -EIO; +		} +	} +	return ret; +} + +/* The hardware wants word-swapped 32-bit values */ +static void memcpy_swahw32(u8 *dest, u8 *src, unsigned int n) +{ +	unsigned int i; + +	for (i = 0; i < n / 4; i++) +		((u32 *)dest)[i] = swahw32(((u32 *)src)[i]); +} + +/* call with substream locked */ +/* returns true if a period elapsed */ +static bool hiface_pcm_playback(struct pcm_substream *sub, struct pcm_urb *urb) +{ +	struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; +	struct device *device = &urb->chip->dev->dev; +	u8 *source; +	unsigned int pcm_buffer_size; + +	WARN_ON(alsa_rt->format != SNDRV_PCM_FORMAT_S32_LE); + +	pcm_buffer_size = snd_pcm_lib_buffer_bytes(sub->instance); + +	if (sub->dma_off + PCM_PACKET_SIZE <= pcm_buffer_size) { +		dev_dbg(device, "%s: (1) buffer_size %#x dma_offset %#x\n", __func__, +			 (unsigned int) pcm_buffer_size, +			 (unsigned int) sub->dma_off); + +		source = alsa_rt->dma_area + sub->dma_off; +		memcpy_swahw32(urb->buffer, source, PCM_PACKET_SIZE); +	} else { +		/* wrap around at end of ring buffer */ +		unsigned int len; + +		dev_dbg(device, "%s: (2) buffer_size %#x dma_offset %#x\n", __func__, +			 (unsigned int) pcm_buffer_size, +			 (unsigned int) sub->dma_off); + +		len = pcm_buffer_size - sub->dma_off; + +		source = alsa_rt->dma_area + sub->dma_off; +		memcpy_swahw32(urb->buffer, source, len); + +		source = alsa_rt->dma_area; +		memcpy_swahw32(urb->buffer + len, source, +			       PCM_PACKET_SIZE - len); +	} +	sub->dma_off += PCM_PACKET_SIZE; +	if (sub->dma_off >= pcm_buffer_size) +		sub->dma_off -= pcm_buffer_size; + +	sub->period_off += PCM_PACKET_SIZE; +	if (sub->period_off >= alsa_rt->period_size) { +		sub->period_off %= alsa_rt->period_size; +		return true; +	} +	return false; +} + +static void hiface_pcm_out_urb_handler(struct urb *usb_urb) +{ +	struct pcm_urb *out_urb = usb_urb->context; +	struct pcm_runtime *rt = out_urb->chip->pcm; +	struct pcm_substream *sub; +	bool do_period_elapsed = false; +	unsigned long flags; +	int ret; + +	if (rt->panic || rt->stream_state == STREAM_STOPPING) +		return; + +	if (unlikely(usb_urb->status == -ENOENT ||	/* unlinked */ +		     usb_urb->status == -ENODEV ||	/* device removed */ +		     usb_urb->status == -ECONNRESET ||	/* unlinked */ +		     usb_urb->status == -ESHUTDOWN)) {	/* device disabled */ +		goto out_fail; +	} + +	if (rt->stream_state == STREAM_STARTING) { +		rt->stream_wait_cond = true; +		wake_up(&rt->stream_wait_queue); +	} + +	/* now send our playback data (if a free out urb was found) */ +	sub = &rt->playback; +	spin_lock_irqsave(&sub->lock, flags); +	if (sub->active) +		do_period_elapsed = hiface_pcm_playback(sub, out_urb); +	else +		memset(out_urb->buffer, 0, PCM_PACKET_SIZE); + +	spin_unlock_irqrestore(&sub->lock, flags); + +	if (do_period_elapsed) +		snd_pcm_period_elapsed(sub->instance); + +	ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC); +	if (ret < 0) +		goto out_fail; + +	return; + +out_fail: +	rt->panic = true; +} + +static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = NULL; +	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; +	int ret; + +	if (rt->panic) +		return -EPIPE; + +	mutex_lock(&rt->stream_mutex); +	alsa_rt->hw = pcm_hw; + +	if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) +		sub = &rt->playback; + +	if (!sub) { +		struct device *device = &rt->chip->dev->dev; +		mutex_unlock(&rt->stream_mutex); +		dev_err(device, "Invalid stream type\n"); +		return -EINVAL; +	} + +	if (rt->extra_freq) { +		alsa_rt->hw.rates |= SNDRV_PCM_RATE_KNOT; +		alsa_rt->hw.rate_max = 384000; + +		/* explicit constraints needed as we added SNDRV_PCM_RATE_KNOT */ +		ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0, +						 SNDRV_PCM_HW_PARAM_RATE, +						 &constraints_extra_rates); +		if (ret < 0) { +			mutex_unlock(&rt->stream_mutex); +			return ret; +		} +	} + +	sub->instance = alsa_sub; +	sub->active = false; +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); +	unsigned long flags; + +	if (rt->panic) +		return 0; + +	mutex_lock(&rt->stream_mutex); +	if (sub) { +		hiface_pcm_stream_stop(rt); + +		/* deactivate substream */ +		spin_lock_irqsave(&sub->lock, flags); +		sub->instance = NULL; +		sub->active = false; +		spin_unlock_irqrestore(&sub->lock, flags); + +	} +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub, +				struct snd_pcm_hw_params *hw_params) +{ +	return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub, +						params_buffer_bytes(hw_params)); +} + +static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub) +{ +	return snd_pcm_lib_free_vmalloc_buffer(alsa_sub); +} + +static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); +	struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; +	int ret; + +	if (rt->panic) +		return -EPIPE; +	if (!sub) +		return -ENODEV; + +	mutex_lock(&rt->stream_mutex); + +	sub->dma_off = 0; +	sub->period_off = 0; + +	if (rt->stream_state == STREAM_DISABLED) { + +		ret = hiface_pcm_set_rate(rt, alsa_rt->rate); +		if (ret) { +			mutex_unlock(&rt->stream_mutex); +			return ret; +		} +		ret = hiface_pcm_stream_start(rt); +		if (ret) { +			mutex_unlock(&rt->stream_mutex); +			return ret; +		} +	} +	mutex_unlock(&rt->stream_mutex); +	return 0; +} + +static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) +{ +	struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); + +	if (rt->panic) +		return -EPIPE; +	if (!sub) +		return -ENODEV; + +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_START: +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		spin_lock_irq(&sub->lock); +		sub->active = true; +		spin_unlock_irq(&sub->lock); +		return 0; + +	case SNDRV_PCM_TRIGGER_STOP: +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		spin_lock_irq(&sub->lock); +		sub->active = false; +		spin_unlock_irq(&sub->lock); +		return 0; + +	default: +		return -EINVAL; +	} +} + +static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub) +{ +	struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); +	struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); +	unsigned long flags; +	snd_pcm_uframes_t dma_offset; + +	if (rt->panic || !sub) +		return SNDRV_PCM_POS_XRUN; + +	spin_lock_irqsave(&sub->lock, flags); +	dma_offset = sub->dma_off; +	spin_unlock_irqrestore(&sub->lock, flags); +	return bytes_to_frames(alsa_sub->runtime, dma_offset); +} + +static struct snd_pcm_ops pcm_ops = { +	.open = hiface_pcm_open, +	.close = hiface_pcm_close, +	.ioctl = snd_pcm_lib_ioctl, +	.hw_params = hiface_pcm_hw_params, +	.hw_free = hiface_pcm_hw_free, +	.prepare = hiface_pcm_prepare, +	.trigger = hiface_pcm_trigger, +	.pointer = hiface_pcm_pointer, +	.page = snd_pcm_lib_get_vmalloc_page, +	.mmap = snd_pcm_lib_mmap_vmalloc, +}; + +static int hiface_pcm_init_urb(struct pcm_urb *urb, +			       struct hiface_chip *chip, +			       unsigned int ep, +			       void (*handler)(struct urb *)) +{ +	urb->chip = chip; +	usb_init_urb(&urb->instance); + +	urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL); +	if (!urb->buffer) +		return -ENOMEM; + +	usb_fill_bulk_urb(&urb->instance, chip->dev, +			  usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, +			  PCM_PACKET_SIZE, handler, urb); +	init_usb_anchor(&urb->submitted); + +	return 0; +} + +void hiface_pcm_abort(struct hiface_chip *chip) +{ +	struct pcm_runtime *rt = chip->pcm; + +	if (rt) { +		rt->panic = true; + +		mutex_lock(&rt->stream_mutex); +		hiface_pcm_stream_stop(rt); +		mutex_unlock(&rt->stream_mutex); +	} +} + +static void hiface_pcm_destroy(struct hiface_chip *chip) +{ +	struct pcm_runtime *rt = chip->pcm; +	int i; + +	for (i = 0; i < PCM_N_URBS; i++) +		kfree(rt->out_urbs[i].buffer); + +	kfree(chip->pcm); +	chip->pcm = NULL; +} + +static void hiface_pcm_free(struct snd_pcm *pcm) +{ +	struct pcm_runtime *rt = pcm->private_data; + +	if (rt) +		hiface_pcm_destroy(rt->chip); +} + +int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) +{ +	int i; +	int ret; +	struct snd_pcm *pcm; +	struct pcm_runtime *rt; + +	rt = kzalloc(sizeof(*rt), GFP_KERNEL); +	if (!rt) +		return -ENOMEM; + +	rt->chip = chip; +	rt->stream_state = STREAM_DISABLED; +	if (extra_freq) +		rt->extra_freq = 1; + +	init_waitqueue_head(&rt->stream_wait_queue); +	mutex_init(&rt->stream_mutex); +	spin_lock_init(&rt->playback.lock); + +	for (i = 0; i < PCM_N_URBS; i++) +		hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, +				    hiface_pcm_out_urb_handler); + +	ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); +	if (ret < 0) { +		kfree(rt); +		dev_err(&chip->dev->dev, "Cannot create pcm instance\n"); +		return ret; +	} + +	pcm->private_data = rt; +	pcm->private_free = hiface_pcm_free; + +	strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name)); +	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); + +	rt->instance = pcm; + +	chip->pcm = rt; +	return 0; +} diff --git a/sound/usb/hiface/pcm.h b/sound/usb/hiface/pcm.h new file mode 100644 index 00000000000..77edd7c12e1 --- /dev/null +++ b/sound/usb/hiface/pcm.h @@ -0,0 +1,24 @@ +/* + * Linux driver for M2Tech hiFace compatible devices + * + * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. + * + * Authors:  Michael Trimarchi <michael@amarulasolutions.com> + *           Antonio Ospite <ao2@amarulasolutions.com> + * + * The driver is based on the work done in TerraTec DMX 6Fire USB + * + * 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. + */ + +#ifndef HIFACE_PCM_H +#define HIFACE_PCM_H + +struct hiface_chip; + +int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq); +void hiface_pcm_abort(struct hiface_chip *chip); +#endif /* HIFACE_PCM_H */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 25bce7e5b1a..9da74d2e8ee 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -47,6 +47,7 @@  #include <linux/usb.h>  #include <linux/wait.h>  #include <linux/usb/audio.h> +#include <linux/module.h>  #include <sound/core.h>  #include <sound/control.h> @@ -54,6 +55,7 @@  #include <sound/asequencer.h>  #include "usbaudio.h"  #include "midi.h" +#include "power.h"  #include "helper.h"  /* @@ -114,6 +116,7 @@ struct snd_usb_midi {  	struct list_head list;  	struct timer_list error_timer;  	spinlock_t disc_lock; +	struct rw_semaphore disc_rwsem;  	struct mutex mutex;  	u32 usb_id;  	int next_midi_device; @@ -123,8 +126,9 @@ struct snd_usb_midi {  		struct snd_usb_midi_in_endpoint *in;  	} endpoints[MIDI_MAX_ENDPOINTS];  	unsigned long input_triggered; -	unsigned int opened; +	unsigned int opened[2];  	unsigned char disconnected; +	unsigned char input_running;  	struct snd_kcontrol *roland_load_ctl;  }; @@ -187,16 +191,16 @@ static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags)  {  	int err = usb_submit_urb(urb, flags);  	if (err < 0 && err != -ENODEV) -		snd_printk(KERN_ERR "usb_submit_urb: %d\n", err); +		dev_err(&urb->dev->dev, "usb_submit_urb: %d\n", err);  	return err;  }  /*   * Error handling for URB completion functions.   */ -static int snd_usbmidi_urb_error(int status) +static int snd_usbmidi_urb_error(const struct urb *urb)  { -	switch (status) { +	switch (urb->status) {  	/* manually unlinked, or device gone */  	case -ENOENT:  	case -ECONNRESET: @@ -209,7 +213,7 @@ static int snd_usbmidi_urb_error(int status)  	case -EILSEQ:  		return -EIO;  	default: -		snd_printk(KERN_ERR "urb status %d\n", status); +		dev_err(&urb->dev->dev, "urb status %d\n", urb->status);  		return 0; /* continue */  	}  } @@ -223,7 +227,7 @@ static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint* ep, int port  	struct usbmidi_in_port* port = &ep->ports[portidx];  	if (!port->substream) { -		snd_printd("unexpected port %d!\n", portidx); +		dev_dbg(&ep->umidi->dev->dev, "unexpected port %d!\n", portidx);  		return;  	}  	if (!test_bit(port->substream->number, &ep->umidi->input_triggered)) @@ -255,7 +259,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)  		ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,  						   urb->actual_length);  	} else { -		int err = snd_usbmidi_urb_error(urb->status); +		int err = snd_usbmidi_urb_error(urb);  		if (err < 0) {  			if (err != -ENODEV) {  				ep->error_resubmit = 1; @@ -285,7 +289,7 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)  	}  	spin_unlock(&ep->buffer_lock);  	if (urb->status < 0) { -		int err = snd_usbmidi_urb_error(urb->status); +		int err = snd_usbmidi_urb_error(urb);  		if (err < 0) {  			if (err != -ENODEV)  				mod_timer(&ep->umidi->error_timer, @@ -815,6 +819,22 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = {  	.output = snd_usbmidi_raw_output,  }; +/* + * FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes. + */ + +static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint* ep, +				   uint8_t* buffer, int buffer_length) +{ +	if (buffer_length > 2) +		snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); +} + +static struct usb_protocol_ops snd_usbmidi_ftdi_ops = { +	.input = snd_usbmidi_ftdi_input, +	.output = snd_usbmidi_raw_output, +}; +  static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,  				     uint8_t *buffer, int buffer_length)  { @@ -850,8 +870,8 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,  		return;  	} -	memset(urb->transfer_buffer + count, 0xFD, 9 - count); -	urb->transfer_buffer_length = count; +	memset(urb->transfer_buffer + count, 0xFD, ep->max_transfer - count); +	urb->transfer_buffer_length = ep->max_transfer;  }  static struct usb_protocol_ops snd_usbmidi_122l_ops = { @@ -1014,29 +1034,48 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)  	snd_usbmidi_input_start(&umidi->list);  } -static void substream_open(struct snd_rawmidi_substream *substream, int open) +static int substream_open(struct snd_rawmidi_substream *substream, int dir, +			  int open)  {  	struct snd_usb_midi* umidi = substream->rmidi->private_data;  	struct snd_kcontrol *ctl; +	down_read(&umidi->disc_rwsem); +	if (umidi->disconnected) { +		up_read(&umidi->disc_rwsem); +		return open ? -ENODEV : 0; +	} +  	mutex_lock(&umidi->mutex);  	if (open) { -		if (umidi->opened++ == 0 && umidi->roland_load_ctl) { -			ctl = umidi->roland_load_ctl; -			ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; -			snd_ctl_notify(umidi->card, +		if (!umidi->opened[0] && !umidi->opened[1]) { +			if (umidi->roland_load_ctl) { +				ctl = umidi->roland_load_ctl; +				ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; +				snd_ctl_notify(umidi->card,  				       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); -			update_roland_altsetting(umidi); +				update_roland_altsetting(umidi); +			}  		} +		umidi->opened[dir]++; +		if (umidi->opened[1]) +			snd_usbmidi_input_start(&umidi->list);  	} else { -		if (--umidi->opened == 0 && umidi->roland_load_ctl) { -			ctl = umidi->roland_load_ctl; -			ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; -			snd_ctl_notify(umidi->card, +		umidi->opened[dir]--; +		if (!umidi->opened[1]) +			snd_usbmidi_input_stop(&umidi->list); +		if (!umidi->opened[0] && !umidi->opened[1]) { +			if (umidi->roland_load_ctl) { +				ctl = umidi->roland_load_ctl; +				ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; +				snd_ctl_notify(umidi->card,  				       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); +			}  		}  	}  	mutex_unlock(&umidi->mutex); +	up_read(&umidi->disc_rwsem); +	return 0;  }  static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) @@ -1056,16 +1095,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)  		snd_BUG();  		return -ENXIO;  	} +  	substream->runtime->private_data = port;  	port->state = STATE_UNKNOWN; -	substream_open(substream, 1); -	return 0; +	return substream_open(substream, 0, 1);  }  static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 0); -	return 0; +	return substream_open(substream, 0, 0);  }  static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1118,14 +1156,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)  static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 1); -	return 0; +	return substream_open(substream, 1, 1);  }  static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 0); -	return 0; +	return substream_open(substream, 1, 0);  }  static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1293,8 +1329,16 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,  	case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */  	case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */  	case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ +	case USB_ID(0xfc08, 0x0101): /* Unknown vendor Cable */  		ep->max_transfer = 4;  		break; +		/* +		 * Some devices only work with 9 bytes packet size: +		 */ +	case USB_ID(0x0644, 0x800E): /* Tascam US-122L */ +	case USB_ID(0x0644, 0x800F): /* Tascam US-144 */ +		ep->max_transfer = 9; +		break;  	}  	for (i = 0; i < OUTPUT_URBS; ++i) {  		buffer = usb_alloc_coherent(umidi->dev, @@ -1366,9 +1410,12 @@ void snd_usbmidi_disconnect(struct list_head* p)  	 * a timer may submit an URB. To reliably break the cycle  	 * a flag under lock must be used  	 */ +	down_write(&umidi->disc_rwsem);  	spin_lock_irq(&umidi->disc_lock);  	umidi->disconnected = 1;  	spin_unlock_irq(&umidi->disc_lock); +	up_write(&umidi->disc_rwsem); +  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {  		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];  		if (ep->out) @@ -1397,6 +1444,7 @@ void snd_usbmidi_disconnect(struct list_head* p)  	}  	del_timer_sync(&umidi->error_timer);  } +EXPORT_SYMBOL(snd_usbmidi_disconnect);  static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)  { @@ -1407,10 +1455,9 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)  static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,  								int stream, int number)  { -	struct list_head* list; +	struct snd_rawmidi_substream *substream; -	list_for_each(list, &umidi->rmidi->streams[stream].substreams) { -		struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list); +	list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, list) {  		if (substream->number == number)  			return substream;  	} @@ -1528,8 +1575,41 @@ static struct port_info {  	EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),  	EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),  	EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"), +	/* BOSS GT-PRO */ +	CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),  	/* Edirol UM-3EX */  	CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"), +	/* Roland VG-99 */ +	CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"), +	/* Cakewalk Sonar V-Studio 100 */ +	EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"), +	/* Roland VB-99 */ +	CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"), +	/* Roland A-PRO */ +	EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"), +	CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"), +	/* Roland SD-50 */ +	ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128), +	EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"), +	/* Roland OCTA-CAPTURE */ +	EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"), +	/* Roland SPD-SX */ +	CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"), +	/* Roland A-Series */ +	CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"), +	EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"), +	/* Roland INTEGRA-7 */ +	ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128), +	CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),  	/* M-Audio MidiSport 8x8 */  	CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),  	CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"), @@ -1588,7 +1668,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,  	struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);  	if (!substream) { -		snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number); +		dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, number);  		return;  	} @@ -1637,7 +1717,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi,  			}  		}  	} -	snd_printdd(KERN_INFO "created %d output and %d input ports\n", +	dev_dbg(&umidi->dev->dev, "created %d output and %d input ports\n",  		    out_ports, in_ports);  	return 0;  } @@ -1667,10 +1747,11 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  	    ms_header->bLength >= 7 &&  	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&  	    ms_header->bDescriptorSubtype == UAC_HEADER) -		snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", +		dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n",  			    ms_header->bcdMSC[1], ms_header->bcdMSC[0]);  	else -		snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n"); +		dev_warn(&umidi->dev->dev, +			 "MIDIStreaming interface descriptor not found\n");  	epidx = 0;  	for (i = 0; i < intfd->bNumEndpoints; ++i) { @@ -1687,7 +1768,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  		if (usb_endpoint_dir_out(ep)) {  			if (endpoints[epidx].out_ep) {  				if (++epidx >= MIDI_MAX_ENDPOINTS) { -					snd_printk(KERN_WARNING "too many endpoints\n"); +					dev_warn(&umidi->dev->dev, +						 "too many endpoints\n");  					break;  				}  			} @@ -1702,12 +1784,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  				 */  				endpoints[epidx].out_interval = 1;  			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; -			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", +			dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",  				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);  		} else {  			if (endpoints[epidx].in_ep) {  				if (++epidx >= MIDI_MAX_ENDPOINTS) { -					snd_printk(KERN_WARNING "too many endpoints\n"); +					dev_warn(&umidi->dev->dev, +						 "too many endpoints\n");  					break;  				}  			} @@ -1717,7 +1800,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  			else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)  				endpoints[epidx].in_interval = 1;  			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; -			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", +			dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",  				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);  		}  	} @@ -1729,13 +1812,7 @@ static int roland_load_info(struct snd_kcontrol *kcontrol,  {  	static const char *const names[] = { "High Load", "Light Load" }; -	info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; -	info->count = 1; -	info->value.enumerated.items = 2; -	if (info->value.enumerated.item > 1) -		info->value.enumerated.item = 1; -	strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); -	return 0; +	return snd_ctl_enum_info(info, 1, 2, names);  }  static int roland_load_get(struct snd_kcontrol *kcontrol, @@ -1791,7 +1868,7 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)  	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)  		return; -	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", +	dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n",  		    intfd->bAlternateSetting);  	usb_set_interface(umidi->dev, intfd->bInterfaceNumber,  			  intfd->bAlternateSetting); @@ -1907,6 +1984,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,  }  /* + * Detects the endpoints and ports of Roland devices. + */ +static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi, +				     struct snd_usb_midi_endpoint_info* endpoint) +{ +	struct usb_interface* intf; +	struct usb_host_interface *hostif; +	u8* cs_desc; + +	intf = umidi->iface; +	if (!intf) +		return -ENOENT; +	hostif = intf->altsetting; +	/* +	 * Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>, +	 * some have standard class descriptors, or both kinds, or neither. +	 */ +	for (cs_desc = hostif->extra; +	     cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; +	     cs_desc += cs_desc[0]) { +		if (cs_desc[0] >= 6 && +		    cs_desc[1] == USB_DT_CS_INTERFACE && +		    cs_desc[2] == 0xf1 && +		    cs_desc[3] == 0x02) { +			endpoint->in_cables  = (1 << cs_desc[4]) - 1; +			endpoint->out_cables = (1 << cs_desc[5]) - 1; +			return snd_usbmidi_detect_endpoints(umidi, endpoint, 1); +		} else if (cs_desc[0] >= 7 && +			   cs_desc[1] == USB_DT_CS_INTERFACE && +			   cs_desc[2] == UAC_HEADER) { +			return snd_usbmidi_get_ms_info(umidi, endpoint); +		} +	} + +	return -ENODEV; +} + +/*   * Creates the endpoints and their ports for Midiman devices.   */  static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, @@ -1935,25 +2050,25 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,  	 * input bulk endpoints (at indices 1 and 3) which aren't used.  	 */  	if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) { -		snd_printdd(KERN_ERR "not enough endpoints\n"); +		dev_dbg(&umidi->dev->dev, "not enough endpoints\n");  		return -ENOENT;  	}  	epd = get_endpoint(hostif, 0);  	if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) { -		snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n"); +		dev_dbg(&umidi->dev->dev, "endpoint[0] isn't interrupt\n");  		return -ENXIO;  	}  	epd = get_endpoint(hostif, 2);  	if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) { -		snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n"); +		dev_dbg(&umidi->dev->dev, "endpoint[2] isn't bulk output\n");  		return -ENXIO;  	}  	if (endpoint->out_cables > 0x0001) {  		epd = get_endpoint(hostif, 4);  		if (!usb_endpoint_dir_out(epd) ||  		    !usb_endpoint_xfer_bulk(epd)) { -			snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n"); +			dev_dbg(&umidi->dev->dev, "endpoint[4] isn't bulk output\n");  			return -ENXIO;  		}  	} @@ -2029,13 +2144,17 @@ void snd_usbmidi_input_stop(struct list_head* p)  	unsigned int i, j;  	umidi = list_entry(p, struct snd_usb_midi, list); +	if (!umidi->input_running) +		return;  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {  		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];  		if (ep->in)  			for (j = 0; j < INPUT_URBS; ++j)  				usb_kill_urb(ep->in->urbs[j]);  	} +	umidi->input_running = 0;  } +EXPORT_SYMBOL(snd_usbmidi_input_stop);  static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)  { @@ -2059,9 +2178,13 @@ void snd_usbmidi_input_start(struct list_head* p)  	int i;  	umidi = list_entry(p, struct snd_usb_midi, list); +	if (umidi->input_running || !umidi->opened[1]) +		return;  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)  		snd_usbmidi_input_start_ep(umidi->endpoints[i].in); +	umidi->input_running = 1;  } +EXPORT_SYMBOL(snd_usbmidi_input_start);  /*   * Creates and registers everything needed for a MIDI streaming interface. @@ -2086,6 +2209,7 @@ int snd_usbmidi_create(struct snd_card *card,  	umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;  	init_timer(&umidi->error_timer);  	spin_lock_init(&umidi->disc_lock); +	init_rwsem(&umidi->disc_rwsem);  	mutex_init(&umidi->mutex);  	umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),  			       le16_to_cpu(umidi->dev->descriptor.idProduct)); @@ -2112,6 +2236,9 @@ int snd_usbmidi_create(struct snd_card *card,  	case QUIRK_MIDI_YAMAHA:  		err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);  		break; +	case QUIRK_MIDI_ROLAND: +		err = snd_usbmidi_detect_roland(umidi, &endpoints[0]); +		break;  	case QUIRK_MIDI_MIDIMAN:  		umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;  		memcpy(&endpoints[0], quirk->data, @@ -2153,8 +2280,19 @@ int snd_usbmidi_create(struct snd_card *card,  		/* endpoint 1 is input-only */  		endpoints[1].out_cables = 0;  		break; +	case QUIRK_MIDI_FTDI: +		umidi->usb_protocol_ops = &snd_usbmidi_ftdi_ops; + +		/* set baud rate to 31250 (48 MHz / 16 / 96) */ +		err = usb_control_msg(umidi->dev, usb_sndctrlpipe(umidi->dev, 0), +				      3, 0x40, 0x60, 0, NULL, 0, 1000); +		if (err < 0) +			break; + +		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); +		break;  	default: -		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); +		dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type);  		err = -ENXIO;  		break;  	} @@ -2186,14 +2324,9 @@ int snd_usbmidi_create(struct snd_card *card,  		return err;  	} -	list_add_tail(&umidi->list, midi_list); +	usb_autopm_get_interface_no_resume(umidi->iface); -	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) -		snd_usbmidi_input_start_ep(umidi->endpoints[i].in); +	list_add_tail(&umidi->list, midi_list);  	return 0;  } -  EXPORT_SYMBOL(snd_usbmidi_create); -EXPORT_SYMBOL(snd_usbmidi_input_stop); -EXPORT_SYMBOL(snd_usbmidi_input_start); -EXPORT_SYMBOL(snd_usbmidi_disconnect); diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index fb5d68fa7ff..a1bab149df4 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -52,7 +52,7 @@ MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}");  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;  static unsigned int queue_length = 21;  module_param_array(index, int, NULL, 0444); @@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream)  	unsigned int i;  	for (i = 0; i < stream->queue_length; ++i) -		usb_kill_urb(&stream->urbs[i]->urb); +		if (stream->urbs[i]) +			usb_kill_urb(&stream->urbs[i]->urb);  }  static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) @@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index)  {  	struct usb_host_interface *alts; +	if (!ua->intf[intf_index]) +		return; +  	alts = ua->intf[intf_index]->cur_altsetting;  	if (alts->desc.bAlternateSetting != 0) {  		int err = usb_set_interface(ua->dev, @@ -609,14 +613,24 @@ static int start_usb_playback(struct ua101 *ua)  static void abort_alsa_capture(struct ua101 *ua)  { -	if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) +	unsigned long flags; + +	if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) { +		snd_pcm_stream_lock_irqsave(ua->capture.substream, flags);  		snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); +		snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags); +	}  }  static void abort_alsa_playback(struct ua101 *ua)  { -	if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) +	unsigned long flags; + +	if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) { +		snd_pcm_stream_lock_irqsave(ua->playback.substream, flags);  		snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); +		snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags); +	}  }  static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, @@ -645,7 +659,7 @@ static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,  	err = snd_pcm_hw_constraint_minmax(substream->runtime,  					   SNDRV_PCM_HW_PARAM_PERIOD_TIME,  					   1500000 / ua->packets_per_second, -					   8192000); +					   UINT_MAX);  	if (err < 0)  		return err;  	err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); @@ -1116,8 +1130,7 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream,  			usb_init_urb(&urb->urb);  			urb->urb.dev = ua->dev;  			urb->urb.pipe = stream->usb_pipe; -			urb->urb.transfer_flags = URB_ISO_ASAP | -					URB_NO_TRANSFER_DMA_MAP; +			urb->urb.transfer_flags = URB_NO_TRANSFER_DMA_MAP;  			urb->urb.transfer_buffer = addr;  			urb->urb.transfer_dma = dma;  			urb->urb.transfer_buffer_length = max_packet_size; @@ -1144,27 +1157,37 @@ static void free_stream_urbs(struct ua101_stream *stream)  {  	unsigned int i; -	for (i = 0; i < stream->queue_length; ++i) +	for (i = 0; i < stream->queue_length; ++i) {  		kfree(stream->urbs[i]); +		stream->urbs[i] = NULL; +	}  }  static void free_usb_related_resources(struct ua101 *ua,  				       struct usb_interface *interface)  {  	unsigned int i; +	struct usb_interface *intf; +	mutex_lock(&ua->mutex);  	free_stream_urbs(&ua->capture);  	free_stream_urbs(&ua->playback); +	mutex_unlock(&ua->mutex);  	free_stream_buffers(ua, &ua->capture);  	free_stream_buffers(ua, &ua->playback); -	for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) -		if (ua->intf[i]) { -			usb_set_intfdata(ua->intf[i], NULL); -			if (ua->intf[i] != interface) +	for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { +		mutex_lock(&ua->mutex); +		intf = ua->intf[i]; +		ua->intf[i] = NULL; +		mutex_unlock(&ua->mutex); +		if (intf) { +			usb_set_intfdata(intf, NULL); +			if (intf != interface)  				usb_driver_release_interface(&ua101_driver, -							     ua->intf[i]); +							     intf);  		} +	}  }  static void ua101_card_free(struct snd_card *card) @@ -1220,8 +1243,9 @@ static int ua101_probe(struct usb_interface *interface,  		mutex_unlock(&devices_mutex);  		return -ENOENT;  	} -	err = snd_card_create(index[card_index], id[card_index], THIS_MODULE, -			      sizeof(*ua), &card); +	err = snd_card_new(&interface->dev, +			   index[card_index], id[card_index], THIS_MODULE, +			   sizeof(*ua), &card);  	if (err < 0) {  		mutex_unlock(&devices_mutex);  		return err; @@ -1260,8 +1284,6 @@ static int ua101_probe(struct usb_interface *interface,  		}  	} -	snd_card_set_dev(card, &interface->dev); -  	err = detect_usb_format(ua);  	if (err < 0)  		goto probe_error; @@ -1336,7 +1358,7 @@ static void ua101_disconnect(struct usb_interface *interface)  	snd_card_disconnect(ua->card);  	/* make sure that there are no pending USB requests */ -	__list_for_each(midi, &ua->midi_list) +	list_for_each(midi, &ua->midi_list)  		snd_usbmidi_disconnect(midi);  	abort_alsa_playback(ua);  	abort_alsa_capture(ua); @@ -1373,16 +1395,4 @@ static struct usb_driver ua101_driver = {  #endif  }; -static int __init alsa_card_ua101_init(void) -{ -	return usb_register(&ua101_driver); -} - -static void __exit alsa_card_ua101_exit(void) -{ -	usb_deregister(&ua101_driver); -	mutex_destroy(&devices_mutex); -} - -module_init(alsa_card_ua101_init); -module_exit(alsa_card_ua101_exit); +module_usb_driver(ua101_driver); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index f2d74d654b3..0b728d886f0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -61,6 +61,7 @@  #include "mixer.h"  #include "helper.h"  #include "mixer_quirks.h" +#include "power.h"  #define MAX_ID_ELEMS	256 @@ -85,17 +86,7 @@ struct mixer_build {  	const struct usbmix_selector_map *selector_map;  }; -enum { -	USB_MIXER_BOOLEAN, -	USB_MIXER_INV_BOOLEAN, -	USB_MIXER_S8, -	USB_MIXER_U8, -	USB_MIXER_S16, -	USB_MIXER_U16, -}; - - -/*E-mu 0202(0404) eXtension Unit(XU) control*/ +/*E-mu 0202/0404/0204 eXtension Unit(XU) control*/  enum {  	USB_XU_CLOCK_RATE 		= 0xe301,  	USB_XU_CLOCK_SOURCE		= 0xe302, @@ -161,6 +152,7 @@ static inline void check_mapped_dB(const struct usbmix_name_map *p,  	if (p && p->dB) {  		cval->dBmin = p->dB->min;  		cval->dBmax = p->dB->max; +		cval->initialized = 1;  	}  } @@ -170,7 +162,7 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,  {  	const struct usbmix_selector_map *p; -	if (! state->selector_map) +	if (!state->selector_map)  		return 0;  	for (p = state->selector_map; p->id; p++) {  		if (p->id == unitid && index < p->count) @@ -182,7 +174,8 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,  /*   * find an audio control unit with the given unit id   */ -static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) +static void *find_audio_control_unit(struct mixer_build *state, +				     unsigned char unit)  {  	/* we just parse the header */  	struct uac_feature_unit_descriptor *hdr = NULL; @@ -202,7 +195,8 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un  /*   * copy a string with the given id   */ -static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen) +static int snd_usb_copy_string_desc(struct mixer_build *state, +				    int index, char *buf, int maxlen)  {  	int len = usb_string(state->chip->dev, index, buf, maxlen - 1);  	buf[len] = 0; @@ -261,7 +255,7 @@ static int convert_bytes_value(struct usb_mixer_elem_info *cval, int val)  static int get_relative_value(struct usb_mixer_elem_info *cval, int val)  { -	if (! cval->res) +	if (!cval->res)  		cval->res = 1;  	if (val < cval->min)  		return 0; @@ -275,7 +269,7 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)  {  	if (val < 0)  		return cval->min; -	if (! cval->res) +	if (!cval->res)  		cval->res = 1;  	val *= cval->res;  	val += cval->min; @@ -289,33 +283,50 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)   * retrieve a mixer value   */ -static int get_ctl_value_v1(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)  {  	struct snd_usb_audio *chip = cval->mixer->chip;  	unsigned char buf[2];  	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;  	int timeout = 10; +	int idx = 0, err; +	err = snd_usb_autoresume(cval->mixer->chip); +	if (err < 0) +		return -EIO; + +	down_read(&chip->shutdown_rwsem);  	while (timeout-- > 0) { +		if (chip->shutdown) +			break; +		idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);  		if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,  				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, -				    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), -				    buf, val_len, 100) >= val_len) { +				    validx, idx, buf, val_len) >= val_len) {  			*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); -			return 0; +			err = 0; +			goto out;  		}  	} -	snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", -		    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); -	return -EINVAL; +	usb_audio_dbg(chip, +		"cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", +		request, validx, idx, cval->val_type); +	err = -EINVAL; + + out: +	up_read(&chip->shutdown_rwsem); +	snd_usb_autosuspend(cval->mixer->chip); +	return err;  } -static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) +static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, +			    int validx, int *value_ret)  {  	struct snd_usb_audio *chip = cval->mixer->chip; -	unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ +	unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */  	unsigned char *val; -	int ret, size; +	int idx = 0, ret, size;  	__u8 bRequest;  	if (request == UAC_GET_CUR) { @@ -328,14 +339,27 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v  	memset(buf, 0, sizeof(buf)); -	ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, +	ret = snd_usb_autoresume(chip) ? -EIO : 0; +	if (ret) +		goto error; + +	down_read(&chip->shutdown_rwsem); +	if (chip->shutdown) { +		ret = -ENODEV; +	} else { +		idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); +		ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,  			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, -			      validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), -			      buf, size, 1000); +			      validx, idx, buf, size); +	} +	up_read(&chip->shutdown_rwsem); +	snd_usb_autosuspend(chip);  	if (ret < 0) { -		snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", -			   request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); +error: +		usb_audio_err(chip, +			"cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", +			request, validx, idx, cval->val_type);  		return ret;  	} @@ -363,14 +387,18 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v  	return 0;  } -static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) +static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, +			 int validx, int *value_ret)  { +	validx += cval->idx_off; +  	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) +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);  } @@ -379,7 +407,9 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *  static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,  				  int channel, int *value)  { -	return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value); +	return get_ctl_value(cval, UAC_GET_CUR, +			     (cval->control << 8) | channel, +			     value);  }  static int get_cur_mix_value(struct usb_mixer_elem_info *cval, @@ -394,8 +424,9 @@ 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", -				   cval->control, channel, err); +			usb_audio_dbg(cval->mixer->chip, +				"cannot get current value for control %d ch %d: err = %d\n", +				      cval->control, channel, err);  		return err;  	}  	cval->cached |= 1 << channel; @@ -403,7 +434,6 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,  	return 0;  } -  /*   * set a mixer value   */ @@ -413,7 +443,9 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,  {  	struct snd_usb_audio *chip = cval->mixer->chip;  	unsigned char buf[2]; -	int val_len, timeout = 10; +	int idx = 0, val_len, err, timeout = 10; + +	validx += cval->idx_off;  	if (cval->mixer->protocol == UAC_VERSION_1) {  		val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; @@ -423,7 +455,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,  		/* FIXME */  		if (request != UAC_SET_CUR) { -			snd_printdd(KERN_WARNING "RANGE setting not yet supported\n"); +			usb_audio_dbg(chip, "RANGE setting not yet supported\n");  			return -EINVAL;  		} @@ -433,19 +465,34 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,  	value_set = convert_bytes_value(cval, value_set);  	buf[0] = value_set & 0xff;  	buf[1] = (value_set >> 8) & 0xff; -	while (timeout-- > 0) +	err = snd_usb_autoresume(chip); +	if (err < 0) +		return -EIO; +	down_read(&chip->shutdown_rwsem); +	while (timeout-- > 0) { +		if (chip->shutdown) +			break; +		idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);  		if (snd_usb_ctl_msg(chip->dev,  				    usb_sndctrlpipe(chip->dev, 0), request,  				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, -				    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), -				    buf, val_len, 100) >= 0) -			return 0; -	snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", -		    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); -	return -EINVAL; +				    validx, idx, buf, val_len) >= 0) { +			err = 0; +			goto out; +		} +	} +	usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", +		      request, validx, idx, cval->val_type, buf[0], buf[1]); +	err = -EINVAL; + + out: +	up_read(&chip->shutdown_rwsem); +	snd_usb_autosuspend(chip); +	return err;  } -static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) +static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, +			     int validx, int value)  {  	return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);  } @@ -459,13 +506,15 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,  		cval->ch_readonly & (1 << (channel - 1));  	if (read_only) { -		snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", +		usb_audio_dbg(cval->mixer->chip, +			      "%s(): channel %d of control %d is read_only\n",  			    __func__, channel, cval->control);  		return 0;  	} -	err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, -			    value); +	err = snd_usb_mixer_set_ctl_value(cval, +					  UAC_SET_CUR, (cval->control << 8) | channel, +					  value);  	if (err < 0)  		return err;  	cval->cached |= 1 << channel; @@ -476,7 +525,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,  /*   * TLV callback for mixer volume controls   */ -static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, +int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,  			 unsigned int size, unsigned int __user *_tlv)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data; @@ -502,13 +551,13 @@ static int parse_audio_unit(struct mixer_build *state, int unitid);   * check if the input/output channel routing is enabled on the given bitmap.   * used for mixer unit parser   */ -static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_outs) +static int check_matrix_bitmap(unsigned char *bmap, +			       int ich, int och, int num_outs)  {  	int idx = ich * num_outs + och;  	return bmap[idx >> 3] & (0x80 >> (idx & 7));  } -  /*   * add an alsa control element   * search and increment the index until an empty slot is found. @@ -516,24 +565,25 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou   * if failed, give up and free the control instance.   */ -static int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl) +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, +			      struct snd_kcontrol *kctl)  {  	struct usb_mixer_elem_info *cval = kctl->private_data;  	int err; -	while (snd_ctl_find_id(state->chip->card, &kctl->id)) +	while (snd_ctl_find_id(mixer->chip->card, &kctl->id))  		kctl->id.index++; -	if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { -		snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); +	if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { +		usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", +			      err);  		return err;  	}  	cval->elem_id = &kctl->id; -	cval->next_id_elem = state->mixer->id_elems[cval->id]; -	state->mixer->id_elems[cval->id] = cval; +	cval->next_id_elem = mixer->id_elems[cval->id]; +	mixer->id_elems[cval->id] = cval;  	return 0;  } -  /*   * get a terminal name string   */ @@ -587,7 +637,8 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm  	struct iterm_name_combo *names;  	if (iterm->name) -		return snd_usb_copy_string_desc(state, iterm->name, name, maxlen); +		return snd_usb_copy_string_desc(state, iterm->name, +						name, maxlen);  	/* virtual type - not a real terminal */  	if (iterm->type >> 16) { @@ -595,13 +646,17 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm  			return 0;  		switch (iterm->type >> 16) {  		case UAC_SELECTOR_UNIT: -			strcpy(name, "Selector"); return 8; +			strcpy(name, "Selector"); +			return 8;  		case UAC1_PROCESSING_UNIT: -			strcpy(name, "Process Unit"); return 12; +			strcpy(name, "Process Unit"); +			return 12;  		case UAC1_EXTENSION_UNIT: -			strcpy(name, "Ext Unit"); return 8; +			strcpy(name, "Ext Unit"); +			return 8;  		case UAC_MIXER_UNIT: -			strcpy(name, "Mixer"); return 5; +			strcpy(name, "Mixer"); +			return 5;  		default:  			return sprintf(name, "Unit %d", iterm->id);  		} @@ -609,29 +664,35 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm  	switch (iterm->type & 0xff00) {  	case 0x0100: -		strcpy(name, "PCM"); return 3; +		strcpy(name, "PCM"); +		return 3;  	case 0x0200: -		strcpy(name, "Mic"); return 3; +		strcpy(name, "Mic"); +		return 3;  	case 0x0400: -		strcpy(name, "Headset"); return 7; +		strcpy(name, "Headset"); +		return 7;  	case 0x0500: -		strcpy(name, "Phone"); return 5; +		strcpy(name, "Phone"); +		return 5;  	} -	for (names = iterm_names; names->type; names++) +	for (names = iterm_names; names->type; names++) {  		if (names->type == iterm->type) {  			strcpy(name, names->name);  			return strlen(names->name);  		} +	} +  	return 0;  } -  /*   * parse the source unit recursively until it reaches to a terminal   * or a branched unit.   */ -static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) +static int check_input_term(struct mixer_build *state, int id, +			    struct usb_audio_term *term)  {  	int err;  	void *p1; @@ -679,16 +740,29 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_  		case UAC2_CLOCK_SELECTOR: {  			struct uac_selector_unit_descriptor *d = p1;  			/* call recursively to retrieve the channel info */ -			if (check_input_term(state, d->baSourceID[0], term) < 0) -				return -ENODEV; +			err = check_input_term(state, d->baSourceID[0], term); +			if (err < 0) +				return err;  			term->type = d->bDescriptorSubtype << 16; /* virtual type */  			term->id = id;  			term->name = uac_selector_unit_iSelector(d);  			return 0;  		}  		case UAC1_PROCESSING_UNIT: -		case UAC1_EXTENSION_UNIT: { +		case UAC1_EXTENSION_UNIT: +		/* UAC2_PROCESSING_UNIT_V2 */ +		/* UAC2_EFFECT_UNIT */ +		case UAC2_EXTENSION_UNIT_V2: {  			struct uac_processing_unit_descriptor *d = p1; + +			if (state->mixer->protocol == UAC_VERSION_2 && +				hdr[2] == UAC2_EFFECT_UNIT) { +				/* UAC2/UAC1 unit IDs overlap here in an +				 * uncompatible way. Ignore this unit for now. +				 */ +				return 0; +			} +  			if (d->bNrInPins) {  				id = d->baSourceID[0];  				break; /* continue to parse */ @@ -713,7 +787,6 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_  	return -ENODEV;  } -  /*   * Feature Unit   */ @@ -741,7 +814,6 @@ static struct usb_feature_control_info audio_feature_info[] = {  	{ "Phase Inverter Control",	USB_MIXER_BOOLEAN },  }; -  /* private_free callback */  static void usb_mixer_elem_free(struct snd_kcontrol *kctl)  { @@ -749,15 +821,117 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)  	kctl->private_data = NULL;  } -  /*   * interface to ALSA control for feature/mixer units   */ +/* volume control quirks */ +static void volume_control_quirks(struct usb_mixer_elem_info *cval, +				  struct snd_kcontrol *kctl) +{ +	struct snd_usb_audio *chip = cval->mixer->chip; +	switch (chip->usb_id) { +	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ +	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ +		if (strcmp(kctl->id.name, "Effect Duration") == 0) { +			cval->min = 0x0000; +			cval->max = 0xffff; +			cval->res = 0x00e6; +			break; +		} +		if (strcmp(kctl->id.name, "Effect Volume") == 0 || +		    strcmp(kctl->id.name, "Effect Feedback Volume") == 0) { +			cval->min = 0x00; +			cval->max = 0xff; +			break; +		} +		if (strstr(kctl->id.name, "Effect Return") != NULL) { +			cval->min = 0xb706; +			cval->max = 0xff7b; +			cval->res = 0x0073; +			break; +		} +		if ((strstr(kctl->id.name, "Playback Volume") != NULL) || +			(strstr(kctl->id.name, "Effect Send") != NULL)) { +			cval->min = 0xb5fb; /* -73 dB = 0xb6ff */ +			cval->max = 0xfcfe; +			cval->res = 0x0073; +		} +		break; + +	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ +	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ +		if (strcmp(kctl->id.name, "Effect Duration") == 0) { +			usb_audio_info(chip, +				       "set quirk for FTU Effect Duration\n"); +			cval->min = 0x0000; +			cval->max = 0x7f00; +			cval->res = 0x0100; +			break; +		} +		if (strcmp(kctl->id.name, "Effect Volume") == 0 || +		    strcmp(kctl->id.name, "Effect Feedback Volume") == 0) { +			usb_audio_info(chip, +				       "set quirks for FTU Effect Feedback/Volume\n"); +			cval->min = 0x00; +			cval->max = 0x7f; +			break; +		} +		break; + +	case USB_ID(0x0471, 0x0101): +	case USB_ID(0x0471, 0x0104): +	case USB_ID(0x0471, 0x0105): +	case USB_ID(0x0672, 0x1041): +	/* quirk for UDA1321/N101. +	 * note that detection between firmware 2.1.1.7 (N101) +	 * and later 2.1.1.21 is not very clear from datasheets. +	 * I hope that the min value is -15360 for newer firmware --jk +	 */ +		if (!strcmp(kctl->id.name, "PCM Playback Volume") && +		    cval->min == -15616) { +			usb_audio_info(chip, +				 "set volume quirk for UDA1321/N101 chip\n"); +			cval->max = -256; +		} +		break; + +	case USB_ID(0x046d, 0x09a4): +		if (!strcmp(kctl->id.name, "Mic Capture Volume")) { +			usb_audio_info(chip, +				"set volume quirk for QuickCam E3500\n"); +			cval->min = 6080; +			cval->max = 8768; +			cval->res = 192; +		} +		break; + +	case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ +	case USB_ID(0x046d, 0x0808): +	case USB_ID(0x046d, 0x0809): +	case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ +	case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ +	case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ +	case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ +	case USB_ID(0x046d, 0x0991): +	/* Most audio usb devices lie about volume resolution. +	 * Most Logitech webcams have res = 384. +	 * Proboly there is some logitech magic behind this number --fishor +	 */ +		if (!strcmp(kctl->id.name, "Mic Capture Volume")) { +			usb_audio_info(chip, +				"set resolution quirk: cval->res = 384\n"); +			cval->res = 384; +		} +		break; +	} +} +  /*   * retrieve the minimum and maximum values for the specified control   */ -static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) +static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, +				   int default_min, struct snd_kcontrol *kctl)  {  	/* for failsafe */  	cval->min = default_min; @@ -780,22 +954,28 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)  		}  		if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||  		    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { -			snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", -				   cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); +			usb_audio_err(cval->mixer->chip, +				      "%d:%d: cannot get min/max values for control %d (id %d)\n", +				   cval->id, snd_usb_ctrl_intf(cval->mixer->chip), +							       cval->control, cval->id);  			return -EINVAL;  		} -		if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { +		if (get_ctl_value(cval, UAC_GET_RES, +				  (cval->control << 8) | minchn, +				  &cval->res) < 0) {  			cval->res = 1;  		} else {  			int last_valid_res = cval->res;  			while (cval->res > 1) {  				if (snd_usb_mixer_set_ctl_value(cval, UAC_SET_RES, -								(cval->control << 8) | minchn, cval->res / 2) < 0) +								(cval->control << 8) | minchn, +								cval->res / 2) < 0)  					break;  				cval->res /= 2;  			} -			if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) +			if (get_ctl_value(cval, UAC_GET_RES, +					  (cval->control << 8) | minchn, &cval->res) < 0)  				cval->res = last_valid_res;  		}  		if (cval->res == 0) @@ -833,6 +1013,9 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)  		cval->initialized = 1;  	} +	if (kctl) +		volume_control_quirks(cval, kctl); +  	/* USB descriptions contain the dB scale in 1/256 dB unit  	 * while ALSA TLV contains in 1/100 dB unit  	 */ @@ -853,9 +1036,11 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)  	return 0;  } +#define get_min_max(cval, def)	get_min_max_with_quirks(cval, def, NULL)  /* get a feature/mixer unit info */ -static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_info *uinfo)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data; @@ -870,8 +1055,17 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_  		uinfo->value.integer.min = 0;  		uinfo->value.integer.max = 1;  	} else { -		if (! cval->initialized) -			get_min_max(cval,  0); +		if (!cval->initialized) { +			get_min_max_with_quirks(cval, 0, kcontrol); +			if (cval->initialized && cval->dBmin >= cval->dBmax) { +				kcontrol->vd[0].access &=  +					~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | +					  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); +				snd_ctl_notify(cval->mixer->chip->card, +					       SNDRV_CTL_EVENT_MASK_INFO, +					       &kcontrol->id); +			} +		}  		uinfo->value.integer.min = 0;  		uinfo->value.integer.max =  			(cval->max - cval->min + cval->res - 1) / cval->res; @@ -880,7 +1074,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_  }  /* get the current value from feature/mixer unit */ -static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, +				 struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int c, cnt, val, err; @@ -911,7 +1106,8 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e  }  /* put the current value to feature/mixer unit */ -static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, +				 struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int c, cnt, val, oval, err; @@ -965,16 +1161,48 @@ static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {  	.put = NULL,  }; +/* + * This symbol is exported in order to allow the mixer quirks to + * hook up to the standard feature unit control mechanism + */ +struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl;  /*   * build a feature control   */ -  static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)  {  	return strlcat(kctl->id.name, str, sizeof(kctl->id.name));  } +/* + * A lot of headsets/headphones have a "Speaker" mixer. Make sure we + * rename it to "Headphone". We determine if something is a headphone + * similar to how udev determines form factor. + */ +static void check_no_speaker_on_headset(struct snd_kcontrol *kctl, +					struct snd_card *card) +{ +	const char *names_to_check[] = { +		"Headset", "headset", "Headphone", "headphone", NULL}; +	const char **s; +	bool found = false; + +	if (strcmp("Speaker", kctl->id.name)) +		return; + +	for (s = names_to_check; *s; s++) +		if (strstr(card->shortname, *s)) { +			found = true; +			break; +		} + +	if (!found) +		return; + +	strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name)); +} +  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, @@ -987,6 +1215,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  	struct snd_kcontrol *kctl;  	struct usb_mixer_elem_info *cval;  	const struct usbmix_name_map *map; +	unsigned int range;  	control++; /* change from zero-based to 1-based value */ @@ -1000,10 +1229,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  		return;  	cval = kzalloc(sizeof(*cval), GFP_KERNEL); -	if (! cval) { -		snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +	if (!cval)  		return; -	}  	cval->mixer = state->mixer;  	cval->id = unitid;  	cval->control = control; @@ -1021,19 +1248,18 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  		cval->ch_readonly = readonly_mask;  	} -	/* get min/max values */ -	get_min_max(cval, 0); - -	/* if all channels in the mask are marked read-only, make the control +	/* +	 * If all channels in the mask are marked read-only, make the control  	 * read-only. set_cur_mix_value() will check the mask again and won't -	 * issue write commands to read-only channels. */ +	 * issue write commands to read-only channels. +	 */  	if (cval->channels == readonly_mask)  		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"); +	if (!kctl) { +		usb_audio_err(state->chip, "cannot malloc kcontrol\n");  		kfree(cval);  		return;  	} @@ -1041,114 +1267,101 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));  	mapped_name = len != 0; -	if (! len && nameid) +	if (!len && nameid)  		len = snd_usb_copy_string_desc(state, nameid,  				kctl->id.name, sizeof(kctl->id.name));  	switch (control) {  	case UAC_FU_MUTE:  	case UAC_FU_VOLUME: -		/* determine the control name.  the rule is: +		/* +		 * 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  		 *   of terminal type.  		 * - if the connected output can be determined, use it.  		 * - otherwise, anonymous name.  		 */ -		if (! len) { -			len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 1); -			if (! len) -				len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1); -			if (! len) -				len = snprintf(kctl->id.name, sizeof(kctl->id.name), +		if (!len) { +			len = get_term_name(state, iterm, kctl->id.name, +					    sizeof(kctl->id.name), 1); +			if (!len) +				len = get_term_name(state, &state->oterm, +						    kctl->id.name, +						    sizeof(kctl->id.name), 1); +			if (!len) +				len = snprintf(kctl->id.name, +					       sizeof(kctl->id.name),  					       "Feature %d", unitid);  		} -		/* determine the stream direction: + +		if (!mapped_name) +			check_no_speaker_on_headset(kctl, state->mixer->chip->card); + +		/* +		 * determine the stream direction:  		 * if the connected output is USB stream, then it's likely a  		 * capture stream.  otherwise it should be playback (hopefully :)  		 */ -		if (! mapped_name && ! (state->oterm.type >> 16)) { -			if ((state->oterm.type & 0xff00) == 0x0100) { +		if (!mapped_name && !(state->oterm.type >> 16)) { +			if ((state->oterm.type & 0xff00) == 0x0100)  				len = append_ctl_name(kctl, " Capture"); -			} else { +			else  				len = append_ctl_name(kctl, " Playback"); -			}  		}  		append_ctl_name(kctl, control == UAC_FU_MUTE ?  				" Switch" : " Volume"); -		if (control == UAC_FU_VOLUME) { -			kctl->tlv.c = mixer_vol_tlv; -			kctl->vd[0].access |=  -				SNDRV_CTL_ELEM_ACCESS_TLV_READ | -				SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; -			check_mapped_dB(map, cval); -		}  		break; -  	default: -		if (! len) +		if (!len)  			strlcpy(kctl->id.name, audio_feature_info[control-1].name,  				sizeof(kctl->id.name));  		break;  	} -	/* volume control quirks */ -	switch (state->chip->usb_id) { -	case USB_ID(0x0471, 0x0101): -	case USB_ID(0x0471, 0x0104): -	case USB_ID(0x0471, 0x0105): -	case USB_ID(0x0672, 0x1041): -	/* quirk for UDA1321/N101. -	 * note that detection between firmware 2.1.1.7 (N101) -	 * and later 2.1.1.21 is not very clear from datasheets. -	 * I hope that the min value is -15360 for newer firmware --jk -	 */ -		if (!strcmp(kctl->id.name, "PCM Playback Volume") && -		    cval->min == -15616) { -			snd_printk(KERN_INFO -				 "set volume quirk for UDA1321/N101 chip\n"); -			cval->max = -256; -		} -		break; - -	case USB_ID(0x046d, 0x09a4): -		if (!strcmp(kctl->id.name, "Mic Capture Volume")) { -			snd_printk(KERN_INFO -				"set volume quirk for QuickCam E3500\n"); -			cval->min = 6080; -			cval->max = 8768; -			cval->res = 192; -		} -		break; +	/* get min/max values */ +	get_min_max_with_quirks(cval, 0, kctl); -	case USB_ID(0x046d, 0x0809): -	case USB_ID(0x046d, 0x0991): -	/* Most audio usb devices lie about volume resolution. -	 * Most Logitech webcams have res = 384. -	 * Proboly there is some logitech magic behind this number --fishor -	 */ -		if (!strcmp(kctl->id.name, "Mic Capture Volume")) { -			snd_printk(KERN_INFO -				"set resolution quirk: cval->res = 384\n"); -			cval->res = 384; +	if (control == UAC_FU_VOLUME) { +		check_mapped_dB(map, cval); +		if (cval->dBmin < cval->dBmax || !cval->initialized) { +			kctl->tlv.c = snd_usb_mixer_vol_tlv; +			kctl->vd[0].access |= +				SNDRV_CTL_ELEM_ACCESS_TLV_READ | +				SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;  		} -		break; -  	} -	snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", -		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); -	add_control_to_empty(state, kctl); +	range = (cval->max - cval->min) / cval->res; +	/* +	 * Are there devices with volume range more than 255? I use a bit more +	 * to be sure. 384 is a resolution magic number found on Logitech +	 * devices. It will definitively catch all buggy Logitech devices. +	 */ +	if (range > 384) { +		usb_audio_warn(state->chip, +			       "Warning! Unlikely big volume range (=%u), " +			       "cval->res is probably wrong.", +			       range); +		usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, " +			       "val = %d/%d/%d", cval->id, +			       kctl->id.name, cval->channels, +			       cval->min, cval->max, cval->res); +	} + +	usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", +		      cval->id, kctl->id.name, cval->channels, +		      cval->min, cval->max, cval->res); +	snd_usb_mixer_add_control(state->mixer, kctl);  } - -  /*   * parse a feature unit   * - * most of controlls are defined here. + * most of controls are defined here.   */ -static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr) +static int parse_audio_feature_unit(struct mixer_build *state, int unitid, +				    void *_ftr)  {  	int channels, i, j;  	struct usb_audio_term iterm; @@ -1159,18 +1372,31 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  	if (state->mixer->protocol == UAC_VERSION_1) {  		csize = hdr->bControlSize; +		if (!csize) { +			usb_audio_dbg(state->chip, +				      "unit %u: invalid bControlSize == 0\n", +				      unitid); +			return -EINVAL; +		}  		channels = (hdr->bLength - 7) / csize - 1;  		bmaControls = hdr->bmaControls; +		if (hdr->bLength < 7 + csize) { +			usb_audio_err(state->chip, +				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +				      unitid); +			return -EINVAL; +		}  	} else {  		struct uac2_feature_unit_descriptor *ftr = _ftr;  		csize = 4;  		channels = (hdr->bLength - 6) / 4 - 1;  		bmaControls = ftr->bmaControls; -	} - -	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; +		if (hdr->bLength < 6 + csize) { +			usb_audio_err(state->chip, +				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", +				      unitid); +			return -EINVAL; +		}  	}  	/* parse the source unit */ @@ -1178,18 +1404,26 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  		return err;  	/* determine the input source type and name */ -	if (check_input_term(state, hdr->bSourceID, &iterm) < 0) -		return -EINVAL; +	err = check_input_term(state, hdr->bSourceID, &iterm); +	if (err < 0) +		return err;  	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"); +		usb_audio_info(state->chip, +			       "usbmixer: master volume quirk for PCM2702 chip\n");  		/* disable non-functional volume control */  		master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);  		break; +	case USB_ID(0x1130, 0xf211): +		usb_audio_info(state->chip, +			       "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n"); +		/* disable non-functional volume control */ +		channels = 0; +		break; +  	}  	if (channels > 0)  		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); @@ -1201,23 +1435,36 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  		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); +				unsigned int mask; + +				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); + +			/* +			 * The first channel must be set +			 * (for ease of programming). +			 */ +			if (ch_bits & 1) +				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); +				build_feature_ctl(state, _ftr, 0, i, &iterm, +						  unitid, 0);  		}  	} else { /* UAC_VERSION_2 */ -		for (i = 0; i < 30/2; i++) { +		for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {  			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); +				unsigned int mask; + +				mask = snd_usb_combine_bytes(bmaControls + +							     csize * (j+1), csize);  				if (uac2_control_is_readable(mask, i)) {  					ch_bits |= (1 << j);  					if (!uac2_control_is_writeable(mask, i)) @@ -1225,12 +1472,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  				}  			} -			/* NOTE: build_feature_ctl() will mark the control read-only if all channels -			 * are marked read-only in the descriptors. Otherwise, the control will be -			 * reported as writeable, but the driver will not actually issue a write -			 * command for read-only channels */ -			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); +			/* +			 * NOTE: build_feature_ctl() will mark the control +			 * read-only if all channels are marked read-only in +			 * the descriptors. Otherwise, the control will be +			 * reported as writeable, but the driver will not +			 * actually issue a write command for read-only +			 * channels. +			 */ + +			/* +			 * The first channel must be set +			 * (for ease of programming). +			 */ +			if (ch_bits & 1) +				build_feature_ctl(state, _ftr, ch_bits, i, +						  &iterm, unitid, ch_read_only);  			if (uac2_control_is_readable(master_bits, i))  				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,  						  !uac2_control_is_writeable(master_bits, i)); @@ -1240,7 +1497,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  	return 0;  } -  /*   * Mixer Unit   */ @@ -1251,7 +1507,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void   * the callbacks are identical with feature unit.   * input channel number (zero based) is given in control field instead.   */ -  static void build_mixer_unit_ctl(struct mixer_build *state,  				 struct uac_mixer_unit_descriptor *desc,  				 int in_pin, int in_ch, int unitid, @@ -1268,7 +1523,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,  		return;  	cval = kzalloc(sizeof(*cval), GFP_KERNEL); -	if (! cval) +	if (!cval)  		return;  	cval->mixer = state->mixer; @@ -1276,7 +1531,9 @@ static void build_mixer_unit_ctl(struct mixer_build *state,  	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(uac_mixer_unit_bmControls(desc, state->mixer->protocol), in_ch, i, num_outs)) { +		__u8 *c = uac_mixer_unit_bmControls(desc, state->mixer->protocol); + +		if (check_matrix_bitmap(c, in_ch, i, num_outs)) {  			cval->cmask |= (1 << i);  			cval->channels++;  		} @@ -1286,43 +1543,48 @@ static void build_mixer_unit_ctl(struct mixer_build *state,  	get_min_max(cval, 0);  	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); -	if (! kctl) { -		snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +	if (!kctl) { +		usb_audio_err(state->chip, "cannot malloc kcontrol\n");  		kfree(cval);  		return;  	}  	kctl->private_free = usb_mixer_elem_free;  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); -	if (! len) -		len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); -	if (! len) +	if (!len) +		len = get_term_name(state, iterm, kctl->id.name, +				    sizeof(kctl->id.name), 0); +	if (!len)  		len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);  	append_ctl_name(kctl, " Volume"); -	snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", +	usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",  		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max); -	add_control_to_empty(state, kctl); +	snd_usb_mixer_add_control(state->mixer, kctl);  } -  /*   * parse a mixer unit   */ -static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *raw_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->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) { -		snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid); +	if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || +	    !(num_outs = uac_mixer_unit_bNrChannels(desc))) { +		usb_audio_err(state->chip, +			      "invalid MIXER UNIT descriptor %d\n", +			      unitid);  		return -EINVAL;  	}  	/* no bmControls field (e.g. Maya44) -> ignore */  	if (desc->bLength <= 10 + input_pins) { -		snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid); +		usb_audio_dbg(state->chip, "MU %d has no bmControls field\n", +			      unitid);  		return 0;  	} @@ -1331,17 +1593,19 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r  	for (pin = 0; pin < input_pins; pin++) {  		err = parse_audio_unit(state, desc->baSourceID[pin]);  		if (err < 0) -			return err; +			continue;  		err = check_input_term(state, desc->baSourceID[pin], &iterm);  		if (err < 0)  			return err;  		num_ins += iterm.channels; -		for (; ich < num_ins; ++ich) { +		for (; ich < num_ins; ich++) {  			int och, ich_has_controls = 0; -			for (och = 0; och < num_outs; ++och) { -				if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol), -							ich, och, num_outs)) { +			for (och = 0; och < num_outs; och++) { +				__u8 *c = uac_mixer_unit_bmControls(desc, +						state->mixer->protocol); + +				if (check_matrix_bitmap(c, ich, och, num_outs)) {  					ich_has_controls = 1;  					break;  				} @@ -1354,13 +1618,13 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r  	return 0;  } -  /*   * Processing Unit / Extension Unit   */  /* get callback for processing/extension unit */ -static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int err, val; @@ -1378,7 +1642,8 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_  }  /* put callback for processing/extension unit */ -static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int val, oval, err; @@ -1407,7 +1672,6 @@ static struct snd_kcontrol_new mixer_procunit_ctl = {  	.put = mixer_ctl_procunit_put,  }; -  /*   * predefined data for processing units   */ @@ -1498,10 +1762,13 @@ static struct procunit_info extunits[] = {  	{ USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info },  	{ 0 }  }; +  /*   * build a processing/extension unit   */ -static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw_desc, 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)  {  	struct uac_processing_unit_descriptor *desc = raw_desc;  	int num_ins = desc->bNrInPins; @@ -1521,7 +1788,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw  	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); +		usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);  		return -EINVAL;  	} @@ -1534,22 +1801,20 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw  	for (info = list; info && info->type; info++)  		if (info->type == type)  			break; -	if (! info || ! info->type) +	if (!info || !info->type)  		info = &default_info;  	for (valinfo = info->values; valinfo->control; valinfo++) {  		__u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol); -		if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) +		if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1))))  			continue;  		map = find_map(state, unitid, valinfo->control);  		if (check_ignored_ctl(map))  			continue;  		cval = kzalloc(sizeof(*cval), GFP_KERNEL); -		if (! cval) { -			snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +		if (!cval)  			return -ENOMEM; -		}  		cval->mixer = state->mixer;  		cval->id = unitid;  		cval->control = valinfo->control; @@ -1566,7 +1831,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw  			cval->initialized = 1;  		} else {  			if (type == USB_XU_CLOCK_RATE) { -				/* E-Mu USB 0404/0202/TrackerPre +				/* +				 * E-Mu USB 0404/0202/TrackerPre/0204  				 * samplerate control quirk  				 */  				cval->min = 0; @@ -1578,77 +1844,81 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw  		}  		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); -		if (! kctl) { -			snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +		if (!kctl) {  			kfree(cval);  			return -ENOMEM;  		}  		kctl->private_free = usb_mixer_elem_free; -		if (check_mapped_name(map, kctl->id.name, -						sizeof(kctl->id.name))) +		if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {  			/* nothing */ ; -		else if (info->name) +		} else if (info->name) {  			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); -		else { +		} else {  			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)); -			if (! len) +				len = snd_usb_copy_string_desc(state, nameid, +							       kctl->id.name, +							       sizeof(kctl->id.name)); +			if (!len)  				strlcpy(kctl->id.name, name, sizeof(kctl->id.name));  		}  		append_ctl_name(kctl, " ");  		append_ctl_name(kctl, valinfo->suffix); -		snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", -			    cval->id, kctl->id.name, cval->channels, cval->min, cval->max); -		if ((err = add_control_to_empty(state, kctl)) < 0) +		usb_audio_dbg(state->chip, +			      "[%d] PU [%s] ch = %d, val = %d/%d\n", +			      cval->id, kctl->id.name, cval->channels, +			      cval->min, cval->max); + +		err = snd_usb_mixer_add_control(state->mixer, kctl); +		if (err < 0)  			return err;  	}  	return 0;  } - -static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc) +static int parse_audio_processing_unit(struct mixer_build *state, int unitid, +				       void *raw_desc)  { -	return build_audio_procunit(state, unitid, raw_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, void *raw_desc) +static int parse_audio_extension_unit(struct mixer_build *state, int unitid, +				      void *raw_desc)  { -	/* 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"); +	/* +	 * 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");  } -  /*   * Selector Unit   */ -/* info callback for selector unit +/* + * info callback for selector unit   * use an enumerator type for routing   */ -static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, +				   struct snd_ctl_elem_info *uinfo)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data; -	char **itemlist = (char **)kcontrol->private_value; +	const char **itemlist = (const char **)kcontrol->private_value;  	if (snd_BUG_ON(!itemlist))  		return -EINVAL; -	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; -	uinfo->count = 1; -	uinfo->value.enumerated.items = cval->max; -	if (uinfo->value.enumerated.item >= cval->max) -		uinfo->value.enumerated.item = cval->max - 1; -	strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], -		sizeof(uinfo->value.enumerated.name)); -	return 0; +	return snd_ctl_enum_info(uinfo, 1, cval->max, itemlist);  }  /* get callback for selector unit */ -static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int val, err; @@ -1667,7 +1937,8 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_  }  /* put callback for selector unit */ -static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, +				  struct snd_ctl_elem_value *ucontrol)  {  	struct usb_mixer_elem_info *cval = kcontrol->private_data;  	int val, oval, err; @@ -1696,8 +1967,8 @@ static struct snd_kcontrol_new mixer_selectunit_ctl = {  	.put = mixer_ctl_selector_put,  }; - -/* private free callback. +/* + * private free callback.   * free both private_data and private_value   */  static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl) @@ -1722,7 +1993,8 @@ 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, void *raw_desc) +static int parse_audio_selector_unit(struct mixer_build *state, int unitid, +				     void *raw_desc)  {  	struct uac_selector_unit_descriptor *desc = raw_desc;  	unsigned int i, nameid, len; @@ -1733,7 +2005,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  	char **namelist;  	if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) { -		snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); +		usb_audio_err(state->chip, +			"invalid SELECTOR UNIT descriptor %d\n", unitid);  		return -EINVAL;  	} @@ -1750,10 +2023,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  		return 0;  	cval = kzalloc(sizeof(*cval), GFP_KERNEL); -	if (! cval) { -		snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +	if (!cval)  		return -ENOMEM; -	}  	cval->mixer = state->mixer;  	cval->id = unitid;  	cval->val_type = USB_MIXER_U8; @@ -1769,8 +2040,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  		cval->control = 0;  	namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); -	if (! namelist) { -		snd_printk(KERN_ERR "cannot malloc\n"); +	if (!namelist) {  		kfree(cval);  		return -ENOMEM;  	} @@ -1779,8 +2049,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  		struct usb_audio_term iterm;  		len = 0;  		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); -		if (! namelist[i]) { -			snd_printk(KERN_ERR "cannot malloc\n"); +		if (!namelist[i]) {  			while (i--)  				kfree(namelist[i]);  			kfree(namelist); @@ -1792,12 +2061,12 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  		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); +			sprintf(namelist[i], "Input %u", i);  	}  	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);  	if (! kctl) { -		snd_printk(KERN_ERR "cannot malloc kcontrol\n"); +		usb_audio_err(state->chip, "cannot malloc kcontrol\n");  		kfree(namelist);  		kfree(cval);  		return -ENOMEM; @@ -1810,11 +2079,12 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  	if (len)  		;  	else if (nameid) -		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); +		snd_usb_copy_string_desc(state, nameid, kctl->id.name, +					 sizeof(kctl->id.name));  	else {  		len = get_term_name(state, &state->oterm,  				    kctl->id.name, sizeof(kctl->id.name), 0); -		if (! len) +		if (!len)  			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));  		if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) @@ -1825,15 +2095,14 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void  			append_ctl_name(kctl, " Playback Source");  	} -	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", +	usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",  		    cval->id, kctl->id.name, desc->bNrInPins); -	if ((err = add_control_to_empty(state, kctl)) < 0) +	if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)  		return err;  	return 0;  } -  /*   * parse an audio unit recursively   */ @@ -1847,7 +2116,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)  	p1 = find_audio_control_unit(state, unitid);  	if (!p1) { -		snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid); +		usb_audio_err(state->chip, "unit %d not found!\n", unitid);  		return -EINVAL;  	} @@ -1874,8 +2143,11 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)  			return parse_audio_extension_unit(state, unitid, p1);  		else /* UAC_VERSION_2 */  			return parse_audio_processing_unit(state, unitid, p1); +	case UAC2_EXTENSION_UNIT_V2: +		return parse_audio_extension_unit(state, unitid, p1);  	default: -		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); +		usb_audio_err(state->chip, +			"unit %u: unexpected type 0x%02x\n", unitid, p1[2]);  		return -EINVAL;  	}  } @@ -1909,15 +2181,13 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)  	struct mixer_build state;  	int err;  	const struct usbmix_ctl_map *map; -	struct usb_host_interface *hostif;  	void *p; -	hostif = mixer->chip->ctrl_intf;  	memset(&state, 0, sizeof(state));  	state.chip = mixer->chip;  	state.mixer = mixer; -	state.buffer = hostif->extra; -	state.buflen = hostif->extralen; +	state.buffer = mixer->hostif->extra; +	state.buflen = mixer->hostif->extralen;  	/* check the mapping table */  	for (map = usbmix_ctl_maps; map->id; map++) { @@ -1930,35 +2200,42 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)  	}  	p = NULL; -	while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { +	while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, +					    mixer->hostif->extralen, +					    p, UAC_OUTPUT_TERMINAL)) != NULL) {  		if (mixer->protocol == UAC_VERSION_1) {  			struct uac1_output_terminal_descriptor *desc = p;  			if (desc->bLength < sizeof(*desc))  				continue; /* invalid descriptor? */ -			set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */ +			/* mark terminal ID as visited */ +			set_bit(desc->bTerminalID, state.unitbitmap);  			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) +			if (err < 0 && err != -EINVAL)  				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 */ +			/* mark terminal ID as visited */ +			set_bit(desc->bTerminalID, state.unitbitmap);  			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) +			if (err < 0 && err != -EINVAL)  				return err; -			/* for UAC2, use the same approach to also add the clock selectors */ +			/* +			 * For UAC2, use the same approach to also add the +			 * clock selectors +			 */  			err = parse_audio_unit(&state, desc->bCSourceID); -			if (err < 0) +			if (err < 0 && err != -EINVAL)  				return err;  		}  	} @@ -2024,8 +2301,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,  	__u8 channel = value & 0xff;  	if (channel >= MAX_CHANNELS) { -		snd_printk(KERN_DEBUG "%s(): bogus channel number %d\n", -				__func__, channel); +		usb_audio_dbg(mixer->chip, +			"%s(): bogus channel number %d\n", +			__func__, channel);  		return;  	} @@ -2054,8 +2332,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,  			break;  		default: -			snd_printk(KERN_DEBUG "unknown attribute %d in interrupt\n", -						attribute); +			usb_audio_dbg(mixer->chip, +				"unknown attribute %d in interrupt\n", +				attribute);  			break;  		} /* switch */  	} @@ -2065,8 +2344,9 @@ static void snd_usb_mixer_interrupt(struct urb *urb)  {  	struct usb_mixer_interface *mixer = urb->context;  	int len = urb->actual_length; +	int ustatus = urb->status; -	if (urb->status != 0) +	if (ustatus != 0)  		goto requeue;  	if (mixer->protocol == UAC_VERSION_1) { @@ -2075,7 +2355,7 @@ static void snd_usb_mixer_interrupt(struct urb *urb)  		for (status = urb->transfer_buffer;  		     len >= sizeof(*status);  		     len -= sizeof(*status), status++) { -			snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", +			dev_dbg(&urb->dev->dev, "status interrupt: %02x %02x\n",  						status->bStatusType,  						status->bOriginator); @@ -2107,7 +2387,9 @@ static void snd_usb_mixer_interrupt(struct urb *urb)  	}  requeue: -	if (urb->status != -ENOENT && urb->status != -ECONNRESET) { +	if (ustatus != -ENOENT && +	    ustatus != -ECONNRESET && +	    ustatus != -ESHUTDOWN) {  		urb->dev = mixer->chip->dev;  		usb_submit_urb(urb, GFP_ATOMIC);  	} @@ -2116,17 +2398,15 @@ requeue:  /* create the handler for the optional status interrupt endpoint */  static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)  { -	struct usb_host_interface *hostif;  	struct usb_endpoint_descriptor *ep;  	void *transfer_buffer;  	int buffer_length;  	unsigned int epnum; -	hostif = mixer->chip->ctrl_intf;  	/* we need one interrupt input endpoint */ -	if (get_iface_desc(hostif)->bNumEndpoints < 1) +	if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)  		return 0; -	ep = get_endpoint(hostif, 0); +	ep = get_endpoint(mixer->hostif, 0);  	if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))  		return 0; @@ -2156,7 +2436,6 @@ 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;  	strcpy(chip->card->mixername, "USB Mixer"); @@ -2173,8 +2452,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,  		return -ENOMEM;  	} -	host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; -	switch (get_iface_desc(host_iface)->bInterfaceProtocol) { +	mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; +	switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {  	case UAC_VERSION_1:  	default:  		mixer->protocol = UAC_VERSION_1; @@ -2190,7 +2469,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,  	snd_usb_mixer_apply_create_quirk(mixer); -	err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); +	err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);  	if (err < 0)  		goto _error; @@ -2214,3 +2493,82 @@ void snd_usb_mixer_disconnect(struct list_head *p)  	usb_kill_urb(mixer->urb);  	usb_kill_urb(mixer->rc_urb);  } + +#ifdef CONFIG_PM +/* stop any bus activity of a mixer */ +static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer) +{ +	usb_kill_urb(mixer->urb); +	usb_kill_urb(mixer->rc_urb); +} + +static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer) +{ +	int err; + +	if (mixer->urb) { +		err = usb_submit_urb(mixer->urb, GFP_NOIO); +		if (err < 0) +			return err; +	} + +	return 0; +} + +int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) +{ +	snd_usb_mixer_inactivate(mixer); +	return 0; +} + +static int restore_mixer_value(struct usb_mixer_elem_info *cval) +{ +	int c, err, idx; + +	if (cval->cmask) { +		idx = 0; +		for (c = 0; c < MAX_CHANNELS; c++) { +			if (!(cval->cmask & (1 << c))) +				continue; +			if (cval->cached & (1 << c)) { +				err = set_cur_mix_value(cval, c + 1, idx, +							cval->cache_val[idx]); +				if (err < 0) +					return err; +			} +			idx++; +		} +	} else { +		/* master */ +		if (cval->cached) { +			err = set_cur_mix_value(cval, 0, 0, *cval->cache_val); +			if (err < 0) +				return err; +		} +	} + +	return 0; +} + +int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) +{ +	struct usb_mixer_elem_info *cval; +	int id, err; + +	/* FIXME: any mixer quirks? */ + +	if (reset_resume) { +		/* restore cached mixer values */ +		for (id = 0; id < MAX_ID_ELEMS; id++) { +			for (cval = mixer->id_elems[id]; cval; +			     cval = cval->next_id_elem) { +				err = restore_mixer_value(cval); +				if (err < 0) +					return err; +			} +		} +	} + +	return snd_usb_mixer_activate(mixer); +} +#endif diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 26c636c5c93..73b1f649447 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -3,6 +3,7 @@  struct usb_mixer_interface {  	struct snd_usb_audio *chip; +	struct usb_host_interface *hostif;  	struct list_head list;  	unsigned int ignore_ctl_error;  	struct urb *urb; @@ -24,7 +25,16 @@ struct usb_mixer_interface {  	u8 xonar_u1_status;  }; -#define MAX_CHANNELS	10	/* max logical channels */ +#define MAX_CHANNELS	16	/* max logical channels */ + +enum { +	USB_MIXER_BOOLEAN, +	USB_MIXER_INV_BOOLEAN, +	USB_MIXER_S8, +	USB_MIXER_U8, +	USB_MIXER_S16, +	USB_MIXER_U16, +};  struct usb_mixer_elem_info {  	struct usb_mixer_interface *mixer; @@ -33,6 +43,7 @@ struct usb_mixer_elem_info {  	unsigned int id;  	unsigned int control;	/* CS or ICN (high byte) */  	unsigned int cmask; /* channel mask bitmap: 0 = master */ +	unsigned int idx_off; /* Control index offset */  	unsigned int ch_readonly;  	unsigned int master_readonly;  	int channels; @@ -53,4 +64,15 @@ 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); +int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, +			      struct snd_kcontrol *kctl); + +int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, +			  unsigned int size, unsigned int __user *_tlv); + +#ifdef CONFIG_PM +int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer); +int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume); +#endif +  #endif /* __USBMIXER_H */ diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index f1324c42383..d1d72ff5034 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -179,6 +179,15 @@ static struct usbmix_name_map audigy2nx_map[] = {  	{ 0 } /* terminator */  }; +static struct usbmix_selector_map c400_selectors[] = { +	{ +		.id = 0x80, +		.count = 2, +		.names = (const char*[]) {"Internal", "SPDIF"} +	}, +	{ 0 } /* terminator */ +}; +  static struct usbmix_selector_map audigy2nx_selectors[] = {  	{  		.id = 14, /* Capture Source */ @@ -288,6 +297,15 @@ static struct usbmix_name_map scratch_live_map[] = {  	{ 0 } /* terminator */  }; +static struct usbmix_name_map ebox44_map[] = { +	{ 4, NULL }, /* FU */ +	{ 6, NULL }, /* MU */ +	{ 7, NULL }, /* FU */ +	{ 10, NULL }, /* FU */ +	{ 11, NULL }, /* MU */ +	{ 0 } +}; +  /* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"   *  most importand difference is SU[8], it should be set to "Capture Source"   *  to make alsamixer and PA working properly. @@ -304,6 +322,17 @@ static struct usbmix_name_map hercules_usb51_map[] = {  	{ 0 }				/* terminator */  }; +/* Plantronics Gamecom 780 has a broken volume control, better to disable it */ +static struct usbmix_name_map gamecom780_map[] = { +	{ 9, NULL }, /* FU, speaker out */ +	{} +}; + +static const struct usbmix_name_map kef_x300a_map[] = { +	{ 10, NULL }, /* firmware locks up (?) when we try to access this FU */ +	{ 0 } +}; +  /*   * Control map entries   */ @@ -332,6 +361,18 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {  		.map = audigy2nx_map,  		.selector_map = audigy2nx_selectors,  	}, +	{	/* Logitech, Inc. QuickCam Pro for Notebooks */ +		.id = USB_ID(0x046d, 0x0991), +		.ignore_ctl_error = 1, +	}, +	{	/* Logitech, Inc. QuickCam E 3500 */ +		.id = USB_ID(0x046d, 0x09a4), +		.ignore_ctl_error = 1, +	}, +	{	/* Plantronics GameCom 780 */ +		.id = USB_ID(0x047f, 0xc010), +		.map = gamecom780_map, +	},  	{  		/* Hercules DJ Console (Windows Edition) */  		.id = USB_ID(0x06f8, 0xb000), @@ -350,6 +391,14 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {  		.map = hercules_usb51_map,  	},  	{ +		.id = USB_ID(0x0763, 0x2030), +		.selector_map = c400_selectors, +	}, +	{ +		.id = USB_ID(0x0763, 0x2031), +		.selector_map = c400_selectors, +	}, +	{  		.id = USB_ID(0x08bb, 0x2702),  		.map = linex_map,  		.ignore_ctl_error = 1, @@ -371,6 +420,14 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {  		.map = scratch_live_map,  		.ignore_ctl_error = 1,  	}, +	{ +		.id = USB_ID(0x200c, 0x1018), +		.map = ebox44_map, +	}, +	{ +		.id = USB_ID(0x27ac, 0x1000), +		.map = kef_x300a_map, +	},  	{ 0 } /* terminator */  }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 782f741cd00..f119a41ed9a 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -9,6 +9,8 @@   *	    Alan Cox (alan@lxorguk.ukuu.org.uk)   *	    Thomas Sailer (sailer@ife.ee.ethz.ch)   * + *   Audio Advantage Micro II support added by: + *	    Przemek Rudy (prudy1@o2.pl)   *   *   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 @@ -30,6 +32,7 @@  #include <linux/usb.h>  #include <linux/usb/audio.h> +#include <sound/asoundef.h>  #include <sound/core.h>  #include <sound/control.h>  #include <sound/hwdep.h> @@ -40,6 +43,119 @@  #include "mixer_quirks.h"  #include "helper.h" +extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; + +struct std_mono_table { +	unsigned int unitid, control, cmask; +	int val_type; +	const char *name; +	snd_kcontrol_tlv_rw_t *tlv_callback; +}; + +/* private_free callback */ +static void usb_mixer_elem_free(struct snd_kcontrol *kctl) +{ +	kfree(kctl->private_data); +	kctl->private_data = NULL; +} + +/* This function allows for the creation of standard UAC controls. + * See the quirks for M-Audio FTUs or Ebox-44. + * If you don't want to set a TLV callback pass NULL. + * + * Since there doesn't seem to be a devices that needs a multichannel + * version, we keep it mono for simplicity. + */ +static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, +				unsigned int unitid, +				unsigned int control, +				unsigned int cmask, +				int val_type, +				unsigned int idx_off, +				const char *name, +				snd_kcontrol_tlv_rw_t *tlv_callback) +{ +	int err; +	struct usb_mixer_elem_info *cval; +	struct snd_kcontrol *kctl; + +	cval = kzalloc(sizeof(*cval), GFP_KERNEL); +	if (!cval) +		return -ENOMEM; + +	cval->id = unitid; +	cval->mixer = mixer; +	cval->val_type = val_type; +	cval->channels = 1; +	cval->control = control; +	cval->cmask = cmask; +	cval->idx_off = idx_off; + +	/* get_min_max() is called only for integer volumes later, +	 * so provide a short-cut for booleans */ +	cval->min = 0; +	cval->max = 1; +	cval->res = 0; +	cval->dBmin = 0; +	cval->dBmax = 0; + +	/* Create control */ +	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); +	if (!kctl) { +		kfree(cval); +		return -ENOMEM; +	} + +	/* Set name */ +	snprintf(kctl->id.name, sizeof(kctl->id.name), name); +	kctl->private_free = usb_mixer_elem_free; + +	/* set TLV */ +	if (tlv_callback) { +		kctl->tlv.c = tlv_callback; +		kctl->vd[0].access |= +			SNDRV_CTL_ELEM_ACCESS_TLV_READ | +			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; +	} +	/* Add control to mixer */ +	err = snd_usb_mixer_add_control(mixer, kctl); +	if (err < 0) +		return err; + +	return 0; +} + +static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, +				unsigned int unitid, +				unsigned int control, +				unsigned int cmask, +				int val_type, +				const char *name, +				snd_kcontrol_tlv_rw_t *tlv_callback) +{ +	return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, +		val_type, 0 /* Offset */, name, tlv_callback); +} + +/* + * Create a set of standard UAC controls from a table + */ +static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, +				struct std_mono_table *t) +{ +	int err; + +	while (t->name != NULL) { +		err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, +				t->cmask, t->val_type, t->name, t->tlv_callback); +		if (err < 0) +			return err; +		t++; +	} + +	return 0; +} +  /*   * Sound Blaster remote control configuration   * @@ -61,6 +177,7 @@ static const struct rc_config {  	{ 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, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */ +	{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */  	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */  }; @@ -183,16 +300,29 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e  	if (value > 1)  		return -EINVAL;  	changed = value != mixer->audigy2nx_leds[index]; +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) { +		err = -ENODEV; +		goto out; +	}  	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))  		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, 0, NULL, 0, 100); +			      !value, 0, NULL, 0); +	/* USB X-Fi S51 Pro */ +	if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) +		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, 0, NULL, 0);  	else  		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); +			      value, index + 2, NULL, 0); + out: +	up_read(&mixer->chip->shutdown_rwsem);  	if (err < 0)  		return err;  	mixer->audigy2nx_leds[index] = value; @@ -234,9 +364,13 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)  		/* USB X-Fi S51 doesn't have a CMSS LED */  		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)  			continue; +		/* USB X-Fi S51 Pro doesn't have one either */ +		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) +			continue;  		if (i > 1 && /* Live24ext has 2 LEDs only */  			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||  			 mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || +			 mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||  			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))  			break;   		err = snd_ctl_add(mixer->chip->card, @@ -282,11 +416,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,  	for (i = 0; jacks[i].name; ++i) {  		snd_iprintf(buffer, "%s: ", jacks[i].name); -		err = snd_usb_ctl_msg(mixer->chip->dev, +		down_read(&mixer->chip->shutdown_rwsem); +		if (mixer->chip->shutdown) +			err = 0; +		else +			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); +				      jacks[i].unitid << 8, buf, 3); +		up_read(&mixer->chip->shutdown_rwsem);  		if (err == 3 && (buf[0] == 3 || buf[0] == 6))  			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);  		else @@ -294,6 +433,91 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,  	}  } +/* EMU0204 */ +static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol, +				      struct snd_ctl_elem_info *uinfo) +{ +	static const char *texts[2] = {"1/2", +				       "3/4" +	}; + +	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; +	uinfo->count = 1; +	uinfo->value.enumerated.items = 2; +	if (uinfo->value.enumerated.item > 1) +		uinfo->value.enumerated.item = 1; +	strcpy(uinfo->value.enumerated.name, +		texts[uinfo->value.enumerated.item]); + +	return 0; +} + +static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, +				     struct snd_ctl_elem_value *ucontrol) +{ +	ucontrol->value.enumerated.item[0] = kcontrol->private_value; +	return 0; +} + +static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, +				     struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	unsigned int value = ucontrol->value.enumerated.item[0]; +	int err, changed; +	unsigned char buf[2]; + +	if (value > 1) +		return -EINVAL; + +	buf[0] = 0x01; +	buf[1] = value ? 0x02 : 0x01; + +	changed = value != kcontrol->private_value; +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) { +		err = -ENODEV; +		goto out; +	} +	err = snd_usb_ctl_msg(mixer->chip->dev, +		      usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR, +		      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, +		      0x0400, 0x0e00, buf, 2); + out: +	up_read(&mixer->chip->shutdown_rwsem); +	if (err < 0) +		return err; +	kcontrol->private_value = value; +	return changed; +} + + +static struct snd_kcontrol_new snd_emu0204_controls[] = { +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Front Jack Channels", +		.info = snd_emu0204_ch_switch_info, +		.get = snd_emu0204_ch_switch_get, +		.put = snd_emu0204_ch_switch_put, +		.private_value = 0, +	}, +}; + +static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) +{ +	int i, err; + +	for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) { +		err = snd_ctl_add(mixer->chip->card, +			snd_ctl_new1(&snd_emu0204_controls[i], mixer)); +		if (err < 0) +			return err; +	} + +	return 0; +} +/* ASUS Xonar U1 / U3 controls */ +  static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,  				   struct snd_ctl_elem_value *ucontrol)  { @@ -316,10 +540,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,  	else  		new_status = old_status & ~0x02;  	changed = new_status != old_status; -	err = snd_usb_ctl_msg(mixer->chip->dev, +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) +		err = -ENODEV; +	else +		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); +			      50, 0, &new_status, 1); +	up_read(&mixer->chip->shutdown_rwsem);  	if (err < 0)  		return err;  	mixer->xonar_u1_status = new_status; @@ -346,6 +575,527 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)  	return 0;  } +/* Native Instruments device quirks */ + +#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) + +static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, +					     struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	struct usb_device *dev = mixer->chip->dev; +	u8 bRequest = (kcontrol->private_value >> 16) & 0xff; +	u16 wIndex = kcontrol->private_value & 0xffff; +	u8 tmp; +	int ret; + +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) +		ret = -ENODEV; +	else +		ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, +				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, +				  0, wIndex, +				  &tmp, sizeof(tmp), 1000); +	up_read(&mixer->chip->shutdown_rwsem); + +	if (ret < 0) { +		dev_err(&dev->dev, +			"unable to issue vendor read request (ret = %d)", ret); +		return ret; +	} + +	ucontrol->value.integer.value[0] = tmp; + +	return 0; +} + +static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, +					     struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	struct usb_device *dev = mixer->chip->dev; +	u8 bRequest = (kcontrol->private_value >> 16) & 0xff; +	u16 wIndex = kcontrol->private_value & 0xffff; +	u16 wValue = ucontrol->value.integer.value[0]; +	int ret; + +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) +		ret = -ENODEV; +	else +		ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, +				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, +				  wValue, wIndex, +				  NULL, 0, 1000); +	up_read(&mixer->chip->shutdown_rwsem); + +	if (ret < 0) { +		dev_err(&dev->dev, +			"unable to issue vendor write request (ret = %d)", ret); +		return ret; +	} + +	return 0; +} + +static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { +	{ +		.name = "Direct Thru Channel A", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x03), +	}, +	{ +		.name = "Direct Thru Channel B", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x05), +	}, +	{ +		.name = "Phono Input Channel A", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x03), +	}, +	{ +		.name = "Phono Input Channel B", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x05), +	}, +}; + +static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { +	{ +		.name = "Direct Thru Channel A", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x03), +	}, +	{ +		.name = "Direct Thru Channel B", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x05), +	}, +	{ +		.name = "Direct Thru Channel C", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x07), +	}, +	{ +		.name = "Direct Thru Channel D", +		.private_value = _MAKE_NI_CONTROL(0x01, 0x09), +	}, +	{ +		.name = "Phono Input Channel A", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x03), +	}, +	{ +		.name = "Phono Input Channel B", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x05), +	}, +	{ +		.name = "Phono Input Channel C", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x07), +	}, +	{ +		.name = "Phono Input Channel D", +		.private_value = _MAKE_NI_CONTROL(0x02, 0x09), +	}, +}; + +static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, +					      const struct snd_kcontrol_new *kc, +					      unsigned int count) +{ +	int i, err = 0; +	struct snd_kcontrol_new template = { +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.get = snd_nativeinstruments_control_get, +		.put = snd_nativeinstruments_control_put, +		.info = snd_ctl_boolean_mono_info, +	}; + +	for (i = 0; i < count; i++) { +		struct snd_kcontrol *c; + +		template.name = kc[i].name; +		template.private_value = kc[i].private_value; + +		c = snd_ctl_new1(&template, mixer); +		err = snd_ctl_add(mixer->chip->card, c); + +		if (err < 0) +			break; +	} + +	return err; +} + +/* M-Audio FastTrack Ultra quirks */ +/* FTU Effect switch (also used by C400/C600) */ +struct snd_ftu_eff_switch_priv_val { +	struct usb_mixer_interface *mixer; +	int cached_value; +	int is_cached; +	int bUnitID; +	int validx; +}; + +static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, +					struct snd_ctl_elem_info *uinfo) +{ +	static const char *texts[8] = {"Room 1", +				       "Room 2", +				       "Room 3", +				       "Hall 1", +				       "Hall 2", +				       "Plate", +				       "Delay", +				       "Echo" +	}; + +	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; +	uinfo->count = 1; +	uinfo->value.enumerated.items = 8; +	if (uinfo->value.enumerated.item > 7) +		uinfo->value.enumerated.item = 7; +	strcpy(uinfo->value.enumerated.name, +		texts[uinfo->value.enumerated.item]); + +	return 0; +} + +static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, +					struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_usb_audio *chip; +	struct usb_mixer_interface *mixer; +	struct snd_ftu_eff_switch_priv_val *pval; +	int err; +	unsigned char value[2]; +	int id, validx; + +	const int val_len = 2; + +	value[0] = 0x00; +	value[1] = 0x00; + +	pval = (struct snd_ftu_eff_switch_priv_val *) +		kctl->private_value; + +	if (pval->is_cached) { +		ucontrol->value.enumerated.item[0] = pval->cached_value; +		return 0; +	} + +	mixer = (struct usb_mixer_interface *) pval->mixer; +	if (snd_BUG_ON(!mixer)) +		return -EINVAL; + +	chip = (struct snd_usb_audio *) mixer->chip; +	if (snd_BUG_ON(!chip)) +		return -EINVAL; + +	id = pval->bUnitID; +	validx = pval->validx; + +	down_read(&mixer->chip->shutdown_rwsem); +	if (mixer->chip->shutdown) +		err = -ENODEV; +	else +		err = snd_usb_ctl_msg(chip->dev, +			usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, +			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, +			validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), +			value, val_len); +	up_read(&mixer->chip->shutdown_rwsem); +	if (err < 0) +		return err; + +	ucontrol->value.enumerated.item[0] = value[0]; +	pval->cached_value = value[0]; +	pval->is_cached = 1; + +	return 0; +} + +static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, +					struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_usb_audio *chip; +	struct snd_ftu_eff_switch_priv_val *pval; + +	struct usb_mixer_interface *mixer; +	int changed, cur_val, err, new_val; +	unsigned char value[2]; +	int id, validx; + +	const int val_len = 2; + +	changed = 0; + +	pval = (struct snd_ftu_eff_switch_priv_val *) +		kctl->private_value; +	cur_val = pval->cached_value; +	new_val = ucontrol->value.enumerated.item[0]; + +	mixer = (struct usb_mixer_interface *) pval->mixer; +	if (snd_BUG_ON(!mixer)) +		return -EINVAL; + +	chip = (struct snd_usb_audio *) mixer->chip; +	if (snd_BUG_ON(!chip)) +		return -EINVAL; + +	id = pval->bUnitID; +	validx = pval->validx; + +	if (!pval->is_cached) { +		/* Read current value */ +		down_read(&mixer->chip->shutdown_rwsem); +		if (mixer->chip->shutdown) +			err = -ENODEV; +		else +			err = snd_usb_ctl_msg(chip->dev, +				usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, +				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, +				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), +				value, val_len); +		up_read(&mixer->chip->shutdown_rwsem); +		if (err < 0) +			return err; + +		cur_val = value[0]; +		pval->cached_value = cur_val; +		pval->is_cached = 1; +	} +	/* update value if needed */ +	if (cur_val != new_val) { +		value[0] = new_val; +		value[1] = 0; +		down_read(&mixer->chip->shutdown_rwsem); +		if (mixer->chip->shutdown) +			err = -ENODEV; +		else +			err = snd_usb_ctl_msg(chip->dev, +				usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, +				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, +				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), +				value, val_len); +		up_read(&mixer->chip->shutdown_rwsem); +		if (err < 0) +			return err; + +		pval->cached_value = new_val; +		pval->is_cached = 1; +		changed = 1; +	} + +	return changed; +} + +static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, +	int validx, int bUnitID) +{ +	static struct snd_kcontrol_new template = { +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Effect Program Switch", +		.index = 0, +		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, +		.info = snd_ftu_eff_switch_info, +		.get = snd_ftu_eff_switch_get, +		.put = snd_ftu_eff_switch_put +	}; + +	int err; +	struct snd_kcontrol *kctl; +	struct snd_ftu_eff_switch_priv_val *pval; + +	pval = kzalloc(sizeof(*pval), GFP_KERNEL); +	if (!pval) +		return -ENOMEM; + +	pval->cached_value = 0; +	pval->is_cached = 0; +	pval->mixer = mixer; +	pval->bUnitID = bUnitID; +	pval->validx = validx; + +	template.private_value = (unsigned long) pval; +	kctl = snd_ctl_new1(&template, mixer->chip); +	if (!kctl) { +		kfree(pval); +		return -ENOMEM; +	} + +	err = snd_ctl_add(mixer->chip->card, kctl); +	if (err < 0) +		return err; + +	return 0; +} + +/* Create volume controls for FTU devices*/ +static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) +{ +	char name[64]; +	unsigned int control, cmask; +	int in, out, err; + +	const unsigned int id = 5; +	const int val_type = USB_MIXER_S16; + +	for (out = 0; out < 8; out++) { +		control = out + 1; +		for (in = 0; in < 8; in++) { +			cmask = 1 << in; +			snprintf(name, sizeof(name), +				"AIn%d - Out%d Capture Volume", +				in  + 1, out + 1); +			err = snd_create_std_mono_ctl(mixer, id, control, +							cmask, val_type, name, +							&snd_usb_mixer_vol_tlv); +			if (err < 0) +				return err; +		} +		for (in = 8; in < 16; in++) { +			cmask = 1 << in; +			snprintf(name, sizeof(name), +				"DIn%d - Out%d Playback Volume", +				in - 7, out + 1); +			err = snd_create_std_mono_ctl(mixer, id, control, +							cmask, val_type, name, +							&snd_usb_mixer_vol_tlv); +			if (err < 0) +				return err; +		} +	} + +	return 0; +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Volume"; +	const unsigned int id = 6; +	const int val_type = USB_MIXER_U8; +	const unsigned int control = 2; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Duration"; +	const unsigned int id = 6; +	const int val_type = USB_MIXER_S16; +	const unsigned int control = 3; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Feedback Volume"; +	const unsigned int id = 6; +	const int val_type = USB_MIXER_U8; +	const unsigned int control = 4; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, NULL); +} + +static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) +{ +	unsigned int cmask; +	int err, ch; +	char name[48]; + +	const unsigned int id = 7; +	const int val_type = USB_MIXER_S16; +	const unsigned int control = 7; + +	for (ch = 0; ch < 4; ++ch) { +		cmask = 1 << ch; +		snprintf(name, sizeof(name), +			"Effect Return %d Volume", ch + 1); +		err = snd_create_std_mono_ctl(mixer, id, control, +						cmask, val_type, name, +						snd_usb_mixer_vol_tlv); +		if (err < 0) +			return err; +	} + +	return 0; +} + +static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) +{ +	unsigned int  cmask; +	int err, ch; +	char name[48]; + +	const unsigned int id = 5; +	const int val_type = USB_MIXER_S16; +	const unsigned int control = 9; + +	for (ch = 0; ch < 8; ++ch) { +		cmask = 1 << ch; +		snprintf(name, sizeof(name), +			"Effect Send AIn%d Volume", ch + 1); +		err = snd_create_std_mono_ctl(mixer, id, control, cmask, +						val_type, name, +						snd_usb_mixer_vol_tlv); +		if (err < 0) +			return err; +	} +	for (ch = 8; ch < 16; ++ch) { +		cmask = 1 << ch; +		snprintf(name, sizeof(name), +			"Effect Send DIn%d Volume", ch - 7); +		err = snd_create_std_mono_ctl(mixer, id, control, cmask, +						val_type, name, +						snd_usb_mixer_vol_tlv); +		if (err < 0) +			return err; +	} +	return 0; +} + +static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) +{ +	int err; + +	err = snd_ftu_create_volume_ctls(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_switch(mixer, 1, 6); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_volume_ctl(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_duration_ctl(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_feedback_ctl(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_return_ctls(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_send_ctls(mixer); +	if (err < 0) +		return err; + +	return 0; +} +  void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,  			       unsigned char samplerate_id)  { @@ -365,33 +1115,565 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,  	}  } -int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) +/* M-Audio Fast Track C400/C600 */ +/* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */ +static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) +{ +	char name[64]; +	unsigned int cmask, offset; +	int out, chan, err; +	int num_outs = 0; +	int num_ins = 0; + +	const unsigned int id = 0x40; +	const int val_type = USB_MIXER_S16; +	const int control = 1; + +	switch (mixer->chip->usb_id) { +	case USB_ID(0x0763, 0x2030): +		num_outs = 6; +		num_ins = 4; +		break; +	case USB_ID(0x0763, 0x2031): +		num_outs = 8; +		num_ins = 6; +		break; +	} + +	for (chan = 0; chan < num_outs + num_ins; chan++) { +		for (out = 0; out < num_outs; out++) { +			if (chan < num_outs) { +				snprintf(name, sizeof(name), +					"PCM%d-Out%d Playback Volume", +					chan + 1, out + 1); +			} else { +				snprintf(name, sizeof(name), +					"In%d-Out%d Playback Volume", +					chan - num_outs + 1, out + 1); +			} + +			cmask = (out == 0) ? 0 : 1 << (out - 1); +			offset = chan * num_outs; +			err = snd_create_std_mono_ctl_offset(mixer, id, control, +						cmask, val_type, offset, name, +						&snd_usb_mixer_vol_tlv); +			if (err < 0) +				return err; +		} +	} + +	return 0; +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Volume"; +	const unsigned int id = 0x43; +	const int val_type = USB_MIXER_U8; +	const unsigned int control = 3; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Duration"; +	const unsigned int id = 0x43; +	const int val_type = USB_MIXER_S16; +	const unsigned int control = 4; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, snd_usb_mixer_vol_tlv); +} + +/* This control needs a volume quirk, see mixer.c */ +static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) +{ +	static const char name[] = "Effect Feedback Volume"; +	const unsigned int id = 0x43; +	const int val_type = USB_MIXER_U8; +	const unsigned int control = 5; +	const unsigned int cmask = 0; + +	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, +					name, NULL); +} + +static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) +{ +	char name[64]; +	unsigned int cmask; +	int chan, err; +	int num_outs = 0; +	int num_ins = 0; + +	const unsigned int id = 0x42; +	const int val_type = USB_MIXER_S16; +	const int control = 1; + +	switch (mixer->chip->usb_id) { +	case USB_ID(0x0763, 0x2030): +		num_outs = 6; +		num_ins = 4; +		break; +	case USB_ID(0x0763, 0x2031): +		num_outs = 8; +		num_ins = 6; +		break; +	} + +	for (chan = 0; chan < num_outs + num_ins; chan++) { +		if (chan < num_outs) { +			snprintf(name, sizeof(name), +				"Effect Send DOut%d", +				chan + 1); +		} else { +			snprintf(name, sizeof(name), +				"Effect Send AIn%d", +				chan - num_outs + 1); +		} + +		cmask = (chan == 0) ? 0 : 1 << (chan - 1); +		err = snd_create_std_mono_ctl(mixer, id, control, +						cmask, val_type, name, +						&snd_usb_mixer_vol_tlv); +		if (err < 0) +			return err; +	} + +	return 0; +} + +static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) +{ +	char name[64]; +	unsigned int cmask; +	int chan, err; +	int num_outs = 0; +	int offset = 0; + +	const unsigned int id = 0x40; +	const int val_type = USB_MIXER_S16; +	const int control = 1; + +	switch (mixer->chip->usb_id) { +	case USB_ID(0x0763, 0x2030): +		num_outs = 6; +		offset = 0x3c; +		/* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ +		break; +	case USB_ID(0x0763, 0x2031): +		num_outs = 8; +		offset = 0x70; +		/* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */ +		break; +	} + +	for (chan = 0; chan < num_outs; chan++) { +		snprintf(name, sizeof(name), +			"Effect Return %d", +			chan + 1); + +		cmask = (chan == 0) ? 0 : +			1 << (chan + (chan % 2) * num_outs - 1); +		err = snd_create_std_mono_ctl_offset(mixer, id, control, +						cmask, val_type, offset, name, +						&snd_usb_mixer_vol_tlv); +		if (err < 0) +			return err; +	} + +	return 0; +} + +static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)  {  	int err; + +	err = snd_c400_create_vol_ctls(mixer); +	if (err < 0) +		return err; + +	err = snd_c400_create_effect_vol_ctls(mixer); +	if (err < 0) +		return err; + +	err = snd_c400_create_effect_ret_vol_ctls(mixer); +	if (err < 0) +		return err; + +	err = snd_ftu_create_effect_switch(mixer, 2, 0x43); +	if (err < 0) +		return err; + +	err = snd_c400_create_effect_volume_ctl(mixer); +	if (err < 0) +		return err; + +	err = snd_c400_create_effect_duration_ctl(mixer); +	if (err < 0) +		return err; + +	err = snd_c400_create_effect_feedback_ctl(mixer); +	if (err < 0) +		return err; + +	return 0; +} + +/* + * The mixer units for Ebox-44 are corrupt, and even where they + * are valid they presents mono controls as L and R channels of + * stereo. So we provide a good mixer here. + */ +static struct std_mono_table ebox44_table[] = { +	{ +		.unitid = 4, +		.control = 1, +		.cmask = 0x0, +		.val_type = USB_MIXER_INV_BOOLEAN, +		.name = "Headphone Playback Switch" +	}, +	{ +		.unitid = 4, +		.control = 2, +		.cmask = 0x1, +		.val_type = USB_MIXER_S16, +		.name = "Headphone A Mix Playback Volume" +	}, +	{ +		.unitid = 4, +		.control = 2, +		.cmask = 0x2, +		.val_type = USB_MIXER_S16, +		.name = "Headphone B Mix Playback Volume" +	}, + +	{ +		.unitid = 7, +		.control = 1, +		.cmask = 0x0, +		.val_type = USB_MIXER_INV_BOOLEAN, +		.name = "Output Playback Switch" +	}, +	{ +		.unitid = 7, +		.control = 2, +		.cmask = 0x1, +		.val_type = USB_MIXER_S16, +		.name = "Output A Playback Volume" +	}, +	{ +		.unitid = 7, +		.control = 2, +		.cmask = 0x2, +		.val_type = USB_MIXER_S16, +		.name = "Output B Playback Volume" +	}, + +	{ +		.unitid = 10, +		.control = 1, +		.cmask = 0x0, +		.val_type = USB_MIXER_INV_BOOLEAN, +		.name = "Input Capture Switch" +	}, +	{ +		.unitid = 10, +		.control = 2, +		.cmask = 0x1, +		.val_type = USB_MIXER_S16, +		.name = "Input A Capture Volume" +	}, +	{ +		.unitid = 10, +		.control = 2, +		.cmask = 0x2, +		.val_type = USB_MIXER_S16, +		.name = "Input B Capture Volume" +	}, + +	{} +}; + +/* Audio Advantage Micro II findings: + * + * Mapping spdif AES bits to vendor register.bit: + * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 + * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 + * AES2: [0 0 0 0 0 0 0 0] + * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request + *                           (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices + * + * power on values: + * r2: 0x10 + * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set + *           just after it to 0xa0, presumably it disables/mutes some analog + *           parts when there is no audio.) + * r9: 0x28 + * + * Optical transmitter on/off: + * vendor register.bit: 9.1 + * 0 - on (0x28 register value) + * 1 - off (0x2a register value) + * + */ +static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_info *uinfo) +{ +	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; +	uinfo->count = 1; +	return 0; +} + +static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	int err; +	struct usb_interface *iface; +	struct usb_host_interface *alts; +	unsigned int ep; +	unsigned char data[3]; +	int rate; + +	ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; +	ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; +	ucontrol->value.iec958.status[2] = 0x00; + +	/* use known values for that card: interface#1 altsetting#1 */ +	iface = usb_ifnum_to_if(mixer->chip->dev, 1); +	alts = &iface->altsetting[1]; +	ep = get_endpoint(alts, 0)->bEndpointAddress; + +	err = snd_usb_ctl_msg(mixer->chip->dev, +			usb_rcvctrlpipe(mixer->chip->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)); +	if (err < 0) +		goto end; + +	rate = data[0] | (data[1] << 8) | (data[2] << 16); +	ucontrol->value.iec958.status[3] = (rate == 48000) ? +			IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; + +	err = 0; +end: +	return err; +} + +static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	int err; +	u8 reg; +	unsigned long priv_backup = kcontrol->private_value; + +	reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) | +			(ucontrol->value.iec958.status[0] & 0x0f); +	err = snd_usb_ctl_msg(mixer->chip->dev, +			usb_sndctrlpipe(mixer->chip->dev, 0), +			UAC_SET_CUR, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			reg, +			2, +			NULL, +			0); +	if (err < 0) +		goto end; + +	kcontrol->private_value &= 0xfffff0f0; +	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; +	kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f); + +	reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ? +			0xa0 : 0x20; +	reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f; +	err = snd_usb_ctl_msg(mixer->chip->dev, +			usb_sndctrlpipe(mixer->chip->dev, 0), +			UAC_SET_CUR, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			reg, +			3, +			NULL, +			0); +	if (err < 0) +		goto end; + +	kcontrol->private_value &= 0xffff0fff; +	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; + +	/* The frequency bits in AES3 cannot be set via register access. */ + +	/* Silently ignore any bits from the request that cannot be set. */ + +	err = (priv_backup != kcontrol->private_value); +end: +	return err; +} + +static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	ucontrol->value.iec958.status[0] = 0x0f; +	ucontrol->value.iec958.status[1] = 0xff; +	ucontrol->value.iec958.status[2] = 0x00; +	ucontrol->value.iec958.status[3] = 0x00; + +	return 0; +} + +static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); + +	return 0; +} + +static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, +	struct snd_ctl_elem_value *ucontrol) +{ +	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); +	int err; +	u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; + +	err = snd_usb_ctl_msg(mixer->chip->dev, +			usb_sndctrlpipe(mixer->chip->dev, 0), +			UAC_SET_CUR, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, +			reg, +			9, +			NULL, +			0); + +	if (!err) { +		err = (reg != (kcontrol->private_value & 0x0ff)); +		if (err) +			kcontrol->private_value = reg; +	} + +	return err; +} + +static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { +	{ +		.iface =    SNDRV_CTL_ELEM_IFACE_PCM, +		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), +		.info =     snd_microii_spdif_info, +		.get =      snd_microii_spdif_default_get, +		.put =      snd_microii_spdif_default_put, +		.private_value = 0x00000100UL,/* reset value */ +	}, +	{ +		.access =   SNDRV_CTL_ELEM_ACCESS_READ, +		.iface =    SNDRV_CTL_ELEM_IFACE_PCM, +		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), +		.info =     snd_microii_spdif_info, +		.get =      snd_microii_spdif_mask_get, +	}, +	{ +		.iface =    SNDRV_CTL_ELEM_IFACE_MIXER, +		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), +		.info =     snd_ctl_boolean_mono_info, +		.get =      snd_microii_spdif_switch_get, +		.put =      snd_microii_spdif_switch_put, +		.private_value = 0x00000028UL,/* reset value */ +	} +}; + +static int snd_microii_controls_create(struct usb_mixer_interface *mixer) +{ +	int err, i; + +	for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { +		err = snd_ctl_add(mixer->chip->card, +			snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer)); +		if (err < 0) +			return err; +	} + +	return 0; +} + +int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) +{ +	int err = 0;  	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, 0x3042) || -	    mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { -		if ((err = snd_audigy2nx_controls_create(mixer)) < 0) -			return err; +	switch (mixer->chip->usb_id) { +	case USB_ID(0x041e, 0x3020): +	case USB_ID(0x041e, 0x3040): +	case USB_ID(0x041e, 0x3042): +	case USB_ID(0x041e, 0x30df): +	case USB_ID(0x041e, 0x3048): +		err = snd_audigy2nx_controls_create(mixer); +		if (err < 0) +			break;  		if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))  			snd_info_set_text_ops(entry, mixer,  					      snd_audigy2nx_proc_read); -	} +		break; -	if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || -	    mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { -		err = snd_xonar_u1_controls_create(mixer); +	/* EMU0204 */ +	case USB_ID(0x041e, 0x3f19): +		err = snd_emu0204_controls_create(mixer);  		if (err < 0) -			return err; +			break; +		break; + +	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ +	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ +		err = snd_c400_create_mixer(mixer); +		break; + +	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ +	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ +		err = snd_ftu_create_mixer(mixer); +		break; + +	case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ +	case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ +	case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ +		err = snd_xonar_u1_controls_create(mixer); +		break; + +	case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ +		err = snd_microii_controls_create(mixer); +		break; + +	case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ +		err = snd_nativeinstruments_create_mixer(mixer, +				snd_nativeinstruments_ta6_mixers, +				ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); +		break; + +	case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ +		err = snd_nativeinstruments_create_mixer(mixer, +				snd_nativeinstruments_ta10_mixers, +				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); +		break; + +	case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ +		/* detection is disabled in mixer_maps.c */ +		err = snd_create_std_mono_table(mixer, ebox44_table); +		break;  	} -	return 0; +	return err;  }  void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, @@ -417,7 +1699,7 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,  			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); +		usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid);  		break;  	}  } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4132522ac90..c62a1659106 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -16,6 +16,8 @@  #include <linux/init.h>  #include <linux/slab.h> +#include <linux/bitrev.h> +#include <linux/ratelimit.h>  #include <linux/usb.h>  #include <linux/usb/audio.h>  #include <linux/usb/audio-v2.h> @@ -28,10 +30,46 @@  #include "card.h"  #include "quirks.h"  #include "debug.h" -#include "urb.h" +#include "endpoint.h"  #include "helper.h"  #include "pcm.h"  #include "clock.h" +#include "power.h" + +#define SUBSTREAM_FLAG_DATA_EP_STARTED	0 +#define SUBSTREAM_FLAG_SYNC_EP_STARTED	1 + +/* return the estimated delay based on USB frame counters */ +snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, +				    unsigned int rate) +{ +	int current_frame_number; +	int frame_diff; +	int est_delay; + +	if (!subs->last_delay) +		return 0; /* short path */ + +	current_frame_number = usb_get_current_frame_number(subs->dev); +	/* +	 * HCD implementations use different widths, use lower 8 bits. +	 * The delay will be managed up to 256ms, which is more than +	 * enough +	 */ +	frame_diff = (current_frame_number - subs->last_frame_number) & 0xff; + +	/* Approximation based on number of samples per USB frame (ms), +	   some truncation for 44.1 but the estimate is good enough */ +	est_delay =  frame_diff * rate / 1000; +	if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) +		est_delay = subs->last_delay - est_delay; +	else +		est_delay = subs->last_delay + est_delay; + +	if (est_delay < 0) +		est_delay = 0; +	return est_delay; +}  /*   * return the current pcm pointer.  just based on the hwptr_done value. @@ -42,8 +80,12 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream  	unsigned int hwptr_done;  	subs = (struct snd_usb_substream *)substream->runtime->private_data; +	if (subs->stream->chip->shutdown) +		return SNDRV_PCM_POS_XRUN;  	spin_lock(&subs->lock);  	hwptr_done = subs->hwptr_done; +	substream->runtime->delay = snd_usb_pcm_delay(subs, +						substream->runtime->rate);  	spin_unlock(&subs->lock);  	return hwptr_done / (substream->runtime->frame_bits >> 3);  } @@ -51,26 +93,24 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream  /*   * find a matching audio format   */ -static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, -				       unsigned int rate, unsigned int channels) +static struct audioformat *find_format(struct snd_usb_substream *subs)  { -	struct list_head *p; +	struct audioformat *fp;  	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))) +	list_for_each_entry(fp, &subs->fmt_list, list) { +		if (!(fp->formats & pcm_format_to_bits(subs->pcm_format)))  			continue; -		if (fp->channels != channels) +		if (fp->channels != subs->channels)  			continue; -		if (rate < fp->rate_min || rate > fp->rate_max) +		if (subs->cur_rate < fp->rate_min || +		    subs->cur_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) +				if (fp->rate_table[i] == subs->cur_rate)  					break;  			if (i >= fp->nr_rates)  				continue; @@ -125,9 +165,9 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,  	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); +				   data, sizeof(data))) < 0) { +		usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", +			      iface, ep);  		return err;  	} @@ -140,18 +180,15 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,  {  	struct usb_device *dev = chip->dev;  	unsigned char data[1]; -	unsigned int ep;  	int err; -	ep = get_endpoint(alts, 0)->bEndpointAddress; -  	data[0] = 1;  	if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,  				   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,  				   UAC2_EP_CS_PITCH << 8, 0, -				   data, sizeof(data), 1000)) < 0) { -		snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", -			   dev->devnum, iface, fmt->altsetting); +				   data, sizeof(data))) < 0) { +		usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", +			      iface, fmt->altsetting);  		return err;  	} @@ -165,13 +202,11 @@ 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); -  	/* if endpoint doesn't have pitch control, bail out */  	if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))  		return 0; -	switch (altsd->bInterfaceProtocol) { +	switch (fmt->protocol) {  	case UAC_VERSION_1:  	default:  		return init_pitch_v1(chip, iface, alts, fmt); @@ -181,6 +216,234 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,  	}  } +static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep) +{ +	int err; + +	if (!subs->data_endpoint) +		return -EINVAL; + +	if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { +		struct snd_usb_endpoint *ep = subs->data_endpoint; + +		dev_dbg(&subs->dev->dev, "Starting data EP @%p\n", ep); + +		ep->data_subs = subs; +		err = snd_usb_endpoint_start(ep, can_sleep); +		if (err < 0) { +			clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); +			return err; +		} +	} + +	if (subs->sync_endpoint && +	    !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { +		struct snd_usb_endpoint *ep = subs->sync_endpoint; + +		if (subs->data_endpoint->iface != subs->sync_endpoint->iface || +		    subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) { +			err = usb_set_interface(subs->dev, +						subs->sync_endpoint->iface, +						subs->sync_endpoint->altsetting); +			if (err < 0) { +				clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); +				dev_err(&subs->dev->dev, +					   "%d:%d: cannot set interface (%d)\n", +					   subs->sync_endpoint->iface, +					   subs->sync_endpoint->altsetting, err); +				return -EIO; +			} +		} + +		dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep); + +		ep->sync_slave = subs->data_endpoint; +		err = snd_usb_endpoint_start(ep, can_sleep); +		if (err < 0) { +			clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); +			return err; +		} +	} + +	return 0; +} + +static void stop_endpoints(struct snd_usb_substream *subs, bool wait) +{ +	if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) +		snd_usb_endpoint_stop(subs->sync_endpoint); + +	if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) +		snd_usb_endpoint_stop(subs->data_endpoint); + +	if (wait) { +		snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); +		snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); +	} +} + +static int search_roland_implicit_fb(struct usb_device *dev, int ifnum, +				     unsigned int altsetting, +				     struct usb_host_interface **alts, +				     unsigned int *ep) +{ +	struct usb_interface *iface; +	struct usb_interface_descriptor *altsd; +	struct usb_endpoint_descriptor *epd; + +	iface = usb_ifnum_to_if(dev, ifnum); +	if (!iface || iface->num_altsetting < altsetting + 1) +		return -ENOENT; +	*alts = &iface->altsetting[altsetting]; +	altsd = get_iface_desc(*alts); +	if (altsd->bAlternateSetting != altsetting || +	    altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC || +	    (altsd->bInterfaceSubClass != 2 && +	     altsd->bInterfaceProtocol != 2   ) || +	    altsd->bNumEndpoints < 1) +		return -ENOENT; +	epd = get_endpoint(*alts, 0); +	if (!usb_endpoint_is_isoc_in(epd) || +	    (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != +					USB_ENDPOINT_USAGE_IMPLICIT_FB) +		return -ENOENT; +	*ep = epd->bEndpointAddress; +	return 0; +} + +static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, +					 struct usb_device *dev, +					 struct usb_interface_descriptor *altsd, +					 unsigned int attr) +{ +	struct usb_host_interface *alts; +	struct usb_interface *iface; +	unsigned int ep; + +	/* Implicit feedback sync EPs consumers are always playback EPs */ +	if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) +		return 0; + +	switch (subs->stream->chip->usb_id) { +	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ +	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ +		ep = 0x81; +		iface = usb_ifnum_to_if(dev, 3); + +		if (!iface || iface->num_altsetting == 0) +			return -EINVAL; + +		alts = &iface->altsetting[1]; +		goto add_sync_ep; +		break; +	case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ +	case USB_ID(0x0763, 0x2081): +		ep = 0x81; +		iface = usb_ifnum_to_if(dev, 2); + +		if (!iface || iface->num_altsetting == 0) +			return -EINVAL; + +		alts = &iface->altsetting[1]; +		goto add_sync_ep; +	} +	if (attr == USB_ENDPOINT_SYNC_ASYNC && +	    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && +	    altsd->bInterfaceProtocol == 2 && +	    altsd->bNumEndpoints == 1 && +	    USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && +	    search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, +				      altsd->bAlternateSetting, +				      &alts, &ep) >= 0) { +		goto add_sync_ep; +	} + +	/* No quirk */ +	return 0; + +add_sync_ep: +	subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, +						   alts, ep, !subs->direction, +						   SND_USB_ENDPOINT_TYPE_DATA); +	if (!subs->sync_endpoint) +		return -EINVAL; + +	subs->data_endpoint->sync_master = subs->sync_endpoint; + +	return 0; +} + +static int set_sync_endpoint(struct snd_usb_substream *subs, +			     struct audioformat *fmt, +			     struct usb_device *dev, +			     struct usb_host_interface *alts, +			     struct usb_interface_descriptor *altsd) +{ +	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; +	unsigned int ep, attr; +	bool implicit_fb; +	int err; + +	/* 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; + +	err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); +	if (err < 0) +		return err; + +	if (altsd->bNumEndpoints < 2) +		return 0; + +	if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) || +	    (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) +		return 0; + +	/* 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) != USB_ENDPOINT_XFER_ISOC || +	    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && +	     get_endpoint(alts, 1)->bSynchAddress != 0)) { +		dev_err(&dev->dev, +			"%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n", +			   fmt->iface, fmt->altsetting, +			   get_endpoint(alts, 1)->bmAttributes, +			   get_endpoint(alts, 1)->bLength, +			   get_endpoint(alts, 1)->bSynchAddress); +		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)))) { +		dev_err(&dev->dev, +			"%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", +			   fmt->iface, fmt->altsetting, +			   is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); +		return -EINVAL; +	} + +	implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) +			== USB_ENDPOINT_USAGE_IMPLICIT_FB; + +	subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, +						   alts, ep, !subs->direction, +						   implicit_fb ? +							SND_USB_ENDPOINT_TYPE_DATA : +							SND_USB_ENDPOINT_TYPE_SYNC); +	if (!subs->sync_endpoint) +		return -EINVAL; + +	subs->data_endpoint->sync_master = subs->sync_endpoint; + +	return 0; +} +  /*   * find a matching format and set up the interface   */ @@ -190,8 +453,6 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)  	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); @@ -207,9 +468,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)  	/* 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); +		err = usb_set_interface(subs->dev, subs->interface, 0); +		if (err < 0) { +			dev_err(&dev->dev, +				"%d:%d: return to setting 0 failed (%d)\n", +				fmt->iface, fmt->altsetting, err);  			return -EIO;  		}  		subs->interface = -1; @@ -217,100 +480,192 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)  	}  	/* 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); +	if (subs->interface != fmt->iface || +	    subs->altset_idx != fmt->altset_idx) { +		err = usb_set_interface(dev, fmt->iface, fmt->altsetting); +		if (err < 0) { +			dev_err(&dev->dev, +				"%d:%d: usb_set_interface failed (%d)\n", +				fmt->iface, fmt->altsetting, err);  			return -EIO;  		} -		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); +		dev_dbg(&dev->dev, "setting usb interface %d:%d\n", +			fmt->iface, fmt->altsetting);  		subs->interface = fmt->iface;  		subs->altset_idx = fmt->altset_idx; + +		snd_usb_set_interface_quirk(dev);  	} -	/* 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->syncmaxsize = 0; -	subs->fill_max = 0; +	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, +						   alts, fmt->endpoint, subs->direction, +						   SND_USB_ENDPOINT_TYPE_DATA); -	/* 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; -		subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); -	} +	if (!subs->data_endpoint) +		return -EINVAL; -	/* always fill max packet size */ -	if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) -		subs->fill_max = 1; +	err = set_sync_endpoint(subs, fmt, dev, alts, altsd); +	if (err < 0) +		return err; -	if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) +	err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); +	if (err < 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;  }  /* + * Return the score of matching two audioformats. + * Veto the audioformat if: + * - It has no channels for some reason. + * - Requested PCM format is not supported. + * - Requested sample rate is not supported. + */ +static int match_endpoint_audioformats(struct snd_usb_substream *subs, +				       struct audioformat *fp, +				       struct audioformat *match, int rate, +				       snd_pcm_format_t pcm_format) +{ +	int i; +	int score = 0; + +	if (fp->channels < 1) { +		dev_dbg(&subs->dev->dev, +			"%s: (fmt @%p) no channels\n", __func__, fp); +		return 0; +	} + +	if (!(fp->formats & pcm_format_to_bits(pcm_format))) { +		dev_dbg(&subs->dev->dev, +			"%s: (fmt @%p) no match for format %d\n", __func__, +			fp, pcm_format); +		return 0; +	} + +	for (i = 0; i < fp->nr_rates; i++) { +		if (fp->rate_table[i] == rate) { +			score++; +			break; +		} +	} +	if (!score) { +		dev_dbg(&subs->dev->dev, +			"%s: (fmt @%p) no match for rate %d\n", __func__, +			fp, rate); +		return 0; +	} + +	if (fp->channels == match->channels) +		score++; + +	dev_dbg(&subs->dev->dev, +		"%s: (fmt @%p) score %d\n", __func__, fp, score); + +	return score; +} + +/* + * Configure the sync ep using the rate and pcm format of the data ep. + */ +static int configure_sync_endpoint(struct snd_usb_substream *subs) +{ +	int ret; +	struct audioformat *fp; +	struct audioformat *sync_fp = NULL; +	int cur_score = 0; +	int sync_period_bytes = subs->period_bytes; +	struct snd_usb_substream *sync_subs = +		&subs->stream->substream[subs->direction ^ 1]; + +	if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA || +	    !subs->stream) +		return snd_usb_endpoint_set_params(subs->sync_endpoint, +						   subs->pcm_format, +						   subs->channels, +						   subs->period_bytes, +						   0, 0, +						   subs->cur_rate, +						   subs->cur_audiofmt, +						   NULL); + +	/* Try to find the best matching audioformat. */ +	list_for_each_entry(fp, &sync_subs->fmt_list, list) { +		int score = match_endpoint_audioformats(subs, +							fp, subs->cur_audiofmt, +			subs->cur_rate, subs->pcm_format); + +		if (score > cur_score) { +			sync_fp = fp; +			cur_score = score; +		} +	} + +	if (unlikely(sync_fp == NULL)) { +		dev_err(&subs->dev->dev, +			"%s: no valid audioformat for sync ep %x found\n", +			__func__, sync_subs->ep_num); +		return -EINVAL; +	} + +	/* +	 * Recalculate the period bytes if channel number differ between +	 * data and sync ep audioformat. +	 */ +	if (sync_fp->channels != subs->channels) { +		sync_period_bytes = (subs->period_bytes / subs->channels) * +			sync_fp->channels; +		dev_dbg(&subs->dev->dev, +			"%s: adjusted sync ep period bytes (%d -> %d)\n", +			__func__, subs->period_bytes, sync_period_bytes); +	} + +	ret = snd_usb_endpoint_set_params(subs->sync_endpoint, +					  subs->pcm_format, +					  sync_fp->channels, +					  sync_period_bytes, +					  0, 0, +					  subs->cur_rate, +					  sync_fp, +					  NULL); + +	return ret; +} + +/* + * configure endpoint params + * + * called  during initial setup and upon resume + */ +static int configure_endpoint(struct snd_usb_substream *subs) +{ +	int ret; + +	/* format changed */ +	stop_endpoints(subs, true); +	ret = snd_usb_endpoint_set_params(subs->data_endpoint, +					  subs->pcm_format, +					  subs->channels, +					  subs->period_bytes, +					  subs->period_frames, +					  subs->buffer_periods, +					  subs->cur_rate, +					  subs->cur_audiofmt, +					  subs->sync_endpoint); +	if (ret < 0) +		return ret; + +	if (subs->sync_endpoint) +		ret = configure_sync_endpoint(subs); + +	return ret; +} + +/*   * hw_params callback   *   * allocate a buffer and set the given audio format. @@ -325,52 +680,42 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,  {  	struct snd_usb_substream *subs = substream->runtime->private_data;  	struct audioformat *fmt; -	unsigned int channels, rate, format; -	int ret, changed; +	int ret;  	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); +	subs->pcm_format = params_format(hw_params); +	subs->period_bytes = params_period_bytes(hw_params); +	subs->period_frames = params_period_size(hw_params); +	subs->buffer_periods = params_periods(hw_params); +	subs->channels = params_channels(hw_params); +	subs->cur_rate = params_rate(hw_params); + +	fmt = find_format(subs);  	if (!fmt) { -		snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", -			   format, rate, channels); +		dev_dbg(&subs->dev->dev, +			"cannot set format: format = %#x, rate = %d, channels = %d\n", +			   subs->pcm_format, subs->cur_rate, subs->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) +	down_read(&subs->stream->chip->shutdown_rwsem); +	if (subs->stream->chip->shutdown) +		ret = -ENODEV; +	else +		ret = set_format(subs, fmt); +	up_read(&subs->stream->chip->shutdown_rwsem); +	if (ret < 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)); -	} +	subs->interface = fmt->iface; +	subs->altset_idx = fmt->altset_idx; +	subs->need_setup_ep = true; -	return ret; +	return 0;  }  /* @@ -385,8 +730,13 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)  	subs->cur_audiofmt = NULL;  	subs->cur_rate = 0;  	subs->period_bytes = 0; -	if (!subs->stream->chip->shutdown) -		snd_usb_release_substream_urbs(subs, 0); +	down_read(&subs->stream->chip->shutdown_rwsem); +	if (!subs->stream->chip->shutdown) { +		stop_endpoints(subs, true); +		snd_usb_endpoint_deactivate(subs->sync_endpoint); +		snd_usb_endpoint_deactivate(subs->data_endpoint); +	} +	up_read(&subs->stream->chip->shutdown_rwsem);  	return snd_pcm_lib_free_vmalloc_buffer(substream);  } @@ -399,23 +749,70 @@ 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; +	struct usb_host_interface *alts; +	struct usb_interface *iface; +	int ret;  	if (! subs->cur_audiofmt) { -		snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); +		dev_err(&subs->dev->dev, "no format is specified!\n");  		return -ENXIO;  	} +	down_read(&subs->stream->chip->shutdown_rwsem); +	if (subs->stream->chip->shutdown) { +		ret = -ENODEV; +		goto unlock; +	} +	if (snd_BUG_ON(!subs->data_endpoint)) { +		ret = -EIO; +		goto unlock; +	} + +	snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); +	snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); + +	ret = set_format(subs, subs->cur_audiofmt); +	if (ret < 0) +		goto unlock; + +	iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); +	alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; +	ret = snd_usb_init_sample_rate(subs->stream->chip, +				       subs->cur_audiofmt->iface, +				       alts, +				       subs->cur_audiofmt, +				       subs->cur_rate); +	if (ret < 0) +		goto unlock; + +	if (subs->need_setup_ep) { +		ret = configure_endpoint(subs); +		if (ret < 0) +			goto unlock; +		subs->need_setup_ep = false; +	} +  	/* some unit conversions in runtime */ -	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); -	subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); +	subs->data_endpoint->maxframesize = +		bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); +	subs->data_endpoint->curframesize = +		bytes_to_frames(runtime, subs->data_endpoint->curpacksize);  	/* reset the pointer */  	subs->hwptr_done = 0;  	subs->transfer_done = 0; -	subs->phase = 0; +	subs->last_delay = 0; +	subs->last_frame_number = 0;  	runtime->delay = 0; -	return snd_usb_substream_prepare(subs, runtime); +	/* 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) +		ret = start_endpoints(subs, true); + + unlock: +	up_read(&subs->stream->chip->shutdown_rwsem); +	return ret;  }  static struct snd_pcm_hardware snd_usb_hardware = @@ -468,7 +865,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,  		return 0;  	}  	/* check whether the period time is >= the data packet interval */ -	if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { +	if (subs->speed != USB_SPEED_FULL) {  		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); @@ -482,7 +879,7 @@ 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 audioformat *fp;  	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);  	unsigned int rmin, rmax;  	int changed; @@ -490,9 +887,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,  	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); +	list_for_each_entry(fp, &subs->fmt_list, list) {  		if (!hw_check_valid_format(subs, params, fp))  			continue;  		if (changed++) { @@ -536,7 +931,7 @@ 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 audioformat *fp;  	struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);  	unsigned int rmin, rmax;  	int changed; @@ -544,9 +939,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,  	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); +	list_for_each_entry(fp, &subs->fmt_list, list) {  		if (!hw_check_valid_format(subs, params, fp))  			continue;  		if (changed++) { @@ -589,7 +982,7 @@ 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 audioformat *fp;  	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);  	u64 fbits;  	u32 oldbits[2]; @@ -597,9 +990,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,  	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); +	list_for_each_entry(fp, &subs->fmt_list, list) {  		if (!hw_check_valid_format(subs, params, fp))  			continue;  		fbits |= fp->formats; @@ -663,9 +1054,13 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,  				  struct snd_usb_substream *subs)  {  	struct audioformat *fp; +	int *rate_list;  	int count = 0, needs_knot = 0;  	int err; +	kfree(subs->rate_list.list); +	subs->rate_list.list = NULL; +  	list_for_each_entry(fp, &subs->fmt_list, list) {  		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)  			return 0; @@ -676,7 +1071,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,  	if (!needs_knot)  		return 0; -	subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); +	subs->rate_list.list = rate_list = +		kmalloc(sizeof(int) * count, GFP_KERNEL);  	if (!subs->rate_list.list)  		return -ENOMEM;  	subs->rate_list.count = count; @@ -685,7 +1081,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,  	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]; +			rate_list[count++] = fp->rate_table[i];  	}  	err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,  					 &subs->rate_list); @@ -702,7 +1098,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,  static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)  { -	struct list_head *p; +	struct audioformat *fp;  	unsigned int pt, ptmin;  	int param_period_time_if_needed;  	int err; @@ -716,9 +1112,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre  	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); +	list_for_each_entry(fp, &subs->fmt_list, list) {  		runtime->hw.rates |= fp->rates;  		if (runtime->hw.rate_min > fp->rate_min)  			runtime->hw.rate_min = fp->rate_min; @@ -736,9 +1130,12 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre  		pt = 125 * (1 << fp->datainterval);  		ptmin = min(ptmin, pt);  	} +	err = snd_usb_autoresume(subs->stream->chip); +	if (err < 0) +		return err;  	param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; -	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) +	if (subs->speed == USB_SPEED_FULL)  		/* full speed devices have fixed data packet interval */  		ptmin = 1000;  	if (ptmin == 1000) @@ -753,21 +1150,21 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre  				       SNDRV_PCM_HW_PARAM_CHANNELS,  				       param_period_time_if_needed,  				       -1)) < 0) -		return err; +		goto rep_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; +		goto rep_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; +		goto rep_err;  	if (param_period_time_if_needed >= 0) {  		err = snd_pcm_hw_rule_add(runtime, 0,  					  SNDRV_PCM_HW_PARAM_PERIOD_TIME, @@ -777,11 +1174,15 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre  					  SNDRV_PCM_HW_PARAM_RATE,  					  -1);  		if (err < 0) -			return err; +			goto rep_err;  	}  	if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) -		return err; +		goto rep_err;  	return 0; + +rep_err: +	snd_usb_autosuspend(subs->stream->chip); +	return err;  }  static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) @@ -795,6 +1196,13 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)  	runtime->hw = snd_usb_hardware;  	runtime->private_data = subs;  	subs->pcm_substream = substream; +	/* runtime PM is also done there */ + +	/* initialize DSD/DOP context */ +	subs->dsd_dop.byte_idx = 0; +	subs->dsd_dop.channel = 0; +	subs->dsd_dop.marker = 1; +  	return setup_hw_info(runtime, subs);  } @@ -803,14 +1211,313 @@ 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]; +	stop_endpoints(subs, true); +  	if (!as->chip->shutdown && subs->interface >= 0) {  		usb_set_interface(subs->dev, subs->interface, 0);  		subs->interface = -1;  	} +  	subs->pcm_substream = NULL; +	snd_usb_autosuspend(subs->stream->chip); +  	return 0;  } +/* 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 void retire_capture_urb(struct snd_usb_substream *subs, +			       struct urb *urb) +{ +	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; +	unsigned int stride, frames, bytes, oldptr; +	int i, period_elapsed = 0; +	unsigned long flags; +	unsigned char *cp; +	int current_frame_number; + +	/* read frame number here, update pointer in critical section */ +	current_frame_number = usb_get_current_frame_number(subs->dev); + +	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 + subs->pkt_offset_adj; +		if (urb->iso_frame_desc[i].status && printk_ratelimit()) { +			dev_dbg(&subs->dev->dev, "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) { +			int oldbytes = bytes; +			bytes = frames * stride; +			dev_warn(&subs->dev->dev, +				 "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; +		} +		/* capture delay is by construction limited to one URB, +		 * reset delays here +		 */ +		runtime->delay = subs->last_delay = 0; + +		/* realign last_frame_number */ +		subs->last_frame_number = current_frame_number; +		subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + +		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); +} + +static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, +					     struct urb *urb, unsigned int bytes) +{ +	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; +	unsigned int stride = runtime->frame_bits >> 3; +	unsigned int dst_idx = 0; +	unsigned int src_idx = subs->hwptr_done; +	unsigned int wrap = runtime->buffer_size * stride; +	u8 *dst = urb->transfer_buffer; +	u8 *src = runtime->dma_area; +	u8 marker[] = { 0x05, 0xfa }; + +	/* +	 * The DSP DOP format defines a way to transport DSD samples over +	 * normal PCM data endpoints. It requires stuffing of marker bytes +	 * (0x05 and 0xfa, alternating per sample frame), and then expects +	 * 2 additional bytes of actual payload. The whole frame is stored +	 * LSB. +	 * +	 * Hence, for a stereo transport, the buffer layout looks like this, +	 * where L refers to left channel samples and R to right. +	 * +	 *   L1 L2 0x05   R1 R2 0x05   L3 L4 0xfa  R3 R4 0xfa +	 *   L5 L6 0x05   R5 R6 0x05   L7 L8 0xfa  R7 R8 0xfa +	 *   ..... +	 * +	 */ + +	while (bytes--) { +		if (++subs->dsd_dop.byte_idx == 3) { +			/* frame boundary? */ +			dst[dst_idx++] = marker[subs->dsd_dop.marker]; +			src_idx += 2; +			subs->dsd_dop.byte_idx = 0; + +			if (++subs->dsd_dop.channel % runtime->channels == 0) { +				/* alternate the marker */ +				subs->dsd_dop.marker++; +				subs->dsd_dop.marker %= ARRAY_SIZE(marker); +				subs->dsd_dop.channel = 0; +			} +		} else { +			/* stuff the DSD payload */ +			int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap; + +			if (subs->cur_audiofmt->dsd_bitrev) +				dst[dst_idx++] = bitrev8(src[idx]); +			else +				dst[dst_idx++] = src[idx]; + +			subs->hwptr_done++; +		} +	} +} + +static void prepare_playback_urb(struct snd_usb_substream *subs, +				 struct urb *urb) +{ +	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; +	struct snd_usb_endpoint *ep = subs->data_endpoint; +	struct snd_urb_ctx *ctx = urb->context; +	unsigned int counts, frames, bytes; +	int i, stride, period_elapsed = 0; +	unsigned long flags; + +	stride = runtime->frame_bits >> 3; + +	frames = 0; +	urb->number_of_packets = 0; +	spin_lock_irqsave(&subs->lock, flags); +	subs->frame_limit += ep->max_urb_frames; +	for (i = 0; i < ctx->packets; i++) { +		if (ctx->packet_size[i]) +			counts = ctx->packet_size[i]; +		else +			counts = snd_usb_endpoint_next_packet_size(ep); + +		/* set up descriptor */ +		urb->iso_frame_desc[i].offset = frames * ep->stride; +		urb->iso_frame_desc[i].length = counts * ep->stride; +		frames += counts; +		urb->number_of_packets++; +		subs->transfer_done += counts; +		if (subs->transfer_done >= runtime->period_size) { +			subs->transfer_done -= runtime->period_size; +			subs->frame_limit = 0; +			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 * ep->stride; +					subs->transfer_done = 0; +				} +				i++; +				if (i < ctx->packets) { +					/* add a transfer delimiter */ +					urb->iso_frame_desc[i].offset = +						frames * ep->stride; +					urb->iso_frame_desc[i].length = 0; +					urb->number_of_packets++; +				} +				break; +			} +		} +		/* finish at the period boundary or after enough frames */ +		if ((period_elapsed || +				subs->transfer_done >= subs->frame_limit) && +		    !snd_usb_endpoint_implicit_feedback_sink(ep)) +			break; +	} +	bytes = frames * ep->stride; + +	if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && +		     subs->cur_audiofmt->dsd_dop)) { +		fill_playback_urb_dsd_dop(subs, urb, bytes); +	} else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 && +			   subs->cur_audiofmt->dsd_bitrev)) { +		/* bit-reverse the bytes */ +		u8 *buf = urb->transfer_buffer; +		for (i = 0; i < bytes; i++) { +			int idx = (subs->hwptr_done + i) +				% (runtime->buffer_size * stride); +			buf[i] = bitrev8(runtime->dma_area[idx]); +		} + +		subs->hwptr_done += bytes; +	} else { +		/* usual PCM */ +		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; + +	/* update delay with exact number of samples queued */ +	runtime->delay = subs->last_delay; +	runtime->delay += frames; +	subs->last_delay = runtime->delay; + +	/* realign last_frame_number */ +	subs->last_frame_number = usb_get_current_frame_number(subs->dev); +	subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + +	spin_unlock_irqrestore(&subs->lock, flags); +	urb->transfer_buffer_length = bytes; +	if (period_elapsed) +		snd_pcm_period_elapsed(subs->pcm_substream); +} + +/* + * process after playback data complete + * - decrease the delay count again + */ +static void retire_playback_urb(struct snd_usb_substream *subs, +			       struct urb *urb) +{ +	unsigned long flags; +	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; +	struct snd_usb_endpoint *ep = subs->data_endpoint; +	int processed = urb->transfer_buffer_length / ep->stride; +	int est_delay; + +	/* ignore the delay accounting when procssed=0 is given, i.e. +	 * silent payloads are procssed before handling the actual data +	 */ +	if (!processed) +		return; + +	spin_lock_irqsave(&subs->lock, flags); +	if (!subs->last_delay) +		goto out; /* short path */ + +	est_delay = snd_usb_pcm_delay(subs, runtime->rate); +	/* update delay with exact number of samples played */ +	if (processed > subs->last_delay) +		subs->last_delay = 0; +	else +		subs->last_delay -= processed; +	runtime->delay = subs->last_delay; + +	/* +	 * Report when delay estimate is off by more than 2ms. +	 * The error should be lower than 2ms since the estimate relies +	 * on two reads of a counter updated every ms. +	 */ +	if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) +		dev_dbg_ratelimited(&subs->dev->dev, +			"delay: estimated %d, actual %d\n", +			est_delay, subs->last_delay); + +	if (!subs->running) { +		/* update last_frame_number for delay counting here since +		 * prepare_playback_urb won't be called during pause +		 */ +		subs->last_frame_number = +			usb_get_current_frame_number(subs->dev) & 0xff; +	} + + out: +	spin_unlock_irqrestore(&subs->lock, flags); +} +  static int snd_usb_playback_open(struct snd_pcm_substream *substream)  {  	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); @@ -831,6 +1538,65 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)  	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);  } +static 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->data_endpoint->prepare_data_urb = prepare_playback_urb; +		subs->data_endpoint->retire_data_urb = retire_playback_urb; +		subs->running = 1; +		return 0; +	case SNDRV_PCM_TRIGGER_STOP: +		stop_endpoints(subs, false); +		subs->running = 0; +		return 0; +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		subs->data_endpoint->prepare_data_urb = NULL; +		/* keep retire_data_urb for delay calculation */ +		subs->data_endpoint->retire_data_urb = retire_playback_urb; +		subs->running = 0; +		return 0; +	} + +	return -EINVAL; +} + +static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, +					     int cmd) +{ +	int err; +	struct snd_usb_substream *subs = substream->runtime->private_data; + +	switch (cmd) { +	case SNDRV_PCM_TRIGGER_START: +		err = start_endpoints(subs, false); +		if (err < 0) +			return err; + +		subs->data_endpoint->retire_data_urb = retire_capture_urb; +		subs->running = 1; +		return 0; +	case SNDRV_PCM_TRIGGER_STOP: +		stop_endpoints(subs, false); +		subs->running = 0; +		return 0; +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +		subs->data_endpoint->retire_data_urb = NULL; +		subs->running = 0; +		return 0; +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +		subs->data_endpoint->retire_data_urb = retire_capture_urb; +		subs->running = 1; +		return 0; +	} + +	return -EINVAL; +} +  static struct snd_pcm_ops snd_usb_playback_ops = {  	.open =		snd_usb_playback_open,  	.close =	snd_usb_playback_close, diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index ed3e283f618..df7a003682a 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -1,6 +1,9 @@  #ifndef __USBAUDIO_PCM_H  #define __USBAUDIO_PCM_H +snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, +				    unsigned int rate); +  void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);  int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, diff --git a/sound/usb/power.h b/sound/usb/power.h new file mode 100644 index 00000000000..48ee51dcb71 --- /dev/null +++ b/sound/usb/power.h @@ -0,0 +1,17 @@ +#ifndef __USBAUDIO_POWER_H +#define __USBAUDIO_POWER_H + +#ifdef CONFIG_PM +int snd_usb_autoresume(struct snd_usb_audio *chip); +void snd_usb_autosuspend(struct snd_usb_audio *chip); +#else +static inline int snd_usb_autoresume(struct snd_usb_audio *chip) +{ +	return 0; +} +static inline void snd_usb_autosuspend(struct snd_usb_audio *chip) +{ +} +#endif + +#endif /* __USBAUDIO_POWER_H */ diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 961c9a25068..5f761ab34c0 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -25,6 +25,7 @@  #include "usbaudio.h"  #include "helper.h"  #include "card.h" +#include "endpoint.h"  #include "proc.h"  /* convert our full speed USB rate into sampling rate in Hz */ @@ -72,20 +73,19 @@ void snd_usb_audio_create_proc(struct snd_usb_audio *chip)   */  static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)  { -	struct list_head *p; +	struct audioformat *fp;  	static char *sync_types[4] = {  		"NONE", "ASYNC", "ADAPTIVE", "SYNC"  	}; -	list_for_each(p, &subs->fmt_list) { -		struct audioformat *fp; +	list_for_each_entry(fp, &subs->fmt_list, list) {  		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)) +			if (fp->formats & pcm_format_to_bits(fmt))  				snd_iprintf(buffer, " %s",  					    snd_pcm_format_name(fmt));  		snd_iprintf(buffer, "\n"); @@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s  			}  			snd_iprintf(buffer, "\n");  		} -		if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) +		if (subs->speed != USB_SPEED_FULL)  			snd_iprintf(buffer, "    Data packet interval: %d us\n",  				    125 * (1 << fp->datainterval));  		// snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize); @@ -115,28 +115,33 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s  	}  } +static void proc_dump_ep_status(struct snd_usb_substream *subs, +				struct snd_usb_endpoint *data_ep, +				struct snd_usb_endpoint *sync_ep, +				struct snd_info_buffer *buffer) +{ +	if (!data_ep) +		return; +	snd_iprintf(buffer, "    Packet Size = %d\n", data_ep->curpacksize); +	snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n", +		    subs->speed == USB_SPEED_FULL +		    ? get_full_speed_hz(data_ep->freqm) +		    : get_high_speed_hz(data_ep->freqm), +		    data_ep->freqm >> 16, data_ep->freqm & 0xffff); +	if (sync_ep && data_ep->freqshift != INT_MIN) { +		int res = 16 - data_ep->freqshift; +		snd_iprintf(buffer, "    Feedback Format = %d.%d\n", +			    (sync_ep->syncmaxsize > 3 ? 32 : 24) - res, res); +	} +} +  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); -		if (subs->freqshift != INT_MIN) -			snd_iprintf(buffer, "    Feedback Format = %d.%d\n", -				    (subs->syncmaxsize > 3 ? 32 : 24) -						- (16 - subs->freqshift), -				    16 - subs->freqshift); +		proc_dump_ep_status(subs, subs->data_endpoint, subs->sync_endpoint, buffer);  	} else {  		snd_iprintf(buffer, "  Status: Stop\n");  	} diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index ad7079d1676..f652b10ce90 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -39,13 +39,36 @@  	.idProduct = prod, \  	.bInterfaceClass = USB_CLASS_VENDOR_SPEC -/* Creative/Toshiba Multimedia Center SB-0500 */ +/* FTDI devices */  { -	USB_DEVICE(0x041e, 0x3048), +	USB_DEVICE(0x0403, 0xb8d8),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "Toshiba", -		.product_name = "SB-0500", -		.ifnum = QUIRK_NO_INTERFACE +		/* .vendor_name = "STARR LABS", */ +		/* .product_name = "Starr Labs MIDI USB device", */ +		.ifnum = 0, +		.type = QUIRK_MIDI_FTDI +	} +}, + +{ +	/* Creative BT-D1 */ +	USB_DEVICE(0x041e, 0x0005), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.ifnum = 1, +		.type = QUIRK_AUDIO_FIXED_ENDPOINT, +		.data = &(const struct audioformat) { +			.formats = SNDRV_PCM_FMTBIT_S16_LE, +			.channels = 2, +			.iface = 1, +			.altsetting = 1, +			.altset_idx = 1, +			.endpoint = 0x03, +			.ep_attr = USB_ENDPOINT_XFER_ISOC, +			.attributes = 0, +			.rates = SNDRV_PCM_RATE_CONTINUOUS, +			.rate_min = 48000, +			.rate_max = 48000, +		}  	}  }, @@ -58,6 +81,15 @@  		.ifnum = QUIRK_NO_INTERFACE  	}  }, +/* Creative/Toshiba Multimedia Center SB-0500 */ +{ +	USB_DEVICE(0x041e, 0x3048), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		.vendor_name = "Toshiba", +		.product_name = "SB-0500", +		.ifnum = QUIRK_NO_INTERFACE +	} +},  {  	/* E-Mu 0202 USB */  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -79,6 +111,49 @@  	.idProduct = 0x3f0a,  	.bInterfaceClass = USB_CLASS_AUDIO,  }, +{ +	/* E-Mu 0204 USB */ +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +	.idVendor = 0x041e, +	.idProduct = 0x3f19, +	.bInterfaceClass = USB_CLASS_AUDIO, +}, + +/* + * HP Wireless Audio + * When not ignored, causes instability issues for some users, forcing them to + * blacklist the entire module. + */ +{ +	USB_DEVICE(0x0424, 0xb832), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "Standard Microsystems Corp.", +		.product_name = "HP Wireless Audio", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			/* Mixer */ +			{ +				.ifnum = 0, +				.type = QUIRK_IGNORE_INTERFACE, +			}, +			/* Playback */ +			{ +				.ifnum = 1, +				.type = QUIRK_IGNORE_INTERFACE, +			}, +			/* Capture */ +			{ +				.ifnum = 2, +				.type = QUIRK_IGNORE_INTERFACE, +			}, +			/* HID Device, .ifnum = 3 */ +			{ +				.ifnum = -1, +			} +		} +	} +},  /*   * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface @@ -139,7 +214,13 @@  	.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL  },  { -	USB_DEVICE(0x046d, 0x0990), +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | +		       USB_DEVICE_ID_MATCH_INT_CLASS | +		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, +	.idVendor = 0x046d, +	.idProduct = 0x0990, +	.bInterfaceClass = USB_CLASS_AUDIO, +	.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {  		.vendor_name = "Logitech, Inc.",  		.product_name = "QuickCam Pro 9000", @@ -251,6 +332,110 @@ YAMAHA_DEVICE(0x105a, NULL),  YAMAHA_DEVICE(0x105b, NULL),  YAMAHA_DEVICE(0x105c, NULL),  YAMAHA_DEVICE(0x105d, NULL), +{ +	USB_DEVICE(0x0499, 0x1503), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "Yamaha", */ +		/* .product_name = "MOX6/MOX8", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 3, +				.type = QUIRK_MIDI_YAMAHA +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	USB_DEVICE(0x0499, 0x1507), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "Yamaha", */ +		/* .product_name = "THR10", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 3, +				.type = QUIRK_MIDI_YAMAHA +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	USB_DEVICE(0x0499, 0x150a), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "Yamaha", */ +		/* .product_name = "THR5A", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 3, +				.type = QUIRK_MIDI_YAMAHA +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	USB_DEVICE(0x0499, 0x150c), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "Yamaha", */ +		/* .product_name = "THR10C", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 3, +				.type = QUIRK_MIDI_YAMAHA +			}, +			{ +				.ifnum = -1 +			} +		} +	} +},  YAMAHA_DEVICE(0x2000, "DGP-7"),  YAMAHA_DEVICE(0x2001, "DGP-5"),  YAMAHA_DEVICE(0x2002, NULL), @@ -275,6 +460,17 @@ YAMAHA_DEVICE(0x7000, "DTX"),  YAMAHA_DEVICE(0x7010, "UB99"),  #undef YAMAHA_DEVICE  #undef YAMAHA_INTERFACE +/* this catches most recent vendor-specific Yamaha devices */ +{ +	.match_flags = USB_DEVICE_ID_MATCH_VENDOR | +	               USB_DEVICE_ID_MATCH_INT_CLASS, +	.idVendor = 0x0499, +	.bInterfaceClass = USB_CLASS_VENDOR_SPEC, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_AUTODETECT +	} +},  /*   * Roland/RolandED/Edirol/BOSS devices @@ -705,11 +901,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		.data = (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_IGNORE_INTERFACE +				.type = QUIRK_AUDIO_STANDARD_INTERFACE  			},  			{  				.ifnum = 1, -				.type = QUIRK_IGNORE_INTERFACE +				.type = QUIRK_AUDIO_STANDARD_INTERFACE  			},  			{  				.ifnum = 2, @@ -950,7 +1146,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, -	/* TODO: add Roland M-1000 support */  {  	/*  	 * Has ID 0x0038 when not in "Advanced Driver" mode; @@ -1065,7 +1260,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, -	/* TODO: add Edirol M-100FX support */  {  	/* has ID 0x004e when not in "Advanced Driver" mode */  	USB_DEVICE(0x0582, 0x004c), @@ -1185,20 +1379,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	/* has ID 0x006b when not in "Advanced Driver" mode */ -	USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "Roland", -		.product_name = "SP-606", -		.ifnum = 3, -		.type = QUIRK_MIDI_FIXED_ENDPOINT, -		.data = & (const struct snd_usb_midi_endpoint_info) { -			.out_cables = 0x0001, -			.in_cables  = 0x0001 -		} -	} -}, -{  	/* has ID 0x006e when not in "Advanced Driver" mode */  	USB_DEVICE(0x0582, 0x006d),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1285,8 +1465,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, -	/* TODO: add Roland V-SYNTH XT support */ -	/* TODO: add BOSS GT-PRO support */  {  	/* has ID 0x008c when not in "Advanced Driver" mode */  	USB_DEVICE(0x0582, 0x008b), @@ -1301,42 +1479,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, -	/* TODO: add Edirol PC-80 support */ -{ -	USB_DEVICE(0x0582, 0x0096), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "EDIROL", -		.product_name = "UA-1EX", -		.ifnum = QUIRK_ANY_INTERFACE, -		.type = QUIRK_COMPOSITE, -		.data = (const struct snd_usb_audio_quirk[]) { -			{ -				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE -			}, -			{ -				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE -			}, -			{ -				.ifnum = -1 -			} -		} -	} -}, -{ -	USB_DEVICE(0x0582, 0x009a), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "EDIROL", -		.product_name = "UM-3EX", -		.ifnum = 0, -		.type = QUIRK_MIDI_FIXED_ENDPOINT, -		.data = & (const struct snd_usb_midi_endpoint_info) { -			.out_cables = 0x000f, -			.in_cables  = 0x000f -		} -	} -},  {  	/*  	 * This quirk is for the "Advanced Driver" mode. If off, the UA-4FX @@ -1367,26 +1509,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		}  	}  }, -	/* TODO: add Edirol MD-P1 support */ -{ -	USB_DEVICE(0x582, 0x00a6), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "Roland", -		.product_name = "Juno-G", -		.ifnum = 0, -		.type = QUIRK_MIDI_FIXED_ENDPOINT, -		.data = & (const struct snd_usb_midi_endpoint_info) { -			.out_cables = 0x0001, -			.in_cables  = 0x0001 -		} -	} -},  { -	/* Roland SH-201 */ -	USB_DEVICE(0x0582, 0x00ad), +	/* Edirol M-16DX */ +	USB_DEVICE(0x0582, 0x00c4),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "Roland", -		.product_name = "SH-201",  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_COMPOSITE,  		.data = (const struct snd_usb_audio_quirk[]) { @@ -1413,29 +1539,28 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	/* Roland SonicCell */ -	USB_DEVICE(0x0582, 0x00c2), +	/* Advanced modes of the Edirol UA-25EX. +	 * For the standard mode, UA-25EX has ID 0582:00e7, which +	 * offers only 16-bit PCM at 44.1 kHz and no MIDI. +	 */ +	USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "Roland", -		.product_name = "SonicCell", +		.vendor_name = "EDIROL", +		.product_name = "UA-25EX",  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_COMPOSITE,  		.data = (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_EDIROL_UAXX  			},  			{  				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_EDIROL_UAXX  			},  			{  				.ifnum = 2, -				.type = QUIRK_MIDI_FIXED_ENDPOINT, -				.data = & (const struct snd_usb_midi_endpoint_info) { -					.out_cables = 0x0001, -					.in_cables  = 0x0001 -				} +				.type = QUIRK_AUDIO_EDIROL_UAXX  			},  			{  				.ifnum = -1 @@ -1444,54 +1569,61 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	/* Edirol M-16DX */ -	/* FIXME: This quirk gives a good-working capture stream but the -	 *        playback seems problematic because of lacking of sync -	 *        with capture stream.  It needs to sync with the capture -	 *        clock.  As now, you'll get frequent sound distortions -	 *        via the playback. -	 */ -	USB_DEVICE(0x0582, 0x00c4), +	/* Edirol UM-3G */ +	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.ifnum = QUIRK_ANY_INTERFACE, -		.type = QUIRK_COMPOSITE, -		.data = (const struct snd_usb_audio_quirk[]) { -			{ -				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE -			}, -			{ -				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE -			}, -			{ -				.ifnum = 2, -				.type = QUIRK_MIDI_FIXED_ENDPOINT, -				.data = & (const struct snd_usb_midi_endpoint_info) { -					.out_cables = 0x0001, -					.in_cables  = 0x0001 -				} -			}, -			{ -				.ifnum = -1 -			} +		.ifnum = 0, +		.type = QUIRK_MIDI_FIXED_ENDPOINT, +		.data = & (const struct snd_usb_midi_endpoint_info) { +			.out_cables = 0x0007, +			.in_cables  = 0x0007  		}  	}  },  { -	/* BOSS GT-10 */ -	USB_DEVICE(0x0582, 0x00da), +	/* only 44.1 kHz works at the moment */ +	USB_DEVICE(0x0582, 0x0120),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		/* .vendor_name = "Roland", */ +		/* .product_name = "OCTO-CAPTURE", */  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_COMPOSITE,  		.data = (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = & (const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S32_LE, +					.channels = 10, +					.iface = 0, +					.altsetting = 1, +					.altset_idx = 1, +					.endpoint = 0x05, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_44100, +					.rate_min = 44100, +					.rate_max = 44100, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { 44100 } +				}  			},  			{  				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = & (const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S32_LE, +					.channels = 12, +					.iface = 1, +					.altsetting = 1, +					.altset_idx = 1, +					.endpoint = 0x85, +					.ep_attr = 0x25, +					.rates = SNDRV_PCM_RATE_44100, +					.rate_min = 44100, +					.rate_max = 44100, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { 44100 } +				}  			},  			{  				.ifnum = 2, @@ -1502,57 +1634,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				}  			},  			{ -				.ifnum = -1 -			} -		} -	} -}, -{ -	/* Advanced modes of the Edirol UA-25EX. -	 * For the standard mode, UA-25EX has ID 0582:00e7, which -	 * offers only 16-bit PCM at 44.1 kHz and no MIDI. -	 */ -	USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		.vendor_name = "EDIROL", -		.product_name = "UA-25EX", -		.ifnum = QUIRK_ANY_INTERFACE, -		.type = QUIRK_COMPOSITE, -		.data = (const struct snd_usb_audio_quirk[]) { -			{ -				.ifnum = 0, -				.type = QUIRK_AUDIO_EDIROL_UAXX -			}, -			{ -				.ifnum = 1, -				.type = QUIRK_AUDIO_EDIROL_UAXX -			}, -			{ -				.ifnum = 2, -				.type = QUIRK_AUDIO_EDIROL_UAXX -			}, -			{ -				.ifnum = -1 -			} -		} -	} -}, -{ -	/* has ID 0x00ea when not in Advanced Driver mode */ -	USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		/* .vendor_name = "Roland", */ -		/* .product_name = "UA-1G", */ -		.ifnum = QUIRK_ANY_INTERFACE, -		.type = QUIRK_COMPOSITE, -		.data = (const struct snd_usb_audio_quirk[]) { -			{ -				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.ifnum = 3, +				.type = QUIRK_IGNORE_INTERFACE  			},  			{ -				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.ifnum = 4, +				.type = QUIRK_IGNORE_INTERFACE  			},  			{  				.ifnum = -1 @@ -1561,34 +1648,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	/* has ID 0x0110 when not in Advanced Driver mode */ -	USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), +	/* only 44.1 kHz works at the moment */ +	USB_DEVICE(0x0582, 0x012f),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {  		/* .vendor_name = "Roland", */ -		/* .product_name = "A-PRO", */ -		.ifnum = 1, -		.type = QUIRK_MIDI_FIXED_ENDPOINT, -		.data = & (const struct snd_usb_midi_endpoint_info) { -			.out_cables = 0x0003, -			.in_cables  = 0x0007 -		} -	} -}, -{ -	USB_DEVICE(0x0582, 0x0113), -	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { -		/* .vendor_name = "BOSS", */ -		/* .product_name = "ME-25", */ +		/* .product_name = "QUAD-CAPTURE", */  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_COMPOSITE,  		.data = (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = & (const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S32_LE, +					.channels = 4, +					.iface = 0, +					.altsetting = 1, +					.altset_idx = 1, +					.endpoint = 0x05, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_44100, +					.rate_min = 44100, +					.rate_max = 44100, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { 44100 } +				}  			},  			{  				.ifnum = 1, -				.type = QUIRK_AUDIO_STANDARD_INTERFACE +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = & (const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S32_LE, +					.channels = 6, +					.iface = 1, +					.altsetting = 1, +					.altset_idx = 1, +					.endpoint = 0x85, +					.ep_attr = 0x25, +					.rates = SNDRV_PCM_RATE_44100, +					.rate_min = 44100, +					.rate_max = 44100, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { 44100 } +				}  			},  			{  				.ifnum = 2, @@ -1599,11 +1701,30 @@ YAMAHA_DEVICE(0x7010, "UB99"),  				}  			},  			{ +				.ifnum = 3, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 4, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{  				.ifnum = -1  			}  		}  	}  }, +/* this catches most recent vendor-specific Roland devices */ +{ +	.match_flags = USB_DEVICE_ID_MATCH_VENDOR | +	               USB_DEVICE_ID_MATCH_INT_CLASS, +	.idVendor = 0x0582, +	.bInterfaceClass = USB_CLASS_VENDOR_SPEC, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_AUTODETECT +	} +},  /* Guillemot devices */  { @@ -1906,7 +2027,149 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE(0x0763, 0x2080), +	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		/* .vendor_name = "M-Audio", */ +		/* .product_name = "Fast Track C400", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = &(const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_MIXER, +			}, +			/* Playback */ +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 6, +					.iface = 2, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x01, +					.ep_attr = 0x09, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000 | +						 SNDRV_PCM_RATE_88200 | +						 SNDRV_PCM_RATE_96000, +					.rate_min = 44100, +					.rate_max = 96000, +					.nr_rates = 4, +					.rate_table = (unsigned int[]) { +							44100, 48000, 88200, 96000 +					}, +					.clock = 0x80, +				} +			}, +			/* Capture */ +			{ +				.ifnum = 3, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 4, +					.iface = 3, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x81, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000 | +						 SNDRV_PCM_RATE_88200 | +						 SNDRV_PCM_RATE_96000, +					.rate_min = 44100, +					.rate_max = 96000, +					.nr_rates = 4, +					.rate_table = (unsigned int[]) { +						44100, 48000, 88200, 96000 +					}, +					.clock = 0x80, +				} +			}, +			/* MIDI */ +			{ +				.ifnum = -1 /* Interface = 4 */ +			} +		} +	} +}, +{ +	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		/* .vendor_name = "M-Audio", */ +		/* .product_name = "Fast Track C600", */ +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = &(const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_MIXER, +			}, +			/* Playback */ +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 8, +					.iface = 2, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x01, +					.ep_attr = 0x09, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000 | +						 SNDRV_PCM_RATE_88200 | +						 SNDRV_PCM_RATE_96000, +					.rate_min = 44100, +					.rate_max = 96000, +					.nr_rates = 4, +					.rate_table = (unsigned int[]) { +							44100, 48000, 88200, 96000 +					}, +					.clock = 0x80, +				} +			}, +			/* Capture */ +			{ +				.ifnum = 3, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 6, +					.iface = 3, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x81, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000 | +						 SNDRV_PCM_RATE_88200 | +						 SNDRV_PCM_RATE_96000, +					.rate_min = 44100, +					.rate_max = 96000, +					.nr_rates = 4, +					.rate_table = (unsigned int[]) { +						44100, 48000, 88200, 96000 +					}, +					.clock = 0x80, +				} +			}, +			/* MIDI */ +			{ +				.ifnum = -1 /* Interface = 4 */ +			} +		} +	} +}, +{ +	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {  		/* .vendor_name = "M-Audio", */  		/* .product_name = "Fast Track Ultra", */ @@ -1915,7 +2178,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		.data = & (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_IGNORE_INTERFACE +				.type = QUIRK_AUDIO_STANDARD_MIXER,  			},  			{  				.ifnum = 1, @@ -1973,7 +2236,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE(0x0763, 0x2081), +	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {  		/* .vendor_name = "M-Audio", */  		/* .product_name = "Fast Track Ultra 8R", */ @@ -1982,7 +2245,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		.data = & (const struct snd_usb_audio_quirk[]) {  			{  				.ifnum = 0, -				.type = QUIRK_IGNORE_INTERFACE +				.type = QUIRK_AUDIO_STANDARD_MIXER,  			},  			{  				.ifnum = 1, @@ -2132,6 +2395,27 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  }, +/* KORG devices */ +{ +	USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		.vendor_name = "KORG, Inc.", +		/* .product_name = "PANDORA PX5D", */ +		.ifnum = 3, +		.type = QUIRK_MIDI_STANDARD_INTERFACE, +	} +}, + +{ +	USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		.vendor_name = "KORG, Inc.", +		/* .product_name = "ToneLab ST", */ +		.ifnum = 3, +		.type = QUIRK_MIDI_STANDARD_INTERFACE, +	} +}, +  /* AKAI devices */  {  	USB_DEVICE(0x09e8, 0x0062), @@ -2236,6 +2520,86 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { +	USB_DEVICE(0x1235, 0x0010), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "Focusrite", +		.product_name = "Saffire 6 USB", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 4, +					.iface = 0, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x01, +					.ep_attr = USB_ENDPOINT_XFER_ISOC, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000, +					.rate_min = 44100, +					.rate_max = 48000, +					.nr_rates = 2, +					.rate_table = (unsigned int[]) { +						44100, 48000 +					} +				} +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_MIDI_RAW_BYTES +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	USB_DEVICE(0x1235, 0x0018), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		.vendor_name = "Novation", +		.product_name = "Twitch", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = & (const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 4, +					.iface = 0, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x01, +					.ep_attr = USB_ENDPOINT_XFER_ISOC, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000, +					.rate_min = 44100, +					.rate_max = 48000, +					.nr_rates = 2, +					.rate_table = (unsigned int[]) { +						44100, 48000 +					} +				} +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_MIDI_RAW_BYTES +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{  	USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),  	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {  		.vendor_name = "Novation", @@ -2244,6 +2608,57 @@ YAMAHA_DEVICE(0x7010, "UB99"),  		.type = QUIRK_MIDI_NOVATION  	}  }, +{ +	/* +	 * Focusrite Scarlett 18i6 +	 * +	 * Avoid mixer creation, which otherwise fails because some of +	 * the interface descriptor subtypes for interface 0 are +	 * unknown.  That should be fixed or worked-around but this at +	 * least allows the device to be used successfully with a DAW +	 * and an external mixer.  See comments below about other +	 * ignored interfaces. +	 */ +	USB_DEVICE(0x1235, 0x8004), +	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +		.vendor_name = "Focusrite", +		.product_name = "Scarlett 18i6", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = & (const struct snd_usb_audio_quirk[]) { +			{ +				/* InterfaceSubClass 1 (Control Device) */ +				.ifnum = 0, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_STANDARD_INTERFACE +			}, +			{ +				/* InterfaceSubClass 1 (Control Device) */ +				.ifnum = 3, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 4, +				.type = QUIRK_MIDI_STANDARD_INTERFACE +			}, +			{ +				/* InterfaceSubClass 1 (Device Firmware Update) */ +				.ifnum = 5, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = -1 +			} +		} +	} +},  /* Access Music devices */  { @@ -2283,6 +2698,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  }, +/* Native Instruments MK2 series */ +{ +	/* Komplete Audio 6 */ +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +	.idVendor = 0x17cc, +	.idProduct = 0x1000, +}, +{ +	/* Traktor Audio 6 */ +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +	.idVendor = 0x17cc, +	.idProduct = 0x1010, +}, +{ +	/* Traktor Audio 10 */ +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +	.idVendor = 0x17cc, +	.idProduct = 0x1020, +}, + +/* KeithMcMillen Stringport */ +{ +	USB_DEVICE(0x1f38, 0x0001), +	.bInterfaceClass = USB_CLASS_AUDIO, +}, +  /* Miditech devices */  {  	USB_DEVICE(0x4752, 0x0011), @@ -2320,7 +2761,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2328,13 +2769,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,  	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {  		.vendor_name = "Hauppauge", -		.product_name = "HVR-850", +		.product_name = "HVR-950Q",  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_AUDIO_ALIGN_TRANSFER,  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2348,7 +2789,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2362,7 +2803,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2376,7 +2817,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2390,7 +2831,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  },  { -	USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f), +	USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240),  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |  		       USB_DEVICE_ID_MATCH_INT_CLASS |  		       USB_DEVICE_ID_MATCH_INT_SUBCLASS, @@ -2398,7 +2839,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,  	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {  		.vendor_name = "Hauppauge", -		.product_name = "HVR-950Q", +		.product_name = "HVR-850",  		.ifnum = QUIRK_ANY_INTERFACE,  		.type = QUIRK_AUDIO_ALIGN_TRANSFER,  	} @@ -2458,7 +2899,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),  					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,  					.endpoint = 0x02,  					.ep_attr = 0x01, -					.maxpacksize = 0x130,  					.rates = SNDRV_PCM_RATE_44100 |  						 SNDRV_PCM_RATE_48000,  					.rate_min = 44100, @@ -2477,6 +2917,231 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  }, +/* DIGIDESIGN MBOX 2 */ +{ +	USB_DEVICE(0x0dba, 0x3000), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "Digidesign", +		.product_name = "Mbox 2", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3BE, +					.channels = 2, +					.iface = 2, +					.altsetting = 2, +					.altset_idx = 1, +					.attributes = 0x00, +					.endpoint = 0x03, +					.ep_attr = USB_ENDPOINT_SYNC_ASYNC, +					.rates = SNDRV_PCM_RATE_48000, +					.rate_min = 48000, +					.rate_max = 48000, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { +						48000 +					} +				} +			}, +			{ +				.ifnum = 3, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 4, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +				.formats = SNDRV_PCM_FMTBIT_S24_3BE, +					.channels = 2, +					.iface = 4, +					.altsetting = 2, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x85, +					.ep_attr = USB_ENDPOINT_SYNC_SYNC, +					.rates = SNDRV_PCM_RATE_48000, +					.rate_min = 48000, +					.rate_max = 48000, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { +						48000 +					} +				} +			}, +			{ +				.ifnum = 5, +				.type = QUIRK_IGNORE_INTERFACE +			}, +			{ +				.ifnum = 6, +				.type = QUIRK_MIDI_MIDIMAN, +				.data = &(const struct snd_usb_midi_endpoint_info) { +					.out_ep =  0x02, +					.out_cables = 0x0001, +					.in_ep = 0x81, +					.in_interval = 0x01, +					.in_cables = 0x0001 +				} +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +{ +	/* Tascam US122 MKII - playback-only support */ +	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, +	.idVendor = 0x0644, +	.idProduct = 0x8021, +	.bInterfaceClass = USB_CLASS_AUDIO, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "TASCAM", +		.product_name = "US122 MKII", +		.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_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 2, +					.iface = 1, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x02, +					.ep_attr = USB_ENDPOINT_XFER_ISOC, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000 | +						 SNDRV_PCM_RATE_88200 | +						 SNDRV_PCM_RATE_96000, +					.rate_min = 44100, +					.rate_max = 96000, +					.nr_rates = 4, +					.rate_table = (unsigned int[]) { +						44100, 48000, 88200, 96000 +					} +				} +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, + +/* Microsoft XboxLive Headset/Xbox Communicator */ +{ +	USB_DEVICE(0x045e, 0x0283), +	.bInterfaceClass = USB_CLASS_PER_INTERFACE, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "Microsoft", +		.product_name = "XboxLive Headset/Xbox Communicator", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = &(const struct snd_usb_audio_quirk[]) { +			{ +				/* playback */ +				.ifnum = 0, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S16_LE, +					.channels = 1, +					.iface = 0, +					.altsetting = 0, +					.altset_idx = 0, +					.attributes = 0, +					.endpoint = 0x04, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_CONTINUOUS, +					.rate_min = 22050, +					.rate_max = 22050 +				} +			}, +			{ +				/* capture */ +				.ifnum = 1, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S16_LE, +					.channels = 1, +					.iface = 1, +					.altsetting = 0, +					.altset_idx = 0, +					.attributes = 0, +					.endpoint = 0x85, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_CONTINUOUS, +					.rate_min = 16000, +					.rate_max = 16000 +				} +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, + +/* Reloop Play */ +{ +	USB_DEVICE(0x200c, 0x100b), +	.bInterfaceClass = USB_CLASS_PER_INTERFACE, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = &(const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_AUDIO_STANDARD_MIXER, +			}, +			{ +				.ifnum = 1, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S24_3LE, +					.channels = 4, +					.iface = 1, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x01, +					.ep_attr = USB_ENDPOINT_SYNC_ADAPTIVE, +					.rates = SNDRV_PCM_RATE_44100 | +						 SNDRV_PCM_RATE_48000, +					.rate_min = 44100, +					.rate_max = 48000, +					.nr_rates = 2, +					.rate_table = (unsigned int[]) { +						44100, 48000 +					} +				} +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +  {  	/*  	 * Some USB MIDI devices don't have an audio control interface, @@ -2492,4 +3157,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  }, +{ +	/* +	 * The original product_name is "USB Sound Device", however this name +	 * is also used by the CM106 based cards, so make it unique. +	 */ +	USB_DEVICE(0x0d8c, 0x0103), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.product_name = "Audio Advantage MicroII", +		.ifnum = QUIRK_NO_INTERFACE +	} +}, +  #undef USB_DEVICE_VENDOR_SPEC diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index cf8bf088394..7c57f2268dd 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -18,7 +18,9 @@  #include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/audio.h> +#include <linux/usb/midi.h> +#include <sound/control.h>  #include <sound/core.h>  #include <sound/info.h>  #include <sound/pcm.h> @@ -33,6 +35,7 @@  #include "endpoint.h"  #include "pcm.h"  #include "clock.h" +#include "stream.h"  /*   * handle the quirks for the contained interfaces @@ -105,9 +108,9 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,  	alts = &iface->altsetting[0];  	altsd = get_iface_desc(alts); -	err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber); +	err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);  	if (err < 0) { -		snd_printk(KERN_ERR "cannot setup if %d: error %d\n", +		usb_audio_err(chip, "cannot setup if %d: error %d\n",  			   altsd->bInterfaceNumber, err);  		return err;  	} @@ -126,27 +129,32 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,  {  	struct audioformat *fp;  	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd;  	int stream, err;  	unsigned *rate_table = NULL;  	fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); -	if (! fp) { -		snd_printk(KERN_ERR "cannot memdup\n"); +	if (!fp) { +		usb_audio_err(chip, "cannot memdup\n");  		return -ENOMEM;  	} +	if (fp->nr_rates > MAX_NR_RATES) { +		kfree(fp); +		return -EINVAL; +	}  	if (fp->nr_rates > 0) { -		rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); +		rate_table = kmemdup(fp->rate_table, +				     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); +	err = snd_usb_add_audio_stream(chip, stream, fp);  	if (err < 0) {  		kfree(fp);  		kfree(rate_table); @@ -159,14 +167,225 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,  		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); +	altsd = get_iface_desc(alts); +	fp->protocol = altsd->bInterfaceProtocol; + +	if (fp->datainterval == 0) +		fp->datainterval = snd_usb_parse_datainterval(chip, alts); +	if (fp->maxpacksize == 0) +		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;  } +static int create_auto_pcm_quirk(struct snd_usb_audio *chip, +				 struct usb_interface *iface, +				 struct usb_driver *driver) +{ +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	struct usb_endpoint_descriptor *epd; +	struct uac1_as_header_descriptor *ashd; +	struct uac_format_type_i_discrete_descriptor *fmtd; + +	/* +	 * Most Roland/Yamaha audio streaming interfaces have more or less +	 * standard descriptors, but older devices might lack descriptors, and +	 * future ones might change, so ensure that we fail silently if the +	 * interface doesn't look exactly right. +	 */ + +	/* must have a non-zero altsetting for streaming */ +	if (iface->num_altsetting < 2) +		return -ENODEV; +	alts = &iface->altsetting[1]; +	altsd = get_iface_desc(alts); + +	/* must have an isochronous endpoint for streaming */ +	if (altsd->bNumEndpoints < 1) +		return -ENODEV; +	epd = get_endpoint(alts, 0); +	if (!usb_endpoint_xfer_isoc(epd)) +		return -ENODEV; + +	/* must have format descriptors */ +	ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, +				       UAC_AS_GENERAL); +	fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, +				       UAC_FORMAT_TYPE); +	if (!ashd || ashd->bLength < 7 || +	    !fmtd || fmtd->bLength < 8) +		return -ENODEV; + +	return create_standard_audio_quirk(chip, iface, driver, NULL); +} + +static int create_yamaha_midi_quirk(struct snd_usb_audio *chip, +				    struct usb_interface *iface, +				    struct usb_driver *driver, +				    struct usb_host_interface *alts) +{ +	static const struct snd_usb_audio_quirk yamaha_midi_quirk = { +		.type = QUIRK_MIDI_YAMAHA +	}; +	struct usb_midi_in_jack_descriptor *injd; +	struct usb_midi_out_jack_descriptor *outjd; + +	/* must have some valid jack descriptors */ +	injd = snd_usb_find_csint_desc(alts->extra, alts->extralen, +				       NULL, USB_MS_MIDI_IN_JACK); +	outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen, +					NULL, USB_MS_MIDI_OUT_JACK); +	if (!injd && !outjd) +		return -ENODEV; +	if (injd && (injd->bLength < 5 || +		     (injd->bJackType != USB_MS_EMBEDDED && +		      injd->bJackType != USB_MS_EXTERNAL))) +		return -ENODEV; +	if (outjd && (outjd->bLength < 6 || +		      (outjd->bJackType != USB_MS_EMBEDDED && +		       outjd->bJackType != USB_MS_EXTERNAL))) +		return -ENODEV; +	return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk); +} + +static int create_roland_midi_quirk(struct snd_usb_audio *chip, +				    struct usb_interface *iface, +				    struct usb_driver *driver, +				    struct usb_host_interface *alts) +{ +	static const struct snd_usb_audio_quirk roland_midi_quirk = { +		.type = QUIRK_MIDI_ROLAND +	}; +	u8 *roland_desc = NULL; + +	/* might have a vendor-specific descriptor <06 24 F1 02 ...> */ +	for (;;) { +		roland_desc = snd_usb_find_csint_desc(alts->extra, +						      alts->extralen, +						      roland_desc, 0xf1); +		if (!roland_desc) +			return -ENODEV; +		if (roland_desc[0] < 6 || roland_desc[3] != 2) +			continue; +		return create_any_midi_quirk(chip, iface, driver, +					     &roland_midi_quirk); +	} +} + +static int create_std_midi_quirk(struct snd_usb_audio *chip, +				 struct usb_interface *iface, +				 struct usb_driver *driver, +				 struct usb_host_interface *alts) +{ +	struct usb_ms_header_descriptor *mshd; +	struct usb_ms_endpoint_descriptor *msepd; + +	/* must have the MIDIStreaming interface header descriptor*/ +	mshd = (struct usb_ms_header_descriptor *)alts->extra; +	if (alts->extralen < 7 || +	    mshd->bLength < 7 || +	    mshd->bDescriptorType != USB_DT_CS_INTERFACE || +	    mshd->bDescriptorSubtype != USB_MS_HEADER) +		return -ENODEV; +	/* must have the MIDIStreaming endpoint descriptor*/ +	msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra; +	if (alts->endpoint[0].extralen < 4 || +	    msepd->bLength < 4 || +	    msepd->bDescriptorType != USB_DT_CS_ENDPOINT || +	    msepd->bDescriptorSubtype != UAC_MS_GENERAL || +	    msepd->bNumEmbMIDIJack < 1 || +	    msepd->bNumEmbMIDIJack > 16) +		return -ENODEV; + +	return create_any_midi_quirk(chip, iface, driver, NULL); +} + +static int create_auto_midi_quirk(struct snd_usb_audio *chip, +				  struct usb_interface *iface, +				  struct usb_driver *driver) +{ +	struct usb_host_interface *alts; +	struct usb_interface_descriptor *altsd; +	struct usb_endpoint_descriptor *epd; +	int err; + +	alts = &iface->altsetting[0]; +	altsd = get_iface_desc(alts); + +	/* must have at least one bulk/interrupt endpoint for streaming */ +	if (altsd->bNumEndpoints < 1) +		return -ENODEV; +	epd = get_endpoint(alts, 0); +	if (!usb_endpoint_xfer_bulk(epd) && +	    !usb_endpoint_xfer_int(epd)) +		return -ENODEV; + +	switch (USB_ID_VENDOR(chip->usb_id)) { +	case 0x0499: /* Yamaha */ +		err = create_yamaha_midi_quirk(chip, iface, driver, alts); +		if (err != -ENODEV) +			return err; +		break; +	case 0x0582: /* Roland */ +		err = create_roland_midi_quirk(chip, iface, driver, alts); +		if (err != -ENODEV) +			return err; +		break; +	} + +	return create_std_midi_quirk(chip, iface, driver, alts); +} + +static int create_autodetect_quirk(struct snd_usb_audio *chip, +				   struct usb_interface *iface, +				   struct usb_driver *driver) +{ +	int err; + +	err = create_auto_pcm_quirk(chip, iface, driver); +	if (err == -ENODEV) +		err = create_auto_midi_quirk(chip, iface, driver); +	return err; +} + +static int create_autodetect_quirks(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 ifcount, ifnum, err; + +	err = create_autodetect_quirk(chip, iface, driver); +	if (err < 0) +		return err; + +	/* +	 * ALSA PCM playback/capture devices cannot be registered in two steps, +	 * so we have to claim the other corresponding interface here. +	 */ +	ifcount = chip->dev->actconfig->desc.bNumInterfaces; +	for (ifnum = 0; ifnum < ifcount; ifnum++) { +		if (ifnum == probed_ifnum || quirk->ifnum >= 0) +			continue; +		iface = usb_ifnum_to_if(chip->dev, ifnum); +		if (!iface || +		    usb_interface_claimed(iface) || +		    get_iface_desc(iface->altsetting)->bInterfaceClass != +							USB_CLASS_VENDOR_SPEC) +			continue; + +		err = create_autodetect_quirk(chip, iface, driver); +		if (err >= 0) +			usb_driver_claim_interface(driver, iface, (void *)-1L); +	} + +	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. @@ -222,10 +441,9 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,  	if (altsd->bNumEndpoints != 1)  		return -ENXIO; -	fp = kmalloc(sizeof(*fp), GFP_KERNEL); +	fp = kmemdup(&ua_format, 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; @@ -246,14 +464,14 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,  		fp->rate_max = fp->rate_min = 96000;  		break;  	default: -		snd_printk(KERN_ERR "unknown sample rate\n"); +		usb_audio_err(chip, "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); +	err = snd_usb_add_audio_stream(chip, stream, fp);  	if (err < 0) {  		kfree(fp);  		return err; @@ -263,10 +481,24 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,  }  /* + * Create a standard mixer for the specified interface. + */ +static int create_standard_mixer_quirk(struct snd_usb_audio *chip, +				       struct usb_interface *iface, +				       struct usb_driver *driver, +				       const struct snd_usb_audio_quirk *quirk) +{ +	if (quirk->ifnum < 0) +		return 0; + +	return snd_usb_create_mixer(chip, quirk->ifnum, 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 + * returns a positive value if standard audio/midi interfaces are parsed   * after this.   * returns a negative value at error.   */ @@ -282,25 +514,29 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,  	static const quirk_func_t quirk_funcs[] = {  		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,  		[QUIRK_COMPOSITE] = create_composite_quirk, +		[QUIRK_AUTODETECT] = create_autodetect_quirks,  		[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_ROLAND] = create_any_midi_quirk,  		[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,  		[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,  		[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,  		[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,  		[QUIRK_MIDI_CME] = create_any_midi_quirk,  		[QUIRK_MIDI_AKAI] = create_any_midi_quirk, +		[QUIRK_MIDI_FTDI] = 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 +		[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk, +		[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_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); +		usb_audio_err(chip, "invalid quirk type %d\n", quirk->type);  		return -ENXIO;  	}  } @@ -319,18 +555,21 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac  	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"); +		dev_dbg(&dev->dev, "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); +				      0x10, 0x43, 0x0001, 0x000a, NULL, 0); +		if (err < 0) +			dev_dbg(&dev->dev, "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); +		if (err < 0) +			dev_dbg(&dev->dev, "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", +		if (err < 0) +			dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); +		dev_dbg(&dev->dev, "extigy_boot: new boot length = %d\n",  			    le16_to_cpu(get_cfg_desc(config)->wTotalLength));  		return -ENODEV; /* quit this anyway */  	} @@ -343,16 +582,43 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)  	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,  			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, -			0, 0, &buf, 1, 1000); +			0, 0, &buf, 1);  	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); +				1, 2000, NULL, 0);  		return -ENODEV;  	}  	return 0;  } +static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev) +{ +	int err; + +	if (dev->actconfig->desc.bConfigurationValue == 1) { +		dev_info(&dev->dev, +			   "Fast Track Pro switching to config #2\n"); +		/* This function has to be available by the usb core module. +		 * if it is not avialable the boot quirk has to be left out +		 * and the configuration has to be set by udev or hotplug +		 * rules +		 */ +		err = usb_driver_set_configuration(dev, 2); +		if (err < 0) +			dev_dbg(&dev->dev, +				"error usb_driver_set_configuration: %d\n", +				err); +		/* Always return an error, so that we stop creating a device +		   that will just be destroyed and recreated with a new +		   configuration */ +		return -ENODEV; +	} else +		dev_info(&dev->dev, "Fast Track Pro config OK\n"); + +	return 0; +} +  /*   * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely   * documented in the device's data sheet. @@ -366,7 +632,7 @@ static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 valu  	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); +			       0, 0, &buf, 4);  }  static int snd_usb_cm106_boot_quirk(struct usb_device *dev) @@ -386,8 +652,8 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)   */  static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)  { -	int err, reg; -	int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; +	int err  = 0, reg; +	int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};  	for (reg = 0; reg < ARRAY_SIZE(val); reg++) {  		err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); @@ -398,6 +664,30 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)  	return err;  } +/* quirk for Plantronics GameCom 780 with CM6302 chip */ +static int snd_usb_gamecon780_boot_quirk(struct usb_device *dev) +{ +	/* set the initial volume and don't change; other values are either +	 * too loud or silent due to firmware bug (bko#65251) +	 */ +	u8 buf[2] = { 0x74, 0xdc }; +	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, +			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, +			UAC_FU_VOLUME << 8, 9 << 8, buf, 2); +} + +/* + * Novation Twitch DJ controller + * Focusrite Novation Saffire 6 USB audio card + */ +static int snd_usb_novation_boot_quirk(struct usb_device *dev) +{ +	/* preemptively set up the device because otherwise the +	 * raw MIDI endpoints are not active */ +	usb_set_interface(dev, 0, 1); +	return 0; +} +  /*   * 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 @@ -425,18 +715,165 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)  }  /* + * Some sound cards from Native Instruments are in fact compliant to the USB + * audio standard of version 2 and other approved USB standards, even though + * they come up as vendor-specific device when first connected. + * + * However, they can be told to come up with a new set of descriptors + * upon their next enumeration, and the interfaces announced by the new + * descriptors will then be handled by the kernel's class drivers. As the + * product ID will also change, no further checks are required. + */ + +static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) +{ +	int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), +				  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE, +				  1, 0, NULL, 0, 1000); + +	if (ret < 0) +		return ret; + +	usb_reset_device(dev); + +	/* return -EAGAIN, so the creation of an audio interface for this +	 * temporary device is aborted. The device will reconnect with a +	 * new product ID */ +	return -EAGAIN; +} + +static void mbox2_setup_48_24_magic(struct usb_device *dev) +{ +	u8 srate[3]; +	u8 temp[12]; + +	/* Choose 48000Hz permanently */ +	srate[0] = 0x80; +	srate[1] = 0xbb; +	srate[2] = 0x00; + +	/* Send the magic! */ +	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), +		0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003); +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), +		0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003); +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), +		0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003); +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), +		0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003); +	return; +} + +/* Digidesign Mbox 2 needs to load firmware onboard + * and driver must wait a few seconds for initialisation. + */ + +#define MBOX2_FIRMWARE_SIZE    646 +#define MBOX2_BOOT_LOADING     0x01 /* Hard coded into the device */ +#define MBOX2_BOOT_READY       0x02 /* Hard coded into the device */ + +static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) +{ +	struct usb_host_config *config = dev->actconfig; +	int err; +	u8 bootresponse[0x12]; +	int fwsize; +	int count; + +	fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength); + +	if (fwsize != MBOX2_FIRMWARE_SIZE) { +		dev_err(&dev->dev, "Invalid firmware size=%d.\n", fwsize); +		return -ENODEV; +	} + +	dev_dbg(&dev->dev, "Sending Digidesign Mbox 2 boot sequence...\n"); + +	count = 0; +	bootresponse[0] = MBOX2_BOOT_LOADING; +	while ((bootresponse[0] == MBOX2_BOOT_LOADING) && (count < 10)) { +		msleep(500); /* 0.5 second delay */ +		snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), +			/* Control magic - load onboard firmware */ +			0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012); +		if (bootresponse[0] == MBOX2_BOOT_READY) +			break; +		dev_dbg(&dev->dev, "device not ready, resending boot sequence...\n"); +		count++; +	} + +	if (bootresponse[0] != MBOX2_BOOT_READY) { +		dev_err(&dev->dev, "Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]); +		return -ENODEV; +	} + +	dev_dbg(&dev->dev, "device initialised!\n"); + +	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, +		&dev->descriptor, sizeof(dev->descriptor)); +	config = dev->actconfig; +	if (err < 0) +		dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + +	err = usb_reset_configuration(dev); +	if (err < 0) +		dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); +	dev_dbg(&dev->dev, "mbox2_boot: new boot length = %d\n", +		le16_to_cpu(get_cfg_desc(config)->wTotalLength)); + +	mbox2_setup_48_24_magic(dev); + +	dev_info(&dev->dev, "Digidesign Mbox 2: 24bit 48kHz"); + +	return 0; /* Successful boot */ +} + +/*   * 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 */ +#define MAUDIO_SET		0x01 /* parse device_setup */ +#define MAUDIO_SET_COMPATIBLE	0x80 /* use only "win-compatible" interfaces */ +#define MAUDIO_SET_DTS		0x02 /* enable DTS Digital Output */ +#define MAUDIO_SET_96K		0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */ +#define MAUDIO_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */ +#define MAUDIO_SET_DI		0x10 /* enable Digital Input */ +#define MAUDIO_SET_MASK		0x1f /* bit mask for setup value */ +#define MAUDIO_SET_24B_48K_DI	 0x19 /* 24bits+48KHz+Digital Input */ +#define MAUDIO_SET_24B_48K_NOTDI 0x09 /* 24bits+48KHz+No Digital Input */ +#define MAUDIO_SET_16B_48K_DI	 0x11 /* 16bits+48KHz+Digital Input */ +#define MAUDIO_SET_16B_48K_NOTDI 0x01 /* 16bits+48KHz+No Digital Input */ + +static int quattro_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 & MAUDIO_SET) { +		if (chip->setup & MAUDIO_SET_COMPATIBLE) { +			if (iface != 1 && iface != 2) +				return 1; /* skip all interfaces but 1 and 2 */ +		} else { +			unsigned int mask; +			if (iface == 1 || iface == 2) +				return 1; /* skip interfaces 1 and 2 */ +			if ((chip->setup & MAUDIO_SET_96K) && altno != 1) +				return 1; /* skip this altsetting */ +			mask = chip->setup & MAUDIO_SET_MASK; +			if (mask == MAUDIO_SET_24B_48K_DI && altno != 2) +				return 1; /* skip this altsetting */ +			if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3) +				return 1; /* skip this altsetting */ +			if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 4) +				return 1; /* skip this altsetting */ +		} +	} +	usb_audio_dbg(chip, +		    "using altsetting %d for interface %d config %d\n", +		    altno, iface, chip->setup); +	return 0; /* keep this altsetting */ +}  static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,  					 int iface, @@ -447,30 +884,64 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,  	 */  	usb_set_interface(chip->dev, iface, 0); -	if (chip->setup & AUDIOPHILE_SET) { -		if ((chip->setup & AUDIOPHILE_SET_DTS) -		    && altno != 6) +	if (chip->setup & MAUDIO_SET) { +		unsigned int mask; +		if ((chip->setup & MAUDIO_SET_DTS) && altno != 6)  			return 1; /* skip this altsetting */ -		if ((chip->setup & AUDIOPHILE_SET_96K) -		    && altno != 1) +		if ((chip->setup & MAUDIO_SET_96K) && altno != 1)  			return 1; /* skip this altsetting */ -		if ((chip->setup & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_24B_48K_DI && altno != 2) +		mask = chip->setup & MAUDIO_SET_MASK; +		if (mask == MAUDIO_SET_24B_48K_DI && altno != 2)  			return 1; /* skip this altsetting */ -		if ((chip->setup & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3) +		if (mask == MAUDIO_SET_24B_48K_NOTDI && altno != 3)  			return 1; /* skip this altsetting */ -		if ((chip->setup & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_16B_48K_DI && altno != 4) +		if (mask == MAUDIO_SET_16B_48K_DI && altno != 4)  			return 1; /* skip this altsetting */ -		if ((chip->setup & AUDIOPHILE_SET_MASK) == -		    AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5) +		if (mask == MAUDIO_SET_16B_48K_NOTDI && altno != 5)  			return 1; /* skip this altsetting */  	}  	return 0; /* keep this altsetting */  } +static int fasttrackpro_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); + +	/* possible configuration where both inputs and only one output is +	 *used is not supported by the current setup +	 */ +	if (chip->setup & (MAUDIO_SET | MAUDIO_SET_24B)) { +		if (chip->setup & MAUDIO_SET_96K) { +			if (altno != 3 && altno != 6) +				return 1; +		} else if (chip->setup & MAUDIO_SET_DI) { +			if (iface == 4) +				return 1; /* no analog input */ +			if (altno != 2 && altno != 5) +				return 1; /* enable only altsets 2 and 5 */ +		} else { +			if (iface == 5) +				return 1; /* disable digialt input */ +			if (altno != 2 && altno != 5) +				return 1; /* enalbe only altsets 2 and 5 */ +		} +	} else { +		/* keep only 16-Bit mode */ +		if (altno != 1) +			return 1; +	} + +	usb_audio_dbg(chip, +		    "using altsetting %d for interface %d config %d\n", +		    altno, iface, chip->setup); +	return 0; /* keep this altsetting */ +} +  int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,  				  int iface,  				  int altno) @@ -478,6 +949,12 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,  	/* audiophile usb: skip altsets incompatible with device_setup */  	if (chip->usb_id == USB_ID(0x0763, 0x2003))  		return audiophile_skip_setting_quirk(chip, iface, altno); +	/* quattro usb: skip altsets incompatible with device_setup */ +	if (chip->usb_id == USB_ID(0x0763, 0x2001)) +		return quattro_skip_setting_quirk(chip, iface, altno); +	/* fasttrackpro usb: skip altsets incompatible with device_setup */ +	if (chip->usb_id == USB_ID(0x0763, 0x2012)) +		return fasttrackpro_skip_setting_quirk(chip, iface, altno);  	return 0;  } @@ -489,27 +966,47 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,  	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)) +	switch (id) { +	case USB_ID(0x041e, 0x3000): +		/* SB Extigy needs special boot-up sequence */ +		/* if more models come, this will go to the quirk list. */  		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)) +	case USB_ID(0x041e, 0x3020): +		/* SB Audigy 2 NX needs its own boot-up magic, too */  		return snd_usb_audigy2nx_boot_quirk(dev); -	/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */ -	if (id == USB_ID(0x10f5, 0x0200)) +	case USB_ID(0x10f5, 0x0200): +		/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */  		return snd_usb_cm106_boot_quirk(dev); -	/* C-Media CM6206 / CM106-Like Sound Device */ -	if (id == USB_ID(0x0d8c, 0x0102)) +	case USB_ID(0x0d8c, 0x0102): +		/* C-Media CM6206 / CM106-Like Sound Device */ +	case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */  		return snd_usb_cm6206_boot_quirk(dev); -	/* Access Music VirusTI Desktop */ -	if (id == USB_ID(0x133e, 0x0815)) +	case USB_ID(0x0dba, 0x3000): +		/* Digidesign Mbox 2 */ +		return snd_usb_mbox2_boot_quirk(dev); + +	case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */ +	case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */ +		return snd_usb_novation_boot_quirk(dev); + +	case USB_ID(0x133e, 0x0815): +		/* Access Music VirusTI Desktop */  		return snd_usb_accessmusic_boot_quirk(dev); +	case USB_ID(0x17cc, 0x1000): /* Komplete Audio 6 */ +	case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */ +	case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */ +		return snd_usb_nativeinstruments_boot_quirk(dev); +	case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */ +		return snd_usb_fasttrackpro_boot_quirk(dev); +	case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */ +		return snd_usb_gamecon780_boot_quirk(dev); +	} +  	return 0;  } @@ -518,21 +1015,30 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,   */  int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp)  { +	/* it depends on altsetting whether the device is big-endian or not */  	switch (chip->usb_id) {  	case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ -		if (fp->endpoint & USB_DIR_IN) +		if (fp->altsetting == 2 || fp->altsetting == 3 || +			fp->altsetting == 5 || fp->altsetting == 6)  			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) +			fp->altsetting == 1 || fp->altsetting == 2 || +			fp->altsetting == 3) +			return 1; +		break; +	case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro */ +		if (fp->altsetting == 2 || fp->altsetting == 3 || +			fp->altsetting == 5 || fp->altsetting == 6)  			return 1; +		break;  	}  	return 0;  }  /* - * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, + * For E-Mu 0404USB/0202USB/TrackerPre/0204 sample rate should be set for device,   * not for interface.   */ @@ -580,6 +1086,7 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,  		break;  	}  	snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +	subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;  }  void snd_usb_set_format_quirk(struct snd_usb_substream *subs, @@ -589,8 +1096,83 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,  	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 */ +	case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */  		set_format_emu_quirk(subs, fmt);  		break;  	}  } +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) +{ +	/* +	 * "Playback Design" products send bogus feedback data at the start +	 * of the stream. Ignore them. +	 */ +	if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && +	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC) +		ep->skip_packets = 4; + +	/* +	 * M-Audio Fast Track C400/C600 - when packets are not skipped, real +	 * world latency varies by approx. +/- 50 frames (at 96KHz) each time +	 * the stream is (re)started. When skipping packets 16 at endpoint +	 * start up, the real world latency is stable within +/- 1 frame (also +	 * across power cycles). +	 */ +	if ((ep->chip->usb_id == USB_ID(0x0763, 0x2030) || +	     ep->chip->usb_id == USB_ID(0x0763, 0x2031)) && +	    ep->type == SND_USB_ENDPOINT_TYPE_DATA) +		ep->skip_packets = 16; +} + +void snd_usb_set_interface_quirk(struct usb_device *dev) +{ +	/* +	 * "Playback Design" products need a 50ms delay after setting the +	 * USB interface. +	 */ +	if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) +		mdelay(50); +} + +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, +			   __u8 request, __u8 requesttype, __u16 value, +			   __u16 index, void *data, __u16 size) +{ +	/* +	 * "Playback Design" products need a 20ms delay after each +	 * class compliant request +	 */ +	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && +	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) +		mdelay(20); +} + +/* + * snd_usb_interface_dsd_format_quirks() is called from format.c to + * augment the PCM format bit-field for DSD types. The UAC standards + * don't have a designated bit field to denote DSD-capable interfaces, + * hence all hardware that is known to support this format has to be + * listed here. + */ +u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, +					struct audioformat *fp, +					unsigned int sample_bytes) +{ +	/* Playback Designs */ +	if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) { +		switch (fp->altsetting) { +		case 1: +			fp->dsd_dop = true; +			return SNDRV_PCM_FMTBIT_DSD_U16_LE; +		case 2: +			fp->dsd_bitrev = true; +			return SNDRV_PCM_FMTBIT_DSD_U8; +		case 3: +			fp->dsd_bitrev = true; +			return SNDRV_PCM_FMTBIT_DSD_U16_LE; +		} +	} + +	return 0; +} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 03e5e94098c..665e972a1b4 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -1,6 +1,10 @@  #ifndef __USBAUDIO_QUIRKS_H  #define __USBAUDIO_QUIRKS_H +struct audioformat; +struct snd_usb_endpoint; +struct snd_usb_substream; +  int snd_usb_create_quirk(struct snd_usb_audio *chip,  			 struct usb_interface *iface,  			 struct usb_driver *driver, @@ -20,4 +24,15 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,  int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,  				 struct audioformat *fp); +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); + +void snd_usb_set_interface_quirk(struct usb_device *dev); +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, +			   __u8 request, __u8 requesttype, __u16 value, +			   __u16 index, void *data, __u16 size); + +u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, +					struct audioformat *fp, +					unsigned int sample_bytes); +  #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c new file mode 100644 index 00000000000..310a3822d2b --- /dev/null +++ b/sound/usb/stream.c @@ -0,0 +1,731 @@ +/* + *   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/control.h> +#include <sound/tlv.h> + +#include "usbaudio.h" +#include "card.h" +#include "proc.h" +#include "quirks.h" +#include "endpoint.h" +#include "pcm.h" +#include "helper.h" +#include "format.h" +#include "clock.h" +#include "stream.h" + +/* + * free a substream + */ +static void free_substream(struct snd_usb_substream *subs) +{ +	struct audioformat *fp, *n; + +	if (!subs->num_formats) +		return; /* not initialized */ +	list_for_each_entry_safe(fp, n, &subs->fmt_list, list) { +		kfree(fp->rate_table); +		kfree(fp->chmap); +		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); +	} +} + +/* + * initialize the substream instance. + */ + +static 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; +	subs->speed = snd_usb_get_speed(subs->dev); +	subs->pkt_offset_adj = 0; + +	snd_usb_set_pcm_ops(as->pcm, stream); + +	list_add_tail(&fp->list, &subs->fmt_list); +	subs->formats |= fp->formats; +	subs->num_formats++; +	subs->fmt_type = fp->fmt_type; +	subs->ep_num = fp->endpoint; +	if (fp->channels > subs->channels_max) +		subs->channels_max = fp->channels; +} + +/* kctl callbacks for usb-audio channel maps */ +static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol, +			      struct snd_ctl_elem_info *uinfo) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct snd_usb_substream *subs = info->private_data; + +	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +	uinfo->count = subs->channels_max; +	uinfo->value.integer.min = 0; +	uinfo->value.integer.max = SNDRV_CHMAP_LAST; +	return 0; +} + +/* check whether a duplicated entry exists in the audiofmt list */ +static bool have_dup_chmap(struct snd_usb_substream *subs, +			   struct audioformat *fp) +{ +	struct list_head *p; + +	for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) { +		struct audioformat *prev; +		prev = list_entry(p, struct audioformat, list); +		if (prev->chmap && +		    !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap))) +			return true; +	} +	return false; +} + +static int usb_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, +			     unsigned int size, unsigned int __user *tlv) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct snd_usb_substream *subs = info->private_data; +	struct audioformat *fp; +	unsigned int __user *dst; +	int count = 0; + +	if (size < 8) +		return -ENOMEM; +	if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) +		return -EFAULT; +	size -= 8; +	dst = tlv + 2; +	list_for_each_entry(fp, &subs->fmt_list, list) { +		int i, ch_bytes; + +		if (!fp->chmap) +			continue; +		if (have_dup_chmap(subs, fp)) +			continue; +		/* copy the entry */ +		ch_bytes = fp->chmap->channels * 4; +		if (size < 8 + ch_bytes) +			return -ENOMEM; +		if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) || +		    put_user(ch_bytes, dst + 1)) +			return -EFAULT; +		dst += 2; +		for (i = 0; i < fp->chmap->channels; i++, dst++) { +			if (put_user(fp->chmap->map[i], dst)) +				return -EFAULT; +		} + +		count += 8 + ch_bytes; +		size -= 8 + ch_bytes; +	} +	if (put_user(count, tlv + 1)) +		return -EFAULT; +	return 0; +} + +static int usb_chmap_ctl_get(struct snd_kcontrol *kcontrol, +			     struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct snd_usb_substream *subs = info->private_data; +	struct snd_pcm_chmap_elem *chmap = NULL; +	int i; + +	memset(ucontrol->value.integer.value, 0, +	       sizeof(ucontrol->value.integer.value)); +	if (subs->cur_audiofmt) +		chmap = subs->cur_audiofmt->chmap; +	if (chmap) { +		for (i = 0; i < chmap->channels; i++) +			ucontrol->value.integer.value[i] = chmap->map[i]; +	} +	return 0; +} + +/* create a chmap kctl assigned to the given USB substream */ +static int add_chmap(struct snd_pcm *pcm, int stream, +		     struct snd_usb_substream *subs) +{ +	struct audioformat *fp; +	struct snd_pcm_chmap *chmap; +	struct snd_kcontrol *kctl; +	int err; + +	list_for_each_entry(fp, &subs->fmt_list, list) +		if (fp->chmap) +			goto ok; +	/* no chmap is found */ +	return 0; + + ok: +	err = snd_pcm_add_chmap_ctls(pcm, stream, NULL, 0, 0, &chmap); +	if (err < 0) +		return err; + +	/* override handlers */ +	chmap->private_data = subs; +	kctl = chmap->kctl; +	kctl->info = usb_chmap_ctl_info; +	kctl->get = usb_chmap_ctl_get; +	kctl->tlv.c = usb_chmap_ctl_tlv; + +	return 0; +} + +/* convert from USB ChannelConfig bits to ALSA chmap element */ +static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, +						int protocol) +{ +	static unsigned int uac1_maps[] = { +		SNDRV_CHMAP_FL,		/* left front */ +		SNDRV_CHMAP_FR,		/* right front */ +		SNDRV_CHMAP_FC,		/* center front */ +		SNDRV_CHMAP_LFE,	/* LFE */ +		SNDRV_CHMAP_SL,		/* left surround */ +		SNDRV_CHMAP_SR,		/* right surround */ +		SNDRV_CHMAP_FLC,	/* left of center */ +		SNDRV_CHMAP_FRC,	/* right of center */ +		SNDRV_CHMAP_RC,		/* surround */ +		SNDRV_CHMAP_SL,		/* side left */ +		SNDRV_CHMAP_SR,		/* side right */ +		SNDRV_CHMAP_TC,		/* top */ +		0 /* terminator */ +	}; +	static unsigned int uac2_maps[] = { +		SNDRV_CHMAP_FL,		/* front left */ +		SNDRV_CHMAP_FR,		/* front right */ +		SNDRV_CHMAP_FC,		/* front center */ +		SNDRV_CHMAP_LFE,	/* LFE */ +		SNDRV_CHMAP_RL,		/* back left */ +		SNDRV_CHMAP_RR,		/* back right */ +		SNDRV_CHMAP_FLC,	/* front left of center */ +		SNDRV_CHMAP_FRC,	/* front right of center */ +		SNDRV_CHMAP_RC,		/* back center */ +		SNDRV_CHMAP_SL,		/* side left */ +		SNDRV_CHMAP_SR,		/* side right */ +		SNDRV_CHMAP_TC,		/* top center */ +		SNDRV_CHMAP_TFL,	/* top front left */ +		SNDRV_CHMAP_TFC,	/* top front center */ +		SNDRV_CHMAP_TFR,	/* top front right */ +		SNDRV_CHMAP_TRL,	/* top back left */ +		SNDRV_CHMAP_TRC,	/* top back center */ +		SNDRV_CHMAP_TRR,	/* top back right */ +		SNDRV_CHMAP_TFLC,	/* top front left of center */ +		SNDRV_CHMAP_TFRC,	/* top front right of center */ +		SNDRV_CHMAP_LLFE,	/* left LFE */ +		SNDRV_CHMAP_RLFE,	/* right LFE */ +		SNDRV_CHMAP_TSL,	/* top side left */ +		SNDRV_CHMAP_TSR,	/* top side right */ +		SNDRV_CHMAP_BC,		/* bottom center */ +		SNDRV_CHMAP_RLC,	/* back left of center */ +		SNDRV_CHMAP_RRC,	/* back right of center */ +		0 /* terminator */ +	}; +	struct snd_pcm_chmap_elem *chmap; +	const unsigned int *maps; +	int c; + +	if (channels > ARRAY_SIZE(chmap->map)) +		return NULL; + +	chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); +	if (!chmap) +		return NULL; + +	maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps; +	chmap->channels = channels; +	c = 0; + +	if (bits) { +		for (; bits && *maps; maps++, bits >>= 1) +			if (bits & 1) +				chmap->map[c++] = *maps; +	} else { +		/* If we're missing wChannelConfig, then guess something +		    to make sure the channel map is not skipped entirely */ +		if (channels == 1) +			chmap->map[c++] = SNDRV_CHMAP_MONO; +		else +			for (; c < channels && *maps; maps++) +				chmap->map[c++] = *maps; +	} + +	for (; c < channels; c++) +		chmap->map[c] = SNDRV_CHMAP_UNKNOWN; + +	return chmap; +} + +/* + * 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_stream(struct snd_usb_audio *chip, +			     int stream, +			     struct audioformat *fp) +{ +	struct snd_usb_stream *as; +	struct snd_usb_substream *subs; +	struct snd_pcm *pcm; +	int err; + +	list_for_each_entry(as, &chip->pcm_list, list) { +		if (as->fmt_type != fp->fmt_type) +			continue; +		subs = &as->substream[stream]; +		if (subs->ep_num == 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_entry(as, &chip->pcm_list, list) { +		if (as->fmt_type != fp->fmt_type) +			continue; +		subs = &as->substream[stream]; +		if (subs->ep_num) +			continue; +		err = snd_pcm_new_stream(as->pcm, stream, 1); +		if (err < 0) +			return err; +		snd_usb_init_substream(as, stream, fp); +		return add_chmap(as->pcm, stream, subs); +	} + +	/* 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 add_chmap(pcm, stream, &as->substream[stream]); +} + +static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, +					 struct usb_host_interface *alts, +					 int protocol, int iface_no) +{ +	/* parsed with a v1 header here. that's ok as we only look at the +	 * header first which is the same for both versions */ +	struct uac_iso_endpoint_descriptor *csep; +	struct usb_interface_descriptor *altsd = get_iface_desc(alts); +	int attributes = 0; + +	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 we can't locate the USB_DT_CS_ENDPOINT descriptor in the extra +	 * bytes after the first endpoint, go search the entire interface. +	 * Some devices have it directly *before* the standard endpoint. +	 */ +	if (!csep) +		csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT); + +	if (!csep || csep->bLength < 7 || +	    csep->bDescriptorSubtype != UAC_EP_GENERAL) { +		usb_audio_warn(chip, +			       "%u:%d : no or invalid class specific endpoint descriptor\n", +			       iface_no, altsd->bAlternateSetting); +		return 0; +	} + +	if (protocol == UAC_VERSION_1) { +		attributes = csep->bmAttributes; +	} else { +		struct uac2_iso_endpoint_descriptor *csep2 = +			(struct uac2_iso_endpoint_descriptor *) csep; + +		attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX; + +		/* emulate the endpoint attributes of a v1 device */ +		if (csep2->bmControls & UAC2_CONTROL_PITCH) +			attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; +	} + +	return attributes; +} + +/* find an input terminal descriptor (either UAC1 or UAC2) with the given + * terminal id + */ +static void * +snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, +					       int terminal_id) +{ +	struct uac2_input_terminal_descriptor *term = NULL; + +	while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, +					       ctrl_iface->extralen, +					       term, UAC_INPUT_TERMINAL))) { +		if (term->bTerminalID == terminal_id) +			return term; +	} + +	return NULL; +} + +static struct uac2_output_terminal_descriptor * +	snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, +						int terminal_id) +{ +	struct uac2_output_terminal_descriptor *term = NULL; + +	while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, +					       ctrl_iface->extralen, +					       term, UAC_OUTPUT_TERMINAL))) { +		if (term->bTerminalID == terminal_id) +			return term; +	} + +	return NULL; +} + +int snd_usb_parse_audio_interface(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; +	unsigned int format = 0, num_channels = 0; +	struct audioformat *fp = NULL; +	int num, protocol, clock = 0; +	struct uac_format_type_i_continuous_descriptor *fmt; +	unsigned int chconfig; + +	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->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && +		       altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC)) && +		     altsd->bInterfaceClass != USB_CLASS_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; + +		/* +		 * Roland audio streaming interfaces are marked with protocols +		 * 0/1/2, but are UAC 1 compatible. +		 */ +		if (USB_ID_VENDOR(chip->usb_id) == 0x0582 && +		    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && +		    protocol <= 2) +			protocol = UAC_VERSION_1; + +		chconfig = 0; +		/* get audio formats */ +		switch (protocol) { +		default: +			dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", +				iface_no, altno, protocol); +			protocol = UAC_VERSION_1; +			/* fall through */ + +		case UAC_VERSION_1: { +			struct uac1_as_header_descriptor *as = +				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); +			struct uac_input_terminal_descriptor *iterm; + +			if (!as) { +				dev_err(&dev->dev, +					"%u:%d : UAC_AS_GENERAL descriptor not found\n", +					iface_no, altno); +				continue; +			} + +			if (as->bLength < sizeof(*as)) { +				dev_err(&dev->dev, +					"%u:%d : invalid UAC_AS_GENERAL desc\n", +					iface_no, altno); +				continue; +			} + +			format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + +			iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, +								       as->bTerminalLink); +			if (iterm) { +				num_channels = iterm->bNrChannels; +				chconfig = le16_to_cpu(iterm->wChannelConfig); +			} + +			break; +		} + +		case UAC_VERSION_2: { +			struct uac2_input_terminal_descriptor *input_term; +			struct uac2_output_terminal_descriptor *output_term; +			struct uac2_as_header_descriptor *as = +				snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + +			if (!as) { +				dev_err(&dev->dev, +					"%u:%d : UAC_AS_GENERAL descriptor not found\n", +					iface_no, altno); +				continue; +			} + +			if (as->bLength < sizeof(*as)) { +				dev_err(&dev->dev, +					"%u:%d : invalid UAC_AS_GENERAL desc\n", +					iface_no, altno); +				continue; +			} + +			num_channels = as->bNrChannels; +			format = le32_to_cpu(as->bmFormats); +			chconfig = le32_to_cpu(as->bmChannelConfig); + +			/* lookup the terminal associated to this interface +			 * to extract the clock */ +			input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, +									    as->bTerminalLink); +			if (input_term) { +				clock = input_term->bCSourceID; +				if (!chconfig && (num_channels == input_term->bNrChannels)) +					chconfig = le32_to_cpu(input_term->bmChannelConfig); +				break; +			} + +			output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, +									      as->bTerminalLink); +			if (output_term) { +				clock = output_term->bCSourceID; +				break; +			} + +			dev_err(&dev->dev, +				"%u:%d : bogus bTerminalLink %d\n", +				iface_no, altno, as->bTerminalLink); +			continue; +		} +		} + +		/* get format type */ +		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); +		if (!fmt) { +			dev_err(&dev->dev, +				"%u:%d : no UAC_FORMAT_TYPE desc\n", +				iface_no, altno); +			continue; +		} +		if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || +		    ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) { +			dev_err(&dev->dev, +				"%u:%d : invalid UAC_FORMAT_TYPE desc\n", +				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->bNrChannels == 1 && +		    fmt->bSubframeSize == 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; + +		fp = kzalloc(sizeof(*fp), GFP_KERNEL); +		if (! fp) { +			dev_err(&dev->dev, "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->protocol = protocol; +		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); +		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 = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); +		fp->clock = clock; + +		/* 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(0x0763, 0x2001):  /* M-Audio Quattro USB */ +		case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */ +		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) < 0) { +			kfree(fp->rate_table); +			kfree(fp); +			fp = NULL; +			continue; +		} + +		/* Create chmap */ +		if (fp->channels != num_channels) +			chconfig = 0; +		fp->chmap = convert_chmap(fp->channels, chconfig, protocol); + +		dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +		err = snd_usb_add_audio_stream(chip, stream, fp); +		if (err < 0) { +			kfree(fp->rate_table); +			kfree(fp->chmap); +			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/stream.h b/sound/usb/stream.h new file mode 100644 index 00000000000..c97f679fc84 --- /dev/null +++ b/sound/usb/stream.h @@ -0,0 +1,12 @@ +#ifndef __USBAUDIO_STREAM_H +#define __USBAUDIO_STREAM_H + +int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, +				  int iface_no); + +int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +			     int stream, +			     struct audioformat *fp); + +#endif /* __USBAUDIO_STREAM_H */ + diff --git a/sound/usb/urb.c b/sound/usb/urb.c deleted file mode 100644 index e184349aee8..00000000000 --- a/sound/usb/urb.c +++ /dev/null @@ -1,941 +0,0 @@ -/* - *   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_free_coherent(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_free_coherent(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; -	subs->freqshift = INT_MIN; -	/* 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_FULL) -		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_alloc_coherent(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_alloc_coherent(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 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 = min(4u, ctx->subs->syncmaxsize); -	urb->iso_frame_desc[0].offset = 0; -	return 0; -} - -/* - * process after playback sync complete - * - * Full speed devices report feedback values in 10.14 format as samples per - * frame, high speed devices in 16.16 format as samples per microframe. - * Because the Audio Class 1 spec was written before USB 2.0, many high speed - * devices use a wrong interpretation, some others use an entirely different - * format.  Therefore, we cannot predict what format any particular device uses - * and must detect it automatically. - */ -static int retire_playback_sync_urb(struct snd_usb_substream *subs, -				    struct snd_pcm_runtime *runtime, -				    struct urb *urb) -{ -	unsigned int f; -	int shift; -	unsigned long flags; - -	if (urb->iso_frame_desc[0].status != 0 || -	    urb->iso_frame_desc[0].actual_length < 3) -		return 0; - -	f = le32_to_cpup(urb->transfer_buffer); -	if (urb->iso_frame_desc[0].actual_length == 3) -		f &= 0x00ffffff; -	else -		f &= 0x0fffffff; -	if (f == 0) -		return 0; - -	if (unlikely(subs->freqshift == INT_MIN)) { -		/* -		 * The first time we see a feedback value, determine its format -		 * by shifting it left or right until it matches the nominal -		 * frequency value.  This assumes that the feedback does not -		 * differ from the nominal value more than +50% or -25%. -		 */ -		shift = 0; -		while (f < subs->freqn - subs->freqn / 4) { -			f <<= 1; -			shift++; -		} -		while (f > subs->freqn + subs->freqn / 2) { -			f >>= 1; -			shift--; -		} -		subs->freqshift = shift; -	} -	else if (subs->freqshift >= 0) -		f <<= subs->freqshift; -	else -		f >>= -subs->freqshift; - -	if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) { -		/* -		 * If the frequency looks valid, set it. -		 * This value is referred to in prepare_playback_urb(). -		 */ -		spin_lock_irqsave(&subs->lock, flags); -		subs->freqm = f; -		spin_unlock_irqrestore(&subs->lock, flags); -	} else { -		/* -		 * Out of range; maybe the shift value is wrong. -		 * Reset it so that we autodetect again the next time. -		 */ -		subs->freqshift = INT_MIN; -	} - -	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, -	}, -}; - -/* - * 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; -	subs->ops = audio_urb_ops[stream]; -	if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) -		subs->ops.prepare_sync = prepare_capture_sync_urb_hs; - -	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 deleted file mode 100644 index 888da38079c..00000000000 --- a/sound/usb/urb.h +++ /dev/null @@ -1,21 +0,0 @@ -#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.h b/sound/usb/usbaudio.h index db3eb21627e..91d0380431b 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -34,13 +34,21 @@ struct snd_usb_audio {  	int index;  	struct usb_device *dev;  	struct snd_card *card; +	struct usb_interface *pm_intf;  	u32 usb_id; -	int shutdown; +	struct mutex mutex; +	struct rw_semaphore shutdown_rwsem; +	unsigned int shutdown:1; +	unsigned int probing:1; +	unsigned int in_pm:1; +	unsigned int autosuspended:1;	  	unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ +	  	int num_interfaces;  	int num_suspended_intf;  	struct list_head pcm_list;	/* list of pcm streams */ +	struct list_head ep_list;	/* list of audio-related endpoints */  	int pcm_devs;  	struct list_head midi_list;	/* list of midi interfaces */ @@ -48,12 +56,20 @@ struct snd_usb_audio {  	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 */ +	bool autoclock;			/* from the 'autoclock' module param */  	struct usb_host_interface *ctrl_intf;	/* the audio control interface */  }; +#define usb_audio_err(chip, fmt, args...) \ +	dev_err(&(chip)->dev->dev, fmt, ##args) +#define usb_audio_warn(chip, fmt, args...) \ +	dev_warn(&(chip)->dev->dev, fmt, ##args) +#define usb_audio_info(chip, fmt, args...) \ +	dev_info(&(chip)->dev->dev, fmt, ##args) +#define usb_audio_dbg(chip, fmt, args...) \ +	dev_dbg(&(chip)->dev->dev, fmt, ##args) +  /*   * Information about devices with broken descriptors   */ @@ -65,9 +81,11 @@ struct snd_usb_audio {  enum quirk_type {  	QUIRK_IGNORE_INTERFACE,  	QUIRK_COMPOSITE, +	QUIRK_AUTODETECT,  	QUIRK_MIDI_STANDARD_INTERFACE,  	QUIRK_MIDI_FIXED_ENDPOINT,  	QUIRK_MIDI_YAMAHA, +	QUIRK_MIDI_ROLAND,  	QUIRK_MIDI_MIDIMAN,  	QUIRK_MIDI_NOVATION,  	QUIRK_MIDI_RAW_BYTES, @@ -75,10 +93,12 @@ enum quirk_type {  	QUIRK_MIDI_CME,  	QUIRK_MIDI_AKAI,  	QUIRK_MIDI_US122L, +	QUIRK_MIDI_FTDI,  	QUIRK_AUDIO_STANDARD_INTERFACE,  	QUIRK_AUDIO_FIXED_ENDPOINT,  	QUIRK_AUDIO_EDIROL_UAXX,  	QUIRK_AUDIO_ALIGN_TRANSFER, +	QUIRK_AUDIO_STANDARD_MIXER,  	QUIRK_TYPE_COUNT  }; diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 6ef68e42138..cf5dc33f4a6 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -19,6 +19,7 @@  #include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/audio.h> +#include <linux/module.h>  #include <sound/core.h>  #include <sound/hwdep.h>  #include <sound/pcm.h> @@ -36,7 +37,7 @@ MODULE_LICENSE("GPL");  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-max */  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* Id for this card */  							/* Enable this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;  module_param_array(index, int, NULL, 0444);  MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS"."); @@ -261,7 +262,9 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,  	}  	area->vm_ops = &usb_stream_hwdep_vm_ops; -	area->vm_flags |= VM_RESERVED; +	area->vm_flags |= VM_DONTDUMP; +	if (!read) +		area->vm_flags |= VM_DONTEXPAND;  	area->vm_private_data = us122l;  	atomic_inc(&us122l->mmap_count);  out: @@ -273,29 +276,26 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,  					  struct file *file, poll_table *wait)  {  	struct us122l	*us122l = hw->private_data; -	struct usb_stream *s = us122l->sk.s;  	unsigned	*polled;  	unsigned int	mask;  	poll_wait(file, &us122l->sk.sleep, wait); -	switch (s->state) { -	case usb_stream_ready: -		if (us122l->first == file) -			polled = &s->periods_polled; -		else -			polled = &us122l->second_periods_polled; -		if (*polled != s->periods_done) { -			*polled = s->periods_done; -			mask = POLLIN | POLLOUT | POLLWRNORM; -			break; +	mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; +	if (mutex_trylock(&us122l->mutex)) { +		struct usb_stream *s = us122l->sk.s; +		if (s && s->state == usb_stream_ready) { +			if (us122l->first == file) +				polled = &s->periods_polled; +			else +				polled = &us122l->second_periods_polled; +			if (*polled != s->periods_done) { +				*polled = s->periods_done; +				mask = POLLIN | POLLOUT | POLLWRNORM; +			} else +				mask = 0;  		} -		/* Fall through */ -		mask = 0; -		break; -	default: -		mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR; -		break; +		mutex_unlock(&us122l->mutex);  	}  	return mask;  } @@ -381,6 +381,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,  {  	struct usb_stream_config *cfg;  	struct us122l *us122l = hw->private_data; +	struct usb_stream *s;  	unsigned min_period_frames;  	int err = 0;  	bool high_speed; @@ -426,18 +427,18 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,  	snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);  	mutex_lock(&us122l->mutex); +	s = us122l->sk.s;  	if (!us122l->master)  		us122l->master = file;  	else if (us122l->master != file) { -		if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) { +		if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) {  			err = -EIO;  			goto unlock;  		}  		us122l->slave = file;  	} -	if (!us122l->sk.s || -	    memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) || -	    us122l->sk.s->state == usb_stream_xrun) { +	if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) || +	    s->state == usb_stream_xrun) {  		us122l_stop(us122l);  		if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames))  			err = -EIO; @@ -448,6 +449,7 @@ unlock:  	mutex_unlock(&us122l->mutex);  free:  	kfree(cfg); +	wake_up_all(&us122l->sk.sleep);  	return err;  } @@ -533,7 +535,9 @@ static void snd_us122l_free(struct snd_card *card)  		snd_us122l_card_used[index] = 0;  } -static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) +static int usx2y_create_card(struct usb_device *device, +			     struct usb_interface *intf, +			     struct snd_card **cardp)  {  	int		dev;  	struct snd_card *card; @@ -544,8 +548,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)  			break;  	if (dev >= SNDRV_CARDS)  		return -ENODEV; -	err = snd_card_create(index[dev], id[dev], THIS_MODULE, -			      sizeof(struct us122l), &card); +	err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE, +			   sizeof(struct us122l), &card);  	if (err < 0)  		return err;  	snd_us122l_card_used[US122L(card)->card_index = dev] = 1; @@ -576,11 +580,10 @@ static int us122l_usb_probe(struct usb_interface *intf,  	struct snd_card *card;  	int err; -	err = usx2y_create_card(device, &card); +	err = usx2y_create_card(device, intf, &card);  	if (err < 0)  		return err; -	snd_card_set_dev(card, &intf->dev);  	if (!us122l_create_card(card)) {  		snd_card_free(card);  		return -EINVAL; @@ -772,16 +775,4 @@ static struct usb_driver snd_us122l_usb_driver = {  	.supports_autosuspend = 1  }; - -static int __init snd_us122l_module_init(void) -{ -	return usb_register(&snd_us122l_usb_driver); -} - -static void __exit snd_us122l_module_exit(void) -{ -	usb_deregister(&snd_us122l_usb_driver); -} - -module_init(snd_us122l_module_init) -module_exit(snd_us122l_module_exit) +module_usb_driver(snd_us122l_usb_driver); diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 04aafb43a13..0b34dbc8f30 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -82,7 +82,7 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v  		us428->us428ctls_sharedmem->CtlSnapShotLast = -2;  	}  	area->vm_ops = &us428ctls_vm_ops; -	area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; +	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;  	area->vm_private_data = hw->private_data;  	return 0;  } diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index c400ade3ff0..bf618e1500a 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -69,7 +69,6 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize,  	     ++u, transfer += transfer_length) {  		struct urb *urb = urbs[u];  		struct usb_iso_packet_descriptor *desc; -		urb->transfer_flags = URB_ISO_ASAP;  		urb->transfer_buffer = transfer;  		urb->dev = dev;  		urb->pipe = pipe; @@ -674,7 +673,7 @@ dotry:  		inurb->transfer_buffer_length =  			inurb->number_of_packets *  			inurb->iso_frame_desc[0].length; -		preempt_disable(); +  		if (u == 0) {  			int now;  			struct usb_device *dev = inurb->dev; @@ -686,19 +685,17 @@ dotry:  		}  		err = usb_submit_urb(inurb, GFP_ATOMIC);  		if (err < 0) { -			preempt_enable();  			snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])"  				   " returned %i\n", u, err);  			return err;  		}  		err = usb_submit_urb(outurb, GFP_ATOMIC);  		if (err < 0) { -			preempt_enable();  			snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])"  				   " returned %i\n", u, err);  			return err;  		} -		preempt_enable(); +  		if (inurb->start_frame != outurb->start_frame) {  			snd_printd(KERN_DEBUG  				   "u[%i] start_frames differ in:%u out:%u\n", diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cbd37f2c76d..91e0e2a4808 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -150,11 +150,11 @@  MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");  MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");  MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}"); +MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604),"NAME_ALLCAPS"(0x8001)(0x8005)(0x8007)}}");  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 */ +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */  module_param_array(index, int, NULL, 0444);  MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS"."); @@ -305,11 +305,9 @@ static void usX2Y_unlinkSeq(struct snd_usX2Y_AsyncSeq *S)  {  	int	i;  	for (i = 0; i < URBS_AsyncSeq; ++i) { -		if (S[i].urb) { -			usb_kill_urb(S->urb[i]); -			usb_free_urb(S->urb[i]); -			S->urb[i] = NULL; -		} +		usb_kill_urb(S->urb[i]); +		usb_free_urb(S->urb[i]); +		S->urb[i] = NULL;  	}  	kfree(S->buffer);  } @@ -334,7 +332,9 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = {  	{ /* terminator */ }  }; -static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) +static int usX2Y_create_card(struct usb_device *device, +			     struct usb_interface *intf, +			     struct snd_card **cardp)  {  	int		dev;  	struct snd_card *	card; @@ -345,15 +345,15 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)  			break;  	if (dev >= SNDRV_CARDS)  		return -ENODEV; -	err = snd_card_create(index[dev], id[dev], THIS_MODULE, -			      sizeof(struct usX2Ydev), &card); +	err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE, +			   sizeof(struct usX2Ydev), &card);  	if (err < 0)  		return err;  	snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1;  	card->private_free = snd_usX2Y_card_private_free;  	usX2Y(card)->dev = device;  	init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); -	mutex_init(&usX2Y(card)->prepare_mutex); +	mutex_init(&usX2Y(card)->pcm_mutex);  	INIT_LIST_HEAD(&usX2Y(card)->midi_list);  	strcpy(card->driver, "USB "NAME_ALLCAPS"");  	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); @@ -384,10 +384,9 @@ static int usX2Y_usb_probe(struct usb_device *device,  	     le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))  		return -EINVAL; -	err = usX2Y_create_card(device, &card); +	err = usX2Y_create_card(device, intf, &card);  	if (err < 0)  		return err; -	snd_card_set_dev(card, &intf->dev);  	if ((err = usX2Y_hwdep_new(card, device)) < 0  ||  	    (err = snd_card_register(card)) < 0) {  		snd_card_free(card); @@ -459,15 +458,4 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr)  	}  } -static int __init snd_usX2Y_module_init(void) -{ -	return usb_register(&snd_usX2Y_usb_driver); -} - -static void __exit snd_usX2Y_module_exit(void) -{ -	usb_deregister(&snd_usX2Y_usb_driver); -} - -module_init(snd_usX2Y_module_init) -module_exit(snd_usX2Y_module_exit) +module_usb_driver(snd_usX2Y_usb_driver); diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index e43c0a86441..6ae6b080693 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -36,7 +36,7 @@ struct usX2Ydev {  	unsigned int		rate,  				format;  	int			chip_status; -	struct mutex		prepare_mutex; +	struct mutex		pcm_mutex;  	struct us428ctls_sharedmem	*us428ctls_sharedmem;  	int			wait_iso_frame;  	wait_queue_head_t	us428ctls_wait_queue_head; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 5d37d1ccf81..a63330dd140 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -34,6 +34,7 @@  #include <linux/interrupt.h>  #include <linux/slab.h>  #include <linux/usb.h> +#include <linux/moduleparam.h>  #include <sound/core.h>  #include <sound/info.h>  #include <sound/pcm.h> @@ -79,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs)  		cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;  		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */  			snd_printk(KERN_ERR "active frame status %i. " -				   "Most propably some hardware problem.\n", +				   "Most probably some hardware problem.\n",  				   urb->iso_frame_desc[i].status);  			return urb->iso_frame_desc[i].status;  		} @@ -272,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)  		struct snd_usX2Y_substream *subs = usX2Y->subs[s];  		if (subs) {  			if (atomic_read(&subs->state) >= state_PRERUNNING) { +				unsigned long flags; + +				snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags);  				snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); +				snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags);  			}  			for (u = 0; u < NRURBS; u++) {  				struct urb *urb = subs->urb[u]; @@ -294,19 +299,6 @@ static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y,  	usX2Y_clients_stop(usX2Y);  } -static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, -				 struct snd_usX2Y_substream *subs, struct urb *urb) -{ -	snd_printk(KERN_ERR -"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" -"Most propably some urb of usb-frame %i is still missing.\n" -"Cause could be too long delays in usb-hcd interrupt handling.\n", -		   usb_get_current_frame_number(usX2Y->dev), -		   subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", -		   usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); -	usX2Y_clients_stop(usX2Y); -} -  static void i_usX2Y_urb_complete(struct urb *urb)  {  	struct snd_usX2Y_substream *subs = urb->context; @@ -323,12 +315,9 @@ static void i_usX2Y_urb_complete(struct urb *urb)  		usX2Y_error_urb_status(usX2Y, subs, urb);  		return;  	} -	if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF))) -		subs->completed_urb = urb; -	else { -		usX2Y_error_sequence(usX2Y, subs, urb); -		return; -	} + +	subs->completed_urb = urb; +  	{  		struct snd_usX2Y_substream *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE],  			*playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; @@ -502,7 +491,6 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)  			if (0 == i)  				atomic_set(&subs->state, state_STARTING3);  			urb->dev = usX2Y->dev; -			urb->transfer_flags = URB_ISO_ASAP;  			for (pack = 0; pack < nr_of_packs(); pack++) {  				urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;  				urb->iso_frame_desc[pack].length = subs->maxpacksize; @@ -695,9 +683,6 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)  			((char*)(usbdata + i))[1] = ra[i].c2;  			usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),  					  usbdata + i, 2, i_usX2Y_04Int, usX2Y); -#ifdef OLD_USB -			us->urb[i]->transfer_flags = USB_QUEUE_BULK; -#endif  		}  		us->submitted =	0;  		us->len =	NOOF_SETRATE_URBS; @@ -767,36 +752,44 @@ static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream,  	unsigned int		rate = params_rate(hw_params);  	snd_pcm_format_t	format = params_format(hw_params);  	struct snd_card *card = substream->pstr->pcm->card; -	struct list_head *list; +	struct usX2Ydev	*dev = usX2Y(card); +	int i; +	mutex_lock(&usX2Y(card)->pcm_mutex);  	snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params); -	// all pcm substreams off one usX2Y have to operate at the same rate & format -	list_for_each(list, &card->devices) { -		struct snd_device *dev; -		struct snd_pcm *pcm; -		int s; -		dev = snd_device(list); -		if (dev->type != SNDRV_DEV_PCM) +	/* all pcm substreams off one usX2Y have to operate at the same +	 * rate & format +	 */ +	for (i = 0; i < dev->pcm_devs * 2; i++) { +		struct snd_usX2Y_substream *subs = dev->subs[i]; +		struct snd_pcm_substream *test_substream; + +		if (!subs) +			continue; +		test_substream = subs->pcm_substream; +		if (!test_substream || test_substream == substream || +		    !test_substream->runtime)  			continue; -		pcm = dev->device_data; -		for (s = 0; s < 2; ++s) { -			struct snd_pcm_substream *test_substream; -			test_substream = pcm->streams[s].substream; -			if (test_substream && test_substream != substream  && -			    test_substream->runtime && -			    ((test_substream->runtime->format && -			      test_substream->runtime->format != format) || -			     (test_substream->runtime->rate && -			      test_substream->runtime->rate != rate))) -				return -EINVAL; +		if ((test_substream->runtime->format && +		     test_substream->runtime->format != format) || +		    (test_substream->runtime->rate && +		     test_substream->runtime->rate != rate)) { +			err = -EINVAL; +			goto error;  		}  	} -	if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) { + +	err = snd_pcm_lib_malloc_pages(substream, +				       params_buffer_bytes(hw_params)); +	if (err < 0) {  		snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n",  			   substream, params_buffer_bytes(hw_params), err); -		return err; +		goto error;  	} -	return 0; + + error: +	mutex_unlock(&usX2Y(card)->pcm_mutex); +	return err;  }  /* @@ -806,7 +799,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct snd_usX2Y_substream *subs = runtime->private_data; -	mutex_lock(&subs->usX2Y->prepare_mutex); +	mutex_lock(&subs->usX2Y->pcm_mutex);  	snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);  	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { @@ -827,7 +820,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)  			usX2Y_urbs_release(subs);  		}  	} -	mutex_unlock(&subs->usX2Y->prepare_mutex); +	mutex_unlock(&subs->usX2Y->pcm_mutex);  	return snd_pcm_lib_free_pages(substream);  }  /* @@ -844,7 +837,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)  	int err = 0;  	snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); -	mutex_lock(&usX2Y->prepare_mutex); +	mutex_lock(&usX2Y->pcm_mutex);  	usX2Y_subs_prepare(subs);  // Start hardware streams  // SyncStream first.... @@ -864,7 +857,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)  		err = usX2Y_urbs_start(subs);   up_prepare_mutex: -	mutex_unlock(&usX2Y->prepare_mutex); +	mutex_unlock(&usX2Y->pcm_mutex);  	return err;  } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 287ef73b123..90766a92e7f 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -20,7 +20,7 @@   at standard samplerates,   what led to this part of the usx2y module:    It provides the alsa kernel half of the usx2y-alsa-jack driver pair. - The pair uses a hardware dependant alsa-device for mmaped pcm transport. + The pair uses a hardware dependent alsa-device for mmaped pcm transport.   Advantage achieved:           The usb_hc moves pcm data from/into memory via DMA.           That memory is mmaped by jack's usx2y driver. @@ -38,7 +38,7 @@           2periods works but is useless cause of crackling).   This is a first "proof of concept" implementation. - Later, functionalities should migrate to more apropriate places: + Later, functionalities should migrate to more appropriate places:   Userland:   - The jackd could mmap its float-pcm buffers directly from alsa-lib.   - alsa-lib could provide power of 2 period sized shaping combined with int/float @@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)  	}  	for (i = 0; i < nr_of_packs(); i++) {  		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ -			snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); +			snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);  			return urb->iso_frame_desc[i].status;  		}  		lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; @@ -244,13 +244,8 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)  		usX2Y_error_urb_status(usX2Y, subs, urb);  		return;  	} -	if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF))) -		subs->completed_urb = urb; -	else { -		usX2Y_error_sequence(usX2Y, subs, urb); -		return; -	} +	subs->completed_urb = urb;  	capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];  	capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];  	playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; @@ -363,7 +358,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct snd_usX2Y_substream *subs = runtime->private_data,  		*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; -	mutex_lock(&subs->usX2Y->prepare_mutex); +	mutex_lock(&subs->usX2Y->pcm_mutex);  	snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);  	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { @@ -392,7 +387,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)  				usX2Y_usbpcm_urbs_release(cap_subs2);  		}  	} -	mutex_unlock(&subs->usX2Y->prepare_mutex); +	mutex_unlock(&subs->usX2Y->pcm_mutex);  	return snd_pcm_lib_free_pages(substream);  } @@ -443,7 +438,6 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)  					if (0 == u)  						atomic_set(&subs->state, state_STARTING3);  					urb->dev = usX2Y->dev; -					urb->transfer_flags = URB_ISO_ASAP;  					for (pack = 0; pack < nr_of_packs(); pack++) {  						urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());  						urb->iso_frame_desc[pack].length = subs->maxpacksize; @@ -499,7 +493,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)  		memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));  	} -	mutex_lock(&usX2Y->prepare_mutex); +	mutex_lock(&usX2Y->pcm_mutex);  	usX2Y_subs_prepare(subs);  // Start hardware streams  // SyncStream first.... @@ -540,7 +534,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)  		usX2Y->hwdep_pcm_shm->capture_iso_start = -1;   up_prepare_mutex: -	mutex_unlock(&usX2Y->prepare_mutex); +	mutex_unlock(&usX2Y->pcm_mutex);  	return err;  } @@ -606,59 +600,30 @@ static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =  }; -static int usX2Y_pcms_lock_check(struct snd_card *card) +static int usX2Y_pcms_busy_check(struct snd_card *card)  { -	struct list_head *list; -	struct snd_device *dev; -	struct snd_pcm *pcm; -	int err = 0; -	list_for_each(list, &card->devices) { -		dev = snd_device(list); -		if (dev->type != SNDRV_DEV_PCM) -			continue; -		pcm = dev->device_data; -		mutex_lock(&pcm->open_mutex); -	} -	list_for_each(list, &card->devices) { -		int s; -		dev = snd_device(list); -		if (dev->type != SNDRV_DEV_PCM) -			continue; -		pcm = dev->device_data; -		for (s = 0; s < 2; ++s) { -			struct snd_pcm_substream *substream; -			substream = pcm->streams[s].substream; -			if (substream && SUBSTREAM_BUSY(substream)) -				err = -EBUSY; -		} -	} -	return err; -} - +	struct usX2Ydev	*dev = usX2Y(card); +	int i; -static void usX2Y_pcms_unlock(struct snd_card *card) -{ -	struct list_head *list; -	struct snd_device *dev; -	struct snd_pcm *pcm; -	list_for_each(list, &card->devices) { -		dev = snd_device(list); -		if (dev->type != SNDRV_DEV_PCM) -			continue; -		pcm = dev->device_data; -		mutex_unlock(&pcm->open_mutex); +	for (i = 0; i < dev->pcm_devs * 2; i++) { +		struct snd_usX2Y_substream *subs = dev->subs[i]; +		if (subs && subs->pcm_substream && +		    SUBSTREAM_BUSY(subs->pcm_substream)) +			return -EBUSY;  	} +	return 0;  } -  static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)  { -	// we need to be the first   	struct snd_card *card = hw->card; -	int err = usX2Y_pcms_lock_check(card); -	if (0 == err) +	int err; + +	mutex_lock(&usX2Y(card)->pcm_mutex); +	err = usX2Y_pcms_busy_check(card); +	if (!err)  		usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; -	usX2Y_pcms_unlock(card); +	mutex_unlock(&usX2Y(card)->pcm_mutex);  	return err;  } @@ -666,10 +631,13 @@ static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)  static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)  {  	struct snd_card *card = hw->card; -	int err = usX2Y_pcms_lock_check(card); -	if (0 == err) +	int err; + +	mutex_lock(&usX2Y(card)->pcm_mutex); +	err = usX2Y_pcms_busy_check(card); +	if (!err)  		usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; -	usX2Y_pcms_unlock(card); +	mutex_unlock(&usX2Y(card)->pcm_mutex);  	return err;  } @@ -723,7 +691,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, st  		return -ENODEV;  	}  	area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; -	area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; +	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;  	area->vm_private_data = hw->private_data;  	return 0;  }  | 
