Loading sound/usb/line6/Kconfig +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ config SND_USB_PODHD config SND_USB_TONEPORT tristate "TonePort GX, UX1 and UX2 USB support" select SND_USB_LINE6 select NEW_LEDS select LEDS_CLASS help This is a driver for TonePort GX, UX1 and UX2 devices. Loading sound/usb/line6/capture.c +39 −184 Original line number Diff line number Diff line Loading @@ -20,26 +20,24 @@ /* Find a free URB and submit it. must be called in line6pcm->in.lock context */ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) { int index; unsigned long flags; int i, urb_size; int ret; struct urb *urb_in; spin_lock_irqsave(&line6pcm->lock_audio_in, flags); index = find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS); if (index < 0 || index >= LINE6_ISO_BUFFERS) { spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); return -EINVAL; } urb_in = line6pcm->urb_audio_in[index]; urb_in = line6pcm->in.urbs[index]; urb_size = 0; for (i = 0; i < LINE6_ISO_PACKETS; ++i) { Loading @@ -51,7 +49,7 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) } urb_in->transfer_buffer = line6pcm->buffer_in + line6pcm->in.buffer + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; urb_in->transfer_buffer_length = urb_size; urb_in->context = line6pcm; Loading @@ -59,81 +57,29 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) ret = usb_submit_urb(urb_in, GFP_ATOMIC); if (ret == 0) set_bit(index, &line6pcm->active_urb_in); set_bit(index, &line6pcm->in.active_urbs); else dev_err(line6pcm->line6->ifcdev, "URB in #%d submission failed (%d)\n", index, ret); spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); return 0; } /* Submit all currently available capture URBs. must be called in line6pcm->in.lock context */ int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) { int ret, i; int ret = 0, i; for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_in_urb(line6pcm); if (ret < 0) return ret; } return 0; } /* Unlink all currently active capture URBs. */ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) { unsigned int i; for (i = LINE6_ISO_BUFFERS; i--;) { if (test_bit(i, &line6pcm->active_urb_in)) { if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { struct urb *u = line6pcm->urb_audio_in[i]; usb_unlink_urb(u); } } } } /* Wait until unlinking of all currently active capture URBs has been finished. */ void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) { int timeout = HZ; unsigned int i; int alive; do { alive = 0; for (i = LINE6_ISO_BUFFERS; i--;) { if (test_bit(i, &line6pcm->active_urb_in)) alive++; } if (!alive) break; set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } while (--timeout > 0); if (alive) snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); } /* Unlink all currently active capture URBs, and wait for finishing. */ void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) { line6_unlink_audio_in_urbs(line6pcm); line6_wait_clear_audio_in_urbs(line6pcm); return ret; } /* Loading @@ -150,18 +96,18 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) if (runtime == NULL) return; if (line6pcm->pos_in_done + frames > runtime->buffer_size) { if (line6pcm->in.pos_done + frames > runtime->buffer_size) { /* The transferred area goes over buffer boundary, copy two separate chunks. */ int len; len = runtime->buffer_size - line6pcm->pos_in_done; len = runtime->buffer_size - line6pcm->in.pos_done; if (len > 0) { memcpy(runtime->dma_area + line6pcm->pos_in_done * bytes_per_frame, fbuf, line6pcm->in.pos_done * bytes_per_frame, fbuf, len * bytes_per_frame); memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, (frames - len) * bytes_per_frame); Loading @@ -173,12 +119,12 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) } else { /* copy single chunk */ memcpy(runtime->dma_area + line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize); } line6pcm->pos_in_done += frames; if (line6pcm->pos_in_done >= runtime->buffer_size) line6pcm->pos_in_done -= runtime->buffer_size; line6pcm->in.pos_done += frames; if (line6pcm->in.pos_done >= runtime->buffer_size) line6pcm->in.pos_done -= runtime->buffer_size; } void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) Loading @@ -186,19 +132,15 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) struct snd_pcm_substream *substream = get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); line6pcm->bytes_in += length; if (line6pcm->bytes_in >= line6pcm->period_in) { line6pcm->bytes_in %= line6pcm->period_in; line6pcm->in.bytes += length; if (line6pcm->in.bytes >= line6pcm->in.period) { line6pcm->in.bytes %= line6pcm->in.period; spin_unlock(&line6pcm->in.lock); snd_pcm_period_elapsed(substream); spin_lock(&line6pcm->in.lock); } } void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) { kfree(line6pcm->buffer_in); line6pcm->buffer_in = NULL; } /* * Callback for completed capture URB. */ Loading @@ -209,14 +151,14 @@ static void audio_in_callback(struct urb *urb) struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; line6pcm->last_frame_in = urb->start_frame; line6pcm->in.last_frame = urb->start_frame; /* find index of URB */ for (index = 0; index < LINE6_ISO_BUFFERS; ++index) if (urb == line6pcm->urb_audio_in[index]) if (urb == line6pcm->in.urbs[index]) break; spin_lock_irqsave(&line6pcm->lock_audio_in, flags); spin_lock_irqsave(&line6pcm->in.lock, flags); for (i = 0; i < LINE6_ISO_PACKETS; ++i) { char *fbuf; Loading @@ -243,27 +185,26 @@ static void audio_in_callback(struct urb *urb) line6pcm->prev_fbuf = fbuf; line6pcm->prev_fsize = fsize; if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags) && (fsize > 0)) if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) && fsize > 0) line6_capture_copy(line6pcm, fbuf, fsize); } clear_bit(index, &line6pcm->active_urb_in); clear_bit(index, &line6pcm->in.active_urbs); if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs)) shutdown = 1; spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); if (!shutdown) { submit_audio_in_urb(line6pcm); if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)) if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) line6_capture_check_period(line6pcm, length); } spin_unlock_irqrestore(&line6pcm->in.lock, flags); } /* open capture callback */ Loading @@ -290,102 +231,16 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) return 0; } /* hw_params capture callback */ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int ret; struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); /* -- Florian Demski [FD] */ /* don't ask me why, but this fixes the bug on my machine */ if (line6pcm == NULL) { if (substream->pcm == NULL) return -ENOMEM; if (substream->pcm->private_data == NULL) return -ENOMEM; substream->private_data = substream->pcm->private_data; line6pcm = snd_pcm_substream_chip(substream); } /* -- [FD] end */ ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); if (ret < 0) return ret; ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) { line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); return ret; } line6pcm->period_in = params_period_bytes(hw_params); return 0; } /* 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); line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); return snd_pcm_lib_free_pages(substream); } /* trigger callback */ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) { int err; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); if (err < 0) return err; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); if (err < 0) return err; break; default: return -EINVAL; } return 0; } /* capture pointer callback */ static snd_pcm_uframes_t snd_line6_capture_pointer(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); return line6pcm->pos_in_done; } /* capture operators */ struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, .close = snd_line6_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_line6_capture_hw_params, .hw_free = snd_line6_capture_hw_free, .hw_params = snd_line6_hw_params, .hw_free = snd_line6_hw_free, .prepare = snd_line6_prepare, .trigger = snd_line6_trigger, .pointer = snd_line6_capture_pointer, .pointer = snd_line6_pointer, }; int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) Loading @@ -398,7 +253,7 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) struct urb *urb; /* URB for audio in: */ urb = line6pcm->urb_audio_in[i] = urb = line6pcm->in.urbs[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); if (urb == NULL) Loading sound/usb/line6/capture.h +0 −6 Original line number Diff line number Diff line Loading @@ -24,12 +24,6 @@ extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, 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 *line6pcm); extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm); extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); #endif sound/usb/line6/driver.c +92 −110 Original line number Diff line number Diff line Loading @@ -412,27 +412,13 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) } EXPORT_SYMBOL_GPL(line6_read_serial_number); /* No operation (i.e., unsupported). */ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } EXPORT_SYMBOL_GPL(line6_nop_read); /* Card destructor. */ static void line6_destruct(struct snd_card *card) { struct usb_line6 *line6 = card->private_data; struct usb_device *usbdev; if (!line6) return; usbdev = line6->usbdev; struct usb_device *usbdev = line6->usbdev; /* free buffer memory first: */ kfree(line6->buffer_message); Loading @@ -441,82 +427,96 @@ static void line6_destruct(struct snd_card *card) /* then free URBs: */ usb_free_urb(line6->urb_listen); /* free interface data: */ kfree(line6); /* decrement reference counters: */ usb_put_dev(usbdev); } /* get data from endpoint descriptor (see usb_maxpacket): */ static void line6_get_interval(struct usb_line6 *line6) { struct usb_device *usbdev = line6->usbdev; struct usb_host_endpoint *ep; unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r); unsigned epnum = usb_pipeendpoint(pipe); ep = usbdev->ep_in[epnum]; if (ep) { line6->interval = ep->desc.bInterval; line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { dev_err(line6->ifcdev, "endpoint not available, using fallback values"); line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; } } static int line6_init_cap_control(struct usb_line6 *line6) { int ret; /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (!line6->buffer_listen) return -ENOMEM; line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); if (!line6->buffer_message) return -ENOMEM; line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); if (!line6->urb_listen) return -ENOMEM; ret = line6_start_listen(line6); if (ret < 0) { dev_err(line6->ifcdev, "cannot start listening: %d\n", ret); return ret; } return 0; } /* Probe USB device. */ int line6_probe(struct usb_interface *interface, struct usb_line6 *line6, const struct usb_device_id *id, const struct line6_properties *properties, int (*private_init)(struct usb_interface *, struct usb_line6 *)) int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), size_t data_size) { struct usb_device *usbdev = interface_to_usbdev(interface); struct snd_card *card; struct usb_line6 *line6; int interface_number; int ret; /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) { ret = -ENODEV; goto err_put; } /* initialize device info: */ dev_info(&interface->dev, "Line 6 %s found\n", properties->name); if (WARN_ON(data_size < sizeof(*line6))) return -EINVAL; /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) return -ENODEV; ret = usb_set_interface(usbdev, interface_number, properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "set_interface failed\n"); goto err_put; } ret = snd_card_new(&interface->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, data_size, &card); if (ret < 0) return ret; /* store basic data: */ line6 = card->private_data; line6->card = card; line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; /* get data from endpoint descriptor (see usb_maxpacket): */ { struct usb_host_endpoint *ep; unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); unsigned epnum = usb_pipeendpoint(pipe); ep = usbdev->ep_in[epnum]; if (ep != NULL) { line6->interval = ep->desc.bInterval; line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; dev_err(line6->ifcdev, "endpoint not available, using fallback values"); } } 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->id, 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, strcpy(card->shortname, properties->name); sprintf(card->longname, "Line 6 %s at USB %s", properties->name, dev_name(line6->ifcdev)); card->private_data = line6; card->private_free = line6_destruct; usb_set_intfdata(interface, line6); Loading @@ -524,52 +524,43 @@ int line6_probe(struct usb_interface *interface, /* increment reference counters: */ usb_get_dev(usbdev); if (properties->capabilities & LINE6_CAP_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (line6->buffer_listen == NULL) { ret = -ENOMEM; goto err_destruct; } line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); if (line6->buffer_message == NULL) { ret = -ENOMEM; goto err_destruct; } line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); /* initialize device info: */ dev_info(&interface->dev, "Line 6 %s found\n", properties->name); if (line6->urb_listen == NULL) { ret = -ENOMEM; goto err_destruct; } /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; ret = line6_start_listen(line6); ret = usb_set_interface(usbdev, interface_number, properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "%s: usb_submit_urb failed\n", __func__); goto err_destruct; dev_err(&interface->dev, "set_interface failed\n"); goto error; } line6_get_interval(line6); if (properties->capabilities & LINE6_CAP_CONTROL) { ret = line6_init_cap_control(line6); if (ret < 0) goto error; } /* initialize device data based on device: */ ret = private_init(interface, line6); ret = private_init(line6, id); if (ret < 0) goto err_destruct; goto error; /* creation of additional special files should go here */ dev_info(&interface->dev, "Line 6 %s now attached\n", line6->properties->name); properties->name); return 0; err_destruct: error: if (line6->disconnect) line6->disconnect(line6); snd_card_free(card); err_put: return ret; } EXPORT_SYMBOL_GPL(line6_probe); Loading @@ -579,32 +570,23 @@ EXPORT_SYMBOL_GPL(line6_probe); */ void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number; struct usb_line6 *line6 = usb_get_intfdata(interface); struct usb_device *usbdev = interface_to_usbdev(interface); if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) if (!line6) return; interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (!line6) if (WARN_ON(usbdev != line6->usbdev)) return; if (line6->urb_listen != NULL) line6_stop_listen(line6); 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); line6->disconnect(line6); dev_info(&interface->dev, "Line 6 %s now disconnected\n", line6->properties->name); Loading sound/usb/line6/driver.h +5 −5 Original line number Diff line number Diff line Loading @@ -157,13 +157,11 @@ struct usb_line6 { int message_length; void (*process_message)(struct usb_line6 *); void (*disconnect)(struct usb_interface *); void (*disconnect)(struct usb_line6 *line6); }; extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, int size); extern ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, char *buf); 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, Loading @@ -182,9 +180,11 @@ 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 usb_device_id *id, const struct line6_properties *properties, int (*private_init)(struct usb_interface *, struct usb_line6 *)); int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), size_t data_size); void line6_disconnect(struct usb_interface *interface); #ifdef CONFIG_PM Loading Loading
sound/usb/line6/Kconfig +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ config SND_USB_PODHD config SND_USB_TONEPORT tristate "TonePort GX, UX1 and UX2 USB support" select SND_USB_LINE6 select NEW_LEDS select LEDS_CLASS help This is a driver for TonePort GX, UX1 and UX2 devices. Loading
sound/usb/line6/capture.c +39 −184 Original line number Diff line number Diff line Loading @@ -20,26 +20,24 @@ /* Find a free URB and submit it. must be called in line6pcm->in.lock context */ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) { int index; unsigned long flags; int i, urb_size; int ret; struct urb *urb_in; spin_lock_irqsave(&line6pcm->lock_audio_in, flags); index = find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS); if (index < 0 || index >= LINE6_ISO_BUFFERS) { spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); return -EINVAL; } urb_in = line6pcm->urb_audio_in[index]; urb_in = line6pcm->in.urbs[index]; urb_size = 0; for (i = 0; i < LINE6_ISO_PACKETS; ++i) { Loading @@ -51,7 +49,7 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) } urb_in->transfer_buffer = line6pcm->buffer_in + line6pcm->in.buffer + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; urb_in->transfer_buffer_length = urb_size; urb_in->context = line6pcm; Loading @@ -59,81 +57,29 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) ret = usb_submit_urb(urb_in, GFP_ATOMIC); if (ret == 0) set_bit(index, &line6pcm->active_urb_in); set_bit(index, &line6pcm->in.active_urbs); else dev_err(line6pcm->line6->ifcdev, "URB in #%d submission failed (%d)\n", index, ret); spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); return 0; } /* Submit all currently available capture URBs. must be called in line6pcm->in.lock context */ int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) { int ret, i; int ret = 0, i; for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_in_urb(line6pcm); if (ret < 0) return ret; } return 0; } /* Unlink all currently active capture URBs. */ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) { unsigned int i; for (i = LINE6_ISO_BUFFERS; i--;) { if (test_bit(i, &line6pcm->active_urb_in)) { if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { struct urb *u = line6pcm->urb_audio_in[i]; usb_unlink_urb(u); } } } } /* Wait until unlinking of all currently active capture URBs has been finished. */ void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) { int timeout = HZ; unsigned int i; int alive; do { alive = 0; for (i = LINE6_ISO_BUFFERS; i--;) { if (test_bit(i, &line6pcm->active_urb_in)) alive++; } if (!alive) break; set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } while (--timeout > 0); if (alive) snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); } /* Unlink all currently active capture URBs, and wait for finishing. */ void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) { line6_unlink_audio_in_urbs(line6pcm); line6_wait_clear_audio_in_urbs(line6pcm); return ret; } /* Loading @@ -150,18 +96,18 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) if (runtime == NULL) return; if (line6pcm->pos_in_done + frames > runtime->buffer_size) { if (line6pcm->in.pos_done + frames > runtime->buffer_size) { /* The transferred area goes over buffer boundary, copy two separate chunks. */ int len; len = runtime->buffer_size - line6pcm->pos_in_done; len = runtime->buffer_size - line6pcm->in.pos_done; if (len > 0) { memcpy(runtime->dma_area + line6pcm->pos_in_done * bytes_per_frame, fbuf, line6pcm->in.pos_done * bytes_per_frame, fbuf, len * bytes_per_frame); memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, (frames - len) * bytes_per_frame); Loading @@ -173,12 +119,12 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) } else { /* copy single chunk */ memcpy(runtime->dma_area + line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize); } line6pcm->pos_in_done += frames; if (line6pcm->pos_in_done >= runtime->buffer_size) line6pcm->pos_in_done -= runtime->buffer_size; line6pcm->in.pos_done += frames; if (line6pcm->in.pos_done >= runtime->buffer_size) line6pcm->in.pos_done -= runtime->buffer_size; } void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) Loading @@ -186,19 +132,15 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) struct snd_pcm_substream *substream = get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); line6pcm->bytes_in += length; if (line6pcm->bytes_in >= line6pcm->period_in) { line6pcm->bytes_in %= line6pcm->period_in; line6pcm->in.bytes += length; if (line6pcm->in.bytes >= line6pcm->in.period) { line6pcm->in.bytes %= line6pcm->in.period; spin_unlock(&line6pcm->in.lock); snd_pcm_period_elapsed(substream); spin_lock(&line6pcm->in.lock); } } void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) { kfree(line6pcm->buffer_in); line6pcm->buffer_in = NULL; } /* * Callback for completed capture URB. */ Loading @@ -209,14 +151,14 @@ static void audio_in_callback(struct urb *urb) struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; line6pcm->last_frame_in = urb->start_frame; line6pcm->in.last_frame = urb->start_frame; /* find index of URB */ for (index = 0; index < LINE6_ISO_BUFFERS; ++index) if (urb == line6pcm->urb_audio_in[index]) if (urb == line6pcm->in.urbs[index]) break; spin_lock_irqsave(&line6pcm->lock_audio_in, flags); spin_lock_irqsave(&line6pcm->in.lock, flags); for (i = 0; i < LINE6_ISO_PACKETS; ++i) { char *fbuf; Loading @@ -243,27 +185,26 @@ static void audio_in_callback(struct urb *urb) line6pcm->prev_fbuf = fbuf; line6pcm->prev_fsize = fsize; if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags) && (fsize > 0)) if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) && fsize > 0) line6_capture_copy(line6pcm, fbuf, fsize); } clear_bit(index, &line6pcm->active_urb_in); clear_bit(index, &line6pcm->in.active_urbs); if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs)) shutdown = 1; spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); if (!shutdown) { submit_audio_in_urb(line6pcm); if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)) if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) line6_capture_check_period(line6pcm, length); } spin_unlock_irqrestore(&line6pcm->in.lock, flags); } /* open capture callback */ Loading @@ -290,102 +231,16 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) return 0; } /* hw_params capture callback */ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int ret; struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); /* -- Florian Demski [FD] */ /* don't ask me why, but this fixes the bug on my machine */ if (line6pcm == NULL) { if (substream->pcm == NULL) return -ENOMEM; if (substream->pcm->private_data == NULL) return -ENOMEM; substream->private_data = substream->pcm->private_data; line6pcm = snd_pcm_substream_chip(substream); } /* -- [FD] end */ ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); if (ret < 0) return ret; ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) { line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); return ret; } line6pcm->period_in = params_period_bytes(hw_params); return 0; } /* 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); line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); return snd_pcm_lib_free_pages(substream); } /* trigger callback */ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) { int err; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); if (err < 0) return err; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); if (err < 0) return err; break; default: return -EINVAL; } return 0; } /* capture pointer callback */ static snd_pcm_uframes_t snd_line6_capture_pointer(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); return line6pcm->pos_in_done; } /* capture operators */ struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, .close = snd_line6_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_line6_capture_hw_params, .hw_free = snd_line6_capture_hw_free, .hw_params = snd_line6_hw_params, .hw_free = snd_line6_hw_free, .prepare = snd_line6_prepare, .trigger = snd_line6_trigger, .pointer = snd_line6_capture_pointer, .pointer = snd_line6_pointer, }; int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) Loading @@ -398,7 +253,7 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) struct urb *urb; /* URB for audio in: */ urb = line6pcm->urb_audio_in[i] = urb = line6pcm->in.urbs[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); if (urb == NULL) Loading
sound/usb/line6/capture.h +0 −6 Original line number Diff line number Diff line Loading @@ -24,12 +24,6 @@ extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, 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 *line6pcm); extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm); extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); #endif
sound/usb/line6/driver.c +92 −110 Original line number Diff line number Diff line Loading @@ -412,27 +412,13 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) } EXPORT_SYMBOL_GPL(line6_read_serial_number); /* No operation (i.e., unsupported). */ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } EXPORT_SYMBOL_GPL(line6_nop_read); /* Card destructor. */ static void line6_destruct(struct snd_card *card) { struct usb_line6 *line6 = card->private_data; struct usb_device *usbdev; if (!line6) return; usbdev = line6->usbdev; struct usb_device *usbdev = line6->usbdev; /* free buffer memory first: */ kfree(line6->buffer_message); Loading @@ -441,82 +427,96 @@ static void line6_destruct(struct snd_card *card) /* then free URBs: */ usb_free_urb(line6->urb_listen); /* free interface data: */ kfree(line6); /* decrement reference counters: */ usb_put_dev(usbdev); } /* get data from endpoint descriptor (see usb_maxpacket): */ static void line6_get_interval(struct usb_line6 *line6) { struct usb_device *usbdev = line6->usbdev; struct usb_host_endpoint *ep; unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r); unsigned epnum = usb_pipeendpoint(pipe); ep = usbdev->ep_in[epnum]; if (ep) { line6->interval = ep->desc.bInterval; line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { dev_err(line6->ifcdev, "endpoint not available, using fallback values"); line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; } } static int line6_init_cap_control(struct usb_line6 *line6) { int ret; /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (!line6->buffer_listen) return -ENOMEM; line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); if (!line6->buffer_message) return -ENOMEM; line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); if (!line6->urb_listen) return -ENOMEM; ret = line6_start_listen(line6); if (ret < 0) { dev_err(line6->ifcdev, "cannot start listening: %d\n", ret); return ret; } return 0; } /* Probe USB device. */ int line6_probe(struct usb_interface *interface, struct usb_line6 *line6, const struct usb_device_id *id, const struct line6_properties *properties, int (*private_init)(struct usb_interface *, struct usb_line6 *)) int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), size_t data_size) { struct usb_device *usbdev = interface_to_usbdev(interface); struct snd_card *card; struct usb_line6 *line6; int interface_number; int ret; /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) { ret = -ENODEV; goto err_put; } /* initialize device info: */ dev_info(&interface->dev, "Line 6 %s found\n", properties->name); if (WARN_ON(data_size < sizeof(*line6))) return -EINVAL; /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; /* we don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) return -ENODEV; ret = usb_set_interface(usbdev, interface_number, properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "set_interface failed\n"); goto err_put; } ret = snd_card_new(&interface->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, data_size, &card); if (ret < 0) return ret; /* store basic data: */ line6 = card->private_data; line6->card = card; line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; /* get data from endpoint descriptor (see usb_maxpacket): */ { struct usb_host_endpoint *ep; unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); unsigned epnum = usb_pipeendpoint(pipe); ep = usbdev->ep_in[epnum]; if (ep != NULL) { line6->interval = ep->desc.bInterval; line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; dev_err(line6->ifcdev, "endpoint not available, using fallback values"); } } 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->id, 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, strcpy(card->shortname, properties->name); sprintf(card->longname, "Line 6 %s at USB %s", properties->name, dev_name(line6->ifcdev)); card->private_data = line6; card->private_free = line6_destruct; usb_set_intfdata(interface, line6); Loading @@ -524,52 +524,43 @@ int line6_probe(struct usb_interface *interface, /* increment reference counters: */ usb_get_dev(usbdev); if (properties->capabilities & LINE6_CAP_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (line6->buffer_listen == NULL) { ret = -ENOMEM; goto err_destruct; } line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); if (line6->buffer_message == NULL) { ret = -ENOMEM; goto err_destruct; } line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); /* initialize device info: */ dev_info(&interface->dev, "Line 6 %s found\n", properties->name); if (line6->urb_listen == NULL) { ret = -ENOMEM; goto err_destruct; } /* query interface number */ interface_number = interface->cur_altsetting->desc.bInterfaceNumber; ret = line6_start_listen(line6); ret = usb_set_interface(usbdev, interface_number, properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "%s: usb_submit_urb failed\n", __func__); goto err_destruct; dev_err(&interface->dev, "set_interface failed\n"); goto error; } line6_get_interval(line6); if (properties->capabilities & LINE6_CAP_CONTROL) { ret = line6_init_cap_control(line6); if (ret < 0) goto error; } /* initialize device data based on device: */ ret = private_init(interface, line6); ret = private_init(line6, id); if (ret < 0) goto err_destruct; goto error; /* creation of additional special files should go here */ dev_info(&interface->dev, "Line 6 %s now attached\n", line6->properties->name); properties->name); return 0; err_destruct: error: if (line6->disconnect) line6->disconnect(line6); snd_card_free(card); err_put: return ret; } EXPORT_SYMBOL_GPL(line6_probe); Loading @@ -579,32 +570,23 @@ EXPORT_SYMBOL_GPL(line6_probe); */ void line6_disconnect(struct usb_interface *interface) { struct usb_line6 *line6; struct usb_device *usbdev; int interface_number; struct usb_line6 *line6 = usb_get_intfdata(interface); struct usb_device *usbdev = interface_to_usbdev(interface); if (interface == NULL) return; usbdev = interface_to_usbdev(interface); if (usbdev == NULL) if (!line6) return; interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); if (!line6) if (WARN_ON(usbdev != line6->usbdev)) return; if (line6->urb_listen != NULL) line6_stop_listen(line6); 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); line6->disconnect(line6); dev_info(&interface->dev, "Line 6 %s now disconnected\n", line6->properties->name); Loading
sound/usb/line6/driver.h +5 −5 Original line number Diff line number Diff line Loading @@ -157,13 +157,11 @@ struct usb_line6 { int message_length; void (*process_message)(struct usb_line6 *); void (*disconnect)(struct usb_interface *); void (*disconnect)(struct usb_line6 *line6); }; extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, int size); extern ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, char *buf); 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, Loading @@ -182,9 +180,11 @@ 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 usb_device_id *id, const struct line6_properties *properties, int (*private_init)(struct usb_interface *, struct usb_line6 *)); int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), size_t data_size); void line6_disconnect(struct usb_interface *interface); #ifdef CONFIG_PM Loading