summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2011-07-02 20:26:37 +0000
committerhselasky <hselasky@FreeBSD.org>2011-07-02 20:26:37 +0000
commite164f9285fa22e26ad10648143a2e7a433e7ce5d (patch)
tree0599c783f93006abf4b9e54f9d99d52f1a0498ef /sys/dev
parentaf3435e1973d3e85d91d1400e0d9e1c9865a96ab (diff)
downloadFreeBSD-src-e164f9285fa22e26ad10648143a2e7a433e7ce5d.zip
FreeBSD-src-e164f9285fa22e26ad10648143a2e7a433e7ce5d.tar.gz
Fix problem about USB MIDI TX data format, that some devices only accept
a maximum of 4 bytes (one command) per short terminated USB transfer. Optimise the TX case by sending multiple USB frames. MFC after: 1 week
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/usb/uaudio.c53
1 files changed, 30 insertions, 23 deletions
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index f40ada7..59fc4f8 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -192,7 +192,8 @@ struct uaudio_chan {
};
#define UMIDI_CABLES_MAX 16 /* units */
-#define UMIDI_BULK_SIZE 1024 /* bytes */
+#define UMIDI_TX_FRAMES 64 /* units */
+#define UMIDI_TX_BUFFER (UMIDI_TX_FRAMES * 4) /* bytes */
enum {
UMIDI_TX_TRANSFER,
@@ -497,8 +498,8 @@ static const struct usb_config
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = UMIDI_BULK_SIZE,
- .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .bufsize = UMIDI_TX_BUFFER,
+ .frames = UMIDI_TX_FRAMES,
.callback = &umidi_bulk_write_callback,
},
@@ -507,7 +508,7 @@ static const struct usb_config
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = 4, /* bytes */
- .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
+ .flags = {.short_xfer_ok = 1,.proxy_buffer = 1,},
.callback = &umidi_bulk_read_callback,
},
};
@@ -3541,7 +3542,7 @@ umidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
struct umidi_sub_chan *sub;
struct usb_page_cache *pc;
uint32_t actlen;
- uint16_t total_length;
+ uint16_t nframes;
uint8_t buf;
uint8_t start_cable;
uint8_t tr_any;
@@ -3549,6 +3550,10 @@ umidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+ /*
+ * NOTE: Some MIDI devices only accept 4 bytes of data per
+ * short terminated USB transfer.
+ */
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
DPRINTF("actlen=%d bytes\n", len);
@@ -3557,10 +3562,9 @@ umidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
tr_setup:
DPRINTF("start\n");
- total_length = 0; /* reset */
+ nframes = 0; /* reset */
start_cable = chan->curr_cable;
tr_any = 0;
- pc = usbd_xfer_get_frame(xfer, 0);
while (1) {
@@ -3569,51 +3573,54 @@ tr_setup:
sub = &chan->sub[chan->curr_cable];
if (sub->write_open) {
- usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX],
- pc, total_length, 1, &actlen, 0);
+ usb_fifo_get_data_linear(sub->fifo.fp[USB_FIFO_TX],
+ &buf, 1, &actlen, 0);
} else {
actlen = 0;
}
if (actlen) {
- usbd_copy_out(pc, total_length, &buf, 1);
tr_any = 1;
- DPRINTF("byte=0x%02x\n", buf);
+ DPRINTF("byte=0x%02x from FIFO %u\n", buf,
+ (unsigned int)chan->curr_cable);
if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) {
- DPRINTF("sub= %02x %02x %02x %02x\n",
+ DPRINTF("sub=0x%02x 0x%02x 0x%02x 0x%02x\n",
sub->temp_cmd[0], sub->temp_cmd[1],
sub->temp_cmd[2], sub->temp_cmd[3]);
- usbd_copy_in(pc, total_length,
- sub->temp_cmd, 4);
+ usbd_xfer_set_frame_offset(xfer, 4 * nframes, nframes);
+ usbd_xfer_set_frame_len(xfer, nframes, 4);
- total_length += 4;
+ pc = usbd_xfer_get_frame(xfer, nframes);
- if (total_length >= UMIDI_BULK_SIZE) {
+ usbd_copy_in(pc, 0, sub->temp_cmd, 4);
+
+ nframes++;
+ if (nframes >= UMIDI_TX_FRAMES)
break;
- }
} else {
continue;
}
}
+
chan->curr_cable++;
- if (chan->curr_cable >= chan->max_cable) {
+ if (chan->curr_cable >= chan->max_cable)
chan->curr_cable = 0;
- }
+
if (chan->curr_cable == start_cable) {
- if (tr_any == 0) {
+ if (tr_any == 0)
break;
- }
tr_any = 0;
}
}
- if (total_length) {
- usbd_xfer_set_frame_len(xfer, 0, total_length);
+ if (nframes > 0) {
+ DPRINTF("Transferring %d frames\n", (int)nframes);
+ usbd_xfer_set_frames(xfer, nframes);
usbd_transfer_submit(xfer);
}
break;
OpenPOWER on IntegriCloud