source: mainline/uspace/drv/usbhid/usbhid.c@ ba358ed

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

Minor changes

  • ifdef guards renamed
  • Property mode set to 100644
File size: 10.9 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#include "mouse/mousedev.h"
50
51/*----------------------------------------------------------------------------*/
52
53/* Array of endpoints expected on the device, NULL terminated. */
54usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
55 &usb_hid_kbd_poll_endpoint_description,
56 &usb_hid_mouse_poll_endpoint_description,
57 &usb_hid_generic_poll_endpoint_description,
58 NULL
59};
60
61/*----------------------------------------------------------------------------*/
62
63static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
64{
65 assert(hid_dev->subdriver_count == 0);
66
67 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
68 sizeof(usb_hid_subdriver_t));
69 if (hid_dev->subdrivers == NULL) {
70 return ENOMEM;
71 }
72
73 // set the init callback
74 hid_dev->subdrivers[0].init = usb_kbd_init;
75
76 // set the polling callback
77 hid_dev->subdrivers[0].poll = usb_kbd_polling_callback;
78
79 // set the polling ended callback
80 hid_dev->subdrivers[0].poll_end = NULL;
81
82 // set the deinit callback
83 hid_dev->subdrivers[0].deinit = usb_kbd_deinit;
84
85 // set subdriver count
86 hid_dev->subdriver_count = 1;
87
88 return EOK;
89}
90
91/*----------------------------------------------------------------------------*/
92
93static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
94{
95 assert(hid_dev->subdriver_count == 0);
96
97 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
98 sizeof(usb_hid_subdriver_t));
99 if (hid_dev->subdrivers == NULL) {
100 return ENOMEM;
101 }
102
103 // set the init callback
104 hid_dev->subdrivers[0].init = usb_mouse_init;
105
106 // set the polling callback
107 hid_dev->subdrivers[0].poll = usb_mouse_polling_callback;
108
109 // set the polling ended callback
110 hid_dev->subdrivers[0].poll_end = NULL;
111
112 // set the deinit callback
113 hid_dev->subdrivers[0].deinit = usb_mouse_deinit;
114
115 // set subdriver count
116 hid_dev->subdriver_count = 1;
117
118 return EOK;
119}
120
121/*----------------------------------------------------------------------------*/
122
123static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
124{
125 assert(hid_dev->subdriver_count == 0);
126
127 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
128 sizeof(usb_hid_subdriver_t));
129 if (hid_dev->subdrivers == NULL) {
130 return ENOMEM;
131 }
132
133 // set the init callback
134 hid_dev->subdrivers[0].init = NULL;
135
136 // set the polling callback
137 hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
138
139 // set the polling ended callback
140 hid_dev->subdrivers[0].poll_end = NULL;
141
142 // set the deinit callback
143 hid_dev->subdrivers[0].deinit = NULL;
144
145 return EOK;
146}
147
148/*----------------------------------------------------------------------------*/
149
150static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
151{
152 return EOK;
153}
154
155/*----------------------------------------------------------------------------*/
156
157static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
158{
159 // first try to find subdrivers that may want to handle this device
160 int rc = usb_hid_find_subdrivers(hid_dev);
161
162 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
163 usb_log_debug("Found keyboard endpoint.\n");
164
165 // save the pipe index
166 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
167
168 // if no subdrivers registered, use the boot kbd subdriver
169 if (hid_dev->subdriver_count == 0) {
170 rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
171 }
172 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
173 usb_log_debug("Found mouse endpoint.\n");
174
175 // save the pipe index
176 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
177 //hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
178
179 // if no subdrivers registered, use the boot kbd subdriver
180 if (hid_dev->subdriver_count == 0) {
181 rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
182 }
183 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
184 usb_log_debug("Found generic HID endpoint.\n");
185
186 // save the pipe index
187 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
188
189 if (hid_dev->subdriver_count == 0) {
190 usb_log_warning("Found no subdriver for handling this"
191 " HID device. Setting generic HID subdriver.\n");
192 usb_hid_set_generic_hid_subdriver(hid_dev);
193 return EOK;
194 }
195 } else {
196 usb_log_error("None of supported endpoints found - probably"
197 " not a supported device.\n");
198 rc = ENOTSUP;
199 }
200
201 return rc;
202}
203
204/*----------------------------------------------------------------------------*/
205
206static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
207{
208 /* Initialize the report parser. */
209 int rc = usb_hid_parser_init(hid_dev->parser);
210 if (rc != EOK) {
211 usb_log_error("Failed to initialize report parser.\n");
212 return rc;
213 }
214
215 /* Get the report descriptor and parse it. */
216 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
217 hid_dev->parser);
218
219 // TODO: remove the hack
220 if (rc != EOK || hid_dev->poll_pipe_index == USB_HID_MOUSE_POLL_EP_NO) {
221 usb_log_warning("Could not process report descriptor.\n");
222
223 if (hid_dev->poll_pipe_index == USB_HID_KBD_POLL_EP_NO) {
224 usb_log_warning("Falling back to boot protocol.\n");
225 rc = usb_kbd_set_boot_protocol(hid_dev);
226 } else if (hid_dev->poll_pipe_index
227 == USB_HID_MOUSE_POLL_EP_NO) {
228 usb_log_warning("Falling back to boot protocol.\n");
229 rc = usb_mouse_set_boot_protocol(hid_dev);
230 }
231 }
232
233 return rc;
234}
235
236/*----------------------------------------------------------------------------*/
237
238usb_hid_dev_t *usb_hid_new(void)
239{
240 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
241 sizeof(usb_hid_dev_t));
242
243 if (hid_dev == NULL) {
244 usb_log_fatal("No memory!\n");
245 return NULL;
246 }
247
248 hid_dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
249 usb_hid_report_parser_t)));
250 if (hid_dev->parser == NULL) {
251 usb_log_fatal("No memory!\n");
252 free(hid_dev);
253 return NULL;
254 }
255
256 return hid_dev;
257}
258
259/*----------------------------------------------------------------------------*/
260
261int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
262{
263 int rc, i;
264
265 usb_log_debug("Initializing HID structure...\n");
266
267 if (hid_dev == NULL) {
268 usb_log_error("Failed to init HID structure: no structure given"
269 ".\n");
270 return EINVAL;
271 }
272
273 if (dev == NULL) {
274 usb_log_error("Failed to init HID structure: no USB device"
275 " given.\n");
276 return EINVAL;
277 }
278
279 /* The USB device should already be initialized, save it in structure */
280 hid_dev->usb_dev = dev;
281
282 rc = usb_hid_check_pipes(hid_dev, dev);
283 if (rc != EOK) {
284 return rc;
285 }
286
287 rc = usb_hid_init_parser(hid_dev);
288 if (rc != EOK) {
289 usb_log_error("Failed to initialize HID parser.\n");
290 return rc;
291 }
292
293 for (i = 0; i < hid_dev->subdriver_count; ++i) {
294 if (hid_dev->subdrivers[i].init != NULL) {
295 rc = hid_dev->subdrivers[i].init(hid_dev);
296 if (rc != EOK) {
297 usb_log_warning("Failed to initialize HID"
298 " subdriver structure.\n");
299 }
300 }
301 }
302
303 return rc;
304}
305
306/*----------------------------------------------------------------------------*/
307
308bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
309 size_t buffer_size, void *arg)
310{
311 int i;
312
313 if (dev == NULL || arg == NULL || buffer == NULL) {
314 usb_log_error("Missing arguments to polling callback.\n");
315 return false;
316 }
317
318 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
319
320 bool cont = false;
321
322 // continue if at least one of the subdrivers want to continue
323 for (i = 0; i < hid_dev->subdriver_count; ++i) {
324 if (hid_dev->subdrivers[i].poll != NULL
325 && hid_dev->subdrivers[i].poll(hid_dev, buffer,
326 buffer_size)) {
327 cont = true;
328 }
329 }
330
331 return cont;
332}
333
334/*----------------------------------------------------------------------------*/
335
336void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
337 void *arg)
338{
339 int i;
340
341 if (dev == NULL || arg == NULL) {
342 return;
343 }
344
345 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
346
347 for (i = 0; i < hid_dev->subdriver_count; ++i) {
348 if (hid_dev->subdrivers[i].poll_end != NULL) {
349 hid_dev->subdrivers[i].poll_end(hid_dev, reason);
350 }
351 }
352
353 usb_hid_free(&hid_dev);
354}
355
356/*----------------------------------------------------------------------------*/
357
358const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev)
359{
360 switch (hid_dev->poll_pipe_index) {
361 case USB_HID_KBD_POLL_EP_NO:
362 return HID_KBD_FUN_NAME;
363 break;
364 case USB_HID_MOUSE_POLL_EP_NO:
365 return HID_MOUSE_FUN_NAME;
366 break;
367 default:
368 return HID_GENERIC_FUN_NAME;
369 }
370}
371
372/*----------------------------------------------------------------------------*/
373
374const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev)
375{
376 // this means that only boot protocol keyboards will be connected
377 // to the console; there is probably no better way to do this
378
379 switch (hid_dev->poll_pipe_index) {
380 case USB_HID_KBD_POLL_EP_NO:
381 return HID_KBD_CLASS_NAME;
382 break;
383 case USB_HID_MOUSE_POLL_EP_NO:
384 return HID_MOUSE_CLASS_NAME;
385 break;
386 default:
387 return HID_GENERIC_CLASS_NAME;
388 }
389}
390
391/*----------------------------------------------------------------------------*/
392
393void usb_hid_free(usb_hid_dev_t **hid_dev)
394{
395 int i;
396
397 if (hid_dev == NULL || *hid_dev == NULL) {
398 return;
399 }
400
401 for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
402 if ((*hid_dev)->subdrivers[i].deinit != NULL) {
403 (*hid_dev)->subdrivers[i].deinit(*hid_dev);
404 }
405 }
406
407 // destroy the parser
408 if ((*hid_dev)->parser != NULL) {
409 usb_hid_free_report_parser((*hid_dev)->parser);
410 }
411
412 if ((*hid_dev)->report_desc != NULL) {
413 free((*hid_dev)->report_desc);
414 }
415
416 free(*hid_dev);
417 *hid_dev = NULL;
418}
419
420/**
421 * @}
422 */
Note: See TracBrowser for help on using the repository browser.