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

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

Saving byte size of report to usb_hid_dev_t + removed printf from driver.c

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