more fixes & formatting
This commit is contained in:
parent
2eba5f83c4
commit
d199e9ccaf
51
us144mkii.c
51
us144mkii.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue