kernel/usb4bsd: Install gadget example drivers and fix usbtest.
authorSascha Wildner <saw@online.de>
Sat, 1 Aug 2015 06:23:24 +0000 (08:23 +0200)
committerSascha Wildner <saw@online.de>
Sat, 1 Aug 2015 06:23:58 +0000 (08:23 +0200)
Taken-from: FreeBSD

21 files changed:
sys/bus/u4b/Makefile
sys/bus/u4b/gadget/Makefile [new file with mode: 0644]
sys/bus/u4b/gadget/g_audio.c [new file with mode: 0644]
sys/bus/u4b/gadget/g_audio.h [new file with mode: 0644]
sys/bus/u4b/gadget/g_audio/Makefile [copied from tools/tools/usbtest/Makefile with 81% similarity]
sys/bus/u4b/gadget/g_keyboard.c [new file with mode: 0644]
sys/bus/u4b/gadget/g_keyboard.h [new file with mode: 0644]
sys/bus/u4b/gadget/g_keyboard/Makefile [copied from tools/tools/usbtest/Makefile with 81% similarity]
sys/bus/u4b/gadget/g_modem.c [new file with mode: 0644]
sys/bus/u4b/gadget/g_modem.h [new file with mode: 0644]
sys/bus/u4b/gadget/g_modem/Makefile [copied from tools/tools/usbtest/Makefile with 81% similarity]
sys/bus/u4b/gadget/g_mouse.c [new file with mode: 0644]
sys/bus/u4b/gadget/g_mouse.h [new file with mode: 0644]
sys/bus/u4b/gadget/g_mouse/Makefile [copied from tools/tools/usbtest/Makefile with 81% similarity]
tools/tools/usbtest/Makefile
tools/tools/usbtest/usb_control_ep_test.c
tools/tools/usbtest/usb_modem_test.c
tools/tools/usbtest/usb_msc_test.c
tools/tools/usbtest/usb_msc_test.h
tools/tools/usbtest/usbtest.c
tools/tools/usbtest/usbtest.h

index 7245e79..52186e6 100644 (file)
@@ -1,4 +1,5 @@
-SUBDIR=        usb audio controller input misc net quirk serial storage template wlan
+SUBDIR=        usb audio controller gadget input misc \
+       net quirk serial storage template wlan
 
 # empty to allow concurrent building
 #
