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

@ -116,7 +116,7 @@ int tascam_alloc_urbs(struct tascam_card *tascam)
tascam->feedback_urbs[i] = urb;
urb->transfer_buffer = usb_alloc_coherent(tascam->dev,
tascam->feedback_urb_alloc_size,
GFP_KERNEL, &urb->transfer_dma);
GFP_KERNEL, &urb->transfer_dma);
if (!urb->transfer_buffer)
return -ENOMEM;
urb->dev = tascam->dev;
@ -226,9 +226,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
int err;
int idx;
char *handshake_buf __free(kfree) = NULL;
if (intf->cur_altsetting->desc.bInterfaceNumber == 1)
return 0;
@ -242,25 +239,6 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
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,
sizeof(struct tascam_card), &card);
if (err < 0) {
@ -312,6 +290,33 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
if (err < 0)
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)
dev_warn(&dev->dev, "Failed to initialize device at 48khz\n");
else

View File

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

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2025 Šerif Rami <ramiserifpersia@gmail.com>
#include <linux/unaligned.h>
#include "us144mkii_pcm.h"
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);
atomic_set(&tascam->capture_active, 0);
usb_kill_anchored_urbs(&tascam->capture_anchor);
tascam->capture_substream = NULL;
return 0;
}
@ -97,7 +100,7 @@ static int tascam_capture_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock_irqrestore(&tascam->lock, flags);
if (stop) {
/* Ensure capture_active is updated before unlinking URBs */
/* Ensure capture_active is updated before unlinking URBs. */
smp_mb();
for (i = 0; i < NUM_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) {
usb_unanchor_urb(tascam->capture_urbs[i]);
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();
for (int j = 0; j < i; 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;
}
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) |
(((src[1] >> bit_offset) & 1) << 6) |
(((src[2] >> bit_offset) & 1) << 5) |
(((src[3] >> bit_offset) & 1) << 4) |
(((src[4] >> bit_offset) & 1) << 3) |
(((src[5] >> bit_offset) & 1) << 2) |
(((src[6] >> bit_offset) & 1) << 1) |
(((src[7] >> bit_offset) & 1));
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 = b0;
*out_bit1 = b1;
}
static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames_to_decode)
{
int frame;
u8 h, m, l;
int i;
u8 h[4], m[4], l[4];
for (frame = 0; frame < frames_to_decode; frame++) {
const u8 *p_src_a = src + (frame * 64);
const u8 *p_src_b = src + (frame * 64) + 32;
for (i = 0; i < frames_to_decode; i++) {
const u8 *p_src_a = src + (i * 64);
const u8 *p_src_b = src + (i * 64) + 32;
h = tascam_pack_byte(p_src_a, 0);
m = tascam_pack_byte(p_src_a + 8, 0);
l = tascam_pack_byte(p_src_a + 16, 0);
*dst++ = (h << 24) | (m << 16) | (l << 8);
/* 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]);
h = tascam_pack_byte(p_src_b, 0);
m = tascam_pack_byte(p_src_b + 8, 0);
l = tascam_pack_byte(p_src_b + 16, 0);
*dst++ = (h << 24) | (m << 16) | (l << 8);
/* 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]);
h = tascam_pack_byte(p_src_a, 1);
m = tascam_pack_byte(p_src_a + 8, 1);
l = tascam_pack_byte(p_src_a + 16, 1);
*dst++ = (h << 24) | (m << 16) | (l << 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);
*dst++ = (h[0] << 24) | (m[0] << 16) | (l[0] << 8);
*dst++ = (h[1] << 24) | (m[1] << 16) | (l[1] << 8);
*dst++ = (h[2] << 24) | (m[2] << 16) | (l[2] << 8);
*dst++ = (h[3] << 24) | (m[3] << 16) | (l[3] << 8);
}
}
@ -200,18 +201,21 @@ void capture_urb_complete(struct urb *urb)
}
substream = tascam->capture_substream;
if (!substream) {
if (!substream || !substream->runtime) {
atomic_dec(&tascam->active_urbs);
return;
}
runtime = substream->runtime;
if (!runtime) {
if (!runtime->dma_area) {
atomic_dec(&tascam->active_urbs);
return;
}
buffer_size = runtime->buffer_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;
if (frames_received > 0) {
@ -252,8 +256,11 @@ void capture_urb_complete(struct urb *urb)
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);
}
}
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) {
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);
@ -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)
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);
atomic_set(&tascam->playback_active, 0);
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;
return 0;
}
@ -130,7 +133,7 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock_irqrestore(&tascam->lock, flags);
if (stop) {
/* Ensure playback_active is updated before unlinking URBs */
/* Ensure playback_active is updated before unlinking URBs. */
smp_mb();
for (i = 0; i < NUM_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]);
dev_err(&tascam->dev->dev, "Failed to submit feedback URB %d\n", i);
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();
for (int j = 0; j < i; 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]);
dev_err(&tascam->dev->dev, "Failed to submit playback URB %d\n", i);
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();
for (int j = 0; j < NUM_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;
if (!substream) {
if (!substream || !substream->runtime) {
atomic_dec(&tascam->active_urbs);
return;
}
runtime = substream->runtime;
if (!runtime) {
if (!runtime->dma_area) {
atomic_dec(&tascam->active_urbs);
return;
}
@ -278,8 +281,11 @@ void playback_urb_complete(struct urb *urb)
if (need_period_elapsed)
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);
}
}
/**
@ -331,6 +337,7 @@ void feedback_urb_complete(struct urb *urb)
spin_unlock_irqrestore(&tascam->lock, flags);
resubmit:
usb_anchor_urb(urb, &tascam->feedback_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
usb_unanchor_urb(urb);