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 | CTLFLAG_MPSAFE, 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); 295