From c379dc65c1b19e3e4942df13b8f7b17aab2b50c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0erif=20Rami?= Date: Tue, 6 Jan 2026 20:01:07 +0100 Subject: [PATCH] improvements --- us144mkii.c | 28 +++++++---- us144mkii.h | 19 ++++---- us144mkii_capture.c | 83 +++++++++++++++++--------------- us144mkii_midi.c | 27 ++++------- us144mkii_pcm.c | 111 +++++++++++++++++++++++++------------------ us144mkii_playback.c | 95 ++++++++++++++++++++---------------- 6 files changed, 202 insertions(+), 161 deletions(-) diff --git a/us144mkii.c b/us144mkii.c index ef0159c..eacab74 100644 --- a/us144mkii.c +++ b/us144mkii.c @@ -87,7 +87,8 @@ int tascam_alloc_urbs(struct tascam_card *tascam) { int i; - tascam->playback_urb_alloc_size = PLAYBACK_URB_PACKETS * (12 + 2) * BYTES_PER_FRAME; + tascam->playback_urb_alloc_size = PLAYBACK_URB_PACKETS * 156; + for (i = 0; i < NUM_PLAYBACK_URBS; i++) { struct urb *urb = usb_alloc_urb(PLAYBACK_URB_PACKETS, GFP_KERNEL); @@ -129,12 +130,13 @@ int tascam_alloc_urbs(struct tascam_card *tascam) for (i = 0; i < NUM_CAPTURE_URBS; i++) { struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); + void *buf; if (!urb) return -ENOMEM; tascam->capture_urbs[i] = urb; - void *buf = usb_alloc_coherent(tascam->dev, CAPTURE_PACKET_SIZE, - GFP_KERNEL, &urb->transfer_dma); + buf = usb_alloc_coherent(tascam->dev, CAPTURE_PACKET_SIZE, + GFP_KERNEL, &urb->transfer_dma); if (!buf) return -ENOMEM; usb_fill_bulk_urb(urb, tascam->dev, @@ -188,9 +190,6 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_anchored_urbs(&tascam->capture_anchor); usb_kill_anchored_urbs(&tascam->midi_anchor); - usb_control_msg(tascam->dev, usb_sndctrlpipe(tascam->dev, 0), - VENDOR_REQ_DEEP_SLEEP, RT_H2D_VENDOR_DEV, - 0x0000, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS); return 0; } @@ -198,6 +197,8 @@ static int tascam_resume(struct usb_interface *intf) { struct tascam_card *tascam = usb_get_intfdata(intf); int err; + unsigned long flags; + int current_rate; if (!tascam) return 0; @@ -205,12 +206,17 @@ static int tascam_resume(struct usb_interface *intf) err = usb_set_interface(tascam->dev, 0, 1); if (err < 0) return err; + err = usb_set_interface(tascam->dev, 1, 1); if (err < 0) return err; - if (tascam->current_rate > 0) - us144mkii_configure_device_for_rate(tascam, tascam->current_rate); + spin_lock_irqsave(&tascam->lock, flags); + current_rate = tascam->current_rate; + spin_unlock_irqrestore(&tascam->lock, flags); + + if (current_rate > 0) + us144mkii_configure_device_for_rate(tascam, current_rate); return 0; } @@ -249,6 +255,8 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id * tascam->card = card; tascam->iface0 = intf; + tascam->dev_id = le16_to_cpu(dev->descriptor.idProduct); + spin_lock_init(&tascam->lock); init_usb_anchor(&tascam->playback_anchor); init_usb_anchor(&tascam->feedback_anchor); @@ -259,7 +267,7 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id * INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler); strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); - if (le16_to_cpu(dev->descriptor.idProduct) == USB_PID_TASCAM_US144) + if (tascam->dev_id == USB_PID_TASCAM_US144) strscpy(card->shortname, "US-144", sizeof(card->shortname)); else strscpy(card->shortname, "US-144MKII", sizeof(card->shortname)); @@ -326,7 +334,7 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id * usb_set_intfdata(intf, tascam); return 0; -free_card: + free_card: snd_card_free(card); atomic_dec(&dev_idx); return err; diff --git a/us144mkii.h b/us144mkii.h index ead811c..7dafda6 100644 --- a/us144mkii.h +++ b/us144mkii.h @@ -41,7 +41,6 @@ enum uac_control_selector { enum tascam_vendor_request { VENDOR_REQ_REGISTER_WRITE = 0x41, - VENDOR_REQ_DEEP_SLEEP = 0x44, VENDOR_REQ_MODE_CONTROL = 0x49, }; @@ -52,25 +51,25 @@ enum tascam_mode_value { }; enum tascam_register { - REG_ADDR_UNKNOWN_0D = 0x0d04, - REG_ADDR_UNKNOWN_0E = 0x0e00, - REG_ADDR_UNKNOWN_0F = 0x0f00, + REG_ADDR_INIT_0D = 0x0d04, + REG_ADDR_INIT_0E = 0x0e00, + REG_ADDR_INIT_0F = 0x0f00, REG_ADDR_RATE_44100 = 0x1000, REG_ADDR_RATE_48000 = 0x1002, REG_ADDR_RATE_88200 = 0x1008, REG_ADDR_RATE_96000 = 0x100a, - REG_ADDR_UNKNOWN_11 = 0x110b, + REG_ADDR_INIT_11 = 0x110b, }; #define REG_VAL_ENABLE 0x0101 -#define NUM_PLAYBACK_URBS 4 -#define PLAYBACK_URB_PACKETS 4 -#define NUM_FEEDBACK_URBS 2 +#define NUM_PLAYBACK_URBS 2 +#define PLAYBACK_URB_PACKETS 8 +#define NUM_FEEDBACK_URBS 4 #define FEEDBACK_URB_PACKETS 1 #define FEEDBACK_PACKET_SIZE 3 #define NUM_CAPTURE_URBS 8 -#define CAPTURE_PACKET_SIZE 512 +#define CAPTURE_PACKET_SIZE 4096 #define MIDI_PACKET_SIZE 9 #define MIDI_PAYLOAD_SIZE 8 @@ -137,6 +136,8 @@ struct tascam_card { struct snd_pcm *pcm; struct snd_rawmidi *rmidi; + u16 dev_id; + u8 *scratch_buf; struct snd_pcm_substream *playback_substream; diff --git a/us144mkii_capture.c b/us144mkii_capture.c index aab7054..421fb43 100644 --- a/us144mkii_capture.c +++ b/us144mkii_capture.c @@ -16,7 +16,7 @@ const struct snd_pcm_hardware tascam_capture_hw = { .channels_min = NUM_CHANNELS, .channels_max = NUM_CHANNELS, .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 32 * BYTES_PER_FRAME, + .period_bytes_min = 48 * BYTES_PER_FRAME, .period_bytes_max = 1024 * BYTES_PER_FRAME, .periods_min = 2, .periods_max = 1024, @@ -80,27 +80,26 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock_irqsave(&tascam->lock, flags); switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - if (!atomic_read(&tascam->capture_active)) { - atomic_set(&tascam->capture_active, 1); - start = true; - } - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - atomic_set(&tascam->capture_active, 0); - stop = true; - break; - default: - ret = -EINVAL; - break; + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + if (!atomic_read(&tascam->capture_active)) { + atomic_set(&tascam->capture_active, 1); + start = true; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + atomic_set(&tascam->capture_active, 0); + stop = true; + break; + default: + ret = -EINVAL; + break; } spin_unlock_irqrestore(&tascam->lock, flags); if (stop) { - /* Ensure capture_active is updated before unlinking URBs. */ smp_mb(); for (i = 0; i < NUM_CAPTURE_URBS; i++) { if (tascam->capture_urbs[i]) @@ -114,7 +113,6 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd) if (usb_submit_urb(tascam->capture_urbs[i], GFP_ATOMIC) < 0) { usb_unanchor_urb(tascam->capture_urbs[i]); atomic_set(&tascam->capture_active, 0); - /* Ensure capture_active is updated before unlinking URBs due to submission error. */ smp_mb(); for (int j = 0; j < i; j++) usb_unlink_urb(tascam->capture_urbs[j]); @@ -130,16 +128,26 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd) static inline void tascam_unpack_8bytes(const u8 *src, u8 *out_bit0, u8 *out_bit1) { u64 val = get_unaligned_le64(src); - u8 b0 = 0, b1 = 0; - int i; - for (i = 0; i < 8; i++) { - b0 |= ((val >> (i * 8)) & 1) << (7 - i); - b1 |= ((val >> (i * 8 + 1)) & 1) << (7 - i); - } + *out_bit0 = + (((val >> 0) & 1) << 7) | + (((val >> 8) & 1) << 6) | + (((val >> 16) & 1) << 5) | + (((val >> 24) & 1) << 4) | + (((val >> 32) & 1) << 3) | + (((val >> 40) & 1) << 2) | + (((val >> 48) & 1) << 1) | + (((val >> 56) & 1) << 0); - *out_bit0 = b0; - *out_bit1 = b1; + *out_bit1 = + (((val >> 1) & 1) << 7) | + (((val >> 9) & 1) << 6) | + (((val >> 17) & 1) << 5) | + (((val >> 25) & 1) << 4) | + (((val >> 33) & 1) << 3) | + (((val >> 41) & 1) << 2) | + (((val >> 49) & 1) << 1) | + (((val >> 57) & 1) << 0); } static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_decode) @@ -151,12 +159,10 @@ static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_d const u8 *p_src_a = src + (i * 64); const u8 *p_src_b = src + (i * 64) + 32; - /* Channel 1 (h0) and Channel 3 (h2) */ tascam_unpack_8bytes(p_src_a, &h[0], &h[2]); tascam_unpack_8bytes(p_src_a + 8, &m[0], &m[2]); tascam_unpack_8bytes(p_src_a + 16, &l[0], &l[2]); - /* Channel 2 (h1) and Channel 4 (h3) */ tascam_unpack_8bytes(p_src_b, &h[1], &h[3]); tascam_unpack_8bytes(p_src_b + 8, &m[1], &m[3]); tascam_unpack_8bytes(p_src_b + 16, &l[1], &l[3]); @@ -168,14 +174,6 @@ static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_d } } -/** - * capture_urb_complete() - completion handler for capture bulk URBs - * @urb: the completed URB - * - * This function runs in interrupt context. It copies the received raw data - * into an intermediate ring buffer and then schedules the workqueue to process - * it. It then resubmits the URB to receive more data. - */ void capture_urb_complete(struct urb *urb) { struct tascam_card *tascam = urb->context; @@ -190,18 +188,27 @@ void capture_urb_complete(struct urb *urb) if (!tascam) return; + if (!tascam->dev) { + usb_unanchor_urb(urb); + atomic_dec(&tascam->active_urbs); + return; + } + if (urb->status) { + usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); return; } substream = tascam->capture_substream; if (!substream || !substream->runtime) { + usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); return; } runtime = substream->runtime; if (!runtime->dma_area) { + usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); return; } @@ -223,7 +230,6 @@ void capture_urb_complete(struct urb *urb) } write_pos = tascam->driver_capture_pos; - u32 *dma_ptr = (u32 *)(runtime->dma_area + frames_to_bytes(runtime, write_pos)); if (write_pos + frames_received <= buffer_size) { @@ -260,6 +266,7 @@ void capture_urb_complete(struct urb *urb) if (usb_submit_urb(urb, GFP_ATOMIC) < 0) { usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); + return; } } diff --git a/us144mkii_midi.c b/us144mkii_midi.c index d58f936..399e444 100644 --- a/us144mkii_midi.c +++ b/us144mkii_midi.c @@ -22,10 +22,11 @@ static void tascam_midi_out_complete(struct urb *urb) spin_unlock_irqrestore(&tascam->midi_lock, flags); return; } - spin_unlock_irqrestore(&tascam->midi_lock, flags); - if (!active) + if (!active) { + spin_unlock_irqrestore(&tascam->midi_lock, flags); return; + } count = snd_rawmidi_transmit(substream, tascam->midi_out_buf, MIDI_PAYLOAD_SIZE); if (count > 0) { @@ -36,20 +37,18 @@ static void tascam_midi_out_complete(struct urb *urb) urb->transfer_buffer_length = MIDI_PACKET_SIZE; submit = true; } else { - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_out_active = false; - spin_unlock_irqrestore(&tascam->midi_lock, flags); } if (submit) { usb_anchor_urb(urb, &tascam->midi_anchor); if (usb_submit_urb(urb, GFP_ATOMIC) < 0) { usb_unanchor_urb(urb); - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_out_active = false; - spin_unlock_irqrestore(&tascam->midi_lock, flags); } } + + spin_unlock_irqrestore(&tascam->midi_lock, flags); } static void tascam_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) @@ -57,18 +56,14 @@ static void tascam_midi_output_trigger(struct snd_rawmidi_substream *substream, struct tascam_card *tascam = substream->rmidi->private_data; unsigned long flags; int count; - bool do_submit = false; + + spin_lock_irqsave(&tascam->midi_lock, flags); if (up) { - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_output = substream; if (!tascam->midi_out_active) { tascam->midi_out_active = true; - do_submit = true; - } - spin_unlock_irqrestore(&tascam->midi_lock, flags); - if (do_submit) { count = snd_rawmidi_transmit(substream, tascam->midi_out_buf, MIDI_PAYLOAD_SIZE); if (count > 0) { if (count < MIDI_PAYLOAD_SIZE) @@ -80,21 +75,17 @@ static void tascam_midi_output_trigger(struct snd_rawmidi_substream *substream, usb_anchor_urb(tascam->midi_out_urb, &tascam->midi_anchor); if (usb_submit_urb(tascam->midi_out_urb, GFP_ATOMIC) < 0) { usb_unanchor_urb(tascam->midi_out_urb); - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_out_active = false; - spin_unlock_irqrestore(&tascam->midi_lock, flags); } } else { - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_out_active = false; - spin_unlock_irqrestore(&tascam->midi_lock, flags); } } } else { - spin_lock_irqsave(&tascam->midi_lock, flags); tascam->midi_output = NULL; - spin_unlock_irqrestore(&tascam->midi_lock, flags); } + + spin_unlock_irqrestore(&tascam->midi_lock, flags); } static void tascam_midi_in_complete(struct urb *urb) diff --git a/us144mkii_pcm.c b/us144mkii_pcm.c index 86d0ad9..47e1960 100644 --- a/us144mkii_pcm.c +++ b/us144mkii_pcm.c @@ -11,7 +11,7 @@ static int tascam_write_regs(struct tascam_card *tascam, const u16 *regs, size_t for (i = 0; i < count; i++) { err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), VENDOR_REQ_REGISTER_WRITE, RT_H2D_VENDOR_DEV, - regs[i], REG_VAL_ENABLE, NULL, 0, USB_CTRL_TIMEOUT_MS); + regs[i], REG_VAL_ENABLE, NULL, 0, USB_CTRL_TIMEOUT_MS); if (err < 0) return err; } @@ -31,74 +31,77 @@ static int tascam_write_regs(struct tascam_card *tascam, const u16 *regs, size_t int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate) { struct usb_device *dev = tascam->dev; - u8 *rate_payload_buf; + u8 *rate_payload; int err = 0; const u8 *current_payload_src; u16 rate_reg; - static const u8 payload_44100[] = { 0x44, 0xac, 0x00 }; static const u8 payload_48000[] = { 0x80, 0xbb, 0x00 }; static const u8 payload_88200[] = { 0x88, 0x58, 0x01 }; static const u8 payload_96000[] = { 0x00, 0x77, 0x01 }; + if (!dev) + return -ENODEV; + switch (rate) { - case 44100: - current_payload_src = payload_44100; - rate_reg = REG_ADDR_RATE_44100; - break; - case 48000: - current_payload_src = payload_48000; - rate_reg = REG_ADDR_RATE_48000; - break; - case 88200: - current_payload_src = payload_88200; - rate_reg = REG_ADDR_RATE_88200; - break; - case 96000: - current_payload_src = payload_96000; - rate_reg = REG_ADDR_RATE_96000; - break; - default: - return -EINVAL; + case 44100: + current_payload_src = payload_44100; + rate_reg = REG_ADDR_RATE_44100; + break; + case 48000: + current_payload_src = payload_48000; + rate_reg = REG_ADDR_RATE_48000; + break; + case 88200: + current_payload_src = payload_88200; + rate_reg = REG_ADDR_RATE_88200; + break; + case 96000: + current_payload_src = payload_96000; + rate_reg = REG_ADDR_RATE_96000; + break; + default: + return -EINVAL; } - rate_payload_buf = kmemdup(current_payload_src, 3, GFP_KERNEL); - if (!rate_payload_buf) + rate_payload = kmemdup(current_payload_src, 3, GFP_KERNEL); + if (!rate_payload) return -ENOMEM; err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, MODE_VAL_CONFIG, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS); if (err < 0) - goto fail; + goto out; - usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, - EP_AUDIO_IN, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS); - usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, - EP_AUDIO_OUT, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS); + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, + EP_AUDIO_IN, rate_payload, 3, USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto out; + + err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, + EP_AUDIO_OUT, rate_payload, 3, USB_CTRL_TIMEOUT_MS); + if (err < 0) + goto out; { const u16 regs_to_write[] = { - REG_ADDR_UNKNOWN_0D, REG_ADDR_UNKNOWN_0E, - REG_ADDR_UNKNOWN_0F, rate_reg, REG_ADDR_UNKNOWN_11 + REG_ADDR_INIT_0D, REG_ADDR_INIT_0E, + REG_ADDR_INIT_0F, rate_reg, REG_ADDR_INIT_11 }; err = tascam_write_regs(tascam, regs_to_write, ARRAY_SIZE(regs_to_write)); if (err < 0) - goto fail; + goto out; } err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, MODE_VAL_STREAM_START, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS); - if (err < 0) - goto fail; - kfree(rate_payload_buf); - return 0; -fail: - kfree(rate_payload_buf); + out: + kfree(rate_payload); return err; } @@ -120,12 +123,20 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream, struct tascam_card *tascam = snd_pcm_substream_chip(substream); unsigned int rate = params_rate(params); int err; + unsigned long flags; - if (tascam->current_rate != rate) { - if (atomic_read(&tascam->playback_active) || - atomic_read(&tascam->capture_active)) { - return -EBUSY; - } + spin_lock_irqsave(&tascam->lock, flags); + if (tascam->current_rate == rate) { + spin_unlock_irqrestore(&tascam->lock, flags); + return 0; + } + + if (atomic_read(&tascam->playback_active) || + atomic_read(&tascam->capture_active)) { + spin_unlock_irqrestore(&tascam->lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&tascam->lock, flags); usb_kill_anchored_urbs(&tascam->playback_anchor); usb_kill_anchored_urbs(&tascam->feedback_anchor); @@ -135,12 +146,17 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream, err = us144mkii_configure_device_for_rate(tascam, rate); if (err < 0) { + spin_lock_irqsave(&tascam->lock, flags); tascam->current_rate = 0; + spin_unlock_irqrestore(&tascam->lock, flags); return err; } + + spin_lock_irqsave(&tascam->lock, flags); tascam->current_rate = rate; - } - return 0; + spin_unlock_irqrestore(&tascam->lock, flags); + + return 0; } /** @@ -151,6 +167,9 @@ void tascam_stop_pcm_work_handler(struct work_struct *work) { struct tascam_card *tascam = container_of(work, struct tascam_card, stop_pcm_work); + if (!tascam->dev) + return; + if (tascam->playback_substream) snd_pcm_stop(tascam->playback_substream, SNDRV_PCM_STATE_XRUN); } diff --git a/us144mkii_playback.c b/us144mkii_playback.c index 860912c..2040d9f 100644 --- a/us144mkii_playback.c +++ b/us144mkii_playback.c @@ -15,7 +15,7 @@ const struct snd_pcm_hardware tascam_playback_hw = { .channels_min = NUM_CHANNELS, .channels_max = NUM_CHANNELS, .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 32 * BYTES_PER_FRAME, + .period_bytes_min = 48 * BYTES_PER_FRAME, .period_bytes_max = 1024 * BYTES_PER_FRAME, .periods_min = 2, .periods_max = 1024, @@ -26,6 +26,7 @@ static int tascam_playback_open(struct snd_pcm_substream *substream) struct tascam_card *tascam = snd_pcm_substream_chip(substream); substream->runtime->hw = tascam_playback_hw; + tascam->playback_substream = substream; atomic_set(&tascam->playback_active, 0); return 0; @@ -48,7 +49,6 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream) struct tascam_card *tascam = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int i, u; - u32 nominal_q16 = (runtime->rate << 16) / 8000; size_t nominal_bytes = (runtime->rate / 8000) * BYTES_PER_FRAME; usb_kill_anchored_urbs(&tascam->playback_anchor); @@ -60,7 +60,7 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream) tascam->feedback_synced = false; tascam->feedback_urb_skip_count = NUM_FEEDBACK_URBS; tascam->phase_accum = 0; - tascam->freq_q16 = nominal_q16; + tascam->freq_q16 = div_u64(((u64)runtime->rate << 16), 8000); for (i = 0; i < NUM_FEEDBACK_URBS; i++) { struct urb *f_urb = tascam->feedback_urbs[i]; @@ -75,11 +75,11 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream) for (u = 0; u < NUM_PLAYBACK_URBS; u++) { struct urb *urb = tascam->playback_urbs[u]; + int num_packets = PLAYBACK_URB_PACKETS; - memset(urb->transfer_buffer, 0, tascam->playback_urb_alloc_size); - urb->number_of_packets = PLAYBACK_URB_PACKETS; - urb->transfer_buffer_length = PLAYBACK_URB_PACKETS * nominal_bytes; - for (i = 0; i < PLAYBACK_URB_PACKETS; i++) { + urb->number_of_packets = num_packets; + urb->transfer_buffer_length = num_packets * nominal_bytes; + for (i = 0; i < num_packets; i++) { urb->iso_frame_desc[i].offset = i * nominal_bytes; urb->iso_frame_desc[i].length = nominal_bytes; } @@ -113,27 +113,28 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock_irqsave(&tascam->lock, flags); switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - if (!atomic_read(&tascam->playback_active)) { - atomic_set(&tascam->playback_active, 1); - start = true; - } - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - atomic_set(&tascam->playback_active, 0); - stop = true; - break; - default: - ret = -EINVAL; - break; + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + if (!atomic_read(&tascam->playback_active)) { + atomic_set(&tascam->playback_active, 1); + tascam->feedback_synced = false; + tascam->feedback_urb_skip_count = NUM_FEEDBACK_URBS; + start = true; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + atomic_set(&tascam->playback_active, 0); + stop = true; + break; + default: + ret = -EINVAL; + break; } spin_unlock_irqrestore(&tascam->lock, flags); if (stop) { - /* Ensure playback_active is updated before unlinking URBs. */ smp_mb(); for (i = 0; i < NUM_FEEDBACK_URBS; i++) { if (tascam->feedback_urbs[i]) @@ -150,9 +151,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd) usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor); if (usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC) < 0) { usb_unanchor_urb(tascam->feedback_urbs[i]); - dev_err(&tascam->dev->dev, "Failed to submit feedback URB %d\n", i); atomic_set(&tascam->playback_active, 0); - /* Ensure playback_active is updated before unlinking feedback URBs due to submission error. */ smp_mb(); for (int j = 0; j < i; j++) usb_unlink_urb(tascam->feedback_urbs[j]); @@ -165,9 +164,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd) usb_anchor_urb(tascam->playback_urbs[i], &tascam->playback_anchor); if (usb_submit_urb(tascam->playback_urbs[i], GFP_ATOMIC) < 0) { usb_unanchor_urb(tascam->playback_urbs[i]); - dev_err(&tascam->dev->dev, "Failed to submit playback URB %d\n", i); atomic_set(&tascam->playback_active, 0); - /* Ensure playback_active is updated before unlinking playback URBs due to submission error. */ smp_mb(); for (int j = 0; j < NUM_FEEDBACK_URBS; j++) usb_unlink_urb(tascam->feedback_urbs[j]); @@ -182,7 +179,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd) schedule_work(&tascam->stop_work); } -error: + error: return ret; } @@ -211,6 +208,7 @@ void playback_urb_complete(struct urb *urb) return; if (urb->status) { + usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); return; } @@ -243,6 +241,10 @@ void playback_urb_complete(struct urb *urb) tascam->phase_accum += tascam->freq_q16; frames_for_packet = tascam->phase_accum >> 16; tascam->phase_accum &= 0xFFFF; + + if (frames_for_packet > 13) + frames_for_packet = 13; + urb->iso_frame_desc[i].offset = total_bytes_for_urb; urb->iso_frame_desc[i].length = frames_for_packet * BYTES_PER_FRAME; total_bytes_for_urb += urb->iso_frame_desc[i].length; @@ -251,6 +253,7 @@ void playback_urb_complete(struct urb *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) % buffer_size; if (total_bytes_for_urb > 0) { @@ -259,9 +262,10 @@ void playback_urb_complete(struct urb *urb) if (offset_frames + frames_to_copy > buffer_size) { size_t part1 = buffer_size - offset_frames; + size_t part1_bytes = frames_to_bytes(runtime, part1); - memcpy(dst_buf, runtime->dma_area + ptr_bytes, frames_to_bytes(runtime, part1)); - memcpy(dst_buf + frames_to_bytes(runtime, part1), runtime->dma_area, total_bytes_for_urb - frames_to_bytes(runtime, part1)); + memcpy(dst_buf, runtime->dma_area + ptr_bytes, part1_bytes); + memcpy(dst_buf + part1_bytes, runtime->dma_area, total_bytes_for_urb - part1_bytes); } else { memcpy(dst_buf, runtime->dma_area + ptr_bytes, total_bytes_for_urb); } @@ -286,6 +290,7 @@ void playback_urb_complete(struct urb *urb) if (usb_submit_urb(urb, GFP_ATOMIC) < 0) { usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); + return; } } @@ -305,20 +310,26 @@ void feedback_urb_complete(struct urb *urb) struct tascam_card *tascam = urb->context; int ret, p; unsigned long flags; + bool playback_active; if (!tascam) return; if (urb->status) { - atomic_dec(&tascam->active_urbs); - return; - } - if (!atomic_read(&tascam->playback_active)) { + usb_unanchor_urb(urb); atomic_dec(&tascam->active_urbs); return; } spin_lock_irqsave(&tascam->lock, flags); + playback_active = atomic_read(&tascam->playback_active); + if (!playback_active) { + spin_unlock_irqrestore(&tascam->lock, flags); + usb_unanchor_urb(urb); + atomic_dec(&tascam->active_urbs); + return; + } + if (tascam->feedback_urb_skip_count > 0) { tascam->feedback_urb_skip_count--; spin_unlock_irqrestore(&tascam->lock, flags); @@ -327,17 +338,21 @@ void feedback_urb_complete(struct urb *urb) for (p = 0; p < urb->number_of_packets; p++) { if (urb->iso_frame_desc[p].status == 0 && urb->iso_frame_desc[p].actual_length >= 3) { - u8 *data = (u8 *)urb->transfer_buffer + urb->iso_frame_desc[p].offset; - u32 sum = data[0] + data[1] + data[2]; - u32 target_freq_q16 = ((sum * 65536) / 3) / 8; - tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT + target_freq_q16 * PLL_FILTER_NEW_WEIGHT) / PLL_FILTER_DIVISOR; + u8 *data = (u8 *)urb->transfer_buffer + urb->iso_frame_desc[p].offset; + u32 sum_frames_3ms = data[0] + data[1] + data[2]; + u32 target_freq_q16 = (sum_frames_3ms * 65536) / 24; + + tascam->freq_q16 = (tascam->freq_q16 * PLL_FILTER_OLD_WEIGHT + + target_freq_q16 * PLL_FILTER_NEW_WEIGHT + + (PLL_FILTER_DIVISOR >> 1)) / PLL_FILTER_DIVISOR; + tascam->feedback_synced = true; } } spin_unlock_irqrestore(&tascam->lock, flags); -resubmit: + resubmit: usb_anchor_urb(urb, &tascam->feedback_anchor); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) {