Commit 773e53d5 authored by Vladimir Zapolskiy's avatar Vladimir Zapolskiy Committed by Felipe Balbi

usb: gadget: u_audio: remove cached period bytes value

Substream period size potentially can be changed in runtime, however
this is not accounted in the data copying routine, the change replaces
the cached value with an actual value from substream runtime.

As a side effect the change also removes a potential division by zero
in u_audio_iso_complete() function, if there is a race with
uac_pcm_hw_free(), which sets prm->period_size to 0.

Fixes: 132fcb46 ("usb: gadget: Add Audio Class 2.0 Driver")
Signed-off-by: default avatarVladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
Signed-off-by: default avatarEugeniu Rosca <erosca@de.adit-jv.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 96afb54e
...@@ -40,8 +40,6 @@ struct uac_rtd_params { ...@@ -40,8 +40,6 @@ struct uac_rtd_params {
void *rbuf; void *rbuf;
size_t period_size;
unsigned max_psize; /* MaxPacketSize of endpoint */ unsigned max_psize; /* MaxPacketSize of endpoint */
struct uac_req *ureq; struct uac_req *ureq;
...@@ -83,7 +81,6 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -83,7 +81,6 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
unsigned pending; unsigned pending;
unsigned long flags; unsigned long flags;
unsigned int hw_ptr; unsigned int hw_ptr;
bool update_alsa = false;
int status = req->status; int status = req->status;
struct uac_req *ur = req->context; struct uac_req *ur = req->context;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
...@@ -136,11 +133,6 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -136,11 +133,6 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
req->actual = req->length; req->actual = req->length;
} }
pending = prm->hw_ptr % prm->period_size;
pending += req->actual;
if (pending >= prm->period_size)
update_alsa = true;
hw_ptr = prm->hw_ptr; hw_ptr = prm->hw_ptr;
spin_unlock_irqrestore(&prm->lock, flags); spin_unlock_irqrestore(&prm->lock, flags);
...@@ -171,14 +163,15 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -171,14 +163,15 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock_irqsave(&prm->lock, flags); spin_lock_irqsave(&prm->lock, flags);
/* update hw_ptr after data is copied to memory */ /* update hw_ptr after data is copied to memory */
prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes; prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes;
hw_ptr = prm->hw_ptr;
spin_unlock_irqrestore(&prm->lock, flags); spin_unlock_irqrestore(&prm->lock, flags);
if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual)
snd_pcm_period_elapsed(substream);
exit: exit:
if (usb_ep_queue(ep, req, GFP_ATOMIC)) if (usb_ep_queue(ep, req, GFP_ATOMIC))
dev_err(uac->card->dev, "%d Error!\n", __LINE__); dev_err(uac->card->dev, "%d Error!\n", __LINE__);
if (update_alsa)
snd_pcm_period_elapsed(substream);
} }
static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
...@@ -241,35 +234,12 @@ static snd_pcm_uframes_t uac_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -241,35 +234,12 @@ static snd_pcm_uframes_t uac_pcm_pointer(struct snd_pcm_substream *substream)
static int uac_pcm_hw_params(struct snd_pcm_substream *substream, static int uac_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params) struct snd_pcm_hw_params *hw_params)
{ {
struct snd_uac_chip *uac = snd_pcm_substream_chip(substream); return snd_pcm_lib_malloc_pages(substream,
struct uac_rtd_params *prm;
int err;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params)); params_buffer_bytes(hw_params));
if (err >= 0)
prm->period_size = params_period_bytes(hw_params);
return err;
} }
static int uac_pcm_hw_free(struct snd_pcm_substream *substream) static int uac_pcm_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
struct uac_rtd_params *prm;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prm = &uac->p_prm;
else
prm = &uac->c_prm;
prm->period_size = 0;
return snd_pcm_lib_free_pages(substream); return snd_pcm_lib_free_pages(substream);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment