diff options
Diffstat (limited to 'sound/usb/hiface/pcm.c')
| -rw-r--r-- | sound/usb/hiface/pcm.c | 133 |
1 files changed, 53 insertions, 80 deletions
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index 6430ed2a9f65..27cd427fbaa5 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Linux driver for M2Tech hiFace compatible devices * @@ -7,11 +8,6 @@ * Antonio Ospite <ao2@amarulasolutions.com> * * The driver is based on the work done in TerraTec DMX 6Fire USB - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/slab.h> @@ -110,7 +106,7 @@ static const struct snd_pcm_hardware pcm_hw = { #define HIFACE_RATE_96000 0x4a #define HIFACE_RATE_176400 0x40 #define HIFACE_RATE_192000 0x48 -#define HIFACE_RATE_352000 0x58 +#define HIFACE_RATE_352800 0x58 #define HIFACE_RATE_384000 0x68 static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) @@ -141,8 +137,8 @@ static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) case 192000: rate_value = HIFACE_RATE_192000; break; - case 352000: - rate_value = HIFACE_RATE_352000; + case 352800: + rate_value = HIFACE_RATE_352800; break; case 384000: rate_value = HIFACE_RATE_384000; @@ -160,16 +156,14 @@ static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) * This control message doesn't have any ack from the * other side */ - ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), - HIFACE_SET_RATE_REQUEST, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - rate_value, 0, NULL, 0, 100); - if (ret < 0) { + ret = usb_control_msg_send(device, 0, + HIFACE_SET_RATE_REQUEST, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + rate_value, 0, NULL, 0, 100, GFP_KERNEL); + if (ret) dev_err(&device->dev, "Error setting samplerate %d.\n", rate); - return ret; - } - return 0; + return ret; } static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream @@ -231,7 +225,7 @@ static int hiface_pcm_stream_start(struct pcm_runtime *rt) } } - /* wait for first out urb to return (sent in in urb handler) */ + /* wait for first out urb to return (sent in urb handler) */ wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, HZ); if (rt->stream_wait_cond) { @@ -311,7 +305,6 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb) struct pcm_runtime *rt = out_urb->chip->pcm; struct pcm_substream *sub; bool do_period_elapsed = false; - unsigned long flags; int ret; if (rt->panic || rt->stream_state == STREAM_STOPPING) @@ -331,13 +324,12 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb) /* now send our playback data (if a free out urb was found) */ sub = &rt->playback; - spin_lock_irqsave(&sub->lock, flags); - if (sub->active) - do_period_elapsed = hiface_pcm_playback(sub, out_urb); - else - memset(out_urb->buffer, 0, PCM_PACKET_SIZE); - - spin_unlock_irqrestore(&sub->lock, flags); + scoped_guard(spinlock_irqsave, &sub->lock) { + if (sub->active) + do_period_elapsed = hiface_pcm_playback(sub, out_urb); + else + memset(out_urb->buffer, 0, PCM_PACKET_SIZE); + } if (do_period_elapsed) snd_pcm_period_elapsed(sub->instance); @@ -362,7 +354,7 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) if (rt->panic) return -EPIPE; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); alsa_rt->hw = pcm_hw; if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -370,7 +362,6 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) if (!sub) { struct device *device = &rt->chip->dev->dev; - mutex_unlock(&rt->stream_mutex); dev_err(device, "Invalid stream type\n"); return -EINVAL; } @@ -383,15 +374,12 @@ static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_extra_rates); - if (ret < 0) { - mutex_unlock(&rt->stream_mutex); + if (ret < 0) return ret; - } } sub->instance = alsa_sub; sub->active = false; - mutex_unlock(&rt->stream_mutex); return 0; } @@ -399,38 +387,22 @@ static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) { struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); - unsigned long flags; if (rt->panic) return 0; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); if (sub) { hiface_pcm_stream_stop(rt); /* deactivate substream */ - spin_lock_irqsave(&sub->lock, flags); + guard(spinlock_irqsave)(&sub->lock); sub->instance = NULL; sub->active = false; - spin_unlock_irqrestore(&sub->lock, flags); - } - mutex_unlock(&rt->stream_mutex); return 0; } -static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub, - struct snd_pcm_hw_params *hw_params) -{ - return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub, - params_buffer_bytes(hw_params)); -} - -static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub) -{ - return snd_pcm_lib_free_vmalloc_buffer(alsa_sub); -} - static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) { struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); @@ -443,7 +415,9 @@ static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (!sub) return -ENODEV; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); + + hiface_pcm_stream_stop(rt); sub->dma_off = 0; sub->period_off = 0; @@ -451,17 +425,12 @@ static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) if (rt->stream_state == STREAM_DISABLED) { ret = hiface_pcm_set_rate(rt, alsa_rt->rate); - if (ret) { - mutex_unlock(&rt->stream_mutex); + if (ret) return ret; - } ret = hiface_pcm_stream_start(rt); - if (ret) { - mutex_unlock(&rt->stream_mutex); + if (ret) return ret; - } } - mutex_unlock(&rt->stream_mutex); return 0; } @@ -478,16 +447,16 @@ static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock_irq(&sub->lock); - sub->active = true; - spin_unlock_irq(&sub->lock); + scoped_guard(spinlock_irq, &sub->lock) { + sub->active = true; + } return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irq(&sub->lock); - sub->active = false; - spin_unlock_irq(&sub->lock); + scoped_guard(spinlock_irq, &sub->lock) { + sub->active = false; + } return 0; default: @@ -499,29 +468,22 @@ static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub) { struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); - unsigned long flags; snd_pcm_uframes_t dma_offset; if (rt->panic || !sub) - return SNDRV_PCM_STATE_XRUN; + return SNDRV_PCM_POS_XRUN; - spin_lock_irqsave(&sub->lock, flags); + guard(spinlock_irqsave)(&sub->lock); dma_offset = sub->dma_off; - spin_unlock_irqrestore(&sub->lock, flags); return bytes_to_frames(alsa_sub->runtime, dma_offset); } -static struct snd_pcm_ops pcm_ops = { +static const struct snd_pcm_ops pcm_ops = { .open = hiface_pcm_open, .close = hiface_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = hiface_pcm_hw_params, - .hw_free = hiface_pcm_hw_free, .prepare = hiface_pcm_prepare, .trigger = hiface_pcm_trigger, .pointer = hiface_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, }; static int hiface_pcm_init_urb(struct pcm_urb *urb, @@ -539,6 +501,8 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb, usb_fill_bulk_urb(&urb->instance, chip->dev, usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, PCM_PACKET_SIZE, handler, urb); + if (usb_urb_ep_type_check(&urb->instance)) + return -EINVAL; init_usb_anchor(&urb->submitted); return 0; @@ -551,9 +515,8 @@ void hiface_pcm_abort(struct hiface_chip *chip) if (rt) { rt->panic = true; - mutex_lock(&rt->stream_mutex); + guard(mutex)(&rt->stream_mutex); hiface_pcm_stream_stop(rt); - mutex_unlock(&rt->stream_mutex); } } @@ -597,25 +560,35 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) mutex_init(&rt->stream_mutex); spin_lock_init(&rt->playback.lock); - for (i = 0; i < PCM_N_URBS; i++) - hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, + for (i = 0; i < PCM_N_URBS; i++) { + ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, hiface_pcm_out_urb_handler); + if (ret < 0) + goto error; + } ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); if (ret < 0) { - kfree(rt); dev_err(&chip->dev->dev, "Cannot create pcm instance\n"); - return ret; + goto error; } pcm->private_data = rt; pcm->private_free = hiface_pcm_free; - strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name)); + strscpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name)); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); rt->instance = pcm; chip->pcm = rt; return 0; + +error: + for (i = 0; i < PCM_N_URBS; i++) + kfree(rt->out_urbs[i].buffer); + kfree(rt); + return ret; } |
