source: mainline/uspace/drv/usbhid/usbhid.c@ 61f49a0

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

Changed way of remembering if event was picked up.

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