diff --git a/sys/bus/u4b/gadget/Makefile b/sys/bus/u4b/gadget/Makefile
new file mode 100644 (file)
index 0000000..2d3d54a
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIR=        g_audio g_keyboard g_modem g_mouse
+
+.include <bsd.subdir.mk>
diff --git a/sys/bus/u4b/gadget/g_audio.c b/sys/bus/u4b/gadget/g_audio.c
new file mode 100644 (file)
index 0000000..7935143
--- /dev/null
@@ -0,0 +1,620 @@
+/*-
+ * Copyright (c) 2010 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.
+ *
+ * $FreeBSD: head/sys/dev/usb/gadget/g_audio.c 269664 2014-08-07 12:47:25Z hselasky $
+ */
+
+/*
+ * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
+ *                 http://www.usb.org/developers/devclass_docs/frmts10.pdf
+ *                 http://www.usb.org/developers/devclass_docs/termt10.pdf
+ */
+
+#include <sys/stdint.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usb_cdc.h>
+#include <bus/u4b/usbdi.h>
+#include <bus/u4b/usbdi_util.h>
+#include <bus/u4b/usbhid.h>
+#include "usb_if.h"
+
+#define        USB_DEBUG_VAR g_audio_debug
+#include <bus/u4b/usb_debug.h>
+
+#include <bus/u4b/gadget/g_audio.h>
+
+enum {
+       G_AUDIO_ISOC0_RD,
+       G_AUDIO_ISOC1_RD,
+       G_AUDIO_ISOC0_WR,
+       G_AUDIO_ISOC1_WR,
+       G_AUDIO_N_TRANSFER,
+};
+
+struct g_audio_softc {
+       struct lock sc_lock;
+       struct usb_callout sc_callout;
+       struct usb_callout sc_watchdog;
+       struct usb_xfer *sc_xfer[G_AUDIO_N_TRANSFER];
+
+       int     sc_mode;
+       int     sc_pattern_len;
+       int     sc_throughput;
+       int     sc_tx_interval;
+       int     sc_state;
+       int     sc_noise_rem;
+
+       int8_t  sc_pattern[G_AUDIO_MAX_STRLEN];
+
+       uint16_t sc_data_len[2][G_AUDIO_FRAMES];
+
+       int16_t sc_data_buf[2][G_AUDIO_BUFSIZE / 2];
+
+       uint8_t sc_volume_setting[32];
+       uint8_t sc_volume_limit[32];
+       uint8_t sc_sample_rate[32];
+};
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, g_audio, CTLFLAG_RW, 0, "USB audio gadget");
+
+#ifdef USB_DEBUG
+static int g_audio_debug = 0;
+
+SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, debug, CTLFLAG_RW,
+    &g_audio_debug, 0, "Debug level");
+#endif
+
+static int g_audio_mode = 0;
+
+SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, mode, CTLFLAG_RW,
+    &g_audio_mode, 0, "Mode selection");
+
+static int g_audio_pattern_interval = 1000;
+
+SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, pattern_interval, CTLFLAG_RW,
+    &g_audio_pattern_interval, 0, "Pattern interval in milliseconds");
+
+static char g_audio_pattern_data[G_AUDIO_MAX_STRLEN];
+
+SYSCTL_STRING(_hw_usb_g_audio, OID_AUTO, pattern, CTLFLAG_RW,
+    &g_audio_pattern_data, sizeof(g_audio_pattern_data), "Data pattern");
+
+static int g_audio_throughput;
+
+SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, throughput, CTLFLAG_RD,
+    &g_audio_throughput, sizeof(g_audio_throughput), "Throughput in bytes per second");
+
+static device_probe_t g_audio_probe;
+static device_attach_t g_audio_attach;
+static device_detach_t g_audio_detach;
+static usb_handle_request_t g_audio_handle_request;
+
+static usb_callback_t g_audio_isoc_read_callback;
+static usb_callback_t g_audio_isoc_write_callback;
+
+static devclass_t g_audio_devclass;
+
+static void g_audio_watchdog(void *arg);
+static void g_audio_timeout(void *arg);
+
+static device_method_t g_audio_methods[] = {
+       /* USB interface */
+       DEVMETHOD(usb_handle_request, g_audio_handle_request),
+
+       /* Device interface */
+       DEVMETHOD(device_probe, g_audio_probe),
+       DEVMETHOD(device_attach, g_audio_attach),
+       DEVMETHOD(device_detach, g_audio_detach),
+
+       DEVMETHOD_END
+};
+
+static driver_t g_audio_driver = {
+       .name = "g_audio",
+       .methods = g_audio_methods,
+       .size = sizeof(struct g_audio_softc),
+};
+
+DRIVER_MODULE(g_audio, uhub, g_audio_driver, g_audio_devclass, 0, 0);
+MODULE_DEPEND(g_audio, usb, 1, 1, 1);
+
+static const struct usb_config g_audio_config[G_AUDIO_N_TRANSFER] = {
+
+       [G_AUDIO_ISOC0_RD] = {
+               .type = UE_ISOCHRONOUS,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_RX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
+               .bufsize = G_AUDIO_BUFSIZE,
+               .callback = &g_audio_isoc_read_callback,
+               .frames = G_AUDIO_FRAMES,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 1,
+       },
+
+       [G_AUDIO_ISOC1_RD] = {
+               .type = UE_ISOCHRONOUS,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_RX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
+               .bufsize = G_AUDIO_BUFSIZE,
+               .callback = &g_audio_isoc_read_callback,
+               .frames = G_AUDIO_FRAMES,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 1,
+       },
+
+       [G_AUDIO_ISOC0_WR] = {
+               .type = UE_ISOCHRONOUS,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_TX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = G_AUDIO_BUFSIZE,
+               .callback = &g_audio_isoc_write_callback,
+               .frames = G_AUDIO_FRAMES,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 2,
+       },
+
+       [G_AUDIO_ISOC1_WR] = {
+               .type = UE_ISOCHRONOUS,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_TX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = G_AUDIO_BUFSIZE,
+               .callback = &g_audio_isoc_write_callback,
+               .frames = G_AUDIO_FRAMES,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 2,
+       },
+};
+
+static void
+g_audio_timeout_reset(struct g_audio_softc *sc)
+{
+       int i = g_audio_pattern_interval;
+
+       sc->sc_tx_interval = i;
+
+       if (i <= 0)
+               i = 1;
+       else if (i > 1023)
+               i = 1023;
+
+       i = USB_MS_TO_TICKS(i);
+
+       usb_callout_reset(&sc->sc_callout, i, &g_audio_timeout, sc);
+}
+
+static void
+g_audio_timeout(void *arg)
+{
+       struct g_audio_softc *sc = arg;
+
+       sc->sc_mode = g_audio_mode;
+
+       memcpy(sc->sc_pattern, g_audio_pattern_data, sizeof(sc->sc_pattern));
+
+       sc->sc_pattern[G_AUDIO_MAX_STRLEN - 1] = 0;
+
+       sc->sc_pattern_len = strlen(sc->sc_pattern);
+
+       if (sc->sc_mode != G_AUDIO_MODE_LOOP) {
+               usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
+               usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
+       }
+       g_audio_timeout_reset(sc);
+}
+
+static void
+g_audio_watchdog_reset(struct g_audio_softc *sc)
+{
+       usb_callout_reset(&sc->sc_watchdog, hz, &g_audio_watchdog, sc);
+}
+
+static void
+g_audio_watchdog(void *arg)
+{
+       struct g_audio_softc *sc = arg;
+       int i;
+
+       i = sc->sc_throughput;
+
+       sc->sc_throughput = 0;
+
+       g_audio_throughput = i;
+
+       g_audio_watchdog_reset(sc);
+}
+
+static int
+g_audio_probe(device_t dev)
+{
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+       DPRINTFN(11, "\n");
+
+       if (uaa->usb_mode != USB_MODE_DEVICE)
+               return (ENXIO);
+
+       if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
+           (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL))
+               return (0);
+
+       return (ENXIO);
+}
+
+static int
+g_audio_attach(device_t dev)
+{
+       struct g_audio_softc *sc = device_get_softc(dev);
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+       int error;
+       int i;
+       uint8_t iface_index[3];
+
+       DPRINTFN(11, "\n");
+
+       device_set_usb_desc(dev);
+
+       lockinit(&sc->sc_lock, "g_audio", 0, 0);
+
+       usb_callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0);
+       usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0);
+
+       sc->sc_mode = G_AUDIO_MODE_SILENT;
+
+       sc->sc_noise_rem = 1;
+
+       for (i = 0; i != G_AUDIO_FRAMES; i++) {
+               sc->sc_data_len[0][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES;
+               sc->sc_data_len[1][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES;
+       }
+
+       iface_index[0] = uaa->info.bIfaceIndex;
+       iface_index[1] = uaa->info.bIfaceIndex + 1;
+       iface_index[2] = uaa->info.bIfaceIndex + 2;
+
+       error = usbd_set_alt_interface_index(uaa->device, iface_index[1], 1);
+       if (error) {
+               DPRINTF("alt iface setting error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+       error = usbd_set_alt_interface_index(uaa->device, iface_index[2], 1);
+       if (error) {
+               DPRINTF("alt iface setting error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+       error = usbd_transfer_setup(uaa->device,
+           iface_index, sc->sc_xfer, g_audio_config,
+           G_AUDIO_N_TRANSFER, sc, &sc->sc_lock);
+
+       if (error) {
+               DPRINTF("error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+       usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]);
+       usbd_set_parent_iface(uaa->device, iface_index[2], iface_index[0]);
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+
+       usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_RD]);
+       usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_RD]);
+
+       usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
+       usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
+
+       g_audio_timeout_reset(sc);
+
+       g_audio_watchdog_reset(sc);
+
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       return (0);                     /* success */
+
+detach:
+       g_audio_detach(dev);
+
+       return (ENXIO);                 /* error */
+}
+
+static int
+g_audio_detach(device_t dev)
+{
+       struct g_audio_softc *sc = device_get_softc(dev);
+
+       DPRINTF("\n");
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       usb_callout_stop(&sc->sc_callout);
+       usb_callout_stop(&sc->sc_watchdog);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       usbd_transfer_unsetup(sc->sc_xfer, G_AUDIO_N_TRANSFER);
+
+       usb_callout_drain(&sc->sc_callout);
+       usb_callout_drain(&sc->sc_watchdog);
+
+       lockuninit(&sc->sc_lock);
+
+       return (0);
+}
+
+
+static int32_t
+g_noise(struct g_audio_softc *sc)
+{
+       uint32_t temp;
+       const uint32_t prime = 0xFFFF1D;
+
+       if (sc->sc_noise_rem & 1) {
+               sc->sc_noise_rem += prime;
+       }
+       sc->sc_noise_rem /= 2;
+
+       temp = sc->sc_noise_rem;
+
+       /* unsigned to signed conversion */
+
+       temp ^= 0x800000;
+       if (temp & 0x800000) {
+               temp |= (-0x800000);
+       }
+       return temp;
+}
+
+static void
+g_audio_make_samples(struct g_audio_softc *sc, int16_t *ptr, int samples)
+{
+       int i;
+       int j;
+
+       for (i = 0; i != samples; i++) {
+
+               j = g_noise(sc);
+
+               if ((sc->sc_state < 0) || (sc->sc_state >= sc->sc_pattern_len))
+                       sc->sc_state = 0;
+
+               if (sc->sc_pattern_len != 0) {
+                       j = (j * sc->sc_pattern[sc->sc_state]) >> 16;
+                       sc->sc_state++;
+               }
+               *ptr++ = j / 256;
+               *ptr++ = j / 256;
+       }
+}
+
+static void
+g_audio_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_audio_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+       int nr = (xfer == sc->sc_xfer[G_AUDIO_ISOC0_WR]) ? 0 : 1;
+       int16_t *ptr;
+       int i;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+
+               sc->sc_throughput += actlen;
+
+               if (sc->sc_mode == G_AUDIO_MODE_LOOP)
+                       break;          /* sync with RX */
+
+       case USB_ST_SETUP:
+tr_setup:
+
+               ptr = sc->sc_data_buf[nr];
+
+               if (sc->sc_mode == G_AUDIO_MODE_PATTERN) {
+
+                       for (i = 0; i != G_AUDIO_FRAMES; i++) {
+
+                               usbd_xfer_set_frame_data(xfer, i, ptr, sc->sc_data_len[nr][i]);
+
+                               g_audio_make_samples(sc, ptr, (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2);
+
+                               ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
+                       }
+               } else if (sc->sc_mode == G_AUDIO_MODE_LOOP) {
+
+                       for (i = 0; i != G_AUDIO_FRAMES; i++) {
+
+                               usbd_xfer_set_frame_data(xfer, i, ptr, sc->sc_data_len[nr][i] & ~3);
+
+                               g_audio_make_samples(sc, ptr, sc->sc_data_len[nr][i] / 4);
+
+                               ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
+                       }
+               }
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static void
+g_audio_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_audio_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+       int nr = (xfer == sc->sc_xfer[G_AUDIO_ISOC0_RD]) ? 0 : 1;
+       int16_t *ptr;
+       int i;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+
+               sc->sc_throughput += actlen;
+
+               for (i = 0; i != G_AUDIO_FRAMES; i++) {
+                       sc->sc_data_len[nr][i] = usbd_xfer_frame_len(xfer, i);
+               }
+
+               usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
+               usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
+
+               break;
+
+       case USB_ST_SETUP:
+tr_setup:
+               ptr = sc->sc_data_buf[nr];
+
+               for (i = 0; i != G_AUDIO_FRAMES; i++) {
+
+                       usbd_xfer_set_frame_data(xfer, i, ptr,
+                           G_AUDIO_BUFSIZE / G_AUDIO_FRAMES);
+
+                       ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
+               }
+
+               usbd_transfer_submit(xfer);
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+
+static int
+g_audio_handle_request(device_t dev,
+    const void *preq, void **pptr, uint16_t *plen,
+    uint16_t offset, uint8_t *pstate)
+{
+       struct g_audio_softc *sc = device_get_softc(dev);
+       const struct usb_device_request *req = preq;
+       uint8_t is_complete = *pstate;
+
+       if (!is_complete) {
+               if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
+                   (req->bRequest == 0x82 /* get min */ )) {
+
+                       if (offset == 0) {
+                               USETW(sc->sc_volume_limit, 0);
+                               *plen = 2;
+                               *pptr = &sc->sc_volume_limit;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
+                   (req->bRequest == 0x83 /* get max */ )) {
+
+                       if (offset == 0) {
+                               USETW(sc->sc_volume_limit, 0x2000);
+                               *plen = 2;
+                               *pptr = &sc->sc_volume_limit;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
+                   (req->bRequest == 0x84 /* get residue */ )) {
+
+                       if (offset == 0) {
+                               USETW(sc->sc_volume_limit, 1);
+                               *plen = 2;
+                               *pptr = &sc->sc_volume_limit;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
+                   (req->bRequest == 0x81 /* get value */ )) {
+
+                       if (offset == 0) {
+                               USETW(sc->sc_volume_setting, 0x2000);
+                               *plen = sizeof(sc->sc_volume_setting);
+                               *pptr = &sc->sc_volume_setting;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == 0x01 /* set value */ )) {
+
+                       if (offset == 0) {
+                               *plen = sizeof(sc->sc_volume_setting);
+                               *pptr = &sc->sc_volume_setting;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_ENDPOINT) &&
+                   (req->bRequest == 0x01 /* set value */ )) {
+
+                       if (offset == 0) {
+                               *plen = sizeof(sc->sc_sample_rate);
+                               *pptr = &sc->sc_sample_rate;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               }
+       }
+       return (ENXIO);                 /* use builtin handler */
+}
diff --git a/sys/bus/u4b/gadget/g_audio.h b/sys/bus/u4b/gadget/g_audio.h
new file mode 100644 (file)
index 0000000..8cf2234
--- /dev/null
@@ -0,0 +1,40 @@
+/* $FreeBSD: head/sys/dev/usb/gadget/g_audio.h 253544 2013-07-22 13:39:33Z hselasky $ */
+/*-
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _G_AUDIO_H_
+#define        _G_AUDIO_H_
+
+#define        G_AUDIO_MAX_STRLEN 32           /* chars */
+#define        G_AUDIO_FRAMES 8
+#define        G_AUDIO_BUFSIZE (G_AUDIO_FRAMES * 2 * 2 * 48)   /* units */
+
+#define        G_AUDIO_MODE_SILENT 0
+#define        G_AUDIO_MODE_DUMP 1
+#define        G_AUDIO_MODE_LOOP 2
+#define        G_AUDIO_MODE_PATTERN 3
+#define        G_AUDIO_MODE_MAX 4
+
+#endif                                 /* _G_AUDIO_H_ */
similarity index 81%
copy from tools/tools/usbtest/Makefile
copy to sys/bus/u4b/gadget/g_audio/Makefile
index 1cc0c83..db14fea 100644 (file)
@@ -1,7 +1,7 @@
 #
-# $FreeBSD$
+# $FreeBSD: head/sys/modules/usb/g_audio/Makefile 253544 2013-07-22 13:39:33Z hselasky $
 #
-# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
+# Copyright (c) 2010 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
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-PROG=  usbtest
-MAN=
-SRCS+= usbtest.c
-SRCS+= usb_msc_test.c
-SRCS+= usb_modem_test.c
-SRCS+= usb_control_ep_test.c
 
-LDADD+=        -lusb
+.PATH: ${.CURDIR}/..
 
-WARNS= 3
+KMOD=  g_audio
 
-CFLAGS+= -I ${.CURDIR}/../../../sys/dev/usb/gadget
+SRCS=  bus_if.h usb_if.h device_if.h \
+    card_if.h opt_usb.h pci_if.h g_audio.c
 
-.include <bsd.prog.mk>
+.include <bsd.kmod.mk>
diff --git a/sys/bus/u4b/gadget/g_keyboard.c b/sys/bus/u4b/gadget/g_keyboard.c
new file mode 100644 (file)
index 0000000..0838b5d
--- /dev/null
@@ -0,0 +1,407 @@
+/*-
+ * Copyright (c) 2010 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.
+ *
+ * $FreeBSD: head/sys/dev/usb/gadget/g_keyboard.c 253618 2013-07-24 18:32:15Z obrien $
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/stdint.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbdi.h>
+#include <bus/u4b/usbdi_util.h>
+#include <bus/u4b/usbhid.h>
+#include "usb_if.h"
+
+#define        USB_DEBUG_VAR g_keyboard_debug
+#include <bus/u4b/usb_debug.h>
+
+#include <bus/u4b/gadget/g_keyboard.h>
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, g_keyboard, CTLFLAG_RW, 0, "USB keyboard gadget");
+
+#ifdef USB_DEBUG
+static int g_keyboard_debug = 0;
+
+SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, debug, CTLFLAG_RW,
+    &g_keyboard_debug, 0, "Debug level");
+#endif
+
+static int g_keyboard_mode = 0;
+
+SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, mode, CTLFLAG_RW,
+    &g_keyboard_mode, 0, "Mode selection");
+
+static int g_keyboard_key_press_interval = 1000;
+
+SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, key_press_interval, CTLFLAG_RW,
+    &g_keyboard_key_press_interval, 0, "Key Press Interval in milliseconds");
+
+static char g_keyboard_key_press_pattern[G_KEYBOARD_MAX_STRLEN];
+
+SYSCTL_STRING(_hw_usb_g_keyboard, OID_AUTO, key_press_pattern, CTLFLAG_RW,
+    g_keyboard_key_press_pattern, sizeof(g_keyboard_key_press_pattern),
+    "Key Press Patterns");
+
+#define        UPROTO_BOOT_KEYBOARD 1
+
+#define        G_KEYBOARD_NMOD                     8   /* units */
+#define        G_KEYBOARD_NKEYCODE                 6   /* units */
+
+struct g_keyboard_data {
+       uint8_t modifiers;
+#define        MOD_CONTROL_L   0x01
+#define        MOD_CONTROL_R   0x10
+#define        MOD_SHIFT_L     0x02
+#define        MOD_SHIFT_R     0x20
+#define        MOD_ALT_L       0x04
+#define        MOD_ALT_R       0x40
+#define        MOD_WIN_L       0x08
+#define        MOD_WIN_R       0x80
+       uint8_t reserved;
+       uint8_t keycode[G_KEYBOARD_NKEYCODE];
+};
+
+enum {
+       G_KEYBOARD_INTR_DT,
+       G_KEYBOARD_N_TRANSFER,
+};
+
+struct g_keyboard_softc {
+       struct lock sc_lock;
+       struct usb_callout sc_callout;
+       struct g_keyboard_data sc_data[2];
+       struct usb_xfer *sc_xfer[G_KEYBOARD_N_TRANSFER];
+
+       int     sc_mode;
+       int     sc_state;
+       int     sc_pattern_len;
+
+       char    sc_pattern[G_KEYBOARD_MAX_STRLEN];
+
+       uint8_t sc_led_state[4];
+};
+
+static device_probe_t g_keyboard_probe;
+static device_attach_t g_keyboard_attach;
+static device_detach_t g_keyboard_detach;
+static usb_handle_request_t g_keyboard_handle_request;
+static usb_callback_t g_keyboard_intr_callback;
+
+static devclass_t g_keyboard_devclass;
+
+static device_method_t g_keyboard_methods[] = {
+       /* USB interface */
+       DEVMETHOD(usb_handle_request, g_keyboard_handle_request),
+
+       /* Device interface */
+       DEVMETHOD(device_probe, g_keyboard_probe),
+       DEVMETHOD(device_attach, g_keyboard_attach),
+       DEVMETHOD(device_detach, g_keyboard_detach),
+
+       DEVMETHOD_END
+};
+
+static driver_t g_keyboard_driver = {
+       .name = "g_keyboard",
+       .methods = g_keyboard_methods,
+       .size = sizeof(struct g_keyboard_softc),
+};
+
+DRIVER_MODULE(g_keyboard, uhub, g_keyboard_driver, g_keyboard_devclass, 0, 0);
+MODULE_DEPEND(g_keyboard, usb, 1, 1, 1);
+
+static const struct usb_config g_keyboard_config[G_KEYBOARD_N_TRANSFER] = {
+       [G_KEYBOARD_INTR_DT] = {
+               .type = UE_INTERRUPT,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_IN,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = sizeof(struct g_keyboard_data),
+               .callback = &g_keyboard_intr_callback,
+               .frames = 2,
+               .usb_mode = USB_MODE_DEVICE,
+       },
+};
+
+static void g_keyboard_timeout(void *arg);
+
+static void
+g_keyboard_timeout_reset(struct g_keyboard_softc *sc)
+{
+       int i = g_keyboard_key_press_interval;
+
+       if (i <= 0)
+               i = 1;
+       else if (i > 1023)
+               i = 1023;
+
+       i = USB_MS_TO_TICKS(i);
+
+       usb_callout_reset(&sc->sc_callout, i, &g_keyboard_timeout, sc);
+}
+
+static void
+g_keyboard_timeout(void *arg)
+{
+       struct g_keyboard_softc *sc = arg;
+
+       sc->sc_mode = g_keyboard_mode;
+
+       memcpy(sc->sc_pattern, g_keyboard_key_press_pattern, sizeof(sc->sc_pattern));
+
+       sc->sc_pattern[G_KEYBOARD_MAX_STRLEN - 1] = 0;
+
+       sc->sc_pattern_len = strlen(sc->sc_pattern);
+
+       DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_KEYBOARD_INTR_DT]);
+
+       usbd_transfer_start(sc->sc_xfer[G_KEYBOARD_INTR_DT]);
+
+       g_keyboard_timeout_reset(sc);
+}
+
+static int
+g_keyboard_probe(device_t dev)
+{
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+       DPRINTFN(11, "\n");
+
+       if (uaa->usb_mode != USB_MODE_DEVICE)
+               return (ENXIO);
+
+       if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
+           (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
+           (uaa->info.bInterfaceProtocol == UPROTO_BOOT_KEYBOARD))
+               return (0);
+
+       return (ENXIO);
+}
+
+static int
+g_keyboard_attach(device_t dev)
+{
+       struct g_keyboard_softc *sc = device_get_softc(dev);
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+       int error;
+
+       DPRINTFN(11, "\n");
+
+       device_set_usb_desc(dev);
+
+       lockinit(&sc->sc_lock, "g_keyboard", 0, 0);
+
+       usb_callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0);
+
+       sc->sc_mode = G_KEYBOARD_MODE_SILENT;
+
+       error = usbd_transfer_setup(uaa->device,
+           &uaa->info.bIfaceIndex, sc->sc_xfer, g_keyboard_config,
+           G_KEYBOARD_N_TRANSFER, sc, &sc->sc_lock);
+
+       if (error) {
+               DPRINTF("error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       g_keyboard_timeout_reset(sc);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       return (0);                     /* success */
+
+detach:
+       g_keyboard_detach(dev);
+
+       return (ENXIO);                 /* error */
+}
+
+static int
+g_keyboard_detach(device_t dev)
+{
+       struct g_keyboard_softc *sc = device_get_softc(dev);
+
+       DPRINTF("\n");
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       usb_callout_stop(&sc->sc_callout);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       usbd_transfer_unsetup(sc->sc_xfer, G_KEYBOARD_N_TRANSFER);
+
+       usb_callout_drain(&sc->sc_callout);
+
+       lockuninit(&sc->sc_lock);
+
+       return (0);
+}
+
+static uint8_t
+g_keyboard_get_keycode(struct g_keyboard_softc *sc, int index)
+{
+       int key;
+       int mod = sc->sc_pattern_len;
+
+       if (mod == 0)
+               index = 0;
+       else
+               index %= mod;
+
+       if ((index >= 0) && (index < sc->sc_pattern_len))
+               key = sc->sc_pattern[index];
+       else
+               key = 'a';
+
+       if (key >= 'a' && key <= 'z')
+               return (key - 'a' + 0x04);
+       else
+               return (0x04);
+}
+
+static void
+g_keyboard_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_keyboard_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+               break;
+
+       case USB_ST_SETUP:
+tr_setup:
+               if (sc->sc_mode == G_KEYBOARD_MODE_SILENT) {
+                       memset(&sc->sc_data, 0, sizeof(sc->sc_data));
+                       usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
+                       usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
+                       usbd_xfer_set_frames(xfer, 2);
+                       usbd_transfer_submit(xfer);
+
+               } else if (sc->sc_mode == G_KEYBOARD_MODE_PATTERN) {
+
+                       memset(&sc->sc_data, 0, sizeof(sc->sc_data));
+
+                       if ((sc->sc_state < 0) || (sc->sc_state >= G_KEYBOARD_MAX_STRLEN))
+                               sc->sc_state = 0;
+
+                       switch (sc->sc_state % 6) {
+                       case 0:
+                               sc->sc_data[0].keycode[0] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 0);
+                       case 1:
+                               sc->sc_data[0].keycode[1] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 1);
+                       case 2:
+                               sc->sc_data[0].keycode[2] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 2);
+                       case 3:
+                               sc->sc_data[0].keycode[3] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 3);
+                       case 4:
+                               sc->sc_data[0].keycode[4] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 4);
+                       default:
+                               sc->sc_data[0].keycode[5] =
+                                   g_keyboard_get_keycode(sc, sc->sc_state + 5);
+                       }
+
+                       sc->sc_state++;
+
+                       usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
+                       usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
+                       usbd_xfer_set_frames(xfer, 2);
+                       usbd_transfer_submit(xfer);
+               }
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static int
+g_keyboard_handle_request(device_t dev,
+    const void *preq, void **pptr, uint16_t *plen,
+    uint16_t offset, uint8_t *pstate)
+{
+       struct g_keyboard_softc *sc = device_get_softc(dev);
+       const struct usb_device_request *req = preq;
+       uint8_t is_complete = *pstate;
+
+       if (!is_complete) {
+               if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UR_SET_REPORT) &&
+                   (req->wValue[0] == 0x00) &&
+                   (req->wValue[1] == 0x02)) {
+
+                       if (offset == 0) {
+                               *plen = sizeof(sc->sc_led_state);
+                               *pptr = &sc->sc_led_state;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                           (req->bRequest == UR_SET_PROTOCOL) &&
+                           (req->wValue[0] == 0x00) &&
+                   (req->wValue[1] == 0x00)) {
+                       *plen = 0;
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UR_SET_IDLE)) {
+                       *plen = 0;
+                       return (0);
+               }
+       }
+       return (ENXIO);                 /* use builtin handler */
+}
diff --git a/sys/bus/u4b/gadget/g_keyboard.h b/sys/bus/u4b/gadget/g_keyboard.h
new file mode 100644 (file)
index 0000000..418f2df
--- /dev/null
@@ -0,0 +1,35 @@
+/* $FreeBSD: head/sys/dev/usb/gadget/g_keyboard.h 253544 2013-07-22 13:39:33Z hselasky $ */
+/*-
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _G_KEYBOARD_H_
+#define        _G_KEYBOARD_H_
+
+#define        G_KEYBOARD_MAX_STRLEN 32
+#define        G_KEYBOARD_MODE_SILENT 0
+#define        G_KEYBOARD_MODE_PATTERN 1
+#define        G_KEYBOARD_MODE_MAX 2
+
+#endif                                 /* _G_KEYBOARD_H_ */
similarity index 81%
copy from tools/tools/usbtest/Makefile
copy to sys/bus/u4b/gadget/g_keyboard/Makefile
index 1cc0c83..0246a88 100644 (file)
@@ -1,7 +1,7 @@
 #
