more fixes & formatting

This commit is contained in:
Šerif Rami 2025-12-01 16:13:59 +01:00
parent 2eba5f83c4
commit d199e9ccaf
5 changed files with 93 additions and 68 deletions

View File

@ -226,9 +226,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
int err; int err;
int idx; int idx;
char *handshake_buf __free(kfree) = NULL;
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) if (intf->cur_altsetting->desc.bInterfaceNumber == 1)
return 0; return 0;
@ -242,25 +239,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
return -ENOENT; return -ENOENT;
} }
handshake_buf = kmalloc(1, GFP_KERNEL);
if (!handshake_buf) {
atomic_dec(&dev_idx);
return -ENOMEM;
}
err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
VENDOR_REQ_MODE_CONTROL, RT_D2H_VENDOR_DEV,
MODE_VAL_HANDSHAKE_READ, 0x0000, handshake_buf, 1,
USB_CTRL_TIMEOUT_MS);
if (err < 0) {
dev_err(&dev->dev, "Handshake failed: %d\n", err);
atomic_dec(&dev_idx);
return err;
}
usb_set_interface(dev, 0, 1);
usb_set_interface(dev, 1, 1);
err = snd_card_new(&dev->dev, index[idx], id[idx], THIS_MODULE, err = snd_card_new(&dev->dev, index[idx], id[idx], THIS_MODULE,
sizeof(struct tascam_card), &card); sizeof(struct tascam_card), &card);
if (err < 0) { if (err < 0) {
@ -312,6 +290,33 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
if (err < 0) if (err < 0)
goto free_card; goto free_card;
tascam->scratch_buf = devm_kzalloc(&dev->dev, 4, GFP_KERNEL);
if (!tascam->scratch_buf) {
err = -ENOMEM;
goto free_card;
}
err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
VENDOR_REQ_MODE_CONTROL, RT_D2H_VENDOR_DEV,
MODE_VAL_HANDSHAKE_READ, 0x0000, tascam->scratch_buf, 1,
USB_CTRL_TIMEOUT_MS);
if (err < 0) {
dev_err(&dev->dev, "Handshake failed: %d\n", err);
goto free_card;
}
err = usb_set_interface(dev, 0, 1);
if (err < 0) {
dev_err(&dev->dev, "Failed to set interface 0: %d\n", err);
goto free_card;
}
err = usb_set_interface(dev, 1, 1);
if (err < 0) {
dev_err(&dev->dev, "Failed to set interface 1: %d\n", err);
goto free_card;
}
if (us144mkii_configure_device_for_rate(tascam, 48000) < 0) if (us144mkii_configure_device_for_rate(tascam, 48000) < 0)
dev_warn(&dev->dev, "Failed to initialize device at 48khz\n"); dev_warn(&dev->dev, "Failed to initialize device at 48khz\n");
else else

View File

@ -64,12 +64,12 @@ enum tascam_register {
#define REG_VAL_ENABLE 0x0101 #define REG_VAL_ENABLE 0x0101
#define NUM_PLAYBACK_URBS 8 #define NUM_PLAYBACK_URBS 4
#define PLAYBACK_URB_PACKETS 2 #define PLAYBACK_URB_PACKETS 4
#define NUM_FEEDBACK_URBS 2 #define NUM_FEEDBACK_URBS 2
#define FEEDBACK_URB_PACKETS 1 #define FEEDBACK_URB_PACKETS 1
#define FEEDBACK_PACKET_SIZE 3 #define FEEDBACK_PACKET_SIZE 3
#define NUM_CAPTURE_URBS 4 #define NUM_CAPTURE_URBS 8
#define CAPTURE_PACKET_SIZE 512 #define CAPTURE_PACKET_SIZE 512
#define MIDI_PACKET_SIZE 9 #define MIDI_PACKET_SIZE 9
@ -92,6 +92,7 @@ enum tascam_register {
* @card: pointer to the ALSA sound card * @card: pointer to the ALSA sound card
* @pcm: pointer to the ALSA PCM device * @pcm: pointer to the ALSA PCM device
* @rmidi: pointer to the ALSA raw MIDI device * @rmidi: pointer to the ALSA raw MIDI device
* @scratch_buf: temporary buffer for control messages
* @playback_substream: pointer to the PCM playback substream * @playback_substream: pointer to the PCM playback substream
* @capture_substream: pointer to the PCM capture substream * @capture_substream: pointer to the PCM capture substream
* @playback_urbs: array of URBs for PCM playback * @playback_urbs: array of URBs for PCM playback
@ -136,6 +137,8 @@ struct tascam_card {
struct snd_pcm *pcm; struct snd_pcm *pcm;
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
u8 *scratch_buf;
struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream; struct snd_pcm_substream *capture_substream;

View File

@ -1,6 +1,7 @@
// 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/unaligned.h>
#include "us144mkii_pcm.h" #include "us144mkii_pcm.h"
const struct snd_pcm_hardware tascam_capture_hw = { const struct snd_pcm_hardware tascam_capture_hw = {
@ -35,6 +36,8 @@ static int tascam_capture_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->capture_active, 0);
usb_kill_anchored_urbs(&tascam->capture_anchor);
tascam->capture_substream = NULL; tascam->capture_substream = NULL;
return 0; return 0;
} }
@ -97,7 +100,7 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock_irqrestore(&tascam->lock, flags); spin_unlock_irqrestore(&tascam->lock, flags);
if (stop) { if (stop) {
/* Ensure capture_active is updated before unlinking URBs */ /* Ensure capture_active is updated before unlinking URBs. */
smp_mb(); smp_mb();
for (i = 0; i < NUM_CAPTURE_URBS; i++) { for (i = 0; i < NUM_CAPTURE_URBS; i++) {
if (tascam->capture_urbs[i]) if (tascam->capture_urbs[i])
@ -111,7 +114,7 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
if (usb_submit_urb(tascam->capture_urbs[i], GFP_ATOMIC) < 0) { if (usb_submit_urb(tascam->capture_urbs[i], GFP_ATOMIC) < 0) {
usb_unanchor_urb(tascam->capture_urbs[i]); usb_unanchor_urb(tascam->capture_urbs[i]);
atomic_set(&tascam->capture_active, 0); atomic_set(&tascam->capture_active, 0);
/* Ensure capture_active is cleared before unlinking URBs */ /* Ensure capture_active is updated before unlinking URBs due to submission error. */
smp_mb(); smp_mb();
for (int j = 0; j < i; j++) for (int j = 0; j < i; j++)
usb_unlink_urb(tascam->capture_urbs[j]); usb_unlink_urb(tascam->capture_urbs[j]);
@ -124,46 +127,44 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
return ret; return ret;
} }
static inline u8 tascam_pack_byte(const u8 *src, int bit_offset) static inline void tascam_unpack_8bytes(const u8 *src, u8 *out_bit0, u8 *out_bit1)
{ {
return (((src[0] >> bit_offset) & 1) << 7) | u64 val = get_unaligned_le64(src);
(((src[1] >> bit_offset) & 1) << 6) | u8 b0 = 0, b1 = 0;
(((src[2] >> bit_offset) & 1) << 5) | int i;
(((src[3] >> bit_offset) & 1) << 4) |
(((src[4] >> bit_offset) & 1) << 3) | for (i = 0; i < 8; i++) {
(((src[5] >> bit_offset) & 1) << 2) | b0 |= ((val >> (i * 8)) & 1) << (7 - i);
(((src[6] >> bit_offset) & 1) << 1) | b1 |= ((val >> (i * 8 + 1)) & 1) << (7 - i);
(((src[7] >> bit_offset) & 1)); }
*out_bit0 = b0;
*out_bit1 = b1;
} }
static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_decode) static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_decode)
{ {
int frame; int i;
u8 h, m, l; u8 h[4], m[4], l[4];
for (frame = 0; frame < frames_to_decode; frame++) { for (i = 0; i < frames_to_decode; i++) {
const u8 *p_src_a = src + (frame * 64); const u8 *p_src_a = src + (i * 64);
const u8 *p_src_b = src + (frame * 64) + 32; const u8 *p_src_b = src + (i * 64) + 32;
h = tascam_pack_byte(p_src_a, 0); /* Channel 1 (h0) and Channel 3 (h2) */
m = tascam_pack_byte(p_src_a + 8, 0); tascam_unpack_8bytes(p_src_a, &h[0], &h[2]);
l = tascam_pack_byte(p_src_a + 16, 0); tascam_unpack_8bytes(p_src_a + 8, &m[0], &m[2]);
*dst++ = (h << 24) | (m << 16) | (l << 8); tascam_unpack_8bytes(p_src_a + 16, &l[0], &l[2]);
h = tascam_pack_byte(p_src_b, 0); /* Channel 2 (h1) and Channel 4 (h3) */
m = tascam_pack_byte(p_src_b + 8, 0); tascam_unpack_8bytes(p_src_b, &h[1], &h[3]);
l = tascam_pack_byte(p_src_b + 16, 0); tascam_unpack_8bytes(p_src_b + 8, &m[1], &m[3]);
*dst++ = (h << 24) | (m << 16) | (l << 8); tascam_unpack_8bytes(p_src_b + 16, &l[1], &l[3]);
h = tascam_pack_byte(p_src_a, 1); *dst++ = (h[0] << 24) | (m[0] << 16) | (l[0] << 8);
m = tascam_pack_byte(p_src_a + 8, 1); *dst++ = (h[1] << 24) | (m[1] << 16) | (l[1] << 8);
l = tascam_pack_byte(p_src_a + 16, 1); *dst++ = (h[2] << 24) | (m[2] << 16) | (l[2] << 8);
*dst++ = (h << 24) | (m << 16) | (l << 8); *dst++ = (h[3] << 24) | (m[3] << 16) | (l[3] << 8);
h = tascam_pack_byte(p_src_b, 1);
m = tascam_pack_byte(p_src_b + 8, 1);
l = tascam_pack_byte(p_src_b + 16, 1);
*dst++ = (h << 24) | (m << 16) | (l << 8);
} }
} }
@ -200,18 +201,21 @@ void capture_urb_complete(struct urb *urb)
} }
substream = tascam->capture_substream; substream = tascam->capture_substream;
if (!substream) { if (!substream || !substream->runtime) {
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
return; return;
} }
runtime = substream->runtime; runtime = substream->runtime;
if (!runtime) { if (!runtime->dma_area) {
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
return; return;
} }
buffer_size = runtime->buffer_size; buffer_size = runtime->buffer_size;
period_size = runtime->period_size; period_size = runtime->period_size;
if (urb->actual_length % 64 != 0)
dev_warn_ratelimited(&tascam->dev->dev, "Unaligned capture packet size: %d\n", urb->actual_length);
frames_received = urb->actual_length / 64; frames_received = urb->actual_length / 64;
if (frames_received > 0) { if (frames_received > 0) {
@ -252,8 +256,11 @@ void capture_urb_complete(struct urb *urb)
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
} }
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) usb_anchor_urb(urb, &tascam->capture_anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
usb_unanchor_urb(urb);
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
}
} }
const struct snd_pcm_ops tascam_capture_ops = { const struct snd_pcm_ops tascam_capture_ops = {

View File

@ -40,7 +40,9 @@ static void tascam_midi_out_complete(struct urb *urb)
} }
if (submit) { if (submit) {
usb_anchor_urb(urb, &tascam->midi_anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) { if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
usb_unanchor_urb(urb);
spin_lock_irqsave(&tascam->midi_lock, flags); spin_lock_irqsave(&tascam->midi_lock, flags);
tascam->midi_out_active = false; tascam->midi_out_active = false;
spin_unlock_irqrestore(&tascam->midi_lock, flags); spin_unlock_irqrestore(&tascam->midi_lock, flags);
@ -111,6 +113,7 @@ static void tascam_midi_in_complete(struct urb *urb)
} }
} }
usb_anchor_urb(urb, &tascam->midi_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);
} }

