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