1246122Shselasky/* $FreeBSD: releng/11.0/sys/dev/usb/template/usb_template_kbd.c 246125 2013-01-30 16:05:54Z hselasky $ */ 2223467Shselasky/*- 3223467Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 4223467Shselasky * 5223467Shselasky * Redistribution and use in source and binary forms, with or without 6223467Shselasky * modification, are permitted provided that the following conditions 7223467Shselasky * are met: 8223467Shselasky * 1. Redistributions of source code must retain the above copyright 9223467Shselasky * notice, this list of conditions and the following disclaimer. 10223467Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11223467Shselasky * notice, this list of conditions and the following disclaimer in the 12223467Shselasky * documentation and/or other materials provided with the distribution. 13223467Shselasky * 14223467Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15223467Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16223467Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17223467Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18223467Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19223467Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20223467Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21223467Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22223467Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23223467Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24223467Shselasky * SUCH DAMAGE. 25223467Shselasky */ 26223467Shselasky 27223467Shselasky/* 28223467Shselasky * This file contains the USB template for an USB Keyboard Device. 29223467Shselasky */ 30223467Shselasky 31246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 32246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 33246122Shselasky#else 34223467Shselasky#include <sys/stdint.h> 35223467Shselasky#include <sys/stddef.h> 36223467Shselasky#include <sys/param.h> 37223467Shselasky#include <sys/queue.h> 38223467Shselasky#include <sys/types.h> 39223467Shselasky#include <sys/systm.h> 40223467Shselasky#include <sys/kernel.h> 41223467Shselasky#include <sys/bus.h> 42223467Shselasky#include <sys/module.h> 43223467Shselasky#include <sys/lock.h> 44223467Shselasky#include <sys/mutex.h> 45223467Shselasky#include <sys/condvar.h> 46223467Shselasky#include <sys/sysctl.h> 47223467Shselasky#include <sys/sx.h> 48223467Shselasky#include <sys/unistd.h> 49223467Shselasky#include <sys/callout.h> 50223467Shselasky#include <sys/malloc.h> 51223467Shselasky#include <sys/priv.h> 52223467Shselasky 53223467Shselasky#include <dev/usb/usb.h> 54223467Shselasky#include <dev/usb/usbdi.h> 55246123Shselasky#include <dev/usb/usb_core.h> 56223467Shselasky#include <dev/usb/usb_cdc.h> 57223467Shselasky 58223467Shselasky#include <dev/usb/template/usb_template.h> 59246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 60223467Shselasky 61223467Shselaskyenum { 62223467Shselasky INDEX_LANG, 63223467Shselasky INDEX_KEYBOARD, 64223467Shselasky INDEX_PRODUCT, 65223467Shselasky INDEX_MAX, 66223467Shselasky}; 67223467Shselasky 68223467Shselasky#define STRING_PRODUCT \ 69246125Shselasky "K\0e\0y\0b\0o\0a\0r\0d\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" 70223467Shselasky 71223467Shselasky#define STRING_KEYBOARD \ 72246125Shselasky "K\0e\0y\0b\0o\0a\0r\0d\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 73223467Shselasky 74223467Shselasky/* make the real string descriptors */ 75223467Shselasky 76223467ShselaskyUSB_MAKE_STRING_DESC(STRING_KEYBOARD, string_keyboard); 77223467ShselaskyUSB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); 78223467Shselasky 79223467Shselasky/* prototypes */ 80223467Shselasky 81223467Shselaskystatic const struct usb_temp_packet_size keyboard_intr_mps = { 82223467Shselasky .mps[USB_SPEED_LOW] = 16, 83223467Shselasky .mps[USB_SPEED_FULL] = 16, 84223467Shselasky .mps[USB_SPEED_HIGH] = 16, 85223467Shselasky}; 86223467Shselasky 87223467Shselaskystatic const struct usb_temp_interval keyboard_intr_interval = { 88228304Shselasky .bInterval[USB_SPEED_LOW] = 2, /* 2 ms */ 89228304Shselasky .bInterval[USB_SPEED_FULL] = 2, /* 2 ms */ 90228304Shselasky .bInterval[USB_SPEED_HIGH] = 5, /* 2 ms */ 91223467Shselasky}; 92223467Shselasky 93223472Shselasky/* The following HID descriptor was dumped from a HP keyboard. */ 94223472Shselasky 95223467Shselaskystatic uint8_t keyboard_hid_descriptor[] = { 96223467Shselasky 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 97223467Shselasky 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 98223467Shselasky 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 99223467Shselasky 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 100223467Shselasky 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 101223467Shselasky 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 102223467Shselasky 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 103223467Shselasky 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 104223467Shselasky 0xc0 105223467Shselasky}; 106223467Shselasky 107223467Shselaskystatic const struct usb_temp_endpoint_desc keyboard_ep_0 = { 108223467Shselasky .ppRawDesc = NULL, /* no raw descriptors */ 109223467Shselasky .pPacketSize = &keyboard_intr_mps, 110223467Shselasky .pIntervals = &keyboard_intr_interval, 111223467Shselasky .bEndpointAddress = UE_DIR_IN, 112223467Shselasky .bmAttributes = UE_INTERRUPT, 113223467Shselasky}; 114223467Shselasky 115223467Shselaskystatic const struct usb_temp_endpoint_desc *keyboard_endpoints[] = { 116223467Shselasky &keyboard_ep_0, 117223467Shselasky NULL, 118223467Shselasky}; 119223467Shselasky 120223467Shselaskystatic const uint8_t keyboard_raw_desc[] = { 121223467Shselasky 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(keyboard_hid_descriptor), 122223467Shselasky 0x00 123223467Shselasky}; 124223467Shselasky 125223467Shselaskystatic const void *keyboard_iface_0_desc[] = { 126223467Shselasky keyboard_raw_desc, 127223467Shselasky NULL, 128223467Shselasky}; 129223467Shselasky 130223467Shselaskystatic const struct usb_temp_interface_desc keyboard_iface_0 = { 131223467Shselasky .ppRawDesc = keyboard_iface_0_desc, 132223467Shselasky .ppEndpoints = keyboard_endpoints, 133223467Shselasky .bInterfaceClass = 3, 134223467Shselasky .bInterfaceSubClass = 1, 135223467Shselasky .bInterfaceProtocol = 1, 136223467Shselasky .iInterface = INDEX_KEYBOARD, 137223467Shselasky}; 138223467Shselasky 139223467Shselaskystatic const struct usb_temp_interface_desc *keyboard_interfaces[] = { 140223467Shselasky &keyboard_iface_0, 141223467Shselasky NULL, 142223467Shselasky}; 143223467Shselasky 144223467Shselaskystatic const struct usb_temp_config_desc keyboard_config_desc = { 145223467Shselasky .ppIfaceDesc = keyboard_interfaces, 146223467Shselasky .bmAttributes = UC_BUS_POWERED, 147223467Shselasky .bMaxPower = 25, /* 50 mA */ 148223467Shselasky .iConfiguration = INDEX_PRODUCT, 149223467Shselasky}; 150223467Shselasky 151223467Shselaskystatic const struct usb_temp_config_desc *keyboard_configs[] = { 152223467Shselasky &keyboard_config_desc, 153223467Shselasky NULL, 154223467Shselasky}; 155223467Shselasky 156223467Shselaskystatic usb_temp_get_string_desc_t keyboard_get_string_desc; 157223467Shselaskystatic usb_temp_get_vendor_desc_t keyboard_get_vendor_desc; 158223467Shselasky 159223467Shselaskyconst struct usb_temp_device_desc usb_template_kbd = { 160223467Shselasky .getStringDesc = &keyboard_get_string_desc, 161223467Shselasky .getVendorDesc = &keyboard_get_vendor_desc, 162223467Shselasky .ppConfigDesc = keyboard_configs, 163223467Shselasky .idVendor = USB_TEMPLATE_VENDOR, 164223467Shselasky .idProduct = 0x00CB, 165223467Shselasky .bcdDevice = 0x0100, 166223467Shselasky .bDeviceClass = UDCLASS_COMM, 167223467Shselasky .bDeviceSubClass = 0, 168223467Shselasky .bDeviceProtocol = 0, 169223467Shselasky .iManufacturer = 0, 170223467Shselasky .iProduct = INDEX_PRODUCT, 171223467Shselasky .iSerialNumber = 0, 172223467Shselasky}; 173223467Shselasky 174223467Shselasky/*------------------------------------------------------------------------* 175223467Shselasky * keyboard_get_vendor_desc 176223467Shselasky * 177223467Shselasky * Return values: 178223467Shselasky * NULL: Failure. No such vendor descriptor. 179223467Shselasky * Else: Success. Pointer to vendor descriptor is returned. 180223467Shselasky *------------------------------------------------------------------------*/ 181223467Shselaskystatic const void * 182223467Shselaskykeyboard_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) 183223467Shselasky{ 184223467Shselasky if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) && 185223467Shselasky (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) && 186223467Shselasky (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) { 187223467Shselasky 188223467Shselasky *plen = sizeof(keyboard_hid_descriptor); 189223467Shselasky return (keyboard_hid_descriptor); 190223467Shselasky } 191223467Shselasky return (NULL); 192223467Shselasky} 193223467Shselasky 194223467Shselasky/*------------------------------------------------------------------------* 195223467Shselasky * keyboard_get_string_desc 196223467Shselasky * 197223467Shselasky * Return values: 198223467Shselasky * NULL: Failure. No such string. 199223467Shselasky * Else: Success. Pointer to string descriptor is returned. 200223467Shselasky *------------------------------------------------------------------------*/ 201223467Shselaskystatic const void * 202223467Shselaskykeyboard_get_string_desc(uint16_t lang_id, uint8_t string_index) 203223467Shselasky{ 204223467Shselasky static const void *ptr[INDEX_MAX] = { 205246123Shselasky [INDEX_LANG] = &usb_string_lang_en, 206223467Shselasky [INDEX_KEYBOARD] = &string_keyboard, 207223467Shselasky [INDEX_PRODUCT] = &string_product, 208223467Shselasky }; 209223467Shselasky 210223467Shselasky if (string_index == 0) { 211246123Shselasky return (&usb_string_lang_en); 212223467Shselasky } 213223467Shselasky if (lang_id != 0x0409) { 214223467Shselasky return (NULL); 215223467Shselasky } 216223467Shselasky if (string_index < INDEX_MAX) { 217223467Shselasky return (ptr[string_index]); 218223467Shselasky } 219223467Shselasky return (NULL); 220223467Shselasky} 221