]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/template/usb_template_kbd.c
MFV 354917, 354918, 354919
[FreeBSD/FreeBSD.git] / sys / dev / usb / template / usb_template_kbd.c
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
67 #include <dev/usb/template/usb_template.h>
68 #endif                  /* USB_GLOBAL_INCLUDE_FILE */
69
70 enum {
71         KBD_LANG_INDEX,
72         KBD_INTERFACE_INDEX,
73         KBD_MANUFACTURER_INDEX,
74         KBD_PRODUCT_INDEX,
75         KBD_SERIAL_NUMBER_INDEX,
76         KBD_MAX_INDEX,
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
86 static struct usb_string_descriptor     kbd_interface;
87 static struct usb_string_descriptor     kbd_manufacturer;
88 static struct usb_string_descriptor     kbd_product;
89 static struct usb_string_descriptor     kbd_serial_number;
90
91 static struct sysctl_ctx_list           kbd_ctx_list;
92
93 /* prototypes */
94
95 static const struct usb_temp_packet_size keyboard_intr_mps = {
96         .mps[USB_SPEED_LOW] = 16,
97         .mps[USB_SPEED_FULL] = 16,
98         .mps[USB_SPEED_HIGH] = 16,
99 };
100
101 static const struct usb_temp_interval keyboard_intr_interval = {
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
109 static 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
121 static const struct usb_temp_endpoint_desc keyboard_ep_0 = {
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
129 static const struct usb_temp_endpoint_desc *keyboard_endpoints[] = {
130         &keyboard_ep_0,
131         NULL,
132 };
133
134 static const uint8_t keyboard_raw_desc[] = {
135         0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(keyboard_hid_descriptor),
136         0x00
137 };
138
139 static const void *keyboard_iface_0_desc[] = {
140         keyboard_raw_desc,
141         NULL,
142 };
143
144 static const struct usb_temp_interface_desc keyboard_iface_0 = {
145         .ppRawDesc = keyboard_iface_0_desc,
146         .ppEndpoints = keyboard_endpoints,
147         .bInterfaceClass = UICLASS_HID,
148         .bInterfaceSubClass = UISUBCLASS_BOOT,
149         .bInterfaceProtocol = UIPROTO_BOOT_KEYBOARD,
150         .iInterface = KBD_INTERFACE_INDEX,
151 };
152
153 static const struct usb_temp_interface_desc *keyboard_interfaces[] = {
154         &keyboard_iface_0,
155         NULL,
156 };
157
158 static const struct usb_temp_config_desc keyboard_config_desc = {
159         .ppIfaceDesc = keyboard_interfaces,
160         .bmAttributes = 0,
161         .bMaxPower = 0,
162         .iConfiguration = KBD_PRODUCT_INDEX,
163 };
164
165 static const struct usb_temp_config_desc *keyboard_configs[] = {
166         &keyboard_config_desc,
167         NULL,
168 };
169
170 static usb_temp_get_string_desc_t keyboard_get_string_desc;
171 static usb_temp_get_vendor_desc_t keyboard_get_vendor_desc;
172
173 struct usb_temp_device_desc usb_template_kbd = {
174         .getStringDesc = &keyboard_get_string_desc,
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  *------------------------------------------------------------------------*/
195 static const void *
196 keyboard_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
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
202                 *plen = sizeof(keyboard_hid_descriptor);
203                 return (keyboard_hid_descriptor);
204         }
205         return (NULL);
206 }
207
208 /*------------------------------------------------------------------------*
209  *      keyboard_get_string_desc
210  *
211  * Return values:
212  * NULL: Failure. No such string.
213  * Else: Success. Pointer to string descriptor is returned.
214  *------------------------------------------------------------------------*/
215 static const void *
216 keyboard_get_string_desc(uint16_t lang_id, uint8_t string_index)
217 {
218         static const void *ptr[KBD_MAX_INDEX] = {
219                 [KBD_LANG_INDEX] = &usb_string_lang_en,
220                 [KBD_INTERFACE_INDEX] = &kbd_interface,
221                 [KBD_MANUFACTURER_INDEX] = &kbd_manufacturer,
222                 [KBD_PRODUCT_INDEX] = &kbd_product,
223                 [KBD_SERIAL_NUMBER_INDEX] = &kbd_serial_number,
224         };
225
226         if (string_index == 0) {
227                 return (&usb_string_lang_en);
228         }
229         if (lang_id != 0x0409) {
230                 return (NULL);
231         }
232         if (string_index < KBD_MAX_INDEX) {
233                 return (ptr[string_index]);
234         }
235         return (NULL);
236 }
237
238 static void
239 kbd_init(void *arg __unused)
240 {
241         struct sysctl_oid *parent;
242         char parent_name[3];
243
244         usb_make_str_desc(&kbd_interface, sizeof(kbd_interface),
245             KBD_DEFAULT_INTERFACE);
246         usb_make_str_desc(&kbd_manufacturer, sizeof(kbd_manufacturer),
247             KBD_DEFAULT_MANUFACTURER);
248         usb_make_str_desc(&kbd_product, sizeof(kbd_product),
249             KBD_DEFAULT_PRODUCT);
250         usb_make_str_desc(&kbd_serial_number, sizeof(kbd_serial_number),
251             KBD_DEFAULT_SERIAL_NUMBER);
252
253         snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_KBD);
254         sysctl_ctx_init(&kbd_ctx_list);
255
256         parent = SYSCTL_ADD_NODE(&kbd_ctx_list,
257             SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
258             parent_name, CTLFLAG_RW,
259             0, "USB Keyboard device side template");
260         SYSCTL_ADD_U16(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
261             "vendor_id", CTLFLAG_RWTUN,
262             &usb_template_kbd.idVendor, 1, "Vendor identifier");
263         SYSCTL_ADD_U16(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
264             "product_id", CTLFLAG_RWTUN,
265             &usb_template_kbd.idProduct, 1, "Product identifier");
266 #if 0
267         SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
268             "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
269             &kbd_interface, sizeof(kbd_interface), usb_temp_sysctl,
270             "A", "Interface string");
271 #endif
272         SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
273             "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
274             &kbd_manufacturer, sizeof(kbd_manufacturer), usb_temp_sysctl,
275             "A", "Manufacturer string");
276         SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
277             "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
278             &kbd_product, sizeof(kbd_product), usb_temp_sysctl,
279             "A", "Product string");
280         SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
281             "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
282             &kbd_serial_number, sizeof(kbd_serial_number), usb_temp_sysctl,
283             "A", "Serial number string");
284 }
285
286 static void
287 kbd_uninit(void *arg __unused)
288 {
289
290         sysctl_ctx_free(&kbd_ctx_list);
291 }
292
293 SYSINIT(kbd_init, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_init, NULL);
294 SYSUNINIT(kbd_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_uninit, NULL);