int ret;
struct urb *urb_in;
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
+ spin_lock_irqsave(&line6pcm->in.lock, flags);
index =
- find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
+ find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
- urb_in = line6pcm->urb_audio_in[index];
+ urb_in = line6pcm->in.urbs[index];
urb_size = 0;
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
}
urb_in->transfer_buffer =
- line6pcm->buffer_in +
+ line6pcm->in.buffer +
index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
urb_in->transfer_buffer_length = urb_size;
urb_in->context = line6pcm;
ret = usb_submit_urb(urb_in, GFP_ATOMIC);
if (ret == 0)
- set_bit(index, &line6pcm->active_urb_in);
+ set_bit(index, &line6pcm->in.active_urbs);
else
dev_err(line6pcm->line6->ifcdev,
"URB in #%d submission failed (%d)\n", index, ret);
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
return 0;
}
unsigned int i;
for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
- if (test_bit(i, &line6pcm->active_urb_in)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
- struct urb *u = line6pcm->urb_audio_in[i];
+ if (test_bit(i, &line6pcm->in.active_urbs)) {
+ if (!test_and_set_bit(i, &line6pcm->in.unlink_urbs)) {
+ struct urb *u = line6pcm->in.urbs[i];
usb_unlink_urb(u);
}
do {
alive = 0;
for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
- if (test_bit(i, &line6pcm->active_urb_in))
+ if (test_bit(i, &line6pcm->in.active_urbs))
alive++;
}
if (!alive)
if (runtime == NULL)
return;
- if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
+ if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
/*
The transferred area goes over buffer boundary,
copy two separate chunks.
*/
int len;
- len = runtime->buffer_size - line6pcm->pos_in_done;
+ len = runtime->buffer_size - line6pcm->in.pos_done;
if (len > 0) {
memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf,
+ line6pcm->in.pos_done * bytes_per_frame, fbuf,
len * bytes_per_frame);
memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
(frames - len) * bytes_per_frame);
} else {
/* copy single chunk */
memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
+ line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
}
- line6pcm->pos_in_done += frames;
- if (line6pcm->pos_in_done >= runtime->buffer_size)
- line6pcm->pos_in_done -= runtime->buffer_size;
+ line6pcm->in.pos_done += frames;
+ if (line6pcm->in.pos_done >= runtime->buffer_size)
+ line6pcm->in.pos_done -= runtime->buffer_size;
}
void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
struct snd_pcm_substream *substream =
get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
- line6pcm->bytes_in += length;
- if (line6pcm->bytes_in >= line6pcm->period_in) {
- line6pcm->bytes_in %= line6pcm->period_in;
+ line6pcm->in.bytes += length;
+ if (line6pcm->in.bytes >= line6pcm->in.period) {
+ line6pcm->in.bytes %= line6pcm->in.period;
snd_pcm_period_elapsed(substream);
}
}
void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
{
- kfree(line6pcm->buffer_in);
- line6pcm->buffer_in = NULL;
+ kfree(line6pcm->in.buffer);
+ line6pcm->in.buffer = NULL;
}
/*
struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
- line6pcm->last_frame_in = urb->start_frame;
+ line6pcm->in.last_frame = urb->start_frame;
/* find index of URB */
for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
- if (urb == line6pcm->urb_audio_in[index])
+ if (urb == line6pcm->in.urbs[index])
break;
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
+ spin_lock_irqsave(&line6pcm->in.lock, flags);
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
char *fbuf;
line6_capture_copy(line6pcm, fbuf, fsize);
}
- clear_bit(index, &line6pcm->active_urb_in);
+ clear_bit(index, &line6pcm->in.active_urbs);
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
+ if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
shutdown = 1;
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
if (!shutdown) {
submit_audio_in_urb(line6pcm);
return ret;
}
- line6pcm->period_in = params_period_bytes(hw_params);
+ line6pcm->in.period = params_period_bytes(hw_params);
return 0;
}
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- return line6pcm->pos_in_done;
+ return line6pcm->in.pos_done;
}
/* capture operators */
struct urb *urb;
/* URB for audio in: */
- urb = line6pcm->urb_audio_in[i] =
+ urb = line6pcm->in.urbs[i] =
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL)
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
/* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_in) {
- line6pcm->buffer_in =
+ if (!line6pcm->in.buffer) {
+ line6pcm->in.buffer =
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_in) {
+ if (!line6pcm->in.buffer) {
err = -ENOMEM;
goto pcm_acquire_error;
}
a bug, we therefore report an error if capturing is restarted
too soon.
*/
- if (line6pcm->active_urb_in || line6pcm->unlink_urb_in) {
+ if (line6pcm->in.active_urbs || line6pcm->in.unlink_urbs) {
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
err = -EBUSY;
goto pcm_acquire_error;
}
- line6pcm->count_in = 0;
+ line6pcm->in.count = 0;
line6pcm->prev_fsize = 0;
err = line6_submit_audio_in_all_urbs(line6pcm);
if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
/* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_out) {
- line6pcm->buffer_out =
+ if (!line6pcm->out.buffer) {
+ line6pcm->out.buffer =
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_out) {
+ if (!line6pcm->out.buffer) {
err = -ENOMEM;
goto pcm_acquire_error;
}
/*
See comment above regarding PCM restart.
*/
- if (line6pcm->active_urb_out || line6pcm->unlink_urb_out) {
+ if (line6pcm->out.active_urbs || line6pcm->out.unlink_urbs) {
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
return -EBUSY;
}
- line6pcm->count_out = 0;
+ line6pcm->out.count = 0;
err = line6_submit_audio_out_all_urbs(line6pcm);
if (err < 0)
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
- if (line6pcm->urb_audio_out[i]) {
- usb_kill_urb(line6pcm->urb_audio_out[i]);
- usb_free_urb(line6pcm->urb_audio_out[i]);
+ if (line6pcm->out.urbs[i]) {
+ usb_kill_urb(line6pcm->out.urbs[i]);
+ usb_free_urb(line6pcm->out.urbs[i]);
}
- if (line6pcm->urb_audio_in[i]) {
- usb_kill_urb(line6pcm->urb_audio_in[i]);
- usb_free_urb(line6pcm->urb_audio_in[i]);
+ if (line6pcm->in.urbs[i]) {
+ usb_kill_urb(line6pcm->in.urbs[i]);
+ usb_free_urb(line6pcm->in.urbs[i]);
}
}
kfree(line6pcm);
usb_maxpacket(line6->usbdev,
usb_sndisocpipe(line6->usbdev, ep_write), 1));
- spin_lock_init(&line6pcm->lock_audio_out);
- spin_lock_init(&line6pcm->lock_audio_in);
+ spin_lock_init(&line6pcm->out.lock);
+ spin_lock_init(&line6pcm->in.lock);
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
line6->line6pcm = line6pcm;
}
if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
- line6pcm->count_out = 0;
- line6pcm->pos_out = 0;
- line6pcm->pos_out_done = 0;
- line6pcm->bytes_out = 0;
- line6pcm->count_in = 0;
- line6pcm->pos_in_done = 0;
- line6pcm->bytes_in = 0;
+ line6pcm->out.count = 0;
+ line6pcm->out.pos = 0;
+ line6pcm->out.pos_done = 0;
+ line6pcm->out.bytes = 0;
+ line6pcm->in.count = 0;
+ line6pcm->in.pos_done = 0;
+ line6pcm->in.bytes = 0;
}
return 0;
int bytes_per_frame;
};
-struct snd_line6_pcm {
- /**
- Pointer back to the Line 6 driver data structure.
- */
- struct usb_line6 *line6;
+struct line6_pcm_stream {
+ /* allocated URBs */
+ struct urb *urbs[LINE6_ISO_BUFFERS];
- /**
- Properties.
- */
- struct line6_pcm_properties *properties;
+ /* Temporary buffer;
+ * Since the packet size is not known in advance, this buffer is
+ * large enough to store maximum size packets.
+ */
+ unsigned char *buffer;
- /**
- ALSA pcm stream
- */
- struct snd_pcm *pcm;
+ /* Free frame position in the buffer. */
+ snd_pcm_uframes_t pos;
- /**
- URBs for audio playback.
- */
- struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
+ /* Count processed bytes;
+ * This is modulo period size (to determine when a period is finished).
+ */
+ unsigned bytes;
- /**
- URBs for audio capture.
- */
- struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
+ /* Counter to create desired sample rate */
+ unsigned count;
- /**
- Temporary buffer for playback.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_out;
+ /* period size in bytes */
+ unsigned period;
- /**
- Temporary buffer for capture.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_in;
+ /* Processed frame position in the buffer;
+ * The contents of the ring buffer have been consumed by the USB
+ * subsystem (i.e., sent to the USB device) up to this position.
+ */
+ snd_pcm_uframes_t pos_done;
- /**
- Previously captured frame (for software monitoring).
- */
- unsigned char *prev_fbuf;
+ /* Bit mask of active URBs */
+ unsigned long active_urbs;
- /**
- Size of previously captured frame (for software monitoring).
- */
- int prev_fsize;
-
- /**
- Free frame position in the playback buffer.
- */
- snd_pcm_uframes_t pos_out;
+ /* Bit mask of URBs currently being unlinked */
+ unsigned long unlink_urbs;
- /**
- Count processed bytes for playback.
- This is modulo period size (to determine when a period is
- finished).
- */
- unsigned bytes_out;
+ /* Spin lock to protect updates of the buffer positions (not contents)
+ */
+ spinlock_t lock;
- /**
- Counter to create desired playback sample rate.
- */
- unsigned count_out;
-
- /**
- Playback period size in bytes
- */
- unsigned period_out;
+ int last_frame;
+};
+struct snd_line6_pcm {
/**
- Processed frame position in the playback buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
+ Pointer back to the Line 6 driver data structure.
*/
- snd_pcm_uframes_t pos_out_done;
+ struct usb_line6 *line6;
/**
- Count processed bytes for capture.
- This is modulo period size (to determine when a period is
- finished).
+ Properties.
*/
- unsigned bytes_in;
+ struct line6_pcm_properties *properties;
/**
- Counter to create desired capture sample rate.
+ ALSA pcm stream
*/
- unsigned count_in;
+ struct snd_pcm *pcm;
- /**
- Capture period size in bytes
- */
- unsigned period_in;
+ /* Capture and playback streams */
+ struct line6_pcm_stream in;
+ struct line6_pcm_stream out;
/**
- Processed frame position in the capture buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
+ Previously captured frame (for software monitoring).
*/
- snd_pcm_uframes_t pos_in_done;
+ unsigned char *prev_fbuf;
/**
- Bit mask of active playback URBs.
+ Size of previously captured frame (for software monitoring).
*/
- unsigned long active_urb_out;
+ int prev_fsize;
/**
Maximum size of USB packet.
*/
int max_packet_size;
- /**
- Bit mask of active capture URBs.
- */
- unsigned long active_urb_in;
-
- /**
- Bit mask of playback URBs currently being unlinked.
- */
- unsigned long unlink_urb_out;
-
- /**
- Bit mask of capture URBs currently being unlinked.
- */
- unsigned long unlink_urb_in;
-
- /**
- Spin lock to protect updates of the playback buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_out;
-
- /**
- Spin lock to protect updates of the capture buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_in;
-
/**
PCM playback volume (left and right).
*/
Several status bits (see LINE6_BIT_*).
*/
unsigned long flags;
-
- int last_frame_in, last_frame_out;
};
extern int line6_init_pcm(struct usb_line6 *line6,
(USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
struct urb *urb_out;
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
+ spin_lock_irqsave(&line6pcm->out.lock, flags);
index =
- find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
+ find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
- urb_out = line6pcm->urb_audio_out[index];
+ urb_out = line6pcm->out.urbs[index];
urb_size = 0;
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
if (fsize == 0) {
int n;
- line6pcm->count_out += frame_increment;
- n = line6pcm->count_out / frame_factor;
- line6pcm->count_out -= n * frame_factor;
+ line6pcm->out.count += frame_increment;
+ n = line6pcm->out.count / frame_factor;
+ line6pcm->out.count -= n * frame_factor;
fsize = n * bytes_per_frame;
}
if (urb_size == 0) {
/* can't determine URB size */
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
return -EINVAL;
}
urb_frames = urb_size / bytes_per_frame;
urb_out->transfer_buffer =
- line6pcm->buffer_out +
+ line6pcm->out.buffer +
index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
urb_out->transfer_buffer_length = urb_size;
urb_out->context = line6pcm;
struct snd_pcm_runtime *runtime =
get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
- if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
+ if (line6pcm->out.pos + urb_frames > runtime->buffer_size) {
/*
The transferred area goes over buffer boundary,
copy the data to the temp buffer.
*/
int len;
- len = runtime->buffer_size - line6pcm->pos_out;
+ len = runtime->buffer_size - line6pcm->out.pos;
if (len > 0) {
memcpy(urb_out->transfer_buffer,
runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
+ line6pcm->out.pos * bytes_per_frame,
len * bytes_per_frame);
memcpy(urb_out->transfer_buffer +
len * bytes_per_frame, runtime->dma_area,
} else {
memcpy(urb_out->transfer_buffer,
runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
+ line6pcm->out.pos * bytes_per_frame,
urb_out->transfer_buffer_length);
}
- line6pcm->pos_out += urb_frames;
- if (line6pcm->pos_out >= runtime->buffer_size)
- line6pcm->pos_out -= runtime->buffer_size;
+ line6pcm->out.pos += urb_frames;
+ if (line6pcm->out.pos >= runtime->buffer_size)
+ line6pcm->out.pos -= runtime->buffer_size;
} else {
memset(urb_out->transfer_buffer, 0,
urb_out->transfer_buffer_length);
ret = usb_submit_urb(urb_out, GFP_ATOMIC);
if (ret == 0)
- set_bit(index, &line6pcm->active_urb_out);
+ set_bit(index, &line6pcm->out.active_urbs);
else
dev_err(line6pcm->line6->ifcdev,
"URB out #%d submission failed (%d)\n", index, ret);
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
return 0;
}
unsigned int i;
for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
- if (test_bit(i, &line6pcm->active_urb_out)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
- struct urb *u = line6pcm->urb_audio_out[i];
+ if (test_bit(i, &line6pcm->out.active_urbs)) {
+ if (!test_and_set_bit(i, &line6pcm->out.unlink_urbs)) {
+ struct urb *u = line6pcm->out.urbs[i];
usb_unlink_urb(u);
}
do {
alive = 0;
for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
- if (test_bit(i, &line6pcm->active_urb_out))
+ if (test_bit(i, &line6pcm->out.active_urbs))
alive++;
}
if (!alive)
void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
{
- kfree(line6pcm->buffer_out);
- line6pcm->buffer_out = NULL;
+ kfree(line6pcm->out.buffer);
+ line6pcm->out.buffer = NULL;
}
/*
memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
#endif
- line6pcm->last_frame_out = urb->start_frame;
+ line6pcm->out.last_frame = urb->start_frame;
/* find index of URB */
for (index = 0; index < LINE6_ISO_BUFFERS; index++)
- if (urb == line6pcm->urb_audio_out[index])
+ if (urb == line6pcm->out.urbs[index])
break;
if (index >= LINE6_ISO_BUFFERS)
for (i = 0; i < LINE6_ISO_PACKETS; i++)
length += urb->iso_frame_desc[i].length;
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
+ spin_lock_irqsave(&line6pcm->out.lock, flags);
if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
struct snd_pcm_runtime *runtime = substream->runtime;
- line6pcm->pos_out_done +=
+ line6pcm->out.pos_done +=
length / line6pcm->properties->bytes_per_frame;
- if (line6pcm->pos_out_done >= runtime->buffer_size)
- line6pcm->pos_out_done -= runtime->buffer_size;
+ if (line6pcm->out.pos_done >= runtime->buffer_size)
+ line6pcm->out.pos_done -= runtime->buffer_size;
}
- clear_bit(index, &line6pcm->active_urb_out);
+ clear_bit(index, &line6pcm->out.active_urbs);
for (i = 0; i < LINE6_ISO_PACKETS; i++)
if (urb->iso_frame_desc[i].status == -EXDEV) {
break;
}
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
+ if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
shutdown = 1;
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
if (!shutdown) {
submit_audio_out_urb(line6pcm);
if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
&line6pcm->flags)) {
- line6pcm->bytes_out += length;
- if (line6pcm->bytes_out >= line6pcm->period_out) {
- line6pcm->bytes_out %= line6pcm->period_out;
+ line6pcm->out.bytes += length;
+ if (line6pcm->out.bytes >= line6pcm->out.period) {
+ line6pcm->out.bytes %= line6pcm->out.period;
snd_pcm_period_elapsed(substream);
}
}
return ret;
}
- line6pcm->period_out = params_period_bytes(hw_params);
+ line6pcm->out.period = params_period_bytes(hw_params);
return 0;
}
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- return line6pcm->pos_out_done;
+ return line6pcm->out.pos_done;
}
/* playback operators */
struct urb *urb;
/* URB for audio out: */
- urb = line6pcm->urb_audio_out[i] =
+ urb = line6pcm->out.urbs[i] =
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL)