diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/Kconfig | 14 | ||||
-rw-r--r-- | sound/usb/caiaq/Makefile | 3 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-audio.c | 7 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-control.c | 315 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-control.h | 6 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-device.c | 92 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-device.h | 20 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-input.c | 238 | ||||
-rw-r--r-- | sound/usb/caiaq/caiaq-midi.c | 3 | ||||
-rw-r--r-- | sound/usb/usbaudio.c | 50 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 1 | ||||
-rw-r--r-- | sound/usb/usbmidi.c | 1 | ||||
-rw-r--r-- | sound/usb/usbmixer.c | 34 | ||||
-rw-r--r-- | sound/usb/usbmixer_maps.c | 11 | ||||
-rw-r--r-- | sound/usb/usbquirks.h | 28 | ||||
-rw-r--r-- | sound/usb/usx2y/usX2Yhwdep.c | 24 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2y.c | 1 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2yaudio.c | 1 | ||||
-rw-r--r-- | sound/usb/usx2y/usx2yhwdeppcm.c | 20 |
19 files changed, 719 insertions, 150 deletions
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 7061438..9351b8a 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -31,17 +31,18 @@ config SND_USB_USX2Y config SND_USB_CAIAQ tristate "Native Instruments USB audio devices" - depends on SND && USB - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help + depends on SND && USB + select SND_HWDEP + select SND_RAWMIDI + select SND_PCM + help Say Y here to include support for caiaq USB audio interfaces, namely: * Native Instruments RigKontrol2 * Native Instruments RigKontrol3 * Native Instruments Kore Controller + * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 * Native Instruments Audio 8 DJ @@ -51,12 +52,15 @@ config SND_USB_CAIAQ config SND_USB_CAIAQ_INPUT bool "enable input device for controllers" depends on SND_USB_CAIAQ + depends on INPUT=y || INPUT=SND_USB_CAIAQ help Say Y here to support input controllers like buttons, knobs, alpha dials and analog pedals on the following products: * Native Instruments RigKontrol2 * Native Instruments RigKontrol3 + * Native Instruments Kore Controller + * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 endmenu diff --git a/sound/usb/caiaq/Makefile b/sound/usb/caiaq/Makefile index 455c8c5..23dadd5 100644 --- a/sound/usb/caiaq/Makefile +++ b/sound/usb/caiaq/Makefile @@ -1,3 +1,4 @@ -snd-usb-caiaq-objs := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-input.o +snd-usb-caiaq-y := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-control.o +snd-usb-caiaq-$(CONFIG_SND_USB_CAIAQ_INPUT) += caiaq-input.o obj-$(CONFIG_SND_USB_CAIAQ) += snd-usb-caiaq.o diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 0666908..9cc4cd8 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <sound/driver.h> #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -27,9 +26,7 @@ #include <sound/initval.h> #include <sound/pcm.h> #include <sound/rawmidi.h> -#ifdef CONFIG_SND_USB_CAIAQ_INPUT #include <linux/input.h> -#endif #include "caiaq-device.h" #include "caiaq-audio.h" @@ -60,7 +57,7 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { .channels_min = CHANNELS_PER_STREAM, .channels_max = CHANNELS_PER_STREAM, .buffer_bytes_max = MAX_BUFFER_SIZE, - .period_bytes_min = 4096, + .period_bytes_min = 128, .period_bytes_max = MAX_BUFFER_SIZE, .periods_min = 1, .periods_max = 1024, @@ -606,7 +603,7 @@ static void free_urbs(struct urb **urbs) kfree(urbs); } -int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) +int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) { int i, ret; diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c new file mode 100644 index 0000000..798ca12 --- /dev/null +++ b/sound/usb/caiaq/caiaq-control.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2007 Daniel Mack + * friendly supported by NI. + * + * 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/interrupt.h> +#include <linux/usb.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/rawmidi.h> +#include <sound/control.h> +#include <linux/input.h> + +#include "caiaq-device.h" +#include "caiaq-control.h" + +#define CNT_INTVAL 0x10000 + +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); + int pos = kcontrol->private_value; + int is_intval = pos & CNT_INTVAL; + + uinfo->count = 1; + pos &= ~CNT_INTVAL; + + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) + && (pos == 0)) { + /* current input mode of A8DJ */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 2; + return 0; + } + + if (is_intval) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 64; + } else { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + } + + return 0; +} + +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); + int pos = kcontrol->private_value; + + if (pos & CNT_INTVAL) + ucontrol->value.integer.value[0] + = dev->control_state[pos & ~CNT_INTVAL]; + else + ucontrol->value.integer.value[0] + = !!(dev->control_state[pos / 8] & (1 << pos % 8)); + + return 0; +} + +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); + int pos = kcontrol->private_value; + + if (pos & CNT_INTVAL) { + dev->control_state[pos & ~CNT_INTVAL] + = ucontrol->value.integer.value[0]; + snd_usb_caiaq_send_command(dev, EP1_CMD_DIMM_LEDS, + dev->control_state, sizeof(dev->control_state)); + } else { + if (ucontrol->value.integer.value[0]) + dev->control_state[pos / 8] |= 1 << (pos % 8); + else + dev->control_state[pos / 8] &= ~(1 << (pos % 8)); + + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, + dev->control_state, sizeof(dev->control_state)); + } + + return 1; +} + +static struct snd_kcontrol_new kcontrol_template __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .index = 0, + .info = control_info, + .get = control_get, + .put = control_put, + /* name and private_value filled later */ +}; + +struct caiaq_controller { + char *name; + int index; +}; + +static struct caiaq_controller ak1_controller[] = { + { "LED left", 2 }, + { "LED middle", 1 }, + { "LED right", 0 }, + { "LED ring", 3 } +}; + +static struct caiaq_controller rk2_controller[] = { + { "LED 1", 5 }, + { "LED 2", 4 }, + { "LED 3", 3 }, + { "LED 4", 2 }, + { "LED 5", 1 }, + { "LED 6", 0 }, + { "LED pedal", 6 }, + { "LED 7seg_1b", 8 }, + { "LED 7seg_1c", 9 }, + { "LED 7seg_2a", 10 }, + { "LED 7seg_2b", 11 }, + { "LED 7seg_2c", 12 }, + { "LED 7seg_2d", 13 }, + { "LED 7seg_2e", 14 }, + { "LED 7seg_2f", 15 }, + { "LED 7seg_2g", 16 }, + { "LED 7seg_3a", 17 }, + { "LED 7seg_3b", 18 }, + { "LED 7seg_3c", 19 }, + { "LED 7seg_3d", 20 }, + { "LED 7seg_3e", 21 }, + { "LED 7seg_3f", 22 }, + { "LED 7seg_3g", 23 } +}; + +static struct caiaq_controller rk3_controller[] = { + { "LED 7seg_1a", 0 + 0 }, + { "LED 7seg_1b", 0 + 1 }, + { "LED 7seg_1c", 0 + 2 }, + { "LED 7seg_1d", 0 + 3 }, + { "LED 7seg_1e", 0 + 4 }, + { "LED 7seg_1f", 0 + 5 }, + { "LED 7seg_1g", 0 + 6 }, + { "LED 7seg_1p", 0 + 7 }, + + { "LED 7seg_2a", 8 + 0 }, + { "LED 7seg_2b", 8 + 1 }, + { "LED 7seg_2c", 8 + 2 }, + { "LED 7seg_2d", 8 + 3 }, + { "LED 7seg_2e", 8 + 4 }, + { "LED 7seg_2f", 8 + 5 }, + { "LED 7seg_2g", 8 + 6 }, + { "LED 7seg_2p", 8 + 7 }, + + { "LED 7seg_3a", 16 + 0 }, + { "LED 7seg_3b", 16 + 1 }, + { "LED 7seg_3c", 16 + 2 }, + { "LED 7seg_3d", 16 + 3 }, + { "LED 7seg_3e", 16 + 4 }, + { "LED 7seg_3f", 16 + 5 }, + { "LED 7seg_3g", 16 + 6 }, + { "LED 7seg_3p", 16 + 7 }, + + { "LED 7seg_4a", 24 + 0 }, + { "LED 7seg_4b", 24 + 1 }, + { "LED 7seg_4c", 24 + 2 }, + { "LED 7seg_4d", 24 + 3 }, + { "LED 7seg_4e", 24 + 4 }, + { "LED 7seg_4f", 24 + 5 }, + { "LED 7seg_4g", 24 + 6 }, + { "LED 7seg_4p", 24 + 7 }, + + { "LED 1", 32 + 0 }, + { "LED 2", 32 + 1 }, + { "LED 3", 32 + 2 }, + { "LED 4", 32 + 3 }, + { "LED 5", 32 + 4 }, + { "LED 6", 32 + 5 }, + { "LED 7", 32 + 6 }, + { "LED 8", 32 + 7 }, + { "LED pedal", 32 + 8 } +}; + +static struct caiaq_controller kore_controller[] = { + { "LED F1", 8 | CNT_INTVAL }, + { "LED F2", 12 | CNT_INTVAL }, + { "LED F3", 0 | CNT_INTVAL }, + { "LED F4", 4 | CNT_INTVAL }, + { "LED F5", 11 | CNT_INTVAL }, + { "LED F6", 15 | CNT_INTVAL }, + { "LED F7", 3 | CNT_INTVAL }, + { "LED F8", 7 | CNT_INTVAL }, + { "LED touch1", 10 | CNT_INTVAL }, + { "LED touch2", 14 | CNT_INTVAL }, + { "LED touch3", 2 | CNT_INTVAL }, + { "LED touch4", 6 | CNT_INTVAL }, + { "LED touch5", 9 | CNT_INTVAL }, + { "LED touch6", 13 | CNT_INTVAL }, + { "LED touch7", 1 | CNT_INTVAL }, + { "LED touch8", 5 | CNT_INTVAL }, + { "LED left", 18 | CNT_INTVAL }, + { "LED right", 22 | CNT_INTVAL }, + { "LED up", 16 | CNT_INTVAL }, + { "LED down", 20 | CNT_INTVAL }, + { "LED stop", 23 | CNT_INTVAL }, + { "LED play", 21 | CNT_INTVAL }, + { "LED record", 19 | CNT_INTVAL }, + { "LED listen", 17 | CNT_INTVAL }, + { "LED lcd", 30 | CNT_INTVAL }, + { "LED menu", 28 | CNT_INTVAL }, + { "LED sound", 31 | CNT_INTVAL }, + { "LED esc", 29 | CNT_INTVAL }, + { "LED view", 27 | CNT_INTVAL }, + { "LED enter", 24 | CNT_INTVAL }, + { "LED control", 26 | CNT_INTVAL } +}; + +static struct caiaq_controller a8dj_controller[] = { + { "Current input mode", 0 | CNT_INTVAL }, + { "GND lift for TC Vinyl mode", 24 + 0 }, + { "GND lift for TC CD/Line mode", 24 + 1 }, + { "GND lift for phono mode", 24 + 2 }, + { "GND lift for TC Vinyl mode", 24 + 3 }, + { "Software lock", 40 } +}; + +int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) +{ + int i; + struct snd_kcontrol *kc; + + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) { + struct caiaq_controller *c = ak1_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): + for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) { + struct caiaq_controller *c = rk2_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) { + struct caiaq_controller *c = rk3_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + for (i = 0; i < ARRAY_SIZE(kore_controller); i++) { + struct caiaq_controller *c = kore_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): + for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) { + struct caiaq_controller *c = a8dj_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + + break; + } + + return 0; +} + diff --git a/sound/usb/caiaq/caiaq-control.h b/sound/usb/caiaq/caiaq-control.h new file mode 100644 index 0000000..2e7ab1a --- /dev/null +++ b/sound/usb/caiaq/caiaq-control.h @@ -0,0 +1,6 @@ +#ifndef CAIAQ_CONTROL_H +#define CAIAQ_CONTROL_H + +int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev); + +#endif /* CAIAQ_CONTROL_H */ diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 58af814..58d25e4 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -26,26 +26,28 @@ #include <linux/usb.h> #include <linux/input.h> #include <linux/spinlock.h> -#include <sound/driver.h> #include <sound/core.h> #include <sound/initval.h> #include <sound/pcm.h> #include <sound/rawmidi.h> +#include <sound/control.h> #include "caiaq-device.h" #include "caiaq-audio.h" #include "caiaq-midi.h" +#include "caiaq-control.h" #ifdef CONFIG_SND_USB_CAIAQ_INPUT #include "caiaq-input.h" #endif MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); -MODULE_DESCRIPTION("caiaq USB audio, version 1.2.0"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2"); 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 8 DJ}}"); @@ -94,6 +96,11 @@ static struct usb_device_id snd_usb_id_table[] = { .idProduct = USB_PID_KORECONTROLLER }, { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_KORECONTROLLER2 + }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_AK1 @@ -140,14 +147,21 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) case EP1_CMD_MIDI_READ: snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); break; - + case EP1_CMD_READ_IO: + if (dev->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); + break; + } #ifdef CONFIG_SND_USB_CAIAQ_INPUT case EP1_CMD_READ_ERP: case EP1_CMD_READ_ANALOG: - case EP1_CMD_READ_IO: snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); - break; #endif + break; } dev->ep1_in_urb.actual_length = 0; @@ -156,10 +170,10 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) log("unable to submit urb. OOM!?\n"); } -static int send_command (struct snd_usb_caiaqdev *dev, - unsigned char command, - const unsigned char *buffer, - int len) +int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, + unsigned char command, + const unsigned char *buffer, + int len) { int actual_len; struct usb_device *usb_dev = dev->chip.dev; @@ -207,7 +221,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, rate, depth, bpp); dev->audio_parm_answer = -1; - ret = send_command(dev, EP1_CMD_AUDIO_PARAMS, tmp, sizeof(tmp)); + ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS, + tmp, sizeof(tmp)); if (ret) return ret; @@ -226,7 +241,8 @@ int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp) { char tmp[3] = { digital, analog, erp }; - return send_command(dev, EP1_CMD_AUTO_MSG, tmp, sizeof(tmp)); + return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, + tmp, sizeof(tmp)); } static void setup_card(struct snd_usb_caiaqdev *dev) @@ -241,7 +257,7 @@ static void setup_card(struct snd_usb_caiaqdev *dev) val[0] = 0x00; val[1] = 0x00; val[2] = 0x01; - send_command(dev, EP1_CMD_WRITE_IO, val, 3); + snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): /* RigKontrol2 - display two centered dashes ('--') */ @@ -249,22 +265,52 @@ static void setup_card(struct snd_usb_caiaqdev *dev) val[1] = 0x40; val[2] = 0x40; val[3] = 0x00; - send_command(dev, EP1_CMD_WRITE_IO, val, 4); + snd_usb_caiaq_send_command(dev, 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; - send_command(dev, EP1_CMD_WRITE_IO, val, 1); + snd_usb_caiaq_send_command(dev, 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); + + if (!wait_event_timeout(dev->ep1_wait_queue, + dev->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); + } + break; } - ret = snd_usb_caiaq_audio_init(dev); - if (ret < 0) - log("Unable to set up audio system (ret=%d)\n", ret); + 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 (ret < 0) + log("Unable to set up audio system (ret=%d)\n", ret); + } - ret = snd_usb_caiaq_midi_init(dev); - if (ret < 0) - log("Unable to set up MIDI 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 (ret < 0) + log("Unable to set up MIDI system (ret=%d)\n", ret); + } #ifdef CONFIG_SND_USB_CAIAQ_INPUT ret = snd_usb_caiaq_input_init(dev); @@ -278,6 +324,10 @@ static void setup_card(struct snd_usb_caiaqdev *dev) log("snd_card_register() returned %d\n", ret); snd_card_free(dev->chip.card); } + + ret = snd_usb_caiaq_control_init(dev); + if (ret < 0) + log("Unable to set up control system (ret=%d)\n", ret); } static struct snd_card* create_card(struct usb_device* usb_dev) @@ -340,7 +390,7 @@ static int init_card(struct snd_usb_caiaqdev *dev) if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) return -EIO; - err = send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); + err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); if (err) return err; diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 79bc5be..96a4913 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -7,7 +7,8 @@ #define USB_PID_RIGKONTROL2 0x1969 #define USB_PID_RIGKONTROL3 0x1940 -#define USB_PID_KORECONTROLLER 0x4711 +#define USB_PID_KORECONTROLLER 0x4711 +#define USB_PID_KORECONTROLLER2 0x4712 #define USB_PID_AK1 0x0815 #define USB_PID_AUDIO8DJ 0x1978 @@ -35,6 +36,7 @@ #define EP1_CMD_MIDI_WRITE 0x7 #define EP1_CMD_AUDIO_PARAMS 0x9 #define EP1_CMD_AUTO_MSG 0xb +#define EP1_CMD_DIMM_LEDS 0xc struct caiaq_device_spec { unsigned short fw_version; @@ -62,7 +64,7 @@ struct snd_usb_caiaqdev { struct urb **data_urbs_in; struct urb **data_urbs_out; struct snd_usb_caiaq_cb_info *data_cb_info; - + unsigned char ep1_in_buf[EP1_BUFSIZE]; unsigned char ep1_out_buf[EP1_BUFSIZE]; unsigned char midi_out_buf[EP1_BUFSIZE]; @@ -72,7 +74,7 @@ struct snd_usb_caiaqdev { wait_queue_head_t ep1_wait_queue; wait_queue_head_t prepare_wait_queue; int spec_received, audio_parm_answer; - + char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; char serial[CAIAQ_USB_STR_LEN]; @@ -90,11 +92,16 @@ struct snd_usb_caiaqdev { struct snd_pcm_substream *sub_playback[MAX_STREAMS]; struct snd_pcm_substream *sub_capture[MAX_STREAMS]; + /* Controls */ + unsigned char control_state[64]; + /* Linux input */ #ifdef CONFIG_SND_USB_CAIAQ_INPUT struct input_dev *input_dev; + char phys[64]; /* physical device path */ + unsigned short keycode[64]; #endif - + /* ALSA */ struct snd_pcm *pcm; struct snd_pcm_hardware pcm_info; @@ -112,6 +119,9 @@ struct snd_usb_caiaq_cb_info { 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, + unsigned char command, + const unsigned char *buffer, + int len); #endif /* CAIAQ_DEVICE_H */ diff --git a/sound/usb/caiaq/caiaq-input.c b/sound/usb/caiaq/caiaq-input.c index cd536ca..f743847 100644 --- a/sound/usb/caiaq/caiaq-input.c +++ b/sound/usb/caiaq/caiaq-input.c @@ -21,28 +21,61 @@ #include <linux/moduleparam.h> #include <linux/input.h> #include <linux/usb.h> +#include <linux/usb/input.h> #include <linux/spinlock.h> -#include <sound/driver.h> #include <sound/core.h> #include <sound/rawmidi.h> #include <sound/pcm.h> #include "caiaq-device.h" #include "caiaq-input.h" -#ifdef CONFIG_SND_USB_CAIAQ_INPUT - -static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; -static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, - KEY_5, KEY_6, KEY_7 }; -static unsigned char keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, - KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; - -#define DEG90 (range/2) -#define DEG180 (range) -#define DEG270 (DEG90 + DEG180) -#define DEG360 (DEG180 * 2) -#define HIGH_PEAK (268) -#define LOW_PEAK (-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 }; + +static unsigned short keycode_kore[] = { + KEY_FN_F1, /* "menu" */ + KEY_FN_F7, /* "lcd backlight */ + KEY_FN_F2, /* "control" */ + KEY_FN_F3, /* "enter" */ + KEY_FN_F4, /* "view" */ + KEY_FN_F5, /* "esc" */ + KEY_FN_F6, /* "sound" */ + KEY_FN_F8, /* array spacer, never triggered. */ + KEY_RIGHT, + KEY_DOWN, + KEY_UP, + KEY_LEFT, + KEY_SOUND, /* "listen" */ + KEY_RECORD, + KEY_PLAYPAUSE, + KEY_STOP, + BTN_4, /* 8 softkeys */ + BTN_3, + BTN_2, + BTN_1, + BTN_8, + BTN_7, + BTN_6, + BTN_5, + KEY_BRL_DOT4, /* touch sensitive knobs */ + KEY_BRL_DOT3, + KEY_BRL_DOT2, + KEY_BRL_DOT1, + KEY_BRL_DOT8, + KEY_BRL_DOT7, + KEY_BRL_DOT6, + KEY_BRL_DOT5 +}; + +#define DEG90 (range / 2) +#define DEG180 (range) +#define DEG270 (DEG90 + DEG180) +#define DEG360 (DEG180 * 2) +#define HIGH_PEAK (268) +#define LOW_PEAK (-7) /* some of these devices have endless rotation potentiometers * built in which use two tapers, 90 degrees phase shifted. @@ -56,8 +89,8 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) int range = HIGH_PEAK - LOW_PEAK; int mid_value = (HIGH_PEAK + LOW_PEAK) / 2; - weight_b = abs(mid_value-a) - (range/2 - 100)/2; - + weight_b = abs(mid_value - a) - (range / 2 - 100) / 2; + if (weight_b < 0) weight_b = 0; @@ -93,7 +126,7 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) if (ret < 0) ret += 1000; - + if (ret >= 1000) ret -= 1000; @@ -108,76 +141,113 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) #undef LOW_PEAK -static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, const unsigned char *buf, unsigned int len) { - switch(dev->input_dev->id.product) { - case USB_PID_RIGKONTROL2: - input_report_abs(dev->input_dev, ABS_X, (buf[4] << 8) |buf[5]); - input_report_abs(dev->input_dev, ABS_Y, (buf[0] << 8) |buf[1]); - input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); - input_sync(dev->input_dev); + struct input_dev *input_dev = dev->input_dev; + + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): + input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); + input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); + input_sync(input_dev); break; - case USB_PID_RIGKONTROL3: - input_report_abs(dev->input_dev, ABS_X, (buf[0] << 8) |buf[1]); - input_report_abs(dev->input_dev, ABS_Y, (buf[2] << 8) |buf[3]); - input_report_abs(dev->input_dev, ABS_Z, (buf[4] << 8) |buf[5]); - input_sync(dev->input_dev); + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); + input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); + input_sync(input_dev); + break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); + input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); + input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); + input_sync(input_dev); break; } } -static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, +static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, const char *buf, unsigned int len) { + struct input_dev *input_dev = dev->input_dev; int i; - switch(dev->input_dev->id.product) { - case USB_PID_AK1: + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): i = decode_erp(buf[0], buf[1]); - input_report_abs(dev->input_dev, ABS_X, i); - input_sync(dev->input_dev); + input_report_abs(input_dev, ABS_X, i); + input_sync(input_dev); + break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + i = decode_erp(buf[7], buf[5]); + input_report_abs(input_dev, ABS_HAT0X, i); + i = decode_erp(buf[12], buf[14]); + input_report_abs(input_dev, ABS_HAT0Y, i); + i = decode_erp(buf[15], buf[13]); + input_report_abs(input_dev, ABS_HAT1X, i); + i = decode_erp(buf[0], buf[2]); + input_report_abs(input_dev, ABS_HAT1Y, i); + i = decode_erp(buf[3], buf[1]); + input_report_abs(input_dev, ABS_HAT2X, i); + i = decode_erp(buf[8], buf[10]); + input_report_abs(input_dev, ABS_HAT2Y, i); + i = decode_erp(buf[11], buf[9]); + input_report_abs(input_dev, ABS_HAT3X, i); + i = decode_erp(buf[4], buf[6]); + input_report_abs(input_dev, ABS_HAT3Y, i); + 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 *dev, char *buf, unsigned int len) { + struct input_dev *input_dev = dev->input_dev; + unsigned short *keycode = input_dev->keycode; int i; - unsigned char *keycode = dev->input_dev->keycode; if (!keycode) return; - if (dev->input_dev->id.product == USB_PID_RIGKONTROL2) - for (i=0; i<len; i++) + if (input_dev->id.product == USB_PID_RIGKONTROL2) + for (i = 0; i < len; i++) buf[i] = ~buf[i]; - for (i=0; (i<dev->input_dev->keycodemax) && (i < len); i++) - input_report_key(dev->input_dev, keycode[i], - buf[i/8] & (1 << (i%8))); + for (i = 0; i < input_dev->keycodemax && i < len * 8; i++) + input_report_key(input_dev, keycode[i], + buf[i / 8] & (1 << (i % 8))); - input_sync(dev->input_dev); + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || + dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2)) + input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); + + input_sync(input_dev); } -void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, - char *buf, +void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, + char *buf, unsigned int len) { - if (!dev->input_dev || (len < 1)) + if (!dev->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(dev, 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(dev, 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(dev, buf + 1, len - 1); break; } } @@ -192,37 +262,34 @@ 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)); + input->name = dev->product_name; - input->id.bustype = BUS_USB; - input->id.vendor = usb_dev->descriptor.idVendor; - input->id.product = usb_dev->descriptor.idProduct; - input->id.version = usb_dev->descriptor.bcdDevice; + input->phys = dev->phys; + usb_to_input_id(usb_dev, &input->id); + input->dev.parent = &usb_dev->dev; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | BIT_MASK(ABS_Z); - input->keycode = keycode_rk2; - input->keycodesize = sizeof(char); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2)); + memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2)); input->keycodemax = ARRAY_SIZE(keycode_rk2); - for (i=0; i<ARRAY_SIZE(keycode_rk2); i++) - set_bit(keycode_rk2[i], input->keybit); - 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); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); - input->keycode = keycode_rk3; - input->keycodesize = sizeof(char); + 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)); input->keycodemax = ARRAY_SIZE(keycode_rk3); - for (i=0; i<ARRAY_SIZE(keycode_rk3); i++) - set_bit(keycode_rk3[i], input->keybit); - 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); @@ -231,21 +298,50 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) 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); - input->keycode = keycode_ak1; - input->keycodesize = sizeof(char); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1)); + memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1)); input->keycodemax = ARRAY_SIZE(keycode_ak1); - for (i=0; i<ARRAY_SIZE(keycode_ak1); i++) - set_bit(keycode_ak1[i], input->keybit); - input_set_abs_params(input, ABS_X, 0, 999, 0, 10); snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | + BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | + BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | + BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | + BIT_MASK(ABS_Z); + input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); + BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore)); + memcpy(dev->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); + 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_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); + input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); + break; default: /* no input methods supported on this device */ input_free_device(input); return 0; } + input->keycode = dev->keycode; + input->keycodesize = sizeof(unsigned short); + for (i = 0; i < input->keycodemax; i++) + __set_bit(dev->keycode[i], input->keybit); + ret = input_register_device(input); if (ret < 0) { input_free_device(input); @@ -265,5 +361,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) dev->input_dev = NULL; } -#endif /* CONFIG_SND_USB_CAIAQ_INPUT */ - diff --git a/sound/usb/caiaq/caiaq-midi.c b/sound/usb/caiaq/caiaq-midi.c index 793ca20..30b57f9 100644 --- a/sound/usb/caiaq/caiaq-midi.c +++ b/sound/usb/caiaq/caiaq-midi.c @@ -23,7 +23,6 @@ #include <linux/usb.h> #include <linux/input.h> #include <linux/spinlock.h> -#include <sound/driver.h> #include <sound/core.h> #include <sound/rawmidi.h> #include <sound/pcm.h> @@ -124,7 +123,7 @@ void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, snd_rawmidi_receive(dev->midi_receive_substream, buf, len); } -int __devinit snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) +int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) { int ret; struct snd_rawmidi *rmidi; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 967b823..8fa9356 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -38,7 +38,6 @@ */ -#include <sound/driver.h> #include <linux/bitops.h> #include <linux/init.h> #include <linux/list.h> @@ -2078,6 +2077,14 @@ static int usb_audio_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_audio_disconnect(struct usb_interface *intf); +#ifdef CONFIG_PM +static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message); +static int usb_audio_resume(struct usb_interface *intf); +#else +#define usb_audio_suspend NULL +#define usb_audio_resume NULL +#endif + static struct usb_device_id usb_audio_ids [] = { #include "usbquirks.h" { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), @@ -2092,6 +2099,8 @@ static struct usb_driver usb_audio_driver = { .name = "snd-usb-audio", .probe = usb_audio_probe, .disconnect = usb_audio_disconnect, + .suspend = usb_audio_suspend, + .resume = usb_audio_resume, .id_table = usb_audio_ids, }; @@ -3654,6 +3663,45 @@ static void usb_audio_disconnect(struct usb_interface *intf) dev_get_drvdata(&intf->dev)); } +#ifdef CONFIG_PM +static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev); + struct list_head *p; + struct snd_usb_stream *as; + + if (chip == (void *)-1L) + return 0; + + snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + if (!chip->num_suspended_intf++) { + list_for_each(p, &chip->pcm_list) { + as = list_entry(p, struct snd_usb_stream, list); + snd_pcm_suspend_all(as->pcm); + } + } + + return 0; +} + +static int usb_audio_resume(struct usb_interface *intf) +{ + struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev); + + if (chip == (void *)-1L) + return 0; + if (--chip->num_suspended_intf) + return 0; + /* + * ALSA leaves material resumption to user space + * we just notify + */ + + snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + + return 0; +} +#endif /* CONFIG_PM */ static int __init snd_usb_audio_init(void) { diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 2272f45..7cf18c3 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -126,6 +126,7 @@ struct snd_usb_audio { u32 usb_id; int shutdown; int num_interfaces; + int num_suspended_intf; struct list_head pcm_list; /* list of pcm streams */ int pcm_devs; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 6330788..750e929 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -35,7 +35,6 @@ * SUCH DAMAGE. */ -#include <sound/driver.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/bitops.h> diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5e32969..89c63d0 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -26,7 +26,6 @@ * */ -#include <sound/driver.h> #include <linux/bitops.h> #include <linux/init.h> #include <linux/list.h> @@ -1703,6 +1702,11 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, case 19: /* speaker out jacks */ case 20: /* headphones out jack */ break; + /* live24ext: 4 = line-in jack */ + case 3: /* hp-out jack (may actuate Mute) */ + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) + snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); + break; default: snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); break; @@ -1951,6 +1955,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) int i, err; for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { + if (i > 1 && /* Live24ext has 2 LEDs only */ + mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) + break; err = snd_ctl_add(mixer->chip->card, snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); if (err < 0) @@ -1963,28 +1970,42 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - static const struct { + static const struct sb_jack { int unitid; const char *name; - } jacks[] = { + } jacks_audigy2nx[] = { {4, "dig in "}, {7, "line in"}, {19, "spk out"}, {20, "hph out"}, + {-1, NULL} + }, jacks_live24ext[] = { + {4, "line in"}, /* &1=Line, &2=Mic*/ + {3, "hph out"}, /* headphones */ + {0, "RC "}, /* last command, 6 bytes see rc_config above */ + {-1, NULL} }; + const struct sb_jack *jacks; struct usb_mixer_interface *mixer = entry->private_data; int i, err; u8 buf[3]; snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); - for (i = 0; i < ARRAY_SIZE(jacks); ++i) { + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) + jacks = jacks_audigy2nx; + else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) + jacks = jacks_live24ext; + else + return; + + for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3, 100); - if (err == 3 && buf[0] == 3) + if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else snd_iprintf(buffer, "?\n"); @@ -2022,7 +2043,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) goto _error; - if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || + mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) { struct snd_info_entry *entry; if ((err = snd_audigy2nx_controls_create(mixer)) < 0) diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 7c4dcb3..d755be0 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -187,6 +187,13 @@ static struct usbmix_selector_map audigy2nx_selectors[] = { { 0 } /* terminator */ }; +/* Creative SoundBlaster Live! 24-bit External */ +static struct usbmix_name_map live24ext_map[] = { + /* 2: PCM Playback Volume */ + { 5, "Mic Capture" }, /* FU, default PCM Capture Volume */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -273,6 +280,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = audigy2nx_map, .selector_map = audigy2nx_selectors, }, + { + .id = USB_ID(0x041e, 0x3040), + .map = live24ext_map, + }, { /* Hercules DJ Console (Windows Edition) */ .id = USB_ID(0x06f8, 0xb000), diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 59410f4..938dff5 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1004,11 +1004,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0049 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0047), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + /* in the 96 kHz modes, only interface 1 is there */ + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ /* has ID 0x004a when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0048), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "EDIROL", - .product_name = "UR-80", + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index b76b3dd..6495534e 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -20,7 +20,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <sound/driver.h> #include <linux/interrupt.h> #include <linux/usb.h> #include <sound/core.h> @@ -34,34 +33,31 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card); -static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) +static int snd_us428ctls_vm_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { unsigned long offset; struct page * page; void *vaddr; - snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n", + snd_printdd("ENTER, start %lXh, pgoff %ld\n", area->vm_start, - address - area->vm_start, - (address - area->vm_start) >> PAGE_SHIFT, - address); + vmf->pgoff); - offset = area->vm_pgoff << PAGE_SHIFT; - offset += address - area->vm_start; - snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); + offset = vmf->pgoff << PAGE_SHIFT; vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset; page = virt_to_page(vaddr); get_page(page); - snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset); + vmf->page = page; - if (type) - *type = VM_FAULT_MINOR; + snd_printdd("vaddr=%p made us428ctls_vm_fault() page %p\n", + vaddr, page); - return page; + return 0; } static struct vm_operations_struct us428ctls_vm_ops = { - .nopage = snd_us428ctls_vm_nopage, + .fault = snd_us428ctls_vm_fault, }; static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index e011fca..e5981a6 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -130,7 +130,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <sound/driver.h> #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 48e9aa3..9a608fa 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -31,7 +31,6 @@ */ -#include <sound/driver.h> #include <linux/interrupt.h> #include <linux/usb.h> #include <sound/core.h> diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index a5e7bcd..800b5ce 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -683,30 +683,24 @@ static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area) } -static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) +static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { unsigned long offset; - struct page *page; void *vaddr; - offset = area->vm_pgoff << PAGE_SHIFT; - offset += address - area->vm_start; - snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); + offset = vmf->pgoff << PAGE_SHIFT; vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset; - page = virt_to_page(vaddr); - get_page(page); - - if (type) - *type = VM_FAULT_MINOR; - - return page; + vmf->page = virt_to_page(vaddr); + get_page(vmf->page); + return 0; } static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { .open = snd_usX2Y_hwdep_pcm_vm_open, .close = snd_usX2Y_hwdep_pcm_vm_close, - .nopage = snd_usX2Y_hwdep_pcm_vm_nopage, + .fault = snd_usX2Y_hwdep_pcm_vm_fault, }; |