source: mainline/uspace/drv/usbhid/usbhid.c@ 8b74997f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8b74997f was fec47d4, checked in by Lubos Slovak <lubos.slovak@…>, 14 years ago

Fixed typos + changed match IDs

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2011 Lubos Slovak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbhid
30 * @{
31 */
32/**
33 * @file
34 * USB HID driver API.
35 */
36
37#include <usb/debug.h>
38#include <usb/classes/classes.h>
39#include <usb/classes/hid.h>
40#include <usb/classes/hidparser.h>
41#include <usb/classes/hidreport.h>
42#include <usb/classes/hidreq.h>
43#include <errno.h>
44
45#include "usbhid.h"
46
47#include "kbd/kbddev.h"
48#include "generic/hiddev.h"
49
50/*----------------------------------------------------------------------------*/
51
52/** Mouse polling endpoint description for boot protocol class. */
53static usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
54 .transfer_type = USB_TRANSFER_INTERRUPT,
55 .direction = USB_DIRECTION_IN,
56 .interface_class = USB_CLASS_HID,
57 .interface_subclass = USB_HID_SUBCLASS_BOOT,
58 .interface_protocol = USB_HID_PROTOCOL_MOUSE,
59 .flags = 0
60};
61
62/* Array of endpoints expected on the device, NULL terminated. */
63usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
64 &usb_hid_kbd_poll_endpoint_description,
65 &usb_hid_mouse_poll_endpoint_description,
66 &usb_hid_generic_poll_endpoint_description,
67 NULL
68};
69
70static const char *HID_MOUSE_FUN_NAME = "mouse";
71static const char *HID_MOUSE_CLASS_NAME = "mouse";
72
73/*----------------------------------------------------------------------------*/
74
75usb_hid_dev_t *usb_hid_new(void)
76{
77 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
78 sizeof(usb_hid_dev_t));
79
80 if (hid_dev == NULL) {
81 usb_log_fatal("No memory!\n");
82 return NULL;
83 }
84
85 hid_dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
86 usb_hid_report_parser_t)));
87 if (hid_dev->parser == NULL) {
88 usb_log_fatal("No memory!\n");
89 free(hid_dev);
90 return NULL;
91 }
92
93 return hid_dev;
94}
95
96/*----------------------------------------------------------------------------*/
97
98static bool usb_dummy_polling_callback(usb_device_t *dev, uint8_t *buffer,
99 size_t buffer_size, void *arg)
100{
101 usb_log_debug("Dummy polling callback.\n");
102 return false;
103}
104
105/*----------------------------------------------------------------------------*/
106
107static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
108{
109 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
110 usb_log_debug("Found keyboard endpoint.\n");
111
112 // save the pipe index and device type
113 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
114 hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;
115
116 // set the polling callback
117 hid_dev->poll_callback = usb_kbd_polling_callback;
118
119 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
120 usb_log_debug("Found mouse endpoint.\n");
121
122 // save the pipe index and device type
123 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
124 hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
125
126 // set the polling callback
127 hid_dev->poll_callback = usb_dummy_polling_callback;
128
129 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
130 usb_log_debug("Found generic HID endpoint.\n");
131
132 // save the pipe index and device type
133 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
134 hid_dev->device_type = USB_HID_PROTOCOL_NONE;
135
136 // set the polling callback
137 hid_dev->poll_callback = usb_hid_polling_callback;
138
139 } else {
140 usb_log_warning("None of supported endpoints found - probably"
141 " not a supported device.\n");
142 return ENOTSUP;
143 }
144
145 return EOK;
146}
147
148/*----------------------------------------------------------------------------*/
149
150static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
151{
152 /* Initialize the report parser. */
153 int rc = usb_hid_parser_init(hid_dev->parser);
154 if (rc != EOK) {
155 usb_log_error("Failed to initialize report parser.\n");
156 return rc;
157 }
158
159 /* Get the report descriptor and parse it. */
160 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
161 hid_dev->parser);
162
163 if (rc != EOK) {
164 usb_log_warning("Could not process report descriptor.\n");
165
166 if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {
167 usb_log_warning("Falling back to boot protocol.\n");
168
169 rc = usb_kbd_set_boot_protocol(hid_dev);
170
171 } else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
172 usb_log_warning("No boot protocol for mouse yet.\n");
173 rc = ENOTSUP;
174 }
175 }
176
177 return rc;
178}
179
180/*----------------------------------------------------------------------------*/
181
182int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
183{
184 int rc;
185
186 usb_log_debug("Initializing HID structure...\n");
187
188 if (hid_dev == NULL) {
189 usb_log_error("Failed to init HID structure: no structure given"
190 ".\n");
191 return EINVAL;
192 }
193
194 if (dev == NULL) {
195 usb_log_error("Failed to init HID structure: no USB device"
196 " given.\n");
197 return EINVAL;
198 }
199
200 /* The USB device should already be initialized, save it in structure */
201 hid_dev->usb_dev = dev;
202
203 rc = usb_hid_check_pipes(hid_dev, dev);
204 if (rc != EOK) {
205 return rc;
206 }
207
208 rc = usb_hid_init_parser(hid_dev);
209 if (rc != EOK) {
210 usb_log_error("Failed to initialize HID parser.\n");
211 return rc;
212 }
213
214 switch (hid_dev->device_type) {
215 case USB_HID_PROTOCOL_KEYBOARD:
216 // initialize the keyboard structure
217 rc = usb_kbd_init(hid_dev);
218 if (rc != EOK) {
219 usb_log_warning("Failed to initialize KBD structure."
220 "\n");
221 }
222 break;
223 case USB_HID_PROTOCOL_MOUSE:
224 break;
225 default:
226// usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
227// hid_dev->usb_dev->interface_no, 0);
228 break;
229 }
230
231 return rc;
232}
233
234/*----------------------------------------------------------------------------*/
235
236void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
237 void *arg)
238{
239 if (dev == NULL || arg == NULL) {
240 return;
241 }
242
243 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
244
245 usb_hid_free(&hid_dev);
246}
247
248/*----------------------------------------------------------------------------*/
249
250const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
251{
252 switch (device_type) {
253 case USB_HID_PROTOCOL_KEYBOARD:
254 return HID_KBD_FUN_NAME;
255 break;
256 case USB_HID_PROTOCOL_MOUSE:
257 return HID_MOUSE_FUN_NAME;
258 break;
259 default:
260 return HID_GENERIC_FUN_NAME;
261 }
262}
263
264/*----------------------------------------------------------------------------*/
265
266const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
267{
268 switch (device_type) {
269 case USB_HID_PROTOCOL_KEYBOARD:
270 return HID_KBD_CLASS_NAME;
271 break;
272 case USB_HID_PROTOCOL_MOUSE:
273 return HID_MOUSE_CLASS_NAME;
274 break;
275 default:
276 return HID_GENERIC_CLASS_NAME;
277 }
278}
279
280/*----------------------------------------------------------------------------*/
281
282void usb_hid_free(usb_hid_dev_t **hid_dev)
283{
284 if (hid_dev == NULL || *hid_dev == NULL) {
285 return;
286 }
287
288 switch ((*hid_dev)->device_type) {
289 case USB_HID_PROTOCOL_KEYBOARD:
290 usb_kbd_deinit(*hid_dev);
291 break;
292 case USB_HID_PROTOCOL_MOUSE:
293 break;
294 default:
295 break;
296 }
297
298 // destroy the parser
299 if ((*hid_dev)->parser != NULL) {
300 usb_hid_free_report_parser((*hid_dev)->parser);
301 }
302
303 if ((*hid_dev)->report_desc != NULL) {
304 free((*hid_dev)->report_desc);
305 }
306
307 free(*hid_dev);
308 *hid_dev = NULL;
309}
310
311/**
312 * @}
313 */
Note: See TracBrowser for help on using the repository browser.