source: mainline/uspace/drv/usbhid/usbhid.c@ 62bd8d3

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

First draft of subdriver mappings.

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