[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