|
@@ -32,9 +32,6 @@ struct uac_req {
|
|
|
struct uac_rtd_params {
|
|
|
struct snd_uac_chip *uac; /* parent chip */
|
|
|
bool ep_enabled; /* if the ep is enabled */
|
|
|
- /* Size of the ring buffer */
|
|
|
- size_t dma_bytes;
|
|
|
- unsigned char *dma_area;
|
|
|
|
|
|
struct snd_pcm_substream *ss;
|
|
|
|
|
@@ -43,8 +40,6 @@ struct uac_rtd_params {
|
|
|
|
|
|
void *rbuf;
|
|
|
|
|
|
- size_t period_size;
|
|
|
-
|
|
|
unsigned max_psize; /* MaxPacketSize of endpoint */
|
|
|
struct uac_req *ureq;
|
|
|
|
|
@@ -84,12 +79,12 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
|
|
|
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
|
|
|
{
|
|
|
unsigned pending;
|
|
|
- unsigned long flags;
|
|
|
+ unsigned long flags, flags2;
|
|
|
unsigned int hw_ptr;
|
|
|
- bool update_alsa = false;
|
|
|
int status = req->status;
|
|
|
struct uac_req *ur = req->context;
|
|
|
struct snd_pcm_substream *substream;
|
|
|
+ struct snd_pcm_runtime *runtime;
|
|
|
struct uac_rtd_params *prm = ur->pp;
|
|
|
struct snd_uac_chip *uac = prm->uac;
|
|
|
|
|
@@ -111,6 +106,14 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
|
|
|
if (!substream)
|
|
|
goto exit;
|
|
|
|
|
|
+ snd_pcm_stream_lock_irqsave(substream, flags2);
|
|
|
+
|
|
|
+ runtime = substream->runtime;
|
|
|
+ if (!runtime || !snd_pcm_running(substream)) {
|
|
|
+ snd_pcm_stream_unlock_irqrestore(substream, flags2);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
spin_lock_irqsave(&prm->lock, flags);
|
|
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
@@ -137,43 +140,46 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
|
|
|
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;
|
|
|
- prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes;
|
|
|
|
|
|
spin_unlock_irqrestore(&prm->lock, flags);
|
|
|
|
|
|
/* Pack USB load in ALSA ring buffer */
|
|
|
- pending = prm->dma_bytes - hw_ptr;
|
|
|
+ pending = runtime->dma_bytes - hw_ptr;
|
|
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
if (unlikely(pending < req->actual)) {
|
|
|
- memcpy(req->buf, prm->dma_area + hw_ptr, pending);
|
|
|
- memcpy(req->buf + pending, prm->dma_area,
|
|
|
+ memcpy(req->buf, runtime->dma_area + hw_ptr, pending);
|
|
|
+ memcpy(req->buf + pending, runtime->dma_area,
|
|
|
req->actual - pending);
|
|
|
} else {
|
|
|
- memcpy(req->buf, prm->dma_area + hw_ptr, req->actual);
|
|
|
+ memcpy(req->buf, runtime->dma_area + hw_ptr,
|
|
|
+ req->actual);
|
|
|
}
|
|
|
} else {
|
|
|
if (unlikely(pending < req->actual)) {
|
|
|
- memcpy(prm->dma_area + hw_ptr, req->buf, pending);
|
|
|
- memcpy(prm->dma_area, req->buf + pending,
|
|
|
+ memcpy(runtime->dma_area + hw_ptr, req->buf, pending);
|
|
|
+ memcpy(runtime->dma_area, req->buf + pending,
|
|
|
req->actual - pending);
|
|
|
} else {
|
|
|
- memcpy(prm->dma_area + hw_ptr, req->buf, req->actual);
|
|
|
+ memcpy(runtime->dma_area + hw_ptr, req->buf,
|
|
|
+ req->actual);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ spin_lock_irqsave(&prm->lock, flags);
|
|
|
+ /* update hw_ptr after data is copied to memory */
|
|
|
+ prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes;
|
|
|
+ hw_ptr = prm->hw_ptr;
|
|
|
+ spin_unlock_irqrestore(&prm->lock, flags);
|
|
|
+ snd_pcm_stream_unlock_irqrestore(substream, flags2);
|
|
|
+
|
|
|
+ if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual)
|
|
|
+ snd_pcm_period_elapsed(substream);
|
|
|
+
|
|
|
exit:
|
|
|
if (usb_ep_queue(ep, req, GFP_ATOMIC))
|
|
|
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)
|
|
@@ -236,40 +242,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,
|
|
|
struct snd_pcm_hw_params *hw_params)
|
|
|
{
|
|
|
- struct snd_uac_chip *uac = snd_pcm_substream_chip(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,
|
|
|
+ return snd_pcm_lib_malloc_pages(substream,
|
|
|
params_buffer_bytes(hw_params));
|
|
|
- if (err >= 0) {
|
|
|
- prm->dma_bytes = substream->runtime->dma_bytes;
|
|
|
- prm->dma_area = substream->runtime->dma_area;
|
|
|
- prm->period_size = params_period_bytes(hw_params);
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
}
|
|
|
|
|
|
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->dma_area = NULL;
|
|
|
- prm->dma_bytes = 0;
|
|
|
- prm->period_size = 0;
|
|
|
-
|
|
|
return snd_pcm_lib_free_pages(substream);
|
|
|
}
|
|
|
|
|
@@ -595,15 +573,15 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
|
|
|
if (err < 0)
|
|
|
goto snd_fail;
|
|
|
|
|
|
- strcpy(pcm->name, pcm_name);
|
|
|
+ strlcpy(pcm->name, pcm_name, sizeof(pcm->name));
|
|
|
pcm->private_data = uac;
|
|
|
uac->pcm = pcm;
|
|
|
|
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
|
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
|
|
|
|
|
|
- strcpy(card->driver, card_name);
|
|
|
- strcpy(card->shortname, card_name);
|
|
|
+ strlcpy(card->driver, card_name, sizeof(card->driver));
|
|
|
+ strlcpy(card->shortname, card_name, sizeof(card->shortname));
|
|
|
sprintf(card->longname, "%s %i", card_name, card->dev->id);
|
|
|
|
|
|
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
|