From owner-freebsd-multimedia@FreeBSD.ORG Thu Feb 17 10:18:54 2011 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 816571065674 for ; Thu, 17 Feb 2011 10:18:54 +0000 (UTC) (envelope-from hselasky@c2i.net) Received: from swip.net (mailfe01.c2i.net [212.247.154.2]) by mx1.freebsd.org (Postfix) with ESMTP id C5C478FC27 for ; Thu, 17 Feb 2011 10:18:53 +0000 (UTC) X-Cloudmark-Score: 0.000000 [] X-Cloudmark-Analysis: v=1.1 cv=Vlw5OJcoxCC473z5moizI40ESYe+BpcMN2hU0iQoJwI= c=1 sm=1 a=46oqABt5gJ4A:10 a=CL8lFSKtTFcA:10 a=i9M/sDlu2rpZ9XS819oYzg==:17 a=ndaoGXS1AAAA:8 a=3ziMWcUK5_xYcMQ0bhMA:9 a=APSVeI_o1NQ5sB_7TB8A:7 a=l_OltHOgMSR2TluNCYralG3mKrgA:4 a=CjuIK1q_8ugA:10 a=qY83MnDu8rvUkoB5eoAA:9 a=VBO2gmYM-_pV7M2Pr-0A:7 a=B4lRkPcYGopspZAsoz1Gw6nR_BcA:4 a=TmWXExzkfR-4VbEZ:21 a=k_LAZnOC6g8uWLS9:21 a=i9M/sDlu2rpZ9XS819oYzg==:117 Received: from [188.126.198.129] (account mc467741@c2i.net HELO laptop002.hselasky.homeunix.org) by mailfe01.swip.net (CommuniGate Pro SMTP 5.2.19) with ESMTPA id 89685611 for freebsd-multimedia@freebsd.org; Thu, 17 Feb 2011 11:18:51 +0100 From: Hans Petter Selasky To: freebsd-multimedia@freebsd.org Date: Thu, 17 Feb 2011 11:18:40 +0100 User-Agent: KMail/1.13.5 (FreeBSD/8.2-PRERELEASE; KDE/4.4.5; amd64; ; ) X-Face: *nPdTl_}RuAI6^PVpA02T?$%Xa^>@hE0uyUIoiha$pC:9TVgl.Oq, NwSZ4V"|LR.+tj}g5 %V,x^qOs~mnU3]Gn; cQLv&.N>TrxmSFf+p6(30a/{)KUU!s}w\IhQBj}[g}bj0I3^glmC( :AuzV9:.hESm-x4h240C`9=w MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_AYPXNgVCRizMd8n" Message-Id: <201102171118.40721.hselasky@c2i.net> Subject: USB MIDI patch for FreeBSD 8/9 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 17 Feb 2011 10:18:54 -0000 --Boundary-00=_AYPXNgVCRizMd8n Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Dear all USB MIDI freaks using FreeBSD 8+! After some more testing I'm going to push a patch for the USB AUDIO driver that improves USB MIDI on FreeBSD. I'm sending the patch out for review so that users get a chance to try out the changes before they get committed. The patch should apply to 8.2-RELEASE aswell as 9-CURRENT. How to apply: cd /usr/src/sys/dev/sound/usb/ cat umidi_patch_001.txt | patch A short summary of what the changes are about: - Make the USB MIDI driver more OSS compliant by implementing the correct data format for the /dev/umidiX.Y character devices. Also implement some missing OSS MIDI ioctls. - Use the USB stack's builtin clear-stall feature. - Wrap some long lines. - Use memcpy() instead of bcopy(). --HPS Some demo tunes: fluidsynth + zynaddsubfx + audacity + midipp: http://www.selasky.org/hans_petter/synth_test_new.mp3 zynaddsubfx + midipp: http://www.selasky.org/hans_petter/synth_test.mp3 --HPS --Boundary-00=_AYPXNgVCRizMd8n Content-Type: text/plain; charset="us-ascii"; name="umidi_patch_001.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="umidi_patch_001.txt" === uaudio.c ================================================================== --- uaudio.c (revision 217265) +++ uaudio.c (patch umidi_patch_001.txt level 1) @@ -191,10 +191,15 @@ uint8_t iface_alt_index; }; -#define UMIDI_N_TRANSFER 4 /* units */ #define UMIDI_CABLES_MAX 16 /* units */ #define UMIDI_BULK_SIZE 1024 /* bytes */ +enum { + UMIDI_TX_TRANSFER, + UMIDI_RX_TRANSFER, + UMIDI_N_TRANSFER, +}; + struct umidi_sub_chan { struct usb_fifo_sc fifo; uint8_t *temp_cmd; @@ -224,10 +229,6 @@ uint8_t iface_index; uint8_t iface_alt_index; - uint8_t flags; -#define UMIDI_FLAG_READ_STALL 0x01 -#define UMIDI_FLAG_WRITE_STALL 0x02 - uint8_t read_open_refcount; uint8_t write_open_refcount; @@ -336,9 +337,7 @@ static usb_callback_t uaudio_chan_play_callback; static usb_callback_t uaudio_chan_record_callback; static usb_callback_t uaudio_mixer_write_cfg_callback; -static usb_callback_t umidi_read_clear_stall_callback; static usb_callback_t umidi_bulk_read_callback; -static usb_callback_t umidi_write_clear_stall_callback; static usb_callback_t umidi_bulk_write_callback; static void uaudio_chan_fill_info_sub(struct uaudio_softc *, @@ -493,7 +492,7 @@ static const struct usb_config umidi_config[UMIDI_N_TRANSFER] = { - [0] = { + [UMIDI_TX_TRANSFER] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, @@ -502,7 +501,7 @@ .callback = &umidi_bulk_write_callback, }, - [1] = { + [UMIDI_RX_TRANSFER] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, @@ -510,26 +509,6 @@ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,}, .callback = &umidi_bulk_read_callback, }, - - [2] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .bufsize = sizeof(struct usb_device_request), - .callback = &umidi_write_clear_stall_callback, - .timeout = 1000, /* 1 second */ - .interval = 50, /* 50ms */ - }, - - [3] = { - .type = UE_CONTROL, - .endpoint = 0x00, /* Control pipe */ - .direction = UE_DIR_ANY, - .bufsize = sizeof(struct usb_device_request), - .callback = &umidi_read_clear_stall_callback, - .timeout = 1000, /* 1 second */ - .interval = 50, /* 50ms */ - }, }; static devclass_t uaudio_devclass; @@ -1577,10 +1556,10 @@ uaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) { struct uaudio_mixer_node *p_mc_new = - malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); + malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); - if (p_mc_new) { - bcopy(mc, p_mc_new, sizeof(*p_mc_new)); + if (p_mc_new != NULL) { + memcpy(p_mc_new, mc, sizeof(*p_mc_new)); p_mc_new->next = sc->sc_mixer_root; sc->sc_mixer_root = p_mc_new; sc->sc_mixer_count++; @@ -3284,25 +3263,12 @@ *========================================================================*/ static void -umidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) -{ - struct umidi_chan *chan = usbd_xfer_softc(xfer); - struct usb_xfer *xfer_other = chan->xfer[1]; - - if (usbd_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - chan->flags &= ~UMIDI_FLAG_READ_STALL; - usbd_transfer_start(xfer_other); - } -} - -static void umidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct umidi_chan *chan = usbd_xfer_softc(xfer); struct umidi_sub_chan *sub; struct usb_page_cache *pc; - uint8_t buf[1]; + uint8_t buf[4]; uint8_t cmd_len; uint8_t cn; uint16_t pos; @@ -3320,60 +3286,64 @@ while (actlen >= 4) { - usbd_copy_out(pc, pos, buf, 1); - - cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; /* command length */ - cn = buf[0] >> 4; /* cable number */ + /* copy out the MIDI data */ + usbd_copy_out(pc, pos, buf, 4); + /* command length */ + cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; + /* cable number */ + cn = buf[0] >> 4; + /* + * Lookup sub-channel. The index is range + * checked below. + */ sub = &chan->sub[cn]; - if (cmd_len && (cn < chan->max_cable) && sub->read_open) { - usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc, - pos + 1, cmd_len, 1); - } else { - /* ignore the command */ + if ((cmd_len != 0) && + (cn < chan->max_cable) && + (sub->read_open != 0)) { + + /* re-pack into a 4-byte array */ + buf[0] = SEQ_MIDIPUTC; + + /* zero unused bytes */ + if (cmd_len == 1) { + buf[2] = 0; + buf[3] = 0; + } else if (cmd_len == 2) { + buf[3] = 0; + } + + /* + * Send data in 4-byte chunks to the + * application: + */ + usb_fifo_put_data_linear( + sub->fifo.fp[USB_FIFO_RX], + buf, 4, 1); } - actlen -= 4; pos += 4; } case USB_ST_SETUP: DPRINTF("start\n"); - - if (chan->flags & UMIDI_FLAG_READ_STALL) { - usbd_transfer_start(chan->xfer[3]); - return; - } +tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); - return; + break; default: DPRINTF("error=%s\n", usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ - chan->flags |= UMIDI_FLAG_READ_STALL; - usbd_transfer_start(chan->xfer[3]); + usbd_xfer_set_stall(xfer); + goto tr_setup; } - return; - + break; } } -static void -umidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) -{ - struct umidi_chan *chan = usbd_xfer_softc(xfer); - struct usb_xfer *xfer_other = chan->xfer[0]; - - if (usbd_clear_stall_callback(xfer, xfer_other)) { - DPRINTF("stall cleared\n"); - chan->flags &= ~UMIDI_FLAG_WRITE_STALL; - usbd_transfer_start(xfer_other); - } -} - /* * The following statemachine, that converts MIDI commands to * USB MIDI packets, derives from Linux's usbmidi.c, which @@ -3502,6 +3472,8 @@ sub->temp_cmd = sub->temp_1; sub->state = UMIDI_ST_SYSEX_0; return (1); + default: + break; } } return (0); @@ -3527,13 +3499,9 @@ DPRINTF("actlen=%d bytes\n", len); case USB_ST_SETUP: - +tr_setup: DPRINTF("start\n"); - if (chan->flags & UMIDI_FLAG_WRITE_STALL) { - usbd_transfer_start(chan->xfer[2]); - return; - } total_length = 0; /* reset */ start_cable = chan->curr_cable; tr_any = 0; @@ -3593,7 +3561,7 @@ usbd_xfer_set_frame_len(xfer, 0, total_length); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ @@ -3601,11 +3569,10 @@ if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ - chan->flags |= UMIDI_FLAG_WRITE_STALL; - usbd_transfer_start(chan->xfer[2]); + usbd_xfer_set_stall(xfer); + goto tr_setup; } - return; - + break; } } @@ -3635,7 +3602,7 @@ { struct umidi_chan *chan = usb_fifo_softc(fifo); - usbd_transfer_start(chan->xfer[1]); + usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); } static void @@ -3662,7 +3629,7 @@ { struct umidi_chan *chan = usb_fifo_softc(fifo); - usbd_transfer_start(chan->xfer[0]); + usbd_transfer_start(chan->xfer[UMIDI_TX_TRANSFER]); } static void @@ -3703,7 +3670,7 @@ } /* clear stall first */ mtx_lock(&chan->mtx); - chan->flags |= UMIDI_FLAG_WRITE_STALL; + usbd_xfer_set_stall(chan->xfer[UMIDI_TX_TRANSFER]); chan->write_open_refcount++; sub->write_open = 1; @@ -3730,6 +3697,50 @@ umidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, int fflags) { + struct synth_info *psi; + struct midi_info *pmi; + + switch (cmd) { + case SNDCTL_SYNTH_INFO: + psi = (struct synth_info *)data; + memset(psi, 0, sizeof(*psi)); + psi->name[0] = 'u'; + psi->name[1] = 'm'; + psi->name[2] = 'i'; + psi->name[3] = 'd'; + psi->name[4] = 'i'; + psi->synth_type = SYNTH_TYPE_MIDI; + psi->capabilities = SYNTH_CAP_INPUT; + return (0); + case SNDCTL_MIDI_INFO: + pmi = (struct midi_info *)data; + memset(pmi, 0, sizeof(*pmi)); + pmi->name[0] = 'u'; + pmi->name[1] = 'm'; + pmi->name[2] = 'i'; + pmi->name[3] = 'd'; + pmi->name[4] = 'i'; + pmi->capabilities = SYNTH_CAP_INPUT; + pmi->dev_type = 0x01; /* XXX */ + return (0); + case SNDCTL_SEQ_GETTIME: + *(int *)data = 0; + return (0); + case SNDCTL_SEQ_GETINCOUNT: + *(int *)data = 0; + return (0); + case SNDCTL_SEQ_GETOUTCOUNT: + *(int *)data = 0; + return (0); + case SNDCTL_SEQ_SYNC: + case SNDCTL_SEQ_RESET: + case SNDCTL_SEQ_PANIC: + /* FALLTHROUGH */ + case SNDCTL_SEQ_TESTMIDI: + return (0); + default: + break; + } return (ENODEV); } @@ -3769,7 +3780,8 @@ DPRINTF("setting of alternate index failed!\n"); goto detach; } - usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index); + usbd_set_parent_iface(sc->sc_udev, chan->iface_index, + sc->sc_mixer_iface_index); error = usbd_transfer_setup(uaa->device, &chan->iface_index, chan->xfer, umidi_config, UMIDI_N_TRANSFER, @@ -3799,13 +3811,15 @@ mtx_lock(&chan->mtx); /* clear stall first */ - chan->flags |= UMIDI_FLAG_READ_STALL; + usbd_xfer_set_stall(chan->xfer[UMIDI_RX_TRANSFER]); /* - * NOTE: at least one device will not work properly unless - * the BULK pipe is open all the time. + * NOTE: At least one device will not work properly unless the + * BULK IN pipe is open all the time. This might have to do + * about that the internal queues of the device overflow if we + * don't read them regularly. */ - usbd_transfer_start(chan->xfer[1]); + usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); mtx_unlock(&chan->mtx); --Boundary-00=_AYPXNgVCRizMd8n--