-# $FreeBSD$
+# $FreeBSD: head/sys/modules/usb/g_keyboard/Makefile 253544 2013-07-22 13:39:33Z hselasky $
 #
-# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
+# Copyright (c) 2008 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
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-PROG=  usbtest
-MAN=
-SRCS+= usbtest.c
-SRCS+= usb_msc_test.c
-SRCS+= usb_modem_test.c
-SRCS+= usb_control_ep_test.c
 
-LDADD+=        -lusb
+.PATH: ${.CURDIR}/..
 
-WARNS= 3
+KMOD=  g_keyboard
 
-CFLAGS+= -I ${.CURDIR}/../../../sys/dev/usb/gadget
+SRCS=  bus_if.h usb_if.h device_if.h \
+    opt_usb.h g_keyboard.c
 
-.include <bsd.prog.mk>
+.include <bsd.kmod.mk>
diff --git a/sys/bus/u4b/gadget/g_modem.c b/sys/bus/u4b/gadget/g_modem.c
new file mode 100644 (file)
index 0000000..394d872
--- /dev/null
@@ -0,0 +1,540 @@
+/*-
+ * Copyright (c) 2010 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.
+ *
+ * $FreeBSD: head/sys/dev/usb/gadget/g_modem.c 253618 2013-07-24 18:32:15Z obrien $
+ */
+
+/*
+ * Comm Class spec:  http://www.usb.org/developers/devclass_docs/usbccs10.pdf
+ *                   http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
+ *                   http://www.usb.org/developers/devclass_docs/cdc_wmc10.zip
+ */
+
+#include <sys/stdint.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usb_cdc.h>
+#include <bus/u4b/usbdi.h>
+#include <bus/u4b/usbdi_util.h>
+#include <bus/u4b/usbhid.h>
+#include "usb_if.h"
+
+#define        USB_DEBUG_VAR g_modem_debug
+#include <bus/u4b/usb_debug.h>
+
+#include <bus/u4b/gadget/g_modem.h>
+
+enum {
+       G_MODEM_INTR_DT,
+       G_MODEM_BULK_RD,
+       G_MODEM_BULK_WR,
+       G_MODEM_N_TRANSFER,
+};
+
+struct g_modem_softc {
+       struct lock sc_lock;
+       struct usb_callout sc_callout;
+       struct usb_callout sc_watchdog;
+       struct usb_xfer *sc_xfer[G_MODEM_N_TRANSFER];
+
+       int     sc_mode;
+       int     sc_tx_busy;
+       int     sc_pattern_len;
+       int     sc_throughput;
+       int     sc_tx_interval;
+
+       char    sc_pattern[G_MODEM_MAX_STRLEN];
+
+       uint16_t sc_data_len;
+
+       uint8_t sc_data_buf[G_MODEM_BUFSIZE];
+       uint8_t sc_line_coding[32];
+       uint8_t sc_abstract_state[32];
+};
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, g_modem, CTLFLAG_RW, 0, "USB modem gadget");
+
+#ifdef USB_DEBUG
+static int g_modem_debug = 0;
+
+SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, debug, CTLFLAG_RW,
+    &g_modem_debug, 0, "Debug level");
+#endif
+
+static int g_modem_mode = 0;
+
+SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, mode, CTLFLAG_RW,
+    &g_modem_mode, 0, "Mode selection");
+
+static int g_modem_pattern_interval = 1000;
+
+SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, pattern_interval, CTLFLAG_RW,
+    &g_modem_pattern_interval, 0, "Pattern interval in milliseconds");
+
+static char g_modem_pattern_data[G_MODEM_MAX_STRLEN];
+
+SYSCTL_STRING(_hw_usb_g_modem, OID_AUTO, pattern, CTLFLAG_RW,
+    &g_modem_pattern_data, sizeof(g_modem_pattern_data), "Data pattern");
+
+static int g_modem_throughput;
+
+SYSCTL_INT(_hw_usb_g_modem, OID_AUTO, throughput, CTLFLAG_RD,
+    &g_modem_throughput, sizeof(g_modem_throughput), "Throughput in bytes per second");
+
+static device_probe_t g_modem_probe;
+static device_attach_t g_modem_attach;
+static device_detach_t g_modem_detach;
+static usb_handle_request_t g_modem_handle_request;
+static usb_callback_t g_modem_intr_callback;
+static usb_callback_t g_modem_bulk_read_callback;
+static usb_callback_t g_modem_bulk_write_callback;
+
+static void g_modem_timeout(void *arg);
+
+static devclass_t g_modem_devclass;
+
+static device_method_t g_modem_methods[] = {
+       /* USB interface */
+       DEVMETHOD(usb_handle_request, g_modem_handle_request),
+
+       /* Device interface */
+       DEVMETHOD(device_probe, g_modem_probe),
+       DEVMETHOD(device_attach, g_modem_attach),
+       DEVMETHOD(device_detach, g_modem_detach),
+
+       DEVMETHOD_END
+};
+
+static driver_t g_modem_driver = {
+       .name = "g_modem",
+       .methods = g_modem_methods,
+       .size = sizeof(struct g_modem_softc),
+};
+
+DRIVER_MODULE(g_modem, uhub, g_modem_driver, g_modem_devclass, 0, 0);
+MODULE_DEPEND(g_modem, usb, 1, 1, 1);
+
+static const struct usb_config g_modem_config[G_MODEM_N_TRANSFER] = {
+
+       [G_MODEM_INTR_DT] = {
+               .type = UE_INTERRUPT,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_TX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = 0,   /* use wMaxPacketSize */
+               .callback = &g_modem_intr_callback,
+               .frames = 1,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 0,
+       },
+
+       [G_MODEM_BULK_RD] = {
+               .type = UE_BULK,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_RX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
+               .bufsize = G_MODEM_BUFSIZE,
+               .callback = &g_modem_bulk_read_callback,
+               .frames = 1,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 1,
+       },
+
+       [G_MODEM_BULK_WR] = {
+               .type = UE_BULK,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_TX,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = G_MODEM_BUFSIZE,
+               .callback = &g_modem_bulk_write_callback,
+               .frames = 1,
+               .usb_mode = USB_MODE_DEVICE,
+               .if_index = 1,
+       },
+};
+
+static void
+g_modem_timeout_reset(struct g_modem_softc *sc)
+{
+       int i = g_modem_pattern_interval;
+
+       sc->sc_tx_interval = i;
+
+       if (i <= 0)
+               i = 1;
+       else if (i > 1023)
+               i = 1023;
+
+       i = USB_MS_TO_TICKS(i);
+
+       usb_callout_reset(&sc->sc_callout, i, &g_modem_timeout, sc);
+}
+
+static void
+g_modem_timeout(void *arg)
+{
+       struct g_modem_softc *sc = arg;
+
+       sc->sc_mode = g_modem_mode;
+
+       memcpy(sc->sc_pattern, g_modem_pattern_data, sizeof(sc->sc_pattern));
+
+       sc->sc_pattern[G_MODEM_MAX_STRLEN - 1] = 0;
+
+       sc->sc_pattern_len = strlen(sc->sc_pattern);
+
+       DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_MODEM_INTR_DT]);
+
+       usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]);
+       usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]);
+
+       g_modem_timeout_reset(sc);
+}
+
+static void g_modem_watchdog(void *arg);
+
+static void
+g_modem_watchdog_reset(struct g_modem_softc *sc)
+{
+       usb_callout_reset(&sc->sc_watchdog, hz, &g_modem_watchdog, sc);
+}
+
+static void
+g_modem_watchdog(void *arg)
+{
+       struct g_modem_softc *sc = arg;
+       int i;
+
+       i = sc->sc_throughput;
+
+       sc->sc_throughput = 0;
+
+       g_modem_throughput = i;
+
+       g_modem_watchdog_reset(sc);
+}
+
+static int
+g_modem_probe(device_t dev)
+{
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+       DPRINTFN(11, "\n");
+
+       if (uaa->usb_mode != USB_MODE_DEVICE)
+               return (ENXIO);
+
+       if ((uaa->info.bInterfaceClass == UICLASS_CDC) &&
+           (uaa->info.bInterfaceSubClass == UISUBCLASS_ABSTRACT_CONTROL_MODEL) &&
+           (uaa->info.bInterfaceProtocol == UIPROTO_CDC_AT))
+               return (0);
+
+       return (ENXIO);
+}
+
+static int
+g_modem_attach(device_t dev)
+{
+       struct g_modem_softc *sc = device_get_softc(dev);
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+       int error;
+       uint8_t iface_index[2];
+
+       DPRINTFN(11, "\n");
+
+       device_set_usb_desc(dev);
+
+       lockinit(&sc->sc_lock, "g_modem", 0, 0);
+
+       usb_callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0);
+       usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0);
+
+       sc->sc_mode = G_MODEM_MODE_SILENT;
+
+       iface_index[0] = uaa->info.bIfaceIndex;
+       iface_index[1] = uaa->info.bIfaceIndex + 1;
+
+       error = usbd_transfer_setup(uaa->device,
+           iface_index, sc->sc_xfer, g_modem_config,
+           G_MODEM_N_TRANSFER, sc, &sc->sc_lock);
+
+       if (error) {
+               DPRINTF("error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+       usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]);
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       g_modem_timeout_reset(sc);
+       g_modem_watchdog_reset(sc);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       return (0);                     /* success */
+
+detach:
+       g_modem_detach(dev);
+
+       return (ENXIO);                 /* error */
+}
+
+static int
+g_modem_detach(device_t dev)
+{
+       struct g_modem_softc *sc = device_get_softc(dev);
+
+       DPRINTF("\n");
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       usb_callout_stop(&sc->sc_callout);
+       usb_callout_stop(&sc->sc_watchdog);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       usbd_transfer_unsetup(sc->sc_xfer, G_MODEM_N_TRANSFER);
+
+       usb_callout_drain(&sc->sc_callout);
+       usb_callout_drain(&sc->sc_watchdog);
+
+       lockuninit(&sc->sc_lock);
+
+       return (0);
+}
+
+static void
+g_modem_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       int actlen;
+       int aframes;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+               break;
+
+       case USB_ST_SETUP:
+tr_setup:
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static void
+g_modem_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_modem_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+       int mod;
+       int x;
+       int max;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+
+               sc->sc_tx_busy = 0;
+               sc->sc_throughput += actlen;
+
+               if (sc->sc_mode == G_MODEM_MODE_LOOP) {
+                       /* start loop */
+                       usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_RD]);
+                       break;
+               } else if ((sc->sc_mode == G_MODEM_MODE_PATTERN) && (sc->sc_tx_interval != 0)) {
+                       /* wait for next timeout */
+                       break;
+               }
+       case USB_ST_SETUP:
+tr_setup:
+               if (sc->sc_mode == G_MODEM_MODE_PATTERN) {
+
+                       mod = sc->sc_pattern_len;
+                       max = sc->sc_tx_interval ? mod : G_MODEM_BUFSIZE;
+
+                       if (mod == 0) {
+                               for (x = 0; x != max; x++)
+                                       sc->sc_data_buf[x] = x % 255;
+                       } else {
+                               for (x = 0; x != max; x++)
+                                       sc->sc_data_buf[x] = sc->sc_pattern[x % mod];
+                       }
+
+                       usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, max);
+                       usbd_xfer_set_interval(xfer, 0);
+                       usbd_xfer_set_frames(xfer, 1);
+                       usbd_transfer_submit(xfer);
+
+               } else if (sc->sc_mode == G_MODEM_MODE_LOOP) {
+
+                       if (sc->sc_tx_busy == 0)
+                               break;
+
+                       x = sc->sc_tx_interval;
+
+                       if (x < 0)
+                               x = 0;
+                       else if (x > 256)
+                               x = 256;
+
+                       usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, sc->sc_data_len);
+                       usbd_xfer_set_interval(xfer, x);
+                       usbd_xfer_set_frames(xfer, 1);
+                       usbd_transfer_submit(xfer);
+               } else {
+                       sc->sc_tx_busy = 0;
+               }
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static void
+g_modem_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_modem_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+
+               sc->sc_throughput += actlen;
+
+               if (sc->sc_mode == G_MODEM_MODE_LOOP) {
+                       sc->sc_tx_busy = 1;
+                       sc->sc_data_len = actlen;
+                       usbd_transfer_start(sc->sc_xfer[G_MODEM_BULK_WR]);
+                       break;
+               }
+
+       case USB_ST_SETUP:
+tr_setup:
+               if ((sc->sc_mode == G_MODEM_MODE_SILENT) ||
+                   (sc->sc_tx_busy != 0))
+                       break;
+
+               usbd_xfer_set_frame_data(xfer, 0, sc->sc_data_buf, G_MODEM_BUFSIZE);
+               usbd_xfer_set_frames(xfer, 1);
+               usbd_transfer_submit(xfer);
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+
+static int
+g_modem_handle_request(device_t dev,
+    const void *preq, void **pptr, uint16_t *plen,
+    uint16_t offset, uint8_t *pstate)
+{
+       struct g_modem_softc *sc = device_get_softc(dev);
+       const struct usb_device_request *req = preq;
+       uint8_t is_complete = *pstate;
+
+       if (!is_complete) {
+               if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UCDC_SET_LINE_CODING) &&
+                   (req->wValue[0] == 0x00) &&
+                   (req->wValue[1] == 0x00)) {
+
+                       if (offset == 0) {
+                               *plen = sizeof(sc->sc_line_coding);
+                               *pptr = &sc->sc_line_coding;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UCDC_SET_COMM_FEATURE)) {
+
+                       if (offset == 0) {
+                               *plen = sizeof(sc->sc_abstract_state);
+                               *pptr = &sc->sc_abstract_state;
+                       } else {
+                               *plen = 0;
+                       }
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UCDC_SET_CONTROL_LINE_STATE)) {
+                       *plen = 0;
+                       return (0);
+               } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UCDC_SEND_BREAK)) {
+                       *plen = 0;
+                       return (0);
+               }
+       }
+       return (ENXIO);                 /* use builtin handler */
+}
diff --git a/sys/bus/u4b/gadget/g_modem.h b/sys/bus/u4b/gadget/g_modem.h
new file mode 100644 (file)
index 0000000..4032002
--- /dev/null
@@ -0,0 +1,39 @@
+/* $FreeBSD: head/sys/dev/usb/gadget/g_modem.h 253544 2013-07-22 13:39:33Z hselasky $ */
+/*-
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _G_MODEM_H_
+#define        _G_MODEM_H_
+
+#define        G_MODEM_MAX_STRLEN 32           /* chars */
+#define        G_MODEM_BUFSIZE 4096            /* bytes */
+
+#define        G_MODEM_MODE_SILENT 0
+#define        G_MODEM_MODE_DUMP 1
+#define        G_MODEM_MODE_LOOP 2
+#define        G_MODEM_MODE_PATTERN 3
+#define        G_MODEM_MODE_MAX 4
+
+#endif                                 /* _G_MODEM_H_ */
similarity index 81%
copy from tools/tools/usbtest/Makefile
copy to sys/bus/u4b/gadget/g_modem/Makefile
index 1cc0c83..bec8345 100644 (file)
@@ -1,7 +1,7 @@
 #
