major improvements to stability and robustness

This commit is contained in:
serifpersia 2025-07-21 15:02:45 +02:00
parent e95f3a1d8e
commit e6b9599f55
1 changed files with 120 additions and 62 deletions

View File

@ -18,7 +18,7 @@ MODULE_DESCRIPTION("ALSA Driver for TASCAM US-144MKII");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
#define DRIVER_NAME "us144mkii" #define DRIVER_NAME "us144mkii"
#define DRIVER_VERSION "1.6.1" #define DRIVER_VERSION "1.7.0"
/* --- Module Parameters --- */ /* --- Module Parameters --- */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@ -124,6 +124,7 @@ struct tascam_card {
s32 *capture_decode_dst_block; s32 *capture_decode_dst_block;
s32 *capture_routing_buffer; s32 *capture_routing_buffer;
struct work_struct capture_work; struct work_struct capture_work;
struct work_struct stop_work;
/* MIDI streams */ /* MIDI streams */
struct snd_rawmidi_substream *midi_in_substream; struct snd_rawmidi_substream *midi_in_substream;
@ -159,6 +160,12 @@ struct tascam_card {
const unsigned int (*feedback_patterns)[8]; const unsigned int (*feedback_patterns)[8];
unsigned int feedback_base_value; unsigned int feedback_base_value;
unsigned int feedback_max_value; unsigned int feedback_max_value;
struct usb_anchor playback_anchor;
struct usb_anchor capture_anchor;
struct usb_anchor feedback_anchor;
struct usb_anchor midi_in_anchor;
struct usb_anchor midi_out_anchor;
}; };
static struct usb_driver tascam_alsa_driver; static struct usb_driver tascam_alsa_driver;
@ -484,9 +491,9 @@ static void tascam_free_urbs(struct tascam_card *tascam)
{ {
int i; int i;
usb_kill_anchored_urbs(&tascam->playback_anchor);
for (i = 0; i < NUM_PLAYBACK_URBS; i++) { for (i = 0; i < NUM_PLAYBACK_URBS; i++) {
if (tascam->playback_urbs[i]) { if (tascam->playback_urbs[i]) {
usb_kill_urb(tascam->playback_urbs[i]);
usb_free_coherent(tascam->dev, tascam->playback_urb_alloc_size, usb_free_coherent(tascam->dev, tascam->playback_urb_alloc_size,
tascam->playback_urbs[i]->transfer_buffer, tascam->playback_urbs[i]->transfer_buffer,
tascam->playback_urbs[i]->transfer_dma); tascam->playback_urbs[i]->transfer_dma);
@ -495,9 +502,9 @@ static void tascam_free_urbs(struct tascam_card *tascam)
} }
} }
usb_kill_anchored_urbs(&tascam->feedback_anchor);
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]) {
usb_kill_urb(tascam->feedback_urbs[i]);
usb_free_coherent(tascam->dev, tascam->feedback_urb_alloc_size, usb_free_coherent(tascam->dev, tascam->feedback_urb_alloc_size,
tascam->feedback_urbs[i]->transfer_buffer, tascam->feedback_urbs[i]->transfer_buffer,
tascam->feedback_urbs[i]->transfer_dma); tascam->feedback_urbs[i]->transfer_dma);
@ -506,9 +513,9 @@ static void tascam_free_urbs(struct tascam_card *tascam)
} }
} }
usb_kill_anchored_urbs(&tascam->capture_anchor);
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]) {
usb_kill_urb(tascam->capture_urbs[i]);
usb_free_coherent(tascam->dev, tascam->capture_urb_alloc_size, usb_free_coherent(tascam->dev, tascam->capture_urb_alloc_size,
tascam->capture_urbs[i]->transfer_buffer, tascam->capture_urbs[i]->transfer_buffer,
tascam->capture_urbs[i]->transfer_dma); tascam->capture_urbs[i]->transfer_dma);
@ -517,10 +524,9 @@ static void tascam_free_urbs(struct tascam_card *tascam)
} }
} }
/* MIDI URB and buffer freeing */ usb_kill_anchored_urbs(&tascam->midi_in_anchor);
for (i = 0; i < NUM_MIDI_IN_URBS; i++) { for (i = 0; i < NUM_MIDI_IN_URBS; i++) {
if (tascam->midi_in_urbs[i]) { if (tascam->midi_in_urbs[i]) {
usb_kill_urb(tascam->midi_in_urbs[i]);
usb_free_coherent(tascam->dev, MIDI_IN_BUF_SIZE, usb_free_coherent(tascam->dev, MIDI_IN_BUF_SIZE,
tascam->midi_in_urbs[i]->transfer_buffer, tascam->midi_in_urbs[i]->transfer_buffer,
tascam->midi_in_urbs[i]->transfer_dma); tascam->midi_in_urbs[i]->transfer_dma);
@ -529,9 +535,9 @@ static void tascam_free_urbs(struct tascam_card *tascam)
} }
} }
usb_kill_anchored_urbs(&tascam->midi_out_anchor);
for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { for (i = 0; i < NUM_MIDI_OUT_URBS; i++) {
if (tascam->midi_out_urbs[i]) { if (tascam->midi_out_urbs[i]) {
usb_kill_urb(tascam->midi_out_urbs[i]);
usb_free_coherent(tascam->dev, MIDI_OUT_BUF_SIZE, usb_free_coherent(tascam->dev, MIDI_OUT_BUF_SIZE,
tascam->midi_out_urbs[i]->transfer_buffer, tascam->midi_out_urbs[i]->transfer_buffer,
tascam->midi_out_urbs[i]->transfer_dma); tascam->midi_out_urbs[i]->transfer_dma);
@ -945,6 +951,17 @@ static int tascam_capture_prepare(struct snd_pcm_substream *substream)
return 0; return 0;
} }
static void tascam_stop_work_handler(struct work_struct *work)
{
struct tascam_card *tascam = container_of(work, struct tascam_card, stop_work);
usb_kill_anchored_urbs(&tascam->playback_anchor);
usb_kill_anchored_urbs(&tascam->feedback_anchor);
usb_kill_anchored_urbs(&tascam->capture_anchor);
atomic_set(&tascam->active_urbs, 0);
cancel_work_sync(&tascam->capture_work);
}
static int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{ {
struct tascam_card *tascam = snd_pcm_substream_chip(substream); struct tascam_card *tascam = snd_pcm_substream_chip(substream);
@ -986,21 +1003,36 @@ static int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
} }
for (i = 0; i < NUM_FEEDBACK_URBS; i++) { for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
usb_get_urb(tascam->feedback_urbs[i]);
usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor);
err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC); err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC);
if (err < 0) if (err < 0) {
usb_unanchor_urb(tascam->feedback_urbs[i]);
usb_put_urb(tascam->feedback_urbs[i]);
goto start_rollback; goto start_rollback;
}
atomic_inc(&tascam->active_urbs); atomic_inc(&tascam->active_urbs);
} }
for (i = 0; i < NUM_PLAYBACK_URBS; i++) { for (i = 0; i < NUM_PLAYBACK_URBS; i++) {
usb_get_urb(tascam->playback_urbs[i]);
usb_anchor_urb(tascam->playback_urbs[i], &tascam->playback_anchor);
err = usb_submit_urb(tascam->playback_urbs[i], GFP_ATOMIC); err = usb_submit_urb(tascam->playback_urbs[i], GFP_ATOMIC);
if (err < 0) if (err < 0) {
usb_unanchor_urb(tascam->playback_urbs[i]);
usb_put_urb(tascam->playback_urbs[i]);
goto start_rollback; goto start_rollback;
}
atomic_inc(&tascam->active_urbs); atomic_inc(&tascam->active_urbs);
} }
for (i = 0; i < NUM_CAPTURE_URBS; i++) { for (i = 0; i < NUM_CAPTURE_URBS; i++) {
usb_get_urb(tascam->capture_urbs[i]);
usb_anchor_urb(tascam->capture_urbs[i], &tascam->capture_anchor);
err = usb_submit_urb(tascam->capture_urbs[i], GFP_ATOMIC); err = usb_submit_urb(tascam->capture_urbs[i], GFP_ATOMIC);
if (err < 0) if (err < 0) {
usb_unanchor_urb(tascam->capture_urbs[i]);
usb_put_urb(tascam->capture_urbs[i]);
goto start_rollback; goto start_rollback;
}
atomic_inc(&tascam->active_urbs); atomic_inc(&tascam->active_urbs);
} }
return 0; return 0;
@ -1009,25 +1041,13 @@ start_rollback:
do_stop = true; do_stop = true;
} }
if (do_stop) { if (do_stop)
for (i = 0; i < NUM_PLAYBACK_URBS; i++) { schedule_work(&tascam->stop_work);
usb_unlink_urb(tascam->playback_urbs[i]);
atomic_dec(&tascam->active_urbs);
}
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
usb_unlink_urb(tascam->feedback_urbs[i]);
atomic_dec(&tascam->active_urbs);
}
for (i = 0; i < NUM_CAPTURE_URBS; i++) {
usb_unlink_urb(tascam->capture_urbs[i]);
atomic_dec(&tascam->active_urbs);
}
cancel_work_sync(&tascam->capture_work);
}
return err; return err;
} }
static snd_pcm_uframes_t tascam_playback_pointer(struct snd_pcm_substream *substream) static snd_pcm_uframes_t tascam_playback_pointer(struct snd_pcm_substream *substream)
{ {
struct tascam_card *tascam = snd_pcm_substream_chip(substream); struct tascam_card *tascam = snd_pcm_substream_chip(substream);
@ -1108,14 +1128,14 @@ static void playback_urb_complete(struct urb *urb)
if (urb->status) { if (urb->status) {
if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN) if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN)
dev_err_ratelimited(tascam->card->dev, "Playback URB failed: %d\n", urb->status); dev_err_ratelimited(tascam->card->dev, "Playback URB failed: %d\n", urb->status);
return; goto out;
} }
if (!tascam || !atomic_read(&tascam->playback_active)) if (!tascam || !atomic_read(&tascam->playback_active))
return; goto out;
substream = tascam->playback_substream; substream = tascam->playback_substream;
if (!substream || !substream->runtime) if (!substream || !substream->runtime)
return; goto out;
runtime = substream->runtime; runtime = substream->runtime;
spin_lock_irqsave(&tascam->lock, flags); spin_lock_irqsave(&tascam->lock, flags);
@ -1165,9 +1185,16 @@ static void playback_urb_complete(struct urb *urb)
} }
urb->dev = tascam->dev; urb->dev = tascam->dev;
usb_get_urb(urb);
usb_anchor_urb(urb, &tascam->playback_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) if (ret < 0) {
dev_err_ratelimited(tascam->card->dev, "Failed to resubmit playback URB: %d\n", ret); dev_err_ratelimited(tascam->card->dev, "Failed to resubmit playback URB: %d\n", ret);
usb_unanchor_urb(urb);
usb_put_urb(urb);
}
out:
usb_put_urb(urb);
} }
/** /**
@ -1196,14 +1223,14 @@ static void feedback_urb_complete(struct urb *urb)
if (urb->status) { if (urb->status) {
if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN) if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN)
dev_err_ratelimited(tascam->card->dev, "Feedback URB failed: %d\n", urb->status); dev_err_ratelimited(tascam->card->dev, "Feedback URB failed: %d\n", urb->status);
return; goto out;
} }
if (!tascam || !atomic_read(&tascam->playback_active)) if (!tascam || !atomic_read(&tascam->playback_active))
return; goto out;
playback_ss = tascam->playback_substream; playback_ss = tascam->playback_substream;
if (!playback_ss || !playback_ss->runtime) if (!playback_ss || !playback_ss->runtime)
return; goto out;
playback_rt = playback_ss->runtime; playback_rt = playback_ss->runtime;
capture_ss = tascam->capture_substream; capture_ss = tascam->capture_substream;
@ -1308,9 +1335,16 @@ unlock_and_continue:
snd_pcm_period_elapsed(capture_ss); snd_pcm_period_elapsed(capture_ss);
urb->dev = tascam->dev; urb->dev = tascam->dev;
usb_get_urb(urb);
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) {
dev_err_ratelimited(tascam->card->dev, "Failed to resubmit feedback URB: %d\n", ret); dev_err_ratelimited(tascam->card->dev, "Failed to resubmit feedback URB: %d\n", ret);
usb_unanchor_urb(urb);
usb_put_urb(urb);
}
out:
usb_put_urb(urb);
} }
/** /**
@ -1449,10 +1483,10 @@ static void capture_urb_complete(struct urb *urb)
if (urb->status) { if (urb->status) {
if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN) if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN)
dev_err_ratelimited(tascam->card->dev, "Capture URB failed: %d\n", urb->status); dev_err_ratelimited(tascam->card->dev, "Capture URB failed: %d\n", urb->status);
return; goto out;
} }
if (!tascam || !atomic_read(&tascam->capture_active)) if (!tascam || !atomic_read(&tascam->capture_active))
return; goto out;
if (urb->actual_length > 0) { if (urb->actual_length > 0) {
size_t i; size_t i;
@ -1470,9 +1504,16 @@ static void capture_urb_complete(struct urb *urb)
schedule_work(&tascam->capture_work); schedule_work(&tascam->capture_work);
} }
usb_get_urb(urb);
usb_anchor_urb(urb, &tascam->capture_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) if (ret < 0) {
dev_err_ratelimited(tascam->card->dev, "Failed to resubmit capture URB: %d\n", ret); dev_err_ratelimited(tascam->card->dev, "Failed to resubmit capture URB: %d\n", ret);
usb_unanchor_urb(urb);
usb_put_urb(urb);
}
out:
usb_put_urb(urb);
} }
@ -1493,11 +1534,11 @@ static void tascam_midi_in_urb_complete(struct urb *urb)
if (urb->status) { if (urb->status) {
if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN) if (urb->status != -ENOENT && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN)
dev_err_ratelimited(tascam->card->dev, "MIDI IN URB failed: status %d\n", urb->status); dev_err_ratelimited(tascam->card->dev, "MIDI IN URB failed: status %d\n", urb->status);
return; goto out;
} }
if (!tascam || !atomic_read(&tascam->midi_in_active)) if (!tascam || !atomic_read(&tascam->midi_in_active))
return; goto out;
if (tascam->midi_in_substream && urb->actual_length > 0) { if (tascam->midi_in_substream && urb->actual_length > 0) {
u8 *raw_buf = urb->transfer_buffer; u8 *raw_buf = urb->transfer_buffer;
@ -1544,9 +1585,16 @@ static void tascam_midi_in_urb_complete(struct urb *urb)
} }
} }
usb_get_urb(urb);
usb_anchor_urb(urb, &tascam->midi_in_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC); ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) if (ret < 0) {
dev_err(tascam->card->dev, "Failed to resubmit MIDI IN URB: error %d\n", ret); dev_err(tascam->card->dev, "Failed to resubmit MIDI IN URB: error %d\n", ret);
usb_unanchor_urb(urb);
usb_put_urb(urb);
}
out:
usb_put_urb(urb);
} }
static int tascam_midi_in_open(struct snd_rawmidi_substream *substream) static int tascam_midi_in_open(struct snd_rawmidi_substream *substream)
@ -1571,16 +1619,19 @@ static void tascam_midi_in_trigger(struct snd_rawmidi_substream *substream, int
if (atomic_xchg(&tascam->midi_in_active, 1) == 0) { if (atomic_xchg(&tascam->midi_in_active, 1) == 0) {
tascam->midi_in_has_pending_packet = false; tascam->midi_in_has_pending_packet = false;
for (i = 0; i < NUM_MIDI_IN_URBS; i++) { for (i = 0; i < NUM_MIDI_IN_URBS; i++) {
usb_get_urb(tascam->midi_in_urbs[i]);
usb_anchor_urb(tascam->midi_in_urbs[i], &tascam->midi_in_anchor);
err = usb_submit_urb(tascam->midi_in_urbs[i], GFP_KERNEL); err = usb_submit_urb(tascam->midi_in_urbs[i], GFP_KERNEL);
if (err < 0) if (err < 0) {
dev_err(tascam->card->dev, "Failed to submit MIDI IN URB %d: %d\n", i, err); dev_err(tascam->card->dev, "Failed to submit MIDI IN URB %d: %d\n", i, err);
usb_unanchor_urb(tascam->midi_in_urbs[i]);
usb_put_urb(tascam->midi_in_urbs[i]);
}
} }
} }
} else { } else {
if (atomic_xchg(&tascam->midi_in_active, 0) == 1) { if (atomic_xchg(&tascam->midi_in_active, 0) == 1)
for (i = 0; i < NUM_MIDI_IN_URBS; i++) usb_kill_anchored_urbs(&tascam->midi_in_anchor);
usb_kill_urb(tascam->midi_in_urbs[i]);
}
} }
} }
@ -1611,7 +1662,7 @@ static void tascam_midi_out_urb_complete(struct urb *urb)
} }
if (!tascam) if (!tascam)
return; goto out;
for (i = 0; i < NUM_MIDI_OUT_URBS; i++) { for (i = 0; i < NUM_MIDI_OUT_URBS; i++) {
if (tascam->midi_out_urbs[i] == urb) { if (tascam->midi_out_urbs[i] == urb) {
@ -1622,7 +1673,7 @@ static void tascam_midi_out_urb_complete(struct urb *urb)
if (urb_index < 0) { if (urb_index < 0) {
dev_err_ratelimited(tascam->card->dev, "Unknown MIDI OUT URB completed!\n"); dev_err_ratelimited(tascam->card->dev, "Unknown MIDI OUT URB completed!\n");
return; goto out;
} }
spin_lock_irqsave(&tascam->midi_out_lock, flags); spin_lock_irqsave(&tascam->midi_out_lock, flags);
@ -1631,6 +1682,8 @@ static void tascam_midi_out_urb_complete(struct urb *urb)
if (atomic_read(&tascam->midi_out_active)) if (atomic_read(&tascam->midi_out_active))
schedule_work(&tascam->midi_out_work); schedule_work(&tascam->midi_out_work);
out:
usb_put_urb(urb);
} }
/** /**
@ -1692,11 +1745,15 @@ start_work:
urb->transfer_buffer_length = 9; urb->transfer_buffer_length = 9;
spin_unlock_irqrestore(&tascam->midi_out_lock, flags); spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
usb_get_urb(urb);
usb_anchor_urb(urb, &tascam->midi_out_anchor);
if (usb_submit_urb(urb, GFP_KERNEL) < 0) { if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
dev_err_ratelimited(tascam->card->dev, "Failed to submit MIDI OUT URB %d\n", urb_index); dev_err_ratelimited(tascam->card->dev, "Failed to submit MIDI OUT URB %d\n", urb_index);
spin_lock_irqsave(&tascam->midi_out_lock, flags); spin_lock_irqsave(&tascam->midi_out_lock, flags);
clear_bit(urb_index, &tascam->midi_out_urbs_in_flight); clear_bit(urb_index, &tascam->midi_out_urbs_in_flight);
spin_unlock_irqrestore(&tascam->midi_out_lock, flags); spin_unlock_irqrestore(&tascam->midi_out_lock, flags);
usb_unanchor_urb(urb);
usb_put_urb(urb);
} }
/* If there's more data, try to fill another URB immediately */ /* If there's more data, try to fill another URB immediately */
@ -1727,11 +1784,9 @@ static int tascam_midi_out_close(struct snd_rawmidi_substream *substream)
static void tascam_midi_out_drain(struct snd_rawmidi_substream *substream) static void tascam_midi_out_drain(struct snd_rawmidi_substream *substream)
{ {
struct tascam_card *tascam = substream->rmidi->private_data; struct tascam_card *tascam = substream->rmidi->private_data;
int i;
cancel_work_sync(&tascam->midi_out_work); cancel_work_sync(&tascam->midi_out_work);
for (i = 0; i < NUM_MIDI_OUT_URBS; i++) usb_kill_anchored_urbs(&tascam->midi_out_anchor);
usb_kill_urb(tascam->midi_out_urbs[i]);
} }
static void tascam_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) static void tascam_midi_out_trigger(struct snd_rawmidi_substream *substream, int up)
@ -1832,18 +1887,11 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message)
cancel_work_sync(&tascam->capture_work); cancel_work_sync(&tascam->capture_work);
cancel_work_sync(&tascam->midi_out_work); cancel_work_sync(&tascam->midi_out_work);
if (atomic_read(&tascam->midi_in_active)) { usb_kill_anchored_urbs(&tascam->playback_anchor);
int i; usb_kill_anchored_urbs(&tascam->capture_anchor);
usb_kill_anchored_urbs(&tascam->feedback_anchor);
for (i = 0; i < NUM_MIDI_IN_URBS; i++) usb_kill_anchored_urbs(&tascam->midi_in_anchor);
usb_kill_urb(tascam->midi_in_urbs[i]); usb_kill_anchored_urbs(&tascam->midi_out_anchor);
}
if (atomic_read(&tascam->midi_out_active)) {
int i;
for (i = 0; i < NUM_MIDI_OUT_URBS; i++)
usb_kill_urb(tascam->midi_out_urbs[i]);
}
return 0; return 0;
} }
@ -1886,9 +1934,12 @@ static int tascam_resume(struct usb_interface *intf)
int i; int i;
for (i = 0; i < NUM_MIDI_IN_URBS; i++) { for (i = 0; i < NUM_MIDI_IN_URBS; i++) {
usb_anchor_urb(tascam->midi_in_urbs[i], &tascam->midi_in_anchor);
err = usb_submit_urb(tascam->midi_in_urbs[i], GFP_KERNEL); err = usb_submit_urb(tascam->midi_in_urbs[i], GFP_KERNEL);
if (err < 0) if (err < 0) {
dev_err(&intf->dev, "Failed to resume MIDI IN URB %d: %d\n", i, err); dev_err(&intf->dev, "Failed to resume MIDI IN URB %d: %d\n", i, err);
usb_unanchor_urb(tascam->midi_in_urbs[i]);
}
} }
} }
if (atomic_read(&tascam->midi_out_active)) if (atomic_read(&tascam->midi_out_active))
@ -1942,12 +1993,19 @@ static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *
spin_lock_init(&tascam->lock); spin_lock_init(&tascam->lock);
atomic_set(&tascam->active_urbs, 0); atomic_set(&tascam->active_urbs, 0);
INIT_WORK(&tascam->capture_work, tascam_capture_work_handler); INIT_WORK(&tascam->capture_work, tascam_capture_work_handler);
INIT_WORK(&tascam->stop_work, tascam_stop_work_handler);
tascam->line_out_source = 0; tascam->line_out_source = 0;
tascam->digital_out_source = 1; tascam->digital_out_source = 1;
tascam->capture_12_source = 0; tascam->capture_12_source = 0;
tascam->capture_34_source = 1; tascam->capture_34_source = 1;
tascam->current_rate = 0; tascam->current_rate = 0;
init_usb_anchor(&tascam->playback_anchor);
init_usb_anchor(&tascam->capture_anchor);
init_usb_anchor(&tascam->feedback_anchor);
init_usb_anchor(&tascam->midi_in_anchor);
init_usb_anchor(&tascam->midi_out_anchor);
/* MIDI initialization */ /* MIDI initialization */
atomic_set(&tascam->midi_in_active, 0); atomic_set(&tascam->midi_in_active, 0);
atomic_set(&tascam->midi_out_active, 0); atomic_set(&tascam->midi_out_active, 0);