diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 54045b745d11..2d2d122b069f 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -25,4 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ -obj-$(CONFIG_LINE6_USB) += line6/ +obj-$(CONFIG_SND_USB_LINE6) += line6/ diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig index 4f1219b4c692..af20947e0bda 100644 --- a/sound/usb/line6/Kconfig +++ b/sound/usb/line6/Kconfig @@ -1,12 +1,14 @@ -menuconfig LINE6_USB - tristate "Line6 USB support" - depends on USB && SND +config SND_USB_LINE6 + tristate select SND_RAWMIDI select SND_PCM + +config SND_USB_POD + tristate "Line 6 POD USB support" + select SND_USB_LINE6 help - This is a driver for the guitar amp, cab, and effects modeller - PODxt Pro by Line6 (and similar devices), supporting the - following features: + This is a driver for PODxt and other similar devices, + supporting the following features: * Reading/writing individual parameters * Reading/writing complete channel, effects setup, and amp setup data @@ -18,21 +20,21 @@ menuconfig LINE6_USB * Signal routing (record clean/processed guitar signal, re-amping) - Preliminary support for the Variax Workbench and TonePort - devices is included. - -if LINE6_USB - -config LINE6_USB_IMPULSE_RESPONSE - bool "measure impulse response" - default n +config SND_USB_PODHD + tristate "Line 6 POD HD300/400/500 USB support" + select SND_USB_LINE6 help - Say Y here to add code to measure the impulse response of a Line6 - device. This is more accurate than user-space methods since it - bypasses any PCM data buffering (e.g., by ALSA or jack). This is - useful for assessing the performance of new devices, but is not - required for normal operation. + This is a driver for POD HD300, 400 and 500 devices. - If unsure, say N. +config SND_USB_TONEPORT + tristate "TonePort GX, UX1 and UX2 USB support" + select SND_USB_LINE6 + help + This is a driver for TonePort GX, UX1 and UX2 devices. + +config SND_USB_VARIAX + tristate "Variax Workbench USB support" + select SND_USB_LINE6 + help + This is a driver for Variax Workbench device. -endif # LINE6_USB diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile index ae5c374b0f87..b8b3b2a543d8 100644 --- a/sound/usb/line6/Makefile +++ b/sound/usb/line6/Makefile @@ -1,14 +1,18 @@ -obj-$(CONFIG_LINE6_USB) += line6usb.o - -line6usb-y := \ - audio.o \ +snd-usb-line6-y := \ capture.o \ driver.o \ midi.o \ midibuf.o \ pcm.o \ - playback.o \ - pod.o \ - toneport.o \ - variax.o \ - podhd.o + playback.o + +snd-usb-pod-y := pod.o +snd-usb-podhd-y := podhd.o +snd-usb-toneport-y := toneport.o +snd-usb-variax-y := variax.o + +obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o +obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o +obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o +obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o +obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o diff --git a/sound/usb/line6/audio.c b/sound/usb/line6/audio.c deleted file mode 100644 index 171d80c1b020..000000000000 --- a/sound/usb/line6/audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * 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, version 2. - * - */ - -#include -#include -#include - -#include "driver.h" -#include "audio.h" - -/* - Initialize the Line6 USB audio system. -*/ -int line6_init_audio(struct usb_line6 *line6) -{ - struct snd_card *card; - int err; - - err = snd_card_new(line6->ifcdev, - SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); - if (err < 0) - return err; - - line6->card = card; - - strcpy(card->id, line6->properties->id); - strcpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, line6->properties->name); - /* longname is 80 chars - see asound.h */ - sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, - dev_name(line6->ifcdev)); - return 0; -} - -/* - Register the Line6 USB audio system. -*/ -int line6_register_audio(struct usb_line6 *line6) -{ - int err; - - err = snd_card_register(line6->card); - if (err < 0) - return err; - - return 0; -} - -/* - Cleanup the Line6 USB audio system. -*/ -void line6_cleanup_audio(struct usb_line6 *line6) -{ - struct snd_card *card = line6->card; - - if (card == NULL) - return; - - snd_card_disconnect(card); - snd_card_free(card); - line6->card = NULL; -} diff --git a/sound/usb/line6/audio.h b/sound/usb/line6/audio.h deleted file mode 100644 index 5f8a09a0fa95..000000000000 --- a/sound/usb/line6/audio.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * 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, version 2. - * - */ - -#ifndef AUDIO_H -#define AUDIO_H - -#include "driver.h" - -extern void line6_cleanup_audio(struct usb_line6 *); -extern int line6_init_audio(struct usb_line6 *); -extern int line6_register_audio(struct usb_line6 *); - -#endif diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index f24c7c5e0a3e..5a010ba163fa 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -14,11 +14,9 @@ #include #include -#include "audio.h" #include "capture.h" #include "driver.h" #include "pcm.h" -#include "pod.h" /* Find a free URB and submit it. @@ -245,9 +243,7 @@ static void audio_in_callback(struct urb *urb) line6pcm->prev_fbuf = fbuf; line6pcm->prev_fsize = fsize; -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags) && (fsize > 0)) line6_capture_copy(line6pcm, fbuf, fsize); @@ -263,9 +259,7 @@ static void audio_in_callback(struct urb *urb) if (!shutdown) { submit_audio_in_urb(line6pcm); -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)) line6_capture_check_period(line6pcm, length); @@ -347,9 +341,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: -#ifdef CONFIG_PM case SNDRV_PCM_TRIGGER_RESUME: -#endif err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); @@ -359,9 +351,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: -#ifdef CONFIG_PM case SNDRV_PCM_TRIGGER_SUSPEND: -#endif err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); @@ -411,10 +401,8 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) urb = line6pcm->urb_audio_in[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); + if (urb == NULL) return -ENOMEM; - } urb->dev = line6->usbdev; urb->pipe = diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 4157bcb598a9..0939f400a405 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index fc852f6ab8bc..93cd4daa56bc 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -11,277 +11,30 @@ #include #include +#include #include #include -#include "audio.h" +#include +#include + #include "capture.h" #include "driver.h" #include "midi.h" #include "playback.h" -#include "pod.h" -#include "podhd.h" #include "revision.h" -#include "toneport.h" #include "usbdefs.h" -#include "variax.h" #define DRIVER_AUTHOR "Markus Grabner " -#define DRIVER_DESC "Line6 USB Driver" -#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION - -#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) -#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) - -/* table of devices that work with this driver */ -static const struct usb_device_id line6_id_table[] = { - { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, - { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, - { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, - { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, - { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, - { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, - { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, - { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, - { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, - { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, - { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, - { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, - { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, - { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, - { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, - { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, - { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, - { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, - { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, - { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, - {} -}; - -MODULE_DEVICE_TABLE(usb, line6_id_table); - -static const struct line6_properties line6_properties_table[] = { - [LINE6_BASSPODXT] = { - .id = "BassPODxt", - .name = "BassPODxt", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_BASSPODXTLIVE] = { - .id = "BassPODxtLive", - .name = "BassPODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_BASSPODXTPRO] = { - .id = "BassPODxtPro", - .name = "BassPODxt Pro", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_GUITARPORT] = { - .id = "GuitarPort", - .name = "GuitarPort", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_POCKETPOD] = { - .id = "PocketPOD", - .name = "Pocket POD", - .capabilities = LINE6_CAP_CONTROL, - .altsetting = 0, - .ep_ctrl_r = 0x82, - .ep_ctrl_w = 0x02, - /* no audio channel */ - }, - [LINE6_PODHD300] = { - .id = "PODHD300", - .name = "POD HD300", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODHD400] = { - .id = "PODHD400", - .name = "POD HD400", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODHD500_0] = { - .id = "PODHD500", - .name = "POD HD500", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x81, - .ep_ctrl_w = 0x01, - .ep_audio_r = 0x86, - .ep_audio_w = 0x02, - }, - [LINE6_PODHD500_1] = { - .id = "PODHD500", - .name = "POD HD500", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x81, - .ep_ctrl_w = 0x01, - .ep_audio_r = 0x86, - .ep_audio_w = 0x02, - }, - [LINE6_PODSTUDIO_GX] = { - .id = "PODStudioGX", - .name = "POD Studio GX", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODSTUDIO_UX1] = { - .id = "PODStudioUX1", - .name = "POD Studio UX1", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODSTUDIO_UX2] = { - .id = "PODStudioUX2", - .name = "POD Studio UX2", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXT] = { - .id = "PODxt", - .name = "PODxt", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTLIVE_POD] = { - .id = "PODxtLive", - .name = "PODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTLIVE_VARIAX] = { - .id = "PODxtLive", - .name = "PODxt Live", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 1, - .ep_ctrl_r = 0x86, - .ep_ctrl_w = 0x05, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_PODXTPRO] = { - .id = "PODxtPro", - .name = "PODxt Pro", - .capabilities = LINE6_CAP_CONTROL - | LINE6_CAP_PCM - | LINE6_CAP_HWMON, - .altsetting = 5, - .ep_ctrl_r = 0x84, - .ep_ctrl_w = 0x03, - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_GX] = { - .id = "TonePortGX", - .name = "TonePort GX", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_UX1] = { - .id = "TonePortUX1", - .name = "TonePort UX1", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* 1..4 seem to be ok */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_TONEPORT_UX2] = { - .id = "TonePortUX2", - .name = "TonePort UX2", - .capabilities = LINE6_CAP_PCM, - .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ - /* no control channel */ - .ep_audio_r = 0x82, - .ep_audio_w = 0x01, - }, - [LINE6_VARIAX] = { - .id = "Variax", - .name = "Variax Workbench", - .capabilities = LINE6_CAP_CONTROL, - .altsetting = 1, - .ep_ctrl_r = 0x82, - .ep_ctrl_w = 0x01, - /* no audio channel */ - } -}; +#define DRIVER_DESC "Line 6 USB Driver" /* - This is Line6's MIDI manufacturer ID. + This is Line 6's MIDI manufacturer ID. */ const unsigned char line6_midi_id[] = { 0x00, 0x01, 0x0c }; +EXPORT_SYMBOL_GPL(line6_midi_id); /* Code to request version of POD, Variax interface @@ -335,8 +88,8 @@ static void line6_stop_listen(struct usb_line6 *line6) /* Send raw message in pieces of wMaxPacketSize bytes. */ -int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, - int size) +static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, + int size) { int i, done = 0; @@ -415,9 +168,9 @@ void line6_start_timer(struct timer_list *timer, unsigned int msecs, void (*function)(unsigned long), unsigned long data) { setup_timer(timer, function, data); - timer->expires = jiffies + msecs * HZ / 1000; - add_timer(timer); + mod_timer(timer, jiffies + msecs * HZ / 1000); } +EXPORT_SYMBOL_GPL(line6_start_timer); /* Asynchronously send raw message. @@ -438,7 +191,6 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, if (urb == NULL) { kfree(msg); - dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; } @@ -451,6 +203,7 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, /* start sending: */ return line6_send_raw_message_async_part(msg, urb); } +EXPORT_SYMBOL_GPL(line6_send_raw_message_async); /* Send asynchronous device version request. @@ -462,16 +215,15 @@ int line6_version_request_async(struct usb_line6 *line6) buffer = kmemdup(line6_request_version, sizeof(line6_request_version), GFP_ATOMIC); - if (buffer == NULL) { - dev_err(line6->ifcdev, "Out of memory"); + if (buffer == NULL) return -ENOMEM; - } retval = line6_send_raw_message_async(line6, buffer, sizeof(line6_request_version)); kfree(buffer); return retval; } +EXPORT_SYMBOL_GPL(line6_version_request_async); /* Send sysex message in pieces of wMaxPacketSize bytes. @@ -483,6 +235,7 @@ int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, size + SYSEX_EXTRA_SIZE) - SYSEX_EXTRA_SIZE; } +EXPORT_SYMBOL_GPL(line6_send_sysex_message); /* Allocate buffer for sysex message and prepare header. @@ -504,9 +257,10 @@ char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; return buffer; } +EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer); /* - Notification of data received from the Line6 device. + Notification of data received from the Line 6 device. */ static void line6_data_received(struct urb *urb) { @@ -544,65 +298,6 @@ static void line6_data_received(struct urb *urb) line6_start_listen(line6); } -/* - Send channel number (i.e., switch to a different sound). -*/ -int line6_send_program(struct usb_line6 *line6, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - buffer, 2, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - -/* - Transmit Line6 control parameter. -*/ -int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(3, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = param; - buffer[2] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->properties->ep_ctrl_w), - buffer, 3, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - /* Read data from device. */ @@ -659,6 +354,7 @@ int line6_read_data(struct usb_line6 *line6, int address, void *data, return 0; } +EXPORT_SYMBOL_GPL(line6_read_data); /* Write data to device. @@ -703,9 +399,10 @@ int line6_write_data(struct usb_line6 *line6, int address, void *data, return 0; } +EXPORT_SYMBOL_GPL(line6_write_data); /* - Read Line6 device serial number. + Read Line 6 device serial number. (POD, TonePort, GuitarPort) */ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) @@ -713,6 +410,7 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) return line6_read_data(line6, 0x80d0, serial_number, sizeof(*serial_number)); } +EXPORT_SYMBOL_GPL(line6_read_serial_number); /* No operation (i.e., unsupported). @@ -722,19 +420,19 @@ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, { return 0; } +EXPORT_SYMBOL_GPL(line6_nop_read); /* - Generic destructor. + Card destructor. */ -static void line6_destruct(struct usb_interface *interface) +static void line6_destruct(struct snd_card *card) { - struct usb_line6 *line6; + struct usb_line6 *line6 = card->private_data; + struct usb_device *usbdev; - if (interface == NULL) - return; - line6 = usb_get_intfdata(interface); - if (line6 == NULL) + if (!line6) return; + usbdev = line6->usbdev; /* free buffer memory first: */ kfree(line6->buffer_message); @@ -743,44 +441,34 @@ static void line6_destruct(struct usb_interface *interface) /* then free URBs: */ usb_free_urb(line6->urb_listen); - /* make sure the device isn't destructed twice: */ - usb_set_intfdata(interface, NULL); - /* free interface data: */ kfree(line6); + + /* decrement reference counters: */ + usb_put_dev(usbdev); } /* Probe USB device. */ -static int line6_probe(struct usb_interface *interface, - const struct usb_device_id *id) +int line6_probe(struct usb_interface *interface, + struct usb_line6 *line6, + const struct line6_properties *properties, + int (*private_init)(struct usb_interface *, struct usb_line6 *)) { - enum line6_device_type devtype; - struct usb_device *usbdev; - struct usb_line6 *line6; - const struct line6_properties *properties; + struct usb_device *usbdev = interface_to_usbdev(interface); + struct snd_card *card; int interface_number; - int size = 0; int ret; - if (interface == NULL) - return -ENODEV; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return -ENODEV; - /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) { ret = -ENODEV; goto err_put; } - devtype = id->driver_info; - /* initialize device info: */ - properties = &line6_properties_table[devtype]; - dev_info(&interface->dev, "Line6 %s found\n", properties->name); + dev_info(&interface->dev, "Line 6 %s found\n", properties->name); /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; @@ -792,76 +480,10 @@ static int line6_probe(struct usb_interface *interface, goto err_put; } - /* initialize device data based on device: */ - switch (devtype) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_PODXT: - case LINE6_PODXTPRO: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - size = sizeof(struct usb_line6_podhd); - break; - - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - size = sizeof(struct usb_line6_podhd); - break; - - case LINE6_POCKETPOD: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - size = sizeof(struct usb_line6_toneport); - break; - - case LINE6_PODXTLIVE_POD: - size = sizeof(struct usb_line6_pod); - break; - - case LINE6_PODXTLIVE_VARIAX: - size = sizeof(struct usb_line6_variax); - break; - - case LINE6_VARIAX: - size = sizeof(struct usb_line6_variax); - break; - - default: - MISSING_CASE; - ret = -ENODEV; - goto err_put; - } - - if (size == 0) { - dev_err(&interface->dev, - "driver bug: interface data size not set\n"); - ret = -ENODEV; - goto err_put; - } - - line6 = kzalloc(size, GFP_KERNEL); - if (line6 == NULL) { - ret = -ENODEV; - goto err_put; - } - /* store basic data: */ line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; - line6->type = devtype; /* get data from endpoint descriptor (see usb_maxpacket): */ { @@ -882,8 +504,26 @@ static int line6_probe(struct usb_interface *interface, } } + ret = snd_card_new(line6->ifcdev, + SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (ret < 0) + goto err_put; + + line6->card = card; + strcpy(card->id, line6->properties->id); + strcpy(card->driver, DRIVER_NAME); + strcpy(card->shortname, line6->properties->name); + sprintf(card->longname, "Line 6 %s at USB %s", line6->properties->name, + dev_name(line6->ifcdev)); + card->private_data = line6; + card->private_free = line6_destruct; + usb_set_intfdata(interface, line6); + /* increment reference counters: */ + usb_get_dev(usbdev); + if (properties->capabilities & LINE6_CAP_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = @@ -903,8 +543,6 @@ static int line6_probe(struct usb_interface *interface, line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); if (line6->urb_listen == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - line6_destruct(interface); ret = -ENOMEM; goto err_destruct; } @@ -918,79 +556,28 @@ static int line6_probe(struct usb_interface *interface, } /* initialize device data based on device: */ - switch (devtype) { - case LINE6_BASSPODXT: - case LINE6_BASSPODXTLIVE: - case LINE6_BASSPODXTPRO: - case LINE6_POCKETPOD: - case LINE6_PODXT: - case LINE6_PODXTPRO: - ret = line6_pod_init(interface, line6); - break; - - case LINE6_PODHD300: - case LINE6_PODHD400: - case LINE6_PODHD500_0: - case LINE6_PODHD500_1: - ret = line6_podhd_init(interface, line6); - break; - - case LINE6_PODXTLIVE_POD: - ret = line6_pod_init(interface, line6); - break; - - case LINE6_PODXTLIVE_VARIAX: - ret = line6_variax_init(interface, line6); - break; - - case LINE6_VARIAX: - ret = line6_variax_init(interface, line6); - break; - - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - ret = line6_toneport_init(interface, line6); - break; - - default: - MISSING_CASE; - ret = -ENODEV; - } - - if (ret < 0) - goto err_destruct; - - ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, - "usb_device"); + ret = private_init(interface, line6); if (ret < 0) goto err_destruct; /* creation of additional special files should go here */ - dev_info(&interface->dev, "Line6 %s now attached\n", + dev_info(&interface->dev, "Line 6 %s now attached\n", line6->properties->name); - /* increment reference counters: */ - usb_get_intf(interface); - usb_get_dev(usbdev); - return 0; -err_destruct: - line6_destruct(interface); -err_put: + err_destruct: + snd_card_free(card); + err_put: return ret; } +EXPORT_SYMBOL_GPL(line6_probe); /* - Line6 device disconnected. + Line 6 device disconnected. */ -static void line6_disconnect(struct usb_interface *interface) +void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; @@ -1002,40 +589,39 @@ static void line6_disconnect(struct usb_interface *interface) if (usbdev == NULL) return; - /* removal of additional special files should go here */ - - sysfs_remove_link(&interface->dev.kobj, "usb_device"); - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); + if (!line6) + return; - if (line6 != NULL) { - if (line6->urb_listen != NULL) - line6_stop_listen(line6); + if (line6->urb_listen != NULL) + line6_stop_listen(line6); - if (usbdev != line6->usbdev) - dev_err(line6->ifcdev, - "driver bug: inconsistent usb device\n"); + if (usbdev != line6->usbdev) + dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); + snd_card_disconnect(line6->card); + if (line6->line6pcm) + line6_pcm_disconnect(line6->line6pcm); + if (line6->disconnect) line6->disconnect(interface); - dev_info(&interface->dev, "Line6 %s now disconnected\n", - line6->properties->name); - } + dev_info(&interface->dev, "Line 6 %s now disconnected\n", + line6->properties->name); - line6_destruct(interface); + /* make sure the device isn't destructed twice: */ + usb_set_intfdata(interface, NULL); - /* decrement reference counters: */ - usb_put_intf(interface); - usb_put_dev(usbdev); + snd_card_free_when_closed(line6->card); } +EXPORT_SYMBOL_GPL(line6_disconnect); #ifdef CONFIG_PM /* - Suspend Line6 device. + Suspend Line 6 device. */ -static int line6_suspend(struct usb_interface *interface, pm_message_t message) +int line6_suspend(struct usb_interface *interface, pm_message_t message) { struct usb_line6 *line6 = usb_get_intfdata(interface); struct snd_line6_pcm *line6pcm = line6->line6pcm; @@ -1047,17 +633,17 @@ static int line6_suspend(struct usb_interface *interface, pm_message_t message) if (line6pcm != NULL) { snd_pcm_suspend_all(line6pcm->pcm); - line6_pcm_disconnect(line6pcm); line6pcm->flags = 0; } return 0; } +EXPORT_SYMBOL_GPL(line6_suspend); /* - Resume Line6 device. + Resume Line 6 device. */ -static int line6_resume(struct usb_interface *interface) +int line6_resume(struct usb_interface *interface) { struct usb_line6 *line6 = usb_get_intfdata(interface); @@ -1067,48 +653,10 @@ static int line6_resume(struct usb_interface *interface) snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); return 0; } - -/* - Resume Line6 device after reset. -*/ -static int line6_reset_resume(struct usb_interface *interface) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - - switch (line6->type) { - case LINE6_PODSTUDIO_GX: - case LINE6_PODSTUDIO_UX1: - case LINE6_PODSTUDIO_UX2: - case LINE6_TONEPORT_GX: - case LINE6_TONEPORT_UX1: - case LINE6_TONEPORT_UX2: - case LINE6_GUITARPORT: - line6_toneport_reset_resume((struct usb_line6_toneport *)line6); - - default: - break; - } - - return line6_resume(interface); -} +EXPORT_SYMBOL_GPL(line6_resume); #endif /* CONFIG_PM */ -static struct usb_driver line6_driver = { - .name = DRIVER_NAME, - .probe = line6_probe, - .disconnect = line6_disconnect, -#ifdef CONFIG_PM - .suspend = line6_suspend, - .resume = line6_resume, - .reset_resume = line6_reset_resume, -#endif - .id_table = line6_id_table, -}; - -module_usb_driver(line6_driver); - MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index ad203f197e80..efd58ac3215b 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -20,35 +20,12 @@ #define DRIVER_NAME "line6usb" -enum line6_device_type { - LINE6_BASSPODXT, - LINE6_BASSPODXTLIVE, - LINE6_BASSPODXTPRO, - LINE6_GUITARPORT, - LINE6_POCKETPOD, - LINE6_PODHD300, - LINE6_PODHD400, - LINE6_PODHD500_0, - LINE6_PODHD500_1, - LINE6_PODSTUDIO_GX, - LINE6_PODSTUDIO_UX1, - LINE6_PODSTUDIO_UX2, - LINE6_PODXT, - LINE6_PODXTLIVE_POD, - LINE6_PODXTLIVE_VARIAX, - LINE6_PODXTPRO, - LINE6_TONEPORT_GX, - LINE6_TONEPORT_UX1, - LINE6_TONEPORT_UX2, - LINE6_VARIAX -}; - #define LINE6_TIMEOUT 1 #define LINE6_BUFSIZE_LISTEN 32 #define LINE6_MESSAGE_MAXLEN 256 /* - Line6 MIDI control commands + Line 6 MIDI control commands */ #define LINE6_PARAM_CHANGE 0xb0 #define LINE6_PROGRAM_CHANGE 0xc0 @@ -71,17 +48,6 @@ enum line6_device_type { #define LINE6_CHANNEL_MASK 0x0f -#define MISSING_CASE \ - pr_err("line6usb driver bug: missing case in %s:%d\n", \ - __FILE__, __LINE__) - -#define CHECK_RETURN(x) \ -do { \ - err = x; \ - if (err < 0) \ - return err; \ -} while (0) - #define CHECK_STARTUP_PROGRESS(x, n) \ do { \ if ((x) >= (n)) \ @@ -95,7 +61,7 @@ static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; /** - Common properties of Line6 devices. + Common properties of Line 6 devices. */ struct line6_properties { /** @@ -125,7 +91,7 @@ struct line6_properties { }; /** - Common data shared by all Line6 devices. + Common data shared by all Line 6 devices. Corresponds to a pair of USB endpoints. */ struct usb_line6 { @@ -134,11 +100,6 @@ struct usb_line6 { */ struct usb_device *usbdev; - /** - Device type. - */ - enum line6_device_type type; - /** Properties. */ @@ -160,18 +121,18 @@ struct usb_line6 { struct device *ifcdev; /** - Line6 sound card data structure. + Line 6 sound card data structure. Each device has at least MIDI or PCM. */ struct snd_card *card; /** - Line6 PCM device data structure. + Line 6 PCM device data structure. */ struct snd_line6_pcm *line6pcm; /** - Line6 MIDI device data structure. + Line 6 MIDI device data structure. */ struct snd_line6_midi *line6midi; @@ -207,9 +168,6 @@ extern int line6_read_data(struct usb_line6 *line6, int address, void *data, size_t datalen); extern int line6_read_serial_number(struct usb_line6 *line6, int *serial_number); -extern int line6_send_program(struct usb_line6 *line6, u8 value); -extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, - int size); extern int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, int size); extern int line6_send_sysex_message(struct usb_line6 *line6, @@ -219,10 +177,19 @@ extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, void (*function)(unsigned long), unsigned long data); -extern int line6_transmit_parameter(struct usb_line6 *line6, int param, - u8 value); extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_write_data(struct usb_line6 *line6, int address, void *data, size_t datalen); +int line6_probe(struct usb_interface *interface, + struct usb_line6 *line6, + const struct line6_properties *properties, + int (*private_init)(struct usb_interface *, struct usb_line6 *)); +void line6_disconnect(struct usb_interface *interface); + +#ifdef CONFIG_PM +int line6_suspend(struct usb_interface *interface, pm_message_t message); +int line6_resume(struct usb_interface *interface); +#endif + #endif diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index c9d725ae85a0..b5a58a7fe11a 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -11,13 +11,12 @@ #include #include +#include #include #include -#include "audio.h" #include "driver.h" #include "midi.h" -#include "pod.h" #include "usbdefs.h" #define line6_rawmidi_substream_midi(substream) \ @@ -121,16 +120,13 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, urb = usb_alloc_urb(0, GFP_ATOMIC); - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); + if (urb == NULL) return -ENOMEM; - } transfer_buffer = kmemdup(data, length, GFP_ATOMIC); if (transfer_buffer == NULL) { usb_free_urb(urb); - dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; } @@ -223,28 +219,20 @@ static struct snd_rawmidi_ops line6_midi_input_ops = { .trigger = line6_midi_input_trigger, }; -/* - Cleanup the Line6 MIDI device. -*/ -static void line6_cleanup_midi(struct snd_rawmidi *rmidi) -{ -} - /* Create a MIDI device */ -static int snd_line6_new_midi(struct snd_line6_midi *line6midi) +static int snd_line6_new_midi(struct usb_line6 *line6, + struct snd_rawmidi **rmidi_ret) { struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, - &rmidi); + err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret); if (err < 0) return err; - rmidi->private_data = line6midi; - rmidi->private_free = line6_cleanup_midi; - strcpy(rmidi->id, line6midi->line6->properties->id); - strcpy(rmidi->name, line6midi->line6->properties->name); + rmidi = *rmidi_ret; + strcpy(rmidi->id, line6->properties->id); + strcpy(rmidi->name, line6->properties->name); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | @@ -258,25 +246,22 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi) } /* MIDI device destructor */ -static int snd_line6_midi_free(struct snd_device *device) +static void snd_line6_midi_free(struct snd_rawmidi *rmidi) { - struct snd_line6_midi *line6midi = device->device_data; + struct snd_line6_midi *line6midi = rmidi->private_data; line6_midibuf_destroy(&line6midi->midibuf_in); line6_midibuf_destroy(&line6midi->midibuf_out); - return 0; + kfree(line6midi); } /* - Initialize the Line6 MIDI subsystem. + Initialize the Line 6 MIDI subsystem. */ int line6_init_midi(struct usb_line6 *line6) { - static struct snd_device_ops midi_ops = { - .dev_free = snd_line6_midi_free, - }; - int err; + struct snd_rawmidi *rmidi; struct snd_line6_midi *line6midi; if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { @@ -284,38 +269,31 @@ int line6_init_midi(struct usb_line6 *line6) return 0; } - line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); + err = snd_line6_new_midi(line6, &rmidi); + if (err < 0) + return err; - if (line6midi == NULL) + line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); + if (!line6midi) return -ENOMEM; - err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); - if (err < 0) { - kfree(line6midi); - return err; - } - - err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); - if (err < 0) { - kfree(line6midi->midibuf_in.buf); - kfree(line6midi); - return err; - } - - line6midi->line6 = line6; - line6->line6midi = line6midi; - - err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, - &midi_ops); - if (err < 0) - return err; - - err = snd_line6_new_midi(line6midi); - if (err < 0) - return err; + rmidi->private_data = line6midi; + rmidi->private_free = snd_line6_midi_free; init_waitqueue_head(&line6midi->send_wait); spin_lock_init(&line6midi->send_urb_lock); spin_lock_init(&line6midi->midi_transmit_lock); + line6midi->line6 = line6; + + err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); + if (err < 0) + return err; + + err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); + if (err < 0) + return err; + + line6->line6midi = line6midi; return 0; } +EXPORT_SYMBOL_GPL(line6_init_midi); diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h index 78f903fb4d41..ba6bf3828aa5 100644 --- a/sound/usb/line6/midi.h +++ b/sound/usb/line6/midi.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -20,7 +20,7 @@ struct snd_line6_midi { /** - Pointer back to the Line6 driver data structure. + Pointer back to the Line 6 driver data structure. */ struct usb_line6 *line6; diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c index 1ff856989fd6..b5c4d79de031 100644 --- a/sound/usb/line6/midibuf.c +++ b/sound/usb/line6/midibuf.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -26,7 +26,7 @@ static int midibuf_message_length(unsigned char code) } else { /* Note that according to the MIDI specification 0xf2 is - the "Song Position Pointer", but this is used by Line6 + the "Song Position Pointer", but this is used by Line 6 to send sysex messages to the host. */ static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h index 707482b940e4..05dbf11a4d63 100644 --- a/sound/usb/line6/midibuf.h +++ b/sound/usb/line6/midibuf.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 6d4e5cd0482c..8a6059adef69 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -10,91 +10,85 @@ */ #include +#include #include #include #include #include -#include "audio.h" #include "capture.h" #include "driver.h" #include "playback.h" -#include "pod.h" -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - -static struct snd_line6_pcm *dev2pcm(struct device *dev) +/* impulse response volume controls */ +static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6 *line6 = usb_get_intfdata(interface); - struct snd_line6_pcm *line6pcm = line6->line6pcm; - return line6pcm; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + return 0; } -/* - "read" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = line6pcm->impulse_volume; + return 0; } -/* - "write" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_line6_pcm *line6pcm = dev2pcm(dev); - int value; - int ret; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int value = ucontrol->value.integer.value[0]; - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; + if (line6pcm->impulse_volume == value) + return 0; line6pcm->impulse_volume = value; - if (value > 0) line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); else line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); - - return count; + return 1; } -static DEVICE_ATTR_RW(impulse_volume); -/* - "read" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_show(struct device *dev, - struct device_attribute *attr, char *buf) +/* impulse response period controls */ +static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 2000; + return 0; } -/* - "write" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int value; - int ret; + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; - - dev2pcm(dev)->impulse_period = value; - return count; + ucontrol->value.integer.value[0] = line6pcm->impulse_period; + return 0; } -static DEVICE_ATTR_RW(impulse_period); -#endif +static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int value = ucontrol->value.integer.value[0]; + + if (line6pcm->impulse_period == value) + return 0; + + line6pcm->impulse_period = value; + return 1; +} static bool test_flags(unsigned long flags0, unsigned long flags1, unsigned long mask) @@ -195,6 +189,7 @@ pcm_acquire_error: line6_pcm_release(line6pcm, flags_final & channels); return err; } +EXPORT_SYMBOL_GPL(line6_pcm_acquire); int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) { @@ -223,6 +218,7 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) return 0; } +EXPORT_SYMBOL_GPL(line6_pcm_release); /* trigger callback */ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) @@ -230,19 +226,19 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; int err; - unsigned long flags; - spin_lock_irqsave(&line6pcm->lock_trigger, flags); + spin_lock(&line6pcm->lock_trigger); clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; switch (s->stream) { case SNDRV_PCM_STREAM_PLAYBACK: err = snd_line6_playback_trigger(line6pcm, cmd); if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); + spin_unlock(&line6pcm->lock_trigger); return err; } @@ -252,8 +248,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) err = snd_line6_capture_trigger(line6pcm, cmd); if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); + spin_unlock(&line6pcm->lock_trigger); return err; } @@ -265,7 +260,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) } } - spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); + spin_unlock(&line6pcm->lock_trigger); return 0; } @@ -312,14 +307,28 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, } /* control definition */ -static struct snd_kcontrol_new line6_control_playback = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_line6_control_playback_info, - .get = snd_line6_control_playback_get, - .put = snd_line6_control_playback_put +static struct snd_kcontrol_new line6_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = snd_line6_control_playback_info, + .get = snd_line6_control_playback_get, + .put = snd_line6_control_playback_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Impulse Response Volume", + .info = snd_line6_impulse_volume_info, + .get = snd_line6_impulse_volume_get, + .put = snd_line6_impulse_volume_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Impulse Response Period", + .info = snd_line6_impulse_period_info, + .get = snd_line6_impulse_period_get, + .put = snd_line6_impulse_period_put + }, }; /* @@ -330,11 +339,6 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm) int i; struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); -#endif - for (i = LINE6_ISO_BUFFERS; i--;) { if (line6pcm->urb_audio_out[i]) { usb_kill_urb(line6pcm->urb_audio_out[i]); @@ -345,24 +349,21 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm) usb_free_urb(line6pcm->urb_audio_in[i]); } } + kfree(line6pcm); } /* create a PCM device */ -static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) +static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) { struct snd_pcm *pcm; int err; - err = snd_pcm_new(line6pcm->line6->card, - (char *)line6pcm->line6->properties->name, - 0, 1, 1, &pcm); + err = snd_pcm_new(line6->card, (char *)line6->properties->name, + 0, 1, 1, pcm_ret); if (err < 0) return err; - - pcm->private_data = line6pcm; - pcm->private_free = line6_cleanup_pcm; - line6pcm->pcm = pcm; - strcpy(pcm->name, line6pcm->line6->properties->name); + pcm = *pcm_ret; + strcpy(pcm->name, line6->properties->name); /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -374,37 +375,14 @@ static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) snd_dma_continuous_data (GFP_KERNEL), 64 * 1024, 128 * 1024); - - return 0; -} - -/* PCM device destructor */ -static int snd_line6_pcm_free(struct snd_device *device) -{ return 0; } /* - Stop substream if still running. -*/ -static void pcm_disconnect_substream(struct snd_pcm_substream *substream) -{ - if (substream->runtime && snd_pcm_running(substream)) { - snd_pcm_stream_lock_irq(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); - snd_pcm_stream_unlock_irq(substream); - } -} - -/* - Stop PCM stream. + Sync with PCM stream stops. */ void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) { - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); line6_unlink_wait_clear_audio_out_urbs(line6pcm); line6_unlink_wait_clear_audio_in_urbs(line6pcm); } @@ -416,23 +394,25 @@ void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) int line6_init_pcm(struct usb_line6 *line6, struct line6_pcm_properties *properties) { - static struct snd_device_ops pcm_ops = { - .dev_free = snd_line6_pcm_free, - }; - - int err; + int i, err; unsigned ep_read = line6->properties->ep_audio_r; unsigned ep_write = line6->properties->ep_audio_w; + struct snd_pcm *pcm; struct snd_line6_pcm *line6pcm; if (!(line6->properties->capabilities & LINE6_CAP_PCM)) return 0; /* skip PCM initialization and report success */ - line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); + err = snd_line6_new_pcm(line6, &pcm); + if (err < 0) + return err; - if (line6pcm == NULL) + line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); + if (!line6pcm) return -ENOMEM; + line6pcm->pcm = pcm; + line6pcm->properties = properties; line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; line6pcm->volume_monitor = 255; line6pcm->line6 = line6; @@ -444,21 +424,15 @@ int line6_init_pcm(struct usb_line6 *line6, usb_maxpacket(line6->usbdev, usb_sndisocpipe(line6->usbdev, ep_write), 1)); - line6pcm->properties = properties; - line6->line6pcm = line6pcm; - - /* PCM device: */ - err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); - if (err < 0) - return err; - - err = snd_line6_new_pcm(line6pcm); - if (err < 0) - return err; - spin_lock_init(&line6pcm->lock_audio_out); spin_lock_init(&line6pcm->lock_audio_in); spin_lock_init(&line6pcm->lock_trigger); + line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; + + line6->line6pcm = line6pcm; + + pcm->private_data = line6pcm; + pcm->private_free = line6_cleanup_pcm; err = line6_create_audio_out_urbs(line6pcm); if (err < 0) @@ -469,27 +443,16 @@ int line6_init_pcm(struct usb_line6 *line6, return err; /* mixer: */ - err = - snd_ctl_add(line6->card, - snd_ctl_new1(&line6_control_playback, line6pcm)); - if (err < 0) - return err; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /* impulse response test: */ - err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); - if (err < 0) - return err; - - err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); - if (err < 0) - return err; - - line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; -#endif + for (i = 0; i < ARRAY_SIZE(line6_controls); i++) { + err = snd_ctl_add(line6->card, + snd_ctl_new1(&line6_controls[i], line6pcm)); + if (err < 0) + return err; + } return 0; } +EXPORT_SYMBOL_GPL(line6_init_pcm); /* prepare pcm callback */ int snd_line6_prepare(struct snd_pcm_substream *substream) @@ -508,9 +471,6 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) line6_unlink_wait_clear_audio_in_urbs(line6pcm); break; - - default: - MISSING_CASE; } if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index 7315e8131184..c742b33666eb 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -26,7 +26,7 @@ /* number of USB frames per URB - The Line6 Windows driver always transmits two frames per packet, but + The Line 6 Windows driver always transmits two frames per packet, but the Linux driver performs significantly better (i.e., lower latency) with only one frame per packet. */ @@ -35,12 +35,10 @@ /* in a "full speed" device (such as the PODxt Pro) this means 1ms */ #define LINE6_ISO_INTERVAL 1 -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE #define LINE6_IMPULSE_DEFAULT_PERIOD 100 -#endif /* - Get substream from Line6 PCM data structure + Get substream from Line 6 PCM data structure */ #define get_substream(line6pcm, stream) \ (line6pcm->pcm->streams[stream].substream) @@ -48,7 +46,7 @@ /* PCM mode bits. - There are several features of the Line6 USB driver which require PCM + There are several features of the Line 6 USB driver which require PCM data to be exchanged with the device: *) PCM playback and capture via ALSA *) software monitoring (for devices without hardware monitoring) @@ -89,12 +87,10 @@ enum { LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, -#endif LINE6_INDEX_PAUSE_PLAYBACK, LINE6_INDEX_PREPARED, @@ -109,12 +105,10 @@ enum { LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), -#endif LINE6_BIT(PAUSE_PLAYBACK), LINE6_BIT(PREPARED), @@ -133,40 +127,30 @@ enum { LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BITS_PCM_IMPULSE = LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, -#endif /* combined bit masks (by direction): */ LINE6_BITS_PLAYBACK_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | -#endif LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, LINE6_BITS_PLAYBACK_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | -#endif LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, LINE6_BITS_CAPTURE_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | -#endif LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, LINE6_BITS_CAPTURE_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | -#endif LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, @@ -183,7 +167,7 @@ struct line6_pcm_properties { struct snd_line6_pcm { /** - Pointer back to the Line6 driver data structure. + Pointer back to the Line 6 driver data structure. */ struct usb_line6 *line6; @@ -338,7 +322,6 @@ struct snd_line6_pcm { */ int volume_monitor; -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE /** Volume of impulse response test signal (if zero, test is disabled). */ @@ -353,7 +336,6 @@ struct snd_line6_pcm { Counter for impulse response test signal. */ int impulse_count; -#endif /** Several status bits (see LINE6_BIT_*). diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index da2e3b8876b8..1c9f95a370ff 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -14,11 +14,9 @@ #include #include -#include "audio.h" #include "capture.h" #include "driver.h" #include "pcm.h" -#include "pod.h" #include "playback.h" /* @@ -61,8 +59,6 @@ static void change_volume(struct urb *urb_out, int volume[], } } -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /* Create signal for impulse response test. */ @@ -106,8 +102,6 @@ static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, } } -#endif - /* Add signal to buffer for software monitoring. */ @@ -244,7 +238,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); if (line6pcm->prev_fbuf != NULL) { -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { create_impulse_test_signal(line6pcm, urb_out, bytes_per_frame); @@ -258,7 +251,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_out->transfer_buffer_length); } } else { -#endif if (! (line6pcm->line6-> properties->capabilities & LINE6_CAP_HWMON) @@ -267,9 +259,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) add_monitor_signal(urb_out, line6pcm->prev_fbuf, line6pcm->volume_monitor, bytes_per_frame); -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE } -#endif } ret = usb_submit_urb(urb_out, GFP_ATOMIC); @@ -499,9 +489,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: -#ifdef CONFIG_PM case SNDRV_PCM_TRIGGER_RESUME: -#endif err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); @@ -511,9 +499,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: -#ifdef CONFIG_PM case SNDRV_PCM_TRIGGER_SUSPEND: -#endif err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); @@ -571,10 +557,8 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) urb = line6pcm->urb_audio_out[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); - if (urb == NULL) { - dev_err(line6->ifcdev, "Out of memory\n"); + if (urb == NULL) return -ENOMEM; - } urb->dev = line6->usbdev; urb->pipe = diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index 743bd6f74c57..78a885113221 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 85a43631996e..bf027fc70cba 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -11,13 +11,93 @@ #include #include +#include +#include +#include + +#include #include -#include "audio.h" #include "capture.h" #include "driver.h" #include "playback.h" -#include "pod.h" +#include "usbdefs.h" + +/* + Locate name in binary program dump +*/ +#define POD_NAME_OFFSET 0 +#define POD_NAME_LENGTH 16 + +/* + Other constants +*/ +#define POD_CONTROL_SIZE 0x80 +#define POD_BUFSIZE_DUMPREQ 7 +#define POD_STARTUP_DELAY 1000 + +/* + Stages of POD startup procedure +*/ +enum { + POD_STARTUP_INIT = 1, + POD_STARTUP_VERSIONREQ, + POD_STARTUP_WORKQUEUE, + POD_STARTUP_SETUP, + POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 +}; + +enum { + LINE6_BASSPODXT, + LINE6_BASSPODXTLIVE, + LINE6_BASSPODXTPRO, + LINE6_POCKETPOD, + LINE6_PODXT, + LINE6_PODXTLIVE_POD, + LINE6_PODXTPRO, +}; + +struct usb_line6_pod { + /** + Generic Line 6 USB data. + */ + struct usb_line6 line6; + + /** + Instrument monitor level. + */ + int monitor_level; + + /** + Timer for device initializaton. + */ + struct timer_list startup_timer; + + /** + Work handler for device initializaton. + */ + struct work_struct startup_work; + + /** + Current progress in startup procedure. + */ + int startup_progress; + + /** + Serial number of device. + */ + int serial_number; + + /** + Firmware version (x 100). + */ + int firmware_version; + + /** + Device ID. + */ + int device_id; +}; #define POD_SYSEX_CODE 3 #define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ @@ -72,9 +152,6 @@ static struct line6_pcm_properties pod_pcm_properties = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_KNOT, @@ -92,9 +169,6 @@ static struct line6_pcm_properties pod_pcm_properties = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_KNOT, @@ -265,7 +339,7 @@ static void pod_startup4(struct work_struct *work) line6_read_serial_number(&pod->line6, &pod->serial_number); /* ALSA audio interface: */ - line6_register_audio(line6); + snd_card_register(line6->card); } /* POD special files: */ @@ -322,21 +396,6 @@ static struct snd_kcontrol_new pod_control_monitor = { .put = snd_pod_control_monitor_put }; -/* - POD destructor. -*/ -static void pod_destruct(struct usb_interface *interface) -{ - struct usb_line6_pod *pod = usb_get_intfdata(interface); - - if (pod == NULL) - return; - line6_cleanup_audio(&pod->line6); - - del_timer(&pod->startup_timer); - cancel_work_sync(&pod->startup_work); -} - /* POD device disconnected. */ @@ -349,21 +408,18 @@ static void line6_pod_disconnect(struct usb_interface *interface) pod = usb_get_intfdata(interface); if (pod != NULL) { - struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; struct device *dev = &interface->dev; - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - if (dev != NULL) { /* remove sysfs entries: */ device_remove_file(dev, &dev_attr_device_id); device_remove_file(dev, &dev_attr_firmware_version); device_remove_file(dev, &dev_attr_serial_number); } - } - pod_destruct(interface); + del_timer_sync(&pod->startup_timer); + cancel_work_sync(&pod->startup_work); + } } /* @@ -373,17 +429,23 @@ static int pod_create_files2(struct device *dev) { int err; - CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); - CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); - CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); + err = device_create_file(dev, &dev_attr_device_id); + if (err < 0) + return err; + err = device_create_file(dev, &dev_attr_firmware_version); + if (err < 0) + return err; + err = device_create_file(dev, &dev_attr_serial_number); + if (err < 0) + return err; return 0; } /* Try to init POD device. */ -static int pod_try_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int pod_init(struct usb_interface *interface, + struct usb_line6 *line6) { int err; struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; @@ -402,11 +464,6 @@ static int pod_try_init(struct usb_interface *interface, if (err < 0) return err; - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - /* initialize MIDI subsystem: */ err = line6_init_midi(line6); if (err < 0) @@ -439,15 +496,136 @@ static int pod_try_init(struct usb_interface *interface, return 0; } +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id pod_id_table[] = { + { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, + { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, + { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, + { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, + { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, + { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, + { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, + {} +}; + +MODULE_DEVICE_TABLE(usb, pod_id_table); + +static const struct line6_properties pod_properties_table[] = { + [LINE6_BASSPODXT] = { + .id = "BassPODxt", + .name = "BassPODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTLIVE] = { + .id = "BassPODxtLive", + .name = "BassPODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_BASSPODXTPRO] = { + .id = "BassPODxtPro", + .name = "BassPODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_POCKETPOD] = { + .id = "PocketPOD", + .name = "Pocket POD", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 0, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x02, + /* no audio channel */ + }, + [LINE6_PODXT] = { + .id = "PODxt", + .name = "PODxt", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTLIVE_POD] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODXTPRO] = { + .id = "PODxtPro", + .name = "PODxt Pro", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, +}; + /* - Init POD device (and clean up in case of failure). + Probe USB device. */ -int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) +static int pod_probe(struct usb_interface *interface, + const struct usb_device_id *id) { - int err = pod_try_init(interface, line6); + struct usb_line6_pod *pod; - if (err < 0) - pod_destruct(interface); - - return err; + pod = kzalloc(sizeof(*pod), GFP_KERNEL); + if (!pod) + return -ENODEV; + return line6_probe(interface, &pod->line6, + &pod_properties_table[id->driver_info], + pod_init); } + +static struct usb_driver pod_driver = { + .name = KBUILD_MODNAME, + .probe = pod_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = pod_id_table, +}; + +module_usb_driver(pod_driver); + +MODULE_DESCRIPTION("Line 6 POD USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/pod.h b/sound/usb/line6/pod.h deleted file mode 100644 index 87a8f0fa9cba..000000000000 --- a/sound/usb/line6/pod.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * 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, version 2. - * - */ - -#ifndef POD_H -#define POD_H - -#include -#include -#include - -#include - -#include "driver.h" - -/* - Locate name in binary program dump -*/ -#define POD_NAME_OFFSET 0 -#define POD_NAME_LENGTH 16 - -/* - Other constants -*/ -#define POD_CONTROL_SIZE 0x80 -#define POD_BUFSIZE_DUMPREQ 7 -#define POD_STARTUP_DELAY 1000 - -/* - Stages of POD startup procedure -*/ -enum { - POD_STARTUP_INIT = 1, - POD_STARTUP_VERSIONREQ, - POD_STARTUP_WORKQUEUE, - POD_STARTUP_SETUP, - POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 -}; - -struct usb_line6_pod { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Instrument monitor level. - */ - int monitor_level; - - /** - Timer for device initializaton. - */ - struct timer_list startup_timer; - - /** - Work handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Current progress in startup procedure. - */ - int startup_progress; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Device ID. - */ - int device_id; -}; - -extern int line6_pod_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 27c5402cece8..7217fa7e5db1 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -1,5 +1,5 @@ /* - * Line6 Pod HD + * Line 6 Pod HD * * Copyright (C) 2011 Stefan Hajnoczi * @@ -9,13 +9,29 @@ * */ +#include +#include +#include #include #include -#include "audio.h" #include "driver.h" #include "pcm.h" -#include "podhd.h" +#include "usbdefs.h" + +enum { + LINE6_PODHD300, + LINE6_PODHD400, + LINE6_PODHD500_0, + LINE6_PODHD500_1, +}; + +struct usb_line6_podhd { + /** + Generic Line 6 USB data. + */ + struct usb_line6 line6; +}; #define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ @@ -33,9 +49,6 @@ static struct line6_pcm_properties podhd_pcm_properties = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_48000, @@ -53,9 +66,6 @@ static struct line6_pcm_properties podhd_pcm_properties = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S24_3LE, .rates = SNDRV_PCM_RATE_48000, @@ -74,58 +84,18 @@ static struct line6_pcm_properties podhd_pcm_properties = { .bytes_per_frame = PODHD_BYTES_PER_FRAME }; -/* - POD HD destructor. -*/ -static void podhd_destruct(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd = usb_get_intfdata(interface); - - if (podhd == NULL) - return; - line6_cleanup_audio(&podhd->line6); -} - -/* - POD HD device disconnected. -*/ -static void line6_podhd_disconnect(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd; - - if (interface == NULL) - return; - podhd = usb_get_intfdata(interface); - - if (podhd != NULL) { - struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - } - - podhd_destruct(interface); -} - /* Try to init POD HD device. */ -static int podhd_try_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd) +static int podhd_init(struct usb_interface *interface, + struct usb_line6 *line6) { + struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; int err; - struct usb_line6 *line6 = &podhd->line6; if ((interface == NULL) || (podhd == NULL)) return -ENODEV; - line6->disconnect = line6_podhd_disconnect; - - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - /* initialize MIDI subsystem: */ err = line6_init_midi(line6); if (err < 0) @@ -137,20 +107,103 @@ static int podhd_try_init(struct usb_interface *interface, return err; /* register USB audio system: */ - err = line6_register_audio(line6); - return err; + return snd_card_register(line6->card); } +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id podhd_id_table[] = { + { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, + { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, + { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, + { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, + {} +}; + +MODULE_DEVICE_TABLE(usb, podhd_id_table); + +static const struct line6_properties podhd_properties_table[] = { + [LINE6_PODHD300] = { + .id = "PODHD300", + .name = "POD HD300", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD400] = { + .id = "PODHD400", + .name = "POD HD400", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 5, + .ep_ctrl_r = 0x84, + .ep_ctrl_w = 0x03, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODHD500_0] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, + [LINE6_PODHD500_1] = { + .id = "PODHD500", + .name = "POD HD500", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x81, + .ep_ctrl_w = 0x01, + .ep_audio_r = 0x86, + .ep_audio_w = 0x02, + }, +}; + /* - Init POD HD device (and clean up in case of failure). + Probe USB device. */ -int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) +static int podhd_probe(struct usb_interface *interface, + const struct usb_device_id *id) { - struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; - int err = podhd_try_init(interface, podhd); + struct usb_line6_podhd *podhd; - if (err < 0) - podhd_destruct(interface); - - return err; + podhd = kzalloc(sizeof(*podhd), GFP_KERNEL); + if (!podhd) + return -ENODEV; + return line6_probe(interface, &podhd->line6, + &podhd_properties_table[id->driver_info], + podhd_init); } + +static struct usb_driver podhd_driver = { + .name = KBUILD_MODNAME, + .probe = podhd_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = podhd_id_table, +}; + +module_usb_driver(podhd_driver); + +MODULE_DESCRIPTION("Line 6 PODHD USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/podhd.h b/sound/usb/line6/podhd.h deleted file mode 100644 index a14f711f9725..000000000000 --- a/sound/usb/line6/podhd.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Line6 Pod HD - * - * Copyright (C) 2011 Stefan Hajnoczi - * - * 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, version 2. - * - */ - -#ifndef PODHD_H -#define PODHD_H - -#include - -#include "driver.h" - -struct usb_line6_podhd { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; -}; - -extern int line6_podhd_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif /* PODHD_H */ diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index aae78d8a82d9..c1f61cde52ab 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Emil Myhrman (emil.myhrman@gmail.com) @@ -11,13 +11,58 @@ */ #include +#include +#include +#include +#include #include -#include "audio.h" #include "capture.h" #include "driver.h" #include "playback.h" -#include "toneport.h" +#include "usbdefs.h" + +enum line6_device_type { + LINE6_GUITARPORT, + LINE6_PODSTUDIO_GX, + LINE6_PODSTUDIO_UX1, + LINE6_PODSTUDIO_UX2, + LINE6_TONEPORT_GX, + LINE6_TONEPORT_UX1, + LINE6_TONEPORT_UX2, +}; + +struct usb_line6_toneport { + /** + Generic Line 6 USB data. + */ + struct usb_line6 line6; + + /** + Source selector. + */ + int source; + + /** + Serial number of device. + */ + int serial_number; + + /** + Firmware version (x 100). + */ + int firmware_version; + + /** + Timer for delayed PCM startup. + */ + struct timer_list timer; + + /** + Device type. + */ + enum line6_device_type type; +}; static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); @@ -37,9 +82,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT, @@ -57,9 +99,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT, @@ -290,18 +329,6 @@ static struct snd_kcontrol_new toneport_control_source = { .put = snd_toneport_source_put }; -/* - Toneport destructor. -*/ -static void toneport_destruct(struct usb_interface *interface) -{ - struct usb_line6_toneport *toneport = usb_get_intfdata(interface); - - if (toneport == NULL) - return; - line6_cleanup_audio(&toneport->line6); -} - /* Setup Toneport device. */ @@ -319,7 +346,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) toneport_send_cmd(usbdev, 0x0301, 0x0000); /* initialize source select: */ - switch (line6->type) { + switch (toneport->type) { case LINE6_TONEPORT_UX1: case LINE6_TONEPORT_UX2: case LINE6_PODSTUDIO_UX1: @@ -331,7 +358,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) break; } - if (toneport_has_led(line6->type)) + if (toneport_has_led(toneport->type)) toneport_update_led(&usbdev->dev); } @@ -354,25 +381,14 @@ static void line6_toneport_disconnect(struct usb_interface *interface) device_remove_file(&interface->dev, &dev_attr_led_red); device_remove_file(&interface->dev, &dev_attr_led_green); } - - if (toneport != NULL) { - struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; - - if (line6pcm != NULL) { - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); - line6_pcm_disconnect(line6pcm); - } - } - - toneport_destruct(interface); } /* Try to init Toneport device. */ -static int toneport_try_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int toneport_init(struct usb_interface *interface, + struct usb_line6 *line6) { int err; struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; @@ -382,11 +398,6 @@ static int toneport_try_init(struct usb_interface *interface, line6->disconnect = line6_toneport_disconnect; - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - /* initialize PCM subsystem: */ err = line6_init_pcm(line6, &toneport_pcm_properties); if (err < 0) @@ -400,7 +411,7 @@ static int toneport_try_init(struct usb_interface *interface, return err; /* register source select control: */ - switch (line6->type) { + switch (toneport->type) { case LINE6_TONEPORT_UX1: case LINE6_TONEPORT_UX2: case LINE6_PODSTUDIO_UX1: @@ -416,50 +427,152 @@ static int toneport_try_init(struct usb_interface *interface, break; } - /* register audio system: */ - err = line6_register_audio(line6); - if (err < 0) - return err; - line6_read_serial_number(line6, &toneport->serial_number); line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); - if (toneport_has_led(line6->type)) { - CHECK_RETURN(device_create_file - (&interface->dev, &dev_attr_led_red)); - CHECK_RETURN(device_create_file - (&interface->dev, &dev_attr_led_green)); + if (toneport_has_led(toneport->type)) { + err = device_create_file(&interface->dev, &dev_attr_led_red); + if (err < 0) + return err; + err = device_create_file(&interface->dev, &dev_attr_led_green); + if (err < 0) + return err; } toneport_setup(toneport); - init_timer(&toneport->timer); - toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; - toneport->timer.function = toneport_start_pcm; - toneport->timer.data = (unsigned long)toneport; - add_timer(&toneport->timer); + setup_timer(&toneport->timer, toneport_start_pcm, + (unsigned long)toneport); + mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); - return 0; -} - -/* - Init Toneport device (and clean up in case of failure). -*/ -int line6_toneport_init(struct usb_interface *interface, - struct usb_line6 *line6) -{ - int err = toneport_try_init(interface, line6); - - if (err < 0) - toneport_destruct(interface); - - return err; + /* register audio system: */ + return snd_card_register(line6->card); } +#ifdef CONFIG_PM /* Resume Toneport device after reset. */ -void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) +static int toneport_reset_resume(struct usb_interface *interface) { - toneport_setup(toneport); + toneport_setup(usb_get_intfdata(interface)); + return line6_resume(interface); } +#endif + +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id toneport_id_table[] = { + { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, + { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, + { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, + { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, + { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, + { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, + { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, + {} +}; + +MODULE_DEVICE_TABLE(usb, toneport_id_table); + +static const struct line6_properties toneport_properties_table[] = { + [LINE6_GUITARPORT] = { + .id = "GuitarPort", + .name = "GuitarPort", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_GX] = { + .id = "PODStudioGX", + .name = "POD Studio GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX1] = { + .id = "PODStudioUX1", + .name = "POD Studio UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_PODSTUDIO_UX2] = { + .id = "PODStudioUX2", + .name = "POD Studio UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_GX] = { + .id = "TonePortGX", + .name = "TonePort GX", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX1] = { + .id = "TonePortUX1", + .name = "TonePort UX1", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* 1..4 seem to be ok */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_TONEPORT_UX2] = { + .id = "TonePortUX2", + .name = "TonePort UX2", + .capabilities = LINE6_CAP_PCM, + .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ + /* no control channel */ + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, +}; + +/* + Probe USB device. +*/ +static int toneport_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_line6_toneport *toneport; + + toneport = kzalloc(sizeof(*toneport), GFP_KERNEL); + if (!toneport) + return -ENODEV; + toneport->type = id->driver_info; + return line6_probe(interface, &toneport->line6, + &toneport_properties_table[id->driver_info], + toneport_init); +} + +static struct usb_driver toneport_driver = { + .name = KBUILD_MODNAME, + .probe = toneport_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = toneport_reset_resume, +#endif + .id_table = toneport_id_table, +}; + +module_usb_driver(toneport_driver); + +MODULE_DESCRIPTION("TonePort USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/toneport.h b/sound/usb/line6/toneport.h deleted file mode 100644 index 8cb14426f6ae..000000000000 --- a/sound/usb/line6/toneport.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * 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, version 2. - * - */ - -#ifndef TONEPORT_H -#define TONEPORT_H - -#include -#include - -#include "driver.h" - -struct usb_line6_toneport { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Source selector. - */ - int source; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Timer for delayed PCM startup. - */ - struct timer_list timer; -}; - -extern int line6_toneport_init(struct usb_interface *interface, - struct usb_line6 *line6); -extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); - -#endif diff --git a/sound/usb/line6/usbdefs.h b/sound/usb/line6/usbdefs.h index f4d080e69abc..5ef7bcd24e18 100644 --- a/sound/usb/line6/usbdefs.h +++ b/sound/usb/line6/usbdefs.h @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at) * diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index b4a41b0ad0ea..99a58cbfd2da 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -1,5 +1,5 @@ /* - * Line6 Linux USB driver - 0.9.1beta + * Line 6 Linux USB driver * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * @@ -10,10 +10,64 @@ */ #include +#include +#include +#include +#include +#include -#include "audio.h" #include "driver.h" -#include "variax.h" +#include "usbdefs.h" + +#define VARIAX_STARTUP_DELAY1 1000 +#define VARIAX_STARTUP_DELAY3 100 +#define VARIAX_STARTUP_DELAY4 100 + +/* + Stages of Variax startup procedure +*/ +enum { + VARIAX_STARTUP_INIT = 1, + VARIAX_STARTUP_VERSIONREQ, + VARIAX_STARTUP_WAIT, + VARIAX_STARTUP_ACTIVATE, + VARIAX_STARTUP_WORKQUEUE, + VARIAX_STARTUP_SETUP, + VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 +}; + +enum { + LINE6_PODXTLIVE_VARIAX, + LINE6_VARIAX +}; + +struct usb_line6_variax { + /** + Generic Line 6 USB data. + */ + struct usb_line6 line6; + + /** + Buffer for activation code. + */ + unsigned char *buffer_activate; + + /** + Handler for device initializaton. + */ + struct work_struct startup_work; + + /** + Timers for device initializaton. + */ + struct timer_list startup_timer1; + struct timer_list startup_timer2; + + /** + Current progress in startup procedure. + */ + int startup_progress; +}; #define VARIAX_OFFSET_ACTIVATE 7 @@ -124,7 +178,7 @@ static void variax_startup6(struct work_struct *work) CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); /* ALSA audio interface: */ - line6_register_audio(&variax->line6); + snd_card_register(variax->line6.card); } /* @@ -156,13 +210,16 @@ static void line6_variax_process_message(struct usb_line6 *line6) /* Variax destructor. */ -static void variax_destruct(struct usb_interface *interface) +static void line6_variax_disconnect(struct usb_interface *interface) { - struct usb_line6_variax *variax = usb_get_intfdata(interface); + struct usb_line6_variax *variax; - if (variax == NULL) + if (!interface) + return; + + variax = usb_get_intfdata(interface); + if (!variax) return; - line6_cleanup_audio(&variax->line6); del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer2); @@ -171,22 +228,11 @@ static void variax_destruct(struct usb_interface *interface) kfree(variax->buffer_activate); } -/* - Workbench device disconnected. -*/ -static void line6_variax_disconnect(struct usb_interface *interface) -{ - if (interface == NULL) - return; - - variax_destruct(interface); -} - /* Try to init workbench device. */ -static int variax_try_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int variax_init(struct usb_interface *interface, + struct usb_line6 *line6) { struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; int err; @@ -205,15 +251,8 @@ static int variax_try_init(struct usb_interface *interface, variax->buffer_activate = kmemdup(variax_activate, sizeof(variax_activate), GFP_KERNEL); - if (variax->buffer_activate == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (variax->buffer_activate == NULL) return -ENOMEM; - } - - /* initialize audio system: */ - err = line6_init_audio(&variax->line6); - if (err < 0) - return err; /* initialize MIDI subsystem: */ err = line6_init_midi(&variax->line6); @@ -225,15 +264,71 @@ static int variax_try_init(struct usb_interface *interface, return 0; } +#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) +#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) + +/* table of devices that work with this driver */ +static const struct usb_device_id variax_id_table[] = { + { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, + { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, + {} +}; + +MODULE_DEVICE_TABLE(usb, variax_id_table); + +static const struct line6_properties variax_properties_table[] = { + [LINE6_PODXTLIVE_VARIAX] = { + .id = "PODxtLive", + .name = "PODxt Live", + .capabilities = LINE6_CAP_CONTROL + | LINE6_CAP_PCM + | LINE6_CAP_HWMON, + .altsetting = 1, + .ep_ctrl_r = 0x86, + .ep_ctrl_w = 0x05, + .ep_audio_r = 0x82, + .ep_audio_w = 0x01, + }, + [LINE6_VARIAX] = { + .id = "Variax", + .name = "Variax Workbench", + .capabilities = LINE6_CAP_CONTROL, + .altsetting = 1, + .ep_ctrl_r = 0x82, + .ep_ctrl_w = 0x01, + /* no audio channel */ + } +}; + /* - Init workbench device (and clean up in case of failure). + Probe USB device. */ -int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) +static int variax_probe(struct usb_interface *interface, + const struct usb_device_id *id) { - int err = variax_try_init(interface, line6); + struct usb_line6_variax *variax; - if (err < 0) - variax_destruct(interface); - - return err; + variax = kzalloc(sizeof(*variax), GFP_KERNEL); + if (!variax) + return -ENODEV; + return line6_probe(interface, &variax->line6, + &variax_properties_table[id->driver_info], + variax_init); } + +static struct usb_driver variax_driver = { + .name = KBUILD_MODNAME, + .probe = variax_probe, + .disconnect = line6_disconnect, +#ifdef CONFIG_PM + .suspend = line6_suspend, + .resume = line6_resume, + .reset_resume = line6_resume, +#endif + .id_table = variax_id_table, +}; + +module_usb_driver(variax_driver); + +MODULE_DESCRIPTION("Vairax Workbench USB driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/usb/line6/variax.h b/sound/usb/line6/variax.h deleted file mode 100644 index dfb94e574cc4..000000000000 --- a/sound/usb/line6/variax.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * 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, version 2. - * - */ - -#ifndef VARIAX_H -#define VARIAX_H - -#include -#include -#include -#include - -#include "driver.h" - -#define VARIAX_STARTUP_DELAY1 1000 -#define VARIAX_STARTUP_DELAY3 100 -#define VARIAX_STARTUP_DELAY4 100 - -/* - Stages of Variax startup procedure -*/ -enum { - VARIAX_STARTUP_INIT = 1, - VARIAX_STARTUP_VERSIONREQ, - VARIAX_STARTUP_WAIT, - VARIAX_STARTUP_ACTIVATE, - VARIAX_STARTUP_WORKQUEUE, - VARIAX_STARTUP_SETUP, - VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 -}; - -struct usb_line6_variax { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Buffer for activation code. - */ - unsigned char *buffer_activate; - - /** - Handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Timers for device initializaton. - */ - struct timer_list startup_timer1; - struct timer_list startup_timer2; - - /** - Current progress in startup procedure. - */ - int startup_progress; -}; - -extern int line6_variax_init(struct usb_interface *interface, - struct usb_line6 *line6); - -#endif