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