~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/drv/usbhid/usbhid.c

  • Committer: Jakub Jermar
  • Date: 2011-06-07 21:31:35 UTC
  • mfrom: (708.2.1 mainline)
  • Revision ID: jakub@jermar.eu-20110607213135-cxz8vhxq21pij1gb
Merge USB support.

Changes from bzr://helenos-usb.bzr.sourceforge.net/bzrroot/helenos-usb/mainline:

- replaced '-' with '_' in new driver names
- USB libs are built for each architecture
- devman starts early
- sys_thread_udelay() uses generic delay()
- sys_as_create_area() now creates cacheable areas by default

Show diffs side-by-side

added added

removed removed

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