4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
33 * \author Andrea Righi <arighi@develer.com>
35 * \brief Generic USB keyboard device driver.
42 #include "cfg/cfg_usbkbd.h"
44 #define LOG_LEVEL USB_KEYBOARD_LOG_LEVEL
45 #define LOG_FORMAT USB_KEYBOARD_LOG_FORMAT
48 #include <cfg/debug.h>
49 #include <cfg/macros.h>
50 #include <cfg/compiler.h>
51 #include <cfg/module.h>
53 #include <cpu/power.h> // cpu_relax()
56 #include <drv/usb_endpoint.h>
60 * HID device configuration (usb-keyboard)
62 #define USB_HID_VENDOR_ID USB_KEYBOARD_VENDOR_ID
63 #define USB_HID_PRODUCT_ID USB_KEYBOARD_PRODUCT_ID
65 #define USB_HID_INTERFACES 1
66 #define USB_HID_ENDPOINTS 1
68 #define USB_STRING_MANUFACTURER 1
69 #define USB_STRING_PRODUCT 2
71 #define USB_HID_REPORT_EP (USB_DIR_IN | USB_KBD_EP_REPORT)
73 static UsbDeviceDesc usb_hid_device_descriptor =
75 .bLength = sizeof(usb_hid_device_descriptor),
76 .bDescriptorType = USB_DT_DEVICE,
81 .idVendor = USB_HID_VENDOR_ID,
82 .idProduct = USB_HID_PRODUCT_ID,
84 .iManufacturer = USB_STRING_MANUFACTURER,
85 .iProduct = USB_STRING_PRODUCT,
87 .bNumConfigurations = 1,
90 static const UsbConfigDesc usb_hid_config_descriptor =
92 .bLength = sizeof(usb_hid_config_descriptor),
93 .bDescriptorType = USB_DT_CONFIG,
94 .bNumInterfaces = USB_HID_INTERFACES,
95 .bConfigurationValue = 1,
97 .bmAttributes = USB_CONFIG_ATT_ONE,
98 .bMaxPower = 50, /* 100 mA */
101 static const UsbInterfaceDesc usb_hid_interface_descriptor =
103 .bLength = sizeof(usb_hid_interface_descriptor),
104 .bDescriptorType = USB_DT_INTERFACE,
105 .bInterfaceNumber = 0,
106 .bAlternateSetting = 0,
107 .bNumEndpoints = USB_HID_ENDPOINTS,
108 .bInterfaceClass = USB_CLASS_HID,
109 .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_BOOT,
110 .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_KEYBOARD,
115 * Keyboard report descriptor
117 * Taken from the USB HID spec:
118 * - E.6 Report Descriptor (Keyboard), HID1_11.pdf, p.69
120 static const uint8_t hid_report_descriptor[] =
122 0x05, 0x01, // Usage Page (Generic Desktop)
123 0x09, 0x06, // Usage (Keyboard)
124 0xA1, 0x01, // Collection (Application)
125 0x05, 0x07, // Usage Page (Key Codes)
126 0x19, 0xE0, // Usage Minimum (224)
127 0x29, 0xE7, // Usage Maximum (231)
128 0x15, 0x00, // Logical Minimum (0)
129 0x25, 0x01, // Logical Maximum (1)
130 0x75, 0x01, // Report Size (1)
131 0x95, 0x08, // Report Count (8)
132 0x81, 0x02, // Input (Data, Variable, Absolute)
133 0x95, 0x01, // Report Count (1)
134 0x75, 0x08, // Report Size (8)
135 0x81, 0x01, // Input (Constant)
136 0x95, 0x05, // Report Count (5)
137 0x75, 0x01, // Report Size (1)
138 0x05, 0x08, // Usage Page (Page# for LEDs)
139 0x19, 0x01, // Usage Minimum (1)
140 0x29, 0x05, // Usage Maximum (5)
141 0x91, 0x02, // Output (Data, Variable, Absolute)
142 0x95, 0x01, // Report Count (1)
143 0x75, 0x03, // Report Size (3)
144 0x91, 0x01, // Output (Constant)
145 0x95, 0x06, // Report Count (6)
146 0x75, 0x08, // Report Size (8)
147 0x15, 0x00, // Logical Minimum (0)
148 0x25, 0x65, // Logical Maximum(101)
149 0x05, 0x07, // Usage Page (Key Codes)
150 0x19, 0x00, // Usage Minimum (0)
151 0x29, 0x65, // Usage Maximum (101)
152 0x81, 0x00, // Input (Data, Array)
153 0xC0, // End Collection
156 static const usb_HidDesc usb_hid_descriptor =
158 .bLength = sizeof(usb_hid_descriptor),
159 .bDescriptorType = HID_DT_HID,
160 .bcdHID = usb_cpu_to_le16((uint16_t)0x0110),
162 .bNumDescriptors = 1,
163 .bDescriptorHidType = HID_DT_REPORT,
165 usb_cpu_to_le16((uint16_t)sizeof(hid_report_descriptor)),
168 static const UsbEndpointDesc usb_hid_ep_descriptor =
170 .bLength = sizeof(usb_hid_ep_descriptor),
171 .bDescriptorType = USB_DT_ENDPOINT,
172 .bEndpointAddress = USB_HID_REPORT_EP,
173 .bmAttributes = USB_ENDPOINT_XFER_INT,
174 .wMaxPacketSize = usb_cpu_to_le16((uint16_t)4),
175 .bInterval = 10, /* resolution in ms */
178 static const UsbDescHeader *usb_hid_config[] =
180 (const UsbDescHeader *)&usb_hid_config_descriptor,
181 (const UsbDescHeader *)&usb_hid_interface_descriptor,
182 (const UsbDescHeader *)&usb_hid_descriptor,
183 (const UsbDescHeader *)&usb_hid_ep_descriptor,
187 static const DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
188 static const DEFINE_USB_STRING(manufacturer_str,
189 USB_STRING("B", "e", "R", "T", "O", "S"));
190 static const DEFINE_USB_STRING(product_str,
191 USB_STRING("U", "S", "B", " ",
192 "K", "e", "y", "b", "o", "a", "r", "d"));
194 static const UsbStringDesc *usb_hid_strings[] =
196 (const UsbStringDesc *)&language_str,
197 (const UsbStringDesc *)&manufacturer_str,
198 (const UsbStringDesc *)&product_str,
202 static uint8_t report[8];
204 static bool hid_keyboard_configured;
206 static void usb_hid_event_cb(UsbCtrlRequest *ctrl)
208 uint16_t value = usb_le16_to_cpu(ctrl->wValue);
209 uint16_t index = usb_le16_to_cpu(ctrl->wIndex);
210 uint16_t length = usb_le16_to_cpu(ctrl->wLength);
211 uint8_t type = ctrl->mRequestType;
212 uint8_t request = ctrl->bRequest;
214 LOG_INFO("%s: s 0x%02x 0x%02x 0x%04x 0x%04x 0x%04x\n",
215 __func__, type, request, value, index, length);
216 switch (ctrl->bRequest)
218 case USB_REQ_GET_DESCRIPTOR:
222 LOG_INFO("%s: HID_DT_HID\n", __func__);
223 usb_endpointWrite(USB_DIR_IN | 0,
225 sizeof(usb_hid_descriptor));
228 LOG_INFO("%s: HID_DT_REPORT\n", __func__);
229 usb_endpointWrite(USB_DIR_IN | 0,
230 &hid_report_descriptor,
231 sizeof(hid_report_descriptor));
232 hid_keyboard_configured = true;
235 LOG_INFO("%s: unknown HID request\n", __func__);
239 case HID_REQ_GET_REPORT:
240 LOG_INFO("%s: HID_REQ_GET_REPORT\n", __func__);
242 case HID_REQ_SET_REPORT:
243 LOG_INFO("%s: HID_REQ_SET_REPORT\n", __func__);
244 usb_endpointWrite(USB_DIR_IN | 0, NULL, 0);
246 case HID_REQ_GET_IDLE:
247 LOG_INFO("%s: HID_REQ_GET_IDLE\n", __func__);
249 case HID_REQ_SET_IDLE:
250 LOG_INFO("%s: HID_REQ_SET_IDLE\n", __func__);
251 usb_endpointWrite(USB_DIR_IN | 0, NULL, 0);
253 case HID_REQ_GET_PROTOCOL:
254 LOG_INFO("%s: HID_REQ_GET_PROTOCOL\n", __func__);
256 case HID_REQ_SET_PROTOCOL:
257 LOG_INFO("%s: HID_REQ_SET_PROTOCOL\n", __func__);
260 LOG_ERR("%s: unknown request: 0x%02x\n",
261 __func__, ctrl->bRequest);
266 /* Global usb-keyboard descriptor that identifies the usb-keyboard device */
267 static UsbDevice usb_keyboard = {
268 .device = &usb_hid_device_descriptor,
269 .config = usb_hid_config,
270 .strings = usb_hid_strings,
271 .event_cb = usb_hid_event_cb,
274 /* Low-level usb-hid device initialization */
275 static int usb_keyboard_hw_init(void)
277 if (usb_deviceRegister(&usb_keyboard) < 0)
279 LOG_INFO("usb-hid: registered new USB keyboard device\n");
283 /* Send a keyboard event */
284 void usbkbd_sendEvent(uint8_t mod, uint8_t code)
288 usb_endpointWrite(USB_HID_REPORT_EP, &report, sizeof(report));
292 * Initialize a USB HID keyboard device.
294 * TODO: support more than one device at the same time.
296 int usbkbd_init(UNUSED_ARG(int, unit))
301 usb_keyboard_hw_init();
302 while (!hid_keyboard_configured)