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 Mouse 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 MOUSE_LANG_INDEX, 72 MOUSE_INTERFACE_INDEX, 73 MOUSE_MANUFACTURER_INDEX, 74 MOUSE_PRODUCT_INDEX, 75 MOUSE_SERIAL_NUMBER_INDEX, 76 MOUSE_MAX_INDEX, 77 }; 78 79 #define MOUSE_DEFAULT_VENDOR_ID USB_TEMPLATE_VENDOR 80 #define MOUSE_DEFAULT_PRODUCT_ID 0x27da 81 #define MOUSE_DEFAULT_INTERFACE "Mouse interface" 82 #define MOUSE_DEFAULT_MANUFACTURER USB_TEMPLATE_MANUFACTURER 83 #define MOUSE_DEFAULT_PRODUCT "Mouse Test Interface" 84 #define MOUSE_DEFAULT_SERIAL_NUMBER "March 2008" 85 86 static struct usb_string_descriptor mouse_interface; 87 static struct usb_string_descriptor mouse_manufacturer; 88 static struct usb_string_descriptor mouse_product; 89 static struct usb_string_descriptor mouse_serial_number; 90 91 static struct sysctl_ctx_list mouse_ctx_list; 92 93 /* prototypes */ 94 95 /* The following HID descriptor was dumped from a HP mouse. */ 96 97 static uint8_t mouse_hid_descriptor[] = { 98 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 99 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 100 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 101 0x81, 0x02, 0x95, 0x05, 0x81, 0x03, 0x05, 0x01, 102 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 103 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 104 0xc0, 0xc0 105 }; 106 107 static const struct usb_temp_packet_size mouse_intr_mps = { 108 .mps[USB_SPEED_LOW] = 8, 109 .mps[USB_SPEED_FULL] = 8, 110 .mps[USB_SPEED_HIGH] = 8, 111 }; 112 113 static const struct usb_temp_interval mouse_intr_interval = { 114 .bInterval[USB_SPEED_LOW] = 2, /* 2ms */ 115 .bInterval[USB_SPEED_FULL] = 2, /* 2ms */ 116 .bInterval[USB_SPEED_HIGH] = 5, /* 2ms */ 117 }; 118 119 static const struct usb_temp_endpoint_desc mouse_ep_0 = { 120 .ppRawDesc = NULL, /* no raw descriptors */ 121 .pPacketSize = &mouse_intr_mps, 122 .pIntervals = &mouse_intr_interval, 123 .bEndpointAddress = UE_DIR_IN, 124 .bmAttributes = UE_INTERRUPT, 125 }; 126 127 static const struct usb_temp_endpoint_desc *mouse_endpoints[] = { 128 &mouse_ep_0, 129 NULL, 130 }; 131 132 static const uint8_t mouse_raw_desc[] = { 133 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(mouse_hid_descriptor), 134 0x00 135 }; 136 137 static const void *mouse_iface_0_desc[] = { 138 mouse_raw_desc, 139 NULL, 140 }; 141 142 static const struct usb_temp_interface_desc mouse_iface_0 = { 143 .ppRawDesc = mouse_iface_0_desc, 144 .ppEndpoints = mouse_endpoints, 145 .bInterfaceClass = UICLASS_HID, 146 .bInterfaceSubClass = UISUBCLASS_BOOT, 147 .bInterfaceProtocol = UIPROTO_MOUSE, 148 .iInterface = MOUSE_INTERFACE_INDEX, 149 }; 150 151 static const struct usb_temp_interface_desc *mouse_interfaces[] = { 152 &mouse_iface_0, 153 NULL, 154 }; 155 156 static const struct usb_temp_config_desc mouse_config_desc = { 157 .ppIfaceDesc = mouse_interfaces, 158 .bmAttributes = 0, 159 .bMaxPower = 0, 160 .iConfiguration = MOUSE_INTERFACE_INDEX, 161 }; 162 163 static const struct usb_temp_config_desc *mouse_configs[] = { 164 &mouse_config_desc, 165 NULL, 166 }; 167 168 static usb_temp_get_string_desc_t mouse_get_string_desc; 169 static usb_temp_get_vendor_desc_t mouse_get_vendor_desc; 170 171 struct usb_temp_device_desc usb_template_mouse = { 172 .getStringDesc = &mouse_get_string_desc, 173 .getVendorDesc = &mouse_get_vendor_desc, 174 .ppConfigDesc = mouse_configs, 175 .idVendor = MOUSE_DEFAULT_VENDOR_ID, 176 .idProduct = MOUSE_DEFAULT_PRODUCT_ID, 177 .bcdDevice = 0x0100, 178 .bDeviceClass = UDCLASS_COMM, 179 .bDeviceSubClass = 0, 180 .bDeviceProtocol = 0, 181 .iManufacturer = MOUSE_MANUFACTURER_INDEX, 182 .iProduct = MOUSE_PRODUCT_INDEX, 183 .iSerialNumber = MOUSE_SERIAL_NUMBER_INDEX, 184 }; 185 186 /*------------------------------------------------------------------------* 187 * mouse_get_vendor_desc 188 * 189 * Return values: 190 * NULL: Failure. No such vendor descriptor. 191 * Else: Success. Pointer to vendor descriptor is returned. 192 *------------------------------------------------------------------------*/ 193 static const void * 194 mouse_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 195 { 196 if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) && 197 (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) && 198 (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) { 199 *plen = sizeof(mouse_hid_descriptor); 200 return (mouse_hid_descriptor); 201 } 202 return (NULL); 203 } 204 205 /*------------------------------------------------------------------------* 206 * mouse_get_string_desc 207 * 208 * Return values: 209 * NULL: Failure. No such string. 210 * Else: Success. Pointer to string descriptor is returned. 211 *------------------------------------------------------------------------*/ 212 static const void * 213 mouse_get_string_desc(uint16_t lang_id, uint8_t string_index) 214 { 215 static const void *ptr[MOUSE_MAX_INDEX] = { 216 [MOUSE_LANG_INDEX] = &usb_string_lang_en, 217 [MOUSE_INTERFACE_INDEX] = &mouse_interface, 218 [MOUSE_MANUFACTURER_INDEX] = &mouse_manufacturer, 219 [MOUSE_PRODUCT_INDEX] = &mouse_product, 220 [MOUSE_SERIAL_NUMBER_INDEX] = &mouse_serial_number, 221 }; 222 223 if (string_index == 0) { 224 return (&usb_string_lang_en); 225 } 226 if (lang_id != 0x0409) { 227 return (NULL); 228 } 229 if (string_index < MOUSE_MAX_INDEX) { 230 return (ptr[string_index]); 231 } 232 return (NULL); 233 } 234 235 static void 236 mouse_init(void *arg __unused) 237 { 238 struct sysctl_oid *parent; 239 char parent_name[3]; 240 241 usb_make_str_desc(&mouse_interface, sizeof(mouse_interface), 242 MOUSE_DEFAULT_INTERFACE); 243 usb_make_str_desc(&mouse_manufacturer, sizeof(mouse_manufacturer), 244 MOUSE_DEFAULT_MANUFACTURER); 245 usb_make_str_desc(&mouse_product, sizeof(mouse_product), 246 MOUSE_DEFAULT_PRODUCT); 247 usb_make_str_desc(&mouse_serial_number, sizeof(mouse_serial_number), 248 MOUSE_DEFAULT_SERIAL_NUMBER); 249 250 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MOUSE); 251 sysctl_ctx_init(&mouse_ctx_list); 252 253 parent = SYSCTL_ADD_NODE(&mouse_ctx_list, 254 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO, 255 parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE, 256 0, "USB Mouse device side template"); 257 SYSCTL_ADD_U16(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 258 "vendor_id", CTLFLAG_RWTUN, 259 &usb_template_mouse.idVendor, 1, "Vendor identifier"); 260 SYSCTL_ADD_U16(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 261 "product_id", CTLFLAG_RWTUN, 262 &usb_template_mouse.idProduct, 1, "Product identifier"); 263 #if 0 264 SYSCTL_ADD_PROC(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 265 "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 266 &mouse_interface, sizeof(mouse_interface), usb_temp_sysctl, 267 "A", "Interface string"); 268 #endif 269 SYSCTL_ADD_PROC(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 270 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 271 &mouse_manufacturer, sizeof(mouse_manufacturer), usb_temp_sysctl, 272 "A", "Manufacturer string"); 273 SYSCTL_ADD_PROC(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 274 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 275 &mouse_product, sizeof(mouse_product), usb_temp_sysctl, 276 "A", "Product string"); 277 SYSCTL_ADD_PROC(&mouse_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 278 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 279 &mouse_serial_number, sizeof(mouse_serial_number), usb_temp_sysctl, 280 "A", "Serial number string"); 281 } 282 283 static void 284 mouse_uninit(void *arg __unused) 285 { 286 287 sysctl_ctx_free(&mouse_ctx_list); 288 } 289 290 SYSINIT(mouse_init, SI_SUB_LOCK, SI_ORDER_FIRST, mouse_init, NULL); 291 SYSUNINIT(mouse_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, mouse_uninit, NULL); 292