Compare commits
No commits in common. "0e75851b4bcaea59085cb147d44c017c4a69a18f" and "4c9ff01806a031e2b651844f5e888ceddea8d154" have entirely different histories.
0e75851b4b
...
4c9ff01806
22
us144mkii.c
22
us144mkii.c
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
MODULE_AUTHOR("Šerif Rami <ramiserifpersia@gmail.com>");
|
MODULE_AUTHOR("Šerif Rami <ramiserifpersia@gmail.com>");
|
||||||
MODULE_DESCRIPTION("ALSA Driver for TASCAM US-144MKII");
|
MODULE_DESCRIPTION("ALSA Driver for TASCAM US-144MKII");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||||
|
|
@ -218,9 +218,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||||
INIT_WORK(&tascam->stop_work, tascam_stop_work_handler);
|
INIT_WORK(&tascam->stop_work, tascam_stop_work_handler);
|
||||||
INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler);
|
INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler);
|
||||||
atomic_set(&tascam->stream_refs, 0);
|
atomic_set(&tascam->stream_refs, 0);
|
||||||
atomic_set(&tascam->active_urbs, 0);
|
|
||||||
atomic_set(&tascam->playback_active, 0);
|
|
||||||
atomic_set(&tascam->capture_active, 0);
|
|
||||||
|
|
||||||
strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
|
strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
|
||||||
|
|
||||||
|
|
@ -264,9 +261,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||||
goto free_card;
|
goto free_card;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device firmware needs ~100ms to be ready on cold boot. Without this
|
|
||||||
* delay, the handshake below fails consistently at boot time and requires
|
|
||||||
* unplug/replug to work. The msleep is intentional despite adding latency. */
|
|
||||||
msleep(100);
|
msleep(100);
|
||||||
|
|
||||||
int handshake_result = -EIO;
|
int handshake_result = -EIO;
|
||||||
|
|
@ -300,12 +294,10 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||||
|
|
||||||
u16 stream_mode = (tascam->dev_id == USB_PID_TASCAM_US200) ? MODE_VAL_STREAM_START_US200 : MODE_VAL_STREAM_START;
|
u16 stream_mode = (tascam->dev_id == USB_PID_TASCAM_US200) ? MODE_VAL_STREAM_START_US200 : MODE_VAL_STREAM_START;
|
||||||
|
|
||||||
if (us144mkii_configure_device_for_rate(tascam, 48000, stream_mode) < 0) {
|
if (us144mkii_configure_device_for_rate(tascam, 48000, stream_mode) < 0)
|
||||||
dev_err(&dev->dev, "Failed to initialize device at 48khz\n");
|
dev_warn(&dev->dev, "Failed to initialize device at 48khz\n");
|
||||||
err = -EIO;
|
else
|
||||||
goto free_card;
|
tascam->current_rate = 48000;
|
||||||
}
|
|
||||||
tascam->current_rate = 48000;
|
|
||||||
|
|
||||||
err = snd_card_register(card);
|
err = snd_card_register(card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|
@ -322,7 +314,7 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tascam_remove(struct usb_interface *intf)
|
static void tascam_disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = usb_get_intfdata(intf);
|
struct tascam_card *tascam = usb_get_intfdata(intf);
|
||||||
|
|
||||||
|
|
@ -359,7 +351,7 @@ MODULE_DEVICE_TABLE(usb, tascam_usb_ids);
|
||||||
static struct usb_driver tascam_alsa_driver = {
|
static struct usb_driver tascam_alsa_driver = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.probe = tascam_probe,
|
.probe = tascam_probe,
|
||||||
.remove = tascam_remove,
|
.disconnect = tascam_disconnect,
|
||||||
.suspend = tascam_suspend,
|
.suspend = tascam_suspend,
|
||||||
.resume = tascam_resume,
|
.resume = tascam_resume,
|
||||||
.id_table = tascam_usb_ids,
|
.id_table = tascam_usb_ids,
|
||||||
|
|
|
||||||
|
|
@ -172,10 +172,6 @@ struct tascam_card {
|
||||||
unsigned int feedback_urb_skip_count;
|
unsigned int feedback_urb_skip_count;
|
||||||
bool running_ghost_playback;
|
bool running_ghost_playback;
|
||||||
|
|
||||||
u8 capture_remainder_buf[63];
|
|
||||||
unsigned int capture_remainder_len;
|
|
||||||
u8 capture_combined_buf[CAPTURE_PACKET_SIZE + 63];
|
|
||||||
|
|
||||||
struct work_struct stop_work;
|
struct work_struct stop_work;
|
||||||
struct work_struct stop_pcm_work;
|
struct work_struct stop_pcm_work;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
const struct snd_pcm_hardware tascam_capture_hw = {
|
const struct snd_pcm_hardware tascam_capture_hw = {
|
||||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
|
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
|
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
|
||||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||||
.rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
.rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
|
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
|
||||||
|
|
@ -46,7 +47,6 @@ static int tascam_capture_prepare(struct snd_pcm_substream *substream)
|
||||||
tascam->driver_capture_pos = 0;
|
tascam->driver_capture_pos = 0;
|
||||||
tascam->capture_frames_processed = 0;
|
tascam->capture_frames_processed = 0;
|
||||||
tascam->last_cap_period_pos = 0;
|
tascam->last_cap_period_pos = 0;
|
||||||
tascam->capture_remainder_len = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,71 +145,40 @@ static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames)
|
||||||
* @urb: the completed URB
|
* @urb: the completed URB
|
||||||
*
|
*
|
||||||
* Decodes audio data, updates ring buffer, and handles period elapsed.
|
* Decodes audio data, updates ring buffer, and handles period elapsed.
|
||||||
* Handles partial 64-byte frames by buffering remainder across URB completions.
|
|
||||||
* Distinguishes transient USB errors from fatal ones for robustness.
|
|
||||||
*/
|
*/
|
||||||
void capture_urb_complete(struct urb *urb)
|
void capture_urb_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = urb->context;
|
struct tascam_card *tascam = urb->context;
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
int frames, part1, total_available, new_remainder;
|
int frames, part1;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
bool need_period_elapsed = false;
|
bool need_period_elapsed = false;
|
||||||
u8 *combined = tascam->capture_combined_buf;
|
|
||||||
|
|
||||||
if (!tascam || !tascam->dev)
|
if (urb->status || !tascam || !tascam->dev)
|
||||||
return;
|
|
||||||
|
|
||||||
if (urb->status) {
|
|
||||||
if (urb->status == -EOVERFLOW || urb->status == -ENOENT || urb->status == -EPIPE) {
|
|
||||||
usb_anchor_urb(urb, &tascam->capture_anchor);
|
|
||||||
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
|
||||||
usb_unanchor_urb(urb);
|
|
||||||
atomic_dec(&tascam->active_urbs);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
|
||||||
|
|
||||||
if (!tascam->capture_substream || !tascam->capture_substream->runtime)
|
if (!tascam->capture_substream || !tascam->capture_substream->runtime)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
runtime = tascam->capture_substream->runtime;
|
runtime = tascam->capture_substream->runtime;
|
||||||
|
frames = urb->actual_length / 64;
|
||||||
memcpy(combined, tascam->capture_remainder_buf, tascam->capture_remainder_len);
|
|
||||||
memcpy(combined + tascam->capture_remainder_len, urb->transfer_buffer, urb->actual_length);
|
|
||||||
total_available = tascam->capture_remainder_len + urb->actual_length;
|
|
||||||
|
|
||||||
frames = total_available / 64;
|
|
||||||
new_remainder = total_available % 64;
|
|
||||||
|
|
||||||
if (frames > runtime->buffer_size) {
|
|
||||||
dev_warn(&tascam->dev->dev, "Capture URB returned %d frames, clamping to buffer size %u\n",
|
|
||||||
frames, runtime->buffer_size);
|
|
||||||
new_remainder = (total_available - runtime->buffer_size * 64);
|
|
||||||
frames = runtime->buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frames > 0) {
|
if (frames > 0) {
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
spin_lock_irqsave(&tascam->lock, flags);
|
||||||
|
|
||||||
if (!atomic_read(&tascam->capture_active)) {
|
if (!atomic_read(&tascam->capture_active)) {
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||||
tascam->capture_remainder_len = new_remainder;
|
goto exit;
|
||||||
if (new_remainder > 0)
|
|
||||||
memcpy(tascam->capture_remainder_buf, combined + (frames * 64), new_remainder);
|
|
||||||
goto resubmit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *dma = (u32 *)(runtime->dma_area + frames_to_bytes(runtime, tascam->driver_capture_pos));
|
u32 *dma = (u32 *)(runtime->dma_area + frames_to_bytes(runtime, tascam->driver_capture_pos));
|
||||||
|
|
||||||
if (tascam->driver_capture_pos + frames <= runtime->buffer_size) {
|
if (tascam->driver_capture_pos + frames <= runtime->buffer_size) {
|
||||||
tascam_decode_capture_chunk(combined, dma, frames);
|
tascam_decode_capture_chunk(urb->transfer_buffer, dma, frames);
|
||||||
} else {
|
} else {
|
||||||
part1 = runtime->buffer_size - tascam->driver_capture_pos;
|
part1 = runtime->buffer_size - tascam->driver_capture_pos;
|
||||||
tascam_decode_capture_chunk(combined, dma, part1);
|
tascam_decode_capture_chunk(urb->transfer_buffer, dma, part1);
|
||||||
tascam_decode_capture_chunk(combined + (part1 * 64),
|
tascam_decode_capture_chunk(urb->transfer_buffer + (part1 * 64),
|
||||||
(u32 *)runtime->dma_area, frames - part1);
|
(u32 *)runtime->dma_area, frames - part1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,11 +192,6 @@ void capture_urb_complete(struct urb *urb)
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
tascam->capture_remainder_len = new_remainder;
|
|
||||||
if (new_remainder > 0)
|
|
||||||
memcpy(tascam->capture_remainder_buf, combined + (frames * 64), new_remainder);
|
|
||||||
|
|
||||||
resubmit:
|
|
||||||
usb_anchor_urb(urb, &tascam->capture_anchor);
|
usb_anchor_urb(urb, &tascam->capture_anchor);
|
||||||
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
||||||
usb_unanchor_urb(urb);
|
usb_unanchor_urb(urb);
|
||||||
|
|
@ -240,7 +204,7 @@ resubmit:
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
usb_unanchor_urb(urb);
|
usb_unanchor_urb(urb);
|
||||||
atomic_dec(&tascam->active_urbs);
|
atomic_dec(&tascam->active_urbs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,16 @@ static void tascam_midi_out_complete(struct urb *urb)
|
||||||
|
|
||||||
if (urb->status || !sub || !tascam->midi_out_active) {
|
if (urb->status || !sub || !tascam->midi_out_active) {
|
||||||
tascam->midi_out_active = false;
|
tascam->midi_out_active = false;
|
||||||
usb_unanchor_urb(urb);
|
|
||||||
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = snd_rawmidi_transmit(sub, tascam->midi_out_buf + 1, 8);
|
count = snd_rawmidi_transmit(sub, tascam->midi_out_buf, 8);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
tascam->midi_out_buf[0] = 0xE0;
|
|
||||||
if (count < 8)
|
if (count < 8)
|
||||||
memset(tascam->midi_out_buf + 1 + count, 0xFD, 8 - count);
|
memset(tascam->midi_out_buf + count, 0xFD, 8 - count);
|
||||||
|
|
||||||
|
tascam->midi_out_buf[8] = 0xE0;
|
||||||
urb->transfer_buffer_length = 9;
|
urb->transfer_buffer_length = 9;
|
||||||
|
|
||||||
usb_anchor_urb(urb, &tascam->midi_anchor);
|
usb_anchor_urb(urb, &tascam->midi_anchor);
|
||||||
|
|
@ -50,12 +49,12 @@ static void tascam_midi_output_trigger(struct snd_rawmidi_substream *sub, int up
|
||||||
tascam->midi_output = sub;
|
tascam->midi_output = sub;
|
||||||
if (!tascam->midi_out_active) {
|
if (!tascam->midi_out_active) {
|
||||||
tascam->midi_out_active = true;
|
tascam->midi_out_active = true;
|
||||||
count = snd_rawmidi_transmit(sub, tascam->midi_out_buf + 1, 8);
|
count = snd_rawmidi_transmit(sub, tascam->midi_out_buf, 8);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
tascam->midi_out_buf[0] = 0xE0;
|
|
||||||
if (count < 8)
|
if (count < 8)
|
||||||
memset(tascam->midi_out_buf + 1 + count, 0xFD, 8 - count);
|
memset(tascam->midi_out_buf + count, 0xFD, 8 - count);
|
||||||
|
|
||||||
|
tascam->midi_out_buf[8] = 0xE0;
|
||||||
tascam->midi_out_urb->transfer_buffer_length = 9;
|
tascam->midi_out_urb->transfer_buffer_length = 9;
|
||||||
|
|
||||||
usb_anchor_urb(tascam->midi_out_urb, &tascam->midi_anchor);
|
usb_anchor_urb(tascam->midi_out_urb, &tascam->midi_anchor);
|
||||||
|
|
@ -88,11 +87,10 @@ static void tascam_midi_in_complete(struct urb *urb)
|
||||||
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
||||||
|
|
||||||
if (urb->actual_length == 9 && sub) {
|
if (urb->actual_length == 9 && sub) {
|
||||||
u8 *buf = (u8 *)urb->transfer_buffer + 1;
|
while (len < 8 && ((u8 *)urb->transfer_buffer)[len] != 0xFD)
|
||||||
while (len < 8 && buf[len] != 0xFD)
|
|
||||||
len++;
|
len++;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
snd_rawmidi_receive(sub, buf, len);
|
snd_rawmidi_receive(sub, urb->transfer_buffer, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_anchor_urb(urb, &tascam->midi_anchor);
|
usb_anchor_urb(urb, &tascam->midi_anchor);
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,6 @@ int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate, u1
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Note: EP_AUDIO_IN is 0x86 (includes USB_DIR_IN direction bit). The UAC spec
|
|
||||||
* expects the bare endpoint number (0x06) in wIndex. This device firmware
|
|
||||||
* tolerates the direction bit, so we keep it as-is rather than risk breakage. */
|
|
||||||
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
|
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
|
||||||
RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL,
|
RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL,
|
||||||
EP_AUDIO_IN, payload, 3, USB_CTRL_TIMEOUT_MS);
|
EP_AUDIO_IN, payload, 3, USB_CTRL_TIMEOUT_MS);
|
||||||
|
|
@ -157,19 +154,9 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_
|
||||||
void tascam_stop_pcm_work_handler(struct work_struct *work)
|
void tascam_stop_pcm_work_handler(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = container_of(work, struct tascam_card, stop_pcm_work);
|
struct tascam_card *tascam = container_of(work, struct tascam_card, stop_pcm_work);
|
||||||
struct snd_pcm_substream *pb, *cap;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!tascam || !tascam->dev)
|
if (tascam->dev && tascam->playback_substream)
|
||||||
return;
|
snd_pcm_stop(tascam->playback_substream, SNDRV_PCM_STATE_XRUN);
|
||||||
|
if (tascam->dev && tascam->capture_substream)
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
snd_pcm_stop(tascam->capture_substream, SNDRV_PCM_STATE_XRUN);
|
||||||
pb = tascam->playback_substream;
|
|
||||||
cap = tascam->capture_substream;
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (pb)
|
|
||||||
snd_pcm_stop(pb, SNDRV_PCM_STATE_XRUN);
|
|
||||||
if (cap)
|
|
||||||
snd_pcm_stop(cap, SNDRV_PCM_STATE_XRUN);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
const struct snd_pcm_hardware tascam_playback_hw = {
|
const struct snd_pcm_hardware tascam_playback_hw = {
|
||||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
|
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
|
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
|
||||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||||
.rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
.rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
|
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000),
|
||||||
|
|
@ -178,10 +179,8 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
/* Re-prepare descriptors with current rate in case hw_params changed */
|
/* Re-prepare descriptors with current rate in case hw_params changed */
|
||||||
prepare_urb_descriptors(tascam);
|
prepare_urb_descriptors(tascam);
|
||||||
} else {
|
} else {
|
||||||
if (submit_urbs(tascam, tascam->feedback_urbs, NUM_FEEDBACK_URBS, &tascam->feedback_anchor) < 0 ||
|
submit_urbs(tascam, tascam->feedback_urbs, NUM_FEEDBACK_URBS, &tascam->feedback_anchor);
|
||||||
submit_urbs(tascam, tascam->playback_urbs, NUM_PLAYBACK_URBS, &tascam->playback_anchor) < 0) {
|
submit_urbs(tascam, tascam->playback_urbs, NUM_PLAYBACK_URBS, &tascam->playback_anchor);
|
||||||
ret = -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -207,15 +206,8 @@ static snd_pcm_uframes_t tascam_playback_pointer(struct snd_pcm_substream *subst
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u64 pos;
|
u64 pos;
|
||||||
|
|
||||||
if (!atomic_read(&tascam->playback_active)) {
|
if (!atomic_read(&tascam->playback_active))
|
||||||
if (tascam->running_ghost_playback) {
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
|
||||||
pos = tascam->playback_frames_consumed;
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
return (snd_pcm_uframes_t)pos;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
spin_lock_irqsave(&tascam->lock, flags);
|
||||||
pos = tascam->playback_frames_consumed;
|
pos = tascam->playback_frames_consumed;
|
||||||
|
|
@ -293,17 +285,15 @@ void playback_urb_complete(struct urb *urb)
|
||||||
|
|
||||||
runtime = tascam->playback_substream->runtime;
|
runtime = tascam->playback_substream->runtime;
|
||||||
ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
||||||
void *dma_area = runtime->dma_area;
|
|
||||||
size_t buf_size_bytes = frames_to_bytes(runtime, runtime->buffer_size);
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||||
|
|
||||||
/* Copy from ALSA Buffer */
|
/* Copy from ALSA Buffer */
|
||||||
if (total_bytes + ptr_bytes > buf_size_bytes) {
|
if (total_bytes + ptr_bytes > frames_to_bytes(runtime, runtime->buffer_size)) {
|
||||||
part1_bytes = buf_size_bytes - ptr_bytes;
|
part1_bytes = frames_to_bytes(runtime, runtime->buffer_size) - ptr_bytes;
|
||||||
memcpy(urb->transfer_buffer, dma_area + ptr_bytes, part1_bytes);
|
memcpy(urb->transfer_buffer, runtime->dma_area + ptr_bytes, part1_bytes);
|
||||||
memcpy(urb->transfer_buffer + part1_bytes, dma_area, total_bytes - part1_bytes);
|
memcpy(urb->transfer_buffer + part1_bytes, runtime->dma_area, total_bytes - part1_bytes);
|
||||||
} else {
|
} else {
|
||||||
memcpy(urb->transfer_buffer, dma_area + ptr_bytes, total_bytes);
|
memcpy(urb->transfer_buffer, runtime->dma_area + ptr_bytes, total_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
spin_lock_irqsave(&tascam->lock, flags);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue