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_keyboard_debug
5846902503SHans Petter Selasky #include <dev/usb/usb_debug.h>
5946902503SHans Petter Selasky
6046902503SHans Petter Selasky #include <dev/usb/gadget/g_keyboard.h>
6146902503SHans Petter Selasky
62f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, g_keyboard,
63f8d2b1f3SPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
64f8d2b1f3SPawel Biernacki "USB keyboard gadget");
6546902503SHans Petter Selasky
6646902503SHans Petter Selasky #ifdef USB_DEBUG
6746902503SHans Petter Selasky static int g_keyboard_debug = 0;
6846902503SHans Petter Selasky
69ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, debug, CTLFLAG_RWTUN,
7046902503SHans Petter Selasky &g_keyboard_debug, 0, "Debug level");
7146902503SHans Petter Selasky #endif
7246902503SHans Petter Selasky
7346902503SHans Petter Selasky static int g_keyboard_mode = 0;
7446902503SHans Petter Selasky
75ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, mode, CTLFLAG_RWTUN,
7646902503SHans Petter Selasky &g_keyboard_mode, 0, "Mode selection");
7746902503SHans Petter Selasky
7846902503SHans Petter Selasky static int g_keyboard_key_press_interval = 1000;
7946902503SHans Petter Selasky
80ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, key_press_interval, CTLFLAG_RWTUN,
8146902503SHans Petter Selasky &g_keyboard_key_press_interval, 0, "Key Press Interval in milliseconds");
8246902503SHans Petter Selasky
8346902503SHans Petter Selasky static char g_keyboard_key_press_pattern[G_KEYBOARD_MAX_STRLEN];
8446902503SHans Petter Selasky
8546902503SHans Petter Selasky SYSCTL_STRING(_hw_usb_g_keyboard, OID_AUTO, key_press_pattern, CTLFLAG_RW,
8646902503SHans Petter Selasky g_keyboard_key_press_pattern, sizeof(g_keyboard_key_press_pattern),
8746902503SHans Petter Selasky "Key Press Patterns");
8846902503SHans Petter Selasky
8946902503SHans Petter Selasky #define UPROTO_BOOT_KEYBOARD 1
9046902503SHans Petter Selasky
9146902503SHans Petter Selasky #define G_KEYBOARD_NMOD 8 /* units */
9246902503SHans Petter Selasky #define G_KEYBOARD_NKEYCODE 6 /* units */
9346902503SHans Petter Selasky
9446902503SHans Petter Selasky struct g_keyboard_data {
9546902503SHans Petter Selasky uint8_t modifiers;
9646902503SHans Petter Selasky #define MOD_CONTROL_L 0x01
9746902503SHans Petter Selasky #define MOD_CONTROL_R 0x10
9846902503SHans Petter Selasky #define MOD_SHIFT_L 0x02
9946902503SHans Petter Selasky #define MOD_SHIFT_R 0x20
10046902503SHans Petter Selasky #define MOD_ALT_L 0x04
10146902503SHans Petter Selasky #define MOD_ALT_R 0x40
10246902503SHans Petter Selasky #define MOD_WIN_L 0x08
10346902503SHans Petter Selasky #define MOD_WIN_R 0x80
10446902503SHans Petter Selasky uint8_t reserved;
10546902503SHans Petter Selasky uint8_t keycode[G_KEYBOARD_NKEYCODE];
10646902503SHans Petter Selasky };
10746902503SHans Petter Selasky
10846902503SHans Petter Selasky enum {
10946902503SHans Petter Selasky G_KEYBOARD_INTR_DT,
11046902503SHans Petter Selasky G_KEYBOARD_N_TRANSFER,
11146902503SHans Petter Selasky };
11246902503SHans Petter Selasky
11346902503SHans Petter Selasky struct g_keyboard_softc {
11446902503SHans Petter Selasky struct mtx sc_mtx;
11546902503SHans Petter Selasky struct usb_callout sc_callout;
11646902503SHans Petter Selasky struct g_keyboard_data sc_data[2];
11746902503SHans Petter Selasky struct usb_xfer *sc_xfer[G_KEYBOARD_N_TRANSFER];
11846902503SHans Petter Selasky
11946902503SHans Petter Selasky int sc_mode;
12046902503SHans Petter Selasky int sc_state;
12146902503SHans Petter Selasky int sc_pattern_len;
12246902503SHans Petter Selasky
12346902503SHans Petter Selasky char sc_pattern[G_KEYBOARD_MAX_STRLEN];
12446902503SHans Petter Selasky
12546902503SHans Petter Selasky uint8_t sc_led_state[4];
12646902503SHans Petter Selasky };
12746902503SHans Petter Selasky
12846902503SHans Petter Selasky static device_probe_t g_keyboard_probe;
12946902503SHans Petter Selasky static device_attach_t g_keyboard_attach;
13046902503SHans Petter Selasky static device_detach_t g_keyboard_detach;
13146902503SHans Petter Selasky static usb_handle_request_t g_keyboard_handle_request;
13246902503SHans Petter Selasky static usb_callback_t g_keyboard_intr_callback;
13346902503SHans Petter Selasky
13446902503SHans Petter Selasky static device_method_t g_keyboard_methods[] = {
13546902503SHans Petter Selasky /* USB interface */
13646902503SHans Petter Selasky DEVMETHOD(usb_handle_request, g_keyboard_handle_request),
13746902503SHans Petter Selasky
13846902503SHans Petter Selasky /* Device interface */
13946902503SHans Petter Selasky DEVMETHOD(device_probe, g_keyboard_probe),
14046902503SHans Petter Selasky DEVMETHOD(device_attach, g_keyboard_attach),
14146902503SHans Petter Selasky DEVMETHOD(device_detach, g_keyboard_detach),
14246902503SHans Petter Selasky
14346902503SHans Petter Selasky DEVMETHOD_END
14446902503SHans Petter Selasky };
14546902503SHans Petter Selasky
14646902503SHans Petter Selasky static driver_t g_keyboard_driver = {
14746902503SHans Petter Selasky .name = "g_keyboard",
14846902503SHans Petter Selasky .methods = g_keyboard_methods,
14946902503SHans Petter Selasky .size = sizeof(struct g_keyboard_softc),
15046902503SHans Petter Selasky };
15146902503SHans Petter Selasky
152bc9372d7SJohn Baldwin DRIVER_MODULE(g_keyboard, uhub, g_keyboard_driver, 0, 0);
15346902503SHans Petter Selasky MODULE_DEPEND(g_keyboard, usb, 1, 1, 1);
15446902503SHans Petter Selasky
15546902503SHans Petter Selasky static const struct usb_config g_keyboard_config[G_KEYBOARD_N_TRANSFER] = {
15646902503SHans Petter Selasky [G_KEYBOARD_INTR_DT] = {
15746902503SHans Petter Selasky .type = UE_INTERRUPT,
15846902503SHans Petter Selasky .endpoint = UE_ADDR_ANY,
15946902503SHans Petter Selasky .direction = UE_DIR_IN,
16046902503SHans Petter Selasky .flags = {.ext_buffer = 1,.pipe_bof = 1,},
16146902503SHans Petter Selasky .bufsize = sizeof(struct g_keyboard_data),
16246902503SHans Petter Selasky .callback = &g_keyboard_intr_callback,
16346902503SHans Petter Selasky .frames = 2,
16446902503SHans Petter Selasky .usb_mode = USB_MODE_DEVICE,
16546902503SHans Petter Selasky },
16646902503SHans Petter Selasky };
16746902503SHans Petter Selasky
16846902503SHans Petter Selasky static void g_keyboard_timeout(void *arg);
16946902503SHans Petter Selasky
17046902503SHans Petter Selasky static void
g_keyboard_timeout_reset(struct g_keyboard_softc * sc)17146902503SHans Petter Selasky g_keyboard_timeout_reset(struct g_keyboard_softc *sc)
17246902503SHans Petter Selasky {
17346902503SHans Petter Selasky int i = g_keyboard_key_press_interval;
17446902503SHans Petter Selasky
17546902503SHans Petter Selasky if (i <= 0)
17646902503SHans Petter Selasky i = 1;
17746902503SHans Petter Selasky else if (i > 1023)
17846902503SHans Petter Selasky i = 1023;
17946902503SHans Petter Selasky
18046902503SHans Petter Selasky i = USB_MS_TO_TICKS(i);
18146902503SHans Petter Selasky
18246902503SHans Petter Selasky usb_callout_reset(&sc->sc_callout, i, &g_keyboard_timeout, sc);
18346902503SHans Petter Selasky }
18446902503SHans Petter Selasky
18546902503SHans Petter Selasky static void
g_keyboard_timeout(void * arg)18646902503SHans Petter Selasky g_keyboard_timeout(void *arg)
18746902503SHans Petter Selasky {
18846902503SHans Petter Selasky struct g_keyboard_softc *sc = arg;
18946902503SHans Petter Selasky
19046902503SHans Petter Selasky sc->sc_mode = g_keyboard_mode;
19146902503SHans Petter Selasky
19246902503SHans Petter Selasky memcpy(sc->sc_pattern, g_keyboard_key_press_pattern, sizeof(sc->sc_pattern));
19346902503SHans Petter Selasky
19446902503SHans Petter Selasky sc->sc_pattern[G_KEYBOARD_MAX_STRLEN - 1] = 0;
19546902503SHans Petter Selasky
19646902503SHans Petter Selasky sc->sc_pattern_len = strlen(sc->sc_pattern);
19746902503SHans Petter Selasky
19846902503SHans Petter Selasky DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_KEYBOARD_INTR_DT]);
19946902503SHans Petter Selasky
20046902503SHans Petter Selasky usbd_transfer_start(sc->sc_xfer[G_KEYBOARD_INTR_DT]);
20146902503SHans Petter Selasky
20246902503SHans Petter Selasky g_keyboard_timeout_reset(sc);
20346902503SHans Petter Selasky }
20446902503SHans Petter Selasky
20546902503SHans Petter Selasky static int
g_keyboard_probe(device_t dev)20646902503SHans Petter Selasky g_keyboard_probe(device_t dev)
20746902503SHans Petter Selasky {
20846902503SHans Petter Selasky struct usb_attach_arg *uaa = device_get_ivars(dev);
20946902503SHans Petter Selasky
21046902503SHans Petter Selasky DPRINTFN(11, "\n");
21146902503SHans Petter Selasky
21246902503SHans Petter Selasky if (uaa->usb_mode != USB_MODE_DEVICE)
21346902503SHans Petter Selasky return (ENXIO);
21446902503SHans Petter Selasky
21546902503SHans Petter Selasky if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
21646902503SHans Petter Selasky (uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
21746902503SHans Petter Selasky (uaa->info.bInterfaceProtocol == UPROTO_BOOT_KEYBOARD))
21846902503SHans Petter Selasky return (0);
21946902503SHans Petter Selasky
22046902503SHans Petter Selasky return (ENXIO);
22146902503SHans Petter Selasky }
22246902503SHans Petter Selasky
22346902503SHans Petter Selasky static int
g_keyboard_attach(device_t dev)22446902503SHans Petter Selasky g_keyboard_attach(device_t dev)
22546902503SHans Petter Selasky {
22646902503SHans Petter Selasky struct g_keyboard_softc *sc = device_get_softc(dev);
22746902503SHans Petter Selasky struct usb_attach_arg *uaa = device_get_ivars(dev);
22846902503SHans Petter Selasky int error;
22946902503SHans Petter Selasky
23046902503SHans Petter Selasky DPRINTFN(11, "\n");
23146902503SHans Petter Selasky
23246902503SHans Petter Selasky device_set_usb_desc(dev);
23346902503SHans Petter Selasky
23446902503SHans Petter Selasky mtx_init(&sc->sc_mtx, "g_keyboard", NULL, MTX_DEF);
23546902503SHans Petter Selasky
23646902503SHans Petter Selasky usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
23746902503SHans Petter Selasky
23846902503SHans Petter Selasky sc->sc_mode = G_KEYBOARD_MODE_SILENT;
23946902503SHans Petter Selasky
24046902503SHans Petter Selasky error = usbd_transfer_setup(uaa->device,
24146902503SHans Petter Selasky &uaa->info.bIfaceIndex, sc->sc_xfer, g_keyboard_config,
24246902503SHans Petter Selasky G_KEYBOARD_N_TRANSFER, sc, &sc->sc_mtx);
24346902503SHans Petter Selasky
24446902503SHans Petter Selasky if (error) {
24546902503SHans Petter Selasky DPRINTF("error=%s\n", usbd_errstr(error));
24646902503SHans Petter Selasky goto detach;
24746902503SHans Petter Selasky }
24846902503SHans Petter Selasky mtx_lock(&sc->sc_mtx);
24946902503SHans Petter Selasky g_keyboard_timeout_reset(sc);
25046902503SHans Petter Selasky mtx_unlock(&sc->sc_mtx);
25146902503SHans Petter Selasky
25246902503SHans Petter Selasky return (0); /* success */
25346902503SHans Petter Selasky
25446902503SHans Petter Selasky detach:
25546902503SHans Petter Selasky g_keyboard_detach(dev);
25646902503SHans Petter Selasky
25746902503SHans Petter Selasky return (ENXIO); /* error */
25846902503SHans Petter Selasky }
25946902503SHans Petter Selasky
26046902503SHans Petter Selasky static int
g_keyboard_detach(device_t dev)26146902503SHans Petter Selasky g_keyboard_detach(device_t dev)
26246902503SHans Petter Selasky {
26346902503SHans Petter Selasky struct g_keyboard_softc *sc = device_get_softc(dev);
26446902503SHans Petter Selasky
26546902503SHans Petter Selasky DPRINTF("\n");
26646902503SHans Petter Selasky
26746902503SHans Petter Selasky mtx_lock(&sc->sc_mtx);
26846902503SHans Petter Selasky usb_callout_stop(&sc->sc_callout);
26946902503SHans Petter Selasky mtx_unlock(&sc->sc_mtx);
27046902503SHans Petter Selasky
27146902503SHans Petter Selasky usbd_transfer_unsetup(sc->sc_xfer, G_KEYBOARD_N_TRANSFER);
27246902503SHans Petter Selasky
27346902503SHans Petter Selasky usb_callout_drain(&sc->sc_callout);
27446902503SHans Petter Selasky
27546902503SHans Petter Selasky mtx_destroy(&sc->sc_mtx);
27646902503SHans Petter Selasky
27746902503SHans Petter Selasky return (0);
27846902503SHans Petter Selasky }
27946902503SHans Petter Selasky
28046902503SHans Petter Selasky static uint8_t
g_keyboard_get_keycode(struct g_keyboard_softc * sc,int index)28146902503SHans Petter Selasky g_keyboard_get_keycode(struct g_keyboard_softc *sc, int index)
28246902503SHans Petter Selasky {
28346902503SHans Petter Selasky int key;
28446902503SHans Petter Selasky int mod = sc->sc_pattern_len;
28546902503SHans Petter Selasky
28646902503SHans Petter Selasky if (mod == 0)
28746902503SHans Petter Selasky index = 0;
28846902503SHans Petter Selasky else
28946902503SHans Petter Selasky index %= mod;
29046902503SHans Petter Selasky
29146902503SHans Petter Selasky if ((index >= 0) && (index < sc->sc_pattern_len))
29246902503SHans Petter Selasky key = sc->sc_pattern[index];
29346902503SHans Petter Selasky else
29446902503SHans Petter Selasky key = 'a';
29546902503SHans Petter Selasky
29646902503SHans Petter Selasky if (key >= 'a' && key <= 'z')
29746902503SHans Petter Selasky return (key - 'a' + 0x04);
29846902503SHans Petter Selasky else
29946902503SHans Petter Selasky return (0x04);
30046902503SHans Petter Selasky }
30146902503SHans Petter Selasky
30246902503SHans Petter Selasky static void
g_keyboard_intr_callback(struct usb_xfer * xfer,usb_error_t error)30346902503SHans Petter Selasky g_keyboard_intr_callback(struct usb_xfer *xfer, usb_error_t error)
30446902503SHans Petter Selasky {
30546902503SHans Petter Selasky struct g_keyboard_softc *sc = usbd_xfer_softc(xfer);
30646902503SHans Petter Selasky int actlen;
30746902503SHans Petter Selasky int aframes;
30846902503SHans Petter Selasky
30946902503SHans Petter Selasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
31046902503SHans Petter Selasky
31146902503SHans Petter Selasky DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
31246902503SHans Petter Selasky USB_GET_STATE(xfer), aframes, actlen);
31346902503SHans Petter Selasky
31446902503SHans Petter Selasky switch (USB_GET_STATE(xfer)) {
31546902503SHans Petter Selasky case USB_ST_TRANSFERRED:
31646902503SHans Petter Selasky break;
31746902503SHans Petter Selasky
31846902503SHans Petter Selasky case USB_ST_SETUP:
31946902503SHans Petter Selasky tr_setup:
32046902503SHans Petter Selasky if (sc->sc_mode == G_KEYBOARD_MODE_SILENT) {
32146902503SHans Petter Selasky memset(&sc->sc_data, 0, sizeof(sc->sc_data));
32246902503SHans Petter Selasky usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
32346902503SHans Petter Selasky usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
32446902503SHans Petter Selasky usbd_xfer_set_frames(xfer, 2);
32546902503SHans Petter Selasky usbd_transfer_submit(xfer);
32646902503SHans Petter Selasky
32746902503SHans Petter Selasky } else if (sc->sc_mode == G_KEYBOARD_MODE_PATTERN) {
32846902503SHans Petter Selasky memset(&sc->sc_data, 0, sizeof(sc->sc_data));
32946902503SHans Petter Selasky
33046902503SHans Petter Selasky if ((sc->sc_state < 0) || (sc->sc_state >= G_KEYBOARD_MAX_STRLEN))
33146902503SHans Petter Selasky sc->sc_state = 0;
33246902503SHans Petter Selasky
33346902503SHans Petter Selasky switch (sc->sc_state % 6) {
33446902503SHans Petter Selasky case 0:
33546902503SHans Petter Selasky sc->sc_data[0].keycode[0] =
33646902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 0);
33746902503SHans Petter Selasky case 1:
33846902503SHans Petter Selasky sc->sc_data[0].keycode[1] =
33946902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 1);
34046902503SHans Petter Selasky case 2:
34146902503SHans Petter Selasky sc->sc_data[0].keycode[2] =
34246902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 2);
34346902503SHans Petter Selasky case 3:
34446902503SHans Petter Selasky sc->sc_data[0].keycode[3] =
34546902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 3);
34646902503SHans Petter Selasky case 4:
34746902503SHans Petter Selasky sc->sc_data[0].keycode[4] =
34846902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 4);
34946902503SHans Petter Selasky default:
35046902503SHans Petter Selasky sc->sc_data[0].keycode[5] =
35146902503SHans Petter Selasky g_keyboard_get_keycode(sc, sc->sc_state + 5);
35246902503SHans Petter Selasky }
35346902503SHans Petter Selasky
35446902503SHans Petter Selasky sc->sc_state++;
35546902503SHans Petter Selasky
35646902503SHans Petter Selasky usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
35746902503SHans Petter Selasky usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
35846902503SHans Petter Selasky usbd_xfer_set_frames(xfer, 2);
35946902503SHans Petter Selasky usbd_transfer_submit(xfer);
36046902503SHans Petter Selasky }
36146902503SHans Petter Selasky break;
36246902503SHans Petter Selasky
36346902503SHans Petter Selasky default: /* Error */
36446902503SHans Petter Selasky DPRINTF("error=%s\n", usbd_errstr(error));
36546902503SHans Petter Selasky
36646902503SHans Petter Selasky if (error != USB_ERR_CANCELLED) {
36746902503SHans Petter Selasky /* try to clear stall first */
36846902503SHans Petter Selasky usbd_xfer_set_stall(xfer);
36946902503SHans Petter Selasky goto tr_setup;
37046902503SHans Petter Selasky }
37146902503SHans Petter Selasky break;
37246902503SHans Petter Selasky }
37346902503SHans Petter Selasky }
37446902503SHans Petter Selasky
37546902503SHans Petter Selasky static int
g_keyboard_handle_request(device_t dev,const void * preq,void ** pptr,uint16_t * plen,uint16_t offset,uint8_t * pstate)37646902503SHans Petter Selasky g_keyboard_handle_request(device_t dev,
37746902503SHans Petter Selasky const void *preq, void **pptr, uint16_t *plen,
37846902503SHans Petter Selasky uint16_t offset, uint8_t *pstate)
37946902503SHans Petter Selasky {
38046902503SHans Petter Selasky struct g_keyboard_softc *sc = device_get_softc(dev);
38146902503SHans Petter Selasky const struct usb_device_request *req = preq;
38246902503SHans Petter Selasky uint8_t is_complete = *pstate;
38346902503SHans Petter Selasky
38446902503SHans Petter Selasky if (!is_complete) {
38546902503SHans Petter Selasky if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
38646902503SHans Petter Selasky (req->bRequest == UR_SET_REPORT) &&
38746902503SHans Petter Selasky (req->wValue[0] == 0x00) &&
38846902503SHans Petter Selasky (req->wValue[1] == 0x02)) {
38946902503SHans Petter Selasky if (offset == 0) {
39046902503SHans Petter Selasky *plen = sizeof(sc->sc_led_state);
39146902503SHans Petter Selasky *pptr = &sc->sc_led_state;
39246902503SHans Petter Selasky } else {
39346902503SHans Petter Selasky *plen = 0;
39446902503SHans Petter Selasky }
39546902503SHans Petter Selasky return (0);
39646902503SHans Petter Selasky } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
39746902503SHans Petter Selasky (req->bRequest == UR_SET_PROTOCOL) &&
39846902503SHans Petter Selasky (req->wValue[0] == 0x00) &&
39946902503SHans Petter Selasky (req->wValue[1] == 0x00)) {
40046902503SHans Petter Selasky *plen = 0;
40146902503SHans Petter Selasky return (0);
40246902503SHans Petter Selasky } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
40346902503SHans Petter Selasky (req->bRequest == UR_SET_IDLE)) {
40446902503SHans Petter Selasky *plen = 0;
40546902503SHans Petter Selasky return (0);
40646902503SHans Petter Selasky }
40746902503SHans Petter Selasky }
40846902503SHans Petter Selasky return (ENXIO); /* use builtin handler */
40946902503SHans Petter Selasky }
410