View File

@ -35,7 +35,10 @@ 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);
cancel_work_sync(&tascam->stop_pcm_work); cancel_work_sync(&tascam->stop_pcm_work);
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;
} }
@ -130,7 +133,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock_irqrestore(&tascam->lock, flags); spin_unlock_irqrestore(&tascam->lock, flags);
if (stop) { if (stop) {
/* Ensure playback_active is updated before unlinking URBs */ /* Ensure playback_active is updated before unlinking URBs. */
smp_mb(); smp_mb();
for (i = 0; i < NUM_FEEDBACK_URBS; i++) { for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
if (tascam->feedback_urbs[i]) if (tascam->feedback_urbs[i])
@ -149,7 +152,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
usb_unanchor_urb(tascam->feedback_urbs[i]); usb_unanchor_urb(tascam->feedback_urbs[i]);
dev_err(&tascam->dev->dev, "Failed to submit feedback URB %d\n", i); dev_err(&tascam->dev->dev, "Failed to submit feedback URB %d\n", i);
atomic_set(&tascam->playback_active, 0); atomic_set(&tascam->playback_active, 0);
/* Ensure playback_active is cleared before unlinking URBs */ /* Ensure playback_active is updated before unlinking feedback URBs due to submission error. */
smp_mb(); smp_mb();
for (int j = 0; j < i; j++) for (int j = 0; j < i; j++)
usb_unlink_urb(tascam->feedback_urbs[j]); usb_unlink_urb(tascam->feedback_urbs[j]);
@ -164,7 +167,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
usb_unanchor_urb(tascam->playback_urbs[i]); usb_unanchor_urb(tascam->playback_urbs[i]);
dev_err(&tascam->dev->dev, "Failed to submit playback URB %d\n", i); dev_err(&tascam->dev->dev, "Failed to submit playback URB %d\n", i);
atomic_set(&tascam->playback_active, 0); atomic_set(&tascam->playback_active, 0);
/* Ensure playback_active is cleared before unlinking URBs */ /* Ensure playback_active is updated before unlinking playback URBs due to submission error. */
smp_mb(); smp_mb();
for (int j = 0; j < NUM_FEEDBACK_URBS; j++) for (int j = 0; j < NUM_FEEDBACK_URBS; j++)
usb_unlink_urb(tascam->feedback_urbs[j]); usb_unlink_urb(tascam->feedback_urbs[j]);
@ -217,12 +220,12 @@ void playback_urb_complete(struct urb *urb)
} }
substream = tascam->playback_substream; substream = tascam->playback_substream;
if (!substream) { if (!substream || !substream->runtime) {
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
return; return;
} }
runtime = substream->runtime; runtime = substream->runtime;
if (!runtime) { if (!runtime->dma_area) {
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
return; return;
} }
@ -278,8 +281,11 @@ void playback_urb_complete(struct urb *urb)
if (need_period_elapsed) if (need_period_elapsed)
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) usb_anchor_urb(urb, &tascam->playback_anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
usb_unanchor_urb(urb);
atomic_dec(&tascam->active_urbs); atomic_dec(&tascam->active_urbs);
}
} }
/** /**
@ -331,6 +337,7 @@ void feedback_urb_complete(struct urb *urb)
spin_unlock_irqrestore(&tascam->lock, flags); spin_unlock_irqrestore(&tascam->lock, flags);
resubmit: resubmit:
usb_anchor_urb(urb, &tascam->feedback_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) { if (ret < 0) {
usb_unanchor_urb(urb); usb_unanchor_urb(urb);