-# $FreeBSD$
+# $FreeBSD: head/sys/modules/usb/g_modem/Makefile 253544 2013-07-22 13:39:33Z hselasky $
 #
-# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
+# Copyright (c) 2010 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
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-PROG=  usbtest
-MAN=
-SRCS+= usbtest.c
-SRCS+= usb_msc_test.c
-SRCS+= usb_modem_test.c
-SRCS+= usb_control_ep_test.c
 
-LDADD+=        -lusb
+.PATH: ${.CURDIR}/..
 
-WARNS= 3
+KMOD=  g_modem
 
-CFLAGS+= -I ${.CURDIR}/../../../sys/dev/usb/gadget
+SRCS=  bus_if.h usb_if.h device_if.h \
+    card_if.h opt_usb.h pci_if.h g_modem.c
 
-.include <bsd.prog.mk>
+.include <bsd.kmod.mk>
diff --git a/sys/bus/u4b/gadget/g_mouse.c b/sys/bus/u4b/gadget/g_mouse.c
new file mode 100644 (file)
index 0000000..1428396
--- /dev/null
@@ -0,0 +1,452 @@
+/*-
+ * Copyright (c) 2010 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.
+ *
+ * $FreeBSD: head/sys/dev/usb/gadget/g_mouse.c 253618 2013-07-24 18:32:15Z obrien $
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/stdint.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbdi.h>
+#include <bus/u4b/usbdi_util.h>
+#include <bus/u4b/usbhid.h>
+#include "usb_if.h"
+
+#define        USB_DEBUG_VAR g_mouse_debug
+#include <bus/u4b/usb_debug.h>
+
+#include <bus/u4b/gadget/g_mouse.h>
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, g_mouse, CTLFLAG_RW, 0, "USB mouse gadget");
+
+#ifdef USB_DEBUG
+static int g_mouse_debug = 0;
+
+SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, debug, CTLFLAG_RW,
+    &g_mouse_debug, 0, "Debug level");
+#endif
+
+static int g_mouse_mode = 0;
+
+SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, mode, CTLFLAG_RW,
+    &g_mouse_mode, 0, "Mode selection");
+
+static int g_mouse_button_press_interval = 0;
+
+SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, button_press_interval, CTLFLAG_RW,
+    &g_mouse_button_press_interval, 0, "Mouse button update interval in milliseconds");
+
+static int g_mouse_cursor_update_interval = 1023;
+
+SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, cursor_update_interval, CTLFLAG_RW,
+    &g_mouse_cursor_update_interval, 0, "Mouse cursor update interval in milliseconds");
+
+static int g_mouse_cursor_radius = 128;
+
+SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, cursor_radius, CTLFLAG_RW,
+    &g_mouse_cursor_radius, 0, "Mouse cursor radius in pixels");
+
+struct g_mouse_data {
+       uint8_t buttons;
+#define        BUT_0 0x01
+#define        BUT_1 0x02
+#define        BUT_2 0x04
+       int8_t dx;
+       int8_t dy;
+       int8_t dz;
+};
+
+enum {
+       G_MOUSE_INTR_DT,
+       G_MOUSE_N_TRANSFER,
+};
+
+struct g_mouse_softc {
+       struct lock sc_lock;
+       struct usb_callout sc_button_press_callout;
+       struct usb_callout sc_cursor_update_callout;
+       struct g_mouse_data sc_data;
+       struct usb_xfer *sc_xfer[G_MOUSE_N_TRANSFER];
+
+       int     sc_mode;
+       int     sc_radius;
+       int     sc_last_x_state;
+       int     sc_last_y_state;
+       int     sc_curr_x_state;
+       int     sc_curr_y_state;
+       int     sc_tick;
+
+       uint8_t sc_do_cursor_update;
+       uint8_t sc_do_button_update;
+};
+
+static device_probe_t g_mouse_probe;
+static device_attach_t g_mouse_attach;
+static device_detach_t g_mouse_detach;
+static usb_handle_request_t g_mouse_handle_request;
+static usb_callback_t g_mouse_intr_callback;
+
+static devclass_t g_mouse_devclass;
+
+static device_method_t g_mouse_methods[] = {
+       /* USB interface */
+       DEVMETHOD(usb_handle_request, g_mouse_handle_request),
+
+       /* Device interface */
+       DEVMETHOD(device_probe, g_mouse_probe),
+       DEVMETHOD(device_attach, g_mouse_attach),
+       DEVMETHOD(device_detach, g_mouse_detach),
+
+       DEVMETHOD_END
+};
+
+static driver_t g_mouse_driver = {
+       .name = "g_mouse",
+       .methods = g_mouse_methods,
+       .size = sizeof(struct g_mouse_softc),
+};
+
+DRIVER_MODULE(g_mouse, uhub, g_mouse_driver, g_mouse_devclass, 0, 0);
+MODULE_DEPEND(g_mouse, usb, 1, 1, 1);
+
+static const struct usb_config g_mouse_config[G_MOUSE_N_TRANSFER] = {
+
+       [G_MOUSE_INTR_DT] = {
+               .type = UE_INTERRUPT,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_IN,
+               .flags = {.ext_buffer = 1,.pipe_bof = 1,},
+               .bufsize = sizeof(struct g_mouse_data),
+               .callback = &g_mouse_intr_callback,
+               .frames = 1,
+               .usb_mode = USB_MODE_DEVICE,
+       },
+};
+
+static void g_mouse_button_press_timeout(void *arg);
+static void g_mouse_cursor_update_timeout(void *arg);
+
+static void
+g_mouse_button_press_timeout_reset(struct g_mouse_softc *sc)
+{
+       int i = g_mouse_button_press_interval;
+
+       if (i <= 0) {
+               sc->sc_data.buttons = 0;
+               sc->sc_do_button_update = 0;
+       } else {
+               sc->sc_do_button_update = 1;
+       }
+
+       if ((i <= 0) || (i > 1023))
+               i = 1023;
+
+       i = USB_MS_TO_TICKS(i);
+
+       usb_callout_reset(&sc->sc_button_press_callout, i, 
+           &g_mouse_button_press_timeout, sc);
+}
+
+static void
+g_mouse_cursor_update_timeout_reset(struct g_mouse_softc *sc)
+{
+       int i = g_mouse_cursor_update_interval;
+
+       if (i <= 0) {
+               sc->sc_data.dx = 0;
+               sc->sc_data.dy = 0;
+               sc->sc_do_cursor_update = 0;
+               sc->sc_tick = 0;
+       } else {
+               sc->sc_do_cursor_update = 1;
+       }
+
+       if ((i <= 0) || (i > 1023))
+               i = 1023;
+
+       i = USB_MS_TO_TICKS(i);
+
+       usb_callout_reset(&sc->sc_cursor_update_callout, i, 
+           &g_mouse_cursor_update_timeout, sc);
+}
+
+static void
+g_mouse_update_mode_radius(struct g_mouse_softc *sc)
+{
+       sc->sc_mode = g_mouse_mode;
+       sc->sc_radius = g_mouse_cursor_radius;
+
+       if (sc->sc_radius < 0)
+               sc->sc_radius = 0;
+       else if (sc->sc_radius > 1023)
+               sc->sc_radius = 1023;
+}
+
+static void
+g_mouse_button_press_timeout(void *arg)
+{
+       struct g_mouse_softc *sc = arg;
+
+       g_mouse_update_mode_radius(sc);
+
+       DPRINTFN(11, "Timeout %p (button press)\n", sc->sc_xfer[G_MOUSE_INTR_DT]);
+
+       g_mouse_button_press_timeout_reset(sc);
+
+       usbd_transfer_start(sc->sc_xfer[G_MOUSE_INTR_DT]);
+}
+
+static void
+g_mouse_cursor_update_timeout(void *arg)
+{
+       struct g_mouse_softc *sc = arg;
+
+       g_mouse_update_mode_radius(sc);
+
+       DPRINTFN(11, "Timeout %p (cursor update)\n", sc->sc_xfer[G_MOUSE_INTR_DT]);
+
+       g_mouse_cursor_update_timeout_reset(sc);
+
+       usbd_transfer_start(sc->sc_xfer[G_MOUSE_INTR_DT]);
+}
+
+static int
+g_mouse_probe(device_t dev)
+{
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+       DPRINTFN(11, "\n");
+
+       if (uaa->usb_mode != USB_MODE_DEVICE)
+               return (ENXIO);
+
+       if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
+           (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
+           (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))
+               return (0);
+
+       return (ENXIO);
+}
+
+static int
+g_mouse_attach(device_t dev)
+{
+       struct g_mouse_softc *sc = device_get_softc(dev);
+       struct usb_attach_arg *uaa = device_get_ivars(dev);
+       int error;
+
+       DPRINTFN(11, "\n");
+
+       device_set_usb_desc(dev);
+
+       lockinit(&sc->sc_lock, "g_mouse", 0, 0);
+
+       usb_callout_init_mtx(&sc->sc_button_press_callout, &sc->sc_lock, 0);
+       usb_callout_init_mtx(&sc->sc_cursor_update_callout, &sc->sc_lock, 0);
+
+       sc->sc_mode = G_MOUSE_MODE_SILENT;
+
+       error = usbd_transfer_setup(uaa->device,
+           &uaa->info.bIfaceIndex, sc->sc_xfer, g_mouse_config,
+           G_MOUSE_N_TRANSFER, sc, &sc->sc_lock);
+
+       if (error) {
+               DPRINTF("error=%s\n", usbd_errstr(error));
+               goto detach;
+       }
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       g_mouse_button_press_timeout_reset(sc);
+       g_mouse_cursor_update_timeout_reset(sc);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       return (0);                     /* success */
+
+detach:
+       g_mouse_detach(dev);
+
+       return (ENXIO);                 /* error */
+}
+
+static int
+g_mouse_detach(device_t dev)
+{
+       struct g_mouse_softc *sc = device_get_softc(dev);
+
+       DPRINTF("\n");
+
+       lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
+       usb_callout_stop(&sc->sc_button_press_callout);
+       usb_callout_stop(&sc->sc_cursor_update_callout);
+       lockmgr(&sc->sc_lock, LK_RELEASE);
+
+       usbd_transfer_unsetup(sc->sc_xfer, G_MOUSE_N_TRANSFER);
+
+       usb_callout_drain(&sc->sc_button_press_callout);
+       usb_callout_drain(&sc->sc_cursor_update_callout);
+
+       lockuninit(&sc->sc_lock);
+
+       return (0);
+}
+
+static void
+g_mouse_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct g_mouse_softc *sc = usbd_xfer_softc(xfer);
+       int actlen;
+       int aframes;
+       int dx;
+       int dy;
+       int radius;
+
+       usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
+
+       DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
+           USB_GET_STATE(xfer), aframes, actlen);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+               if (!(sc->sc_do_cursor_update || sc->sc_do_button_update))
+                       break;
+
+       case USB_ST_SETUP:
+tr_setup:
+
+         if (sc->sc_do_cursor_update) {
+               sc->sc_do_cursor_update = 0;
+               sc->sc_tick += 80;
+               if ((sc->sc_tick < 0) || (sc->sc_tick > 7999))
+                       sc->sc_tick = 0;
+         }
+
+         if (sc->sc_do_button_update) {
+                       sc->sc_do_button_update = 0;
+                       sc->sc_data.buttons ^= BUT_0;
+         }
+
+         radius = sc->sc_radius;
+
+               switch (sc->sc_mode) {
+               case G_MOUSE_MODE_SILENT:
+                       sc->sc_data.buttons = 0;
+                       break;
+               case G_MOUSE_MODE_SPIRAL:
+                       radius = (radius * (8000-sc->sc_tick)) / 8000;
+               case G_MOUSE_MODE_CIRCLE:
+                       /* TODO */
+                       sc->sc_curr_y_state = 0;
+                       sc->sc_curr_x_state = 0;
+                       break;
+               case G_MOUSE_MODE_BOX:
+                       if (sc->sc_tick < 2000) {
+                               sc->sc_curr_x_state = (sc->sc_tick * radius) / 2000;
+                               sc->sc_curr_y_state = 0;
+                       } else if (sc->sc_tick < 4000) {
+                               sc->sc_curr_x_state = radius;
+                               sc->sc_curr_y_state = -(((sc->sc_tick - 2000) * radius) / 2000);
+                       } else if (sc->sc_tick < 6000) {
+                               sc->sc_curr_x_state = radius - (((sc->sc_tick - 4000) * radius) / 2000);
+                               sc->sc_curr_y_state = -radius;
+                       } else {
+                               sc->sc_curr_x_state = 0;
+                               sc->sc_curr_y_state = -radius + (((sc->sc_tick - 6000) * radius) / 2000);
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               dx = sc->sc_curr_x_state - sc->sc_last_x_state;
+               dy = sc->sc_curr_y_state - sc->sc_last_y_state;
+
+               if (dx < -63)
+                 dx = -63;
+               else if (dx > 63)
+                 dx = 63;
+
+               if (dy < -63)
+                 dy = -63;
+               else if (dy > 63)
+                 dy = 63;
+
+               sc->sc_last_x_state += dx;
+               sc->sc_last_y_state += dy;
+
+               sc->sc_data.dx = dx;
+               sc->sc_data.dy = dy;
+
+               usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data, sizeof(sc->sc_data));
+               usbd_xfer_set_frames(xfer, 1);
+               usbd_transfer_submit(xfer);
+               break;
+
+       default:                        /* Error */
+               DPRINTF("error=%s\n", usbd_errstr(error));
+
+               if (error != USB_ERR_CANCELLED) {
+                       /* try to clear stall first */
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static int
+g_mouse_handle_request(device_t dev,
+    const void *preq, void **pptr, uint16_t *plen,
+    uint16_t offset, uint8_t *pstate)
+{
+       const struct usb_device_request *req = preq;
+       uint8_t is_complete = *pstate;
+
+       if (!is_complete) {
+               if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
+                   (req->bRequest == UR_SET_PROTOCOL) &&
+                   (req->wValue[0] == 0x00) &&
+                   (req->wValue[1] == 0x00)) {
+                       *plen = 0;
+                       return (0);
+               }
+       }
+       return (ENXIO);                 /* use builtin handler */
+}
diff --git a/sys/bus/u4b/gadget/g_mouse.h b/sys/bus/u4b/gadget/g_mouse.h
new file mode 100644 (file)
index 0000000..bc744fa
--- /dev/null
@@ -0,0 +1,36 @@
+/* $FreeBSD: head/sys/dev/usb/gadget/g_mouse.h 253544 2013-07-22 13:39:33Z hselasky $ */
+/*-
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef _G_MOUSE_H_
+#define        _G_MOUSE_H_
+
+#define        G_MOUSE_MODE_SILENT 0
+#define        G_MOUSE_MODE_CIRCLE 1
+#define        G_MOUSE_MODE_BOX 2
+#define        G_MOUSE_MODE_SPIRAL 3
+#define        G_MOUSE_MODE_MAX 4
+
+#endif                                 /* _G_MOUSE_H_ */
similarity index 81%
copy from tools/tools/usbtest/Makefile
copy to sys/bus/u4b/gadget/g_mouse/Makefile
index 1cc0c83..43f3ce7 100644 (file)
@@ -1,7 +1,7 @@
 #
-# $FreeBSD$
+# $FreeBSD: head/sys/modules/usb/g_mouse/Makefile 253544 2013-07-22 13:39:33Z hselasky $
 #
-# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
+# Copyright (c) 2008 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
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-PROG=  usbtest
-MAN=
-SRCS+= usbtest.c
-SRCS+= usb_msc_test.c
-SRCS+= usb_modem_test.c
-SRCS+= usb_control_ep_test.c
 
-LDADD+=        -lusb
+.PATH: ${.CURDIR}/..
 
-WARNS= 3
+KMOD=  g_mouse
 
-CFLAGS+= -I ${.CURDIR}/../../../sys/dev/usb/gadget
+SRCS=  bus_if.h usb_if.h device_if.h \
+    opt_usb.h g_mouse.c
 
-.include <bsd.prog.mk>
+.include <bsd.kmod.mk>
index 1cc0c83..eec83c9 100644 (file)
@@ -1,5 +1,5 @@
 #
-# $FreeBSD$
+# $FreeBSD: head/tools/tools/usbtest/Makefile 275407 2014-12-02 13:58:57Z hselasky $
 #
 # Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
 #
@@ -31,10 +31,11 @@ SRCS+=      usb_msc_test.c
 SRCS+= usb_modem_test.c
 SRCS+= usb_control_ep_test.c
 
+DPADD+=        ${LIBUSB}
 LDADD+=        -lusb
 
 WARNS= 3
 
-CFLAGS+= -I ${.CURDIR}/../../../sys/dev/usb/gadget
+CFLAGS+= -I ${.CURDIR}/../../../sys/bus/u4b/gadget
 
 .include <bsd.prog.mk>
index d2153c2..2e48bb6 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usb_control_ep_test.c 254241 2013-08-12 09:15:33Z hselasky $ */
 /*-
  * Copyright (c) 2007-2010 Hans Petter Selasky. All rights reserved.
  *
@@ -38,9 +38,9 @@
 #include <libusb20.h>
 #include <libusb20_desc.h>
 
-#include <dev/usb/usb_endian.h>
-#include <dev/usb/usb.h>
-#include <dev/usb/usb_cdc.h>
+#include <bus/u4b/usb_endian.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usb_cdc.h>
 
 #include "usbtest.h"
 
@@ -286,7 +286,7 @@ usb_port_reset_test(uint16_t vid, uint16_t pid, uint32_t duration)
                }
                timersub(&sub_tv, &ref_tv, &res_tv);
 
-               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= duration))
+               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
                        break;
 
                if (libusb20_dev_reset(pdev)) {
@@ -445,7 +445,7 @@ usb_suspend_resume_test(uint16_t vid, uint16_t pid, uint32_t duration)
                }
                timersub(&sub_tv, &ref_tv, &res_tv);
 
-               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= duration))
+               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
                        break;
 
                error = libusb20_dev_set_power_mode(pdev, (iter & 1) ?
index 5aec956..c6a3a16 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usb_modem_test.c 254241 2013-08-12 09:15:33Z hselasky $ */
 /*-
  * Copyright (c) 2007-2010 Hans Petter Selasky. All rights reserved.
  *
@@ -38,9 +38,9 @@
 #include <libusb20.h>
 #include <libusb20_desc.h>
 
-#include <dev/usb/usb_endian.h>
-#include <dev/usb/usb.h>
-#include <dev/usb/usb_cdc.h>
+#include <bus/u4b/usb_endian.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usb_cdc.h>
 
 #include "usbtest.h"
 
@@ -215,7 +215,7 @@ usb_modem_control_ep_test(struct modem *p, uint32_t duration, uint8_t flag)
                }
                timersub(&sub_tv, &ref_tv, &res_tv);
 
-               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= duration))
+               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
                        break;
 
                LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
@@ -333,7 +333,7 @@ usb_modem_data_stress_test(struct modem *p, uint32_t duration)
                }
                timersub(&sub_tv, &ref_tv, &res_tv);
 
-               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= duration))
+               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
                        break;
 
                libusb20_dev_process(p->usb_dev);
index 5ece858..60ef721 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usb_msc_test.c 260587 2014-01-13 13:27:00Z hselasky $ */
 /*-
  * Copyright (c) 2007-2012 Hans Petter Selasky. All rights reserved.
  *
@@ -38,7 +38,7 @@
 #include <libusb20.h>
 #include <libusb20_desc.h>
 
-#include <dev/usb/usb_endian.h>
+#include <bus/u4b/usb_endian.h>
 
 #include "usbtest.h"
 
@@ -105,7 +105,7 @@ static int sense_recurse;
 
 /*
  * SCSI commands sniffed off the wire - LUN maybe needs to be
- * adjusted!  Refer to "dev/usb/storage/ustorage_fs.c" for more
+ * adjusted!  Refer to "bus/u4b/storage/ustorage_fs.c" for more
  * information.
  */
 static uint8_t mode_sense_6[0x6] = {0x1a, 0, 0x3f, 0, 0x0c};
@@ -255,6 +255,35 @@ do_msc_cmd(uint8_t *pcmd, uint8_t cmdlen, void *pdata, uint32_t datalen,
        }
 }
 
