usb_template_mouse.c revision 302408
11590Srgrimes/* $FreeBSD: stable/11/sys/dev/usb/template/usb_template_mouse.c 246125 2013-01-30 16:05:54Z hselasky $ */
21590Srgrimes/*-
31590Srgrimes * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes *
141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241590Srgrimes * SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes/*
281590Srgrimes * This file contains the USB template for an USB Mouse Device.
291590Srgrimes */
301590Srgrimes
311590Srgrimes#ifdef USB_GLOBAL_INCLUDE_FILE
321590Srgrimes#include USB_GLOBAL_INCLUDE_FILE
331590Srgrimes#else
341590Srgrimes#include <sys/stdint.h>
3516509Sjraynard#include <sys/stddef.h>
361590Srgrimes#include <sys/param.h>
3716509Sjraynard#include <sys/queue.h>
3816509Sjraynard#include <sys/types.h>
3916509Sjraynard#include <sys/systm.h>
401590Srgrimes#include <sys/kernel.h>
411590Srgrimes#include <sys/bus.h>
421590Srgrimes#include <sys/module.h>
431590Srgrimes#include <sys/lock.h>
441590Srgrimes#include <sys/mutex.h>
451590Srgrimes#include <sys/condvar.h>
461590Srgrimes#include <sys/sysctl.h>
471590Srgrimes#include <sys/sx.h>
4816509Sjraynard#include <sys/unistd.h>
491590Srgrimes#include <sys/callout.h>
5016509Sjraynard#include <sys/malloc.h>
511590Srgrimes#include <sys/priv.h>
521590Srgrimes
531590Srgrimes#include <dev/usb/usb.h>
541590Srgrimes#include <dev/usb/usbdi.h>
551590Srgrimes#include <dev/usb/usb_core.h>
561590Srgrimes#include <dev/usb/usb_cdc.h>
571590Srgrimes
581590Srgrimes#include <dev/usb/template/usb_template.h>
591590Srgrimes#endif			/* USB_GLOBAL_INCLUDE_FILE */
601590Srgrimes
611590Srgrimesenum {
621590Srgrimes	INDEX_LANG,
631590Srgrimes	INDEX_MOUSE,
641590Srgrimes	INDEX_PRODUCT,
651590Srgrimes	INDEX_MAX,
661590Srgrimes};
671590Srgrimes
681590Srgrimes#define	STRING_PRODUCT \
691590Srgrimes  "M\0o\0u\0s\0e\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e"
701590Srgrimes
711590Srgrimes#define	STRING_MOUSE \
721590Srgrimes  "M\0o\0u\0s\0e\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
731590Srgrimes
741590Srgrimes/* make the real string descriptors */
751590Srgrimes
761590SrgrimesUSB_MAKE_STRING_DESC(STRING_MOUSE, string_mouse);
771590SrgrimesUSB_MAKE_STRING_DESC(STRING_PRODUCT, string_product);
781590Srgrimes
791590Srgrimes/* prototypes */
801590Srgrimes
811590Srgrimes/* The following HID descriptor was dumped from a HP mouse. */
821590Srgrimes
831590Srgrimesstatic uint8_t mouse_hid_descriptor[] = {
841590Srgrimes	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
851590Srgrimes	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
861590Srgrimes	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
871590Srgrimes	0x81, 0x02, 0x95, 0x05, 0x81, 0x03, 0x05, 0x01,
881590Srgrimes	0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81,
891590Srgrimes	0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06,
901590Srgrimes	0xc0, 0xc0
911590Srgrimes};
921590Srgrimes
931590Srgrimesstatic const struct usb_temp_packet_size mouse_intr_mps = {
941590Srgrimes	.mps[USB_SPEED_LOW] = 8,
951590Srgrimes	.mps[USB_SPEED_FULL] = 8,
961590Srgrimes	.mps[USB_SPEED_HIGH] = 8,
971590Srgrimes};
981590Srgrimes
991590Srgrimesstatic const struct usb_temp_interval mouse_intr_interval = {
1001590Srgrimes	.bInterval[USB_SPEED_LOW] = 2,		/* 2ms */
1011590Srgrimes	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
1021590Srgrimes	.bInterval[USB_SPEED_HIGH] = 5,		/* 2ms */
1031590Srgrimes};
1041590Srgrimes
1051590Srgrimesstatic const struct usb_temp_endpoint_desc mouse_ep_0 = {
1061590Srgrimes	.ppRawDesc = NULL,		/* no raw descriptors */
1071590Srgrimes	.pPacketSize = &mouse_intr_mps,
1081590Srgrimes	.pIntervals = &mouse_intr_interval,
1091590Srgrimes	.bEndpointAddress = UE_DIR_IN,
1101590Srgrimes	.bmAttributes = UE_INTERRUPT,
1111590Srgrimes};
1121590Srgrimes
1131590Srgrimesstatic const struct usb_temp_endpoint_desc *mouse_endpoints[] = {
114	&mouse_ep_0,
115	NULL,
116};
117
118static const uint8_t mouse_raw_desc[] = {
119	0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(mouse_hid_descriptor),
120	0x00
121};
122
123static const void *mouse_iface_0_desc[] = {
124	mouse_raw_desc,
125	NULL,
126};
127
128static const struct usb_temp_interface_desc mouse_iface_0 = {
129	.ppRawDesc = mouse_iface_0_desc,
130	.ppEndpoints = mouse_endpoints,
131	.bInterfaceClass = 3,
132	.bInterfaceSubClass = 1,
133	.bInterfaceProtocol = 2,
134	.iInterface = INDEX_MOUSE,
135};
136
137static const struct usb_temp_interface_desc *mouse_interfaces[] = {
138	&mouse_iface_0,
139	NULL,
140};
141
142static const struct usb_temp_config_desc mouse_config_desc = {
143	.ppIfaceDesc = mouse_interfaces,
144	.bmAttributes = UC_BUS_POWERED,
145	.bMaxPower = 25,		/* 50 mA */
146	.iConfiguration = INDEX_PRODUCT,
147};
148
149static const struct usb_temp_config_desc *mouse_configs[] = {
150	&mouse_config_desc,
151	NULL,
152};
153
154static usb_temp_get_string_desc_t mouse_get_string_desc;
155static usb_temp_get_vendor_desc_t mouse_get_vendor_desc;
156
157const struct usb_temp_device_desc usb_template_mouse = {
158	.getStringDesc = &mouse_get_string_desc,
159	.getVendorDesc = &mouse_get_vendor_desc,
160	.ppConfigDesc = mouse_configs,
161	.idVendor = USB_TEMPLATE_VENDOR,
162	.idProduct = 0x00AE,
163	.bcdDevice = 0x0100,
164	.bDeviceClass = UDCLASS_COMM,
165	.bDeviceSubClass = 0,
166	.bDeviceProtocol = 0,
167	.iManufacturer = 0,
168	.iProduct = INDEX_PRODUCT,
169	.iSerialNumber = 0,
170};
171
172/*------------------------------------------------------------------------*
173 *      mouse_get_vendor_desc
174 *
175 * Return values:
176 * NULL: Failure. No such vendor descriptor.
177 * Else: Success. Pointer to vendor descriptor is returned.
178 *------------------------------------------------------------------------*/
179static const void *
180mouse_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
181{
182	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
183	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
184	    (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) {
185
186		*plen = sizeof(mouse_hid_descriptor);
187		return (mouse_hid_descriptor);
188	}
189	return (NULL);
190}
191
192/*------------------------------------------------------------------------*
193 *	mouse_get_string_desc
194 *
195 * Return values:
196 * NULL: Failure. No such string.
197 * Else: Success. Pointer to string descriptor is returned.
198 *------------------------------------------------------------------------*/
199static const void *
200mouse_get_string_desc(uint16_t lang_id, uint8_t string_index)
201{
202	static const void *ptr[INDEX_MAX] = {
203		[INDEX_LANG] = &usb_string_lang_en,
204		[INDEX_MOUSE] = &string_mouse,
205		[INDEX_PRODUCT] = &string_product,
206	};
207
208	if (string_index == 0) {
209		return (&usb_string_lang_en);
210	}
211	if (lang_id != 0x0409) {
212		return (NULL);
213	}
214	if (string_index < INDEX_MAX) {
215		return (ptr[string_index]);
216	}
217	return (NULL);
218}
219