FreeBSD kernel usb device Code
usb_template_kbd.c
Go to the documentation of this file.
1/* $FreeBSD$ */
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2010 Hans Petter Selasky
6 * Copyright (c) 2018 The FreeBSD Foundation
7 * All rights reserved.
8 *
9 * Portions of this software were developed by Edward Tomasz Napierala
10 * under sponsorship from the FreeBSD Foundation.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * This file contains the USB template for an USB Keyboard Device.
36 */
37
38#ifdef USB_GLOBAL_INCLUDE_FILE
39#include USB_GLOBAL_INCLUDE_FILE
40#else
41#include <sys/stdint.h>
42#include <sys/stddef.h>
43#include <sys/param.h>
44#include <sys/queue.h>
45#include <sys/types.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/bus.h>
49#include <sys/module.h>
50#include <sys/lock.h>
51#include <sys/mutex.h>
52#include <sys/condvar.h>
53#include <sys/sysctl.h>
54#include <sys/sx.h>
55#include <sys/unistd.h>
56#include <sys/callout.h>
57#include <sys/malloc.h>
58#include <sys/priv.h>
59
60#include <dev/usb/usb.h>
61#include <dev/usb/usbdi.h>
62#include <dev/usb/usb_core.h>
63#include <dev/usb/usb_cdc.h>
64#include <dev/usb/usb_ioctl.h>
65#include <dev/usb/usb_util.h>
66
68#endif /* USB_GLOBAL_INCLUDE_FILE */
69
70enum {
77};
78
79#define KBD_DEFAULT_VENDOR_ID USB_TEMPLATE_VENDOR
80#define KBD_DEFAULT_PRODUCT_ID 0x27db
81#define KBD_DEFAULT_INTERFACE "Keyboard Interface"
82#define KBD_DEFAULT_MANUFACTURER USB_TEMPLATE_MANUFACTURER
83#define KBD_DEFAULT_PRODUCT "Keyboard Test Device"
84#define KBD_DEFAULT_SERIAL_NUMBER "March 2008"
85
90
91static struct sysctl_ctx_list kbd_ctx_list;
92
93/* prototypes */
94
96 .mps[USB_SPEED_LOW] = 16,
97 .mps[USB_SPEED_FULL] = 16,
98 .mps[USB_SPEED_HIGH] = 16,
99};
100
102 .bInterval[USB_SPEED_LOW] = 2, /* 2 ms */
103 .bInterval[USB_SPEED_FULL] = 2, /* 2 ms */
104 .bInterval[USB_SPEED_HIGH] = 5, /* 2 ms */
105};
106
107/* The following HID descriptor was dumped from a HP keyboard. */
108
109static uint8_t keyboard_hid_descriptor[] = {
110 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07,
111 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01,
112 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01,
113 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01,
114 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02,
115 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06,
116 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
117 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00,
118 0xc0
119};
120
122 .ppRawDesc = NULL, /* no raw descriptors */
123 .pPacketSize = &keyboard_intr_mps,
124 .pIntervals = &keyboard_intr_interval,
125 .bEndpointAddress = UE_DIR_IN,
126 .bmAttributes = UE_INTERRUPT,
127};
128
131 NULL,
132};
133
134static const uint8_t keyboard_raw_desc[] = {
135 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(keyboard_hid_descriptor),
136 0x00
137};
138
139static const void *keyboard_iface_0_desc[] = {
141 NULL,
142};
143
146 .ppEndpoints = keyboard_endpoints,
147 .bInterfaceClass = UICLASS_HID,
148 .bInterfaceSubClass = UISUBCLASS_BOOT,
149 .bInterfaceProtocol = UIPROTO_BOOT_KEYBOARD,
150 .iInterface = KBD_INTERFACE_INDEX,
151};
152
155 NULL,
156};
157
160 .bmAttributes = 0,
161 .bMaxPower = 0,
162 .iConfiguration = KBD_PRODUCT_INDEX,
163};
164
165static const struct usb_temp_config_desc *keyboard_configs[] = {
167 NULL,
168};
169
172
175 .getVendorDesc = &keyboard_get_vendor_desc,
176 .ppConfigDesc = keyboard_configs,
177 .idVendor = KBD_DEFAULT_VENDOR_ID,
178 .idProduct = KBD_DEFAULT_PRODUCT_ID,
179 .bcdDevice = 0x0100,
180 .bDeviceClass = UDCLASS_COMM,
181 .bDeviceSubClass = 0,
182 .bDeviceProtocol = 0,
183 .iManufacturer = KBD_MANUFACTURER_INDEX,
184 .iProduct = KBD_PRODUCT_INDEX,
185 .iSerialNumber = KBD_SERIAL_NUMBER_INDEX,
186};
187
188/*------------------------------------------------------------------------*
189 * keyboard_get_vendor_desc
190 *
191 * Return values:
192 * NULL: Failure. No such vendor descriptor.
193 * Else: Success. Pointer to vendor descriptor is returned.
194 *------------------------------------------------------------------------*/
195static const void *
197{
198 if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
199 (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
200 (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) {
201 *plen = sizeof(keyboard_hid_descriptor);
203 }
204 return (NULL);
205}
206
207/*------------------------------------------------------------------------*
208 * keyboard_get_string_desc
209 *
210 * Return values:
211 * NULL: Failure. No such string.
212 * Else: Success. Pointer to string descriptor is returned.
213 *------------------------------------------------------------------------*/
214static const void *
215keyboard_get_string_desc(uint16_t lang_id, uint8_t string_index)
216{
217 static const void *ptr[KBD_MAX_INDEX] = {
223 };
224
225 if (string_index == 0) {
226 return (&usb_string_lang_en);
227 }
228 if (lang_id != 0x0409) {
229 return (NULL);
230 }
231 if (string_index < KBD_MAX_INDEX) {
232 return (ptr[string_index]);
233 }
234 return (NULL);
235}
236
237static void
238kbd_init(void *arg __unused)
239{
240 struct sysctl_oid *parent;
241 char parent_name[3];
242
251
252 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_KBD);
253 sysctl_ctx_init(&kbd_ctx_list);
254
255 parent = SYSCTL_ADD_NODE(&kbd_ctx_list,
256 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
257 parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
258 0, "USB Keyboard device side template");
259 SYSCTL_ADD_U16(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
260 "vendor_id", CTLFLAG_RWTUN,
261 &usb_template_kbd.idVendor, 1, "Vendor identifier");
262 SYSCTL_ADD_U16(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
263 "product_id", CTLFLAG_RWTUN,
264 &usb_template_kbd.idProduct, 1, "Product identifier");
265#if 0
266 SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
267 "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
269 "A", "Interface string");
270#endif
271 SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
272 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
274 "A", "Manufacturer string");
275 SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
276 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
278 "A", "Product string");
279 SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
280 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
282 "A", "Serial number string");
283}
284
285static void
286kbd_uninit(void *arg __unused)
287{
288
289 sysctl_ctx_free(&kbd_ctx_list);
290}
291
292SYSINIT(kbd_init, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_init, NULL);
293SYSUNINIT(kbd_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_uninit, NULL);
const struct usb_temp_interface_desc ** ppIfaceDesc
Definition: usb_template.h:79
usb_temp_get_string_desc_t * getStringDesc
Definition: usb_template.h:86
const void ** ppRawDesc
Definition: usb_template.h:56
const void ** ppRawDesc
Definition: usb_template.h:69
uint8_t bInterval[USB_SPEED_MAX]
Definition: usb_template.h:52
uint16_t mps[USB_SPEED_MAX]
Definition: usb_template.h:48
#define UE_INTERRUPT
Definition: usb.h:544
#define UISUBCLASS_BOOT
Definition: usb.h:454
#define UE_DIR_IN
Definition: usb.h:531
#define UICLASS_HID
Definition: usb.h:453
@ USB_SPEED_LOW
Definition: usb.h:753
@ USB_SPEED_FULL
Definition: usb.h:754
@ USB_SPEED_HIGH
Definition: usb.h:755
#define UDCLASS_COMM
Definition: usb.h:372
#define UIPROTO_BOOT_KEYBOARD
Definition: usb.h:455
const struct usb_string_lang usb_string_lang_en
Definition: usb_core.c:63
uint16_t * plen
Definition: usb_if.m:53
const void * req
Definition: usb_if.m:51
@ USB_TEMP_KBD
Definition: usb_ioctl.h:57
int usb_temp_sysctl(SYSCTL_HANDLER_ARGS)
Definition: usb_template.c:173
const void *() usb_temp_get_vendor_desc_t(const struct usb_device_request *req, uint16_t *plen)
Definition: usb_template.h:45
const void *() usb_temp_get_string_desc_t(uint16_t lang_id, uint8_t string_index)
Definition: usb_template.h:44
#define KBD_DEFAULT_VENDOR_ID
#define KBD_DEFAULT_MANUFACTURER
static void kbd_init(void *arg __unused)
SYSINIT(kbd_init, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_init, NULL)
static usb_temp_get_vendor_desc_t keyboard_get_vendor_desc
static struct usb_string_descriptor kbd_manufacturer
static const uint8_t keyboard_raw_desc[]
#define KBD_DEFAULT_INTERFACE
static struct usb_string_descriptor kbd_product
@ KBD_PRODUCT_INDEX
@ KBD_SERIAL_NUMBER_INDEX
@ KBD_LANG_INDEX
@ KBD_INTERFACE_INDEX
@ KBD_MANUFACTURER_INDEX
@ KBD_MAX_INDEX
#define KBD_DEFAULT_SERIAL_NUMBER
static struct usb_string_descriptor kbd_serial_number
static struct usb_string_descriptor kbd_interface
static uint8_t keyboard_hid_descriptor[]
static const struct usb_temp_endpoint_desc keyboard_ep_0
static const struct usb_temp_endpoint_desc * keyboard_endpoints[]
static const struct usb_temp_packet_size keyboard_intr_mps
static const struct usb_temp_config_desc * keyboard_configs[]
static const struct usb_temp_interface_desc keyboard_iface_0
static usb_temp_get_string_desc_t keyboard_get_string_desc
static const void * keyboard_iface_0_desc[]
static const struct usb_temp_interface_desc * keyboard_interfaces[]
SYSUNINIT(kbd_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_uninit, NULL)
static struct sysctl_ctx_list kbd_ctx_list
static const struct usb_temp_interval keyboard_intr_interval
#define KBD_DEFAULT_PRODUCT
static void kbd_uninit(void *arg __unused)
struct usb_temp_device_desc usb_template_kbd
#define KBD_DEFAULT_PRODUCT_ID
static const struct usb_temp_config_desc keyboard_config_desc
uint8_t usb_make_str_desc(void *ptr, uint16_t max_len, const char *s)
Definition: usb_util.c:193