146902503SHans Petter Selasky /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
446902503SHans Petter Selasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
546902503SHans Petter Selasky *
646902503SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
746902503SHans Petter Selasky * modification, are permitted provided that the following conditions
846902503SHans Petter Selasky * are met:
946902503SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
1046902503SHans Petter Selasky * notice, this list of conditions and the following disclaimer.
1146902503SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
1246902503SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
1346902503SHans Petter Selasky * documentation and/or other materials provided with the distribution.
1446902503SHans Petter Selasky *
1546902503SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1646902503SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1746902503SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1846902503SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1946902503SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2046902503SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2146902503SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2246902503SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2346902503SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2446902503SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2546902503SHans Petter Selasky * SUCH DAMAGE.
2646902503SHans Petter Selasky */
2746902503SHans Petter Selasky
2846902503SHans Petter Selasky /*
2946902503SHans Petter Selasky * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
3046902503SHans Petter Selasky */
3146902503SHans Petter Selasky
321ae56a1cSDavid E. O'Brien #include <sys/param.h>
3346902503SHans Petter Selasky #include <sys/stdint.h>
3446902503SHans Petter Selasky #include <sys/stddef.h>
3546902503SHans Petter Selasky #include <sys/queue.h>
3646902503SHans Petter Selasky #include <sys/systm.h>
3746902503SHans Petter Selasky #include <sys/kernel.h>
3846902503SHans Petter Selasky #include <sys/bus.h>
3946902503SHans Petter Selasky #include <sys/linker_set.h>
4046902503SHans Petter Selasky #include <sys/module.h>
4146902503SHans Petter Selasky #include <sys/lock.h>
4246902503SHans Petter Selasky #include <sys/mutex.h>
4346902503SHans Petter Selasky #include <sys/condvar.h>
4446902503SHans Petter Selasky #include <sys/sysctl.h>
4546902503SHans Petter Selasky #include <sys/sx.h>
4646902503SHans Petter Selasky #include <sys/unistd.h>
4746902503SHans Petter Selasky #include <sys/callout.h>
4846902503SHans Petter Selasky #include <sys/malloc.h>
4946902503SHans Petter Selasky #include <sys/priv.h>
5046902503SHans Petter Selasky
5146902503SHans Petter Selasky #include <dev/usb/usb.h>
5246902503SHans Petter Selasky #include <dev/usb/usbdi.h>
5346902503SHans Petter Selasky #include <dev/usb/usbdi_util.h>
5446902503SHans Petter Selasky #include <dev/usb/usbhid.h>
5546902503SHans Petter Selasky #include "usb_if.h"
5646902503SHans Petter Selasky
5746902503SHans Petter Selasky #define USB_DEBUG_VAR g_mouse_debug
5846902503SHans Petter Selasky #include <dev/usb/usb_debug.h>
5946902503SHans Petter Selasky
6046902503SHans Petter Selasky #include <dev/usb/gadget/g_mouse.h>
6146902503SHans Petter Selasky
62f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, g_mouse, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
63f8d2b1f3SPawel Biernacki "USB mouse gadget");
6446902503SHans Petter Selasky
6546902503SHans Petter Selasky #ifdef USB_DEBUG
6646902503SHans Petter Selasky static int g_mouse_debug = 0;
6746902503SHans Petter Selasky
68ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, debug, CTLFLAG_RWTUN,
6946902503SHans Petter Selasky &g_mouse_debug, 0, "Debug level");
7046902503SHans Petter Selasky #endif
7146902503SHans Petter Selasky
7246902503SHans Petter Selasky static int g_mouse_mode = 0;
7346902503SHans Petter Selasky
74ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, mode, CTLFLAG_RWTUN,
7546902503SHans Petter Selasky &g_mouse_mode, 0, "Mode selection");
7646902503SHans Petter Selasky
7746902503SHans Petter Selasky static int g_mouse_button_press_interval = 0;
7846902503SHans Petter Selasky
79ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, button_press_interval, CTLFLAG_RWTUN,
8046902503SHans Petter Selasky &g_mouse_button_press_interval, 0, "Mouse button update interval in milliseconds");
8146902503SHans Petter Selasky
8246902503SHans Petter Selasky static int g_mouse_cursor_update_interval = 1023;
8346902503SHans Petter Selasky
84ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, cursor_update_interval, CTLFLAG_RWTUN,
8546902503SHans Petter Selasky &g_mouse_cursor_update_interval, 0, "Mouse cursor update interval in milliseconds");
8646902503SHans Petter Selasky
8746902503SHans Petter Selasky static int g_mouse_cursor_radius = 128;
8846902503SHans Petter Selasky
89ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_mouse, OID_AUTO, cursor_radius, CTLFLAG_RWTUN,
9046902503SHans Petter Selasky &g_mouse_cursor_radius, 0, "Mouse cursor radius in pixels");
9146902503SHans Petter Selasky
9246902503SHans Petter Selasky struct g_mouse_data {
9346902503SHans Petter Selasky uint8_t buttons;
9446902503SHans Petter Selasky #define BUT_0 0x01
9546902503SHans Petter Selasky #define BUT_1 0x02
9646902503SHans Petter Selasky #define BUT_2 0x04
9746902503SHans Petter Selasky int8_t dx;
9846902503SHans Petter Selasky int8_t dy;
9946902503SHans Petter Selasky int8_t dz;
10046902503SHans Petter Selasky };
10146902503SHans Petter Selasky
10246902503SHans Petter Selasky enum {
10346902503SHans Petter Selasky G_MOUSE_INTR_DT,
10446902503SHans Petter Selasky G_MOUSE_N_TRANSFER,
10546902503SHans Petter Selasky };
10646902503SHans Petter Selasky
10746902503SHans Petter Selasky struct g_mouse_softc {
10846902503SHans Petter Selasky struct mtx sc_mtx;
10946902503SHans Petter Selasky struct usb_callout sc_button_press_callout;
11046902503SHans Petter Selasky struct usb_callout sc_cursor_update_callout;
11146902503SHans Petter Selasky struct g_mouse_data sc_data;
11246902503SHans Petter Selasky struct usb_xfer *sc_xfer[G_MOUSE_N_TRANSFER];
11346902503SHans Petter Selasky
11446902503SHans Petter Selasky int sc_mode;
11546902503SHans Petter Selasky int sc_radius;
11646902503SHans Petter Selasky int sc_last_x_state;
11746902503SHans Petter Selasky int sc_last_y_state;
11846902503SHans Petter Selasky int sc_curr_x_state;
11946902503SHans Petter Selasky int sc_curr_y_state;
12046902503SHans Petter Selasky int sc_tick;
12146902503SHans Petter Selasky
12246902503SHans Petter Selasky uint8_t sc_do_cursor_update;
12346902503SHans Petter Selasky uint8_t sc_do_button_update;
12446902503SHans Petter Selasky };
12546902503SHans Petter Selasky
12646902503SHans Petter Selasky static device_probe_t g_mouse_probe;
12746902503SHans Petter Selasky static device_attach_t g_mouse_attach;
12846902503SHans Petter Selasky static device_detach_t g_mouse_detach;
12946902503SHans Petter Selasky static usb_handle_request_t g_mouse_handle_request;
13046902503SHans Petter Selasky static usb_callback_t g_mouse_intr_callback;
13146902503SHans Petter Selasky
13246902503SHans Petter Selasky static device_method_t g_mouse_methods[] = {
13346902503SHans Petter Selasky /* USB interface */
13446902503SHans Petter Selasky DEVMETHOD(usb_handle_request, g_mouse_handle_request),
13546902503SHans Petter Selasky
13646902503SHans Petter Selasky /* Device interface */
13746902503SHans Petter Selasky DEVMETHOD(device_probe, g_mouse_probe),
13846902503SHans Petter Selasky DEVMETHOD(device_attach, g_mouse_attach),
13946902503SHans Petter Selasky DEVMETHOD(device_detach, g_mouse_detach),
14046902503SHans Petter Selasky
14146902503SHans Petter Selasky DEVMETHOD_END
14246902503SHans Petter Selasky };
14346902503SHans Petter Selasky
14446902503SHans Petter Selasky static driver_t g_mouse_driver = {
14546902503SHans Petter Selasky .name = "g_mouse",
14646902503SHans Petter Selasky .methods = g_mouse_methods,
14746902503SHans Petter Selasky .size = sizeof(struct g_mouse_softc),
14846902503SHans Petter Selasky };
14946902503SHans Petter Selasky
150bc9372d7SJohn Baldwin DRIVER_MODULE(g_mouse, uhub, g_mouse_driver, 0, 0);
15146902503SHans Petter Selasky MODULE_DEPEND(g_mouse, usb, 1, 1, 1);
15246902503SHans Petter Selasky
15346902503SHans Petter Selasky static const struct usb_config g_mouse_config[G_MOUSE_N_TRANSFER] = {
15446902503SHans Petter Selasky [G_MOUSE_INTR_DT] = {
15546902503SHans Petter Selasky .type = UE_INTERRUPT,
15646902503SHans Petter Selasky .endpoint = UE_ADDR_ANY,
15746902503SHans Petter Selasky .direction = UE_DIR_IN,
15846902503SHans Petter Selasky .flags = {.ext_buffer = 1,.pipe_bof = 1,},
15946902503SHans Petter Selasky .bufsize = sizeof(struct g_mouse_data),
16046902503SHans Petter Selasky .callback = &g_mouse_intr_callback,
16146902503SHans Petter Selasky .frames = 1,
16246902503SHans Petter Selasky .usb_mode = USB_MODE_DEVICE,
16346902503SHans Petter Selasky },
16446902503SHans Petter Selasky };
16546902503SHans Petter Selasky
16646902503SHans Petter Selasky static void g_mouse_button_press_timeout(void *arg);
16746902503SHans Petter Selasky static void g_mouse_cursor_update_timeout(void *arg);
16846902503SHans Petter Selasky
16946902503SHans Petter Selasky static void
g_mouse_button_press_timeout_reset(struct g_mouse_softc * sc)17046902503SHans Petter Selasky g_mouse_button_press_timeout_reset(struct g_mouse_softc *sc)
17146902503SHans Petter Selasky {
17246902503SHans Petter Selasky int i = g_mouse_button_press_interval;
17346902503SHans Petter Selasky
17446902503SHans Petter Selasky if (i <= 0) {
17546902503SHans Petter Selasky sc->sc_data.buttons = 0;
17646902503SHans Petter Selasky sc->sc_do_button_update = 0;
17746902503SHans Petter Selasky } else {
17846902503SHans Petter Selasky sc->sc_do_button_update = 1;
17946902503SHans Petter Selasky }
18046902503SHans Petter Selasky
18146902503SHans Petter Selasky if ((i <= 0) || (i > 1023))
18246902503SHans Petter Selasky i = 1023;
18346902503SHans Petter Selasky
18446902503SHans Petter Selasky i = USB_MS_TO_TICKS(i);
18546902503SHans Petter Selasky
18646902503SHans Petter Selasky usb_callout_reset(&sc->sc_button_press_callout, i,
18746902503SHans Petter Selasky &g_mouse_button_press_timeout, sc);
18846902503SHans Petter Selasky }
18946902503SHans Petter Selasky
19046902503SHans Petter Selasky static void
g_mouse_cursor_update_timeout_reset(struct g_mouse_softc * sc)19146902503SHans Petter Selasky g_mouse_cursor_update_timeout_reset(struct g_mouse_softc *sc)
19246902503SHans Petter Selasky {
19346902503SHans Petter Selasky int i = g_mouse_cursor_update_interval;
19446902503SHans Petter Selasky
19546902503SHans Petter Selasky if (i <= 0) {
19646902503SHans Petter Selasky sc->sc_data.dx = 0;
19746902503SHans Petter Selasky sc->sc_data.dy = 0;
19846902503SHans Petter Selasky sc->sc_do_cursor_update = 0;
19946902503SHans Petter Selasky sc->sc_tick = 0;
20046902503SHans Petter Selasky } else {
20146902503SHans Petter Selasky sc->sc_do_cursor_update = 1;
20246902503SHans Petter Selasky }
20346902503SHans Petter Selasky
20446902503SHans Petter Selasky if ((i <= 0) || (i > 1023))
20546902503SHans Petter Selasky i = 1023;
20646902503SHans Petter Selasky
20746902503SHans Petter Selasky i = USB_MS_TO_TICKS(i);
20846902503SHans Petter Selasky
20946902503SHans Petter Selasky usb_callout_reset(&sc->sc_cursor_update_callout, i,
21046902503SHans Petter Selasky &g_mouse_cursor_update_timeout, sc);
21146902503SHans Petter Selasky }
21246902503SHans Petter Selasky
21346902503SHans Petter Selasky static void
g_mouse_update_mode_radius(struct g_mouse_softc * sc)21446902503SHans Petter Selasky g_mouse_update_mode_radius(struct g_mouse_softc *sc)
21546902503SHans Petter Selasky {
21646902503SHans Petter Selasky sc->sc_mode = g_mouse_mode;
21746902503SHans Petter Selasky sc->sc_radius = g_mouse_cursor_radius;
21846902503SHans Petter Selasky
21946902503SHans Petter Selasky if (sc->sc_radius < 0)
22046902503SHans Petter Selasky sc->sc_radius = 0;
22146902503SHans Petter Selasky else if (sc->sc_radius > 1023)
22246902503SHans Petter Selasky sc->sc_radius = 1023;
22346902503SHans Petter Selasky }
22446902503SHans Petter Selasky
22546902503SHans Petter Selasky static void
g_mouse_button_press_timeout(void * arg)22646902503SHans Petter Selasky g_mouse_button_press_timeout(void *arg)
22746902503SHans Petter Selasky {
22846902503SHans Petter Selasky struct g_mouse_softc *sc = arg;
22946902503SHans Petter Selasky
23046902503SHans Petter Selasky g_mouse_update_mode_radius(sc);
23146902503SHans Petter Selasky
23246902503SHans Petter Selasky DPRINTFN(11, "Timeout %p (button press)\n", sc->sc_xfer[G_MOUSE_INTR_DT]);
23346902503SHans Petter Selasky
23446902503SHans Petter Selasky g_mouse_button_press_timeout_reset(sc);
23546902503SHans Petter Selasky
23646902503SHans Petter Selasky usbd_transfer_start(sc->sc_xfer[G_MOUSE_INTR_DT]);
23746902503SHans Petter Selasky }
23846902503SHans Petter Selasky
23946902503SHans Petter Selasky static void
g_mouse_cursor_update_timeout(void * arg)24046902503SHans Petter Selasky g_mouse_cursor_update_timeout(void *arg)
24146902503SHans Petter Selasky {
24246902503SHans Petter Selasky struct g_mouse_softc *sc = arg;
24346902503SHans Petter Selasky
24446902503SHans Petter Selasky g_mouse_update_mode_radius(sc);
24546902503SHans Petter Selasky
24646902503SHans Petter Selasky DPRINTFN(11, "Timeout %p (cursor update)\n", sc->sc_xfer[G_MOUSE_INTR_DT]);
24746902503SHans Petter Selasky
24846902503SHans Petter Selasky g_mouse_cursor_update_timeout_reset(sc);
24946902503SHans Petter Selasky
25046902503SHans Petter Selasky usbd_transfer_start(sc->sc_xfer[G_MOUSE_INTR_DT]);
25146902503SHans Petter Selasky }
25246902503SHans Petter Selasky
25346902503SHans Petter Selasky static int
g_mouse_probe(device_t dev)25446902503SHans Petter Selasky g_mouse_probe(device_t dev)
25546902503SHans Petter Selasky {
25646902503SHans Petter Selasky struct usb_attach_arg *uaa = device_get_ivars(dev);
25746902503SHans Petter Selasky
25846902503SHans Petter Selasky DPRINTFN(11, "\n");
25946902503SHans Petter Selasky
26046902503SHans Petter Selasky if (uaa->usb_mode != USB_MODE_DEVICE)
26146902503SHans Petter Selasky return (ENXIO);
26246902503SHans Petter Selasky
26346902503SHans Petter Selasky if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
26446902503SHans Petter Selasky (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
26546902503SHans Petter Selasky (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))
26646902503SHans Petter Selasky return (0);
26746902503SHans Petter Selasky
26846902503SHans Petter Selasky return (ENXIO);
26946902503SHans Petter Selasky }
27046902503SHans Petter Selasky
27146902503SHans Petter Selasky static int
g_mouse_attach(device_t dev)27246902503SHans Petter Selasky g_mouse_attach(device_t dev)
27346902503SHans Petter Selasky {
27446902503SHans Petter Selasky struct g_mouse_softc *sc = device_get_softc(dev);
27546902503SHans Petter Selasky struct usb_attach_arg *uaa = device_get_ivars(dev);
27646902503SHans Petter Selasky int error;
27746902503SHans Petter Selasky
27846902503SHans Petter Selasky DPRINTFN(11, "\n");
27946902503SHans Petter Selasky
28046902503SHans Petter Selasky device_set_usb_desc(dev);
28146902503SHans Petter Selasky
28246902503SHans Petter Selasky mtx_init(&sc->sc_mtx, "g_mouse", NULL, MTX_DEF);
28346902503SHans Petter Selasky
28446902503SHans Petter Selasky usb_callout_init_mtx(&sc->sc_button_press_callout, &sc->sc_mtx, 0);
28546902503SHans Petter Selasky usb_callout_init_mtx(&sc->sc_cursor_update_callout, &sc->sc_mtx, 0);
28646902503SHans Petter Selasky
28746902503SHans Petter Selasky sc->sc_mode = G_MOUSE_MODE_SILENT;
28846902503SHans Petter Selasky
28946902503SHans Petter Selasky error = usbd_transfer_setup(uaa->device,
29046902503SHans Petter Selasky &uaa->info.bIfaceIndex, sc->sc_xfer, g_mouse_config,
29146902503SHans Petter Selasky G_MOUSE_N_TRANSFER, sc, &sc->sc_mtx);
29246902503SHans Petter Selasky
29346902503SHans Petter Selasky if (error) {
29446902503SHans Petter Selasky DPRINTF("error=%s\n", usbd_errstr(error));
29546902503SHans Petter Selasky goto detach;
29646902503SHans Petter Selasky }
29746902503SHans Petter Selasky
29846902503SHans Petter Selasky mtx_lock(&sc->sc_mtx);
29946902503SHans Petter Selasky g_mouse_button_press_timeout_reset(sc);
30046902503SHans Petter Selasky g_mouse_cursor_update_timeout_reset(sc);
30146902503SHans Petter Selasky mtx_unlock(&sc->sc_mtx);
30246902503SHans Petter Selasky
30346902503SHans Petter Selasky return (0); /* success */
30446902503SHans Petter Selasky
30546902503SHans Petter Selasky detach:
30646902503SHans Petter Selasky g_mouse_detach(dev);
30746902503SHans Petter Selasky
30846902503SHans Petter Selasky return (ENXIO); /* error */
30946902503SHans Petter Selasky }
31046902503SHans Petter Selasky
31146902503SHans Petter Selasky static int
g_mouse_detach(device_t dev)31246902503SHans Petter Selasky g_mouse_detach(device_t dev)
31346902503SHans Petter Selasky {
31446902503SHans Petter Selasky struct g_mouse_softc *sc = device_get_softc(dev);
31546902503SHans Petter Selasky
31646902503SHans Petter Selasky DPRINTF("\n");
31746902503SHans Petter Selasky
31846902503SHans Petter Selasky mtx_lock(&sc->sc_mtx);
31946902503SHans Petter Selasky usb_callout_stop(&sc->sc_button_press_callout);
32046902503SHans Petter Selasky usb_callout_stop(&sc->sc_cursor_update_callout);
32146902503SHans Petter Selasky mtx_unlock(&sc->sc_mtx);
32246902503SHans Petter Selasky
32346902503SHans Petter Selasky usbd_transfer_unsetup(sc->sc_xfer, G_MOUSE_N_TRANSFER);
32446902503SHans Petter Selasky
32546902503SHans Petter Selasky usb_callout_drain(&sc->sc_button_press_callout);
32646902503SHans Petter Selasky usb_callout_drain(&sc->sc_cursor_update_callout);
32746902503SHans Petter Selasky
32846902503SHans Petter Selasky mtx_destroy(&sc->sc_mtx);
32946902503SHans Petter Selasky
33046902503SHans Petter Selasky return (0);
33146902503SHans Petter Selasky }
33246902503SHans Petter Selasky
33346902503SHans Petter Selasky static void
g_mouse_intr_callback(struct usb_xfer * xfer,usb_error_t error)33446902503SHans Petter Selasky g_mouse_intr_callback(struct usb_xfer *xfer, usb_error_t error)
33546902503SHans Petter Selasky {
33646902503SHans Petter Selasky struct g_mouse_softc *sc = usbd_xfer_softc(xfer);
33746902503SHans Petter Selasky int actlen;
33846902503SHans Petter Selasky int aframes;
33946902503SHans Petter Selasky int dx;
34046902503SHans Petter Selasky int dy;
34146902503SHans Petter Selasky int radius;
34246902503SHans Petter Selasky
34346902503SHans Petter Selasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
34446902503SHans Petter Selasky
34546902503SHans Petter Selasky DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
34646902503SHans Petter Selasky USB_GET_STATE(xfer), aframes, actlen);
34746902503SHans Petter Selasky
34846902503SHans Petter Selasky switch (USB_GET_STATE(xfer)) {
34946902503SHans Petter Selasky case USB_ST_TRANSFERRED:
35046902503SHans Petter Selasky if (!(sc->sc_do_cursor_update || sc->sc_do_button_update))
35146902503SHans Petter Selasky break;
35246902503SHans Petter Selasky
35346902503SHans Petter Selasky case USB_ST_SETUP:
35446902503SHans Petter Selasky tr_setup:
35546902503SHans Petter Selasky
35646902503SHans Petter Selasky if (sc->sc_do_cursor_update) {
35746902503SHans Petter Selasky sc->sc_do_cursor_update = 0;
35846902503SHans Petter Selasky sc->sc_tick += 80;
35946902503SHans Petter Selasky if ((sc->sc_tick < 0) || (sc->sc_tick > 7999))
36046902503SHans Petter Selasky sc->sc_tick = 0;
36146902503SHans Petter Selasky }
36246902503SHans Petter Selasky
36346902503SHans Petter Selasky if (sc->sc_do_button_update) {
36446902503SHans Petter Selasky sc->sc_do_button_update = 0;
36546902503SHans Petter Selasky sc->sc_data.buttons ^= BUT_0;
36646902503SHans Petter Selasky }
36746902503SHans Petter Selasky
36846902503SHans Petter Selasky radius = sc->sc_radius;
36946902503SHans Petter Selasky
37046902503SHans Petter Selasky switch (sc->sc_mode) {
37146902503SHans Petter Selasky case G_MOUSE_MODE_SILENT:
37246902503SHans Petter Selasky sc->sc_data.buttons = 0;
37346902503SHans Petter Selasky break;
37446902503SHans Petter Selasky case G_MOUSE_MODE_SPIRAL:
37546902503SHans Petter Selasky radius = (radius * (8000-sc->sc_tick)) / 8000;
37646902503SHans Petter Selasky case G_MOUSE_MODE_CIRCLE:
37746902503SHans Petter Selasky /* TODO */
37846902503SHans Petter Selasky sc->sc_curr_y_state = 0;
37946902503SHans Petter Selasky sc->sc_curr_x_state = 0;
38046902503SHans Petter Selasky break;
38146902503SHans Petter Selasky case G_MOUSE_MODE_BOX:
38246902503SHans Petter Selasky if (sc->sc_tick < 2000) {
38346902503SHans Petter Selasky sc->sc_curr_x_state = (sc->sc_tick * radius) / 2000;
38446902503SHans Petter Selasky sc->sc_curr_y_state = 0;
38546902503SHans Petter Selasky } else if (sc->sc_tick < 4000) {
38646902503SHans Petter Selasky sc->sc_curr_x_state = radius;
38746902503SHans Petter Selasky sc->sc_curr_y_state = -(((sc->sc_tick - 2000) * radius) / 2000);
38846902503SHans Petter Selasky } else if (sc->sc_tick < 6000) {
38946902503SHans Petter Selasky sc->sc_curr_x_state = radius - (((sc->sc_tick - 4000) * radius) / 2000);
39046902503SHans Petter Selasky sc->sc_curr_y_state = -radius;
39146902503SHans Petter Selasky } else {
39246902503SHans Petter Selasky sc->sc_curr_x_state = 0;
39346902503SHans Petter Selasky sc->sc_curr_y_state = -radius + (((sc->sc_tick - 6000) * radius) / 2000);
39446902503SHans Petter Selasky }
39546902503SHans Petter Selasky break;
39646902503SHans Petter Selasky default:
39746902503SHans Petter Selasky break;
39846902503SHans Petter Selasky }
39946902503SHans Petter Selasky
40046902503SHans Petter Selasky dx = sc->sc_curr_x_state - sc->sc_last_x_state;
40146902503SHans Petter Selasky dy = sc->sc_curr_y_state - sc->sc_last_y_state;
40246902503SHans Petter Selasky
40346902503SHans Petter Selasky if (dx < -63)
40446902503SHans Petter Selasky dx = -63;
40546902503SHans Petter Selasky else if (dx > 63)
40646902503SHans Petter Selasky dx = 63;
40746902503SHans Petter Selasky
40846902503SHans Petter Selasky if (dy < -63)
40946902503SHans Petter Selasky dy = -63;
41046902503SHans Petter Selasky else if (dy > 63)
41146902503SHans Petter Selasky dy = 63;
41246902503SHans Petter Selasky
41346902503SHans Petter Selasky sc->sc_last_x_state += dx;
41446902503SHans Petter Selasky sc->sc_last_y_state += dy;
41546902503SHans Petter Selasky
41646902503SHans Petter Selasky sc->sc_data.dx = dx;
41746902503SHans Petter Selasky sc->sc_data.dy = dy;
41846902503SHans Petter Selasky
41946902503SHans Petter Selasky usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data, sizeof(sc->sc_data));
42046902503SHans Petter Selasky usbd_xfer_set_frames(xfer, 1);
42146902503SHans Petter Selasky usbd_transfer_submit(xfer);
42246902503SHans Petter Selasky break;
42346902503SHans Petter Selasky
42446902503SHans Petter Selasky default: /* Error */
42546902503SHans Petter Selasky DPRINTF("error=%s\n", usbd_errstr(error));
42646902503SHans Petter Selasky
42746902503SHans Petter Selasky if (error != USB_ERR_CANCELLED) {
42846902503SHans Petter Selasky /* try to clear stall first */
42946902503SHans Petter Selasky usbd_xfer_set_stall(xfer);
43046902503SHans Petter Selasky goto tr_setup;
43146902503SHans Petter Selasky }
43246902503SHans Petter Selasky break;
43346902503SHans Petter Selasky }
43446902503SHans Petter Selasky }
43546902503SHans Petter Selasky
43646902503SHans Petter Selasky static int
g_mouse_handle_request(device_t dev,const void * preq,void ** pptr,uint16_t * plen,uint16_t offset,uint8_t * pstate)43746902503SHans Petter Selasky g_mouse_handle_request(device_t dev,
43846902503SHans Petter Selasky const void *preq, void **pptr, uint16_t *plen,
43946902503SHans Petter Selasky uint16_t offset, uint8_t *pstate)
44046902503SHans Petter Selasky {
44146902503SHans Petter Selasky const struct usb_device_request *req = preq;
44246902503SHans Petter Selasky uint8_t is_complete = *pstate;
44346902503SHans Petter Selasky
44446902503SHans Petter Selasky if (!is_complete) {
44546902503SHans Petter Selasky if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
44646902503SHans Petter Selasky (req->bRequest == UR_SET_PROTOCOL) &&
44746902503SHans Petter Selasky (req->wValue[0] == 0x00) &&
44846902503SHans Petter Selasky (req->wValue[1] == 0x00)) {
44946902503SHans Petter Selasky *plen = 0;
45046902503SHans Petter Selasky return (0);
45146902503SHans Petter Selasky }
45246902503SHans Petter Selasky }
45346902503SHans Petter Selasky return (ENXIO); /* use builtin handler */
45446902503SHans Petter Selasky }
455