FreeBSD kernel usb device Code
g_keyboard.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
30 */
31
32#include <sys/param.h>
33__FBSDID("$FreeBSD$");
34
35#include <sys/stdint.h>
36#include <sys/stddef.h>
37#include <sys/queue.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/bus.h>
41#include <sys/linker_set.h>
42#include <sys/module.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/condvar.h>
46#include <sys/sysctl.h>
47#include <sys/sx.h>
48#include <sys/unistd.h>
49#include <sys/callout.h>
50#include <sys/malloc.h>
51#include <sys/priv.h>
52
53#include <dev/usb/usb.h>
54#include <dev/usb/usbdi.h>
55#include <dev/usb/usbdi_util.h>
56#include <dev/usb/usbhid.h>
57#include "usb_if.h"
58
59#define USB_DEBUG_VAR g_keyboard_debug
60#include <dev/usb/usb_debug.h>
61
63
64static SYSCTL_NODE(_hw_usb, OID_AUTO, g_keyboard,
65 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
66 "USB keyboard gadget");
67
68#ifdef USB_DEBUG
69static int g_keyboard_debug = 0;
70
71SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, debug, CTLFLAG_RWTUN,
72 &g_keyboard_debug, 0, "Debug level");
73#endif
74
75static int g_keyboard_mode = 0;
76
77SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, mode, CTLFLAG_RWTUN,
78 &g_keyboard_mode, 0, "Mode selection");
79
81
82SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, key_press_interval, CTLFLAG_RWTUN,
83 &g_keyboard_key_press_interval, 0, "Key Press Interval in milliseconds");
84
86
87SYSCTL_STRING(_hw_usb_g_keyboard, OID_AUTO, key_press_pattern, CTLFLAG_RW,
89 "Key Press Patterns");
90
91#define UPROTO_BOOT_KEYBOARD 1
92
93#define G_KEYBOARD_NMOD 8 /* units */
94#define G_KEYBOARD_NKEYCODE 6 /* units */
95
97 uint8_t modifiers;
98#define MOD_CONTROL_L 0x01
99#define MOD_CONTROL_R 0x10
100#define MOD_SHIFT_L 0x02
101#define MOD_SHIFT_R 0x20
102#define MOD_ALT_L 0x04
103#define MOD_ALT_R 0x40
104#define MOD_WIN_L 0x08
105#define MOD_WIN_R 0x80
106 uint8_t reserved;
108};
109
110enum {
113};
114
116 struct mtx sc_mtx;
120
124
126
127 uint8_t sc_led_state[4];
128};
129
130static device_probe_t g_keyboard_probe;
131static device_attach_t g_keyboard_attach;
132static device_detach_t g_keyboard_detach;
133static usb_handle_request_t g_keyboard_handle_request;
135
136static devclass_t g_keyboard_devclass;
137
138static device_method_t g_keyboard_methods[] = {
139 /* USB interface */
141
142 /* Device interface */
143 DEVMETHOD(device_probe, g_keyboard_probe),
144 DEVMETHOD(device_attach, g_keyboard_attach),
145 DEVMETHOD(device_detach, g_keyboard_detach),
146
147 DEVMETHOD_END
148};
149
150static driver_t g_keyboard_driver = {
151 .name = "g_keyboard",
152 .methods = g_keyboard_methods,
153 .size = sizeof(struct g_keyboard_softc),
154};
155
157MODULE_DEPEND(g_keyboard, usb, 1, 1, 1);
158
162 .endpoint = UE_ADDR_ANY,
163 .direction = UE_DIR_IN,
164 .flags = {.ext_buffer = 1,.pipe_bof = 1,},
165 .bufsize = sizeof(struct g_keyboard_data),
166 .callback = &g_keyboard_intr_callback,
167 .frames = 2,
168 .usb_mode = USB_MODE_DEVICE,
169 },
170};
171
172static void g_keyboard_timeout(void *arg);
173
174static void
176{
178
179 if (i <= 0)
180 i = 1;
181 else if (i > 1023)
182 i = 1023;
183
184 i = USB_MS_TO_TICKS(i);
185
187}
188
189static void
191{
192 struct g_keyboard_softc *sc = arg;
193
195
196 memcpy(sc->sc_pattern, g_keyboard_key_press_pattern, sizeof(sc->sc_pattern));
197
199
200 sc->sc_pattern_len = strlen(sc->sc_pattern);
201
202 DPRINTFN(11, "Timeout %p\n", sc->sc_xfer[G_KEYBOARD_INTR_DT]);
203
205
207}
208
209static int
210g_keyboard_probe(device_t dev)
211{
212 struct usb_attach_arg *uaa = device_get_ivars(dev);
213
214 DPRINTFN(11, "\n");
215
216 if (uaa->usb_mode != USB_MODE_DEVICE)
217 return (ENXIO);
218
219 if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
222 return (0);
223
224 return (ENXIO);
225}
226
227static int
228g_keyboard_attach(device_t dev)
229{
230 struct g_keyboard_softc *sc = device_get_softc(dev);
231 struct usb_attach_arg *uaa = device_get_ivars(dev);
232 int error;
233
234 DPRINTFN(11, "\n");
235
237
238 mtx_init(&sc->sc_mtx, "g_keyboard", NULL, MTX_DEF);
239
241
243
246 G_KEYBOARD_N_TRANSFER, sc, &sc->sc_mtx);
247
248 if (error) {
249 DPRINTF("error=%s\n", usbd_errstr(error));
250 goto detach;
251 }
252 mtx_lock(&sc->sc_mtx);
254 mtx_unlock(&sc->sc_mtx);
255
256 return (0); /* success */
257
258detach:
260
261 return (ENXIO); /* error */
262}
263
264static int
265g_keyboard_detach(device_t dev)
266{
267 struct g_keyboard_softc *sc = device_get_softc(dev);
268
269 DPRINTF("\n");
270
271 mtx_lock(&sc->sc_mtx);
273 mtx_unlock(&sc->sc_mtx);
274
276
278
279 mtx_destroy(&sc->sc_mtx);
280
281 return (0);
282}
283
284static uint8_t
286{
287 int key;
288 int mod = sc->sc_pattern_len;
289
290 if (mod == 0)
291 index = 0;
292 else
293 index %= mod;
294
295 if ((index >= 0) && (index < sc->sc_pattern_len))
296 key = sc->sc_pattern[index];
297 else
298 key = 'a';
299
300 if (key >= 'a' && key <= 'z')
301 return (key - 'a' + 0x04);
302 else
303 return (0x04);
304}
305
306static void
308{
309 struct g_keyboard_softc *sc = usbd_xfer_softc(xfer);
310 int actlen;
311 int aframes;
312
313 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
314
315 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
316 USB_GET_STATE(xfer), aframes, actlen);
317
318 switch (USB_GET_STATE(xfer)) {
320 break;
321
322 case USB_ST_SETUP:
323tr_setup:
324 if (sc->sc_mode == G_KEYBOARD_MODE_SILENT) {
325 memset(&sc->sc_data, 0, sizeof(sc->sc_data));
326 usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
327 usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
328 usbd_xfer_set_frames(xfer, 2);
330
331 } else if (sc->sc_mode == G_KEYBOARD_MODE_PATTERN) {
332 memset(&sc->sc_data, 0, sizeof(sc->sc_data));
333
334 if ((sc->sc_state < 0) || (sc->sc_state >= G_KEYBOARD_MAX_STRLEN))
335 sc->sc_state = 0;
336
337 switch (sc->sc_state % 6) {
338 case 0:
339 sc->sc_data[0].keycode[0] =
340 g_keyboard_get_keycode(sc, sc->sc_state + 0);
341 case 1:
342 sc->sc_data[0].keycode[1] =
343 g_keyboard_get_keycode(sc, sc->sc_state + 1);
344 case 2:
345 sc->sc_data[0].keycode[2] =
346 g_keyboard_get_keycode(sc, sc->sc_state + 2);
347 case 3:
348 sc->sc_data[0].keycode[3] =
349 g_keyboard_get_keycode(sc, sc->sc_state + 3);
350 case 4:
351 sc->sc_data[0].keycode[4] =
352 g_keyboard_get_keycode(sc, sc->sc_state + 4);
353 default:
354 sc->sc_data[0].keycode[5] =
355 g_keyboard_get_keycode(sc, sc->sc_state + 5);
356 }
357
358 sc->sc_state++;
359
360 usbd_xfer_set_frame_data(xfer, 0, &sc->sc_data[0], sizeof(sc->sc_data[0]));
361 usbd_xfer_set_frame_data(xfer, 1, &sc->sc_data[1], sizeof(sc->sc_data[1]));
362 usbd_xfer_set_frames(xfer, 2);
364 }
365 break;
366
367 default: /* Error */
368 DPRINTF("error=%s\n", usbd_errstr(error));
369
370 if (error != USB_ERR_CANCELLED) {
371 /* try to clear stall first */
373 goto tr_setup;
374 }
375 break;
376 }
377}
378
379static int
381 const void *preq, void **pptr, uint16_t *plen,
382 uint16_t offset, uint8_t *pstate)
383{
384 struct g_keyboard_softc *sc = device_get_softc(dev);
385 const struct usb_device_request *req = preq;
386 uint8_t is_complete = *pstate;
387
388 if (!is_complete) {
389 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
390 (req->bRequest == UR_SET_REPORT) &&
391 (req->wValue[0] == 0x00) &&
392 (req->wValue[1] == 0x02)) {
393 if (offset == 0) {
394 *plen = sizeof(sc->sc_led_state);
395 *pptr = &sc->sc_led_state;
396 } else {
397 *plen = 0;
398 }
399 return (0);
400 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
401 (req->bRequest == UR_SET_PROTOCOL) &&
402 (req->wValue[0] == 0x00) &&
403 (req->wValue[1] == 0x00)) {
404 *plen = 0;
405 return (0);
406 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
407 (req->bRequest == UR_SET_IDLE)) {
408 *plen = 0;
409 return (0);
410 }
411 }
412 return (ENXIO); /* use builtin handler */
413}
static int debug
Definition: cfumass.c:73
DRIVER_MODULE(g_keyboard, uhub, g_keyboard_driver, g_keyboard_devclass, 0, 0)
static driver_t g_keyboard_driver
Definition: g_keyboard.c:150
#define G_KEYBOARD_NKEYCODE
Definition: g_keyboard.c:94
static device_detach_t g_keyboard_detach
Definition: g_keyboard.c:132
SYSCTL_INT(_hw_usb_g_keyboard, OID_AUTO, mode, CTLFLAG_RWTUN, &g_keyboard_mode, 0, "Mode selection")
static void g_keyboard_timeout_reset(struct g_keyboard_softc *sc)
Definition: g_keyboard.c:175
static usb_handle_request_t g_keyboard_handle_request
Definition: g_keyboard.c:133
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")
static devclass_t g_keyboard_devclass
Definition: g_keyboard.c:136
static int g_keyboard_key_press_interval
Definition: g_keyboard.c:80
static const struct usb_config g_keyboard_config[G_KEYBOARD_N_TRANSFER]
Definition: g_keyboard.c:159
__FBSDID("$FreeBSD$")
static int g_keyboard_mode
Definition: g_keyboard.c:75
static device_attach_t g_keyboard_attach
Definition: g_keyboard.c:131
static device_method_t g_keyboard_methods[]
Definition: g_keyboard.c:138
static uint8_t g_keyboard_get_keycode(struct g_keyboard_softc *sc, int index)
Definition: g_keyboard.c:285
static void g_keyboard_timeout(void *arg)
Definition: g_keyboard.c:190
MODULE_DEPEND(g_keyboard, usb, 1, 1, 1)
static device_probe_t g_keyboard_probe
Definition: g_keyboard.c:130
static char g_keyboard_key_press_pattern[G_KEYBOARD_MAX_STRLEN]
Definition: g_keyboard.c:85
static usb_callback_t g_keyboard_intr_callback
Definition: g_keyboard.c:134
@ G_KEYBOARD_INTR_DT
Definition: g_keyboard.c:111
@ G_KEYBOARD_N_TRANSFER
Definition: g_keyboard.c:112
#define UPROTO_BOOT_KEYBOARD
Definition: g_keyboard.c:91
static SYSCTL_NODE(_hw_usb, OID_AUTO, g_keyboard, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB keyboard gadget")
#define G_KEYBOARD_MODE_PATTERN
Definition: g_keyboard.h:34
#define G_KEYBOARD_MODE_SILENT
Definition: g_keyboard.h:33
#define G_KEYBOARD_MAX_STRLEN
Definition: g_keyboard.h:32
struct @109 error
u_int index
device_t dev
uint8_t keycode[G_KEYBOARD_NKEYCODE]
Definition: g_keyboard.c:107
uint8_t modifiers
Definition: g_keyboard.c:97
uint8_t reserved
Definition: g_keyboard.c:106
struct mtx sc_mtx
Definition: g_keyboard.c:116
uint8_t sc_led_state[4]
Definition: g_keyboard.c:127
char sc_pattern[G_KEYBOARD_MAX_STRLEN]
Definition: g_keyboard.c:125
struct usb_xfer * sc_xfer[G_KEYBOARD_N_TRANSFER]
Definition: g_keyboard.c:119
struct usb_callout sc_callout
Definition: g_keyboard.c:117
struct g_keyboard_data sc_data[2]
Definition: g_keyboard.c:118
enum usb_hc_mode usb_mode
Definition: usbdi.h:432
struct usbd_lookup_info info
Definition: usbdi.h:426
struct usb_device * device
Definition: usbdi.h:430
uint8_t type
Definition: usbdi.h:238
uint8_t bIfaceIndex
Definition: usbdi.h:417
uint8_t bInterfaceSubClass
Definition: usbdi.h:415
uint8_t bInterfaceClass
Definition: usbdi.h:414
uint8_t bInterfaceProtocol
Definition: usbdi.h:416
#define DPRINTF(...)
Definition: umass.c:179
#define UE_INTERRUPT
Definition: usb.h:544
#define UE_ADDR_ANY
Definition: usb.h:537
#define UISUBCLASS_BOOT
Definition: usb.h:454
#define UE_DIR_IN
Definition: usb.h:531
#define UICLASS_HID
Definition: usb.h:453
@ USB_MODE_DEVICE
Definition: usb.h:779
#define UT_WRITE_CLASS_INTERFACE
Definition: usb.h:177
const char * usbd_errstr(usb_error_t err)
Definition: usb_error.c:93
static usb_error_t usb_handle_request(struct usb_xfer *)
void ** pptr
Definition: usb_if.m:52
uint8_t * pstate
Definition: usb_if.m:55
uint16_t * plen
Definition: usb_if.m:53
uint16_t offset
Definition: usb_if.m:54
const void * req
Definition: usb_if.m:51
INTERFACE usb
Definition: usb_if.m:35
void usbd_transfer_submit(struct usb_xfer *xfer)
void usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n)
void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
void usbd_xfer_set_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex, void *ptr, usb_frlength_t len)
usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **ppxfer, const struct usb_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *xfer_mtx)
Definition: usb_transfer.c:987
void usbd_transfer_start(struct usb_xfer *xfer)
void * usbd_xfer_softc(struct usb_xfer *xfer)
void usbd_xfer_set_stall(struct usb_xfer *xfer)
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes, int *nframes)
void device_set_usb_desc(device_t dev)
Definition: usb_util.c:73
#define usb_callout_init_mtx(c, m, f)
Definition: usbdi.h:480
#define USB_ST_SETUP
Definition: usbdi.h:502
#define usb_callout_reset(c,...)
Definition: usbdi.h:481
usb_error_t
Definition: usbdi.h:45
@ USB_ERR_CANCELLED
Definition: usbdi.h:51
#define usb_callout_drain(c)
Definition: usbdi.h:497
#define USB_ST_TRANSFERRED
Definition: usbdi.h:503
#define USB_MS_TO_TICKS(ms)
Definition: usbdi.h:120
void() usb_callback_t(struct usb_xfer *, usb_error_t)
Definition: usbdi.h:94
#define usb_callout_stop(c)
Definition: usbdi.h:489
#define USB_GET_STATE(xfer)
Definition: usbdi.h:515
#define UR_SET_REPORT
Definition: usbhid.h:46
#define UR_SET_IDLE
Definition: usbhid.h:48
#define UR_SET_PROTOCOL
Definition: usbhid.h:50