diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-01-19 15:54:00 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-01-20 08:17:16 +0100 |
commit | 85a9339becf0af4d547ceb6bb16d1893b05fbce4 (patch) | |
tree | 0f25a3def6f9aeca37f942c4aa70b88772a48259 /sound/usb/line6/driver.c | |
parent | 84ac9bb12e8158e1affad4ae7718eb653fa5e36d (diff) | |
download | lwn-85a9339becf0af4d547ceb6bb16d1893b05fbce4.tar.gz lwn-85a9339becf0af4d547ceb6bb16d1893b05fbce4.zip |
ALSA: line6: Reorganize card resource handling
This is a fairly big rewrite regarding the card resource management in
line6 drivers:
- The card creation is moved into line6_probe(). This adds the global
destructor to private_free, so that each driver doesn't have to call
it any longer.
- The USB disconnect callback handles the card release, thus each
driver needs to concentrate on only its own resources. No need to
snd_card_*() call in the destructor.
- Fix the potential stall in disconnection by removing
snd_card_free(). It's replaced with snd_card_free_when_closed()
for asynchronous release.
- The only remaining operation for the card in each driver is the call
of snd_card_register(). All the rest are dealt in the common module
by itself.
- These ended up with removal of audio.[ch] as a result of a reduction
of one layer. Each driver just needs to call line6_probe().
Tested-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/line6/driver.c')
-rw-r--r-- | sound/usb/line6/driver.c | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index b8f5134dcec2..8b6a658a8a58 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -15,7 +15,9 @@ #include <linux/slab.h> #include <linux/usb.h> -#include "audio.h" +#include <sound/core.h> +#include <sound/initval.h> + #include "capture.h" #include "driver.h" #include "midi.h" @@ -481,17 +483,16 @@ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, EXPORT_SYMBOL_GPL(line6_nop_read); /* - Generic destructor. + Card destructor. */ -static void line6_destruct(struct usb_interface *interface) +static void line6_destruct(struct snd_card *card) { - struct usb_line6 *line6; + struct usb_line6 *line6 = card->private_data; + struct usb_device *usbdev; - if (interface == NULL) - return; - line6 = usb_get_intfdata(interface); - if (line6 == NULL) + if (!line6) return; + usbdev = line6->usbdev; /* free buffer memory first: */ kfree(line6->buffer_message); @@ -500,8 +501,11 @@ static void line6_destruct(struct usb_interface *interface) /* then free URBs: */ usb_free_urb(line6->urb_listen); - /* make sure the device isn't destructed twice: */ - usb_set_intfdata(interface, NULL); + /* free interface data: */ + kfree(line6); + + /* decrement reference counters: */ + usb_put_dev(usbdev); } /* @@ -513,6 +517,7 @@ int line6_probe(struct usb_interface *interface, int (*private_init)(struct usb_interface *, struct usb_line6 *)) { struct usb_device *usbdev; + struct snd_card *card; int interface_number; int ret; @@ -569,8 +574,26 @@ int line6_probe(struct usb_interface *interface, } } + ret = snd_card_new(line6->ifcdev, + SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (ret < 0) + goto err_put; + + line6->card = card; + strcpy(card->id, line6->properties->id); + strcpy(card->driver, DRIVER_NAME); + strcpy(card->shortname, line6->properties->name); + sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, + dev_name(line6->ifcdev)); + card->private_data = line6; + card->private_free = line6_destruct; + usb_set_intfdata(interface, line6); + /* increment reference counters: */ + usb_get_dev(usbdev); + if (properties->capabilities & LINE6_CAP_CONTROL) { /* initialize USB buffers: */ line6->buffer_listen = @@ -612,15 +635,11 @@ int line6_probe(struct usb_interface *interface, dev_info(&interface->dev, "Line6 %s now attached\n", line6->properties->name); - /* increment reference counters: */ - usb_get_intf(interface); - usb_get_dev(usbdev); - return 0; -err_destruct: - line6_destruct(interface); -err_put: + err_destruct: + snd_card_free(card); + err_put: return ret; } EXPORT_SYMBOL_GPL(line6_probe); @@ -642,29 +661,26 @@ void line6_disconnect(struct usb_interface *interface) interface_number = interface->cur_altsetting->desc.bInterfaceNumber; line6 = usb_get_intfdata(interface); + if (!line6) + return; - if (line6 != NULL) { - if (line6->urb_listen != NULL) - line6_stop_listen(line6); + if (line6->urb_listen != NULL) + line6_stop_listen(line6); - if (usbdev != line6->usbdev) - dev_err(line6->ifcdev, - "driver bug: inconsistent usb device\n"); + if (usbdev != line6->usbdev) + dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n"); + snd_card_disconnect(line6->card); + if (line6->disconnect) line6->disconnect(interface); - dev_info(&interface->dev, "Line6 %s now disconnected\n", - line6->properties->name); - } - - line6_destruct(interface); + dev_info(&interface->dev, "Line6 %s now disconnected\n", + line6->properties->name); - /* free interface data: */ - kfree(line6); + /* make sure the device isn't destructed twice: */ + usb_set_intfdata(interface, NULL); - /* decrement reference counters: */ - usb_put_intf(interface); - usb_put_dev(usbdev); + snd_card_free_when_closed(line6->card); } EXPORT_SYMBOL_GPL(line6_disconnect); |