"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "sound/usb/card.c" between
linux-3.16.62.tar.xz and linux-3.16.63.tar.xz

About: The full source of the Linux kernel 3.16.x (longterm stable)

card.c  (linux-3.16.62.tar.xz):card.c  (linux-3.16.63.tar.xz)
skipping to change at line 397 skipping to change at line 397
return err; return err;
} }
chip = kzalloc(sizeof(*chip), GFP_KERNEL); chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (! chip) { if (! chip) {
snd_card_free(card); snd_card_free(card);
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&chip->mutex); mutex_init(&chip->mutex);
init_rwsem(&chip->shutdown_rwsem); init_waitqueue_head(&chip->shutdown_wait);
chip->index = idx; chip->index = idx;
chip->dev = dev; chip->dev = dev;
chip->card = card; chip->card = card;
chip->setup = device_setup[idx]; chip->setup = device_setup[idx];
chip->autoclock = autoclock; chip->autoclock = autoclock;
chip->probing = 1; atomic_set(&chip->active, 1); /* avoid autopm during probing */
atomic_set(&chip->usage_count, 0);
atomic_set(&chip->shutdown, 0);
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idProduct));
INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->ep_list); INIT_LIST_HEAD(&chip->ep_list);
INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list); INIT_LIST_HEAD(&chip->mixer_list);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_usb_audio_free(chip); snd_usb_audio_free(chip);
skipping to change at line 526 skipping to change at line 528
/* /*
* found a config. now register to ALSA * found a config. now register to ALSA
*/ */
/* check whether it's already registered */ /* check whether it's already registered */
chip = NULL; chip = NULL;
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
for (i = 0; i < SNDRV_CARDS; i++) { for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) { if (usb_chip[i] && usb_chip[i]->dev == dev) {
if (usb_chip[i]->shutdown) { if (atomic_read(&usb_chip[i]->shutdown)) {
dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
goto __error; goto __error;
} }
chip = usb_chip[i]; chip = usb_chip[i];
chip->probing = 1; atomic_inc(&chip->active); /* avoid autopm */
break; break;
} }
} }
if (! chip) { if (! chip) {
/* it's a fresh one. /* it's a fresh one.
* now look for an empty slot and create a new card instance * now look for an empty slot and create a new card instance
*/ */
for (i = 0; i < SNDRV_CARDS; i++) for (i = 0; i < SNDRV_CARDS; i++)
if (enable[i] && ! usb_chip[i] && if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
skipping to change at line 587 skipping to change at line 589
} }
} }
/* we are allowed to call snd_card_register() many times */ /* we are allowed to call snd_card_register() many times */
if (snd_card_register(chip->card) < 0) { if (snd_card_register(chip->card) < 0) {
goto __error; goto __error;
} }
usb_chip[chip->index] = chip; usb_chip[chip->index] = chip;
chip->num_interfaces++; chip->num_interfaces++;
chip->probing = 0; atomic_dec(&chip->active);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
return chip; return chip;
__error: __error:
if (chip) { if (chip) {
/* chip->active is inside the chip->card object,
* decrement before memory is possibly returned.
*/
atomic_dec(&chip->active);
if (!chip->num_interfaces) if (!chip->num_interfaces)
snd_card_free(chip->card); snd_card_free(chip->card);
chip->probing = 0;
} }
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
__err_val: __err_val:
return NULL; return NULL;
} }
/* /*
* we need to take care of counter, since disconnection can be called also * we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe(). * many times as well as usb_audio_probe().
*/ */
static void snd_usb_audio_disconnect(struct usb_device *dev, static void snd_usb_audio_disconnect(struct usb_device *dev,
struct snd_usb_audio *chip) struct snd_usb_audio *chip)
{ {
struct snd_card *card; struct snd_card *card;
struct list_head *p; struct list_head *p;
bool was_shutdown;
if (chip == (void *)-1L) if (chip == (void *)-1L)
return; return;
card = chip->card; card = chip->card;
down_write(&chip->shutdown_rwsem);
was_shutdown = chip->shutdown;
chip->shutdown = 1;
up_write(&chip->shutdown_rwsem);
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
if (!was_shutdown) { if (atomic_inc_return(&chip->shutdown) == 1) {
struct snd_usb_endpoint *ep; struct snd_usb_endpoint *ep;
/* wait until all pending tasks done;
* they are protected by snd_usb_lock_shutdown()
*/
wait_event(chip->shutdown_wait,
!atomic_read(&chip->usage_count));
snd_card_disconnect(card); snd_card_disconnect(card);
/* release the pcm resources */ /* release the pcm resources */
list_for_each(p, &chip->pcm_list) { list_for_each(p, &chip->pcm_list) {
snd_usb_stream_disconnect(p); snd_usb_stream_disconnect(p);
} }
/* release the endpoint resources */ /* release the endpoint resources */
list_for_each_entry(ep, &chip->ep_list, list) { list_for_each_entry(ep, &chip->ep_list, list) {
snd_usb_endpoint_release(ep); snd_usb_endpoint_release(ep);
} }
/* release the midi resources */ /* release the midi resources */
skipping to change at line 676 skipping to change at line 681
} else } else
return -EIO; return -EIO;
} }
static void usb_audio_disconnect(struct usb_interface *intf) static void usb_audio_disconnect(struct usb_interface *intf)
{ {
snd_usb_audio_disconnect(interface_to_usbdev(intf), snd_usb_audio_disconnect(interface_to_usbdev(intf),
usb_get_intfdata(intf)); usb_get_intfdata(intf));
} }
#ifdef CONFIG_PM /* lock the shutdown (disconnect) task and autoresume */
int snd_usb_lock_shutdown(struct snd_usb_audio *chip)
int snd_usb_autoresume(struct snd_usb_audio *chip)
{ {
int err = -ENODEV; int err;
down_read(&chip->shutdown_rwsem); atomic_inc(&chip->usage_count);
if (chip->probing || chip->in_pm) if (atomic_read(&chip->shutdown)) {
err = 0; err = -EIO;
else if (!chip->shutdown) goto error;
err = usb_autopm_get_interface(chip->pm_intf); }
up_read(&chip->shutdown_rwsem); err = snd_usb_autoresume(chip);
if (err < 0)
goto error;
return 0;
error:
if (atomic_dec_and_test(&chip->usage_count))
wake_up(&chip->shutdown_wait);
return err; return err;
} }
/* autosuspend and unlock the shutdown */
void snd_usb_unlock_shutdown(struct snd_usb_audio *chip)
{
snd_usb_autosuspend(chip);
if (atomic_dec_and_test(&chip->usage_count))
wake_up(&chip->shutdown_wait);
}
#ifdef CONFIG_PM
int snd_usb_autoresume(struct snd_usb_audio *chip)
{
if (atomic_read(&chip->shutdown))
return -EIO;
if (atomic_inc_return(&chip->active) == 1)
return usb_autopm_get_interface(chip->pm_intf);
return 0;
}
void snd_usb_autosuspend(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip)
{ {
down_read(&chip->shutdown_rwsem); if (atomic_dec_and_test(&chip->active))
if (!chip->shutdown && !chip->probing && !chip->in_pm)
usb_autopm_put_interface(chip->pm_intf); usb_autopm_put_interface(chip->pm_intf);
up_read(&chip->shutdown_rwsem);
} }
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_usb_stream *as; struct snd_usb_stream *as;
struct usb_mixer_interface *mixer; struct usb_mixer_interface *mixer;
if (chip == (void *)-1L) if (chip == (void *)-1L)
return 0; return 0;
skipping to change at line 745 skipping to change at line 772
{ {
struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct usb_mixer_interface *mixer; struct usb_mixer_interface *mixer;
int err = 0; int err = 0;
if (chip == (void *)-1L) if (chip == (void *)-1L)
return 0; return 0;
if (--chip->num_suspended_intf) if (--chip->num_suspended_intf)
return 0; return 0;
chip->in_pm = 1; atomic_inc(&chip->active); /* avoid autopm */
/* /*
* ALSA leaves material resumption to user space * ALSA leaves material resumption to user space
* we just notify and restart the mixers * we just notify and restart the mixers
*/ */
list_for_each_entry(mixer, &chip->mixer_list, list) { list_for_each_entry(mixer, &chip->mixer_list, list) {
err = snd_usb_mixer_resume(mixer, reset_resume); err = snd_usb_mixer_resume(mixer, reset_resume);
if (err < 0) if (err < 0)
goto err_out; goto err_out;
} }
if (!chip->autosuspended) if (!chip->autosuspended)
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
chip->autosuspended = 0; chip->autosuspended = 0;
err_out: err_out:
chip->in_pm = 0; atomic_dec(&chip->active); /* allow autopm after this point */
return err; return err;
} }
static int usb_audio_resume(struct usb_interface *intf) static int usb_audio_resume(struct usb_interface *intf)
{ {
return __usb_audio_resume(intf, false); return __usb_audio_resume(intf, false);
} }
static int usb_audio_reset_resume(struct usb_interface *intf) static int usb_audio_reset_resume(struct usb_interface *intf)
{ {
 End of changes. 20 change blocks. 
27 lines changed or deleted 54 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)