code safety improvements
This commit is contained in:
parent
87ac941e35
commit
f4b17d24c8
|
|
@ -415,7 +415,7 @@ static int tascam_probe(struct usb_interface *intf,
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
struct tascam_card *tascam;
|
struct tascam_card *tascam;
|
||||||
int err;
|
int err;
|
||||||
char *handshake_buf;
|
char *handshake_buf __free(kfree);
|
||||||
|
|
||||||
if (dev->speed != USB_SPEED_HIGH)
|
if (dev->speed != USB_SPEED_HIGH)
|
||||||
dev_info(&dev->dev,
|
dev_info(&dev->dev,
|
||||||
|
|
@ -449,17 +449,15 @@ static int tascam_probe(struct usb_interface *intf,
|
||||||
handshake_buf, 1, USB_CTRL_TIMEOUT_MS);
|
handshake_buf, 1, USB_CTRL_TIMEOUT_MS);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&dev->dev, "Handshake read failed with %d\n", err);
|
dev_err(&dev->dev, "Handshake read failed with %d\n", err);
|
||||||
kfree(handshake_buf);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handshake_buf[0] != 0x12 && handshake_buf[0] != 0x16 &&
|
if (handshake_buf[0] != 0x12 && handshake_buf[0] != 0x16 &&
|
||||||
handshake_buf[0] != 0x30) {
|
handshake_buf[0] != 0x30) {
|
||||||
dev_err(&dev->dev, "Unexpected handshake value: 0x%x\n", handshake_buf[0]);
|
dev_err(&dev->dev, "Unexpected handshake value: 0x%x\n", handshake_buf[0]);
|
||||||
kfree(handshake_buf);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
kfree(handshake_buf);
|
|
||||||
|
|
||||||
err = usb_set_interface(dev, 0, 1);
|
err = usb_set_interface(dev, 0, 1);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
||||||
|
|
@ -73,14 +73,12 @@ tascam_capture_pointer(struct snd_pcm_substream *substream) {
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
u64 pos;
|
u64 pos;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!atomic_read(&tascam->capture_active))
|
if (!atomic_read(&tascam->capture_active))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
pos = tascam->capture_frames_processed;
|
pos = tascam->capture_frames_processed;
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (runtime->buffer_size == 0)
|
if (runtime->buffer_size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -165,7 +163,6 @@ void tascam_capture_work_handler(struct work_struct *work) {
|
||||||
container_of(work, struct tascam_card, capture_work);
|
container_of(work, struct tascam_card, capture_work);
|
||||||
struct snd_pcm_substream *substream = tascam->capture_substream;
|
struct snd_pcm_substream *substream = tascam->capture_substream;
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
unsigned long flags;
|
|
||||||
u8 *raw_block = tascam->capture_decode_raw_block;
|
u8 *raw_block = tascam->capture_decode_raw_block;
|
||||||
s32 *decoded_block = tascam->capture_decode_dst_block;
|
s32 *decoded_block = tascam->capture_decode_dst_block;
|
||||||
s32 *routed_block = tascam->capture_routing_buffer;
|
s32 *routed_block = tascam->capture_routing_buffer;
|
||||||
|
|
@ -184,28 +181,29 @@ void tascam_capture_work_handler(struct work_struct *work) {
|
||||||
size_t write_ptr, read_ptr, available_data;
|
size_t write_ptr, read_ptr, available_data;
|
||||||
bool can_process;
|
bool can_process;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
write_ptr = tascam->capture_ring_buffer_write_ptr;
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
read_ptr = tascam->capture_ring_buffer_read_ptr;
|
write_ptr = tascam->capture_ring_buffer_write_ptr;
|
||||||
available_data = (write_ptr >= read_ptr)
|
read_ptr = tascam->capture_ring_buffer_read_ptr;
|
||||||
? (write_ptr - read_ptr)
|
available_data = (write_ptr >= read_ptr)
|
||||||
: (CAPTURE_RING_BUFFER_SIZE - read_ptr + write_ptr);
|
? (write_ptr - read_ptr)
|
||||||
can_process = (available_data >= RAW_BYTES_PER_DECODE_BLOCK);
|
: (CAPTURE_RING_BUFFER_SIZE - read_ptr + write_ptr);
|
||||||
|
can_process = (available_data >= RAW_BYTES_PER_DECODE_BLOCK);
|
||||||
|
|
||||||
if (can_process) {
|
if (can_process) {
|
||||||
size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - read_ptr;
|
size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - read_ptr;
|
||||||
if (bytes_to_end >= RAW_BYTES_PER_DECODE_BLOCK) {
|
if (bytes_to_end >= RAW_BYTES_PER_DECODE_BLOCK) {
|
||||||
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr,
|
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr,
|
||||||
RAW_BYTES_PER_DECODE_BLOCK);
|
RAW_BYTES_PER_DECODE_BLOCK);
|
||||||
} else {
|
} else {
|
||||||
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr, bytes_to_end);
|
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr, bytes_to_end);
|
||||||
memcpy(raw_block + bytes_to_end, tascam->capture_ring_buffer,
|
memcpy(raw_block + bytes_to_end, tascam->capture_ring_buffer,
|
||||||
RAW_BYTES_PER_DECODE_BLOCK - bytes_to_end);
|
RAW_BYTES_PER_DECODE_BLOCK - bytes_to_end);
|
||||||
|
}
|
||||||
|
tascam->capture_ring_buffer_read_ptr =
|
||||||
|
(read_ptr + RAW_BYTES_PER_DECODE_BLOCK) % CAPTURE_RING_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
tascam->capture_ring_buffer_read_ptr =
|
|
||||||
(read_ptr + RAW_BYTES_PER_DECODE_BLOCK) % CAPTURE_RING_BUFFER_SIZE;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (!can_process)
|
if (!can_process)
|
||||||
break;
|
break;
|
||||||
|
|
@ -213,29 +211,30 @@ void tascam_capture_work_handler(struct work_struct *work) {
|
||||||
decode_tascam_capture_block(raw_block, decoded_block);
|
decode_tascam_capture_block(raw_block, decoded_block);
|
||||||
process_capture_routing_us144mkii(tascam, decoded_block, routed_block);
|
process_capture_routing_us144mkii(tascam, decoded_block, routed_block);
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
if (atomic_read(&tascam->capture_active)) {
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
int f;
|
if (atomic_read(&tascam->capture_active)) {
|
||||||
|
int f;
|
||||||
|
|
||||||
for (f = 0; f < FRAMES_PER_DECODE_BLOCK; ++f) {
|
for (f = 0; f < FRAMES_PER_DECODE_BLOCK; ++f) {
|
||||||
u8 *dst_frame_start =
|
u8 *dst_frame_start =
|
||||||
runtime->dma_area +
|
runtime->dma_area +
|
||||||
frames_to_bytes(runtime, tascam->driver_capture_pos);
|
frames_to_bytes(runtime, tascam->driver_capture_pos);
|
||||||
s32 *routed_frame_start = routed_block + (f * NUM_CHANNELS);
|
s32 *routed_frame_start = routed_block + (f * NUM_CHANNELS);
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
for (c = 0; c < NUM_CHANNELS; c++) {
|
for (c = 0; c < NUM_CHANNELS; c++) {
|
||||||
u8 *dst_channel = dst_frame_start + (c * BYTES_PER_SAMPLE);
|
u8 *dst_channel = dst_frame_start + (c * BYTES_PER_SAMPLE);
|
||||||
s32 *src_channel_s32 = routed_frame_start + c;
|
s32 *src_channel_s32 = routed_frame_start + c;
|
||||||
|
|
||||||
memcpy(dst_channel, ((char *)src_channel_s32) + 1, 3);
|
memcpy(dst_channel, ((char *)src_channel_s32) + 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
tascam->driver_capture_pos =
|
||||||
|
(tascam->driver_capture_pos + 1) % runtime->buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
tascam->driver_capture_pos =
|
|
||||||
(tascam->driver_capture_pos + 1) % runtime->buffer_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,7 +249,6 @@ void tascam_capture_work_handler(struct work_struct *work) {
|
||||||
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;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (urb->status) {
|
if (urb->status) {
|
||||||
if (urb->status != -ENOENT && urb->status != -ECONNRESET &&
|
if (urb->status != -ENOENT && urb->status != -ECONNRESET &&
|
||||||
|
|
@ -267,20 +265,25 @@ void capture_urb_complete(struct urb *urb) {
|
||||||
size_t write_ptr;
|
size_t write_ptr;
|
||||||
size_t bytes_to_end;
|
size_t bytes_to_end;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
write_ptr = tascam->capture_ring_buffer_write_ptr;
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr;
|
write_ptr = tascam->capture_ring_buffer_write_ptr;
|
||||||
|
bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr;
|
||||||
|
|
||||||
if (urb->actual_length > bytes_to_end) {
|
if (urb->actual_length > bytes_to_end) {
|
||||||
memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer, bytes_to_end);
|
memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer,
|
||||||
memcpy(tascam->capture_ring_buffer, urb->transfer_buffer + bytes_to_end, urb->actual_length - bytes_to_end);
|
bytes_to_end);
|
||||||
} else {
|
memcpy(tascam->capture_ring_buffer, urb->transfer_buffer + bytes_to_end,
|
||||||
memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer, urb->actual_length);
|
urb->actual_length - bytes_to_end);
|
||||||
|
} else {
|
||||||
|
memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer,
|
||||||
|
urb->actual_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
tascam->capture_ring_buffer_write_ptr =
|
||||||
|
(write_ptr + urb->actual_length) % CAPTURE_RING_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
tascam->capture_ring_buffer_write_ptr = (write_ptr + urb->actual_length) % CAPTURE_RING_BUFFER_SIZE;
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
schedule_work(&tascam->capture_work);
|
schedule_work(&tascam->capture_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,7 @@ static const char *const capture_source_texts[] = {"Analog In", "Digital In"};
|
||||||
*/
|
*/
|
||||||
static int tascam_playback_source_info(struct snd_kcontrol *kcontrol,
|
static int tascam_playback_source_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo) {
|
struct snd_ctl_elem_info *uinfo) {
|
||||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
return snd_ctl_enum_info(uinfo, 1, 2, playback_source_texts);
|
||||||
uinfo->count = 1;
|
|
||||||
uinfo->value.enumerated.items = 2;
|
|
||||||
if (uinfo->value.enumerated.item >= 2)
|
|
||||||
uinfo->value.enumerated.item = 1;
|
|
||||||
strscpy(uinfo->value.enumerated.name,
|
|
||||||
playback_source_texts[uinfo->value.enumerated.item],
|
|
||||||
sizeof(uinfo->value.enumerated.name));
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -179,15 +171,7 @@ static const struct snd_kcontrol_new tascam_digital_out_control = {
|
||||||
*/
|
*/
|
||||||
static int tascam_capture_source_info(struct snd_kcontrol *kcontrol,
|
static int tascam_capture_source_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo) {
|
struct snd_ctl_elem_info *uinfo) {
|
||||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
return snd_ctl_enum_info(uinfo, 1, 2, capture_source_texts);
|
||||||
uinfo->count = 1;
|
|
||||||
uinfo->value.enumerated.items = 2;
|
|
||||||
if (uinfo->value.enumerated.item >= 2)
|
|
||||||
uinfo->value.enumerated.item = 1;
|
|
||||||
strscpy(uinfo->value.enumerated.name,
|
|
||||||
capture_source_texts[uinfo->value.enumerated.item],
|
|
||||||
sizeof(uinfo->value.enumerated.name));
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -349,7 +333,7 @@ static int tascam_samplerate_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol) {
|
struct snd_ctl_elem_value *ucontrol) {
|
||||||
struct tascam_card *tascam =
|
struct tascam_card *tascam =
|
||||||
(struct tascam_card *)snd_kcontrol_chip(kcontrol);
|
(struct tascam_card *)snd_kcontrol_chip(kcontrol);
|
||||||
u8 *buf;
|
u8 *buf __free(kfree);
|
||||||
int err;
|
int err;
|
||||||
u32 rate = 0;
|
u32 rate = 0;
|
||||||
|
|
||||||
|
|
@ -370,7 +354,6 @@ static int tascam_samplerate_get(struct snd_kcontrol *kcontrol,
|
||||||
rate = buf[0] | (buf[1] << 8) | (buf[2] << 16);
|
rate = buf[0] | (buf[1] << 8) | (buf[2] << 16);
|
||||||
|
|
||||||
ucontrol->value.integer.value[0] = rate;
|
ucontrol->value.integer.value[0] = rate;
|
||||||
kfree(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,13 +124,13 @@ static void tascam_midi_in_trigger(struct snd_rawmidi_substream *substream,
|
||||||
int up) {
|
int up) {
|
||||||
struct tascam_card *tascam = substream->rmidi->private_data;
|
struct tascam_card *tascam = substream->rmidi->private_data;
|
||||||
int i, err;
|
int i, err;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (up) {
|
if (up) {
|
||||||
if (atomic_xchg(&tascam->midi_in_active, 1) == 0) {
|
if (atomic_xchg(&tascam->midi_in_active, 1) == 0) {
|
||||||
spin_lock_irqsave(&tascam->midi_in_lock, flags);
|
{
|
||||||
kfifo_reset(&tascam->midi_in_fifo);
|
guard(spinlock_irqsave)(&tascam->midi_in_lock);
|
||||||
spin_unlock_irqrestore(&tascam->midi_in_lock, flags);
|
kfifo_reset(&tascam->midi_in_fifo);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < NUM_MIDI_IN_URBS; i++) {
|
for (i = 0; i < NUM_MIDI_IN_URBS; i++) {
|
||||||
usb_get_urb(tascam->midi_in_urbs[i]);
|
usb_get_urb(tascam->midi_in_urbs[i]);
|
||||||
|
|
@ -175,7 +175,6 @@ static const struct snd_rawmidi_ops tascam_midi_in_ops = {
|
||||||
*/
|
*/
|
||||||
void tascam_midi_out_urb_complete(struct urb *urb) {
|
void tascam_midi_out_urb_complete(struct urb *urb) {
|
||||||
struct tascam_card *tascam = urb->context;
|
struct tascam_card *tascam = urb->context;
|
||||||
unsigned long flags;
|
|
||||||
int i, urb_index = -1;
|
int i, urb_index = -1;
|
||||||
|
|
||||||
if (urb->status) {
|
if (urb->status) {
|
||||||
|
|
@ -184,6 +183,7 @@ void tascam_midi_out_urb_complete(struct urb *urb) {
|
||||||
dev_err_ratelimited(tascam->card->dev, "MIDI OUT URB failed: %d\n",
|
dev_err_ratelimited(tascam->card->dev, "MIDI OUT URB failed: %d\n",
|
||||||
urb->status);
|
urb->status);
|
||||||
}
|
}
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tascam)
|
if (!tascam)
|
||||||
|
|
@ -201,12 +201,14 @@ void tascam_midi_out_urb_complete(struct urb *urb) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->midi_out_lock, flags);
|
{
|
||||||
clear_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
guard(spinlock_irqsave)(&tascam->midi_out_lock);
|
||||||
spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
|
clear_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
||||||
|
}
|
||||||
|
|
||||||
if (atomic_read(&tascam->midi_out_active))
|
if (atomic_read(&tascam->midi_out_active))
|
||||||
schedule_work(&tascam->midi_out_work);
|
schedule_work(&tascam->midi_out_work);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
usb_put_urb(urb);
|
usb_put_urb(urb);
|
||||||
}
|
}
|
||||||
|
|
@ -231,52 +233,51 @@ static void tascam_midi_out_work_handler(struct work_struct *work) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (snd_rawmidi_transmit_peek(substream, (u8[]){0}, 1) == 1) {
|
while (snd_rawmidi_transmit_peek(substream, (u8[]){0}, 1) == 1) {
|
||||||
unsigned long flags;
|
|
||||||
int urb_index;
|
int urb_index;
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
int bytes_to_send;
|
int bytes_to_send;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->midi_out_lock, flags);
|
{
|
||||||
|
guard(spinlock_irqsave)(&tascam->midi_out_lock);
|
||||||
|
|
||||||
urb_index = -1;
|
urb_index = -1;
|
||||||
for (i = 0; i < NUM_MIDI_OUT_URBS; i++) {
|
for (i = 0; i < NUM_MIDI_OUT_URBS; i++) {
|
||||||
if (!test_bit(i, &tascam->midi_out_urbs_in_flight)) {
|
if (!test_bit(i, &tascam->midi_out_urbs_in_flight)) {
|
||||||
urb_index = i;
|
urb_index = i;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (urb_index < 0) {
|
||||||
|
return; /* No free URBs, will be rescheduled by completion handler */
|
||||||
|
}
|
||||||
|
|
||||||
|
urb = tascam->midi_out_urbs[urb_index];
|
||||||
|
buf = urb->transfer_buffer;
|
||||||
|
bytes_to_send = snd_rawmidi_transmit(substream, buf, 8);
|
||||||
|
|
||||||
|
if (bytes_to_send <= 0) {
|
||||||
|
break; /* No more data */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_to_send < 9)
|
||||||
|
memset(buf + bytes_to_send, 0xfd, 9 - bytes_to_send);
|
||||||
|
buf[8] = 0x00;
|
||||||
|
|
||||||
|
set_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
||||||
|
urb->transfer_buffer_length = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urb_index < 0) {
|
|
||||||
spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
|
|
||||||
return; /* No free URBs, will be rescheduled by completion handler */
|
|
||||||
}
|
|
||||||
|
|
||||||
urb = tascam->midi_out_urbs[urb_index];
|
|
||||||
buf = urb->transfer_buffer;
|
|
||||||
bytes_to_send = snd_rawmidi_transmit(substream, buf, 8);
|
|
||||||
|
|
||||||
if (bytes_to_send <= 0) {
|
|
||||||
spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
|
|
||||||
break; /* No more data */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_to_send < 9)
|
|
||||||
memset(buf + bytes_to_send, 0xfd, 9 - bytes_to_send);
|
|
||||||
buf[8] = 0x00;
|
|
||||||
|
|
||||||
set_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
|
||||||
urb->transfer_buffer_length = 9;
|
|
||||||
spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
|
|
||||||
|
|
||||||
usb_get_urb(urb);
|
usb_get_urb(urb);
|
||||||
usb_anchor_urb(urb, &tascam->midi_out_anchor);
|
usb_anchor_urb(urb, &tascam->midi_out_anchor);
|
||||||
if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
|
if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
|
||||||
dev_err_ratelimited(tascam->card->dev,
|
dev_err_ratelimited(tascam->card->dev,
|
||||||
"Failed to submit MIDI OUT URB %d\n", urb_index);
|
"Failed to submit MIDI OUT URB %d\n", urb_index);
|
||||||
spin_lock_irqsave(&tascam->midi_out_lock, flags);
|
{
|
||||||
clear_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
guard(spinlock_irqsave)(&tascam->midi_out_lock);
|
||||||
spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
|
clear_bit(urb_index, &tascam->midi_out_urbs_in_flight);
|
||||||
|
}
|
||||||
usb_unanchor_urb(urb);
|
usb_unanchor_urb(urb);
|
||||||
usb_put_urb(urb);
|
usb_put_urb(urb);
|
||||||
break; /* Stop on error */
|
break; /* Stop on error */
|
||||||
|
|
|
||||||
|
|
@ -259,10 +259,6 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
int err;
|
int err;
|
||||||
unsigned int rate = params_rate(params);
|
unsigned int rate = params_rate(params);
|
||||||
|
|
||||||
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
tascam->fpo.sample_rate_khz = rate / 1000;
|
tascam->fpo.sample_rate_khz = rate / 1000;
|
||||||
tascam->fpo.base_feedback_value = tascam->fpo.sample_rate_khz;
|
tascam->fpo.base_feedback_value = tascam->fpo.sample_rate_khz;
|
||||||
|
|
@ -300,9 +296,7 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
*
|
*
|
||||||
* Return: 0 on success.
|
* Return: 0 on success.
|
||||||
*/
|
*/
|
||||||
int tascam_pcm_hw_free(struct snd_pcm_substream *substream) {
|
int tascam_pcm_hw_free(struct snd_pcm_substream *substream) { return 0; }
|
||||||
return snd_pcm_lib_free_pages(substream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tascam_pcm_trigger() - Triggers the start or stop of PCM streams.
|
* tascam_pcm_trigger() - Triggers the start or stop of PCM streams.
|
||||||
|
|
@ -318,36 +312,36 @@ int tascam_pcm_hw_free(struct snd_pcm_substream *substream) {
|
||||||
*/
|
*/
|
||||||
int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
unsigned long flags;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int i;
|
int i;
|
||||||
bool do_start = false;
|
bool do_start = false;
|
||||||
bool do_stop = false;
|
bool do_stop = false;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
switch (cmd) {
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
if (!atomic_read(&tascam->playback_active)) {
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
atomic_set(&tascam->playback_active, 1);
|
if (!atomic_read(&tascam->playback_active)) {
|
||||||
atomic_set(&tascam->capture_active, 1);
|
atomic_set(&tascam->playback_active, 1);
|
||||||
do_start = true;
|
atomic_set(&tascam->capture_active, 1);
|
||||||
|
do_start = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
|
if (atomic_read(&tascam->playback_active)) {
|
||||||
|
atomic_set(&tascam->playback_active, 0);
|
||||||
|
atomic_set(&tascam->capture_active, 0);
|
||||||
|
do_stop = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
||||||
if (atomic_read(&tascam->playback_active)) {
|
|
||||||
atomic_set(&tascam->playback_active, 0);
|
|
||||||
atomic_set(&tascam->capture_active, 0);
|
|
||||||
do_stop = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (do_start) {
|
if (do_start) {
|
||||||
if (atomic_read(&tascam->active_urbs) > 0) {
|
if (atomic_read(&tascam->active_urbs) > 0) {
|
||||||
|
|
@ -362,7 +356,7 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
usb_unanchor_urb(tascam->feedback_urbs[i]);
|
usb_unanchor_urb(tascam->feedback_urbs[i]);
|
||||||
usb_put_urb(tascam->feedback_urbs[i]);
|
usb_put_urb(tascam->feedback_urbs[i]);
|
||||||
atomic_dec(&tascam->active_urbs); /* Decrement on failed submission */
|
atomic_dec(&tascam->active_urbs);
|
||||||
goto start_rollback;
|
goto start_rollback;
|
||||||
}
|
}
|
||||||
atomic_inc(&tascam->active_urbs);
|
atomic_inc(&tascam->active_urbs);
|
||||||
|
|
@ -374,7 +368,7 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
usb_unanchor_urb(tascam->playback_urbs[i]);
|
usb_unanchor_urb(tascam->playback_urbs[i]);
|
||||||
usb_put_urb(tascam->playback_urbs[i]);
|
usb_put_urb(tascam->playback_urbs[i]);
|
||||||
atomic_dec(&tascam->active_urbs); /* Decrement on failed submission */
|
atomic_dec(&tascam->active_urbs);
|
||||||
goto start_rollback;
|
goto start_rollback;
|
||||||
}
|
}
|
||||||
atomic_inc(&tascam->active_urbs);
|
atomic_inc(&tascam->active_urbs);
|
||||||
|
|
@ -386,7 +380,7 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
usb_unanchor_urb(tascam->capture_urbs[i]);
|
usb_unanchor_urb(tascam->capture_urbs[i]);
|
||||||
usb_put_urb(tascam->capture_urbs[i]);
|
usb_put_urb(tascam->capture_urbs[i]);
|
||||||
atomic_dec(&tascam->active_urbs); /* Decrement on failed submission */
|
atomic_dec(&tascam->active_urbs);
|
||||||
goto start_rollback;
|
goto start_rollback;
|
||||||
}
|
}
|
||||||
atomic_inc(&tascam->active_urbs);
|
atomic_inc(&tascam->active_urbs);
|
||||||
|
|
@ -405,26 +399,18 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* tascam_init_pcm() - Initializes the ALSA PCM device.
|
|
||||||
* @pcm: Pointer to the ALSA PCM device to initialize.
|
|
||||||
*
|
|
||||||
* This function sets up the PCM operations for playback and capture,
|
|
||||||
* preallocates pages for the PCM buffer, and initializes the workqueue
|
|
||||||
* for deferred capture processing.
|
|
||||||
*
|
|
||||||
* Return: 0 on success.
|
|
||||||
*/
|
|
||||||
int tascam_init_pcm(struct snd_pcm *pcm) {
|
int tascam_init_pcm(struct snd_pcm *pcm) {
|
||||||
struct tascam_card *tascam = pcm->private_data;
|
struct tascam_card *tascam = pcm->private_data;
|
||||||
|
|
||||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &tascam_playback_ops);
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &tascam_playback_ops);
|
||||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tascam_capture_ops);
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tascam_capture_ops);
|
||||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
|
|
||||||
tascam->dev->dev.parent, 64 * 1024,
|
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
|
||||||
tascam_pcm_hw.buffer_bytes_max);
|
tascam->dev->dev.parent, 64 * 1024,
|
||||||
|
tascam_pcm_hw.buffer_bytes_max);
|
||||||
|
|
||||||
INIT_WORK(&tascam->capture_work, tascam_capture_work_handler);
|
INIT_WORK(&tascam->capture_work, tascam_capture_work_handler);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,12 @@ tascam_playback_pointer(struct snd_pcm_substream *substream) {
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
u64 pos;
|
u64 pos;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!atomic_read(&tascam->playback_active))
|
if (!atomic_read(&tascam->playback_active))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
pos = tascam->playback_frames_consumed;
|
pos = tascam->playback_frames_consumed;
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (runtime->buffer_size == 0)
|
if (runtime->buffer_size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -160,7 +158,6 @@ void playback_urb_complete(struct urb *urb) {
|
||||||
struct tascam_card *tascam = urb->context;
|
struct tascam_card *tascam = urb->context;
|
||||||
struct snd_pcm_substream *substream;
|
struct snd_pcm_substream *substream;
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
size_t total_bytes_for_urb = 0;
|
size_t total_bytes_for_urb = 0;
|
||||||
snd_pcm_uframes_t offset_frames;
|
snd_pcm_uframes_t offset_frames;
|
||||||
|
|
@ -182,35 +179,35 @@ void playback_urb_complete(struct urb *urb) {
|
||||||
goto out;
|
goto out;
|
||||||
runtime = substream->runtime;
|
runtime = substream->runtime;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
|
|
||||||
for (i = 0; i < urb->number_of_packets; i++) {
|
for (i = 0; i < urb->number_of_packets; i++) {
|
||||||
unsigned int frames_for_packet;
|
unsigned int frames_for_packet;
|
||||||
size_t bytes_for_packet;
|
size_t bytes_for_packet;
|
||||||
|
|
||||||
if (tascam->feedback_synced) {
|
if (tascam->feedback_synced) {
|
||||||
frames_for_packet =
|
frames_for_packet =
|
||||||
tascam
|
tascam->feedback_accumulator_pattern
|
||||||
->feedback_accumulator_pattern[tascam->feedback_pattern_out_idx];
|
[tascam->feedback_pattern_out_idx];
|
||||||
tascam->feedback_pattern_out_idx =
|
tascam->feedback_pattern_out_idx =
|
||||||
(tascam->feedback_pattern_out_idx + 1) % FEEDBACK_ACCUMULATOR_SIZE;
|
(tascam->feedback_pattern_out_idx + 1) % FEEDBACK_ACCUMULATOR_SIZE;
|
||||||
} else {
|
} else {
|
||||||
frames_for_packet = runtime->rate / 8000;
|
frames_for_packet = runtime->rate / 8000;
|
||||||
|
}
|
||||||
|
bytes_for_packet = frames_for_packet * BYTES_PER_FRAME;
|
||||||
|
|
||||||
|
urb->iso_frame_desc[i].offset = total_bytes_for_urb;
|
||||||
|
urb->iso_frame_desc[i].length = bytes_for_packet;
|
||||||
|
total_bytes_for_urb += bytes_for_packet;
|
||||||
}
|
}
|
||||||
bytes_for_packet = frames_for_packet * BYTES_PER_FRAME;
|
urb->transfer_buffer_length = total_bytes_for_urb;
|
||||||
|
|
||||||
urb->iso_frame_desc[i].offset = total_bytes_for_urb;
|
offset_frames = tascam->driver_playback_pos;
|
||||||
urb->iso_frame_desc[i].length = bytes_for_packet;
|
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
|
||||||
total_bytes_for_urb += bytes_for_packet;
|
tascam->driver_playback_pos =
|
||||||
|
(offset_frames + frames_to_copy) % runtime->buffer_size;
|
||||||
}
|
}
|
||||||
urb->transfer_buffer_length = total_bytes_for_urb;
|
|
||||||
|
|
||||||
offset_frames = tascam->driver_playback_pos;
|
|
||||||
frames_to_copy = bytes_to_frames(runtime, total_bytes_for_urb);
|
|
||||||
tascam->driver_playback_pos =
|
|
||||||
(offset_frames + frames_to_copy) % runtime->buffer_size;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (total_bytes_for_urb > 0) {
|
if (total_bytes_for_urb > 0) {
|
||||||
u8 *dst_buf = urb->transfer_buffer;
|
u8 *dst_buf = urb->transfer_buffer;
|
||||||
|
|
@ -267,7 +264,6 @@ void feedback_urb_complete(struct urb *urb) {
|
||||||
struct tascam_card *tascam = urb->context;
|
struct tascam_card *tascam = urb->context;
|
||||||
struct snd_pcm_substream *playback_ss, *capture_ss;
|
struct snd_pcm_substream *playback_ss, *capture_ss;
|
||||||
struct snd_pcm_runtime *playback_rt, *capture_rt;
|
struct snd_pcm_runtime *playback_rt, *capture_rt;
|
||||||
unsigned long flags;
|
|
||||||
u64 total_frames_in_urb = 0;
|
u64 total_frames_in_urb = 0;
|
||||||
int ret, p;
|
int ret, p;
|
||||||
unsigned int old_in_idx, new_in_idx;
|
unsigned int old_in_idx, new_in_idx;
|
||||||
|
|
@ -294,126 +290,126 @@ void feedback_urb_complete(struct urb *urb) {
|
||||||
capture_ss = tascam->capture_substream;
|
capture_ss = tascam->capture_substream;
|
||||||
capture_rt = capture_ss ? capture_ss->runtime : NULL;
|
capture_rt = capture_ss ? capture_ss->runtime : NULL;
|
||||||
|
|
||||||
spin_lock_irqsave(&tascam->lock, flags);
|
{
|
||||||
|
guard(spinlock_irqsave)(&tascam->lock);
|
||||||
|
|
||||||
if (tascam->feedback_urb_skip_count > 0) {
|
if (tascam->feedback_urb_skip_count > 0) {
|
||||||
tascam->feedback_urb_skip_count--;
|
tascam->feedback_urb_skip_count--;
|
||||||
goto unlock_and_continue;
|
goto continue_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_in_idx = tascam->feedback_pattern_in_idx;
|
old_in_idx = tascam->feedback_pattern_in_idx;
|
||||||
|
|
||||||
for (p = 0; p < urb->number_of_packets; p++) {
|
for (p = 0; p < urb->number_of_packets; p++) {
|
||||||
u8 feedback_value = 0;
|
u8 feedback_value = 0;
|
||||||
const unsigned int *pattern;
|
const unsigned int *pattern;
|
||||||
bool packet_ok = (urb->iso_frame_desc[p].status == 0 &&
|
bool packet_ok = (urb->iso_frame_desc[p].status == 0 &&
|
||||||
urb->iso_frame_desc[p].actual_length >= 1);
|
urb->iso_frame_desc[p].actual_length >= 1);
|
||||||
|
|
||||||
if (packet_ok)
|
if (packet_ok)
|
||||||
feedback_value =
|
feedback_value =
|
||||||
*((u8 *)urb->transfer_buffer + urb->iso_frame_desc[p].offset);
|
*((u8 *)urb->transfer_buffer + urb->iso_frame_desc[p].offset);
|
||||||
|
|
||||||
if (packet_ok) {
|
if (packet_ok) {
|
||||||
int delta = feedback_value - tascam->fpo.base_feedback_value +
|
int delta = feedback_value - tascam->fpo.base_feedback_value +
|
||||||
tascam->fpo.feedback_offset;
|
tascam->fpo.feedback_offset;
|
||||||
int pattern_idx;
|
int pattern_idx;
|
||||||
|
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
pattern_idx = 0; // Clamp to the lowest pattern
|
pattern_idx = 0; // Clamp to the lowest pattern
|
||||||
} else if (delta >= 5) {
|
} else if (delta >= 5) {
|
||||||
pattern_idx = 4; // Clamp to the highest pattern
|
pattern_idx = 4; // Clamp to the highest pattern
|
||||||
|
} else {
|
||||||
|
pattern_idx = delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = tascam->fpo.full_frame_patterns[pattern_idx];
|
||||||
|
tascam->feedback_consecutive_errors = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
unsigned int in_idx = (tascam->feedback_pattern_in_idx + i) %
|
||||||
|
FEEDBACK_ACCUMULATOR_SIZE;
|
||||||
|
|
||||||
|
tascam->feedback_accumulator_pattern[in_idx] = pattern[i];
|
||||||
|
total_frames_in_urb += pattern[i];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pattern_idx = delta;
|
unsigned int nominal_frames = playback_rt->rate / 8000;
|
||||||
}
|
int i;
|
||||||
|
|
||||||
pattern = tascam->fpo.full_frame_patterns[pattern_idx];
|
if (tascam->feedback_synced) {
|
||||||
tascam->feedback_consecutive_errors = 0;
|
tascam->feedback_consecutive_errors++;
|
||||||
int i;
|
if (tascam->feedback_consecutive_errors >
|
||||||
|
FEEDBACK_SYNC_LOSS_THRESHOLD) {
|
||||||
|
dev_err(tascam->card->dev,
|
||||||
|
"Fatal: Feedback sync lost. Stopping stream.\n");
|
||||||
|
if (playback_ss)
|
||||||
|
snd_pcm_stop(playback_ss, SNDRV_PCM_STATE_XRUN);
|
||||||
|
if (capture_ss)
|
||||||
|
snd_pcm_stop(capture_ss, SNDRV_PCM_STATE_XRUN);
|
||||||
|
tascam->feedback_synced = false;
|
||||||
|
goto continue_unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
unsigned int in_idx = (tascam->feedback_pattern_in_idx + i) %
|
||||||
|
FEEDBACK_ACCUMULATOR_SIZE;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
tascam->feedback_accumulator_pattern[in_idx] = nominal_frames;
|
||||||
unsigned int in_idx =
|
total_frames_in_urb += nominal_frames;
|
||||||
(tascam->feedback_pattern_in_idx + i) % FEEDBACK_ACCUMULATOR_SIZE;
|
|
||||||
|
|
||||||
tascam->feedback_accumulator_pattern[in_idx] = pattern[i];
|
|
||||||
total_frames_in_urb += pattern[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsigned int nominal_frames = playback_rt->rate / 8000;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (tascam->feedback_synced) {
|
|
||||||
tascam->feedback_consecutive_errors++;
|
|
||||||
if (tascam->feedback_consecutive_errors >
|
|
||||||
FEEDBACK_SYNC_LOSS_THRESHOLD) {
|
|
||||||
dev_err(tascam->card->dev,
|
|
||||||
"Fatal: Feedback sync lost. Stopping stream.\n");
|
|
||||||
if (playback_ss)
|
|
||||||
snd_pcm_stop(playback_ss, SNDRV_PCM_STATE_XRUN);
|
|
||||||
if (capture_ss)
|
|
||||||
snd_pcm_stop(capture_ss, SNDRV_PCM_STATE_XRUN);
|
|
||||||
tascam->feedback_synced = false;
|
|
||||||
goto unlock_and_continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < 8; i++) {
|
tascam->feedback_pattern_in_idx =
|
||||||
unsigned int in_idx =
|
(tascam->feedback_pattern_in_idx + 8) % FEEDBACK_ACCUMULATOR_SIZE;
|
||||||
(tascam->feedback_pattern_in_idx + i) % FEEDBACK_ACCUMULATOR_SIZE;
|
}
|
||||||
|
|
||||||
tascam->feedback_accumulator_pattern[in_idx] = nominal_frames;
|
new_in_idx = tascam->feedback_pattern_in_idx;
|
||||||
total_frames_in_urb += nominal_frames;
|
|
||||||
|
if (!tascam->feedback_synced) {
|
||||||
|
unsigned int out_idx = tascam->feedback_pattern_out_idx;
|
||||||
|
bool is_ahead = (new_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE <
|
||||||
|
(FEEDBACK_ACCUMULATOR_SIZE / 2);
|
||||||
|
bool was_behind = (old_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE >=
|
||||||
|
(FEEDBACK_ACCUMULATOR_SIZE / 2);
|
||||||
|
|
||||||
|
if (is_ahead && was_behind) {
|
||||||
|
dev_dbg(tascam->card->dev, "Sync Acquired! (in: %u, out: %u)\n",
|
||||||
|
new_in_idx, out_idx);
|
||||||
|
tascam->feedback_synced = true;
|
||||||
|
tascam->feedback_consecutive_errors = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tascam->feedback_pattern_in_idx =
|
|
||||||
(tascam->feedback_pattern_in_idx + 8) % FEEDBACK_ACCUMULATOR_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_in_idx = tascam->feedback_pattern_in_idx;
|
if (total_frames_in_urb > 0) {
|
||||||
|
tascam->playback_frames_consumed += total_frames_in_urb;
|
||||||
|
if (atomic_read(&tascam->capture_active))
|
||||||
|
tascam->capture_frames_processed += total_frames_in_urb;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tascam->feedback_synced) {
|
if (playback_rt->period_size > 0) {
|
||||||
unsigned int out_idx = tascam->feedback_pattern_out_idx;
|
u64 current_period = div_u64(tascam->playback_frames_consumed,
|
||||||
bool is_ahead = (new_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE <
|
playback_rt->period_size);
|
||||||
(FEEDBACK_ACCUMULATOR_SIZE / 2);
|
|
||||||
bool was_behind = (old_in_idx - out_idx) % FEEDBACK_ACCUMULATOR_SIZE >=
|
|
||||||
(FEEDBACK_ACCUMULATOR_SIZE / 2);
|
|
||||||
|
|
||||||
if (is_ahead && was_behind) {
|
if (current_period > tascam->last_period_pos) {
|
||||||
dev_dbg(tascam->card->dev, "Sync Acquired! (in: %u, out: %u)\n",
|
tascam->last_period_pos = current_period;
|
||||||
new_in_idx, out_idx);
|
playback_period_elapsed = true;
|
||||||
tascam->feedback_synced = true;
|
}
|
||||||
tascam->feedback_consecutive_errors = 0;
|
}
|
||||||
|
|
||||||
|
if (atomic_read(&tascam->capture_active) && capture_rt &&
|
||||||
|
capture_rt->period_size > 0) {
|
||||||
|
u64 current_capture_period = div_u64(tascam->capture_frames_processed,
|
||||||
|
capture_rt->period_size);
|
||||||
|
|
||||||
|
if (current_capture_period > tascam->last_capture_period_pos) {
|
||||||
|
tascam->last_capture_period_pos = current_capture_period;
|
||||||
|
capture_period_elapsed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_frames_in_urb > 0) {
|
continue_unlock:
|
||||||
tascam->playback_frames_consumed += total_frames_in_urb;
|
|
||||||
if (atomic_read(&tascam->capture_active))
|
|
||||||
tascam->capture_frames_processed += total_frames_in_urb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playback_rt->period_size > 0) {
|
|
||||||
u64 current_period =
|
|
||||||
div_u64(tascam->playback_frames_consumed, playback_rt->period_size);
|
|
||||||
|
|
||||||
if (current_period > tascam->last_period_pos) {
|
|
||||||
tascam->last_period_pos = current_period;
|
|
||||||
playback_period_elapsed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atomic_read(&tascam->capture_active) && capture_rt &&
|
|
||||||
capture_rt->period_size > 0) {
|
|
||||||
u64 current_capture_period =
|
|
||||||
div_u64(tascam->capture_frames_processed, capture_rt->period_size);
|
|
||||||
|
|
||||||
if (current_capture_period > tascam->last_capture_period_pos) {
|
|
||||||
tascam->last_capture_period_pos = current_capture_period;
|
|
||||||
capture_period_elapsed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock_and_continue:
|
|
||||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
|
||||||
|
|
||||||
if (playback_period_elapsed)
|
if (playback_period_elapsed)
|
||||||
snd_pcm_period_elapsed(playback_ss);
|
snd_pcm_period_elapsed(playback_ss);
|
||||||
if (capture_period_elapsed)
|
if (capture_period_elapsed)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue