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