improvements
This commit is contained in:
parent
7716f17b21
commit
c379dc65c1
28
us144mkii.c
28
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;
|
||||
|
|
|
|||
19
us144mkii.h
19
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
111
us144mkii_pcm.c
111
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue