[Midnightbsd-cvs] src [10052] trunk/sys/dev/usb/gadget: add gadget
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sun May 27 18:43:30 EDT 2018
Revision: 10052
http://svnweb.midnightbsd.org/src/?rev=10052
Author: laffer1
Date: 2018-05-27 18:43:30 -0400 (Sun, 27 May 2018)
Log Message:
-----------
add gadget
Added Paths:
-----------
trunk/sys/dev/usb/gadget/
trunk/sys/dev/usb/gadget/g_audio.c
trunk/sys/dev/usb/gadget/g_audio.h
trunk/sys/dev/usb/gadget/g_keyboard.c
trunk/sys/dev/usb/gadget/g_keyboard.h
trunk/sys/dev/usb/gadget/g_modem.c
trunk/sys/dev/usb/gadget/g_modem.h
trunk/sys/dev/usb/gadget/g_mouse.c
trunk/sys/dev/usb/gadget/g_mouse.h
Added: trunk/sys/dev/usb/gadget/g_audio.c
===================================================================
--- trunk/sys/dev/usb/gadget/g_audio.c (rev 0)
+++ trunk/sys/dev/usb/gadget/g_audio.c 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,614 @@
+/* $MidnightBSD$ */
+/*-
+ * 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.
+ */
+
+/*
+ * 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/param.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/gadget/g_audio.c 253618 2013-07-24 18:32:15Z obrien $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.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/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/usb_cdc.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usb_if.h"
+
+#define USB_DEBUG_VAR g_audio_debug
+#include <dev/usb/usb_debug.h>
+
+#include <dev/usb/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 mtx sc_mtx;
+ 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);
+
+ mtx_init(&sc->sc_mtx, "g_audio", NULL, MTX_DEF);
+
+ usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
+ usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 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_mtx);
+
+ 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]);
+
+ mtx_lock(&sc->sc_mtx);
+
+ 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);
+
+ mtx_unlock(&sc->sc_mtx);
+
+ 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");
+
+ mtx_lock(&sc->sc_mtx);
+ usb_callout_stop(&sc->sc_callout);
+ usb_callout_stop(&sc->sc_watchdog);
+ mtx_unlock(&sc->sc_mtx);
+
+ usbd_transfer_unsetup(sc->sc_xfer, G_AUDIO_N_TRANSFER);
+
+ usb_callout_drain(&sc->sc_callout);
+ usb_callout_drain(&sc->sc_watchdog);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ 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, 0);
+ *plen = 2;
+ *pptr = &sc->sc_volume_limit;
+ } 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 */
+}
Property changes on: trunk/sys/dev/usb/gadget/g_audio.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_audio.h
===================================================================
--- trunk/sys/dev/usb/gadget/g_audio.h (rev 0)
+++ trunk/sys/dev/usb/gadget/g_audio.h 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,41 @@
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/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_ */
Property changes on: trunk/sys/dev/usb/gadget/g_audio.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_keyboard.c
===================================================================
--- trunk/sys/dev/usb/gadget/g_keyboard.c (rev 0)
+++ trunk/sys/dev/usb/gadget/g_keyboard.c 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,412 @@
+/* $MidnightBSD$ */
+/*-
+ * 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.
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/gadget/g_keyboard.c 253618 2013-07-24 18:32:15Z obrien $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.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/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/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usb_if.h"
+
+#define USB_DEBUG_VAR g_keyboard_debug
+#include <dev/usb/usb_debug.h>
+
+#include <dev/usb/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 mtx sc_mtx;
+ 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);
+
+ mtx_init(&sc->sc_mtx, "g_keyboard", NULL, MTX_DEF);
+
+ usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 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_mtx);
+
+ if (error) {
+ DPRINTF("error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+ mtx_lock(&sc->sc_mtx);
+ g_keyboard_timeout_reset(sc);
+ mtx_unlock(&sc->sc_mtx);
+
+ 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");
+
+ mtx_lock(&sc->sc_mtx);
+ usb_callout_stop(&sc->sc_callout);
+ mtx_unlock(&sc->sc_mtx);
+
+ usbd_transfer_unsetup(sc->sc_xfer, G_KEYBOARD_N_TRANSFER);
+
+ usb_callout_drain(&sc->sc_callout);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ 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 */
+}
Property changes on: trunk/sys/dev/usb/gadget/g_keyboard.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_keyboard.h
===================================================================
--- trunk/sys/dev/usb/gadget/g_keyboard.h (rev 0)
+++ trunk/sys/dev/usb/gadget/g_keyboard.h 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,36 @@
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/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_ */
Property changes on: trunk/sys/dev/usb/gadget/g_keyboard.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_modem.c
===================================================================
--- trunk/sys/dev/usb/gadget/g_modem.c (rev 0)
+++ trunk/sys/dev/usb/gadget/g_modem.c 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,545 @@
+/* $MidnightBSD$ */
+/*-
+ * 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.
+ */
+
+/*
+ * 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/param.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/gadget/g_modem.c 253618 2013-07-24 18:32:15Z obrien $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.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/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/usb_cdc.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usb_if.h"
+
+#define USB_DEBUG_VAR g_modem_debug
+#include <dev/usb/usb_debug.h>
+
+#include <dev/usb/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 mtx sc_mtx;
+ 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);
+
+ mtx_init(&sc->sc_mtx, "g_modem", NULL, MTX_DEF);
+
+ usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
+ usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 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_mtx);
+
+ if (error) {
+ DPRINTF("error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+ usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]);
+
+ mtx_lock(&sc->sc_mtx);
+ g_modem_timeout_reset(sc);
+ g_modem_watchdog_reset(sc);
+ mtx_unlock(&sc->sc_mtx);
+
+ 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");
+
+ mtx_lock(&sc->sc_mtx);
+ usb_callout_stop(&sc->sc_callout);
+ usb_callout_stop(&sc->sc_watchdog);
+ mtx_unlock(&sc->sc_mtx);
+
+ usbd_transfer_unsetup(sc->sc_xfer, G_MODEM_N_TRANSFER);
+
+ usb_callout_drain(&sc->sc_callout);
+ usb_callout_drain(&sc->sc_watchdog);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ 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 */
+}
Property changes on: trunk/sys/dev/usb/gadget/g_modem.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_modem.h
===================================================================
--- trunk/sys/dev/usb/gadget/g_modem.h (rev 0)
+++ trunk/sys/dev/usb/gadget/g_modem.h 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,40 @@
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/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_ */
Property changes on: trunk/sys/dev/usb/gadget/g_modem.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_mouse.c
===================================================================
--- trunk/sys/dev/usb/gadget/g_mouse.c (rev 0)
+++ trunk/sys/dev/usb/gadget/g_mouse.c 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,457 @@
+/* $MidnightBSD$ */
+/*-
+ * 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.
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/gadget/g_mouse.c 253618 2013-07-24 18:32:15Z obrien $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.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/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/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usb_if.h"
+
+#define USB_DEBUG_VAR g_mouse_debug
+#include <dev/usb/usb_debug.h>
+
+#include <dev/usb/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 mtx sc_mtx;
+ 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);
+
+ mtx_init(&sc->sc_mtx, "g_mouse", NULL, MTX_DEF);
+
+ usb_callout_init_mtx(&sc->sc_button_press_callout, &sc->sc_mtx, 0);
+ usb_callout_init_mtx(&sc->sc_cursor_update_callout, &sc->sc_mtx, 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_mtx);
+
+ if (error) {
+ DPRINTF("error=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+
+ mtx_lock(&sc->sc_mtx);
+ g_mouse_button_press_timeout_reset(sc);
+ g_mouse_cursor_update_timeout_reset(sc);
+ mtx_unlock(&sc->sc_mtx);
+
+ 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");
+
+ mtx_lock(&sc->sc_mtx);
+ usb_callout_stop(&sc->sc_button_press_callout);
+ usb_callout_stop(&sc->sc_cursor_update_callout);
+ mtx_unlock(&sc->sc_mtx);
+
+ 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);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ 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 */
+}
Property changes on: trunk/sys/dev/usb/gadget/g_mouse.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/usb/gadget/g_mouse.h
===================================================================
--- trunk/sys/dev/usb/gadget/g_mouse.h (rev 0)
+++ trunk/sys/dev/usb/gadget/g_mouse.h 2018-05-27 22:43:30 UTC (rev 10052)
@@ -0,0 +1,37 @@
+/* $MidnightBSD$ */
+/* $FreeBSD: stable/10/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_ */
Property changes on: trunk/sys/dev/usb/gadget/g_mouse.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
More information about the Midnightbsd-cvs
mailing list