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