From 270fd9c7f91fe8be900ede740ceeaa4abefa5d98 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 08:40:51 +0100 Subject: ALSA: line6: Yet more cleanup of superfluous NULL checks ... in line6_disconnect() as well. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 93cd4daa56bc..e8d51381ffdb 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -579,18 +579,9 @@ EXPORT_SYMBOL_GPL(line6_probe); */ void line6_disconnect(struct usb_interface *interface) { - struct usb_line6 *line6; - struct usb_device *usbdev; - int interface_number; - - if (interface == NULL) - return; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return; + struct usb_line6 *line6 = usb_get_intfdata(interface); + struct usb_device *usbdev = interface_to_usbdev(interface); - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - line6 = usb_get_intfdata(interface); if (!line6) return; -- cgit From 2a324fcdb568f4d7b0b65b271039beb987f6e1cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 09:58:54 +0100 Subject: ALSA: line6: Abort if inconsistent usbdev is found at disconnect It's utterly unsafe to proceed further the disconnect procedure if the assigned usbdev is inconsistent with the expected object. Better to put a WARN_ON() for more cautions and abort immediately. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index e8d51381ffdb..625272fe227a 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -585,12 +585,12 @@ void line6_disconnect(struct usb_interface *interface) if (!line6) return; + 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); -- cgit From 8a3b7c086a509d90c312ebab6d8e5a9bf48c6cf5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 08:42:42 +0100 Subject: ALSA: line6: Remove superfluous NULL checks in each driver The interface and driver objects are always set when callbacks are called. Drop such superfluous NULL checks in init and disconnect calls of each driver. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pod.c | 28 ++++++++-------------------- sound/usb/line6/podhd.c | 4 ---- sound/usb/line6/toneport.c | 6 ------ sound/usb/line6/variax.c | 8 -------- 4 files changed, 8 insertions(+), 38 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index bf027fc70cba..26ecf26a33ec 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -401,25 +401,16 @@ static struct snd_kcontrol_new pod_control_monitor = { */ static void line6_pod_disconnect(struct usb_interface *interface) { - struct usb_line6_pod *pod; - - if (interface == NULL) - return; - pod = usb_get_intfdata(interface); - - if (pod != NULL) { - struct device *dev = &interface->dev; + struct usb_line6_pod *pod = usb_get_intfdata(interface); + struct device *dev = &interface->dev; - 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); - } + /* 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); - del_timer_sync(&pod->startup_timer); - cancel_work_sync(&pod->startup_work); - } + del_timer_sync(&pod->startup_timer); + cancel_work_sync(&pod->startup_work); } /* @@ -456,9 +447,6 @@ static int pod_init(struct usb_interface *interface, init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, pod_startup4); - if ((interface == NULL) || (pod == NULL)) - return -ENODEV; - /* create sysfs entries: */ err = pod_create_files2(&interface->dev); if (err < 0) diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 7217fa7e5db1..59abbd92624e 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -90,12 +90,8 @@ static struct line6_pcm_properties podhd_pcm_properties = { static int podhd_init(struct usb_interface *interface, struct usb_line6 *line6) { - struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; int err; - if ((interface == NULL) || (podhd == NULL)) - return -ENODEV; - /* initialize MIDI subsystem: */ err = line6_init_midi(line6); if (err < 0) diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index c1f61cde52ab..e5669bd3233a 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -370,9 +370,6 @@ static void line6_toneport_disconnect(struct usb_interface *interface) struct usb_line6_toneport *toneport; u16 idProduct; - if (interface == NULL) - return; - toneport = usb_get_intfdata(interface); del_timer_sync(&toneport->timer); idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); @@ -393,9 +390,6 @@ static int toneport_init(struct usb_interface *interface, int err; struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; - if ((interface == NULL) || (toneport == NULL)) - return -ENODEV; - line6->disconnect = line6_toneport_disconnect; /* initialize PCM subsystem: */ diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index 99a58cbfd2da..cd3adeffde02 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -214,12 +214,7 @@ static void line6_variax_disconnect(struct usb_interface *interface) { struct usb_line6_variax *variax; - if (!interface) - return; - variax = usb_get_intfdata(interface); - if (!variax) - return; del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer2); @@ -244,9 +239,6 @@ static int variax_init(struct usb_interface *interface, init_timer(&variax->startup_timer2); INIT_WORK(&variax->startup_work, variax_startup6); - if ((interface == NULL) || (variax == NULL)) - return -ENODEV; - /* initialize USB buffers: */ variax->buffer_activate = kmemdup(variax_activate, sizeof(variax_activate), GFP_KERNEL); -- cgit From 6dd1c05cd7c26a463bbcca1ab50b59b86d88de64 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 09:40:20 +0100 Subject: ALSA: line6/toneport: Move setup_timer() at the beginning ... so that timer_del_sync() in the destructor can be called safely at any time. Also move the mod_timer() call in toneport_setup(), which is a bit clearer place. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/toneport.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index e5669bd3233a..fb6d5e1e2ade 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -360,6 +360,8 @@ static void toneport_setup(struct usb_line6_toneport *toneport) if (toneport_has_led(toneport->type)) toneport_update_led(&usbdev->dev); + + mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); } /* @@ -390,6 +392,9 @@ static int toneport_init(struct usb_interface *interface, int err; struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; + setup_timer(&toneport->timer, toneport_start_pcm, + (unsigned long)toneport); + line6->disconnect = line6_toneport_disconnect; /* initialize PCM subsystem: */ @@ -435,10 +440,6 @@ static int toneport_init(struct usb_interface *interface, toneport_setup(toneport); - setup_timer(&toneport->timer, toneport_start_pcm, - (unsigned long)toneport); - mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); - /* register audio system: */ return snd_card_register(line6->card); } -- cgit From eedd0e95d355c7bc09df1481ef92511f631832b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 09:09:27 +0100 Subject: ALSA: line6: Don't forget to call driver's destructor at error path Currently disconnect callback is used as a driver's destructor, and this has to be called not only at the disconnection time but also at the error paths during probe. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 625272fe227a..e7f9a99e1949 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -568,6 +568,8 @@ int line6_probe(struct usb_interface *interface, return 0; err_destruct: + if (line6->disconnect) + line6->disconnect(interface); snd_card_free(card); err_put: return ret; -- cgit From bf115fcf957f080a1766bb785e23980c1440d06e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 08:55:06 +0100 Subject: ALSA: line6/toneport: Fix wrong argument for toneport_has_led() Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/toneport.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index fb6d5e1e2ade..9a4f5403569e 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -370,13 +370,11 @@ static void toneport_setup(struct usb_line6_toneport *toneport) static void line6_toneport_disconnect(struct usb_interface *interface) { struct usb_line6_toneport *toneport; - u16 idProduct; toneport = usb_get_intfdata(interface); del_timer_sync(&toneport->timer); - idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); - if (toneport_has_led(idProduct)) { + if (toneport_has_led(toneport->type)) { device_remove_file(&interface->dev, &dev_attr_led_red); device_remove_file(&interface->dev, &dev_attr_led_green); } -- cgit From f44edd7b2bbeddef602fe84d3b175818024d7fce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 20 Jan 2015 09:36:31 +0100 Subject: ALSA: line6/toneport: Implement LED controls via LED class Instead of non-standard sysfs, reimplement the LED controls on TonePort as LED class devices. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/Kconfig | 2 + sound/usb/line6/toneport.c | 163 +++++++++++++++++++++++++-------------------- 2 files changed, 91 insertions(+), 74 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig index af20947e0bda..f4585d378ef3 100644 --- a/sound/usb/line6/Kconfig +++ b/sound/usb/line6/Kconfig @@ -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. diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 9a4f5403569e..9a769463f7bf 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,15 @@ enum line6_device_type { LINE6_TONEPORT_UX2, }; +struct usb_line6_toneport; + +struct toneport_led { + struct led_classdev dev; + char name[64]; + struct usb_line6_toneport *toneport; + bool registered; +}; + struct usb_line6_toneport { /** Generic Line 6 USB data. @@ -62,6 +72,9 @@ struct usb_line6_toneport { Device type. */ enum line6_device_type type; + + /* LED instances */ + struct toneport_led leds[2]; }; static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); @@ -117,15 +130,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { .bytes_per_frame = 4 }; -/* - For the led on Guitarport. - Brightness goes from 0x00 to 0x26. Set a value above this to have led - blink. - (void cmd_0x02(byte red, byte green) -*/ -static int led_red = 0x00; -static int led_green = 0x26; - static const struct { const char *name; int code; @@ -136,62 +140,6 @@ static const struct { {"Inst & Mic", 0x0901} }; -static bool toneport_has_led(enum line6_device_type type) -{ - return - (type == LINE6_GUITARPORT) || - (type == LINE6_TONEPORT_GX); - /* add your device here if you are missing support for the LEDs */ -} - -static void toneport_update_led(struct device *dev) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6_toneport *tp = usb_get_intfdata(interface); - struct usb_line6 *line6; - - if (!tp) - return; - - line6 = &tp->line6; - if (line6) - toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, - led_green); -} - -static ssize_t toneport_set_led_red(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int retval; - - retval = kstrtoint(buf, 10, &led_red); - if (retval) - return retval; - - toneport_update_led(dev); - return count; -} - -static ssize_t toneport_set_led_green(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int retval; - - retval = kstrtoint(buf, 10, &led_green); - if (retval) - return retval; - - toneport_update_led(dev); - return count; -} - -static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, - toneport_set_led_red); -static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, - toneport_set_led_green); - static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) { int ret; @@ -329,6 +277,78 @@ static struct snd_kcontrol_new toneport_control_source = { .put = snd_toneport_source_put }; +/* + For the led on Guitarport. + Brightness goes from 0x00 to 0x26. Set a value above this to have led + blink. + (void cmd_0x02(byte red, byte green) +*/ + +static bool toneport_has_led(enum line6_device_type type) +{ + return + (type == LINE6_GUITARPORT) || + (type == LINE6_TONEPORT_GX); + /* add your device here if you are missing support for the LEDs */ +} + +static const char * const led_colors[2] = { "red", "green" }; +static const int led_init_vals[2] = { 0x00, 0x26 }; + +static void toneport_update_led(struct usb_line6_toneport *toneport) +{ + toneport_send_cmd(toneport->line6.usbdev, + (toneport->leds[0].dev.brightness << 8) | 0x0002, + toneport->leds[1].dev.brightness); +} + +static void toneport_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct toneport_led *leds = + container_of(led_cdev, struct toneport_led, dev); + toneport_update_led(leds->toneport); +} + +static int toneport_init_leds(struct usb_line6_toneport *toneport) +{ + struct device *dev = &toneport->line6.usbdev->dev; + int i, err; + + for (i = 0; i < 2; i++) { + struct toneport_led *led = &toneport->leds[i]; + struct led_classdev *leddev = &led->dev; + + led->toneport = toneport; + snprintf(led->name, sizeof(led->name), "%s::%s", + dev_name(dev), led_colors[i]); + leddev->name = led->name; + leddev->brightness = led_init_vals[i]; + leddev->max_brightness = 0x26; + leddev->brightness_set = toneport_led_brightness_set; + err = led_classdev_register(dev, leddev); + if (err) + return err; + led->registered = true; + } + + return 0; +} + +static void toneport_remove_leds(struct usb_line6_toneport *toneport) +{ + struct toneport_led *led; + int i; + + for (i = 0; i < 2; i++) { + led = &toneport->leds[i]; + if (!led->registered) + break; + led_classdev_unregister(&led->dev); + led->registered = false; + } +} + /* Setup Toneport device. */ @@ -359,7 +379,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) } if (toneport_has_led(toneport->type)) - toneport_update_led(&usbdev->dev); + toneport_update_led(toneport); mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); } @@ -374,10 +394,8 @@ static void line6_toneport_disconnect(struct usb_interface *interface) toneport = usb_get_intfdata(interface); del_timer_sync(&toneport->timer); - if (toneport_has_led(toneport->type)) { - device_remove_file(&interface->dev, &dev_attr_led_red); - device_remove_file(&interface->dev, &dev_attr_led_green); - } + if (toneport_has_led(toneport->type)) + toneport_remove_leds(toneport); } @@ -428,10 +446,7 @@ static int toneport_init(struct usb_interface *interface, line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); 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); + err = toneport_init_leds(toneport); if (err < 0) return err; } -- cgit From 644d90850c65c6ac5698e4fadb01682196a25eea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 12:24:03 +0100 Subject: ALSA: line6: Minor refactoring Split some codes in the lengthy line6_probe(). Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 94 +++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 45 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index e7f9a99e1949..b783c0788e45 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -448,6 +448,52 @@ static void line6_destruct(struct snd_card *card) 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. */ @@ -485,24 +531,7 @@ int line6_probe(struct usb_interface *interface, 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"); - } - } + line6_get_interval(line6); ret = snd_card_new(line6->ifcdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -525,34 +554,9 @@ int line6_probe(struct usb_interface *interface, 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; + ret = line6_init_cap_control(line6); + if (ret < 0) goto err_destruct; - } - - line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); - - if (line6->urb_listen == NULL) { - ret = -ENOMEM; - goto err_destruct; - } - - ret = line6_start_listen(line6); - if (ret < 0) { - dev_err(&interface->dev, "%s: usb_submit_urb failed\n", - __func__); - goto err_destruct; - } } /* initialize device data based on device: */ -- cgit From 6b562f63dd603443c97c885daa2b88bff700b2dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 12:27:39 +0100 Subject: ALSA: line6: Fix memory leak at probe error path Fix memory leak at probe error path by rearranging the call order in line6_destruct() so that the common destructor is always called. Also this simplifies the error path to a single goto label. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index b783c0788e45..bf9630cd2395 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -507,39 +507,20 @@ int line6_probe(struct usb_interface *interface, 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); - - /* query interface number */ - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - - ret = usb_set_interface(usbdev, interface_number, - properties->altsetting); + ret = snd_card_new(&interface->dev, + SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); if (ret < 0) { - dev_err(&interface->dev, "set_interface failed\n"); - goto err_put; + kfree(line6); + return ret; } /* store basic data: */ + line6->card = card; line6->properties = properties; line6->usbdev = usbdev; line6->ifcdev = &interface->dev; - line6_get_interval(line6); - - 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); @@ -553,16 +534,37 @@ int line6_probe(struct usb_interface *interface, /* increment reference counters: */ usb_get_dev(usbdev); + /* we don't handle multiple configurations */ + if (usbdev->descriptor.bNumConfigurations != 1) { + ret = -ENODEV; + goto error; + } + + /* initialize device info: */ + dev_info(&interface->dev, "Line 6 %s found\n", properties->name); + + /* query interface number */ + interface_number = interface->cur_altsetting->desc.bInterfaceNumber; + + ret = usb_set_interface(usbdev, interface_number, + properties->altsetting); + if (ret < 0) { + 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 err_destruct; + goto error; } /* initialize device data based on device: */ ret = private_init(interface, line6); if (ret < 0) - goto err_destruct; + goto error; /* creation of additional special files should go here */ @@ -571,11 +573,10 @@ int line6_probe(struct usb_interface *interface, return 0; - err_destruct: + error: if (line6->disconnect) line6->disconnect(interface); snd_card_free(card); - err_put: return ret; } EXPORT_SYMBOL_GPL(line6_probe); -- cgit From b55004f9fdee80de1b6982b3e99ebaeb7d1e7a6c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 12:30:48 +0100 Subject: ALSA: line6: Remove unused line6_nop_read() The function isn't used any longer after rewriting from sysfs to leds class in toneport.c. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 10 ---------- sound/usb/line6/driver.h | 2 -- 2 files changed, 12 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index bf9630cd2395..4d2d233d0505 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -412,16 +412,6 @@ 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. */ diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index efd58ac3215b..a6c0b2f08ba8 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -162,8 +162,6 @@ struct usb_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, -- cgit From bc518ba4ccb487ef52e418c3ff68050cf07b3bc0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 12:39:11 +0100 Subject: ALSA: line6: Reduce superfluous spinlock in midi.c The midi_transmit_lock is used always inside the send_urb_lock, thus it doesn't play any role. Let's kill it. Also, rename "send_urb_lock" as a more simple name "lock" since this is the only lock for midi. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/midi.c | 18 ++++++------------ sound/usb/line6/midi.h | 7 +------ 2 files changed, 7 insertions(+), 18 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index b5a58a7fe11a..beeedf9a2cbe 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -45,12 +45,9 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream) line6_rawmidi_substream_midi(substream)->line6; struct snd_line6_midi *line6midi = line6->line6midi; struct midi_buffer *mb = &line6midi->midibuf_out; - unsigned long flags; unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; int req, done; - spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); - for (;;) { req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); done = snd_rawmidi_transmit_peek(substream, chunk, req); @@ -71,8 +68,6 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream) send_midi_async(line6, chunk, done); } - - spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); } /* @@ -92,7 +87,7 @@ static void midi_sent(struct urb *urb) if (status == -ESHUTDOWN) return; - spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); + spin_lock_irqsave(&line6->line6midi->lock, flags); num = --line6->line6midi->num_active_send_urbs; if (num == 0) { @@ -103,12 +98,12 @@ static void midi_sent(struct urb *urb) if (num == 0) wake_up(&line6->line6midi->send_wait); - spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); + spin_unlock_irqrestore(&line6->line6midi->lock, flags); } /* Send an asynchronous MIDI message. - Assumes that line6->line6midi->send_urb_lock is held + Assumes that line6->line6midi->lock is held (i.e., this function is serialized). */ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, @@ -166,12 +161,12 @@ static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, line6_rawmidi_substream_midi(substream)->line6; line6->line6midi->substream_transmit = substream; - spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); + spin_lock_irqsave(&line6->line6midi->lock, flags); if (line6->line6midi->num_active_send_urbs == 0) line6_midi_transmit(substream); - spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); + spin_unlock_irqrestore(&line6->line6midi->lock, flags); } static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) @@ -281,8 +276,7 @@ int line6_init_midi(struct usb_line6 *line6) 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); + spin_lock_init(&line6midi->lock); line6midi->line6 = line6; err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h index ba6bf3828aa5..9d9467b2613c 100644 --- a/sound/usb/line6/midi.h +++ b/sound/usb/line6/midi.h @@ -39,15 +39,10 @@ struct snd_line6_midi { */ int num_active_send_urbs; - /** - Spin lock to protect updates of send_urb. - */ - spinlock_t send_urb_lock; - /** Spin lock to protect MIDI buffer handling. */ - spinlock_t midi_transmit_lock; + spinlock_t lock; /** Wait queue for MIDI transmission. -- cgit From eab22e4053d47250ef755deb8592e0834eb409da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 13:00:03 +0100 Subject: ALSA: line6: Fix missing error handling in line6_pcm_acquire() Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 8a6059adef69..826158fe9149 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -133,7 +133,8 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) */ if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; + err = -EBUSY; + goto pcm_acquire_error; } line6pcm->count_in = 0; -- cgit From 6aa7f8ef293f27215f685b2f94e980c7f3a337d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 14:31:03 +0100 Subject: ALSA: line6: Use logical OR Fixed a few places using bits OR wrongly for condition checks. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 826158fe9149..f740b4490d75 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -131,7 +131,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) a bug, we therefore report an error if capturing is restarted too soon. */ - if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { + if (line6pcm->active_urb_in || line6pcm->unlink_urb_in) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); err = -EBUSY; goto pcm_acquire_error; @@ -166,7 +166,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) /* See comment above regarding PCM restart. */ - if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { + if (line6pcm->active_urb_out || line6pcm->unlink_urb_out) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); return -EBUSY; } -- cgit From 5343ecf4e5c94aecdd6a859b76c125c3544865d1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 14:34:42 +0100 Subject: ALSA: line6: Fix the error recovery in line6_pcm_acquire() line6_pcm_acquire() tries to restore the newly obtained resources at the error path. But some flags aren't recorded and released properly when the corresponding buffer is already present. These bits have to be cleared in the error recovery, too. Also, "flags_final" can be initialized to zero since we pass only the subset of "channels" bits. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index f740b4490d75..9a2a15f4c4e4 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -106,7 +106,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) flags_new = flags_old | channels; } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - flags_final = flags_old; + flags_final = 0; line6pcm->prev_fbuf = NULL; @@ -120,9 +120,9 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) err = -ENOMEM; goto pcm_acquire_error; } - - flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; } + + flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; } if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { @@ -157,9 +157,9 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) err = -ENOMEM; goto pcm_acquire_error; } - - flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; } + + flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; } if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { @@ -187,7 +187,7 @@ pcm_acquire_error: If not all requested resources/streams could be obtained, release those which were successfully obtained (if any). */ - line6_pcm_release(line6pcm, flags_final & channels); + line6_pcm_release(line6pcm, flags_final); return err; } EXPORT_SYMBOL_GPL(line6_pcm_acquire); -- cgit From f2a76225b962f00642002fb109aee2e5b0dc4259 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 14:49:22 +0100 Subject: ALSA: line6: Drop superfluous spinlock for trigger The trigger callback is already spinlocked, so we need no more lock here (even for the linked substreams). Let's drop it. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 23 ++++++----------------- sound/usb/line6/pcm.h | 5 ----- 2 files changed, 6 insertions(+), 22 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 9a2a15f4c4e4..adbcac46b785 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -226,9 +226,8 @@ 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; + int err = 0; - spin_lock(&line6pcm->lock_trigger); clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); snd_pcm_group_for_each_entry(s, substream) { @@ -237,32 +236,23 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) switch (s->stream) { case SNDRV_PCM_STREAM_PLAYBACK: err = snd_line6_playback_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock(&line6pcm->lock_trigger); - return err; - } - break; case SNDRV_PCM_STREAM_CAPTURE: err = snd_line6_capture_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock(&line6pcm->lock_trigger); - return err; - } - break; default: dev_err(line6pcm->line6->ifcdev, "Unknown stream direction %d\n", s->stream); + err = -EINVAL; + break; } + if (err < 0) + break; } - spin_unlock(&line6pcm->lock_trigger); - return 0; + return err; } /* control info callback */ @@ -427,7 +417,6 @@ int line6_init_pcm(struct usb_line6 *line6, 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; diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index c742b33666eb..a84753ee0fa2 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -307,11 +307,6 @@ struct snd_line6_pcm { */ spinlock_t lock_audio_in; - /** - Spin lock to protect trigger. - */ - spinlock_t lock_trigger; - /** PCM playback volume (left and right). */ -- cgit From 9fb754b79e536eb35d69a4678687addff589e45b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 15:08:40 +0100 Subject: ALSA: line6: Use incremental loop Using a decremental loop without particular reasons worsens the readability a lot. Use incremental loops instead. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 4 ++-- sound/usb/line6/pcm.c | 6 +++--- sound/usb/line6/playback.c | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 5a010ba163fa..97283e631e45 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -91,7 +91,7 @@ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) { unsigned int i; - for (i = LINE6_ISO_BUFFERS; i--;) { + for (i = 0; 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]; @@ -114,7 +114,7 @@ void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) do { alive = 0; - for (i = LINE6_ISO_BUFFERS; i--;) { + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { if (test_bit(i, &line6pcm->active_urb_in)) alive++; } diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index adbcac46b785..43474c4ebb6b 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -273,7 +273,7 @@ static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, int i; struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - for (i = 2; i--;) + for (i = 0; i < 2; i++) ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; return 0; @@ -286,7 +286,7 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, int i, changed = 0; struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - for (i = 2; i--;) + for (i = 0; i < 2; i++) if (line6pcm->volume_playback[i] != ucontrol->value.integer.value[i]) { line6pcm->volume_playback[i] = @@ -330,7 +330,7 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm) int i; struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); - for (i = LINE6_ISO_BUFFERS; i--;) { + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { if (line6pcm->urb_audio_out[i]) { usb_kill_urb(line6pcm->urb_audio_out[i]); usb_free_urb(line6pcm->urb_audio_out[i]); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 1c9f95a370ff..ab9a83f0f864 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -297,7 +297,7 @@ void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) { unsigned int i; - for (i = LINE6_ISO_BUFFERS; i--;) { + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { if (test_bit(i, &line6pcm->active_urb_out)) { if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { struct urb *u = line6pcm->urb_audio_out[i]; @@ -320,7 +320,7 @@ void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) do { alive = 0; - for (i = LINE6_ISO_BUFFERS; i--;) { + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { if (test_bit(i, &line6pcm->active_urb_out)) alive++; } @@ -366,14 +366,14 @@ static void audio_out_callback(struct urb *urb) line6pcm->last_frame_out = urb->start_frame; /* find index of URB */ - for (index = LINE6_ISO_BUFFERS; index--;) + for (index = 0; index < LINE6_ISO_BUFFERS; index++) if (urb == line6pcm->urb_audio_out[index]) break; - if (index < 0) + if (index >= LINE6_ISO_BUFFERS) return; /* URB has been unlinked asynchronously */ - for (i = LINE6_ISO_PACKETS; i--;) + for (i = 0; i < LINE6_ISO_PACKETS; i++) length += urb->iso_frame_desc[i].length; spin_lock_irqsave(&line6pcm->lock_audio_out, flags); @@ -390,7 +390,7 @@ static void audio_out_callback(struct urb *urb) clear_bit(index, &line6pcm->active_urb_out); - for (i = LINE6_ISO_PACKETS; i--;) + for (i = 0; i < LINE6_ISO_PACKETS; i++) if (urb->iso_frame_desc[i].status == -EXDEV) { shutdown = 1; break; -- cgit From ab5cdcbab2efb833b4c199d0b0a6603af080eaa2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 15:12:13 +0100 Subject: ALSA: line6: Drop voodoo workarounds If the problem still really remains, we should fix it instead of papering over it like this... Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 12 ------------ sound/usb/line6/playback.c | 12 ------------ 2 files changed, 24 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 97283e631e45..bad1b5b02786 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -297,18 +297,6 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, 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) diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index ab9a83f0f864..7e031b1761aa 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -445,18 +445,6 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, 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_PLAYBACK_BUFFER); if (ret < 0) -- cgit From ad0119abe29fe3d506486a789de4c4619fa7602c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:10:57 +0100 Subject: ALSA: line6: Rearrange PCM structure Introduce a new line6_pcm_stream structure and group individual fields of snd_line6_pcm struct to playback and capture groups. This patch itself just does rename and nothing else. More meaningful cleanups based on these fields shuffling will follow. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 64 +++++++++--------- sound/usb/line6/pcm.c | 50 +++++++------- sound/usb/line6/pcm.h | 158 +++++++++++++-------------------------------- sound/usb/line6/playback.c | 78 +++++++++++----------- 4 files changed, 142 insertions(+), 208 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index bad1b5b02786..439f1941eb56 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -29,17 +29,17 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) int ret; struct urb *urb_in; - spin_lock_irqsave(&line6pcm->lock_audio_in, flags); + spin_lock_irqsave(&line6pcm->in.lock, 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); + spin_unlock_irqrestore(&line6pcm->in.lock, 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) { @@ -51,7 +51,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; @@ -59,12 +59,12 @@ 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); + spin_unlock_irqrestore(&line6pcm->in.lock, flags); return 0; } @@ -92,9 +92,9 @@ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) unsigned int i; for (i = 0; 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]; + if (test_bit(i, &line6pcm->in.active_urbs)) { + if (!test_and_set_bit(i, &line6pcm->in.unlink_urbs)) { + struct urb *u = line6pcm->in.urbs[i]; usb_unlink_urb(u); } @@ -115,7 +115,7 @@ void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) do { alive = 0; for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->active_urb_in)) + if (test_bit(i, &line6pcm->in.active_urbs)) alive++; } if (!alive) @@ -150,18 +150,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); @@ -173,12 +173,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) @@ -186,17 +186,17 @@ 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; snd_pcm_period_elapsed(substream); } } void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) { - kfree(line6pcm->buffer_in); - line6pcm->buffer_in = NULL; + kfree(line6pcm->in.buffer); + line6pcm->in.buffer = NULL; } /* @@ -209,14 +209,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; @@ -249,12 +249,12 @@ static void audio_in_callback(struct urb *urb) 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); + spin_unlock_irqrestore(&line6pcm->in.lock, flags); if (!shutdown) { submit_audio_in_urb(line6pcm); @@ -309,7 +309,7 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, return ret; } - line6pcm->period_in = params_period_bytes(hw_params); + line6pcm->in.period = params_period_bytes(hw_params); return 0; } @@ -361,7 +361,7 @@ snd_line6_capture_pointer(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - return line6pcm->pos_in_done; + return line6pcm->in.pos_done; } /* capture operators */ @@ -386,7 +386,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) diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 43474c4ebb6b..738bfd82cecd 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -112,11 +112,11 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_in) { - line6pcm->buffer_in = + if (!line6pcm->in.buffer) { + line6pcm->in.buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_in) { + if (!line6pcm->in.buffer) { err = -ENOMEM; goto pcm_acquire_error; } @@ -131,13 +131,13 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) a bug, we therefore report an error if capturing is restarted too soon. */ - if (line6pcm->active_urb_in || line6pcm->unlink_urb_in) { + if (line6pcm->in.active_urbs || line6pcm->in.unlink_urbs) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); err = -EBUSY; goto pcm_acquire_error; } - line6pcm->count_in = 0; + line6pcm->in.count = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); @@ -149,11 +149,11 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_out) { - line6pcm->buffer_out = + if (!line6pcm->out.buffer) { + line6pcm->out.buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_out) { + if (!line6pcm->out.buffer) { err = -ENOMEM; goto pcm_acquire_error; } @@ -166,12 +166,12 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) /* See comment above regarding PCM restart. */ - if (line6pcm->active_urb_out || line6pcm->unlink_urb_out) { + if (line6pcm->out.active_urbs || line6pcm->out.unlink_urbs) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); return -EBUSY; } - line6pcm->count_out = 0; + line6pcm->out.count = 0; err = line6_submit_audio_out_all_urbs(line6pcm); if (err < 0) @@ -331,13 +331,13 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm) struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (line6pcm->urb_audio_out[i]) { - usb_kill_urb(line6pcm->urb_audio_out[i]); - usb_free_urb(line6pcm->urb_audio_out[i]); + if (line6pcm->out.urbs[i]) { + usb_kill_urb(line6pcm->out.urbs[i]); + usb_free_urb(line6pcm->out.urbs[i]); } - if (line6pcm->urb_audio_in[i]) { - usb_kill_urb(line6pcm->urb_audio_in[i]); - usb_free_urb(line6pcm->urb_audio_in[i]); + if (line6pcm->in.urbs[i]) { + usb_kill_urb(line6pcm->in.urbs[i]); + usb_free_urb(line6pcm->in.urbs[i]); } } kfree(line6pcm); @@ -415,8 +415,8 @@ int line6_init_pcm(struct usb_line6 *line6, usb_maxpacket(line6->usbdev, usb_sndisocpipe(line6->usbdev, ep_write), 1)); - spin_lock_init(&line6pcm->lock_audio_out); - spin_lock_init(&line6pcm->lock_audio_in); + spin_lock_init(&line6pcm->out.lock); + spin_lock_init(&line6pcm->in.lock); line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; line6->line6pcm = line6pcm; @@ -464,13 +464,13 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) } if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { - line6pcm->count_out = 0; - line6pcm->pos_out = 0; - line6pcm->pos_out_done = 0; - line6pcm->bytes_out = 0; - line6pcm->count_in = 0; - line6pcm->pos_in_done = 0; - line6pcm->bytes_in = 0; + line6pcm->out.count = 0; + line6pcm->out.pos = 0; + line6pcm->out.pos_done = 0; + line6pcm->out.bytes = 0; + line6pcm->in.count = 0; + line6pcm->in.pos_done = 0; + line6pcm->in.bytes = 0; } return 0; diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index a84753ee0fa2..4c74f4e85074 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -165,148 +165,84 @@ struct line6_pcm_properties { int bytes_per_frame; }; -struct snd_line6_pcm { - /** - Pointer back to the Line 6 driver data structure. - */ - struct usb_line6 *line6; +struct line6_pcm_stream { + /* allocated URBs */ + struct urb *urbs[LINE6_ISO_BUFFERS]; - /** - Properties. - */ - struct line6_pcm_properties *properties; + /* Temporary buffer; + * Since the packet size is not known in advance, this buffer is + * large enough to store maximum size packets. + */ + unsigned char *buffer; - /** - ALSA pcm stream - */ - struct snd_pcm *pcm; + /* Free frame position in the buffer. */ + snd_pcm_uframes_t pos; - /** - URBs for audio playback. - */ - struct urb *urb_audio_out[LINE6_ISO_BUFFERS]; + /* Count processed bytes; + * This is modulo period size (to determine when a period is finished). + */ + unsigned bytes; - /** - URBs for audio capture. - */ - struct urb *urb_audio_in[LINE6_ISO_BUFFERS]; + /* Counter to create desired sample rate */ + unsigned count; - /** - Temporary buffer for playback. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_out; + /* period size in bytes */ + unsigned period; - /** - Temporary buffer for capture. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_in; + /* Processed frame position in the buffer; + * The contents of the ring buffer have been consumed by the USB + * subsystem (i.e., sent to the USB device) up to this position. + */ + snd_pcm_uframes_t pos_done; - /** - Previously captured frame (for software monitoring). - */ - unsigned char *prev_fbuf; + /* Bit mask of active URBs */ + unsigned long active_urbs; - /** - Size of previously captured frame (for software monitoring). - */ - int prev_fsize; - - /** - Free frame position in the playback buffer. - */ - snd_pcm_uframes_t pos_out; + /* Bit mask of URBs currently being unlinked */ + unsigned long unlink_urbs; - /** - Count processed bytes for playback. - This is modulo period size (to determine when a period is - finished). - */ - unsigned bytes_out; + /* Spin lock to protect updates of the buffer positions (not contents) + */ + spinlock_t lock; - /** - Counter to create desired playback sample rate. - */ - unsigned count_out; - - /** - Playback period size in bytes - */ - unsigned period_out; + int last_frame; +}; +struct snd_line6_pcm { /** - Processed frame position in the playback buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. + Pointer back to the Line 6 driver data structure. */ - snd_pcm_uframes_t pos_out_done; + struct usb_line6 *line6; /** - Count processed bytes for capture. - This is modulo period size (to determine when a period is - finished). + Properties. */ - unsigned bytes_in; + struct line6_pcm_properties *properties; /** - Counter to create desired capture sample rate. + ALSA pcm stream */ - unsigned count_in; + struct snd_pcm *pcm; - /** - Capture period size in bytes - */ - unsigned period_in; + /* Capture and playback streams */ + struct line6_pcm_stream in; + struct line6_pcm_stream out; /** - Processed frame position in the capture buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. + Previously captured frame (for software monitoring). */ - snd_pcm_uframes_t pos_in_done; + unsigned char *prev_fbuf; /** - Bit mask of active playback URBs. + Size of previously captured frame (for software monitoring). */ - unsigned long active_urb_out; + int prev_fsize; /** Maximum size of USB packet. */ int max_packet_size; - /** - Bit mask of active capture URBs. - */ - unsigned long active_urb_in; - - /** - Bit mask of playback URBs currently being unlinked. - */ - unsigned long unlink_urb_out; - - /** - Bit mask of capture URBs currently being unlinked. - */ - unsigned long unlink_urb_in; - - /** - Spin lock to protect updates of the playback buffer positions (not - contents!) - */ - spinlock_t lock_audio_out; - - /** - Spin lock to protect updates of the capture buffer positions (not - contents!) - */ - spinlock_t lock_audio_in; - /** PCM playback volume (left and right). */ @@ -336,8 +272,6 @@ struct snd_line6_pcm { Several status bits (see LINE6_BIT_*). */ unsigned long flags; - - int last_frame_in, last_frame_out; }; extern int line6_init_pcm(struct usb_line6 *line6, diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 7e031b1761aa..d619c1718306 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -145,17 +145,17 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); struct urb *urb_out; - spin_lock_irqsave(&line6pcm->lock_audio_out, flags); + spin_lock_irqsave(&line6pcm->out.lock, flags); index = - find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); + find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS); if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + spin_unlock_irqrestore(&line6pcm->out.lock, flags); dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); return -EINVAL; } - urb_out = line6pcm->urb_audio_out[index]; + urb_out = line6pcm->out.urbs[index]; urb_size = 0; for (i = 0; i < LINE6_ISO_PACKETS; ++i) { @@ -170,9 +170,9 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) if (fsize == 0) { int n; - line6pcm->count_out += frame_increment; - n = line6pcm->count_out / frame_factor; - line6pcm->count_out -= n * frame_factor; + line6pcm->out.count += frame_increment; + n = line6pcm->out.count / frame_factor; + line6pcm->out.count -= n * frame_factor; fsize = n * bytes_per_frame; } @@ -183,14 +183,14 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) if (urb_size == 0) { /* can't determine URB size */ - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + spin_unlock_irqrestore(&line6pcm->out.lock, flags); dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); return -EINVAL; } urb_frames = urb_size / bytes_per_frame; urb_out->transfer_buffer = - line6pcm->buffer_out + + line6pcm->out.buffer + index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; urb_out->transfer_buffer_length = urb_size; urb_out->context = line6pcm; @@ -200,19 +200,19 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) struct snd_pcm_runtime *runtime = get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; - if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { + if (line6pcm->out.pos + urb_frames > runtime->buffer_size) { /* The transferred area goes over buffer boundary, copy the data to the temp buffer. */ int len; - len = runtime->buffer_size - line6pcm->pos_out; + len = runtime->buffer_size - line6pcm->out.pos; if (len > 0) { memcpy(urb_out->transfer_buffer, runtime->dma_area + - line6pcm->pos_out * bytes_per_frame, + line6pcm->out.pos * bytes_per_frame, len * bytes_per_frame); memcpy(urb_out->transfer_buffer + len * bytes_per_frame, runtime->dma_area, @@ -223,13 +223,13 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) } else { memcpy(urb_out->transfer_buffer, runtime->dma_area + - line6pcm->pos_out * bytes_per_frame, + line6pcm->out.pos * bytes_per_frame, urb_out->transfer_buffer_length); } - line6pcm->pos_out += urb_frames; - if (line6pcm->pos_out >= runtime->buffer_size) - line6pcm->pos_out -= runtime->buffer_size; + line6pcm->out.pos += urb_frames; + if (line6pcm->out.pos >= runtime->buffer_size) + line6pcm->out.pos -= runtime->buffer_size; } else { memset(urb_out->transfer_buffer, 0, urb_out->transfer_buffer_length); @@ -265,12 +265,12 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) ret = usb_submit_urb(urb_out, GFP_ATOMIC); if (ret == 0) - set_bit(index, &line6pcm->active_urb_out); + set_bit(index, &line6pcm->out.active_urbs); else dev_err(line6pcm->line6->ifcdev, "URB out #%d submission failed (%d)\n", index, ret); - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + spin_unlock_irqrestore(&line6pcm->out.lock, flags); return 0; } @@ -298,9 +298,9 @@ void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) unsigned int i; for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->active_urb_out)) { - if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { - struct urb *u = line6pcm->urb_audio_out[i]; + if (test_bit(i, &line6pcm->out.active_urbs)) { + if (!test_and_set_bit(i, &line6pcm->out.unlink_urbs)) { + struct urb *u = line6pcm->out.urbs[i]; usb_unlink_urb(u); } @@ -321,7 +321,7 @@ void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) do { alive = 0; for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->active_urb_out)) + if (test_bit(i, &line6pcm->out.active_urbs)) alive++; } if (!alive) @@ -344,8 +344,8 @@ void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) { - kfree(line6pcm->buffer_out); - line6pcm->buffer_out = NULL; + kfree(line6pcm->out.buffer); + line6pcm->out.buffer = NULL; } /* @@ -363,11 +363,11 @@ static void audio_out_callback(struct urb *urb) memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); #endif - line6pcm->last_frame_out = urb->start_frame; + line6pcm->out.last_frame = urb->start_frame; /* find index of URB */ for (index = 0; index < LINE6_ISO_BUFFERS; index++) - if (urb == line6pcm->urb_audio_out[index]) + if (urb == line6pcm->out.urbs[index]) break; if (index >= LINE6_ISO_BUFFERS) @@ -376,19 +376,19 @@ static void audio_out_callback(struct urb *urb) for (i = 0; i < LINE6_ISO_PACKETS; i++) length += urb->iso_frame_desc[i].length; - spin_lock_irqsave(&line6pcm->lock_audio_out, flags); + spin_lock_irqsave(&line6pcm->out.lock, flags); if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { struct snd_pcm_runtime *runtime = substream->runtime; - line6pcm->pos_out_done += + line6pcm->out.pos_done += length / line6pcm->properties->bytes_per_frame; - if (line6pcm->pos_out_done >= runtime->buffer_size) - line6pcm->pos_out_done -= runtime->buffer_size; + if (line6pcm->out.pos_done >= runtime->buffer_size) + line6pcm->out.pos_done -= runtime->buffer_size; } - clear_bit(index, &line6pcm->active_urb_out); + clear_bit(index, &line6pcm->out.active_urbs); for (i = 0; i < LINE6_ISO_PACKETS; i++) if (urb->iso_frame_desc[i].status == -EXDEV) { @@ -396,19 +396,19 @@ static void audio_out_callback(struct urb *urb) break; } - if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) + if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs)) shutdown = 1; - spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); + spin_unlock_irqrestore(&line6pcm->out.lock, flags); if (!shutdown) { submit_audio_out_urb(line6pcm); if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { - line6pcm->bytes_out += length; - if (line6pcm->bytes_out >= line6pcm->period_out) { - line6pcm->bytes_out %= line6pcm->period_out; + line6pcm->out.bytes += length; + if (line6pcm->out.bytes >= line6pcm->out.period) { + line6pcm->out.bytes %= line6pcm->out.period; snd_pcm_period_elapsed(substream); } } @@ -457,7 +457,7 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, return ret; } - line6pcm->period_out = params_period_bytes(hw_params); + line6pcm->out.period = params_period_bytes(hw_params); return 0; } @@ -517,7 +517,7 @@ snd_line6_playback_pointer(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - return line6pcm->pos_out_done; + return line6pcm->out.pos_done; } /* playback operators */ @@ -542,7 +542,7 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) struct urb *urb; /* URB for audio out: */ - urb = line6pcm->urb_audio_out[i] = + urb = line6pcm->out.urbs[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); if (urb == NULL) -- cgit From d8131e67f08bc15e54104cb69deb06bad9d87f30 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:18:42 +0100 Subject: ALSA: line6: Consolidate URB unlink and sync helpers The codes to unlink and sync URBs are identical for both playback and capture streams. Consolidate to single helper functions. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 52 --------------------------- sound/usb/line6/capture.h | 4 --- sound/usb/line6/pcm.c | 90 +++++++++++++++++++++++++++++++++++----------- sound/usb/line6/playback.c | 52 --------------------------- sound/usb/line6/playback.h | 4 --- 5 files changed, 69 insertions(+), 133 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 439f1941eb56..1d477d7a42fb 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -84,58 +84,6 @@ int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) return 0; } -/* - Unlink all currently active capture URBs. -*/ -void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - unsigned int i; - - for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->in.active_urbs)) { - if (!test_and_set_bit(i, &line6pcm->in.unlink_urbs)) { - struct urb *u = line6pcm->in.urbs[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 = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->in.active_urbs)) - 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); -} - /* Copy data into ALSA capture buffer. */ diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 0939f400a405..3cc71bc70b21 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -26,10 +26,6 @@ extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, 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 diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 738bfd82cecd..677419dcacf9 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -90,6 +90,47 @@ static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, return 1; } +/* + Unlink all currently active URBs. +*/ +static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + int i; + + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { + if (test_bit(i, &pcms->active_urbs)) { + if (!test_and_set_bit(i, &pcms->unlink_urbs)) + usb_unlink_urb(pcms->urbs[i]); + } + } +} + +/* + Wait until unlinking of all currently active URBs has been finished. +*/ +static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + int timeout = HZ; + int i; + int alive; + + do { + alive = 0; + for (i = 0; i < LINE6_ISO_BUFFERS; i++) { + if (test_bit(i, &pcms->active_urbs)) + 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); +} + static bool test_flags(unsigned long flags0, unsigned long flags1, unsigned long mask) { @@ -202,18 +243,18 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) - line6_unlink_audio_in_urbs(line6pcm); + line6_unlink_audio_urbs(line6pcm, &line6pcm->in); if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { - line6_wait_clear_audio_in_urbs(line6pcm); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); line6_free_capture_buffer(line6pcm); } if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) - line6_unlink_audio_out_urbs(line6pcm); + line6_unlink_audio_urbs(line6pcm, &line6pcm->out); if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { - line6_wait_clear_audio_out_urbs(line6pcm); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); line6_free_playback_buffer(line6pcm); } @@ -325,21 +366,24 @@ static struct snd_kcontrol_new line6_controls[] = { /* Cleanup the PCM device. */ -static void line6_cleanup_pcm(struct snd_pcm *pcm) +static void cleanup_urbs(struct line6_pcm_stream *pcms) { int i; - struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (line6pcm->out.urbs[i]) { - usb_kill_urb(line6pcm->out.urbs[i]); - usb_free_urb(line6pcm->out.urbs[i]); - } - if (line6pcm->in.urbs[i]) { - usb_kill_urb(line6pcm->in.urbs[i]); - usb_free_urb(line6pcm->in.urbs[i]); + if (pcms->urbs[i]) { + usb_kill_urb(pcms->urbs[i]); + usb_free_urb(pcms->urbs[i]); } } +} + +static void line6_cleanup_pcm(struct snd_pcm *pcm) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); + + cleanup_urbs(&line6pcm->out); + cleanup_urbs(&line6pcm->in); kfree(line6pcm); } @@ -374,8 +418,10 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) */ void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) { - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - line6_unlink_wait_clear_audio_in_urbs(line6pcm); + line6_unlink_audio_urbs(line6pcm, &line6pcm->out); + line6_unlink_audio_urbs(line6pcm, &line6pcm->in); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); } /* @@ -451,15 +497,17 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) switch (substream->stream) { case SNDRV_PCM_STREAM_PLAYBACK: - if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - + if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) { + line6_unlink_audio_urbs(line6pcm, &line6pcm->out); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); + } break; case SNDRV_PCM_STREAM_CAPTURE: - if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) - line6_unlink_wait_clear_audio_in_urbs(line6pcm); - + if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) { + line6_unlink_audio_urbs(line6pcm, &line6pcm->in); + line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); + } break; } diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index d619c1718306..3820ed08b342 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -290,58 +290,6 @@ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) return 0; } -/* - Unlink all currently active playback URBs. -*/ -void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - unsigned int i; - - for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->out.active_urbs)) { - if (!test_and_set_bit(i, &line6pcm->out.unlink_urbs)) { - struct urb *u = line6pcm->out.urbs[i]; - - usb_unlink_urb(u); - } - } - } -} - -/* - Wait until unlinking of all currently active playback URBs has been - finished. -*/ -void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - int timeout = HZ; - unsigned int i; - int alive; - - do { - alive = 0; - for (i = 0; i < LINE6_ISO_BUFFERS; i++) { - if (test_bit(i, &line6pcm->out.active_urbs)) - 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 playback URBs, and wait for finishing. -*/ -void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) -{ - line6_unlink_audio_out_urbs(line6pcm); - line6_wait_clear_audio_out_urbs(line6pcm); -} - void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) { kfree(line6pcm->out.buffer); diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index 78a885113221..52a278353d3b 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -32,10 +32,6 @@ extern struct snd_pcm_ops snd_line6_playback_ops; 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 - *line6pcm); -extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); #endif -- cgit From ccaac9ed79c6051733f781a1cd639d488696f512 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:20:50 +0100 Subject: ALSA: line6: Use dev_err() This is the last remaining snd_printk() usage in this driver. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 677419dcacf9..4152d92105b1 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -128,7 +128,8 @@ static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, schedule_timeout(1); } while (--timeout > 0); if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); + dev_err(line6pcm->line6->ifcdev, + "timeout: still %d active urbs..\n", alive); } static bool test_flags(unsigned long flags0, unsigned long flags1, -- cgit From e90576c5955c83cd7e8c191b47f70d1946015041 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:25:03 +0100 Subject: ALSA: line6: Consolidate PCM stream buffer allocation and free The PCM stream buffer allocation and free are identical for both playback and capture streams. Provide single helper functions. These are used only in pcm.c, thus they can be even static. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 6 ------ sound/usb/line6/capture.h | 1 - sound/usb/line6/pcm.c | 53 +++++++++++++++++++++++++--------------------- sound/usb/line6/playback.c | 6 ------ sound/usb/line6/playback.h | 1 - 5 files changed, 29 insertions(+), 38 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 1d477d7a42fb..47cfcc2ab387 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -141,12 +141,6 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) } } -void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) -{ - kfree(line6pcm->in.buffer); - line6pcm->in.buffer = NULL; -} - /* * Callback for completed capture URB. */ diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index 3cc71bc70b21..db062e7200a6 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -24,7 +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 int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 4152d92105b1..f75825995e24 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -132,6 +132,27 @@ static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, "timeout: still %d active urbs..\n", alive); } +static int line6_alloc_stream_buffer(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + /* Invoked multiple times in a row so allocate once only */ + if (pcms->buffer) + return 0; + + pcms->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + if (!pcms->buffer) + return -ENOMEM; + return 0; +} + +static void line6_free_stream_buffer(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pcms) +{ + kfree(pcms->buffer); + pcms->buffer = NULL; +} + static bool test_flags(unsigned long flags0, unsigned long flags1, unsigned long mask) { @@ -153,17 +174,9 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) line6pcm->prev_fbuf = NULL; if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->in.buffer) { - line6pcm->in.buffer = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->in.buffer) { - err = -ENOMEM; - goto pcm_acquire_error; - } - } - + err = line6_alloc_stream_buffer(line6pcm, &line6pcm->in); + if (err < 0) + goto pcm_acquire_error; flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; } @@ -190,17 +203,9 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) } if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->out.buffer) { - line6pcm->out.buffer = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->out.buffer) { - err = -ENOMEM; - goto pcm_acquire_error; - } - } - + err = line6_alloc_stream_buffer(line6pcm, &line6pcm->out); + if (err < 0) + goto pcm_acquire_error; flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; } @@ -248,7 +253,7 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); - line6_free_capture_buffer(line6pcm); + line6_free_stream_buffer(line6pcm, &line6pcm->in); } if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) @@ -256,7 +261,7 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); - line6_free_playback_buffer(line6pcm); + line6_free_stream_buffer(line6pcm, &line6pcm->out); } return 0; diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 3820ed08b342..750d91dced57 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -290,12 +290,6 @@ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) return 0; } -void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) -{ - kfree(line6pcm->out.buffer); - line6pcm->out.buffer = NULL; -} - /* Callback for completed playback URB. */ diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index 52a278353d3b..f6a9e18f87b6 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -30,7 +30,6 @@ extern struct snd_pcm_ops snd_line6_playback_ops; 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 int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); -- cgit From c8491535d7f1a1e8f7f3e0d31e8f7525809c98a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:54:36 +0100 Subject: ALSA: line6: Do clipping in volume / monitor manipulations Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/playback.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 750d91dced57..cbcd97f5d629 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -37,7 +37,8 @@ static void change_volume(struct urb *urb_out, int volume[], buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); for (; p < buf_end; ++p) { - *p = (*p * volume[chn & 1]) >> 8; + int val = (*p * volume[chn & 1]) >> 8; + *p = clamp(val, 0x7fff, -0x8000); ++chn; } } else if (bytes_per_frame == 6) { @@ -51,6 +52,7 @@ static void change_volume(struct urb *urb_out, int volume[], val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); val = (val * volume[chn & 1]) >> 8; + val = clamp(val, 0x7fffff, -0x800000); p[0] = val; p[1] = val >> 8; p[2] = val >> 16; @@ -118,8 +120,10 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, po = (short *)urb_out->transfer_buffer; buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); - for (; po < buf_end; ++pi, ++po) - *po += (*pi * volume) >> 8; + for (; po < buf_end; ++pi, ++po) { + int val = *po + ((*pi * volume) >> 8); + *po = clamp(val, 0x7fff, -0x8000); + } } /* -- cgit From 62a109d9e2ce948ee75222bbb92a97669f683875 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Jan 2015 16:58:30 +0100 Subject: ALSA: line6: Skip volume manipulation during silence copying A minor optimization; while pausing, the driver just copies the zero that doesn't need any volume changes. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/playback.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index cbcd97f5d629..3762a98026aa 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -234,13 +234,14 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) line6pcm->out.pos += urb_frames; if (line6pcm->out.pos >= runtime->buffer_size) line6pcm->out.pos -= runtime->buffer_size; + + change_volume(urb_out, line6pcm->volume_playback, + bytes_per_frame); } else { memset(urb_out->transfer_buffer, 0, urb_out->transfer_buffer_length); } - change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); - if (line6pcm->prev_fbuf != NULL) { if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { create_impulse_test_signal(line6pcm, urb_out, -- cgit From f66fd990c5db177d6b9f0eae301ca6b15882eb2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 25 Jan 2015 18:22:58 +0100 Subject: ALSA: line6: Drop interface argument from private_init and disconnect callbacks The interface argument is used just for retrieving the assigned device, which can be already found in line6->ifcdev. Drop them from the callbacks. Also, pass the usb id to private_init so that the driver can deal with it there. This is a preliminary work for the further cleanup to move the whole allocation into driver.c. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 9 +++++---- sound/usb/line6/driver.h | 6 ++++-- sound/usb/line6/pod.c | 14 +++++++------- sound/usb/line6/podhd.c | 6 +++--- sound/usb/line6/toneport.c | 14 +++++++------- sound/usb/line6/variax.c | 12 +++++------- 6 files changed, 31 insertions(+), 30 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 4d2d233d0505..e2fbff05c1b1 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -488,9 +488,10 @@ static int line6_init_cap_control(struct usb_line6 *line6) Probe USB device. */ int line6_probe(struct usb_interface *interface, + const struct usb_device_id *id, struct usb_line6 *line6, 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)) { struct usb_device *usbdev = interface_to_usbdev(interface); struct snd_card *card; @@ -552,7 +553,7 @@ int line6_probe(struct usb_interface *interface, } /* initialize device data based on device: */ - ret = private_init(interface, line6); + ret = private_init(line6, id); if (ret < 0) goto error; @@ -565,7 +566,7 @@ int line6_probe(struct usb_interface *interface, error: if (line6->disconnect) - line6->disconnect(interface); + line6->disconnect(line6); snd_card_free(card); return ret; } @@ -592,7 +593,7 @@ void line6_disconnect(struct usb_interface *interface) 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); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index a6c0b2f08ba8..4dc6c28e8224 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -157,7 +157,7 @@ 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, @@ -180,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, + const struct usb_device_id *id, struct usb_line6 *line6, 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)); + void line6_disconnect(struct usb_interface *interface); #ifdef CONFIG_PM diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 26ecf26a33ec..d1e952fbcae7 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -399,10 +399,10 @@ static struct snd_kcontrol_new pod_control_monitor = { /* POD device disconnected. */ -static void line6_pod_disconnect(struct usb_interface *interface) +static void line6_pod_disconnect(struct usb_line6 *line6) { - struct usb_line6_pod *pod = usb_get_intfdata(interface); - struct device *dev = &interface->dev; + struct usb_line6_pod *pod = (struct usb_line6_pod *)line6; + struct device *dev = line6->ifcdev; /* remove sysfs entries: */ device_remove_file(dev, &dev_attr_device_id); @@ -435,8 +435,8 @@ static int pod_create_files2(struct device *dev) /* Try to init POD device. */ -static int pod_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int pod_init(struct usb_line6 *line6, + const struct usb_device_id *id) { int err; struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; @@ -448,7 +448,7 @@ static int pod_init(struct usb_interface *interface, INIT_WORK(&pod->startup_work, pod_startup4); /* create sysfs entries: */ - err = pod_create_files2(&interface->dev); + err = pod_create_files2(line6->ifcdev); if (err < 0) return err; @@ -596,7 +596,7 @@ static int pod_probe(struct usb_interface *interface, pod = kzalloc(sizeof(*pod), GFP_KERNEL); if (!pod) return -ENODEV; - return line6_probe(interface, &pod->line6, + return line6_probe(interface, id, &pod->line6, &pod_properties_table[id->driver_info], pod_init); } diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 59abbd92624e..21d7edcfa272 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -87,8 +87,8 @@ static struct line6_pcm_properties podhd_pcm_properties = { /* Try to init POD HD device. */ -static int podhd_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int podhd_init(struct usb_line6 *line6, + const struct usb_device_id *id) { int err; @@ -182,7 +182,7 @@ static int podhd_probe(struct usb_interface *interface, podhd = kzalloc(sizeof(*podhd), GFP_KERNEL); if (!podhd) return -ENODEV; - return line6_probe(interface, &podhd->line6, + return line6_probe(interface, id, &podhd->line6, &podhd_properties_table[id->driver_info], podhd_init); } diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 9a769463f7bf..8e7020df0d10 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -387,11 +387,11 @@ static void toneport_setup(struct usb_line6_toneport *toneport) /* Toneport device disconnected. */ -static void line6_toneport_disconnect(struct usb_interface *interface) +static void line6_toneport_disconnect(struct usb_line6 *line6) { - struct usb_line6_toneport *toneport; + struct usb_line6_toneport *toneport = + (struct usb_line6_toneport *)line6; - toneport = usb_get_intfdata(interface); del_timer_sync(&toneport->timer); if (toneport_has_led(toneport->type)) @@ -402,12 +402,13 @@ static void line6_toneport_disconnect(struct usb_interface *interface) /* Try to init Toneport device. */ -static int toneport_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int toneport_init(struct usb_line6 *line6, + const struct usb_device_id *id) { int err; struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; + toneport->type = id->driver_info; setup_timer(&toneport->timer, toneport_start_pcm, (unsigned long)toneport); @@ -562,8 +563,7 @@ static int toneport_probe(struct usb_interface *interface, toneport = kzalloc(sizeof(*toneport), GFP_KERNEL); if (!toneport) return -ENODEV; - toneport->type = id->driver_info; - return line6_probe(interface, &toneport->line6, + return line6_probe(interface, id, &toneport->line6, &toneport_properties_table[id->driver_info], toneport_init); } diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index cd3adeffde02..ba6e85eed2ba 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -210,11 +210,9 @@ static void line6_variax_process_message(struct usb_line6 *line6) /* Variax destructor. */ -static void line6_variax_disconnect(struct usb_interface *interface) +static void line6_variax_disconnect(struct usb_line6 *line6) { - struct usb_line6_variax *variax; - - variax = usb_get_intfdata(interface); + struct usb_line6_variax *variax = (struct usb_line6_variax *)line6; del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer2); @@ -226,8 +224,8 @@ static void line6_variax_disconnect(struct usb_interface *interface) /* Try to init workbench device. */ -static int variax_init(struct usb_interface *interface, - struct usb_line6 *line6) +static int variax_init(struct usb_line6 *line6, + const struct usb_device_id *id) { struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; int err; @@ -303,7 +301,7 @@ static int variax_probe(struct usb_interface *interface, variax = kzalloc(sizeof(*variax), GFP_KERNEL); if (!variax) return -ENODEV; - return line6_probe(interface, &variax->line6, + return line6_probe(interface, id, &variax->line6, &variax_properties_table[id->driver_info], variax_init); } -- cgit From aca514b82356dcc3575da33453382bd27593aea1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 25 Jan 2015 18:36:29 +0100 Subject: ALSA: line6: Let snd_card_new() allocate private data Instead of allocating the private data individually in each driver's probe at first, let snd_card_new() allocate the data that is called in line6_probe(). This simplifies the primary probe functions. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 25 ++++++++++--------------- sound/usb/line6/driver.h | 4 ++-- sound/usb/line6/pod.c | 9 ++------- sound/usb/line6/podhd.c | 9 ++------- sound/usb/line6/toneport.c | 9 ++------- sound/usb/line6/variax.c | 9 ++------- 6 files changed, 20 insertions(+), 45 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index e2fbff05c1b1..c696f9773cbb 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -418,11 +418,7 @@ EXPORT_SYMBOL_GPL(line6_read_serial_number); 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); @@ -431,9 +427,6 @@ 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); } @@ -489,24 +482,27 @@ static int line6_init_cap_control(struct usb_line6 *line6) */ int line6_probe(struct usb_interface *interface, const struct usb_device_id *id, - struct usb_line6 *line6, const struct line6_properties *properties, - int (*private_init)(struct usb_line6 *, const struct usb_device_id *id)) + 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; + if (WARN_ON(data_size < sizeof(*line6))) + return -EINVAL; + ret = snd_card_new(&interface->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); - if (ret < 0) { - kfree(line6); + 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; @@ -517,7 +513,6 @@ int line6_probe(struct usb_interface *interface, 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); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index 4dc6c28e8224..fce10f12f0d3 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -181,9 +181,9 @@ extern int line6_write_data(struct usb_line6 *line6, int address, void *data, int line6_probe(struct usb_interface *interface, const struct usb_device_id *id, - struct usb_line6 *line6, const struct line6_properties *properties, - int (*private_init)(struct usb_line6 *, const struct usb_device_id *id)); + int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), + size_t data_size); void line6_disconnect(struct usb_interface *interface); diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index d1e952fbcae7..6f7cd585f2d8 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -591,14 +591,9 @@ static const struct line6_properties pod_properties_table[] = { static int pod_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_line6_pod *pod; - - pod = kzalloc(sizeof(*pod), GFP_KERNEL); - if (!pod) - return -ENODEV; - return line6_probe(interface, id, &pod->line6, + return line6_probe(interface, id, &pod_properties_table[id->driver_info], - pod_init); + pod_init, sizeof(struct usb_line6_pod)); } static struct usb_driver pod_driver = { diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 21d7edcfa272..43c39886597e 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -177,14 +177,9 @@ static const struct line6_properties podhd_properties_table[] = { static int podhd_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_line6_podhd *podhd; - - podhd = kzalloc(sizeof(*podhd), GFP_KERNEL); - if (!podhd) - return -ENODEV; - return line6_probe(interface, id, &podhd->line6, + return line6_probe(interface, id, &podhd_properties_table[id->driver_info], - podhd_init); + podhd_init, sizeof(struct usb_line6_podhd)); } static struct usb_driver podhd_driver = { diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 8e7020df0d10..33d16ecf18a0 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -558,14 +558,9 @@ static const struct line6_properties toneport_properties_table[] = { 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; - return line6_probe(interface, id, &toneport->line6, + return line6_probe(interface, id, &toneport_properties_table[id->driver_info], - toneport_init); + toneport_init, sizeof(struct usb_line6_toneport)); } static struct usb_driver toneport_driver = { diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index ba6e85eed2ba..9701ffa61365 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -296,14 +296,9 @@ static const struct line6_properties variax_properties_table[] = { static int variax_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_line6_variax *variax; - - variax = kzalloc(sizeof(*variax), GFP_KERNEL); - if (!variax) - return -ENODEV; - return line6_probe(interface, id, &variax->line6, + return line6_probe(interface, id, &variax_properties_table[id->driver_info], - variax_init); + variax_init, sizeof(struct usb_line6_variax)); } static struct usb_driver variax_driver = { -- cgit From d6ca69d82522cb0e59777deea3673c85c7db7f45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 25 Jan 2015 18:41:26 +0100 Subject: ALSA: line6: Minor tidy up in line6_probe() Move the check of multi configurations before snd_card_new() as a short path, and reduce superfluous pointer references. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index c696f9773cbb..a0436993a167 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -495,6 +495,10 @@ int line6_probe(struct usb_interface *interface, if (WARN_ON(data_size < sizeof(*line6))) return -EINVAL; + /* we don't handle multiple configurations */ + if (usbdev->descriptor.bNumConfigurations != 1) + return -ENODEV; + ret = snd_card_new(&interface->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, data_size, &card); @@ -508,10 +512,10 @@ int line6_probe(struct usb_interface *interface, line6->usbdev = usbdev; line6->ifcdev = &interface->dev; - 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_free = line6_destruct; @@ -520,12 +524,6 @@ int line6_probe(struct usb_interface *interface, /* increment reference counters: */ usb_get_dev(usbdev); - /* we don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) { - ret = -ENODEV; - goto error; - } - /* initialize device info: */ dev_info(&interface->dev, "Line 6 %s found\n", properties->name); @@ -533,7 +531,7 @@ int line6_probe(struct usb_interface *interface, interface_number = interface->cur_altsetting->desc.bInterfaceNumber; ret = usb_set_interface(usbdev, interface_number, - properties->altsetting); + properties->altsetting); if (ret < 0) { dev_err(&interface->dev, "set_interface failed\n"); goto error; @@ -555,7 +553,7 @@ int line6_probe(struct usb_interface *interface, /* 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; -- cgit From 3d3ae4454deb94bbad9ad0b2b559cbf6c0db4ec2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jan 2015 12:50:44 +0100 Subject: ALSA: line6: Fix racy loopback handling The impulse and monitor handling in submit_audio_out_urb() isn't protected thus this can be racy with the capture stream handling. This patch extends the range to protect via each stream's spinlock (now the whole submit_audio_*_urb() are covered), and take the capture stream lock additionally for the impulse and monitor handling part. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 20 +++++++++++--------- sound/usb/line6/playback.c | 24 +++++++++++++----------- 2 files changed, 24 insertions(+), 20 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 47cfcc2ab387..21342a9dddd7 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -20,21 +20,19 @@ /* 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->in.lock, flags); index = find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS); if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->in.lock, flags); dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); return -EINVAL; } @@ -64,7 +62,6 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) dev_err(line6pcm->line6->ifcdev, "URB in #%d submission failed (%d)\n", index, ret); - spin_unlock_irqrestore(&line6pcm->in.lock, flags); return 0; } @@ -73,15 +70,18 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) */ int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) { - int ret, i; + unsigned long flags; + int ret = 0, i; + spin_lock_irqsave(&line6pcm->in.lock, flags); for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_in_urb(line6pcm); if (ret < 0) - return ret; + break; } - return 0; + spin_unlock_irqrestore(&line6pcm->in.lock, flags); + return ret; } /* @@ -137,7 +137,9 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) 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); } } @@ -196,8 +198,6 @@ static void audio_in_callback(struct urb *urb) if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs)) shutdown = 1; - spin_unlock_irqrestore(&line6pcm->in.lock, flags); - if (!shutdown) { submit_audio_in_urb(line6pcm); @@ -206,6 +206,8 @@ static void audio_in_callback(struct urb *urb) &line6pcm->flags)) line6_capture_check_period(line6pcm, length); } + + spin_unlock_irqrestore(&line6pcm->in.lock, flags); } /* open capture callback */ diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 3762a98026aa..b4a26d0c8267 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -134,11 +134,11 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, /* Find a free URB, prepare audio data, and submit URB. + must be called in line6pcm->out.lock context */ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) { int index; - unsigned long flags; int i, urb_size, urb_frames; int ret; const int bytes_per_frame = line6pcm->properties->bytes_per_frame; @@ -149,12 +149,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); struct urb *urb_out; - spin_lock_irqsave(&line6pcm->out.lock, flags); index = find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS); if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->out.lock, flags); dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); return -EINVAL; } @@ -187,7 +185,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) if (urb_size == 0) { /* can't determine URB size */ - spin_unlock_irqrestore(&line6pcm->out.lock, flags); dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); return -EINVAL; } @@ -242,7 +239,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_out->transfer_buffer_length); } - if (line6pcm->prev_fbuf != NULL) { + spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); + if (line6pcm->prev_fbuf) { if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { create_impulse_test_signal(line6pcm, urb_out, bytes_per_frame); @@ -266,6 +264,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) bytes_per_frame); } } + spin_unlock(&line6pcm->in.lock); ret = usb_submit_urb(urb_out, GFP_ATOMIC); @@ -275,7 +274,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) dev_err(line6pcm->line6->ifcdev, "URB out #%d submission failed (%d)\n", index, ret); - spin_unlock_irqrestore(&line6pcm->out.lock, flags); return 0; } @@ -284,15 +282,18 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) */ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) { - int ret, i; + unsigned long flags; + int ret = 0, i; + spin_lock_irqsave(&line6pcm->out.lock, flags); for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_out_urb(line6pcm); if (ret < 0) - return ret; + break; } - return 0; + spin_unlock_irqrestore(&line6pcm->out.lock, flags); + return ret; } /* @@ -346,8 +347,6 @@ static void audio_out_callback(struct urb *urb) if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs)) shutdown = 1; - spin_unlock_irqrestore(&line6pcm->out.lock, flags); - if (!shutdown) { submit_audio_out_urb(line6pcm); @@ -356,10 +355,13 @@ static void audio_out_callback(struct urb *urb) line6pcm->out.bytes += length; if (line6pcm->out.bytes >= line6pcm->out.period) { line6pcm->out.bytes %= line6pcm->out.period; + spin_unlock(&line6pcm->out.lock); snd_pcm_period_elapsed(substream); + spin_lock(&line6pcm->out.lock); } } } + spin_unlock_irqrestore(&line6pcm->out.lock, flags); } /* open playback callback */ -- cgit From f2bb614bb6c7f5245521195f144272ef93d9f086 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jan 2015 16:17:26 +0100 Subject: ALSA: line6: Clear prev_fbuf and prev_fsize properly Clearing prev_fsize in line6_pcm_acquire() is pretty racy. This can be called at any time while the stream is being played. Rather better to clear prev_fbuf and prev_fsize at the proper place like the stream stop for capture, and just after copying the monitor / impulse data inside the spinlock. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 8 ++++---- sound/usb/line6/playback.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index f75825995e24..dedbe24cbf60 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -171,8 +171,6 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) flags_final = 0; - line6pcm->prev_fbuf = NULL; - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { err = line6_alloc_stream_buffer(line6pcm, &line6pcm->in); if (err < 0) @@ -193,7 +191,6 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) } line6pcm->in.count = 0; - line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); if (err < 0) @@ -248,8 +245,11 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) flags_new = flags_old & ~channels; } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) + if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) { line6_unlink_audio_urbs(line6pcm, &line6pcm->in); + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; + } if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index b4a26d0c8267..242265929145 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -166,9 +166,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) struct usb_iso_packet_descriptor *fout = &urb_out->iso_frame_desc[i]; - if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) - fsize = line6pcm->prev_fsize; - + fsize = line6pcm->prev_fsize; if (fsize == 0) { int n; @@ -263,6 +261,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) line6pcm->volume_monitor, bytes_per_frame); } + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; } spin_unlock(&line6pcm->in.lock); -- cgit From 63e20df1e5b2ef8d871ecbdb6c038d554ed1ca74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jan 2015 15:24:09 +0100 Subject: ALSA: line6: Reorganize PCM stream handling The current code deals with the stream start / stop solely via line6_pcm_acquire() and line6_pcm_release(). This was (supposedly) intended to avoid the races, but it doesn't work as expected. The concurrent acquire and release calls can be performed without proper protections, thus this might result in memory corruption. Furthermore, we can't take a mutex to protect the whole function because it can be called from the PCM trigger callback that is an atomic context. Also spinlock isn't appropriate because the function allocates with kmalloc with GFP_KERNEL. That is, these function just lead to singular problems. This is an attempt to reduce the existing races. First off, separate both the stream buffer management and the stream URB management. The former is protected via a newly introduced state_mutex while the latter is protected via each line6_pcm_stream lock. Secondly, the stream state are now managed in opened and running bit flags of each line6_pcm_stream. Not only this a bit clearer than previous combined bit flags, this also gives a better abstraction. These rewrites allows us to make common hw_params and hw_free callbacks for both playback and capture directions. For the monitor and impulse operations, still line6_pcm_acquire() and line6_pcm_release() are used. They call internally the corresponding functions for both playback and capture streams with proper lock or mutex. Unlike the previous versions, these function don't take the bit masks but the only single type value. Also they are supposed to be applied only as duplex operations. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 88 ++---------- sound/usb/line6/capture.h | 1 - sound/usb/line6/pcm.c | 333 +++++++++++++++++++++++++-------------------- sound/usb/line6/pcm.h | 144 ++++++-------------- sound/usb/line6/playback.c | 104 ++------------ sound/usb/line6/playback.h | 1 - sound/usb/line6/toneport.c | 6 +- 7 files changed, 252 insertions(+), 425 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 21342a9dddd7..7b8186b6c0e4 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -67,20 +67,18 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) /* 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) { - unsigned long flags; int ret = 0, i; - spin_lock_irqsave(&line6pcm->in.lock, flags); for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_in_urb(line6pcm); if (ret < 0) break; } - spin_unlock_irqrestore(&line6pcm->in.lock, flags); return ret; } @@ -187,10 +185,10 @@ 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)) - line6_capture_copy(line6pcm, fbuf, fsize); + 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->in.active_urbs); @@ -201,10 +199,9 @@ static void audio_in_callback(struct urb *urb) 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)) - line6_capture_check_period(line6pcm, length); + 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); @@ -234,71 +231,6 @@ 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); - - 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->in.period = 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) @@ -313,8 +245,8 @@ 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, diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index db062e7200a6..890b21bff18c 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -25,6 +25,5 @@ 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 int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); -extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); #endif diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index dedbe24cbf60..470fc1049d54 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -51,9 +51,9 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, line6pcm->impulse_volume = value; if (value > 0) - line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); + line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); else - line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); + line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); return 1; } @@ -132,176 +132,226 @@ static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, "timeout: still %d active urbs..\n", alive); } -static int line6_alloc_stream_buffer(struct snd_line6_pcm *line6pcm, - struct line6_pcm_stream *pcms) +static inline struct line6_pcm_stream * +get_stream(struct snd_line6_pcm *line6pcm, int direction) { - /* Invoked multiple times in a row so allocate once only */ - if (pcms->buffer) - return 0; - - pcms->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!pcms->buffer) - return -ENOMEM; - return 0; + return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? + &line6pcm->out : &line6pcm->in; } -static void line6_free_stream_buffer(struct snd_line6_pcm *line6pcm, - struct line6_pcm_stream *pcms) +/* allocate a buffer if not opened yet; + * call this in line6pcm.state_change mutex + */ +static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pstr, int type) { - kfree(pcms->buffer); - pcms->buffer = NULL; + /* Invoked multiple times in a row so allocate once only */ + if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { + pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * + line6pcm->max_packet_size, GFP_KERNEL); + if (!pstr->buffer) + return -ENOMEM; + } + return 0; } -static bool test_flags(unsigned long flags0, unsigned long flags1, - unsigned long mask) +/* free a buffer if all streams are closed; + * call this in line6pcm.state_change mutex + */ +static void line6_buffer_release(struct snd_line6_pcm *line6pcm, + struct line6_pcm_stream *pstr, int type) { - return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); + + clear_bit(type, &pstr->opened); + if (!pstr->opened) { + line6_wait_clear_audio_urbs(line6pcm, pstr); + kfree(pstr->buffer); + pstr->buffer = NULL; + } } -int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) +/* start a PCM stream */ +static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, + int type) { - unsigned long flags_old, flags_new, flags_final; - int err; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old | channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - flags_final = 0; + unsigned long flags; + struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); + int ret = 0; + + spin_lock_irqsave(&pstr->lock, flags); + if (!test_and_set_bit(type, &pstr->running)) { + if (pstr->active_urbs || pstr->unlink_urbs) { + ret = -EBUSY; + goto error; + } - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { - err = line6_alloc_stream_buffer(line6pcm, &line6pcm->in); - if (err < 0) - goto pcm_acquire_error; - flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; + pstr->count = 0; + /* Submit all currently available URBs */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + ret = line6_submit_audio_out_all_urbs(line6pcm); + else + ret = line6_submit_audio_in_all_urbs(line6pcm); } + error: + if (ret < 0) + clear_bit(type, &pstr->running); + spin_unlock_irqrestore(&pstr->lock, flags); + return ret; +} - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { - /* - Waiting for completion of active URBs in the stop handler is - a bug, we therefore report an error if capturing is restarted - too soon. - */ - if (line6pcm->in.active_urbs || line6pcm->in.unlink_urbs) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - err = -EBUSY; - goto pcm_acquire_error; +/* stop a PCM stream; this doesn't sync with the unlinked URBs */ +static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, + int type) +{ + unsigned long flags; + struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); + + spin_lock_irqsave(&pstr->lock, flags); + clear_bit(type, &pstr->running); + if (!pstr->running) { + line6_unlink_audio_urbs(line6pcm, pstr); + if (direction == SNDRV_PCM_STREAM_CAPTURE) { + line6pcm->prev_fbuf = NULL; + line6pcm->prev_fsize = 0; } + } + spin_unlock_irqrestore(&pstr->lock, flags); +} - line6pcm->in.count = 0; - err = line6_submit_audio_in_all_urbs(line6pcm); +/* common PCM trigger callback */ +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; - if (err < 0) - goto pcm_acquire_error; + clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); - flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; - } + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { - err = line6_alloc_stream_buffer(line6pcm, &line6pcm->out); - if (err < 0) - goto pcm_acquire_error; - flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; - } + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + err = line6_stream_start(line6pcm, s->stream, + LINE6_STREAM_PCM); + if (err < 0) + return err; + break; - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { - /* - See comment above regarding PCM restart. - */ - if (line6pcm->out.active_urbs || line6pcm->out.unlink_urbs) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; - } + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + line6_stream_stop(line6pcm, s->stream, + LINE6_STREAM_PCM); + break; - line6pcm->out.count = 0; - err = line6_submit_audio_out_all_urbs(line6pcm); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); + break; - if (err < 0) - goto pcm_acquire_error; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); + break; - flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; + default: + return -EINVAL; + } } return 0; - -pcm_acquire_error: - /* - If not all requested resources/streams could be obtained, release - those which were successfully obtained (if any). - */ - line6_pcm_release(line6pcm, flags_final); - return err; } -EXPORT_SYMBOL_GPL(line6_pcm_acquire); -int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) +/* Acquire and start duplex streams: + * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR + */ +int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) { - unsigned long flags_old, flags_new; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old & ~channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) { - line6_unlink_audio_urbs(line6pcm, &line6pcm->in); - line6pcm->prev_fbuf = NULL; - line6pcm->prev_fsize = 0; + struct line6_pcm_stream *pstr; + int ret = 0, dir; + + mutex_lock(&line6pcm->state_mutex); + for (dir = 0; dir < 2; dir++) { + pstr = get_stream(line6pcm, dir); + ret = line6_buffer_acquire(line6pcm, pstr, type); + if (ret < 0) + goto error; + if (!pstr->running) + line6_wait_clear_audio_urbs(line6pcm, pstr); } - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { - line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); - line6_free_stream_buffer(line6pcm, &line6pcm->in); + for (dir = 0; dir < 2; dir++) { + ret = line6_stream_start(line6pcm, dir, type); + if (ret < 0) + goto error; } + error: + mutex_unlock(&line6pcm->state_mutex); + if (ret < 0) + line6_pcm_release(line6pcm, type); + return ret; +} +EXPORT_SYMBOL_GPL(line6_pcm_acquire); - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) - line6_unlink_audio_urbs(line6pcm, &line6pcm->out); - - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { - line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); - line6_free_stream_buffer(line6pcm, &line6pcm->out); +/* Stop and release duplex streams */ +void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) +{ + struct line6_pcm_stream *pstr; + int dir; + + mutex_lock(&line6pcm->state_mutex); + for (dir = 0; dir < 2; dir++) + line6_stream_stop(line6pcm, dir, type); + for (dir = 0; dir < 2; dir++) { + pstr = get_stream(line6pcm, dir); + line6_buffer_release(line6pcm, pstr, type); } - - return 0; + mutex_unlock(&line6pcm->state_mutex); } EXPORT_SYMBOL_GPL(line6_pcm_release); -/* trigger callback */ -int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) +/* common PCM hw_params callback */ +int snd_line6_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); - struct snd_pcm_substream *s; - int err = 0; - - 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); - break; + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + mutex_lock(&line6pcm->state_mutex); + ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM); + if (ret < 0) + goto error; + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); + goto error; + } - case SNDRV_PCM_STREAM_CAPTURE: - err = snd_line6_capture_trigger(line6pcm, cmd); - break; + pstr->period = params_period_bytes(hw_params); + error: + mutex_unlock(&line6pcm->state_mutex); + return ret; +} - default: - dev_err(line6pcm->line6->ifcdev, - "Unknown stream direction %d\n", s->stream); - err = -EINVAL; - break; - } - if (err < 0) - break; - } +/* common PCM hw_free callback */ +int snd_line6_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); - return err; + mutex_lock(&line6pcm->state_mutex); + line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); + mutex_unlock(&line6pcm->state_mutex); + return snd_pcm_lib_free_pages(substream); } + /* control info callback */ static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -454,6 +504,7 @@ int line6_init_pcm(struct usb_line6 *line6, if (!line6pcm) return -ENOMEM; + mutex_init(&line6pcm->state_mutex); line6pcm->pcm = pcm; line6pcm->properties = properties; line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; @@ -500,24 +551,13 @@ EXPORT_SYMBOL_GPL(line6_init_pcm); int snd_line6_prepare(struct snd_pcm_substream *substream) { struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) { - line6_unlink_audio_urbs(line6pcm, &line6pcm->out); - line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); - } - break; - - case SNDRV_PCM_STREAM_CAPTURE: - if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) { - line6_unlink_audio_urbs(line6pcm, &line6pcm->in); - line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); - } - break; - } + mutex_lock(&line6pcm->state_mutex); + if (!pstr->running) + line6_wait_clear_audio_urbs(line6pcm, pstr); - if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { + if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { line6pcm->out.count = 0; line6pcm->out.pos = 0; line6pcm->out.pos_done = 0; @@ -527,5 +567,6 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) line6pcm->in.bytes = 0; } + mutex_unlock(&line6pcm->state_mutex); return 0; } diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index 4c74f4e85074..66f603dfa34e 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -54,109 +54,33 @@ However, from the device's point of view, there is just a single capture and playback stream, which must be shared between these subsystems. It is therefore necessary to maintain the state of the - subsystems with respect to PCM usage. We define several constants of - the form LINE6_BIT_PCM___ with the - following meanings: - *) is one of - -) ALSA: PCM playback and capture via ALSA - -) MONITOR: software monitoring - -) IMPULSE: optional impulse response measurement - *) is one of - -) PLAYBACK: audio output (from host to device) - -) CAPTURE: audio input (from device to host) - *) is one of - -) BUFFER: buffer required by PCM data stream - -) STREAM: actual PCM data stream - - The subsystems call line6_pcm_acquire() to acquire the (shared) - resources needed for a particular operation (e.g., allocate the buffer - for ALSA playback or start the capture stream for software monitoring). - When a resource is no longer needed, it is released by calling - line6_pcm_release(). Buffer allocation and stream startup are handled - separately to allow the ALSA kernel driver to perform them at - appropriate places (since the callback which starts a PCM stream is not - allowed to sleep). + subsystems with respect to PCM usage. + + We define two bit flags, "opened" and "running", for each playback + or capture stream. Both can contain the bit flag corresponding to + LINE6_STREAM_* type, + LINE6_STREAM_PCM = ALSA PCM playback or capture + LINE6_STREAM_MONITOR = software monitoring + IMPULSE = optional impulse response measurement + The opened flag indicates whether the buffer is allocated while + the running flag indicates whether the stream is running. + + For monitor or impulse operations, the driver needs to call + snd_line6_duplex_acquire() or snd_line6_duplex_release() with the + appropriate LINE6_STREAM_* flag. */ + +/* stream types */ +enum { + LINE6_STREAM_PCM, + LINE6_STREAM_MONITOR, + LINE6_STREAM_IMPULSE, +}; + +/* misc bit flags for PCM operation */ enum { - /* individual bit indices: */ - LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, - LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, - LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, - LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, - LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, - LINE6_INDEX_PAUSE_PLAYBACK, - LINE6_INDEX_PREPARED, - -#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x - - /* individual bit masks: */ - LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), - LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), - LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), - LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), - LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), - LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), - LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), - LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), - LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), - LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), - LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), - LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), - LINE6_BIT(PAUSE_PLAYBACK), - LINE6_BIT(PREPARED), - - /* combined bit masks (by operation): */ - LINE6_BITS_PCM_ALSA_BUFFER = - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, - - LINE6_BITS_PCM_ALSA_STREAM = - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, - - LINE6_BITS_PCM_MONITOR = - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - - 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, - - /* combined bit masks (by direction): */ - LINE6_BITS_PLAYBACK_BUFFER = - LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, - - LINE6_BITS_PLAYBACK_STREAM = - LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, - - LINE6_BITS_CAPTURE_BUFFER = - LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, - - LINE6_BITS_CAPTURE_STREAM = - LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - - LINE6_BITS_STREAM = - LINE6_BITS_PLAYBACK_STREAM | - LINE6_BITS_CAPTURE_STREAM + LINE6_FLAG_PAUSE_PLAYBACK, + LINE6_FLAG_PREPARED, }; struct line6_pcm_properties { @@ -205,6 +129,12 @@ struct line6_pcm_stream { */ spinlock_t lock; + /* Bit flags for operational stream types */ + unsigned long opened; + + /* Bit flags for running stream types */ + unsigned long running; + int last_frame; }; @@ -224,6 +154,9 @@ struct snd_line6_pcm { */ struct snd_pcm *pcm; + /* protection to state changes of in/out streams */ + struct mutex state_mutex; + /* Capture and playback streams */ struct line6_pcm_stream in; struct line6_pcm_stream out; @@ -269,7 +202,7 @@ struct snd_line6_pcm { int impulse_count; /** - Several status bits (see LINE6_BIT_*). + Several status bits (see LINE6_FLAG_*). */ unsigned long flags; }; @@ -278,8 +211,11 @@ extern int line6_init_pcm(struct usb_line6 *line6, struct line6_pcm_properties *properties); extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); extern int snd_line6_prepare(struct snd_pcm_substream *substream); +extern int snd_line6_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); +extern int snd_line6_hw_free(struct snd_pcm_substream *substream); extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); -extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); -extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); +extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); +extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); #endif diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 242265929145..f8b04e2d36b3 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -194,8 +194,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_out->transfer_buffer_length = urb_size; urb_out->context = line6pcm; - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) && - !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) { + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) && + !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) { struct snd_pcm_runtime *runtime = get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; @@ -239,11 +239,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); if (line6pcm->prev_fbuf) { - if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { + if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) { create_impulse_test_signal(line6pcm, urb_out, bytes_per_frame); - if (line6pcm->flags & - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) { + if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) { line6_capture_copy(line6pcm, urb_out->transfer_buffer, urb_out-> @@ -252,11 +251,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) urb_out->transfer_buffer_length); } } else { - if (! - (line6pcm->line6-> - properties->capabilities & LINE6_CAP_HWMON) - && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) - && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) + if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON) + && line6pcm->out.running && line6pcm->in.running) add_monitor_signal(urb_out, line6pcm->prev_fbuf, line6pcm->volume_monitor, bytes_per_frame); @@ -279,20 +275,18 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) /* Submit all currently available playback URBs. -*/ + must be called in line6pcm->out.lock context + */ int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) { - unsigned long flags; int ret = 0, i; - spin_lock_irqsave(&line6pcm->out.lock, flags); for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { ret = submit_audio_out_urb(line6pcm); if (ret < 0) break; } - spin_unlock_irqrestore(&line6pcm->out.lock, flags); return ret; } @@ -326,7 +320,7 @@ static void audio_out_callback(struct urb *urb) spin_lock_irqsave(&line6pcm->out.lock, flags); - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { struct snd_pcm_runtime *runtime = substream->runtime; line6pcm->out.pos_done += @@ -350,8 +344,7 @@ static void audio_out_callback(struct urb *urb) if (!shutdown) { submit_audio_out_urb(line6pcm); - if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, - &line6pcm->flags)) { + if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { line6pcm->out.bytes += length; if (line6pcm->out.bytes >= line6pcm->out.period) { line6pcm->out.bytes %= line6pcm->out.period; @@ -387,79 +380,6 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) return 0; } -/* hw_params playback callback */ -static int snd_line6_playback_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); - - ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_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_PLAYBACK_BUFFER); - return ret; - } - - line6pcm->out.period = params_period_bytes(hw_params); - return 0; -} - -/* 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); - - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); - return snd_pcm_lib_free_pages(substream); -} - -/* trigger playback callback */ -int snd_line6_playback_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_PLAYBACK_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_PLAYBACK_STREAM); - - if (err < 0) - return err; - - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - /* playback pointer callback */ static snd_pcm_uframes_t snd_line6_playback_pointer(struct snd_pcm_substream *substream) @@ -474,8 +394,8 @@ struct snd_pcm_ops snd_line6_playback_ops = { .open = snd_line6_playback_open, .close = snd_line6_playback_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_line6_playback_hw_params, - .hw_free = snd_line6_playback_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_playback_pointer, diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index f6a9e18f87b6..51fce29e8726 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -31,6 +31,5 @@ extern struct snd_pcm_ops snd_line6_playback_ops; extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); -extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); #endif diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 33d16ecf18a0..61fa6256d7b0 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -189,9 +189,9 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, line6pcm->volume_monitor = ucontrol->value.integer.value[0]; if (line6pcm->volume_monitor > 0) - line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); else - line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); return 1; } @@ -252,7 +252,7 @@ static void toneport_start_pcm(unsigned long arg) struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; struct usb_line6 *line6 = &toneport->line6; - line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); + line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); } /* control definition */ -- cgit From 2954f914f2816738b800be7909b771f30bf6a856 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jan 2015 15:41:27 +0100 Subject: ALSA: line6: Make common PCM pointer callback Both playback and capture callbacks are identical, so let's merge them. Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 11 +---------- sound/usb/line6/pcm.c | 9 +++++++++ sound/usb/line6/pcm.h | 1 + sound/usb/line6/playback.c | 11 +---------- 4 files changed, 12 insertions(+), 20 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 7b8186b6c0e4..4183c5f5edc2 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -231,15 +231,6 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) 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->in.pos_done; -} - /* capture operators */ struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, @@ -249,7 +240,7 @@ struct snd_pcm_ops snd_line6_capture_ops = { .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) diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 470fc1049d54..73c87467d2e0 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -266,6 +266,15 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } +/* common PCM pointer callback */ +snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) +{ + struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); + struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); + + return pstr->pos_done; +} + /* Acquire and start duplex streams: * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR */ diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index 66f603dfa34e..42d3e6fc2c61 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -214,6 +214,7 @@ extern int snd_line6_prepare(struct snd_pcm_substream *substream); extern int snd_line6_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params); extern int snd_line6_hw_free(struct snd_pcm_substream *substream); +extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream); extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index f8b04e2d36b3..1708c05f14db 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -380,15 +380,6 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) return 0; } -/* playback pointer callback */ -static snd_pcm_uframes_t -snd_line6_playback_pointer(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - return line6pcm->out.pos_done; -} - /* playback operators */ struct snd_pcm_ops snd_line6_playback_ops = { .open = snd_line6_playback_open, @@ -398,7 +389,7 @@ struct snd_pcm_ops snd_line6_playback_ops = { .hw_free = snd_line6_hw_free, .prepare = snd_line6_prepare, .trigger = snd_line6_trigger, - .pointer = snd_line6_playback_pointer, + .pointer = snd_line6_pointer, }; int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) -- cgit From 247d95ee6dd22e5323ecf7a73ff64110ef2fa2da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Jan 2015 16:42:14 +0100 Subject: ALSA: line6: Handle error from line6_pcm_acquire() Tested-by: Chris Rorvick Signed-off-by: Takashi Iwai --- sound/usb/line6/pcm.c | 13 ++++++++++--- sound/usb/line6/toneport.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index 73c87467d2e0..8461d6bf992f 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c @@ -45,15 +45,22 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, { struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); int value = ucontrol->value.integer.value[0]; + int err; if (line6pcm->impulse_volume == value) return 0; line6pcm->impulse_volume = value; - if (value > 0) - line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); - else + if (value > 0) { + err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); + if (err < 0) { + line6pcm->impulse_volume = 0; + line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); + return err; + } + } else { line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); + } return 1; } diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 61fa6256d7b0..819e06b3f3db 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -182,16 +182,23 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); + int err; if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) return 0; line6pcm->volume_monitor = ucontrol->value.integer.value[0]; - if (line6pcm->volume_monitor > 0) - line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); - else + if (line6pcm->volume_monitor > 0) { + err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); + if (err < 0) { + line6pcm->volume_monitor = 0; + line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); + return err; + } + } else { line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); + } return 1; } -- cgit