diff --git a/build_and_install.sh b/build_and_install.sh new file mode 100755 index 0000000..8eea0ff --- /dev/null +++ b/build_and_install.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +echo "--- Cleaning build directory ---" +make clean + +echo "--- Compiling the driver ---" +make + +echo "--- Installing the driver ---" +SUDO_CMD="sudo" +KERNEL_MODULE_DIR="/lib/modules/$(uname -r)/extra" + +echo "Creating directory if it doesn't exist: $KERNEL_MODULE_DIR" +$SUDO_CMD mkdir -p "$KERNEL_MODULE_DIR" + +echo "Copying snd-usb-us144mkii.ko to $KERNEL_MODULE_DIR" +$SUDO_CMD cp snd-usb-us144mkii.ko "$KERNEL_MODULE_DIR" + +echo "--- Updating module dependencies ---" +$SUDO_CMD depmod -a + +echo "--- Reloading the driver ---" +echo "Unloading old driver (if present)..." +$SUDO_CMD rmmod snd_usb_us144mkii -f || true + +echo "Loading new driver..." +$SUDO_CMD modprobe snd-usb-us144mkii + +echo "--- Driver build and installation complete! ---" \ No newline at end of file diff --git a/us144mkii.c b/us144mkii.c index cfeb4b9..b86cad8 100644 --- a/us144mkii.c +++ b/us144mkii.c @@ -286,7 +286,6 @@ void tascam_stop_work_handler(struct work_struct *work) { 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); } /** @@ -508,6 +507,7 @@ static int tascam_probe(struct usb_interface *intf, } tascam = card->private_data; + card->private_free = tascam_card_private_free; tascam->dev = usb_get_dev(dev); tascam->card = card; tascam->iface0 = intf; @@ -525,10 +525,10 @@ static int tascam_probe(struct usb_interface *intf, INIT_WORK(&tascam->stop_work, tascam_stop_work_handler); - if (kfifo_alloc(&tascam->midi_in_fifo, MIDI_IN_FIFO_SIZE, GFP_KERNEL)) - goto free_card; - - card->private_free = tascam_card_private_free; + if (kfifo_alloc(&tascam->midi_in_fifo, MIDI_IN_FIFO_SIZE, GFP_KERNEL)) { + snd_card_free(card); + return -ENOMEM; + } strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); if (dev->descriptor.idProduct == USB_PID_TASCAM_US144) { @@ -599,15 +599,20 @@ static void tascam_disconnect(struct usb_interface *intf) { if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { device_remove_file(&tascam->dev->dev, &dev_attr_driver_version); - device_remove_file(&intf->dev, &dev_attr_driver_version); + + /* Ensure all deferred work is complete before freeing resources */ + snd_card_disconnect(tascam->card); + cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->capture_work); + cancel_work_sync(&tascam->midi_in_work); + cancel_work_sync(&tascam->midi_out_work); + usb_kill_anchored_urbs(&tascam->playback_anchor); usb_kill_anchored_urbs(&tascam->capture_anchor); usb_kill_anchored_urbs(&tascam->feedback_anchor); usb_kill_anchored_urbs(&tascam->midi_in_anchor); usb_kill_anchored_urbs(&tascam->midi_out_anchor); timer_delete_sync(&tascam->error_timer); - snd_card_disconnect(tascam->card); - tascam_free_urbs(tascam); snd_card_free(tascam->card); dev_idx--; } diff --git a/us144mkii.h b/us144mkii.h index 5f07b73..980ed85 100644 --- a/us144mkii.h +++ b/us144mkii.h @@ -15,7 +15,7 @@ #include #define DRIVER_NAME "us144mkii" -#define DRIVER_VERSION "1.7.5" +#define DRIVER_VERSION "1.7.6" /* --- USB Device Identification --- */ #define USB_VID_TASCAM 0x0644 diff --git a/us144mkii_capture.c b/us144mkii_capture.c index 30a5e58..c28b573 100644 --- a/us144mkii_capture.c +++ b/us144mkii_capture.c @@ -82,6 +82,9 @@ tascam_capture_pointer(struct snd_pcm_substream *substream) { pos = tascam->capture_frames_processed; spin_unlock_irqrestore(&tascam->lock, flags); + if (runtime->buffer_size == 0) + return 0; + u64 remainder = do_div(pos, runtime->buffer_size); return runtime ? remainder : 0; } @@ -261,16 +264,21 @@ void capture_urb_complete(struct urb *urb) { goto out; if (urb->actual_length > 0) { - size_t i; size_t write_ptr; + size_t bytes_to_end; spin_lock_irqsave(&tascam->lock, flags); write_ptr = tascam->capture_ring_buffer_write_ptr; - for (i = 0; i < urb->actual_length; i++) { - tascam->capture_ring_buffer[write_ptr] = ((u8 *)urb->transfer_buffer)[i]; - write_ptr = (write_ptr + 1) % CAPTURE_RING_BUFFER_SIZE; + bytes_to_end = CAPTURE_RING_BUFFER_SIZE - write_ptr; + + if (urb->actual_length > bytes_to_end) { + memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer, bytes_to_end); + memcpy(tascam->capture_ring_buffer, urb->transfer_buffer + bytes_to_end, urb->actual_length - bytes_to_end); + } else { + memcpy(tascam->capture_ring_buffer + write_ptr, urb->transfer_buffer, urb->actual_length); } - tascam->capture_ring_buffer_write_ptr = write_ptr; + + tascam->capture_ring_buffer_write_ptr = (write_ptr + urb->actual_length) % CAPTURE_RING_BUFFER_SIZE; spin_unlock_irqrestore(&tascam->lock, flags); schedule_work(&tascam->capture_work); diff --git a/us144mkii_midi.c b/us144mkii_midi.c index f54a8a7..6cfb5cf 100644 --- a/us144mkii_midi.c +++ b/us144mkii_midi.c @@ -11,51 +11,36 @@ * the kfifo, processes it by stripping protocol-specific padding bytes, and * passes the clean MIDI data to the ALSA rawmidi subsystem. */ -static void tascam_midi_in_work_handler(struct work_struct *work) { - struct tascam_card *tascam = - container_of(work, struct tascam_card, midi_in_work); - u8 buf[MIDI_IN_BUF_SIZE]; - unsigned int len; - int i; +static void tascam_midi_in_work_handler(struct work_struct *work) +{ + struct tascam_card *tascam = container_of(work, struct tascam_card, midi_in_work); + u8 buf[MIDI_IN_BUF_SIZE]; + u8 clean_buf[MIDI_IN_BUF_SIZE]; + unsigned int len, clean_len; - if (!tascam->midi_in_substream) - return; + if (!tascam->midi_in_substream) + return; - while (!kfifo_is_empty(&tascam->midi_in_fifo)) { - len = kfifo_out_spinlocked(&tascam->midi_in_fifo, buf, sizeof(buf), - &tascam->midi_in_lock); + while (!kfifo_is_empty(&tascam->midi_in_fifo)) { + len = kfifo_out_spinlocked(&tascam->midi_in_fifo, + buf, sizeof(buf), &tascam->midi_in_lock); - if (len == 0) - continue; + if (len == 0) + continue; - if (!tascam->midi_in_substream) - continue; + if (!tascam->midi_in_substream) + continue; - for (i = 0; i < len; ++i) { - u8 byte = buf[i]; + clean_len = 0; + for (int i = 0; i < len; ++i) { + if (buf[i] == 0xfd) continue; + if (i == (len - 1) && (buf[i] == 0x00 || buf[i] == 0xff)) continue; + clean_buf[clean_len++] = buf[i]; + } - /* Skip padding bytes */ - if (byte == 0xfd) - continue; - - if (byte == 0xf0) { /* SysEx Start */ - tascam->in_sysex = true; - } else if (byte == 0xf7) { /* SysEx End */ - tascam->in_sysex = false; - } else if (tascam->in_sysex) { - /* Inside a SysEx message */ - } else if (byte & 0x80) { /* Status byte */ - tascam->midi_running_status = byte; - } else { /* Data byte */ - if (tascam->midi_running_status != 0) - snd_rawmidi_receive(tascam->midi_in_substream, - &tascam->midi_running_status, 1); - } - - /* Submit valid MIDI bytes one by one */ - snd_rawmidi_receive(tascam->midi_in_substream, &byte, 1); - } - } + if (clean_len > 0) + snd_rawmidi_receive(tascam->midi_in_substream, clean_buf, clean_len); + } } /** @@ -75,7 +60,6 @@ void tascam_midi_in_urb_complete(struct urb *urb) { urb->status != -ESHUTDOWN && urb->status != -EPROTO) { dev_err_ratelimited(tascam->card->dev, "MIDI IN URB failed: status %d\n", urb->status); - mod_timer(&tascam->error_timer, jiffies + msecs_to_jiffies(50)); } goto out; } @@ -199,7 +183,6 @@ void tascam_midi_out_urb_complete(struct urb *urb) { urb->status != -ESHUTDOWN) { dev_err_ratelimited(tascam->card->dev, "MIDI OUT URB failed: %d\n", urb->status); - mod_timer(&tascam->error_timer, jiffies + msecs_to_jiffies(50)); } } @@ -338,6 +321,19 @@ static int tascam_midi_out_close(struct snd_rawmidi_substream *substream) { */ static void tascam_midi_out_drain(struct snd_rawmidi_substream *substream) { struct tascam_card *tascam = substream->rmidi->private_data; + bool in_flight = true; + + while (in_flight) { + in_flight = false; + for (int i = 0; i < NUM_MIDI_OUT_URBS; i++) { + if (test_bit(i, &tascam->midi_out_urbs_in_flight)) { + in_flight = true; + break; + } + } + if (in_flight) + schedule_timeout_uninterruptible(1); + } cancel_work_sync(&tascam->midi_out_work); usb_kill_anchored_urbs(&tascam->midi_out_anchor); diff --git a/us144mkii_pcm.c b/us144mkii_pcm.c index 52bbd4e..159e26c 100644 --- a/us144mkii_pcm.c +++ b/us144mkii_pcm.c @@ -16,52 +16,20 @@ */ static void fpoInitPattern(unsigned int size, unsigned int *pattern_array, unsigned int initial_value, int target_sum) { - unsigned int current_sum; - int diff; - int abs_diff; - unsigned int stride; - unsigned int i; + int diff, i; if (!size) return; - /* 1. Initialize the array with the base value. */ - current_sum = 0; - for (i = 0; i < size; ++i) { + for (i = 0; i < size; ++i) pattern_array[i] = initial_value; - } - current_sum = size * initial_value; - /* 2. Iteratively adjust until the sum is correct. */ - while (current_sum != target_sum) { - diff = target_sum - current_sum; - abs_diff = (diff > 0) ? diff : -diff; - - if (abs_diff == 0) - break; - - /* Calculate the stride to distribute the adjustments. */ - stride = size / abs_diff; - if (stride == 0) { - /* This would happen if the difference is larger than the array - * size, which indicates a problem. The original code breaks - * here. - */ - break; - } - - /* Apply the adjustments. */ - for (i = 0; i < size; i += stride) { - if (diff > 0) - pattern_array[i]++; - else - pattern_array[i]--; - } - - /* Recalculate the sum for the next iteration. */ - current_sum = 0; - for (i = 0; i < size; ++i) - current_sum += pattern_array[i]; + diff = target_sum - (size * initial_value); + for (i = 0; i < abs(diff); ++i) { + if (diff > 0) + pattern_array[i]++; + else + pattern_array[i]--; } } diff --git a/us144mkii_playback.c b/us144mkii_playback.c index 299d9ee..30b328f 100644 --- a/us144mkii_playback.c +++ b/us144mkii_playback.c @@ -122,6 +122,9 @@ tascam_playback_pointer(struct snd_pcm_substream *substream) { pos = tascam->playback_frames_consumed; spin_unlock_irqrestore(&tascam->lock, flags); + if (runtime->buffer_size == 0) + return 0; + u64 remainder = do_div(pos, runtime->buffer_size); return runtime ? remainder : 0; }