+static void
+do_msc_shorter_cmd(uint8_t lun)
+{
+       uint8_t buffer[sizeof(umass_bbb_cbw_t)];
+       int actlen;
+       int error;
+       int x;
+
+       memset(buffer, 0, sizeof(buffer));
+
+       for (x = 0; x != (sizeof(buffer) - 1); x++) {
+               error = libusb20_tr_bulk_intr_sync(xfer_out,
+                   buffer, x, &actlen, 250);
+
+               printf("Sent short %d of %d bytes wrapper block, "
+                   "status = %d\n", x, (int)(sizeof(buffer) - 1),
+                   error);
+
+               do_msc_reset(lun);
+
+               if (error != 0) {
+                       printf("ERROR: Too short command wrapper "
+                           "was not accepted\n");
+                       stats.xfer_error++;
+                       break;
+               }
+       }
+}
+
 static uint8_t
 do_read_10(uint32_t lba, uint32_t len, void *buf, uint8_t lun)
 {
@@ -564,6 +593,11 @@ usb_msc_test(struct usb_msc_params *p)
        if (capacity_bs != 512)
                printf("INFO: Blocksize is not 512 bytes\n");
 
+       if (p->try_shorter_wrapper_block) {
+               printf("Trying too short command wrapper:\n");
+               do_msc_shorter_cmd(lun);
+       }
+
        if (p->try_invalid_scsi_command) {
                int status;
 
@@ -798,7 +832,7 @@ retry_read_init:
                }
                timersub(&sub_tv, &ref_tv, &res_tv);
 
-               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= p->duration))
+               if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)p->duration))
                        break;
 
                do_io_test(p, lun, lba_max, buffer, reference);
