1223467Shselasky#include <sys/cdefs.h>
2223467Shselasky__FBSDID("$FreeBSD$");
3223467Shselasky
4223467Shselasky/*-
5223467Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
6223467Shselasky *
7223467Shselasky * Redistribution and use in source and binary forms, with or without
8223467Shselasky * modification, are permitted provided that the following conditions
9223467Shselasky * are met:
10223467Shselasky * 1. Redistributions of source code must retain the above copyright
11223467Shselasky *    notice, this list of conditions and the following disclaimer.
12223467Shselasky * 2. Redistributions in binary form must reproduce the above copyright
13223467Shselasky *    notice, this list of conditions and the following disclaimer in the
14223467Shselasky *    documentation and/or other materials provided with the distribution.
15223467Shselasky *
16223467Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17223467Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18223467Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19223467Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20223467Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21223467Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22223467Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23223467Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24223467Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25223467Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26223467Shselasky * SUCH DAMAGE.
27223467Shselasky */
28223467Shselasky
29223467Shselasky/*
30223467Shselasky * This file contains the USB template for an USB Mouse Device.
31223467Shselasky */
32223467Shselasky
33223467Shselasky#include <sys/stdint.h>
34223467Shselasky#include <sys/stddef.h>
35223467Shselasky#include <sys/param.h>
36223467Shselasky#include <sys/queue.h>
37223467Shselasky#include <sys/types.h>
38223467Shselasky#include <sys/systm.h>
39223467Shselasky#include <sys/kernel.h>
40223467Shselasky#include <sys/bus.h>
41223467Shselasky#include <sys/module.h>
42223467Shselasky#include <sys/lock.h>
43223467Shselasky#include <sys/mutex.h>
44223467Shselasky#include <sys/condvar.h>
45223467Shselasky#include <sys/sysctl.h>
46223467Shselasky#include <sys/sx.h>
47223467Shselasky#include <sys/unistd.h>
48223467Shselasky#include <sys/callout.h>
49223467Shselasky#include <sys/malloc.h>
50223467Shselasky#include <sys/priv.h>
51223467Shselasky
52223467Shselasky#include <dev/usb/usb.h>
53223467Shselasky#include <dev/usb/usbdi.h>
54223467Shselasky#include <dev/usb/usb_cdc.h>
55223467Shselasky
56223467Shselasky#include <dev/usb/template/usb_template.h>
57223467Shselasky
58223467Shselaskyenum {
59223467Shselasky	INDEX_LANG,
60223467Shselasky	INDEX_MOUSE,
61223467Shselasky	INDEX_PRODUCT,
62223467Shselasky	INDEX_MAX,
63223467Shselasky};
64223467Shselasky
65223467Shselasky#define	STRING_LANG \
66223467Shselasky  0x09, 0x04,				/* American English */
67223467Shselasky
68223467Shselasky#define	STRING_PRODUCT \
69223467Shselasky  'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \
70223467Shselasky  'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \
71223467Shselasky  'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
72223467Shselasky
73223467Shselasky#define	STRING_MOUSE \
74223467Shselasky  'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \
75223467Shselasky  'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
76223467Shselasky
77223467Shselasky/* make the real string descriptors */
78223467Shselasky
79223467ShselaskyUSB_MAKE_STRING_DESC(STRING_LANG, string_lang);
80223467ShselaskyUSB_MAKE_STRING_DESC(STRING_MOUSE, string_mouse);
81223467ShselaskyUSB_MAKE_STRING_DESC(STRING_PRODUCT, string_product);
82223467Shselasky
83223467Shselasky/* prototypes */
84223467Shselasky
85223472Shselasky/* The following HID descriptor was dumped from a HP mouse. */
86223472Shselasky
87223467Shselaskystatic uint8_t mouse_hid_descriptor[] = {
88223467Shselasky	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
89223467Shselasky	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
90223467Shselasky	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
91223467Shselasky	0x81, 0x02, 0x95, 0x05, 0x81, 0x03, 0x05, 0x01,
92223467Shselasky	0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81,
93223467Shselasky	0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06,
94223467Shselasky	0xc0, 0xc0
95223467Shselasky};
96223467Shselasky
97223467Shselaskystatic const struct usb_temp_packet_size mouse_intr_mps = {
98223467Shselasky	.mps[USB_SPEED_LOW] = 8,
99223467Shselasky	.mps[USB_SPEED_FULL] = 8,
100223467Shselasky	.mps[USB_SPEED_HIGH] = 8,
101223467Shselasky};
102223467Shselasky
103223467Shselaskystatic const struct usb_temp_interval mouse_intr_interval = {
104229103Shselasky	.bInterval[USB_SPEED_LOW] = 2,		/* 2ms */
105229103Shselasky	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
106229103Shselasky	.bInterval[USB_SPEED_HIGH] = 5,		/* 2ms */
107223467Shselasky};
108223467Shselasky
109223467Shselaskystatic const struct usb_temp_endpoint_desc mouse_ep_0 = {
110223467Shselasky	.ppRawDesc = NULL,		/* no raw descriptors */
111223467Shselasky	.pPacketSize = &mouse_intr_mps,
112223467Shselasky	.pIntervals = &mouse_intr_interval,
113223467Shselasky	.bEndpointAddress = UE_DIR_IN,
114223467Shselasky	.bmAttributes = UE_INTERRUPT,
115223467Shselasky};
116223467Shselasky
117223467Shselaskystatic const struct usb_temp_endpoint_desc *mouse_endpoints[] = {
118223467Shselasky	&mouse_ep_0,
119223467Shselasky	NULL,
120223467Shselasky};
121223467Shselasky
122223467Shselaskystatic const uint8_t mouse_raw_desc[] = {
123223467Shselasky	0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(mouse_hid_descriptor),
124223467Shselasky	0x00
125223467Shselasky};
126223467Shselasky
127223467Shselaskystatic const void *mouse_iface_0_desc[] = {
128223467Shselasky	mouse_raw_desc,
129223467Shselasky	NULL,
130223467Shselasky};
131223467Shselasky
132223467Shselaskystatic const struct usb_temp_interface_desc mouse_iface_0 = {
133223467Shselasky	.ppRawDesc = mouse_iface_0_desc,
134223467Shselasky	.ppEndpoints = mouse_endpoints,
135223467Shselasky	.bInterfaceClass = 3,
136223467Shselasky	.bInterfaceSubClass = 1,
137223467Shselasky	.bInterfaceProtocol = 2,
138223467Shselasky	.iInterface = INDEX_MOUSE,
139223467Shselasky};
140223467Shselasky
141223467Shselaskystatic const struct usb_temp_interface_desc *mouse_interfaces[] = {
142223467Shselasky	&mouse_iface_0,
143223467Shselasky	NULL,
144223467Shselasky};
145223467Shselasky
146223467Shselaskystatic const struct usb_temp_config_desc mouse_config_desc = {
147223467Shselasky	.ppIfaceDesc = mouse_interfaces,
148223467Shselasky	.bmAttributes = UC_BUS_POWERED,
149223467Shselasky	.bMaxPower = 25,		/* 50 mA */
150223467Shselasky	.iConfiguration = INDEX_PRODUCT,
151223467Shselasky};
152223467Shselasky
153223467Shselaskystatic const struct usb_temp_config_desc *mouse_configs[] = {
154223467Shselasky	&mouse_config_desc,
155223467Shselasky	NULL,
156223467Shselasky};
157223467Shselasky
158223467Shselaskystatic usb_temp_get_string_desc_t mouse_get_string_desc;
159223467Shselaskystatic usb_temp_get_vendor_desc_t mouse_get_vendor_desc;
160223467Shselasky
161223467Shselaskyconst struct usb_temp_device_desc usb_template_mouse = {
162223467Shselasky	.getStringDesc = &mouse_get_string_desc,
163223467Shselasky	.getVendorDesc = &mouse_get_vendor_desc,
164223467Shselasky	.ppConfigDesc = mouse_configs,
165223467Shselasky	.idVendor = USB_TEMPLATE_VENDOR,
166223467Shselasky	.idProduct = 0x00AE,
167223467Shselasky	.bcdDevice = 0x0100,
168223467Shselasky	.bDeviceClass = UDCLASS_COMM,
169223467Shselasky	.bDeviceSubClass = 0,
170223467Shselasky	.bDeviceProtocol = 0,
171223467Shselasky	.iManufacturer = 0,
172223467Shselasky	.iProduct = INDEX_PRODUCT,
173223467Shselasky	.iSerialNumber = 0,
174223467Shselasky};
175223467Shselasky
176223467Shselasky/*------------------------------------------------------------------------*
177223467Shselasky *      mouse_get_vendor_desc
178223467Shselasky *
179223467Shselasky * Return values:
180223467Shselasky * NULL: Failure. No such vendor descriptor.
181223467Shselasky * Else: Success. Pointer to vendor descriptor is returned.
182223467Shselasky *------------------------------------------------------------------------*/
183223467Shselaskystatic const void *
184223467Shselaskymouse_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
185223467Shselasky{
186223467Shselasky	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
187223467Shselasky	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
188223467Shselasky	    (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) {
189223467Shselasky
190223467Shselasky		*plen = sizeof(mouse_hid_descriptor);
191223467Shselasky		return (mouse_hid_descriptor);
192223467Shselasky	}
193223467Shselasky	return (NULL);
194223467Shselasky}
195223467Shselasky
196223467Shselasky/*------------------------------------------------------------------------*
197223467Shselasky *	mouse_get_string_desc
198223467Shselasky *
199223467Shselasky * Return values:
200223467Shselasky * NULL: Failure. No such string.
201223467Shselasky * Else: Success. Pointer to string descriptor is returned.
202223467Shselasky *------------------------------------------------------------------------*/
203223467Shselaskystatic const void *
204223467Shselaskymouse_get_string_desc(uint16_t lang_id, uint8_t string_index)
205223467Shselasky{
206223467Shselasky	static const void *ptr[INDEX_MAX] = {
207223467Shselasky		[INDEX_LANG] = &string_lang,
208223467Shselasky		[INDEX_MOUSE] = &string_mouse,
209223467Shselasky		[INDEX_PRODUCT] = &string_product,
210223467Shselasky	};
211223467Shselasky
212223467Shselasky	if (string_index == 0) {
213223467Shselasky		return (&string_lang);
214223467Shselasky	}
215223467Shselasky	if (lang_id != 0x0409) {
216223467Shselasky		return (NULL);
217223467Shselasky	}
218223467Shselasky	if (string_index < INDEX_MAX) {
219223467Shselasky		return (ptr[string_index]);
220223467Shselasky	}
221223467Shselasky	return (NULL);
222223467Shselasky}
223