From 78caf66cb568f2b0c63bf8f87cff2fe1583dd9d0 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Mon, 4 Apr 2011 11:45:28 +0200 Subject: ALSA: 6fire - Update kernel configuration Kernel configuration updated: - experimental dependency removed - description updated Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/Kconfig | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 97724d8fa9f6..cc47a9caec9d 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -100,7 +100,6 @@ config SND_USB_US122L config SND_USB_6FIRE tristate "TerraTec DMX 6Fire USB" - depends on EXPERIMENTAL select FW_LOADER select SND_RAWMIDI select SND_PCM @@ -108,11 +107,9 @@ config SND_USB_6FIRE 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. This driver currently does not support - firmware loading for all devices. If you own such a device, - you could start windows and let the windows driver upload - the firmware. As long as you do not unplug your device from power, - it should be usable. + after it has been coldstarted. An install script for the firmware + and further help can be found at + http://sixfireusb.sourceforge.net endif # SND_USB -- cgit v1.2.3-55-g7522 From e220fa3bf503d63039fa8e0398a1c252d24663f9 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Mon, 4 Apr 2011 11:47:50 +0200 Subject: ALSA: 6fire - Fix pcm rate assignment Completion of signedness bug for pcm_runtime.rate: variable will never get assigned a negative value now. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/pcm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba62c7468ba8..2110cbf35474 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -456,7 +456,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) /* all substreams closed? if so, stop streaming */ if (!rt->playback.instance && !rt->capture.instance) { usb6fire_pcm_stream_stop(rt); - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); } } mutex_unlock(&rt->stream_mutex); @@ -480,7 +480,6 @@ 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 i; int ret; if (rt->panic) @@ -493,12 +492,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) sub->period_off = 0; if (rt->stream_state == STREAM_DISABLED) { - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (alsa_rt->rate == rates[i]) { - rt->rate = i; + for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) + if (alsa_rt->rate == rates[rt->rate]) break; - } - if (i == ARRAY_SIZE(rates)) { + if (rt->rate == ARRAY_SIZE(rates)) { mutex_unlock(&rt->stream_mutex); snd_printk("invalid rate %d in prepare.\n", alsa_rt->rate); @@ -613,7 +610,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip) rt->chip = chip; rt->stream_state = STREAM_DISABLED; - rt->rate = -1; + rt->rate = ARRAY_SIZE(rates); init_waitqueue_head(&rt->stream_wait_queue); mutex_init(&rt->stream_mutex); -- cgit v1.2.3-55-g7522 From 58c54fa47f5de976959767fa8d9bb857eee4c4e5 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Mon, 4 Apr 2011 11:49:00 +0200 Subject: ALSA: 6fire - Add support for S32_LE format Added support for sample format s32_le. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/pcm.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 2110cbf35474..7ea698793d43 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -64,7 +64,7 @@ static const struct snd_pcm_hardware pcm_hw = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -228,7 +228,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) 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 = (u32 *) urb->buffer; + 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 @@ -244,7 +244,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) else frame_count = 0; - src = (u32 *) (urb->buffer + total_length); + 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++) { @@ -274,9 +279,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, * (alsa_rt->frame_bits >> 3)); u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size * (alsa_rt->frame_bits >> 3)); - u32 *dest = (u32 *) urb->buffer; + 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 { + snd_printk(KERN_ERR PREFIX "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 */ -- cgit v1.2.3-55-g7522 From b84610b95f7e7bcd1cd9ecf3e8506a59e9f557fd Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Mon, 4 Apr 2011 11:49:57 +0200 Subject: ALSA: 6fire - Improve firmware loader Firmware loader: magical device bytes check updated (accepts all device versions now and accepts possibly loaded firmware, if it is knowing to be working) Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/firmware.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 9081a54a9c6c..e720035fbd1e 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -3,12 +3,6 @@ * * Firmware loader * - * Currently not working for all devices. To be able to use the device - * in linux, it is also possible to let the windows driver upload the firmware. - * For that, start the computer in windows and reboot. - * As long as the device is connected to the power supply, no firmware reload - * needs to be performed. - * * Author: Torsten Schenk * Created: Jan 01, 2011 * Version: 0.3.0 @@ -72,6 +66,10 @@ static const u8 ep_w_max_packet_size[] = { 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ }; +static const u8 known_fw_versions[][4] = { + { 0x03, 0x01, 0x0b, 0x00 } +}; + struct ihex_record { u16 address; u8 len; @@ -363,6 +361,25 @@ static int usb6fire_fw_fpga_upload( 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(u8 *version) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++) + if (!memcmp(version, known_fw_versions + i, 4)) + return 0; + + snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " + "%02x %02x %02x %02x. " + "please reconnect to power. if this failure " + "still happens, check your firmware installation.", + version[0], version[1], version[2], version[3]); + return -EINVAL; +} + int usb6fire_fw_init(struct usb_interface *intf) { int i; @@ -378,9 +395,7 @@ int usb6fire_fw_init(struct usb_interface *intf) "firmware state.\n"); return ret; } - if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55 - || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7] - != 0x00) { + if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) { snd_printk(KERN_ERR PREFIX "unknown device firmware state " "received from device: "); for (i = 0; i < 8; i++) @@ -389,7 +404,7 @@ int usb6fire_fw_init(struct usb_interface *intf) return -EIO; } /* do we need fpga loader ezusb firmware? */ - if (buffer[3] == 0x01 && buffer[6] == 0x19) { + if (buffer[3] == 0x01) { ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6firel2.ihx", 0, NULL, 0); if (ret < 0) @@ -397,7 +412,10 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* do we need fpga firmware and application ezusb firmware? */ - else if (buffer[3] == 0x02 && buffer[6] == 0x0b) { + else if (buffer[3] == 0x02) { + ret = usb6fire_fw_check(buffer + 4); + if (ret < 0) + return ret; ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); if (ret < 0) return ret; @@ -410,8 +428,8 @@ int usb6fire_fw_init(struct usb_interface *intf) return FW_NOT_READY; } /* all fw loaded? */ - else if (buffer[3] == 0x03 && buffer[6] == 0x0b) - return 0; + else if (buffer[3] == 0x03) + return usb6fire_fw_check(buffer + 4); /* unknown data? */ else { snd_printk(KERN_ERR PREFIX "unknown device firmware state " -- cgit v1.2.3-55-g7522 From 2475b0d407614ea5a41b8325d45c614d94087088 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Mon, 4 Apr 2011 11:50:53 +0200 Subject: ALSA: 6fire - Add support of digital-thru mixer Digital Thru mixer element added (device can act as converter optical<->coax) Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ sound/usb/6fire/control.h | 17 ++++++++ sound/usb/6fire/pcm.c | 62 +++++++-------------------- 3 files changed, 137 insertions(+), 47 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 248463511186..ac828eff1a63 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -65,6 +65,15 @@ init_data[] = { { 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}; + +enum { + DIGITAL_THRU_ONLY_SAMPLERATE = 3 +}; + static void usb6fire_control_master_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; @@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt) } } +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_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, 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 __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .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 + }, {} }; @@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) 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) { @@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_master_vol_update(rt); + usb6fire_control_streaming_update(rt); i = 0; while (elements[i].name) { diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index b534c777ab02..8f5aeead2e3d 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -21,12 +21,29 @@ 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 master_vol; }; diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 7ea698793d43..b137b25865cc 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -17,26 +17,23 @@ #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 */ + * 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_altsetting[] = { 1, 1, 2, 2, 3, 3 }; 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 }; -/* 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}; - enum { /* settings for pcm */ OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 }; @@ -48,15 +45,6 @@ enum { /* pcm streaming states */ STREAM_STOPPING }; -enum { /* pcm sample rates (also index into RATES_XXX[]) */ - RATE_44KHZ, - RATE_48KHZ, - RATE_88KHZ, - RATE_96KHZ, - RATE_176KHZ, - RATE_192KHZ -}; - static const struct snd_pcm_hardware pcm_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = { static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) { int ret; - struct usb_device *device = rt->chip->dev; - struct comm_runtime *comm_rt = rt->chip->comm; + struct control_runtime *ctrl_rt = rt->chip->control; - if (rt->rate >= ARRAY_SIZE(rates)) - return -EINVAL; - /* disable streaming */ - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); + ctrl_rt->usb_streaming = false; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error stopping streaming while " "setting samplerate %d.\n", rates[rt->rate]); return ret; } - ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error setting interface " - "altsetting %d for samplerate %d.\n", - rates_altsetting[rt->rate], rates[rt->rate]); - return ret; - } - - /* set soundcard clock */ - ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate], - rates_6fire_vh[rt->rate]); + ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* enable analog inputs and outputs - * (one bit per stereo-channel) */ - ret = comm_rt->write16(comm_rt, 0x02, 0x02, - (1 << (OUT_N_CHANNELS / 2)) - 1, - (1 << (IN_N_CHANNELS / 2)) - 1); + ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, + false, false); if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing analog channels " + snd_printk(KERN_ERR PREFIX "error initializing channels " "while setting samplerate %d.\n", rates[rt->rate]); return ret; } - /* disable digital inputs and outputs */ - ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); - if (ret < 0) { - snd_printk(KERN_ERR PREFIX "error initializing digital " - "channels while setting samplerate %d.\n", - rates[rt->rate]); - return ret; - } - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01); + ctrl_rt->usb_streaming = true; + ret = ctrl_rt->update_streaming(ctrl_rt); if (ret < 0) { snd_printk(KERN_ERR PREFIX "error starting streaming while " "setting samplerate %d.\n", rates[rt->rate]); @@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream( 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) { 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; } } -- cgit v1.2.3-55-g7522 From 9cdc352936311eea55624cbabafda296b99ff137 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 11 Apr 2011 17:56:32 +0200 Subject: ALSA: usb-audio: Add quirks for Audio Kontrol 6 This new device by Native Instruments is also compliant to the USB standard v2.0, but hides this detail at when connected. It needs the same boot quirks than other models, and also has two non-class-compliant mixer controls. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 17 +++++++++++++++++ sound/usb/quirks-table.h | 6 ++++++ sound/usb/quirks.c | 1 + 3 files changed, 24 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 73dcc8256bc0..4a7ad7ed62f7 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -398,6 +398,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, return 0; } +static struct snd_kcontrol_new snd_nativeinstruments_ak6_mixers[] = { + { + .name = "Direct Monitor Channel 1+2", + .private_value = _MAKE_NI_CONTROL(0x03, 0x03), + }, + { + .name = "Direct Monitor Channel 3+4", + .private_value = _MAKE_NI_CONTROL(0x03, 0x05), + }, +}; + static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { { .name = "Direct Thru Channel A", @@ -526,6 +537,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_xonar_u1_controls_create(mixer); break; + case USB_ID(0x17cc, 0x1001): /* Audio Kontrol 6 */ + err = snd_nativeinstruments_create_mixer(mixer, + snd_nativeinstruments_ak6_mixers, + ARRAY_SIZE(snd_nativeinstruments_ak6_mixers)); + break; + case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ err = snd_nativeinstruments_create_mixer(mixer, snd_nativeinstruments_ta6_mixers, diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c66d3f64dcf8..54e18c181a12 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2331,6 +2331,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, /* Native Instruments MK2 series */ +{ + /* Audio Kontrol 6 */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x17cc, + .idProduct = 0x1000, +}, { /* Traktor Audio 6 */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 355759bad581..2452edd2f141 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -539,6 +539,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); + case USB_ID(0x17cc, 0x1000): /* Audio Kontrol 6 */ case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */ case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */ return snd_usb_nativeinstruments_boot_quirk(dev); -- cgit v1.2.3-55-g7522 From 8ae9572b5b08f1d2a2ea6613f59d00f741b38b2d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sat, 23 Apr 2011 20:56:43 +0200 Subject: ALSA: 6fire: use the kernel's built-in bit reverse table Signed-off-by: Daniel Mack Cc: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/firmware.c | 29 ++--------------------------- sound/usb/Kconfig | 1 + 2 files changed, 3 insertions(+), 27 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index e720035fbd1e..45ffa12f0dab 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -15,6 +15,7 @@ */ #include +#include #include "firmware.h" #include "chip.h" @@ -27,32 +28,6 @@ enum { FPGA_BUFSIZE = 512, FPGA_EP = 2 }; -static const u8 BIT_REVERSE_TABLE[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, - 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, - 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, - 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, - 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, - 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, - 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, - 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, - 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, - 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, - 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, - 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, - 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, - 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, - 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, - 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, - 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, - 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, - 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, - 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, - 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, - 0xbf, 0x7f, 0xff }; - /* * wMaxPacketSize of pcm endpoints. * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c @@ -338,7 +313,7 @@ static int usb6fire_fw_fpga_upload( while (c != end) { for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) - buffer[i] = BIT_REVERSE_TABLE[(u8) *c]; + buffer[i] = byte_rev_table[(u8) *c]; ret = usb6fire_fw_fpga_write(device, buffer, i); if (ret < 0) { diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index cc47a9caec9d..8beb77563da2 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -101,6 +101,7 @@ config SND_USB_US122L config SND_USB_6FIRE tristate "TerraTec DMX 6Fire USB" select FW_LOADER + select BITREVERSE select SND_RAWMIDI select SND_PCM help -- cgit v1.2.3-55-g7522 From 59bb7f0eebe69aa32a5c7917a23a7da1c5667d73 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 28 Apr 2011 09:58:43 +0200 Subject: ALSA: usb-audio - Don't expose broken dB ranges Some crappy USB-audio devices give broken dB ranges, e.g. both min and max are 0dB. This confuses the volume control that prefers dB expression such as alsactl or PulseAudio. In such a case, it's much better not to expose the broken dB information. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5e4775716607..c8c28cd75534 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1097,11 +1097,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, 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); + if (cval->dBmin < cval->dBmax) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } } break; -- cgit v1.2.3-55-g7522 From 60ed286a61b43e3fedf18e63f2d71b758f3505aa Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:39 +0200 Subject: ALSA: usb-audio: make hwc_debug a noop in case HW_CONST_DEBUG is not set Just defining it to nothing is dangerous as it can alter the code execution flow, for example when used in as only function in a conditional code block. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/debug.h b/sound/usb/debug.h index 343ec2d9ee66..58030176f008 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 */ -- cgit v1.2.3-55-g7522 From ee95cb6121dae17bc199cd566503dff1b2dd243b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:40 +0200 Subject: ALSA: usb-audio: include format.h in format.c Just in case a prototype changes, we'll be warned. This also fixes a sparse warning. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/format.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/usb') diff --git a/sound/usb/format.c b/sound/usb/format.c index 5b792d2c8061..95d5d7c4f957 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 -- cgit v1.2.3-55-g7522 From 759e890f5c25ef087d866b330261e793b03ef7a4 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:41 +0200 Subject: ALSA: usb-audio: remove invalid extra mixers for Komplete Audio 6 This was a flaw in the reading of the spec tables - Native Instrument's "Komplete Audio 6" device has no such extra controls. This patch also fixes the device name in two comments. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 17 ----------------- sound/usb/quirks-table.h | 2 +- sound/usb/quirks.c | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 4a7ad7ed62f7..73dcc8256bc0 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -398,17 +398,6 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_nativeinstruments_ak6_mixers[] = { - { - .name = "Direct Monitor Channel 1+2", - .private_value = _MAKE_NI_CONTROL(0x03, 0x03), - }, - { - .name = "Direct Monitor Channel 3+4", - .private_value = _MAKE_NI_CONTROL(0x03, 0x05), - }, -}; - static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { { .name = "Direct Thru Channel A", @@ -537,12 +526,6 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_xonar_u1_controls_create(mixer); break; - case USB_ID(0x17cc, 0x1001): /* Audio Kontrol 6 */ - err = snd_nativeinstruments_create_mixer(mixer, - snd_nativeinstruments_ak6_mixers, - ARRAY_SIZE(snd_nativeinstruments_ak6_mixers)); - break; - case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ err = snd_nativeinstruments_create_mixer(mixer, snd_nativeinstruments_ta6_mixers, diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 54e18c181a12..5c1a176c426d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2332,7 +2332,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), /* Native Instruments MK2 series */ { - /* Audio Kontrol 6 */ + /* Komplete Audio 6 */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x17cc, .idProduct = 0x1000, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 2452edd2f141..c1a5d7d4580b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -539,7 +539,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); - case USB_ID(0x17cc, 0x1000): /* Audio Kontrol 6 */ + 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); -- cgit v1.2.3-55-g7522 From 56a9eb1f30c3c7b543a5684e91b47d6ae952feba Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:42 +0200 Subject: ALSA: usb-audio: Add quirk for KORG PANDORA PX5D MIDI interface Signed-off-by: Daniel Mack Reported-and-tested-by: Frédéric Jaume Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 5c1a176c426d..78c3e8dbca60 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2179,6 +2179,17 @@ 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, + } +}, + /* AKAI devices */ { USB_DEVICE(0x09e8, 0x0062), -- cgit v1.2.3-55-g7522 From 0ef283247a0cf0fd2e8370ee467030292eb3129e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:43 +0200 Subject: ALSA: usb-audio: add quirks for Roland GR-55 Signed-off-by: Daniel Mack Reported-by: Jeffrey Scott Flesher Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 78c3e8dbca60..690767c0aad0 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1651,6 +1651,32 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0127), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "GR-55", */ + .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_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { -- cgit v1.2.3-55-g7522 From 3bc6fbc7439a88969de97d979795ce7847950668 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:44 +0200 Subject: ALSA: usb-audio: assume valid clock If the interface can't report a clock's validity, assume that it's valid. Signed-off-by: Daniel Mack Reported-by: Vicente Joel Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 7754a1034545..075195e8661a 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -104,6 +104,15 @@ 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)) + return 1; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, @@ -114,7 +123,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) if (err < 0) { snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", __func__, source_id); - return err; + return 0; } return !!data; -- cgit v1.2.3-55-g7522 From c91d9cda558fc348205fa972c8b864f8579ef258 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 18 May 2011 11:28:45 +0200 Subject: ALSA: usb-audio: handle "Fast Track Ultra" with USB_DEVICE_VENDOR_SPEC() That way, the class compliant MIDI interface is also handled. Signed-off-by: Daniel Mack Reported-and-tested-by: Grant Diffey Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 690767c0aad0..78792a8900c3 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1979,7 +1979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0763, 0x2080), + 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", */ @@ -2046,7 +2046,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", */ -- cgit v1.2.3-55-g7522 From 7cdd8d73139ec935a8e91806131a5b91e26c653e Mon Sep 17 00:00:00 2001 From: Mathieu Bouffard Date: Wed, 18 May 2011 17:09:17 +0200 Subject: ALSA: usb-audio - Add support for USB X-Fi S51 Pro USB X-Fi S51 Pro volume and mute from the volume knob on the unit. Compiled and tested with 2.6.39-rc7-git12 Signed-off-by: Mathieu Bouffard Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 73dcc8256bc0..9146cffa6ede 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -61,6 +61,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 */ }; @@ -188,6 +189,12 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, !value, 0, NULL, 0, 100); + /* 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, 100); else err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, @@ -234,9 +241,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, @@ -512,6 +523,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 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) -- cgit v1.2.3-55-g7522