@@ -1195,6 +1229,7 @@ show_host_msc_test(uint8_t level, uint16_t vid,
                    "14) Toggle try aborted write transfer: <%s>\n"
                    "15) Toggle request sense on error: <%s>\n"
                    "16) Toggle try all LUN: <%s>\n"
+                   "17) Toggle try too short wrapper block: <%s>\n"
                    "20) Reset parameters\n"
                    "30) Start test (VID=0x%04x, PID=0x%04x)\n"
                    "40) Select another device\n"
@@ -1215,6 +1250,7 @@ show_host_msc_test(uint8_t level, uint16_t vid,
                    (params.try_abort_data_write ? "YES" : "NO"),
                    (params.try_sense_on_error ? "YES" : "NO"),
                    (params.try_all_lun ? "YES" : "NO"),
+                   (params.try_shorter_wrapper_block ? "YES" : "NO"),
                    vid, pid);
                switch (retval) {
                case 0:
@@ -1274,6 +1310,9 @@ show_host_msc_test(uint8_t level, uint16_t vid,
                case 16:
                        params.try_all_lun ^= 1;
                        break;
+               case 17:
+                       params.try_shorter_wrapper_block ^= 1;
+                       break;
                case 20:
                        set_defaults(&params);
                        break;
index 3af7b08..e76e5eb 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usb_msc_test.h 260587 2014-01-13 13:27:00Z hselasky $ */
 /*-
  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
  *
@@ -109,6 +109,7 @@ struct usb_msc_params {
        uint8_t try_invalid_scsi_command;
        uint8_t try_invalid_wrapper_block;
        uint8_t try_invalid_max_packet_size;
+       uint8_t try_shorter_wrapper_block;
        uint8_t try_last_lba;
        uint8_t try_abort_data_write;
        uint8_t try_sense_on_error;
index 725b9ea..647f93a 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usbtest.c 254159 2013-08-09 20:08:42Z hselasky $ */
 /*-
  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
  *
@@ -35,7 +35,7 @@
 #include <sys/types.h>
 #include <sys/sysctl.h>
 
-#include <dev/usb/usb_ioctl.h>
+#include <bus/u4b/usb_ioctl.h>
 
 #include "usbtest.h"
 
index 3d6643c..75cb506 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/tools/tools/usbtest/usbtest.h 254159 2013-08-09 20:08:42Z hselasky $ */
 /*-
  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
  *