diff options
Diffstat (limited to 'drivers/staging/line6')
-rw-r--r-- | drivers/staging/line6/Makefile | 3 | ||||
-rw-r--r-- | drivers/staging/line6/capture.c | 44 | ||||
-rw-r--r-- | drivers/staging/line6/capture.h | 2 | ||||
-rw-r--r-- | drivers/staging/line6/driver.c | 74 | ||||
-rw-r--r-- | drivers/staging/line6/driver.h | 10 | ||||
-rw-r--r-- | drivers/staging/line6/midi.c | 37 | ||||
-rw-r--r-- | drivers/staging/line6/midi.h | 4 | ||||
-rw-r--r-- | drivers/staging/line6/pcm.c | 115 | ||||
-rw-r--r-- | drivers/staging/line6/pcm.h | 8 | ||||
-rw-r--r-- | drivers/staging/line6/playback.c | 53 | ||||
-rw-r--r-- | drivers/staging/line6/playback.h | 2 | ||||
-rw-r--r-- | drivers/staging/line6/pod.c | 6 | ||||
-rw-r--r-- | drivers/staging/line6/podhd.c | 154 | ||||
-rw-r--r-- | drivers/staging/line6/podhd.h | 30 | ||||
-rw-r--r-- | drivers/staging/line6/revision.h | 2 | ||||
-rw-r--r-- | drivers/staging/line6/toneport.c | 6 | ||||
-rw-r--r-- | drivers/staging/line6/usbdefs.h | 91 | ||||
-rw-r--r-- | drivers/staging/line6/variax.c | 6 |
18 files changed, 481 insertions, 166 deletions
diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile index de6bd12e9736..34a2ddacc7e9 100644 --- a/drivers/staging/line6/Makefile +++ b/drivers/staging/line6/Makefile @@ -12,4 +12,5 @@ line6usb-y := \ playback.o \ pod.o \ toneport.o \ - variax.o + variax.o \ + podhd.o diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c index 9647154a4923..127f95247749 100644 --- a/drivers/staging/line6/capture.c +++ b/drivers/staging/line6/capture.c @@ -9,6 +9,7 @@ * */ +#include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -192,6 +193,31 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) } } +int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm) +{ + /* We may be invoked multiple times in a row so allocate once only */ + if (line6pcm->buffer_in) + return 0; + + line6pcm->buffer_in = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + + if (!line6pcm->buffer_in) { + dev_err(line6pcm->line6->ifcdev, + "cannot malloc capture buffer\n"); + return -ENOMEM; + } + + return 0; +} + +void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_in); + line6pcm->buffer_in = NULL; +} + /* * Callback for completed capture URB. */ @@ -243,11 +269,7 @@ static void audio_in_callback(struct urb *urb) length += fsize; /* the following assumes LINE6_ISO_PACKETS == 1: */ -#if LINE6_BACKUP_MONITOR_SIGNAL - memcpy(line6pcm->prev_fbuf, fbuf, fsize); -#else line6pcm->prev_fbuf = fbuf; -#endif line6pcm->prev_fsize = fsize; #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE @@ -319,6 +341,13 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, } /* -- [FD] end */ + if ((line6pcm->flags & MASK_CAPTURE) == 0) { + ret = line6_alloc_capture_buffer(line6pcm); + + if (ret < 0) + return ret; + } + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) @@ -331,6 +360,13 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, /* hw_free capture callback */ static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) { + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + if ((line6pcm->flags & MASK_CAPTURE) == 0) { + line6_unlink_wait_clear_audio_in_urbs(line6pcm); + line6_free_capture_buffer(line6pcm); + } + return snd_pcm_lib_free_pages(substream); } diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h index a7509fbbb954..366cbaa7c88d 100644 --- a/drivers/staging/line6/capture.h +++ b/drivers/staging/line6/capture.h @@ -19,11 +19,13 @@ extern struct snd_pcm_ops snd_line6_capture_ops; +extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm); extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length); extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 851b762319cf..6a1959e16e00 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -21,6 +21,7 @@ #include "midi.h" #include "playback.h" #include "pod.h" +#include "podhd.h" #include "revision.h" #include "toneport.h" #include "usbdefs.h" @@ -37,6 +38,8 @@ static const struct usb_device_id line6_id_table[] = { {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)}, + {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)}, + {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, @@ -56,23 +59,25 @@ MODULE_DEVICE_TABLE(usb, line6_id_table); /* *INDENT-OFF* */ static struct line6_properties line6_properties_table[] = { - { "BassPODxt", "BassPODxt", LINE6_BIT_BASSPODXT, LINE6_BIT_CONTROL_PCM_HWMON }, - { "BassPODxtLive", "BassPODxt Live", LINE6_BIT_BASSPODXTLIVE, LINE6_BIT_CONTROL_PCM_HWMON }, - { "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_BASSPODXTPRO, LINE6_BIT_CONTROL_PCM_HWMON }, - { "GuitarPort", "GuitarPort", LINE6_BIT_GUITARPORT, LINE6_BIT_PCM }, - { "PocketPOD", "Pocket POD", LINE6_BIT_POCKETPOD, LINE6_BIT_CONTROL }, - { "PODStudioGX", "POD Studio GX", LINE6_BIT_PODSTUDIO_GX, LINE6_BIT_PCM }, - { "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PODSTUDIO_UX1, LINE6_BIT_PCM }, - { "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PODSTUDIO_UX2, LINE6_BIT_PCM }, - { "PODX3", "POD X3", LINE6_BIT_PODX3, LINE6_BIT_PCM }, - { "PODX3Live", "POD X3 Live", LINE6_BIT_PODX3LIVE, LINE6_BIT_PCM }, - { "PODxt", "PODxt", LINE6_BIT_PODXT, LINE6_BIT_CONTROL_PCM_HWMON }, - { "PODxtLive", "PODxt Live", LINE6_BIT_PODXTLIVE, LINE6_BIT_CONTROL_PCM_HWMON }, - { "PODxtPro", "PODxt Pro", LINE6_BIT_PODXTPRO, LINE6_BIT_CONTROL_PCM_HWMON }, - { "TonePortGX", "TonePort GX", LINE6_BIT_TONEPORT_GX, LINE6_BIT_PCM }, - { "TonePortUX1", "TonePort UX1", LINE6_BIT_TONEPORT_UX1, LINE6_BIT_PCM }, - { "TonePortUX2", "TonePort UX2", LINE6_BIT_TONEPORT_UX2, LINE6_BIT_PCM }, - { "Variax", "Variax Workbench", LINE6_BIT_VARIAX, LINE6_BIT_CONTROL } + { LINE6_BIT_BASSPODXT, "BassPODxt", "BassPODxt", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_GUITARPORT, "GuitarPort", "GuitarPort", LINE6_BIT_PCM }, + { LINE6_BIT_POCKETPOD, "PocketPOD", "Pocket POD", LINE6_BIT_CONTROL }, + { LINE6_BIT_PODHD300, "PODHD300", "POD HD300", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODHD500, "PODHD500", "POD HD500", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", LINE6_BIT_PCM }, + { LINE6_BIT_PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PCM }, + { LINE6_BIT_PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PCM }, + { LINE6_BIT_PODX3, "PODX3", "POD X3", LINE6_BIT_PCM }, + { LINE6_BIT_PODX3LIVE, "PODX3Live", "POD X3 Live", LINE6_BIT_PCM }, + { LINE6_BIT_PODXT, "PODxt", "PODxt", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODXTLIVE, "PODxtLive", "PODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_PODXTPRO, "PODxtPro", "PODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, + { LINE6_BIT_TONEPORT_GX, "TonePortGX", "TonePort GX", LINE6_BIT_PCM }, + { LINE6_BIT_TONEPORT_UX1, "TonePortUX1", "TonePort UX1", LINE6_BIT_PCM }, + { LINE6_BIT_TONEPORT_UX2, "TonePortUX2", "TonePort UX2", LINE6_BIT_PCM }, + { LINE6_BIT_VARIAX, "Variax", "Variax Workbench", LINE6_BIT_CONTROL }, }; /* *INDENT-ON* */ @@ -437,6 +442,10 @@ static void line6_data_received(struct urb *urb) line6); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + break; /* let userspace handle MIDI */ + case LINE6_DEVID_PODXTLIVE: switch (line6->interface_number) { case PODXTLIVE_INTERFACE_POD: @@ -720,8 +729,8 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_id *id) { int devtype; - struct usb_device *usbdev = NULL; - struct usb_line6 *line6 = NULL; + struct usb_device *usbdev; + struct usb_line6 *line6; const struct line6_properties *properties; int devnum; int interface_number, alternate = 0; @@ -794,6 +803,7 @@ static int line6_probe(struct usb_interface *interface, } break; + case LINE6_DEVID_PODHD500: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: switch (interface_number) { @@ -812,6 +822,7 @@ static int line6_probe(struct usb_interface *interface, case LINE6_DEVID_BASSPODXTPRO: case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTPRO: + case LINE6_DEVID_PODHD300: alternate = 5; break; @@ -865,6 +876,18 @@ static int line6_probe(struct usb_interface *interface, ep_write = 0x03; break; + case LINE6_DEVID_PODHD300: + size = sizeof(struct usb_line6_podhd); + ep_read = 0x84; + ep_write = 0x03; + break; + + case LINE6_DEVID_PODHD500: + size = sizeof(struct usb_line6_podhd); + ep_read = 0x81; + ep_write = 0x01; + break; + case LINE6_DEVID_POCKETPOD: size = sizeof(struct usb_line6_pod); ep_read = 0x82; @@ -923,7 +946,7 @@ static int line6_probe(struct usb_interface *interface, } if (size == 0) { - dev_err(line6->ifcdev, + dev_err(&interface->dev, "driver bug: interface data size not set\n"); ret = -ENODEV; goto err_put; @@ -1017,6 +1040,12 @@ static int line6_probe(struct usb_interface *interface, ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + ret = line6_podhd_init(interface, + (struct usb_line6_podhd *)line6); + break; + case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: @@ -1139,6 +1168,11 @@ static void line6_disconnect(struct usb_interface *interface) line6_pod_disconnect(interface); break; + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + line6_podhd_disconnect(interface); + break; + case LINE6_DEVID_PODXTLIVE: switch (interface_number) { case PODXTLIVE_INTERFACE_POD: diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 553192f49317..117bf9943568 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -88,6 +88,11 @@ static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; */ struct line6_properties { /** + Bit identifying this device in the line6usb driver. + */ + int device_bit; + + /** Card id string (maximum 16 characters). This can be used to address the device in ALSA programs as "default:CARD=<id>" @@ -100,11 +105,6 @@ struct line6_properties { const char *name; /** - Bit identifying this device in the line6usb driver. - */ - int device_bit; - - /** Bit vector defining this device's capabilities in the line6usb driver. */ diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index e554a2da643a..13d02939c3cb 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -135,7 +135,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, line6_write_hexdump(line6, 'S', data, length); #endif - transfer_buffer = kmalloc(length, GFP_ATOMIC); + transfer_buffer = kmemdup(data, length, GFP_ATOMIC); if (transfer_buffer == NULL) { usb_free_urb(urb); @@ -143,7 +143,6 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, return -ENOMEM; } - memcpy(transfer_buffer, data, length); usb_fill_int_urb(urb, line6->usbdev, usb_sndbulkpipe(line6->usbdev, line6->ep_control_write), @@ -173,6 +172,8 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, break; case LINE6_DEVID_VARIAX: + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: break; default: @@ -307,10 +308,10 @@ static ssize_t midi_set_midi_mask_transmit(struct device *dev, { struct usb_interface *interface = to_usb_interface(dev); struct usb_line6 *line6 = usb_get_intfdata(interface); - unsigned long value; + unsigned short value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou16(buf, 10, &value); if (ret) return ret; @@ -339,10 +340,10 @@ static ssize_t midi_set_midi_mask_receive(struct device *dev, { struct usb_interface *interface = to_usb_interface(dev); struct usb_line6 *line6 = usb_get_intfdata(interface); - unsigned long value; + unsigned short value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou16(buf, 10, &value); if (ret) return ret; @@ -391,16 +392,32 @@ int line6_init_midi(struct usb_line6 *line6) return -ENOMEM; err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); - if (err < 0) + if (err < 0) { + kfree(line6midi); return err; + } err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); - if (err < 0) + if (err < 0) { + kfree(line6midi->midibuf_in.buf); + kfree(line6midi); return err; + } line6midi->line6 = line6; - line6midi->midi_mask_transmit = 1; - line6midi->midi_mask_receive = 4; + + switch(line6->product) { + case LINE6_DEVID_PODHD300: + case LINE6_DEVID_PODHD500: + line6midi->midi_mask_transmit = 1; + line6midi->midi_mask_receive = 1; + break; + + default: + line6midi->midi_mask_transmit = 1; + line6midi->midi_mask_receive = 4; + } + line6->line6midi = line6midi; err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h index b73a025d8be9..4a9e9f947297 100644 --- a/drivers/staging/line6/midi.h +++ b/drivers/staging/line6/midi.h @@ -57,12 +57,12 @@ struct snd_line6_midi { /** Bit mask for output MIDI channels. */ - int midi_mask_transmit; + unsigned short midi_mask_transmit; /** Bit mask for input MIDI channels. */ - int midi_mask_receive; + unsigned short midi_mask_receive; /** Buffer for incoming MIDI stream. diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 9d4c8a606eea..37675e66da81 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -86,31 +86,22 @@ static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period, #endif +static bool test_flags(unsigned long flags0, unsigned long flags1, + unsigned long mask) +{ + return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); +} + int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) { unsigned long flags_old = __sync_fetch_and_or(&line6pcm->flags, channels); unsigned long flags_new = flags_old | channels; int err = 0; - -#if LINE6_BACKUP_MONITOR_SIGNAL - if (!(line6pcm->line6->properties->capabilities & LINE6_BIT_HWMON)) { - line6pcm->prev_fbuf = - kmalloc(LINE6_ISO_PACKETS * line6pcm->max_packet_size, - GFP_KERNEL); - - if (!line6pcm->prev_fbuf) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc monitor buffer\n"); - return -ENOMEM; - } - } -#else + line6pcm->prev_fbuf = NULL; -#endif - if (((flags_old & MASK_CAPTURE) == 0) && - ((flags_new & MASK_CAPTURE) != 0)) { + if (test_flags(flags_old, flags_new, MASK_CAPTURE)) { /* Waiting for completion of active URBs in the stop handler is a bug, we therefore report an error if capturing is restarted @@ -119,54 +110,47 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) return -EBUSY; - line6pcm->buffer_in = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); + if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) { + err = line6_alloc_capture_buffer(line6pcm); - if (!line6pcm->buffer_in) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc capture buffer\n"); - return -ENOMEM; + if (err < 0) + goto pcm_start_error; } line6pcm->count_in = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto pcm_start_error; } - if (((flags_old & MASK_PLAYBACK) == 0) && - ((flags_new & MASK_PLAYBACK) != 0)) { + if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) { /* See comment above regarding PCM restart. */ if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) return -EBUSY; - line6pcm->buffer_out = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); + if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) { + err = line6_alloc_playback_buffer(line6pcm); - if (!line6pcm->buffer_out) { - dev_err(line6pcm->line6->ifcdev, - "cannot malloc playback buffer\n"); - return -ENOMEM; + if (err < 0) + goto pcm_start_error; } line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); - if (err < 0) { - __sync_fetch_and_and(&line6pcm->flags, ~channels); - return err; - } + if (err < 0) + goto pcm_start_error; } return 0; + +pcm_start_error: + __sync_fetch_and_and(&line6pcm->flags, ~channels); + return err; } int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) @@ -175,22 +159,19 @@ int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) __sync_fetch_and_and(&line6pcm->flags, ~channels); unsigned long flags_new = flags_old & ~channels; - if (((flags_old & MASK_CAPTURE) != 0) && - ((flags_new & MASK_CAPTURE) == 0)) { + if (test_flags(flags_new, flags_old, MASK_CAPTURE)) { line6_unlink_audio_in_urbs(line6pcm); - kfree(line6pcm->buffer_in); - line6pcm->buffer_in = NULL; + + if (!(flags_old & MASK_PCM_ALSA_CAPTURE)) + line6_free_capture_buffer(line6pcm); } - if (((flags_old & MASK_PLAYBACK) != 0) && - ((flags_new & MASK_PLAYBACK) == 0)) { + if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) { line6_unlink_audio_out_urbs(line6pcm); - kfree(line6pcm->buffer_out); - line6pcm->buffer_out = NULL; + + if (!(flags_old & MASK_PCM_ALSA_PLAYBACK)) + line6_free_playback_buffer(line6pcm); } -#if LINE6_BACKUP_MONITOR_SIGNAL - kfree(line6pcm->prev_fbuf); -#endif return 0; } @@ -403,10 +384,12 @@ int line6_init_pcm(struct usb_line6 *line6, case LINE6_DEVID_PODXT: case LINE6_DEVID_PODXTLIVE: case LINE6_DEVID_PODXTPRO: + case LINE6_DEVID_PODHD300: ep_read = 0x82; ep_write = 0x01; break; + case LINE6_DEVID_PODHD500: case LINE6_DEVID_PODX3: case LINE6_DEVID_PODX3LIVE: ep_read = 0x86; @@ -451,9 +434,14 @@ int line6_init_pcm(struct usb_line6 *line6, line6pcm->line6 = line6; line6pcm->ep_audio_read = ep_read; line6pcm->ep_audio_write = ep_write; - line6pcm->max_packet_size = usb_maxpacket(line6->usbdev, - usb_rcvintpipe(line6->usbdev, - ep_read), 0); + + /* Read and write buffers are sized identically, so choose minimum */ + line6pcm->max_packet_size = min( + usb_maxpacket(line6->usbdev, + usb_rcvisocpipe(line6->usbdev, ep_read), 0), + usb_maxpacket(line6->usbdev, + usb_sndisocpipe(line6->usbdev, ep_write), 1)); + line6pcm->properties = properties; line6->line6pcm = line6pcm; @@ -508,6 +496,23 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + if ((line6pcm->flags & MASK_PLAYBACK) == 0) + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + + break; + + case SNDRV_PCM_STREAM_CAPTURE: + if ((line6pcm->flags & MASK_CAPTURE) == 0) + line6_unlink_wait_clear_audio_in_urbs(line6pcm); + + break; + + default: + MISSING_CASE; + } + if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) { line6pcm->count_out = 0; line6pcm->pos_out = 0; diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h index 77055b3724ad..55d8297dd3d9 100644 --- a/drivers/staging/line6/pcm.h +++ b/drivers/staging/line6/pcm.h @@ -39,9 +39,6 @@ #define LINE6_IMPULSE_DEFAULT_PERIOD 100 #endif -#define LINE6_BACKUP_MONITOR_SIGNAL 0 -#define LINE6_REUSE_DMA_AREA_FOR_PLAYBACK 0 - /* Get substream from Line6 PCM data structure */ @@ -149,11 +146,6 @@ struct snd_line6_pcm { unsigned char *buffer_in; /** - Temporary buffer index for playback. - */ - int index_out; - - /** Previously captured frame (for software monitoring). */ unsigned char *prev_fbuf; diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 10c543836583..4152db2328b7 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -9,6 +9,7 @@ * */ +#include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -191,13 +192,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_frames = urb_size / bytes_per_frame; urb_out->transfer_buffer = line6pcm->buffer_out + - line6pcm->max_packet_size * line6pcm->index_out; + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; urb_out->transfer_buffer_length = urb_size; urb_out->context = line6pcm; - if (++line6pcm->index_out == LINE6_ISO_BUFFERS) - line6pcm->index_out = 0; - if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) && !test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) { struct snd_pcm_runtime *runtime = @@ -222,18 +220,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) } else dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", len); /* this is somewhat paranoid */ } else { -#if LINE6_REUSE_DMA_AREA_FOR_PLAYBACK - /* set the buffer pointer */ - urb_out->transfer_buffer = - runtime->dma_area + - line6pcm->pos_out * bytes_per_frame; -#else - /* copy data */ memcpy(urb_out->transfer_buffer, runtime->dma_area + line6pcm->pos_out * bytes_per_frame, urb_out->transfer_buffer_length); -#endif } line6pcm->pos_out += urb_frames; @@ -361,6 +351,31 @@ void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) wait_clear_audio_out_urbs(line6pcm); } +int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm) +{ + /* We may be invoked multiple times in a row so allocate once only */ + if (line6pcm->buffer_out) + return 0; + + line6pcm->buffer_out = + kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + + if (!line6pcm->buffer_out) { + dev_err(line6pcm->line6->ifcdev, + "cannot malloc playback buffer\n"); + return -ENOMEM; + } + + return 0; +} + +void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) +{ + kfree(line6pcm->buffer_out); + line6pcm->buffer_out = NULL; +} + /* Callback for completed playback URB. */ @@ -469,6 +484,13 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, } /* -- [FD] end */ + if ((line6pcm->flags & MASK_PLAYBACK) == 0) { + ret = line6_alloc_playback_buffer(line6pcm); + + if (ret < 0) + return ret; + } + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) @@ -481,6 +503,13 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, /* hw_free playback callback */ static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) { + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + + if ((line6pcm->flags & MASK_PLAYBACK) == 0) { + line6_unlink_wait_clear_audio_out_urbs(line6pcm); + line6_free_playback_buffer(line6pcm); + } + return snd_pcm_lib_free_pages(substream); } diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h index f2fc8c0526e3..02487ff24538 100644 --- a/drivers/staging/line6/playback.h +++ b/drivers/staging/line6/playback.h @@ -29,7 +29,9 @@ extern struct snd_pcm_ops snd_line6_playback_ops; +extern int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm); extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); +extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index d9b30212585c..4dadc571d961 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -1149,14 +1149,10 @@ static struct snd_kcontrol_new pod_control_monitor = { static void pod_destruct(struct usb_interface *interface) { struct usb_line6_pod *pod = usb_get_intfdata(interface); - struct usb_line6 *line6; if (pod == NULL) return; - line6 = &pod->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&pod->line6); del_timer(&pod->startup_timer); cancel_work_sync(&pod->startup_work); diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c new file mode 100644 index 000000000000..7ef45437b4f2 --- /dev/null +++ b/drivers/staging/line6/podhd.c @@ -0,0 +1,154 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> + * + * 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 <sound/core.h> +#include <sound/pcm.h> + +#include "audio.h" +#include "driver.h" +#include "pcm.h" +#include "podhd.h" + +#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ + +static struct snd_ratden podhd_ratden = { + .num_min = 48000, + .num_max = 48000, + .num_step = 1, + .den = 1, +}; + +static struct line6_pcm_properties podhd_pcm_properties = { + .snd_line6_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + 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, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + 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, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 60000, + .period_bytes_min = 64, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 1024}, + .snd_line6_rates = { + .nrats = 1, + .rats = &podhd_ratden}, + .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); +} + +/* + Try to init POD HD device. +*/ +static int podhd_try_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd) +{ + int err; + struct usb_line6 *line6 = &podhd->line6; + + if ((interface == NULL) || (podhd == NULL)) + return -ENODEV; + + /* initialize audio system: */ + err = line6_init_audio(line6); + if (err < 0) + return err; + + /* initialize MIDI subsystem: */ + err = line6_init_midi(line6); + if (err < 0) + return err; + + /* initialize PCM subsystem: */ + err = line6_init_pcm(line6, &podhd_pcm_properties); + if (err < 0) + return err; + + /* register USB audio system: */ + err = line6_register_audio(line6); + return err; +} + +/* + Init POD HD device (and clean up in case of failure). +*/ +int line6_podhd_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd) +{ + int err = podhd_try_init(interface, podhd); + + if (err < 0) + podhd_destruct(interface); + + return err; +} + +/* + POD HD device disconnected. +*/ +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); +} diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h new file mode 100644 index 000000000000..652f74056bb9 --- /dev/null +++ b/drivers/staging/line6/podhd.h @@ -0,0 +1,30 @@ +/* + * Line6 Pod HD + * + * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> + * + * 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 <linux/usb.h> + +#include "driver.h" + +struct usb_line6_podhd { + /** + Generic Line6 USB data. + */ + struct usb_line6 line6; +}; + +extern void line6_podhd_disconnect(struct usb_interface *interface); +extern int line6_podhd_init(struct usb_interface *interface, + struct usb_line6_podhd *podhd); + +#endif /* PODHD_H */ diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h index 350d0dfff8f8..b4eee2b73831 100644 --- a/drivers/staging/line6/revision.h +++ b/drivers/staging/line6/revision.h @@ -1,4 +1,4 @@ #ifndef DRIVER_REVISION /* current subversion revision */ -#define DRIVER_REVISION " (revision 690)" +#define DRIVER_REVISION " (904)" #endif diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 879e6992bbc6..f31057830dbc 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -295,14 +295,10 @@ static struct snd_kcontrol_new toneport_control_source = { static void toneport_destruct(struct usb_interface *interface) { struct usb_line6_toneport *toneport = usb_get_intfdata(interface); - struct usb_line6 *line6; if (toneport == NULL) return; - line6 = &toneport->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&toneport->line6); } /* diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index c6dffe6bc1a5..aff9e5caea46 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -24,6 +24,8 @@ #define LINE6_DEVID_BASSPODXTPRO 0x4252 #define LINE6_DEVID_GUITARPORT 0x4750 #define LINE6_DEVID_POCKETPOD 0x5051 +#define LINE6_DEVID_PODHD300 0x5057 +#define LINE6_DEVID_PODHD500 0x414D #define LINE6_DEVID_PODSTUDIO_GX 0x4153 #define LINE6_DEVID_PODSTUDIO_UX1 0x4150 #define LINE6_DEVID_PODSTUDIO_UX2 0x4151 @@ -37,48 +39,71 @@ #define LINE6_DEVID_TONEPORT_UX2 0x4142 #define LINE6_DEVID_VARIAX 0x534d -#define LINE6_BIT_BASSPODXT (1 << 0) -#define LINE6_BIT_BASSPODXTLIVE (1 << 1) -#define LINE6_BIT_BASSPODXTPRO (1 << 2) -#define LINE6_BIT_GUITARPORT (1 << 3) -#define LINE6_BIT_POCKETPOD (1 << 4) -#define LINE6_BIT_PODSTUDIO_GX (1 << 5) -#define LINE6_BIT_PODSTUDIO_UX1 (1 << 6) -#define LINE6_BIT_PODSTUDIO_UX2 (1 << 7) -#define LINE6_BIT_PODX3 (1 << 8) -#define LINE6_BIT_PODX3LIVE (1 << 9) -#define LINE6_BIT_PODXT (1 << 10) -#define LINE6_BIT_PODXTLIVE (1 << 11) -#define LINE6_BIT_PODXTPRO (1 << 12) -#define LINE6_BIT_TONEPORT_GX (1 << 13) -#define LINE6_BIT_TONEPORT_UX1 (1 << 14) -#define LINE6_BIT_TONEPORT_UX2 (1 << 15) -#define LINE6_BIT_VARIAX (1 << 16) +enum { + LINE6_ID_BASSPODXT, + LINE6_ID_BASSPODXTLIVE, + LINE6_ID_BASSPODXTPRO, + LINE6_ID_GUITARPORT, + LINE6_ID_POCKETPOD, + LINE6_ID_PODHD300, + LINE6_ID_PODHD500, + LINE6_ID_PODSTUDIO_GX, + LINE6_ID_PODSTUDIO_UX1, + LINE6_ID_PODSTUDIO_UX2, + LINE6_ID_PODX3, + LINE6_ID_PODX3LIVE, + LINE6_ID_PODXT, + LINE6_ID_PODXTLIVE, + LINE6_ID_PODXTPRO, + LINE6_ID_TONEPORT_GX, + LINE6_ID_TONEPORT_UX1, + LINE6_ID_TONEPORT_UX2, + LINE6_ID_VARIAX +}; -#define LINE6_BITS_PRO (LINE6_BIT_BASSPODXTPRO | \ - LINE6_BIT_PODXTPRO) -#define LINE6_BITS_LIVE (LINE6_BIT_BASSPODXTLIVE | \ - LINE6_BIT_PODXTLIVE | \ - LINE6_BIT_PODX3LIVE) -#define LINE6_BITS_PODXTALL (LINE6_BIT_PODXT | \ - LINE6_BIT_PODXTLIVE | \ - LINE6_BIT_PODXTPRO) -#define LINE6_BITS_BASSPODXTALL (LINE6_BIT_BASSPODXT | \ - LINE6_BIT_BASSPODXTLIVE | \ - LINE6_BIT_BASSPODXTPRO) +#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_ID_ ## x + +enum { + LINE6_BIT(BASSPODXT), + LINE6_BIT(BASSPODXTLIVE), + LINE6_BIT(BASSPODXTPRO), + LINE6_BIT(GUITARPORT), + LINE6_BIT(POCKETPOD), + LINE6_BIT(PODHD300), + LINE6_BIT(PODHD500), + LINE6_BIT(PODSTUDIO_GX), + LINE6_BIT(PODSTUDIO_UX1), + LINE6_BIT(PODSTUDIO_UX2), + LINE6_BIT(PODX3), + LINE6_BIT(PODX3LIVE), + LINE6_BIT(PODXT), + LINE6_BIT(PODXTLIVE), + LINE6_BIT(PODXTPRO), + LINE6_BIT(TONEPORT_GX), + LINE6_BIT(TONEPORT_UX1), + LINE6_BIT(TONEPORT_UX2), + LINE6_BIT(VARIAX), + + LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO, + LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE | LINE6_BIT_PODX3LIVE, + LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE | LINE6_BIT_PODXTPRO, + LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE, + LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | LINE6_BIT_PODHD500, + LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT | LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_BASSPODXTPRO +}; /* device supports settings parameter via USB */ -#define LINE6_BIT_CONTROL (1 << 0) +#define LINE6_BIT_CONTROL (1 << 0) /* device supports PCM input/output via USB */ -#define LINE6_BIT_PCM (1 << 1) +#define LINE6_BIT_PCM (1 << 1) /* device support hardware monitoring */ -#define LINE6_BIT_HWMON (1 << 2) +#define LINE6_BIT_HWMON (1 << 2) #define LINE6_BIT_CONTROL_PCM_HWMON (LINE6_BIT_CONTROL | \ LINE6_BIT_PCM | \ LINE6_BIT_HWMON) -#define LINE6_FALLBACK_INTERVAL 10 -#define LINE6_FALLBACK_MAXPACKETSIZE 16 +#define LINE6_FALLBACK_INTERVAL 10 +#define LINE6_FALLBACK_MAXPACKETSIZE 16 #endif diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index 81241cdf1be9..d36622228b2d 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -572,14 +572,10 @@ static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2); static void variax_destruct(struct usb_interface *interface) { struct usb_line6_variax *variax = usb_get_intfdata(interface); - struct usb_line6 *line6; if (variax == NULL) return; - line6 = &variax->line6; - if (line6 == NULL) - return; - line6_cleanup_audio(line6); + line6_cleanup_audio(&variax->line6); del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer2); |