source: mainline/uspace/drv/usbhid/usbhid.c@ 3a6e423

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3a6e423 was 3a6e423, checked in by Matej Klonfar <maklf@…>, 14 years ago

Parsing of usages in case of array items repaired

  • Property mode set to 100644
File size: 17.4 KB
RevLine 
[966acede]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>
[61257f4]39#include <usb/classes/hid.h>
40#include <usb/classes/hidparser.h>
41#include <usb/classes/hidreport.h>
[7f2e33a]42#include <usb/classes/hidreq.h>
[61257f4]43#include <errno.h>
[f76153ce]44#include <str_error.h>
[966acede]45
46#include "usbhid.h"
47
[61257f4]48#include "kbd/kbddev.h"
[dd10e07]49#include "generic/hiddev.h"
[e9f0348]50#include "mouse/mousedev.h"
[62bd8d3]51#include "subdrivers.h"
[61257f4]52
[966acede]53/*----------------------------------------------------------------------------*/
54
55/* Array of endpoints expected on the device, NULL terminated. */
[fec47d4]56usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
57 &usb_hid_kbd_poll_endpoint_description,
58 &usb_hid_mouse_poll_endpoint_description,
[61257f4]59 &usb_hid_generic_poll_endpoint_description,
[966acede]60 NULL
61};
62
[f76153ce]63static const int USB_HID_MAX_SUBDRIVERS = 10;
64
[dd3eda2]65static fibril_local bool report_received;
66
[966acede]67/*----------------------------------------------------------------------------*/
68
[60c0573]69static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
[61257f4]70{
[e7df6cd]71 assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
[61257f4]72
[60c0573]73 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
74 sizeof(usb_hid_subdriver_t));
75 if (hid_dev->subdrivers == NULL) {
76 return ENOMEM;
[61257f4]77 }
78
[60c0573]79 // set the init callback
80 hid_dev->subdrivers[0].init = usb_kbd_init;
81
82 // set the polling callback
83 hid_dev->subdrivers[0].poll = usb_kbd_polling_callback;
84
85 // set the polling ended callback
86 hid_dev->subdrivers[0].poll_end = NULL;
87
88 // set the deinit callback
89 hid_dev->subdrivers[0].deinit = usb_kbd_deinit;
90
91 // set subdriver count
92 hid_dev->subdriver_count = 1;
93
94 return EOK;
95}
96
97/*----------------------------------------------------------------------------*/
98
99static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
100{
[e7df6cd]101 assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
[60c0573]102
103 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
104 sizeof(usb_hid_subdriver_t));
105 if (hid_dev->subdrivers == NULL) {
106 return ENOMEM;
[61257f4]107 }
108
[60c0573]109 // set the init callback
110 hid_dev->subdrivers[0].init = usb_mouse_init;
111
112 // set the polling callback
113 hid_dev->subdrivers[0].poll = usb_mouse_polling_callback;
114
115 // set the polling ended callback
116 hid_dev->subdrivers[0].poll_end = NULL;
117
118 // set the deinit callback
119 hid_dev->subdrivers[0].deinit = usb_mouse_deinit;
120
121 // set subdriver count
122 hid_dev->subdriver_count = 1;
123
124 return EOK;
125}
126
127/*----------------------------------------------------------------------------*/
128
129static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
130{
[e7df6cd]131 assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
[60c0573]132
133 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
134 sizeof(usb_hid_subdriver_t));
135 if (hid_dev->subdrivers == NULL) {
136 return ENOMEM;
137 }
138
139 // set the init callback
[3facf63a]140 hid_dev->subdrivers[0].init = usb_generic_hid_init;
[60c0573]141
142 // set the polling callback
143 hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
144
145 // set the polling ended callback
146 hid_dev->subdrivers[0].poll_end = NULL;
147
148 // set the deinit callback
149 hid_dev->subdrivers[0].deinit = NULL;
150
[f76153ce]151 // set subdriver count
152 hid_dev->subdriver_count = 1;
153
[60c0573]154 return EOK;
155}
156
157/*----------------------------------------------------------------------------*/
158
[f76153ce]159static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev,
160 const usb_hid_subdriver_mapping_t *mapping)
161{
[36f737a]162 assert(hid_dev != NULL);
163 assert(hid_dev->usb_dev != NULL);
164
165 return (hid_dev->usb_dev->descriptors.device.vendor_id
166 == mapping->vendor_id
167 && hid_dev->usb_dev->descriptors.device.product_id
168 == mapping->product_id);
[f76153ce]169}
170
171/*----------------------------------------------------------------------------*/
172
173static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
[e3b5129]174 const usb_hid_subdriver_mapping_t *mapping)
[f76153ce]175{
176 assert(hid_dev != NULL);
[e3b5129]177 assert(mapping != NULL);
[f76153ce]178
179 usb_hid_report_path_t *usage_path = usb_hid_report_path();
180 if (usage_path == NULL) {
[1cbb4b7]181 usb_log_debug("Failed to create usage path.\n");
[f76153ce]182 return false;
183 }
[777e336]184 int i = 0;
[e3b5129]185 while (mapping->usage_path[i].usage != 0
186 || mapping->usage_path[i].usage_page != 0) {
[f76153ce]187 if (usb_hid_report_path_append_item(usage_path,
[e3b5129]188 mapping->usage_path[i].usage_page,
189 mapping->usage_path[i].usage) != EOK) {
[1cbb4b7]190 usb_log_debug("Failed to append to usage path.\n");
[f76153ce]191 usb_hid_report_path_free(usage_path);
192 return false;
193 }
[777e336]194 ++i;
[f76153ce]195 }
196
[e3b5129]197 if (mapping->report_id >= 0) {
198 usb_hid_report_path_set_report_id(usage_path,
199 mapping->report_id);
[f76153ce]200 }
201
[e60436b]202 assert(hid_dev->report != NULL);
[1cbb4b7]203
[e3b5129]204 usb_log_debug("Compare flags: %d\n", mapping->compare);
[3a6e423]205// size_t size = usb_hid_report_size(hid_dev->report, 0,
206// USB_HID_REPORT_TYPE_INPUT);
207 size_t size = 0;
208 usb_hid_report_field_t *field = usb_hid_report_get_sibling (hid_dev->report,
209 NULL, usage_path, mapping->compare, USB_HID_REPORT_TYPE_INPUT);
210 while(field != NULL) {
211 size++;
212 field = usb_hid_report_get_sibling (hid_dev->report,
213 field, usage_path, mapping->compare,
214 USB_HID_REPORT_TYPE_INPUT);
215 }
[f76153ce]216
[3a6e423]217 usb_log_debug("Size of the input report: %zuB\n", size);
[f76153ce]218 usb_hid_report_path_free(usage_path);
219
[1cbb4b7]220 return (size > 0);
[f76153ce]221}
222
223/*----------------------------------------------------------------------------*/
224
225static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
226 const usb_hid_subdriver_t **subdrivers, int count)
[60c0573]227{
[f76153ce]228 int i;
229
230 if (count <= 0) {
231 hid_dev->subdriver_count = 0;
232 hid_dev->subdrivers = NULL;
233 return EOK;
234 }
235
236 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(count *
237 sizeof(usb_hid_subdriver_t));
238 if (hid_dev->subdrivers == NULL) {
239 return ENOMEM;
240 }
241
242 for (i = 0; i < count; ++i) {
243 hid_dev->subdrivers[i].init = subdrivers[i]->init;
244 hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit;
245 hid_dev->subdrivers[i].poll = subdrivers[i]->poll;
246 hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end;
247 }
248
249 hid_dev->subdriver_count = count;
250
[60c0573]251 return EOK;
[61257f4]252}
[966acede]253
254/*----------------------------------------------------------------------------*/
255
[f76153ce]256static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
257{
[e7df6cd]258 assert(hid_dev != NULL);
259
[f76153ce]260 const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
261
262 int i = 0, count = 0;
263 const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i];
[4bb9fd2]264
265 bool ids_matched;
266 bool matched;
[f76153ce]267
268 while (count < USB_HID_MAX_SUBDRIVERS &&
269 (mapping->usage_path != NULL
[d0a6e54]270 || mapping->vendor_id >= 0 || mapping->product_id >= 0)) {
[f76153ce]271 // check the vendor & product ID
[d0a6e54]272 if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
273 usb_log_warning("Missing Product ID for Vendor ID %d\n",
[f76153ce]274 mapping->vendor_id);
275 return EINVAL;
276 }
[d0a6e54]277 if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
278 usb_log_warning("Missing Vendor ID for Product ID %d\n",
[f76153ce]279 mapping->product_id);
280 return EINVAL;
281 }
282
[4bb9fd2]283 ids_matched = false;
284 matched = false;
285
[d0a6e54]286 if (mapping->vendor_id >= 0) {
287 assert(mapping->product_id >= 0);
[777e336]288 usb_log_debug("Comparing device against vendor ID %u"
289 " and product ID %u.\n", mapping->vendor_id,
[f76153ce]290 mapping->product_id);
291 if (usb_hid_ids_match(hid_dev, mapping)) {
[4bb9fd2]292 usb_log_debug("IDs matched.\n");
293 ids_matched = true;
[f76153ce]294 }
295 }
296
297 if (mapping->usage_path != NULL) {
[1cbb4b7]298 usb_log_debug("Comparing device against usage path.\n");
[e3b5129]299 if (usb_hid_path_matches(hid_dev, mapping)) {
[4bb9fd2]300 // does not matter if IDs were matched
301 matched = true;
[f76153ce]302 }
[4bb9fd2]303 } else {
304 // matched only if IDs were matched and there is no path
305 matched = ids_matched;
[f76153ce]306 }
[4bb9fd2]307
308 if (matched) {
309 subdrivers[count++] = &mapping->subdriver;
[f76153ce]310 }
[4bb9fd2]311
[f76153ce]312 mapping = &usb_hid_subdrivers[++i];
313 }
314
315 // we have all subdrivers determined, save them into the hid device
316 return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
317}
318
319/*----------------------------------------------------------------------------*/
320
[61257f4]321static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
[966acede]322{
[e7df6cd]323 assert(hid_dev != NULL && dev != NULL);
324
[f76153ce]325 int rc = EOK;
[60c0573]326
[61257f4]327 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
328 usb_log_debug("Found keyboard endpoint.\n");
[60c0573]329 // save the pipe index
[61257f4]330 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
331 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
332 usb_log_debug("Found mouse endpoint.\n");
[60c0573]333 // save the pipe index
[61257f4]334 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
335 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
336 usb_log_debug("Found generic HID endpoint.\n");
[60c0573]337 // save the pipe index
[61257f4]338 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
339 } else {
[60c0573]340 usb_log_error("None of supported endpoints found - probably"
[61257f4]341 " not a supported device.\n");
[60c0573]342 rc = ENOTSUP;
[61257f4]343 }
344
[60c0573]345 return rc;
[61257f4]346}
347
348/*----------------------------------------------------------------------------*/
349
[60c0573]350usb_hid_dev_t *usb_hid_new(void)
351{
352 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
353 sizeof(usb_hid_dev_t));
354
355 if (hid_dev == NULL) {
356 usb_log_fatal("No memory!\n");
357 return NULL;
358 }
359
[e60436b]360 hid_dev->report = (usb_hid_report_t *)(malloc(sizeof(
[e50cd7f]361 usb_hid_report_t)));
[e60436b]362 if (hid_dev->report == NULL) {
[60c0573]363 usb_log_fatal("No memory!\n");
364 free(hid_dev);
365 return NULL;
366 }
367
[f76153ce]368 hid_dev->poll_pipe_index = -1;
369
[60c0573]370 return hid_dev;
371}
372
373/*----------------------------------------------------------------------------*/
374
[61257f4]375int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
376{
[60c0573]377 int rc, i;
[61257f4]378
379 usb_log_debug("Initializing HID structure...\n");
380
381 if (hid_dev == NULL) {
382 usb_log_error("Failed to init HID structure: no structure given"
383 ".\n");
384 return EINVAL;
385 }
386
387 if (dev == NULL) {
388 usb_log_error("Failed to init HID structure: no USB device"
389 " given.\n");
390 return EINVAL;
391 }
392
393 /* The USB device should already be initialized, save it in structure */
394 hid_dev->usb_dev = dev;
395
396 rc = usb_hid_check_pipes(hid_dev, dev);
397 if (rc != EOK) {
[aaf6155]398 //usb_hid_free(&hid_dev);
[61257f4]399 return rc;
400 }
[e50cd7f]401
[f76153ce]402 /* Get the report descriptor and parse it. */
403 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
[e60436b]404 hid_dev->report);
[f76153ce]405
406 bool fallback = false;
407
408 if (rc == EOK) {
409 // try to find subdrivers that may want to handle this device
410 rc = usb_hid_find_subdrivers(hid_dev);
411 if (rc != EOK || hid_dev->subdriver_count == 0) {
412 // try to fall back to the boot protocol if available
413 usb_log_info("No subdrivers found to handle this"
414 " device.\n");
415 fallback = true;
[aaf6155]416 assert(hid_dev->subdrivers == NULL);
417 assert(hid_dev->subdriver_count == 0);
[f76153ce]418 }
419 } else {
420 usb_log_error("Failed to parse Report descriptor.\n");
421 // try to fall back to the boot protocol if available
422 fallback = true;
423 }
424
[7bb8036]425 if (fallback) {
[f76153ce]426 // fall back to boot protocol
427 switch (hid_dev->poll_pipe_index) {
428 case USB_HID_KBD_POLL_EP_NO:
429 usb_log_info("Falling back to kbd boot protocol.\n");
430 rc = usb_kbd_set_boot_protocol(hid_dev);
431 if (rc == EOK) {
432 rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
[60c0573]433 }
[f76153ce]434 break;
435 case USB_HID_MOUSE_POLL_EP_NO:
436 usb_log_info("Falling back to mouse boot protocol.\n");
437 rc = usb_mouse_set_boot_protocol(hid_dev);
438 if (rc == EOK) {
439 rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
440 }
441 break;
442 default:
443 assert(hid_dev->poll_pipe_index
444 == USB_HID_GENERIC_POLL_EP_NO);
445
446 /* TODO: this has no meaning if the report descriptor
447 is not parsed */
448 usb_log_info("Falling back to generic HID driver.\n");
449 rc = usb_hid_set_generic_hid_subdriver(hid_dev);
[e9f0348]450 }
[61257f4]451 }
452
[f76153ce]453 if (rc != EOK) {
454 usb_log_error("No subdriver for handling this device could be"
455 " initialized: %s.\n", str_error(rc));
[aaf6155]456 usb_log_debug("Subdriver count: %d\n",
457 hid_dev->subdriver_count);
458 //usb_hid_free(&hid_dev);
[f76153ce]459 } else {
460 bool ok = false;
461
462 usb_log_debug("Subdriver count: %d\n",
463 hid_dev->subdriver_count);
464
465 for (i = 0; i < hid_dev->subdriver_count; ++i) {
466 if (hid_dev->subdrivers[i].init != NULL) {
467 usb_log_debug("Initializing subdriver %d.\n",i);
468 rc = hid_dev->subdrivers[i].init(hid_dev);
469 if (rc != EOK) {
470 usb_log_warning("Failed to initialize"
471 " HID subdriver structure.\n");
472 } else {
473 // at least one subdriver initialized
474 ok = true;
475 }
476 } else {
477 ok = true;
478 }
479 }
480
481 rc = (ok) ? EOK : -1; // what error to report
482 }
483
[61257f4]484 return rc;
485}
486
487/*----------------------------------------------------------------------------*/
488
[60c0573]489bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
490 size_t buffer_size, void *arg)
491{
492 int i;
493
494 if (dev == NULL || arg == NULL || buffer == NULL) {
495 usb_log_error("Missing arguments to polling callback.\n");
496 return false;
497 }
498
499 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
500
[054537b]501 int allocated = (hid_dev->input_report != NULL);
[31cfee16]502
503 if (!allocated
504 || hid_dev->input_report_size < buffer_size) {
505 uint8_t *input_old = hid_dev->input_report;
506 uint8_t *input_new = (uint8_t *)malloc(buffer_size);
507
508 if (input_new == NULL) {
509 usb_log_error("Failed to allocate space for input "
510 "buffer. This event may not be reported\n");
511 memset(hid_dev->input_report, 0,
512 hid_dev->input_report_size);
513 } else {
514 memcpy(input_new, input_old,
515 hid_dev->input_report_size);
516 hid_dev->input_report = input_new;
517 if (allocated) {
518 free(input_old);
519 }
[dd3eda2]520 usb_hid_new_report();
[31cfee16]521 }
522 }
523
524 /*! @todo This should probably be atomic. */
525 memcpy(hid_dev->input_report, buffer, buffer_size);
526 hid_dev->input_report_size = buffer_size;
527
[60c0573]528 bool cont = false;
529
530 // continue if at least one of the subdrivers want to continue
531 for (i = 0; i < hid_dev->subdriver_count; ++i) {
532 if (hid_dev->subdrivers[i].poll != NULL
533 && hid_dev->subdrivers[i].poll(hid_dev, buffer,
534 buffer_size)) {
535 cont = true;
536 }
537 }
538
539 return cont;
540}
541
542/*----------------------------------------------------------------------------*/
543
[61257f4]544void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason,
545 void *arg)
546{
[60c0573]547 int i;
548
[61257f4]549 if (dev == NULL || arg == NULL) {
550 return;
551 }
552
553 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
554
[60c0573]555 for (i = 0; i < hid_dev->subdriver_count; ++i) {
556 if (hid_dev->subdrivers[i].poll_end != NULL) {
557 hid_dev->subdrivers[i].poll_end(hid_dev, reason);
558 }
559 }
560
[61257f4]561 usb_hid_free(&hid_dev);
562}
563
564/*----------------------------------------------------------------------------*/
565
[31cfee16]566//const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev)
567//{
568// switch (hid_dev->poll_pipe_index) {
569// case USB_HID_KBD_POLL_EP_NO:
570// return HID_KBD_FUN_NAME;
571// break;
572// case USB_HID_MOUSE_POLL_EP_NO:
573// return HID_MOUSE_FUN_NAME;
574// break;
575// default:
576// return HID_GENERIC_FUN_NAME;
577// }
578//}
[61257f4]579
580/*----------------------------------------------------------------------------*/
581
[31cfee16]582//const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev)
583//{
584// // this means that only boot protocol keyboards will be connected
585// // to the console; there is probably no better way to do this
586
587// switch (hid_dev->poll_pipe_index) {
588// case USB_HID_KBD_POLL_EP_NO:
589// return HID_KBD_CLASS_NAME;
590// break;
591// case USB_HID_MOUSE_POLL_EP_NO:
592// return HID_MOUSE_CLASS_NAME;
593// break;
594// default:
595// return HID_GENERIC_CLASS_NAME;
596// }
597//}
[61257f4]598
599/*----------------------------------------------------------------------------*/
600
[dd3eda2]601void usb_hid_new_report(void)
602{
603 report_received = false;
604}
605
606/*----------------------------------------------------------------------------*/
607
608void usb_hid_report_received(void)
609{
610 report_received = true;
611}
612
613/*----------------------------------------------------------------------------*/
614
615bool usb_hid_report_ready(void)
616{
617 return !report_received;
618}
619
620/*----------------------------------------------------------------------------*/
621
[61257f4]622void usb_hid_free(usb_hid_dev_t **hid_dev)
623{
[60c0573]624 int i;
625
[61257f4]626 if (hid_dev == NULL || *hid_dev == NULL) {
627 return;
628 }
629
[aaf6155]630 usb_log_debug("Subdrivers: %p, subdriver count: %d\n",
631 (*hid_dev)->subdrivers, (*hid_dev)->subdriver_count);
632
[f76153ce]633 assert((*hid_dev)->subdrivers != NULL
634 || (*hid_dev)->subdriver_count == 0);
635
[60c0573]636 for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
637 if ((*hid_dev)->subdrivers[i].deinit != NULL) {
638 (*hid_dev)->subdrivers[i].deinit(*hid_dev);
639 }
[61257f4]640 }
[f76153ce]641
642 // free the subdrivers info
643 if ((*hid_dev)->subdrivers != NULL) {
[1cbb4b7]644 free((*hid_dev)->subdrivers);
[f76153ce]645 }
[61257f4]646
647 // destroy the parser
[e60436b]648 if ((*hid_dev)->report != NULL) {
649 usb_hid_free_report((*hid_dev)->report);
[61257f4]650 }
651
652 if ((*hid_dev)->report_desc != NULL) {
653 free((*hid_dev)->report_desc);
654 }
655
656 free(*hid_dev);
657 *hid_dev = NULL;
[966acede]658}
659
660/**
661 * @}
662 */
Note: See TracBrowser for help on using the repository browser.