source: mainline/uspace/drv/hid/usbhid/usbhid.c@ 1b20da0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1b20da0 was e0a5d4c, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usb: update copyrights

The data was generated by a script, guided manually. If you feel your
name is missing somewhere, please add it!

The semi-automated process was roughly:

1) Changes per file and author (limited to our team) were counted
2) Trivial numbers were thrown away
3) Authors were sorted by lines added to file
4) All previous copyrights were replaced by the newly generated one
5) Hunks changing only year were discarded

It seems that a lot of my copyrights were added. It is due to me being
both sticking my nose everywhere and lazy to update the copyright right
away :)

  • Property mode set to 100644
File size: 16.2 KB
RevLine 
[966acede]1/*
2 * Copyright (c) 2011 Lubos Slovak
[e0a5d4c]3 * Copyright (c) 2018 Petr Manek, Ondrej Hlavaty
[966acede]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup drvusbhid
31 * @{
32 */
33/**
34 * @file
35 * USB HID driver API.
36 */
37
38#include <usb/debug.h>
39#include <usb/classes/classes.h>
[faa44e58]40#include <usb/hid/hid.h>
41#include <usb/hid/hidparser.h>
42#include <usb/hid/hidreport.h>
43#include <usb/hid/request.h>
[bb70637]44
[61257f4]45#include <errno.h>
[bb70637]46#include <macros.h>
[f76153ce]47#include <str_error.h>
[966acede]48
49#include "usbhid.h"
50
[61257f4]51#include "kbd/kbddev.h"
[dd10e07]52#include "generic/hiddev.h"
[e9f0348]53#include "mouse/mousedev.h"
[62bd8d3]54#include "subdrivers.h"
[61257f4]55
[966acede]56/* Array of endpoints expected on the device, NULL terminated. */
[b803845]57const usb_endpoint_description_t *usb_hid_endpoints[] = {
[fec47d4]58 &usb_hid_kbd_poll_endpoint_description,
59 &usb_hid_mouse_poll_endpoint_description,
[61257f4]60 &usb_hid_generic_poll_endpoint_description,
[966acede]61 NULL
62};
[76fbd9a]63
[5a6cc679]64static errno_t usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
[61257f4]65{
[3f8f09f]66 assert(hid_dev != NULL);
67 assert(hid_dev->subdriver_count == 0);
[cc29622]68
[3f8f09f]69 hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
[60c0573]70 if (hid_dev->subdrivers == NULL) {
71 return ENOMEM;
[61257f4]72 }
[3f8f09f]73 hid_dev->subdriver_count = 1;
74 // TODO 0 should be keyboard, but find a better way
75 hid_dev->subdrivers[0] = usb_hid_subdrivers[0].subdriver;
[cc29622]76
[60c0573]77 return EOK;
78}
[76fbd9a]79
[5a6cc679]80static errno_t usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
[60c0573]81{
[3f8f09f]82 assert(hid_dev != NULL);
83 assert(hid_dev->subdriver_count == 0);
[cc29622]84
[3f8f09f]85 hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
[60c0573]86 if (hid_dev->subdrivers == NULL) {
87 return ENOMEM;
[61257f4]88 }
[3f8f09f]89 hid_dev->subdriver_count = 1;
90 // TODO 2 should be mouse, but find a better way
[6f730278]91 hid_dev->subdrivers[0] = usb_hid_subdrivers[2].subdriver;
[cc29622]92
[60c0573]93 return EOK;
94}
[76fbd9a]95
[5a6cc679]96static errno_t usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
[60c0573]97{
[07b9cbae]98 assert(hid_dev != NULL);
99 assert(hid_dev->subdriver_count == 0);
[cc29622]100
[3f8f09f]101 hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
[60c0573]102 if (hid_dev->subdrivers == NULL) {
103 return ENOMEM;
104 }
[3f8f09f]105 hid_dev->subdriver_count = 1;
[cc29622]106
[3f8f09f]107 /* Set generic hid subdriver routines */
108 hid_dev->subdrivers[0].init = usb_generic_hid_init;
109 hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
110 hid_dev->subdrivers[0].poll_end = NULL;
111 hid_dev->subdrivers[0].deinit = usb_generic_hid_deinit;
[cc29622]112
[60c0573]113 return EOK;
114}
[76fbd9a]115
[3f8f09f]116static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
[f76153ce]117 const usb_hid_subdriver_mapping_t *mapping)
118{
[945d66c]119 assert(hid_dev);
120 assert(hid_dev->usb_dev);
121 assert(mapping);
122 const usb_standard_device_descriptor_t *d =
[e2dfa86]123 &usb_device_descriptors(hid_dev->usb_dev)->device;
[945d66c]124
125 return (d->vendor_id == mapping->vendor_id)
126 && (d->product_id == mapping->product_id);
[f76153ce]127}
[76fbd9a]128
[3f8f09f]129static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
[e3b5129]130 const usb_hid_subdriver_mapping_t *mapping)
[f76153ce]131{
132 assert(hid_dev != NULL);
[e3b5129]133 assert(mapping != NULL);
[cc29622]134
[f76153ce]135 usb_hid_report_path_t *usage_path = usb_hid_report_path();
136 if (usage_path == NULL) {
[a1732929]137 usb_log_debug("Failed to create usage path.");
[f76153ce]138 return false;
139 }
[07b9cbae]140
141 for (int i = 0; mapping->usage_path[i].usage != 0
142 || mapping->usage_path[i].usage_page != 0; ++i) {
[3f8f09f]143 if (usb_hid_report_path_append_item(usage_path,
144 mapping->usage_path[i].usage_page,
[e3b5129]145 mapping->usage_path[i].usage) != EOK) {
[a1732929]146 usb_log_debug("Failed to append to usage path.");
[f76153ce]147 usb_hid_report_path_free(usage_path);
148 return false;
149 }
150 }
[cc29622]151
[a1732929]152 usb_log_debug("Compare flags: %d", mapping->compare);
[cc29622]153
[f3f9733]154 bool matches = false;
155 uint8_t report_id = mapping->report_id;
[dcb7d7cd]156
[19e0560e]157 do {
[a1732929]158 usb_log_debug("Trying report id %u", report_id);
[f3f9733]159 if (report_id != 0) {
[dcb7d7cd]160 usb_hid_report_path_set_report_id(usage_path,
[f3f9733]161 report_id);
[dcb7d7cd]162 }
163
[07b9cbae]164 const usb_hid_report_field_t *field =
165 usb_hid_report_get_sibling(
166 &hid_dev->report, NULL, usage_path, mapping->compare,
167 USB_HID_REPORT_TYPE_INPUT);
[a8c4e871]168
[a1732929]169 usb_log_debug("Field: %p", field);
[dcb7d7cd]170
[f3f9733]171 if (field != NULL) {
172 matches = true;
173 break;
[dcb7d7cd]174 }
[a8c4e871]175
[f3f9733]176 report_id = usb_hid_get_next_report_id(
[a8c4e871]177 &hid_dev->report, report_id, USB_HID_REPORT_TYPE_INPUT);
[f3f9733]178 } while (!matches && report_id != 0);
[cc29622]179
[f76153ce]180 usb_hid_report_path_free(usage_path);
[cc29622]181
[f3f9733]182 return matches;
[f76153ce]183}
[76fbd9a]184
[5a6cc679]185static errno_t usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
[07b9cbae]186 const usb_hid_subdriver_t **subdrivers, unsigned count)
[60c0573]187{
[07b9cbae]188 assert(hid_dev);
189 assert(subdrivers);
[cc29622]190
[07b9cbae]191 if (count == 0) {
[f76153ce]192 hid_dev->subdriver_count = 0;
193 hid_dev->subdrivers = NULL;
194 return EOK;
195 }
[cc29622]196
[3f8f09f]197 /* +1 for generic hid subdriver */
198 hid_dev->subdrivers = calloc((count + 1), sizeof(usb_hid_subdriver_t));
[f76153ce]199 if (hid_dev->subdrivers == NULL) {
200 return ENOMEM;
201 }
[cc29622]202
[07b9cbae]203 for (unsigned i = 0; i < count; ++i) {
204 hid_dev->subdrivers[i] = *subdrivers[i];
[f76153ce]205 }
[cc29622]206
[3f8f09f]207 /* Add one generic HID subdriver per device */
[78bfae9]208 hid_dev->subdrivers[count].init = usb_generic_hid_init;
209 hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
[c5b6db53]210 hid_dev->subdrivers[count].deinit = usb_generic_hid_deinit;
[78bfae9]211 hid_dev->subdrivers[count].poll_end = NULL;
[cc29622]212
[78bfae9]213 hid_dev->subdriver_count = count + 1;
[cc29622]214
[60c0573]215 return EOK;
[61257f4]216}
[76fbd9a]217
[5a6cc679]218static errno_t usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
[f76153ce]219{
[e7df6cd]220 assert(hid_dev != NULL);
[cc29622]221
[f76153ce]222 const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
[07b9cbae]223 unsigned count = 0;
[cc29622]224
[07b9cbae]225 for (unsigned i = 0; i < USB_HID_MAX_SUBDRIVERS; ++i) {
226 const usb_hid_subdriver_mapping_t *mapping =
227 &usb_hid_subdrivers[i];
228 /* Check the vendor & product ID. */
[d0a6e54]229 if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
[07b9cbae]230 usb_log_warning("Mapping[%d]: Missing Product ID for "
231 "Vendor ID %d\n", i, mapping->vendor_id);
[f76153ce]232 }
[d0a6e54]233 if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
[07b9cbae]234 usb_log_warning("Mapping[%d]: Missing Vendor ID for "
235 "Product ID %d\n", i, mapping->product_id);
[f76153ce]236 }
[3f8f09f]237
[07b9cbae]238 bool matched = false;
[3f8f09f]239
[07b9cbae]240 /* Check ID match. */
241 if (mapping->vendor_id >= 0 && mapping->product_id >= 0) {
[777e336]242 usb_log_debug("Comparing device against vendor ID %u"
243 " and product ID %u.\n", mapping->vendor_id,
[f76153ce]244 mapping->product_id);
245 if (usb_hid_ids_match(hid_dev, mapping)) {
[a1732929]246 usb_log_debug("IDs matched.");
[07b9cbae]247 matched = true;
[f76153ce]248 }
249 }
[3f8f09f]250
[07b9cbae]251 /* Check usage match. */
[f76153ce]252 if (mapping->usage_path != NULL) {
[a1732929]253 usb_log_debug("Comparing device against usage path.");
[e3b5129]254 if (usb_hid_path_matches(hid_dev, mapping)) {
[2d1ba51]255 /* Does not matter if IDs were matched. */
[4bb9fd2]256 matched = true;
[f76153ce]257 }
258 }
[3f8f09f]259
[4bb9fd2]260 if (matched) {
[a1732929]261 usb_log_debug("Subdriver matched.");
[4bb9fd2]262 subdrivers[count++] = &mapping->subdriver;
[f76153ce]263 }
264 }
[cc29622]265
[3f8f09f]266 /* We have all subdrivers determined, save them into the hid device */
[f76153ce]267 return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
268}
[76fbd9a]269
[5a6cc679]270static errno_t usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
[966acede]271{
[3f8f09f]272 assert(hid_dev);
273 assert(dev);
[cc29622]274
[90df90c]275 static const struct {
[bb70637]276 const usb_endpoint_description_t *desc;
[90df90c]277 const char* description;
278 } endpoints[] = {
[bb70637]279 {&usb_hid_kbd_poll_endpoint_description, "Keyboard endpoint"},
280 {&usb_hid_mouse_poll_endpoint_description, "Mouse endpoint"},
281 {&usb_hid_generic_poll_endpoint_description, "Generic HID endpoint"},
[90df90c]282 };
283
[bb70637]284 for (unsigned i = 0; i < ARRAY_SIZE(endpoints); ++i) {
285 usb_endpoint_mapping_t *epm =
286 usb_device_get_mapped_ep_desc(dev, endpoints[i].desc);
287 if (epm && epm->present) {
[a1732929]288 usb_log_debug("Found: %s.", endpoints[i].description);
[bb70637]289 hid_dev->poll_pipe_mapping = epm;
[90df90c]290 return EOK;
291 }
[61257f4]292 }
[90df90c]293 return ENOTSUP;
[61257f4]294}
[76fbd9a]295
[5a6cc679]296static errno_t usb_hid_init_report(usb_hid_dev_t *hid_dev)
[d1fb591]297{
[a8c4e871]298 assert(hid_dev != NULL);
[cc29622]299
[d1fb591]300 uint8_t report_id = 0;
301 size_t max_size = 0;
[cc29622]302
[a9cdca0]303 do {
[a1732929]304 usb_log_debug("Getting size of the report.");
[a8c4e871]305 const size_t size =
306 usb_hid_report_byte_size(&hid_dev->report, report_id,
307 USB_HID_REPORT_TYPE_INPUT);
[a1732929]308 usb_log_debug("Report ID: %u, size: %zu", report_id, size);
[8fb45e08]309 max_size = (size > max_size) ? size : max_size;
[a1732929]310 usb_log_debug("Getting next report ID");
[a8c4e871]311 report_id = usb_hid_get_next_report_id(&hid_dev->report,
[a9cdca0]312 report_id, USB_HID_REPORT_TYPE_INPUT);
313 } while (report_id != 0);
[cc29622]314
[a1732929]315 usb_log_debug("Max size of input report: %zu", max_size);
[cc29622]316
[d1fb591]317 assert(hid_dev->input_report == NULL);
[cc29622]318
[3f8f09f]319 hid_dev->input_report = calloc(1, max_size);
[d1fb591]320 if (hid_dev->input_report == NULL) {
321 return ENOMEM;
322 }
[3f8f09f]323 hid_dev->max_input_report_size = max_size;
[cc29622]324
[d1fb591]325 return EOK;
326}
[76fbd9a]327
[17c1d9db]328static bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
329 size_t buffer_size, void *arg)
330{
331 if (dev == NULL || arg == NULL || buffer == NULL) {
[a1732929]332 usb_log_error("Missing arguments to polling callback.");
[17c1d9db]333 return false;
334 }
335 usb_hid_dev_t *hid_dev = arg;
336
337 assert(hid_dev->input_report != NULL);
338
[a1732929]339 usb_log_debug("New data [%zu/%zu]: %s", buffer_size,
[17c1d9db]340 hid_dev->max_input_report_size,
341 usb_debug_str_buffer(buffer, buffer_size, 0));
342
343 if (hid_dev->max_input_report_size >= buffer_size) {
344 /*! @todo This should probably be atomic. */
345 memcpy(hid_dev->input_report, buffer, buffer_size);
346 hid_dev->input_report_size = buffer_size;
347 usb_hid_new_report(hid_dev);
348 }
349
350 /* Parse the input report */
[be01eb3]351 const errno_t rc = usb_hid_parse_report(
[17c1d9db]352 &hid_dev->report, buffer, buffer_size, &hid_dev->report_id);
353 if (rc != EOK) {
354 usb_log_warning("Failure in usb_hid_parse_report():"
355 "%s\n", str_error(rc));
356 }
357
358 bool cont = false;
359 /* Continue if at least one of the subdrivers want to continue */
360 for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
361 if (hid_dev->subdrivers[i].poll != NULL) {
362 cont = cont || hid_dev->subdrivers[i].poll(
363 hid_dev, hid_dev->subdrivers[i].data);
364 }
365 }
366
367 return cont;
368}
369
[be01eb3]370static bool usb_hid_polling_error_callback(usb_device_t *dev, errno_t err_code, void *arg)
[17c1d9db]371{
372 assert(dev);
373 assert(arg);
374 usb_hid_dev_t *hid_dev = arg;
375
376 usb_log_error("Device %s polling error: %s", usb_device_get_name(dev),
377 str_error(err_code));
378
379 /* Continue polling until the device is about to be removed. */
380 return hid_dev->running;
381}
382
383static void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
384{
385 assert(dev);
386 assert(arg);
387
388 usb_hid_dev_t *hid_dev = arg;
389
390 for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
391 if (hid_dev->subdrivers[i].poll_end != NULL) {
392 hid_dev->subdrivers[i].poll_end(
393 hid_dev, hid_dev->subdrivers[i].data, reason);
394 }
395 }
396
397 hid_dev->running = false;
398}
399
[555499da]400/*
401 * This functions initializes required structures from the device's descriptors
402 * and starts new fibril for polling the keyboard for events and another one for
403 * handling auto-repeat of keys.
404 *
405 * During initialization, the keyboard is switched into boot protocol, the idle
406 * rate is set to 0 (infinity), resulting in the keyboard only reporting event
[970f6e1]407 * when a key is pressed or released. Finally, the LED lights are turned on
[555499da]408 * according to the default setup of lock keys.
409 *
[970f6e1]410 * @note By default, the keyboards is initialized with Num Lock turned on and
[555499da]411 * other locks turned off.
412 *
413 * @param hid_dev Device to initialize, non-NULL.
414 * @param dev USB device, non-NULL.
415 * @return Error code.
416 */
[5a6cc679]417errno_t usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
[61257f4]418{
[555499da]419 assert(hid_dev);
420 assert(dev);
[cc29622]421
[a1732929]422 usb_log_debug("Initializing HID structure...");
[cc29622]423
[a8c4e871]424 usb_hid_report_init(&hid_dev->report);
[e5024111]425
[61257f4]426 /* The USB device should already be initialized, save it in structure */
427 hid_dev->usb_dev = dev;
[bb70637]428 hid_dev->poll_pipe_mapping = NULL;
[cc29622]429
[5a6cc679]430 errno_t rc = usb_hid_check_pipes(hid_dev, dev);
[61257f4]431 if (rc != EOK) {
432 return rc;
433 }
[a8c4e871]434
[f76153ce]435 /* Get the report descriptor and parse it. */
[07b9cbae]436 rc = usb_hid_process_report_descriptor(
437 hid_dev->usb_dev, &hid_dev->report, &hid_dev->report_desc,
438 &hid_dev->report_desc_size);
[cc29622]439
[07b9cbae]440 /* If report parsing went well, find subdrivers. */
[f76153ce]441 if (rc == EOK) {
[07b9cbae]442 usb_hid_find_subdrivers(hid_dev);
[f76153ce]443 } else {
[a1732929]444 usb_log_error("Failed to parse report descriptor: fallback.");
[07b9cbae]445 hid_dev->subdrivers = NULL;
446 hid_dev->subdriver_count = 0;
[f76153ce]447 }
[cc29622]448
[a1732929]449 usb_log_debug("Subdriver count(before trying boot protocol): %d",
[07b9cbae]450 hid_dev->subdriver_count);
451
452 /* No subdrivers, fall back to the boot protocol if available. */
453 if (hid_dev->subdriver_count == 0) {
454 assert(hid_dev->subdrivers == NULL);
455 usb_log_info("No subdrivers found to handle device, trying "
456 "boot protocol.\n");
457
[bb70637]458 switch (hid_dev->poll_pipe_mapping->interface->interface_protocol) {
459 case USB_HID_PROTOCOL_KEYBOARD:
[a1732929]460 usb_log_info("Falling back to kbd boot protocol.");
[f76153ce]461 rc = usb_kbd_set_boot_protocol(hid_dev);
462 if (rc == EOK) {
[07b9cbae]463 usb_hid_set_boot_kbd_subdriver(hid_dev);
[60c0573]464 }
[f76153ce]465 break;
[bb70637]466 case USB_HID_PROTOCOL_MOUSE:
[a1732929]467 usb_log_info("Falling back to mouse boot protocol.");
[f76153ce]468 rc = usb_mouse_set_boot_protocol(hid_dev);
469 if (rc == EOK) {
[07b9cbae]470 usb_hid_set_boot_mouse_subdriver(hid_dev);
[f76153ce]471 }
472 break;
473 default:
[a1732929]474 usb_log_info("Falling back to generic HID driver.");
[07b9cbae]475 usb_hid_set_generic_hid_subdriver(hid_dev);
[e9f0348]476 }
[61257f4]477 }
[cc29622]478
[a1732929]479 usb_log_debug("Subdriver count(after trying boot protocol): %d",
[07b9cbae]480 hid_dev->subdriver_count);
481
482 /* Still no subdrivers? */
483 if (hid_dev->subdriver_count == 0) {
484 assert(hid_dev->subdrivers == NULL);
485 usb_log_error(
486 "No subdriver for handling this device could be found.\n");
487 return ENOTSUP;
488 }
489
[ad22fa4]490 /* Initialize subdrivers */
[07b9cbae]491 bool ok = false;
[f317490]492 for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
[07b9cbae]493 if (hid_dev->subdrivers[i].init != NULL) {
[a1732929]494 usb_log_debug("Initializing subdriver %d.",i);
[5a6cc679]495 const errno_t pret = hid_dev->subdrivers[i].init(hid_dev,
[07b9cbae]496 &hid_dev->subdrivers[i].data);
497 if (pret != EOK) {
498 usb_log_warning("Failed to initialize"
499 " HID subdriver structure: %s.\n",
500 str_error(pret));
501 rc = pret;
[f76153ce]502 } else {
[07b9cbae]503 /* At least one subdriver initialized. */
[f76153ce]504 ok = true;
505 }
[07b9cbae]506 } else {
507 /* Does not need initialization. */
508 ok = true;
[f76153ce]509 }
510 }
[cc29622]511
[07b9cbae]512 if (ok) {
513 /* Save max input report size and
514 * allocate space for the report */
[2002595]515 rc = usb_hid_init_report(hid_dev);
516 if (rc != EOK) {
[a1732929]517 usb_log_error("Failed to initialize input report buffer: %s", str_error(rc));
[745a3f1]518 // FIXME: What happens now?
[2002595]519 }
[8b71f3e]520
521 usb_polling_t *polling = &hid_dev->polling;
522 if ((rc = usb_polling_init(polling))) {
[a1732929]523 usb_log_error("Failed to initialize polling: %s", str_error(rc));
[745a3f1]524 // FIXME: What happens now?
[8b71f3e]525 }
526
527 polling->device = hid_dev->usb_dev;
528 polling->ep_mapping = hid_dev->poll_pipe_mapping;
529 polling->request_size = hid_dev->poll_pipe_mapping->pipe.desc.max_transfer_size;
530 polling->buffer = malloc(polling->request_size);
[745a3f1]531 polling->on_data = usb_hid_polling_callback;
532 polling->on_polling_end = usb_hid_polling_ended_callback;
533 polling->on_error = usb_hid_polling_error_callback;
[8b71f3e]534 polling->arg = hid_dev;
[d1fb591]535 }
[cc29622]536
[61257f4]537 return rc;
538}
[76fbd9a]539
[8fb45e08]540void usb_hid_new_report(usb_hid_dev_t *hid_dev)
[dd3eda2]541{
[8fb45e08]542 ++hid_dev->report_nr;
[dd3eda2]543}
[76fbd9a]544
[3f8f09f]545int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
[dd3eda2]546{
[8fb45e08]547 return hid_dev->report_nr;
[dd3eda2]548}
[76fbd9a]549
[a8c4e871]550void usb_hid_deinit(usb_hid_dev_t *hid_dev)
[61257f4]551{
[3f8f09f]552 assert(hid_dev);
553 assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
[cc29622]554
[8b71f3e]555 free(hid_dev->polling.buffer);
556 usb_polling_fini(&hid_dev->polling);
557
[a1732929]558 usb_log_debug("Subdrivers: %p, subdriver count: %d",
[5f6e25e]559 hid_dev->subdrivers, hid_dev->subdriver_count);
[cc29622]560
[f317490]561 for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
[5f6e25e]562 if (hid_dev->subdrivers[i].deinit != NULL) {
563 hid_dev->subdrivers[i].deinit(hid_dev,
564 hid_dev->subdrivers[i].data);
[60c0573]565 }
[61257f4]566 }
[cc29622]567
[cddd151]568 /* Free allocated structures */
569 free(hid_dev->subdrivers);
570 free(hid_dev->report_desc);
[61257f4]571
[cddd151]572 /* Destroy the parser */
[a8c4e871]573 usb_hid_report_deinit(&hid_dev->report);
[966acede]574}
575
576/**
577 * @}
578 */
Note: See TracBrowser for help on using the repository browser.