Loading sound/usb/card.c +67 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,71 @@ static DEFINE_MUTEX(register_mutex); static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; static struct usb_driver usb_audio_driver; struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)) { int idx; struct snd_usb_stream *as; struct snd_usb_substream *subs = NULL; struct snd_usb_audio *chip = NULL; mutex_lock(®ister_mutex); /* * legacy audio snd card number assignment is dynamic. Hence * search using chip->card->number */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!usb_chip[idx]) continue; if (usb_chip[idx]->card->number == card_num) { chip = usb_chip[idx]; break; } } if (!chip || atomic_read(&chip->shutdown)) { pr_debug("%s: instance of usb crad # %d does not exist\n", __func__, card_num); goto err; } if (pcm_idx >= chip->pcm_devs) { pr_err("%s: invalid pcm dev number %u > %d\n", __func__, pcm_idx, chip->pcm_devs); goto err; } if (direction > SNDRV_PCM_STREAM_CAPTURE) { pr_err("%s: invalid direction %u\n", __func__, direction); goto err; } list_for_each_entry(as, &chip->pcm_list, list) { if (as->pcm_index == pcm_idx) { subs = &as->substream[direction]; if (subs->interface < 0 && !subs->data_endpoint && !subs->sync_endpoint) { pr_debug("%s: stream disconnected, bail out\n", __func__); subs = NULL; goto err; } goto done; } } done: chip->card_num = card_num; chip->disconnect_cb = disconnect_cb; err: *uchip = chip; if (!subs) pr_debug("%s: substream instance not found\n", __func__); mutex_unlock(®ister_mutex); return subs; } /* * disconnect streams * called from usb_audio_disconnect() Loading Loading @@ -693,6 +758,8 @@ static void usb_audio_disconnect(struct usb_interface *intf) if (chip->num_interfaces <= 0) { usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); if (chip->disconnect_cb) chip->disconnect_cb(chip); snd_card_free_when_closed(card); } else { mutex_unlock(®ister_mutex); Loading sound/usb/card.h +4 −0 Original line number Diff line number Diff line Loading @@ -167,4 +167,8 @@ struct snd_usb_stream { struct list_head list; }; struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)); #endif /* __USBAUDIO_CARD_H */ sound/usb/pcm.c +64 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,70 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) return 0; } int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, bool enable) { struct audioformat *fmt; struct usb_host_interface *alts; struct usb_interface *iface; int ret; if (!enable) { if (subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); subs->altset_idx = 0; subs->interface = -1; subs->cur_audiofmt = NULL; } snd_usb_autosuspend(subs->stream->chip); return 0; } snd_usb_autoresume(subs->stream->chip); fmt = find_format(subs); if (!fmt) { dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); return -EINVAL; } subs->altset_idx = 0; subs->interface = -1; if (atomic_read(&subs->stream->chip->shutdown)) { ret = -ENODEV; } else { ret = set_format(subs, fmt); if (ret < 0) return ret; iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); if (!iface) { dev_err(&subs->dev->dev, "Could not get iface %d\n", subs->cur_audiofmt->iface); return -ENODEV; } alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; ret = snd_usb_init_sample_rate(subs->stream->chip, subs->cur_audiofmt->iface, alts, subs->cur_audiofmt, subs->cur_rate); if (ret < 0) { dev_err(&subs->dev->dev, "failed to set rate %d\n", subs->cur_rate); return ret; } } subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; return 0; } /* * Return the score of matching two audioformats. * Veto the audioformat if: Loading sound/usb/pcm.h +2 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt); int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, bool enable); #endif /* __USBAUDIO_PCM_H */ sound/usb/usbaudio.h +2 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ struct snd_usb_audio { bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ int card_num; /* cache pcm card number to use upon disconnect */ void (*disconnect_cb)(struct snd_usb_audio *chip); }; #define usb_audio_err(chip, fmt, args...) \ Loading Loading
sound/usb/card.c +67 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,71 @@ static DEFINE_MUTEX(register_mutex); static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; static struct usb_driver usb_audio_driver; struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)) { int idx; struct snd_usb_stream *as; struct snd_usb_substream *subs = NULL; struct snd_usb_audio *chip = NULL; mutex_lock(®ister_mutex); /* * legacy audio snd card number assignment is dynamic. Hence * search using chip->card->number */ for (idx = 0; idx < SNDRV_CARDS; idx++) { if (!usb_chip[idx]) continue; if (usb_chip[idx]->card->number == card_num) { chip = usb_chip[idx]; break; } } if (!chip || atomic_read(&chip->shutdown)) { pr_debug("%s: instance of usb crad # %d does not exist\n", __func__, card_num); goto err; } if (pcm_idx >= chip->pcm_devs) { pr_err("%s: invalid pcm dev number %u > %d\n", __func__, pcm_idx, chip->pcm_devs); goto err; } if (direction > SNDRV_PCM_STREAM_CAPTURE) { pr_err("%s: invalid direction %u\n", __func__, direction); goto err; } list_for_each_entry(as, &chip->pcm_list, list) { if (as->pcm_index == pcm_idx) { subs = &as->substream[direction]; if (subs->interface < 0 && !subs->data_endpoint && !subs->sync_endpoint) { pr_debug("%s: stream disconnected, bail out\n", __func__); subs = NULL; goto err; } goto done; } } done: chip->card_num = card_num; chip->disconnect_cb = disconnect_cb; err: *uchip = chip; if (!subs) pr_debug("%s: substream instance not found\n", __func__); mutex_unlock(®ister_mutex); return subs; } /* * disconnect streams * called from usb_audio_disconnect() Loading Loading @@ -693,6 +758,8 @@ static void usb_audio_disconnect(struct usb_interface *intf) if (chip->num_interfaces <= 0) { usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); if (chip->disconnect_cb) chip->disconnect_cb(chip); snd_card_free_when_closed(card); } else { mutex_unlock(®ister_mutex); Loading
sound/usb/card.h +4 −0 Original line number Diff line number Diff line Loading @@ -167,4 +167,8 @@ struct snd_usb_stream { struct list_head list; }; struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)); #endif /* __USBAUDIO_CARD_H */
sound/usb/pcm.c +64 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,70 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) return 0; } int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, bool enable) { struct audioformat *fmt; struct usb_host_interface *alts; struct usb_interface *iface; int ret; if (!enable) { if (subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); subs->altset_idx = 0; subs->interface = -1; subs->cur_audiofmt = NULL; } snd_usb_autosuspend(subs->stream->chip); return 0; } snd_usb_autoresume(subs->stream->chip); fmt = find_format(subs); if (!fmt) { dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); return -EINVAL; } subs->altset_idx = 0; subs->interface = -1; if (atomic_read(&subs->stream->chip->shutdown)) { ret = -ENODEV; } else { ret = set_format(subs, fmt); if (ret < 0) return ret; iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); if (!iface) { dev_err(&subs->dev->dev, "Could not get iface %d\n", subs->cur_audiofmt->iface); return -ENODEV; } alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; ret = snd_usb_init_sample_rate(subs->stream->chip, subs->cur_audiofmt->iface, alts, subs->cur_audiofmt, subs->cur_rate); if (ret < 0) { dev_err(&subs->dev->dev, "failed to set rate %d\n", subs->cur_rate); return ret; } } subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; return 0; } /* * Return the score of matching two audioformats. * Veto the audioformat if: Loading
sound/usb/pcm.h +2 −1 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt); int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, bool enable); #endif /* __USBAUDIO_PCM_H */
sound/usb/usbaudio.h +2 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ struct snd_usb_audio { bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ int card_num; /* cache pcm card number to use upon disconnect */ void (*disconnect_cb)(struct snd_usb_audio *chip); }; #define usb_audio_err(chip, fmt, args...) \ Loading