diff options
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/controller/dwc_otg.c | 108 | ||||
-rw-r--r-- | sys/dev/usb/quirk/usb_quirk.c | 1 | ||||
-rw-r--r-- | sys/dev/usb/template/usb_template.c | 3 | ||||
-rw-r--r-- | sys/dev/usb/template/usb_template.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/template/usb_template_midi.c | 240 | ||||
-rw-r--r-- | sys/dev/usb/usb_dev.c | 3 | ||||
-rw-r--r-- | sys/dev/usb/usb_ioctl.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/usbdevs | 1 |
8 files changed, 301 insertions, 57 deletions
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c index 50ead5c..868c7c7 100644 --- a/sys/dev/usb/controller/dwc_otg.c +++ b/sys/dev/usb/controller/dwc_otg.c @@ -180,6 +180,22 @@ dwc_otg_get_hw_ep_profile(struct usb_device *udev, *ppf = NULL; } +static void +dwc_otg_tx_fifo_reset(struct dwc_otg_softc *sc, uint32_t value) +{ + uint32_t temp; + + /* reset FIFO */ + DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL, value); + + /* wait for reset to complete */ + for (temp = 0; temp != 16; temp++) { + value = DWC_OTG_READ_4(sc, DOTG_GRSTCTL); + if (!(value & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH))) + break; + } +} + static int dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) { @@ -331,12 +347,11 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) } /* reset RX FIFO */ - DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL, - GRSTCTL_RXFFLSH); + dwc_otg_tx_fifo_reset(sc, GRSTCTL_RXFFLSH); if (mode != DWC_MODE_OTG) { /* reset all TX FIFOs */ - DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL, + dwc_otg_tx_fifo_reset(sc, GRSTCTL_TXFIFO(0x10) | GRSTCTL_TXFFLSH); } else { @@ -947,15 +962,21 @@ dwc_otg_setup_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != 0) goto not_complete; - if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != - GRXSTSRD_DPID_DATA0) { + if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) != + GRXSTSRD_STP_DATA) { + if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) != + GRXSTSRD_STP_COMPLETE || td->remainder != 0) { + /* release FIFO */ + dwc_otg_common_rx_ack(sc); + goto not_complete; + } /* release FIFO */ dwc_otg_common_rx_ack(sc); - goto not_complete; + return (0); /* complete */ } - if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) != - GRXSTSRD_STP_DATA) { + if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != + GRXSTSRD_DPID_DATA0) { /* release FIFO */ dwc_otg_common_rx_ack(sc); goto not_complete; @@ -969,14 +990,6 @@ dwc_otg_setup_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) /* get the packet byte count */ count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); - /* verify data length */ - if (count != td->remainder) { - DPRINTFN(0, "Invalid SETUP packet " - "length, %d bytes\n", count); - /* release FIFO */ - dwc_otg_common_rx_ack(sc); - goto not_complete; - } if (count != sizeof(req)) { DPRINTFN(0, "Unsupported SETUP packet " "length, %d bytes\n", count); @@ -1002,43 +1015,27 @@ dwc_otg_setup_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) } /* don't send any data by default */ - DWC_OTG_WRITE_4(sc, DOTG_DIEPTSIZ(0), - DXEPTSIZ_SET_NPKT(0) | - DXEPTSIZ_SET_NBYTES(0)); - - temp = sc->sc_in_ctl[0]; - - /* enable IN endpoint */ - DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0), - temp | DIEPCTL_EPENA); - DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0), - temp | DIEPCTL_SNAK); + DWC_OTG_WRITE_4(sc, DOTG_DIEPTSIZ(0), DIEPCTL_EPDIS); + DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(0), DOEPCTL_EPDIS); /* reset IN endpoint buffer */ - DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL, + dwc_otg_tx_fifo_reset(sc, GRSTCTL_TXFIFO(0) | GRSTCTL_TXFFLSH); /* acknowledge RX status */ dwc_otg_common_rx_ack(sc); - return (0); /* complete */ + td->did_stall = 1; not_complete: /* abort any ongoing transfer, before enabling again */ - - temp = sc->sc_out_ctl[0]; - - temp |= DOEPCTL_EPENA | - DOEPCTL_SNAK; - - /* enable OUT endpoint */ - DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(0), temp); - if (!td->did_stall) { td->did_stall = 1; DPRINTFN(5, "stalling IN and OUT direction\n"); + temp = sc->sc_out_ctl[0]; + /* set stall after enabling endpoint */ DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(0), temp | DOEPCTL_STALL); @@ -1049,13 +1046,6 @@ not_complete: DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0), temp | DIEPCTL_STALL); } - - /* setup number of buffers to receive */ - DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(0), - DXEPTSIZ_SET_MULTI(3) | - DXEPTSIZ_SET_NPKT(1) | - DXEPTSIZ_SET_NBYTES(sizeof(req))); - return (1); /* not complete */ } @@ -1499,7 +1489,9 @@ dwc_otg_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) /* check for SETUP packet */ if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) == - GRXSTSRD_STP_DATA) { + GRXSTSRD_STP_DATA || + (sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) == + GRXSTSRD_STP_COMPLETE) { if (td->remainder == 0) { /* * We are actually complete and have @@ -1584,15 +1576,10 @@ dwc_otg_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td) not_complete: - temp = sc->sc_out_ctl[td->ep_no]; - - temp |= DOEPCTL_EPENA | DOEPCTL_CNAK; - - DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(td->ep_no), temp); - /* enable SETUP and transfer complete interrupt */ if (td->ep_no == 0) { DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(0), + DXEPTSIZ_SET_MULTI(3) | DXEPTSIZ_SET_NPKT(1) | DXEPTSIZ_SET_NBYTES(td->max_packet_size)); } else { @@ -1601,8 +1588,12 @@ not_complete: DXEPTSIZ_SET_MULTI(1) | DXEPTSIZ_SET_NPKT(4) | DXEPTSIZ_SET_NBYTES(4 * - ((td->max_packet_size + 3) & ~3))); + ((td->max_packet_size + 3) & ~3))); } + temp = sc->sc_out_ctl[td->ep_no]; + DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(td->ep_no), temp | + DOEPCTL_EPENA | DOEPCTL_CNAK); + return (1); /* not complete */ } @@ -2004,7 +1995,9 @@ repeat: (GRXSTSRD_CHNUM_GET(temp) == 0)) { if ((temp & GRXSTSRD_PKTSTS_MASK) != - GRXSTSRD_STP_DATA) { + GRXSTSRD_STP_DATA && + (temp & GRXSTSRD_PKTSTS_MASK) != + GRXSTSRD_STP_COMPLETE) { /* dump data - wrong direction */ dwc_otg_common_rx_ack(sc); @@ -2209,7 +2202,9 @@ not_complete: (GRXSTSRD_CHNUM_GET(temp) == 0)) { if ((temp & GRXSTSRD_PKTSTS_MASK) == - GRXSTSRD_STP_DATA) { + GRXSTSRD_STP_DATA || + (temp & GRXSTSRD_PKTSTS_MASK) == + GRXSTSRD_STP_COMPLETE) { DPRINTFN(5, "faking complete\n"); /* * Race condition: We are complete! @@ -2634,6 +2629,7 @@ repeat: /* non-data messages we simply skip */ if (temp != GRXSTSRD_STP_DATA && + temp != GRXSTSRD_STP_COMPLETE && temp != GRXSTSRD_OUT_DATA) { dwc_otg_common_rx_ack(sc); goto repeat; @@ -3669,7 +3665,7 @@ dwc_otg_clear_stall_sub_locked(struct dwc_otg_softc *sc, uint32_t mps, /* we only reset the transmit FIFO */ if (ep_dir) { - DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL, + dwc_otg_tx_fifo_reset(sc, GRSTCTL_TXFIFO(ep_no) | GRSTCTL_TXFFLSH); diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index 3cfaef0..c756b24 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -94,6 +94,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(SILICONPORTALS, YAPPHONE, 0x100, 0x100, UQ_AU_INP_ASYNC), USB_QUIRK(LOGITECH, UN53B, 0x0000, 0xffff, UQ_NO_STRINGS), USB_QUIRK(REALTEK, RTL8196EU, 0x0000, 0xffff, UQ_CFG_INDEX_1), + USB_QUIRK(REALTEK, RTL8153, 0x0000, 0xffff, UQ_CFG_INDEX_1), USB_QUIRK(ELSA, MODEM1, 0x0000, 0xffff, UQ_CFG_INDEX_1), USB_QUIRK(PLANEX2, MZKUE150N, 0x0000, 0xffff, UQ_CFG_INDEX_1), /* Quirks for printer devices */ diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c index 49bd373..140c0b9 100644 --- a/sys/dev/usb/template/usb_template.c +++ b/sys/dev/usb/template/usb_template.c @@ -1374,6 +1374,9 @@ usb_temp_setup_by_index(struct usb_device *udev, uint16_t index) case USB_TEMP_SERIALNET: err = usb_temp_setup(udev, &usb_template_serialnet); break; + case USB_TEMP_MIDI: + err = usb_temp_setup(udev, &usb_template_midi); + break; default: return (USB_ERR_INVAL); } diff --git a/sys/dev/usb/template/usb_template.h b/sys/dev/usb/template/usb_template.h index 484608d..1b320c6 100644 --- a/sys/dev/usb/template/usb_template.h +++ b/sys/dev/usb/template/usb_template.h @@ -107,6 +107,7 @@ extern const struct usb_temp_device_desc usb_template_msc; extern const struct usb_temp_device_desc usb_template_mtp; extern const struct usb_temp_device_desc usb_template_phone; extern const struct usb_temp_device_desc usb_template_serialnet; +extern const struct usb_temp_device_desc usb_template_midi; usb_error_t usb_temp_setup(struct usb_device *, const struct usb_temp_device_desc *); diff --git a/sys/dev/usb/template/usb_template_midi.c b/sys/dev/usb/template/usb_template_midi.c new file mode 100644 index 0000000..9be1b9e --- /dev/null +++ b/sys/dev/usb/template/usb_template_midi.c @@ -0,0 +1,240 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2015 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file contains the USB template for an USB MIDI Device. + */ + +#ifdef USB_GLOBAL_INCLUDE_FILE +#include USB_GLOBAL_INCLUDE_FILE +#else +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_core.h> + +#include <dev/usb/template/usb_template.h> +#endif /* USB_GLOBAL_INCLUDE_FILE */ + +enum { + INDEX_MIDI_LANG, + INDEX_MIDI_IF, + INDEX_MIDI_PRODUCT, + INDEX_MIDI_MAX, +}; + +#define STRING_MIDI_PRODUCT \ + "M\0I\0D\0I\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" + +#define STRING_MIDI_IF \ + "M\0I\0D\0I\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" + +/* make the real string descriptors */ + +USB_MAKE_STRING_DESC(STRING_MIDI_IF, string_midi_if); +USB_MAKE_STRING_DESC(STRING_MIDI_PRODUCT, string_midi_product); + +/* prototypes */ + +static const uint8_t midi_desc_raw_0[9] = { + 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01 +}; + +static const void *midi_descs_0[] = { + &midi_desc_raw_0, + NULL +}; + +static const struct usb_temp_interface_desc midi_iface_0 = { + .ppEndpoints = NULL, /* no endpoints */ + .ppRawDesc = midi_descs_0, + .bInterfaceClass = 1, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .iInterface = INDEX_MIDI_IF, +}; + +static const struct usb_temp_packet_size midi_mps = { + .mps[USB_SPEED_LOW] = 8, + .mps[USB_SPEED_FULL] = 64, + .mps[USB_SPEED_HIGH] = 512, +}; + +static const uint8_t midi_desc_raw_7[5] = { + 0x05, 0x25, 0x01, 0x01, 0x01 +}; + +static const void *midi_descs_2[] = { + &midi_desc_raw_7, + NULL +}; + +static const struct usb_temp_endpoint_desc midi_bulk_out_ep = { + .ppRawDesc = midi_descs_2, + .pPacketSize = &midi_mps, + .bEndpointAddress = UE_DIR_OUT, + .bmAttributes = UE_BULK, +}; + +static const uint8_t midi_desc_raw_6[5] = { + 0x05, 0x25, 0x01, 0x01, 0x03, +}; + +static const void *midi_descs_3[] = { + &midi_desc_raw_6, + NULL +}; + +static const struct usb_temp_endpoint_desc midi_bulk_in_ep = { + .ppRawDesc = midi_descs_3, + .pPacketSize = &midi_mps, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_BULK, +}; + +static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = { + &midi_bulk_out_ep, + &midi_bulk_in_ep, + NULL, +}; + +static const uint8_t midi_desc_raw_1[7] = { + 0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00 +}; + +static const uint8_t midi_desc_raw_2[6] = { + 0x06, 0x24, 0x02, 0x01, 0x01, 0x00 +}; + +static const uint8_t midi_desc_raw_3[6] = { + 0x06, 0x24, 0x02, 0x02, 0x02, 0x00 +}; + +static const uint8_t midi_desc_raw_4[9] = { + 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00 +}; + +static const uint8_t midi_desc_raw_5[9] = { + 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00 +}; + +static const void *midi_descs_1[] = { + &midi_desc_raw_1, + &midi_desc_raw_2, + &midi_desc_raw_3, + &midi_desc_raw_4, + &midi_desc_raw_5, + NULL +}; + +static const struct usb_temp_interface_desc midi_iface_1 = { + .ppRawDesc = midi_descs_1, + .ppEndpoints = midi_iface_1_ep, + .bInterfaceClass = 0x01, /* MIDI */ + .bInterfaceSubClass = 3, /* MIDI streaming */ + .bInterfaceProtocol = 0, + .iInterface = INDEX_MIDI_IF, +}; + +static const struct usb_temp_interface_desc *midi_interfaces[] = { + &midi_iface_0, + &midi_iface_1, + NULL, +}; + +static const struct usb_temp_config_desc midi_config_desc = { + .ppIfaceDesc = midi_interfaces, + .bmAttributes = UC_BUS_POWERED, + .bMaxPower = 25, /* 50 mA */ + .iConfiguration = INDEX_MIDI_PRODUCT, +}; + +static const struct usb_temp_config_desc *midi_configs[] = { + &midi_config_desc, + NULL, +}; + +static usb_temp_get_string_desc_t midi_get_string_desc; + +const struct usb_temp_device_desc usb_template_midi = { + .getStringDesc = &midi_get_string_desc, + .ppConfigDesc = midi_configs, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x00BB, + .bcdDevice = 0x0100, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .iManufacturer = 0, + .iProduct = INDEX_MIDI_PRODUCT, + .iSerialNumber = 0, +}; + +/*------------------------------------------------------------------------* + * midi_get_string_desc + * + * Return values: + * NULL: Failure. No such string. + * Else: Success. Pointer to string descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +midi_get_string_desc(uint16_t lang_id, uint8_t string_index) +{ + static const void *ptr[INDEX_MIDI_MAX] = { + [INDEX_MIDI_LANG] = &usb_string_lang_en, + [INDEX_MIDI_IF] = &string_midi_if, + [INDEX_MIDI_PRODUCT] = &string_midi_product, + }; + + if (string_index == 0) { + return (&usb_string_lang_en); + } + if (lang_id != 0x0409) { + return (NULL); + } + if (string_index < INDEX_MIDI_MAX) { + return (ptr[string_index]); + } + return (NULL); +} diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 1076a9f..c48bfc9 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -830,7 +830,8 @@ usb_fifo_close(struct usb_fifo *f, int fflags) (!f->flag_iserror)) { /* wait until all data has been written */ f->flag_sleeping = 1; - err = cv_wait_sig(&f->cv_io, f->priv_mtx); + err = cv_timedwait_sig(&f->cv_io, f->priv_mtx, + USB_MS_TO_TICKS(USB_DEFAULT_TIMEOUT)); if (err) { DPRINTF("signal received\n"); break; diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h index 539f881..683f3e6 100644 --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -66,6 +66,7 @@ enum { USB_TEMP_MOUSE, /* USB Mouse */ USB_TEMP_PHONE, /* USB Phone */ USB_TEMP_SERIALNET, /* USB CDC Ethernet and Modem */ + USB_TEMP_MIDI, /* USB MIDI */ USB_TEMP_MAX, }; diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index f8ba5b5..b19f766 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -3748,6 +3748,7 @@ product REALTEK USB20CRW 0x0158 USB20CRW Card Reader product REALTEK RTL8188ETV 0x0179 RTL8188ETV product REALTEK RTL8188CTV 0x018a RTL8188CTV product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet +product REALTEK RTL8153 0x8153 RTL8153 USB Ethernet product REALTEK RTL8188CE_0 0x8170 RTL8188CE product REALTEK RTL8171 0x8171 RTL8171 product REALTEK RTL8172 0x8172 RTL8172 |