xref: /freebsd/sys/dev/usb/template/usb_template_kbd.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /* $FreeBSD$ */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause
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 		*plen = sizeof(keyboard_hid_descriptor);
202 		return (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  *------------------------------------------------------------------------*/
214 static const void *
215 keyboard_get_string_desc(uint16_t lang_id, uint8_t string_index)
216 {
217 	static const void *ptr[KBD_MAX_INDEX] = {
218 		[KBD_LANG_INDEX] = &usb_string_lang_en,
219 		[KBD_INTERFACE_INDEX] = &kbd_interface,
220 		[KBD_MANUFACTURER_INDEX] = &kbd_manufacturer,
221 		[KBD_PRODUCT_INDEX] = &kbd_product,
222 		[KBD_SERIAL_NUMBER_INDEX] = &kbd_serial_number,
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 
237 static void
238 kbd_init(void *arg __unused)
239 {
240 	struct sysctl_oid *parent;
241 	char parent_name[3];
242 
243 	usb_make_str_desc(&kbd_interface, sizeof(kbd_interface),
244 	    KBD_DEFAULT_INTERFACE);
245 	usb_make_str_desc(&kbd_manufacturer, sizeof(kbd_manufacturer),
246 	    KBD_DEFAULT_MANUFACTURER);
247 	usb_make_str_desc(&kbd_product, sizeof(kbd_product),
248 	    KBD_DEFAULT_PRODUCT);
249 	usb_make_str_desc(&kbd_serial_number, sizeof(kbd_serial_number),
250 	    KBD_DEFAULT_SERIAL_NUMBER);
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,
268 	    &kbd_interface, sizeof(kbd_interface), usb_temp_sysctl,
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,
273 	    &kbd_manufacturer, sizeof(kbd_manufacturer), usb_temp_sysctl,
274 	    "A", "Manufacturer string");
275 	SYSCTL_ADD_PROC(&kbd_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
276 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
277 	    &kbd_product, sizeof(kbd_product), usb_temp_sysctl,
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,
281 	    &kbd_serial_number, sizeof(kbd_serial_number), usb_temp_sysctl,
282 	    "A", "Serial number string");
283 }
284 
285 static void
286 kbd_uninit(void *arg __unused)
287 {
288 
289 	sysctl_ctx_free(&kbd_ctx_list);
290 }
291 
292 SYSINIT(kbd_init, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_init, NULL);
293 SYSUNINIT(kbd_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, kbd_uninit, NULL);
294