summaryrefslogtreecommitdiffstats
path: root/sound/usb/usx2y/usbusx2yaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/usx2y/usbusx2yaudio.c')
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c140
1 files changed, 80 insertions, 60 deletions
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 8033bb7255d5..f92a9d52ea33 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
*
- * Many codes borrowed from audio.c by
+ * Many codes borrowed from audio.c by
* Alan Cox (alan@lxorguk.ukuu.org.uk)
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*/
@@ -28,50 +28,51 @@
#include "usx2y.h"
#include "usbusx2y.h"
-#define USX2Y_NRPACKS 4 /* Default value used for nr of packs per urb.
- 1 to 4 have been tested ok on uhci.
- To use 3 on ohci, you'd need a patch:
- look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
- "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
- .
- 1, 2 and 4 work out of the box on ohci, if I recall correctly.
- Bigger is safer operation,
- smaller gives lower latencies.
- */
-#define USX2Y_NRPACKS_VARIABLE y /* If your system works ok with this module's parameter
- nrpacks set to 1, you might as well comment
- this #define out, and thereby produce smaller, faster code.
- You'd also set USX2Y_NRPACKS to 1 then.
- */
+/* Default value used for nr of packs per urb.
+ * 1 to 4 have been tested ok on uhci.
+ * To use 3 on ohci, you'd need a patch:
+ * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
+ * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
+ *
+ * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
+ * Bigger is safer operation, smaller gives lower latencies.
+ */
+#define USX2Y_NRPACKS 4
+
+/* If your system works ok with this module's parameter
+ * nrpacks set to 1, you might as well comment
+ * this define out, and thereby produce smaller, faster code.
+ * You'd also set USX2Y_NRPACKS to 1 then.
+ */
+#define USX2Y_NRPACKS_VARIABLE 1
#ifdef USX2Y_NRPACKS_VARIABLE
- static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
- #define nr_of_packs() nrpacks
- module_param(nrpacks, int, 0444);
- MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
+static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
+#define nr_of_packs() nrpacks
+module_param(nrpacks, int, 0444);
+MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
#else
- #define nr_of_packs() USX2Y_NRPACKS
+#define nr_of_packs() USX2Y_NRPACKS
#endif
-
static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
{
struct urb *urb = subs->completed_urb;
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
unsigned char *cp;
- int i, len, lens = 0, hwptr_done = subs->hwptr_done;
+ int i, len, lens = 0, hwptr_done = subs->hwptr_done;
struct usx2ydev *usx2y = subs->usx2y;
for (i = 0; i < nr_of_packs(); i++) {
- cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
- snd_printk(KERN_ERR "active frame status %i. "
- "Most probably some hardware problem.\n",
+ snd_printk(KERN_ERR
+ "active frame status %i. Most probably some hardware problem.\n",
urb->iso_frame_desc[i].status);
return urb->iso_frame_desc[i].status;
}
len = urb->iso_frame_desc[i].actual_length / usx2y->stride;
- if (! len) {
+ if (!len) {
snd_printd("0 == len ERROR!\n");
continue;
}
@@ -80,6 +81,7 @@ static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
if ((hwptr_done + len) > runtime->buffer_size) {
int cnt = runtime->buffer_size - hwptr_done;
int blen = cnt * usx2y->stride;
+
memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, blen);
memcpy(runtime->dma_area, cp + blen, len * usx2y->stride - blen);
} else {
@@ -100,6 +102,7 @@ static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
}
return 0;
}
+
/*
* prepare urb for playback data pipe
*
@@ -140,6 +143,7 @@ static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs,
* copy the data to the temp buffer.
*/
int len;
+
len = runtime->buffer_size - subs->hwptr;
urb->transfer_buffer = subs->tmpbuf;
memcpy(subs->tmpbuf, runtime->dma_area +
@@ -183,6 +187,7 @@ static void usx2y_urb_play_retire(struct snd_usx2y_substream *subs, struct urb *
static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, int frame)
{
int err;
+
if (!urb)
return -ENODEV;
urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks
@@ -243,13 +248,13 @@ static inline int usx2y_usbframe_complete(struct snd_usx2y_substream *capsubs,
return 0;
}
-
static void usx2y_clients_stop(struct usx2ydev *usx2y)
{
int s, u;
for (s = 0; s < 4; s++) {
struct snd_usx2y_substream *subs = usx2y->subs[s];
+
if (subs) {
snd_printdd("%i %p state=%i\n", s, subs, atomic_read(&subs->state));
atomic_set(&subs->state, STATE_STOPPED);
@@ -257,11 +262,13 @@ static void usx2y_clients_stop(struct usx2ydev *usx2y)
}
for (s = 0; s < 4; s++) {
struct snd_usx2y_substream *subs = usx2y->subs[s];
+
if (subs) {
if (atomic_read(&subs->state) >= STATE_PRERUNNING)
snd_pcm_stop_xrun(subs->pcm_substream);
for (u = 0; u < NRURBS; u++) {
struct urb *urb = subs->urb[u];
+
if (NULL != urb)
snd_printdd("%i status=%i start_frame=%i\n",
u, urb->status, urb->start_frame);
@@ -302,6 +309,7 @@ static void i_usx2y_urb_complete(struct urb *urb)
{
struct snd_usx2y_substream *capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE],
*playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
+
if (capsubs->completed_urb &&
atomic_read(&capsubs->state) >= STATE_PREPARED &&
(playbacksubs->completed_urb ||
@@ -316,22 +324,25 @@ static void i_usx2y_urb_complete(struct urb *urb)
}
}
-static void usx2y_urbs_set_complete(struct usx2ydev * usx2y,
+static void usx2y_urbs_set_complete(struct usx2ydev *usx2y,
void (*complete)(struct urb *))
{
int s, u;
+
for (s = 0; s < 4; s++) {
struct snd_usx2y_substream *subs = usx2y->subs[s];
+
if (NULL != subs)
for (u = 0; u < NRURBS; u++) {
- struct urb * urb = subs->urb[u];
+ struct urb *urb = subs->urb[u];
+
if (NULL != urb)
urb->complete = complete;
}
}
}
-static void usx2y_subs_startup_finish(struct usx2ydev * usx2y)
+static void usx2y_subs_startup_finish(struct usx2ydev *usx2y)
{
usx2y_urbs_set_complete(usx2y, i_usx2y_urb_complete);
usx2y->prepare_subs = NULL;
@@ -342,6 +353,7 @@ static void i_usx2y_subs_startup(struct urb *urb)
struct snd_usx2y_substream *subs = urb->context;
struct usx2ydev *usx2y = subs->usx2y;
struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
+
if (NULL != prepare_subs)
if (urb->start_frame == prepare_subs->urb[0]->start_frame) {
usx2y_subs_startup_finish(usx2y);
@@ -362,7 +374,6 @@ static void usx2y_subs_prepare(struct snd_usx2y_substream *subs)
subs->transfer_done = 0;
}
-
static void usx2y_urb_release(struct urb **urb, int free_tb)
{
if (*urb) {
@@ -373,12 +384,14 @@ static void usx2y_urb_release(struct urb **urb, int free_tb)
*urb = NULL;
}
}
+
/*
* release a substreams urbs
*/
static void usx2y_urbs_release(struct snd_usx2y_substream *subs)
{
int i;
+
snd_printdd("usx2y_urbs_release() %i\n", subs->endpoint);
for (i = 0; i < NRURBS; i++)
usx2y_urb_release(subs->urb + i,
@@ -387,6 +400,7 @@ static void usx2y_urbs_release(struct snd_usx2y_substream *subs)
kfree(subs->tmpbuf);
subs->tmpbuf = NULL;
}
+
/*
* initialize a substream's urbs
*/
@@ -411,6 +425,7 @@ static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs)
/* allocate and initialize data urbs */
for (i = 0; i < NRURBS; i++) {
struct urb **purb = subs->urb + i;
+
if (*purb) {
usb_kill_urb(*purb);
continue;
@@ -443,6 +458,7 @@ static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs)
static void usx2y_subs_startup(struct snd_usx2y_substream *subs)
{
struct usx2ydev *usx2y = subs->usx2y;
+
usx2y->prepare_subs = subs;
subs->urb[0]->start_frame = -1;
wmb();
@@ -459,6 +475,7 @@ static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
subs->completed_urb = NULL;
for (i = 0; i < 4; i++) {
struct snd_usx2y_substream *subs = usx2y->subs[i];
+
if (subs != NULL && atomic_read(&subs->state) >= STATE_PREPARED)
goto start;
}
@@ -467,8 +484,10 @@ static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
usx2y_subs_startup(subs);
for (i = 0; i < NRURBS; i++) {
struct urb *urb = subs->urb[i];
+
if (usb_pipein(urb->pipe)) {
unsigned long pack;
+
if (0 == i)
atomic_set(&subs->state, STATE_STARTING3);
urb->dev = usx2y->dev;
@@ -476,9 +495,9 @@ static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
urb->iso_frame_desc[pack].length = subs->maxpacksize;
}
- urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
+ urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+ snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
err = -EPIPE;
goto cleanup;
} else
@@ -509,8 +528,10 @@ static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
static snd_pcm_uframes_t snd_usx2y_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_usx2y_substream *subs = substream->runtime->private_data;
+
return subs->hwptr_done;
}
+
/*
* start/stop substream
*/
@@ -540,7 +561,6 @@ static int snd_usx2y_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
-
/*
* allocate a buffer, setup samplerate
*
@@ -553,8 +573,7 @@ static const struct s_c2
{
char c1, c2;
}
- setrate_44100[] =
-{
+ setrate_44100[] = {
{ 0x14, 0x08}, // this line sets 44100, well actually a little less
{ 0x18, 0x40}, // only tascam / frontier design knows the further lines .......
{ 0x18, 0x42},
@@ -589,8 +608,8 @@ static const struct s_c2
{ 0x18, 0x7C},
{ 0x18, 0x7E}
};
-static const struct s_c2 setrate_48000[] =
-{
+
+static const struct s_c2 setrate_48000[] = {
{ 0x14, 0x09}, // this line sets 48000, well actually a little less
{ 0x18, 0x40}, // only tascam / frontier design knows the further lines .......
{ 0x18, 0x42},
@@ -625,12 +644,13 @@ static const struct s_c2 setrate_48000[] =
{ 0x18, 0x7C},
{ 0x18, 0x7E}
};
+
#define NOOF_SETRATE_URBS ARRAY_SIZE(setrate_48000)
static void i_usx2y_04int(struct urb *urb)
{
struct usx2ydev *usx2y = urb->context;
-
+
if (urb->status)
snd_printk(KERN_ERR "snd_usx2y_04int() urb->status=%i\n", urb->status);
if (0 == --usx2y->us04->len)
@@ -645,7 +665,7 @@ static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
const struct s_c2 *ra = rate == 48000 ? setrate_48000 : setrate_44100;
if (usx2y->rate != rate) {
- us = kzalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
+ us = kzalloc(sizeof(*us) + sizeof(struct urb *) * NOOF_SETRATE_URBS, GFP_KERNEL);
if (NULL == us) {
err = -ENOMEM;
goto cleanup;
@@ -661,8 +681,8 @@ static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
err = -ENOMEM;
goto cleanup;
}
- ((char*)(usbdata + i))[0] = ra[i].c1;
- ((char*)(usbdata + i))[1] = ra[i].c2;
+ ((char *)(usbdata + i))[0] = ra[i].c1;
+ ((char *)(usbdata + i))[1] = ra[i].c2;
usb_fill_bulk_urb(us->urb[i], usx2y->dev, usb_sndbulkpipe(usx2y->dev, 4),
usbdata + i, 2, i_usx2y_04int, usx2y);
}
@@ -681,6 +701,7 @@ static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
us->submitted = 2*NOOF_SETRATE_URBS;
for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
struct urb *urb = us->urb[i];
+
if (!urb)
continue;
if (urb->status) {
@@ -705,7 +726,8 @@ static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format)
{
int alternate, err;
- struct list_head* p;
+ struct list_head *p;
+
if (format == SNDRV_PCM_FORMAT_S24_3LE) {
alternate = 2;
usx2y->stride = 6;
@@ -718,7 +740,7 @@ static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format)
}
usb_kill_urb(usx2y->in04_urb);
if ((err = usb_set_interface(usx2y->dev, 0, alternate))) {
- snd_printk(KERN_ERR "usb_set_interface error \n");
+ snd_printk(KERN_ERR "usb_set_interface error\n");
return err;
}
usx2y->in04_urb->dev = usx2y->dev;
@@ -778,11 +800,13 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_usx2y_substream *subs = runtime->private_data;
+
mutex_lock(&subs->usx2y->pcm_mutex);
snd_printdd("snd_usx2y_hw_free(%p)\n", substream);
if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
struct snd_usx2y_substream *cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
+
atomic_set(&subs->state, STATE_STOPPED);
usx2y_urbs_release(subs);
if (!cap_subs->pcm_substream ||
@@ -794,6 +818,7 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream)
}
} else {
struct snd_usx2y_substream *playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
+
if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
atomic_set(&subs->state, STATE_STOPPED);
usx2y_urbs_release(subs);
@@ -802,6 +827,7 @@ static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream)
mutex_unlock(&subs->usx2y->pcm_mutex);
return 0;
}
+
/*
* prepare callback
*
@@ -814,12 +840,13 @@ static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream)
struct usx2ydev *usx2y = subs->usx2y;
struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
int err = 0;
+
snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
mutex_lock(&usx2y->pcm_mutex);
usx2y_subs_prepare(subs);
-// Start hardware streams
-// SyncStream first....
+ // Start hardware streams
+ // SyncStream first....
if (atomic_read(&capsubs->state) < STATE_PREPARED) {
if (usx2y->format != runtime->format)
if ((err = usx2y_format_set(usx2y, runtime->format)) < 0)
@@ -840,8 +867,7 @@ static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream)
return err;
}
-static const struct snd_pcm_hardware snd_usx2y_2c =
-{
+static const struct snd_pcm_hardware snd_usx2y_2c = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -860,8 +886,6 @@ static const struct snd_pcm_hardware snd_usx2y_2c =
.fifo_size = 0
};
-
-
static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_usx2y_substream *subs = ((struct snd_usx2y_substream **)
@@ -878,8 +902,6 @@ static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream)
return 0;
}
-
-
static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -890,9 +912,7 @@ static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-
-static const struct snd_pcm_ops snd_usx2y_pcm_ops =
-{
+static const struct snd_pcm_ops snd_usx2y_pcm_ops = {
.open = snd_usx2y_pcm_open,
.close = snd_usx2y_pcm_close,
.hw_params = snd_usx2y_pcm_hw_params,
@@ -902,7 +922,6 @@ static const struct snd_pcm_ops snd_usx2y_pcm_ops =
.pointer = snd_usx2y_pcm_pointer,
};
-
/*
* free a usb stream instance
*/
@@ -919,6 +938,7 @@ static void usx2y_audio_stream_free(struct snd_usx2y_substream **usx2y_substream
static void snd_usx2y_pcm_private_free(struct snd_pcm *pcm)
{
struct snd_usx2y_substream **usx2y_stream = pcm->private_data;
+
if (usx2y_stream)
usx2y_audio_stream_free(usx2y_stream);
}
@@ -983,14 +1003,14 @@ static int usx2y_audio_stream_new(struct snd_card *card, int playback_endpoint,
int usx2y_audio_create(struct snd_card *card)
{
int err = 0;
-
+
INIT_LIST_HEAD(&usx2y(card)->pcm_list);
if (0 > (err = usx2y_audio_stream_new(card, 0xA, 0x8)))
return err;
if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) == USB_ID_US428)
- if (0 > (err = usx2y_audio_stream_new(card, 0, 0xA)))
- return err;
+ if (0 > (err = usx2y_audio_stream_new(card, 0, 0xA)))
+ return err;
if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) != USB_ID_US122)
err = usx2y_rate_set(usx2y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122.
return err;