Compare commits
No commits in common. "main" and "us200-boot-delay-fix" have entirely different histories.
main
...
us200-boot
|
|
@ -1,14 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
// Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>
|
// Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <asm/unaligned.h>
|
||||||
#include <linux/unaligned/packed_struct.h>
|
|
||||||
#include <asm/byteorder.h>
|
|
||||||
#include "us144mkii_pcm.h"
|
#include "us144mkii_pcm.h"
|
||||||
|
|
||||||
#define get_unaligned_le64(ptr) le64_to_cpu(__get_unaligned_cpu64(ptr))
|
|
||||||
#define put_unaligned_le32(val, ptr) __put_unaligned_cpu32((val), ptr)
|
|
||||||
|
|
||||||
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 |
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,6 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_
|
||||||
usb_kill_anchored_urbs(&tascam->feedback_anchor);
|
usb_kill_anchored_urbs(&tascam->feedback_anchor);
|
||||||
usb_kill_anchored_urbs(&tascam->capture_anchor);
|
usb_kill_anchored_urbs(&tascam->capture_anchor);
|
||||||
atomic_set(&tascam->active_urbs, 0);
|
atomic_set(&tascam->active_urbs, 0);
|
||||||
tascam->running_ghost_playback = false;
|
|
||||||
|
|
||||||
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;
|
||||||
err = us144mkii_configure_device_for_rate(tascam, rate, stream_mode);
|
err = us144mkii_configure_device_for_rate(tascam, rate, stream_mode);
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ static int tascam_playback_close(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
atomic_set(&tascam->playback_active, 0);
|
atomic_set(&tascam->playback_active, 0);
|
||||||
|
usb_kill_anchored_urbs(&tascam->playback_anchor);
|
||||||
|
usb_kill_anchored_urbs(&tascam->feedback_anchor);
|
||||||
tascam->playback_substream = NULL;
|
tascam->playback_substream = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -138,21 +140,18 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
struct tascam_card *tascam = snd_pcm_substream_chip(substream);
|
||||||
|
|
||||||
|
usb_kill_anchored_urbs(&tascam->playback_anchor);
|
||||||
|
usb_kill_anchored_urbs(&tascam->feedback_anchor);
|
||||||
|
|
||||||
tascam->driver_playback_pos = 0;
|
tascam->driver_playback_pos = 0;
|
||||||
tascam->playback_frames_consumed = 0;
|
tascam->playback_frames_consumed = 0;
|
||||||
tascam->last_pb_period_pos = 0;
|
tascam->last_pb_period_pos = 0;
|
||||||
tascam->feedback_synced = false;
|
tascam->feedback_synced = false;
|
||||||
|
tascam->running_ghost_playback = false;
|
||||||
if (tascam->running_ghost_playback)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
usb_kill_anchored_urbs(&tascam->playback_anchor);
|
|
||||||
usb_kill_anchored_urbs(&tascam->feedback_anchor);
|
|
||||||
|
|
||||||
tascam->feedback_urb_skip_count = 4;
|
tascam->feedback_urb_skip_count = 4;
|
||||||
tascam->phase_accum = 0;
|
tascam->phase_accum = 0;
|
||||||
tascam->freq_q16 = div_u64(((u64)tascam->current_rate << 16), 8000);
|
tascam->freq_q16 = div_u64(((u64)tascam->current_rate << 16), 8000);
|
||||||
tascam->running_ghost_playback = false;
|
|
||||||
prepare_urb_descriptors(tascam);
|
prepare_urb_descriptors(tascam);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +181,9 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
atomic_set(&tascam->playback_active, 0);
|
atomic_set(&tascam->playback_active, 0);
|
||||||
tascam->running_ghost_playback = true;
|
/* Fall back to ghost playback if capture/midi active */
|
||||||
|
if (atomic_read(&tascam->stream_refs) > 0)
|
||||||
|
tascam->running_ghost_playback = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
@ -198,15 +199,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;
|
||||||
|
|
@ -256,22 +250,6 @@ void playback_urb_complete(struct urb *urb)
|
||||||
}
|
}
|
||||||
urb->transfer_buffer_length = total_bytes;
|
urb->transfer_buffer_length = total_bytes;
|
||||||
|
|
||||||
/* A stuck PLL can produce all-zero-length packets, which makes the
|
|
||||||
* device underflow and output persistent noise. Force a minimal
|
|
||||||
* nominal packet if that happens.
|
|
||||||
*/
|
|
||||||
if (total_bytes == 0) {
|
|
||||||
tascam->freq_q16 = div_u64(((u64)tascam->current_rate << 16), 8000);
|
|
||||||
tascam->phase_accum = 0;
|
|
||||||
frames = min((u32)(tascam->current_rate / 8000), (u32)MAX_FRAMES_PER_PACKET);
|
|
||||||
if (frames == 0)
|
|
||||||
frames = 1;
|
|
||||||
urb->iso_frame_desc[0].offset = 0;
|
|
||||||
urb->iso_frame_desc[0].length = frames * PLAYBACK_FRAME_SIZE;
|
|
||||||
total_bytes = urb->iso_frame_desc[0].length;
|
|
||||||
urb->transfer_buffer_length = total_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ghost Playback: Send Silence */
|
/* Ghost Playback: Send Silence */
|
||||||
if (!atomic_read(&tascam->playback_active)) {
|
if (!atomic_read(&tascam->playback_active)) {
|
||||||
if (tascam->running_ghost_playback) {
|
if (tascam->running_ghost_playback) {
|
||||||
|
|
@ -358,22 +336,9 @@ void feedback_urb_complete(struct urb *urb)
|
||||||
u8 *d = urb->transfer_buffer + urb->iso_frame_desc[p].offset;
|
u8 *d = urb->transfer_buffer + urb->iso_frame_desc[p].offset;
|
||||||
u32 val = (urb->iso_frame_desc[p].actual_length >= 3) ? (d[0] + d[1] + d[2]) : (d[0] * 3);
|
u32 val = (urb->iso_frame_desc[p].actual_length >= 3) ? (d[0] + d[1] + d[2]) : (d[0] * 3);
|
||||||
u32 target = (val << 16) / 24;
|
u32 target = (val << 16) / 24;
|
||||||
u32 nominal = div_u64(((u64)tascam->current_rate << 16), 8000);
|
tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT +
|
||||||
u32 min_freq = nominal - (nominal >> 2);
|
target * PLL_FILTER_NEW_WEIGHT) / PLL_FILTER_DIVISOR;
|
||||||
u32 max_freq = nominal + (nominal >> 2);
|
tascam->feedback_synced = true;
|
||||||
|
|
||||||
/* Ignore transient bad feedback that would drive the PLL to
|
|
||||||
* zero or an unrealistic value and cause DAC underflow noise.
|
|
||||||
*/
|
|
||||||
if (tascam->current_rate > 0 && target >= min_freq && target <= max_freq) {
|
|
||||||
tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT +
|
|
||||||
target * PLL_FILTER_NEW_WEIGHT) / PLL_FILTER_DIVISOR;
|
|
||||||
if (tascam->freq_q16 < min_freq)
|
|
||||||
tascam->freq_q16 = min_freq;
|
|
||||||
else if (tascam->freq_q16 > max_freq)
|
|
||||||
tascam->freq_q16 = max_freq;
|
|
||||||
tascam->feedback_synced = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue