source: mainline/uspace/drv/usbhid/kbddev.c@ 0e164ed

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

Using polling interval from endpoint descriptor

  • Property mode set to 100644
File size: 20.2 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 keyboard device structure and API.
35 */
36
37#include <errno.h>
38#include <str_error.h>
39#include <fibril.h>
40
41#include <io/keycode.h>
42#include <ipc/kbd.h>
43#include <async.h>
44
45#include <usb/usb.h>
46#include <usb/classes/hid.h>
47#include <usb/pipes.h>
48#include <usb/debug.h>
49#include <usb/classes/hidparser.h>
50#include <usb/classes/classes.h>
51
52#include "kbddev.h"
53#include "hiddev.h"
54#include "hidreq.h"
55#include "layout.h"
56#include "conv.h"
57
58/*----------------------------------------------------------------------------*/
59
60static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
61static const size_t BOOTP_REPORT_SIZE = 6;
62static const size_t BOOTP_BUFFER_SIZE = 8;
63static const size_t BOOTP_BUFFER_OUT_SIZE = 1;
64
65/** Keyboard polling endpoint description for boot protocol class. */
66static usb_endpoint_description_t poll_endpoint_description = {
67 .transfer_type = USB_TRANSFER_INTERRUPT,
68 .direction = USB_DIRECTION_IN,
69 .interface_class = USB_CLASS_HID,
70 .interface_subclass = USB_HID_SUBCLASS_BOOT,
71 .interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
72 .flags = 0
73};
74
75/*----------------------------------------------------------------------------*/
76/* Keyboard layouts */
77/*----------------------------------------------------------------------------*/
78
79#define NUM_LAYOUTS 3
80
81static layout_op_t *layout[NUM_LAYOUTS] = {
82 &us_qwerty_op,
83 &us_dvorak_op,
84 &cz_op
85};
86
87static int active_layout = 0;
88
89/*----------------------------------------------------------------------------*/
90/* Modifier constants */
91/*----------------------------------------------------------------------------*/
92
93static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = {
94 KC_LCTRL, /* USB_HID_MOD_LCTRL */
95 KC_LSHIFT, /* USB_HID_MOD_LSHIFT */
96 KC_LALT, /* USB_HID_MOD_LALT */
97 0, /* USB_HID_MOD_LGUI */
98 KC_RCTRL, /* USB_HID_MOD_RCTRL */
99 KC_RSHIFT, /* USB_HID_MOD_RSHIFT */
100 KC_RALT, /* USB_HID_MOD_RALT */
101 0, /* USB_HID_MOD_RGUI */
102};
103
104/*----------------------------------------------------------------------------*/
105/* IPC method handler */
106/*----------------------------------------------------------------------------*/
107
108static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
109static ddf_dev_ops_t keyboard_ops = {
110 .default_handler = default_connection_handler
111};
112
113/** Default handler for IPC methods not handled by DDF.
114 *
115 * @param dev Device handling the call.
116 * @param icallid Call id.
117 * @param icall Call data.
118 */
119void default_connection_handler(ddf_fun_t *fun,
120 ipc_callid_t icallid, ipc_call_t *icall)
121{
122 sysarg_t method = IPC_GET_IMETHOD(*icall);
123
124 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)fun->driver_data;
125 assert(kbd_dev != NULL);
126
127 if (method == IPC_M_CONNECT_TO_ME) {
128 int callback = IPC_GET_ARG5(*icall);
129
130 if (kbd_dev->console_phone != -1) {
131 async_answer_0(icallid, ELIMIT);
132 return;
133 }
134
135 kbd_dev->console_phone = callback;
136 async_answer_0(icallid, EOK);
137 return;
138 }
139
140 async_answer_0(icallid, EINVAL);
141}
142
143/*----------------------------------------------------------------------------*/
144/* Key processing functions */
145/*----------------------------------------------------------------------------*/
146
147static void usbhid_kbd_set_led(usbhid_kbd_t *kbd_dev)
148{
149 uint8_t buffer[BOOTP_BUFFER_OUT_SIZE];
150 int rc= 0;
151 unsigned i;
152
153 memset(buffer, 0, BOOTP_BUFFER_OUT_SIZE);
154 uint8_t leds = 0;
155
156 if (kbd_dev->mods & KM_NUM_LOCK) {
157 leds |= USB_HID_LED_NUM_LOCK;
158 }
159
160 if (kbd_dev->mods & KM_CAPS_LOCK) {
161 leds |= USB_HID_LED_CAPS_LOCK;
162 }
163
164 if (kbd_dev->mods & KM_SCROLL_LOCK) {
165 leds |= USB_HID_LED_SCROLL_LOCK;
166 }
167
168 // TODO: COMPOSE and KANA
169
170 usb_log_debug("Creating output report.\n");
171 usb_log_debug("Leds: 0x%x\n", leds);
172 if ((rc = usb_hid_boot_keyboard_output_report(
173 leds, buffer, BOOTP_BUFFER_OUT_SIZE)) != EOK) {
174 usb_log_warning("Error composing output report to the keyboard:"
175 "%s.\n", str_error(rc));
176 return;
177 }
178
179 // TODO: REFACTOR!!!
180
181 usb_log_debug("Output report buffer: ");
182 for (i = 0; i < BOOTP_BUFFER_OUT_SIZE; ++i) {
183 usb_log_debug("0x%x ", buffer[i]);
184 }
185 usb_log_debug("\n");
186
187 uint16_t value = 0;
188 value |= (USB_HID_REPORT_TYPE_OUTPUT << 8);
189
190 assert(kbd_dev->hid_dev != NULL);
191 assert(kbd_dev->hid_dev->initialized);
192 usbhid_req_set_report(kbd_dev->hid_dev, value, buffer,
193 BOOTP_BUFFER_OUT_SIZE);
194}
195
196/*----------------------------------------------------------------------------*/
197
198static void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type,
199 unsigned int key)
200{
201 console_event_t ev;
202 unsigned mod_mask;
203
204 // TODO: replace by our own parsing?? or are the key codes identical??
205 switch (key) {
206 case KC_LCTRL: mod_mask = KM_LCTRL; break;
207 case KC_RCTRL: mod_mask = KM_RCTRL; break;
208 case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
209 case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
210 case KC_LALT: mod_mask = KM_LALT; break;
211 case KC_RALT: mod_mask = KM_RALT; break;
212 default: mod_mask = 0; break;
213 }
214
215 if (mod_mask != 0) {
216 if (type == KEY_PRESS)
217 kbd_dev->mods = kbd_dev->mods | mod_mask;
218 else
219 kbd_dev->mods = kbd_dev->mods & ~mod_mask;
220 }
221
222 switch (key) {
223 case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
224 case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
225 case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
226 default: mod_mask = 0; break;
227 }
228
229 if (mod_mask != 0) {
230 usb_log_debug2("\n\nChanging mods and lock keys\n");
231 usb_log_debug2("\nmods before: 0x%x\n", kbd_dev->mods);
232 usb_log_debug2("\nLock keys before:0x%x\n\n",
233 kbd_dev->lock_keys);
234
235 if (type == KEY_PRESS) {
236 usb_log_debug2("\nKey pressed.\n");
237 /*
238 * Only change lock state on transition from released
239 * to pressed. This prevents autorepeat from messing
240 * up the lock state.
241 */
242 kbd_dev->mods =
243 kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
244 kbd_dev->lock_keys = kbd_dev->lock_keys | mod_mask;
245
246 /* Update keyboard lock indicator lights. */
247 usbhid_kbd_set_led(kbd_dev);
248 } else {
249 usb_log_debug2("\nKey released.\n");
250 kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
251 }
252 }
253
254 usb_log_debug2("\n\nmods after: 0x%x\n", kbd_dev->mods);
255 usb_log_debug2("\nLock keys after: 0x%x\n\n", kbd_dev->lock_keys);
256
257 if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
258 // do not send anything to the console, this is our business
259 return;
260 }
261
262 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
263 active_layout = 0;
264 layout[active_layout]->reset();
265 return;
266 }
267
268 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
269 active_layout = 1;
270 layout[active_layout]->reset();
271 return;
272 }
273
274 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
275 active_layout = 2;
276 layout[active_layout]->reset();
277 return;
278 }
279
280 ev.type = type;
281 ev.key = key;
282 ev.mods = kbd_dev->mods;
283
284 if (ev.mods & KM_NUM_LOCK) {
285 usb_log_debug("\n\nNum Lock turned on.\n\n");
286 }
287
288 ev.c = layout[active_layout]->parse_ev(&ev);
289
290 usb_log_debug2("Sending key %d to the console\n", ev.key);
291 if (kbd_dev->console_phone < 0) {
292 usb_log_warning(
293 "Connection to console not ready, key discarded.\n");
294 return;
295 }
296
297 async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key,
298 ev.mods, ev.c);
299}
300
301/*----------------------------------------------------------------------------*/
302
303static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev,
304 uint8_t modifiers)
305{
306 /*
307 * TODO: why the USB keyboard has NUM_, SCROLL_ and CAPS_LOCK
308 * both as modifiers and as keys with their own scancodes???
309 *
310 * modifiers should be sent as normal keys to usbhid_parse_scancode()!!
311 * so maybe it would be better if I received it from report parser in
312 * that way
313 */
314
315 int i;
316 for (i = 0; i < USB_HID_MOD_COUNT; ++i) {
317 if ((modifiers & usb_hid_modifiers_consts[i]) &&
318 !(kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
319 // modifier pressed
320 if (usbhid_modifiers_keycodes[i] != 0) {
321 usbhid_kbd_push_ev(kbd_dev, KEY_PRESS,
322 usbhid_modifiers_keycodes[i]);
323 }
324 } else if (!(modifiers & usb_hid_modifiers_consts[i]) &&
325 (kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
326 // modifier released
327 if (usbhid_modifiers_keycodes[i] != 0) {
328 usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE,
329 usbhid_modifiers_keycodes[i]);
330 }
331 } // no change
332 }
333
334 kbd_dev->modifiers = modifiers;
335}
336
337/*----------------------------------------------------------------------------*/
338
339static void usbhid_kbd_check_key_changes(usbhid_kbd_t *kbd_dev,
340 const uint8_t *key_codes)
341{
342 // TODO: phantom state!!
343
344 unsigned int key;
345 unsigned int i, j;
346
347 // TODO: quite dummy right now, think of better implementation
348
349 /*
350 * 1) Key releases
351 */
352 for (j = 0; j < kbd_dev->keycode_count; ++j) {
353 // try to find the old key in the new key list
354 i = 0;
355 while (i < kbd_dev->keycode_count
356 && key_codes[i] != kbd_dev->keycodes[j]) {
357 ++i;
358 }
359
360 if (i == kbd_dev->keycode_count) {
361 // not found, i.e. the key was released
362 key = usbhid_parse_scancode(kbd_dev->keycodes[j]);
363 usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
364 usb_log_debug2("\nKey released: %d\n", key);
365 } else {
366 // found, nothing happens
367 }
368 }
369
370 /*
371 * 1) Key presses
372 */
373 for (i = 0; i < kbd_dev->keycode_count; ++i) {
374 // try to find the new key in the old key list
375 j = 0;
376 while (j < kbd_dev->keycode_count
377 && kbd_dev->keycodes[j] != key_codes[i]) {
378 ++j;
379 }
380
381 if (j == kbd_dev->keycode_count) {
382 // not found, i.e. new key pressed
383 key = usbhid_parse_scancode(key_codes[i]);
384 usb_log_debug2("\nKey pressed: %d (keycode: %d)\n", key,
385 key_codes[i]);
386 usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key);
387 } else {
388 // found, nothing happens
389 }
390 }
391
392 memcpy(kbd_dev->keycodes, key_codes, kbd_dev->keycode_count);
393
394 usb_log_debug2("\nNew stored keycodes: ");
395 for (i = 0; i < kbd_dev->keycode_count; ++i) {
396 usb_log_debug2("%d ", kbd_dev->keycodes[i]);
397 }
398}
399
400/*----------------------------------------------------------------------------*/
401/* Callbacks for parser */
402/*----------------------------------------------------------------------------*/
403
404static void usbhid_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
405 uint8_t modifiers, void *arg)
406{
407 if (arg == NULL) {
408 usb_log_warning("Missing argument in callback "
409 "usbhid_process_keycodes().\n");
410 return;
411 }
412
413 usb_log_debug2("Got keys from parser: ");
414 unsigned i;
415 for (i = 0; i < count; ++i) {
416 usb_log_debug2("%d ", key_codes[i]);
417 }
418 usb_log_debug2("\n");
419
420 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
421 assert(kbd_dev != NULL);
422
423 if (count != kbd_dev->keycode_count) {
424 usb_log_warning("Number of received keycodes (%d) differs from"
425 " expected number (%d).\n", count, kbd_dev->keycode_count);
426 return;
427 }
428
429 usbhid_kbd_check_modifier_changes(kbd_dev, modifiers);
430 usbhid_kbd_check_key_changes(kbd_dev, key_codes);
431}
432
433/*----------------------------------------------------------------------------*/
434/* General kbd functions */
435/*----------------------------------------------------------------------------*/
436
437static void usbhid_kbd_process_data(usbhid_kbd_t *kbd_dev,
438 uint8_t *buffer, size_t actual_size)
439{
440 usb_hid_report_in_callbacks_t *callbacks =
441 (usb_hid_report_in_callbacks_t *)malloc(
442 sizeof(usb_hid_report_in_callbacks_t));
443
444 callbacks->keyboard = usbhid_kbd_process_keycodes;
445
446 //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
447 // NULL);
448 /*usb_log_debug2("Calling usb_hid_boot_keyboard_input_report() with size"
449 " %zu\n", actual_size);*/
450 //dump_buffer("bufffer: ", buffer, actual_size);
451
452 int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
453 callbacks, kbd_dev);
454
455 if (rc != EOK) {
456 usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
457 "%s\n", str_error(rc));
458 }
459}
460
461/*----------------------------------------------------------------------------*/
462/* HID/KBD structure manipulation */
463/*----------------------------------------------------------------------------*/
464
465static usbhid_kbd_t *usbhid_kbd_new(void)
466{
467 usbhid_kbd_t *kbd_dev =
468 (usbhid_kbd_t *)malloc(sizeof(usbhid_kbd_t));
469
470 if (kbd_dev == NULL) {
471 usb_log_fatal("No memory!\n");
472 return NULL;
473 }
474
475 memset(kbd_dev, 0, sizeof(usbhid_kbd_t));
476
477 kbd_dev->hid_dev = usbhid_dev_new();
478 if (kbd_dev->hid_dev == NULL) {
479 usb_log_fatal("Could not create HID device structure.\n");
480 return NULL;
481 }
482
483 kbd_dev->console_phone = -1;
484 kbd_dev->initialized = 0;
485
486 return kbd_dev;
487}
488
489/*----------------------------------------------------------------------------*/
490
491static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
492{
493 if (kbd_dev == NULL || *kbd_dev == NULL) {
494 return;
495 }
496
497 // hangup phone to the console
498 async_hangup((*kbd_dev)->console_phone);
499
500 if ((*kbd_dev)->hid_dev != NULL) {
501 usbhid_dev_free(&(*kbd_dev)->hid_dev);
502 assert((*kbd_dev)->hid_dev == NULL);
503 }
504
505 free(*kbd_dev);
506 *kbd_dev = NULL;
507}
508
509/*----------------------------------------------------------------------------*/
510
511static int usbhid_kbd_init(usbhid_kbd_t *kbd_dev, ddf_dev_t *dev)
512{
513 int rc;
514
515 usb_log_info("Initializing HID/KBD structure...\n");
516
517 if (kbd_dev == NULL) {
518 usb_log_error("Failed to init keyboard structure: no structure"
519 " given.\n");
520 return EINVAL;
521 }
522
523 if (dev == NULL) {
524 usb_log_error("Failed to init keyboard structure: no device"
525 " given.\n");
526 return EINVAL;
527 }
528
529 if (kbd_dev->initialized) {
530 usb_log_warning("Keyboard structure already initialized.\n");
531 return EINVAL;
532 }
533
534 rc = usbhid_dev_init(kbd_dev->hid_dev, dev, &poll_endpoint_description);
535
536 if (rc != EOK) {
537 usb_log_error("Failed to initialize HID device structure: %s\n",
538 str_error(rc));
539 return rc;
540 }
541
542 assert(kbd_dev->hid_dev->initialized);
543
544 // save the size of the report (boot protocol report by default)
545 kbd_dev->keycode_count = BOOTP_REPORT_SIZE;
546 kbd_dev->keycodes = (uint8_t *)calloc(
547 kbd_dev->keycode_count, sizeof(uint8_t));
548
549 if (kbd_dev->keycodes == NULL) {
550 usb_log_fatal("No memory!\n");
551 return rc;
552 }
553
554 kbd_dev->modifiers = 0;
555 kbd_dev->mods = DEFAULT_ACTIVE_MODS;
556 kbd_dev->lock_keys = 0;
557
558 /*
559 * Set boot protocol.
560 * Set LEDs according to initial setup.
561 */
562 assert(kbd_dev->hid_dev != NULL);
563 assert(kbd_dev->hid_dev->initialized);
564 usbhid_req_set_protocol(kbd_dev->hid_dev, USB_HID_PROTOCOL_BOOT);
565
566 usbhid_kbd_set_led(kbd_dev);
567
568 kbd_dev->initialized = 1;
569 usb_log_info("HID/KBD device structure initialized.\n");
570
571 return EOK;
572}
573
574/*----------------------------------------------------------------------------*/
575/* HID/KBD polling */
576/*----------------------------------------------------------------------------*/
577
578static void usbhid_kbd_poll(usbhid_kbd_t *kbd_dev)
579{
580 int rc, sess_rc;
581 uint8_t buffer[BOOTP_BUFFER_SIZE];
582 size_t actual_size;
583
584 usb_log_info("Polling keyboard...\n");
585
586 if (!kbd_dev->initialized) {
587 usb_log_error("HID/KBD device not initialized!\n");
588 return;
589 }
590
591 assert(kbd_dev->hid_dev != NULL);
592 assert(kbd_dev->hid_dev->initialized);
593
594 while (true) {
595 sess_rc = usb_endpoint_pipe_start_session(
596 &kbd_dev->hid_dev->poll_pipe);
597 if (sess_rc != EOK) {
598 usb_log_warning("Failed to start a session: %s.\n",
599 str_error(sess_rc));
600 continue;
601 }
602
603 rc = usb_endpoint_pipe_read(&kbd_dev->hid_dev->poll_pipe,
604 buffer, BOOTP_BUFFER_SIZE, &actual_size);
605
606 sess_rc = usb_endpoint_pipe_end_session(
607 &kbd_dev->hid_dev->poll_pipe);
608
609 if (rc != EOK) {
610 usb_log_warning("Error polling the keyboard: %s.\n",
611 str_error(rc));
612 continue;
613 }
614
615 if (sess_rc != EOK) {
616 usb_log_warning("Error closing session: %s.\n",
617 str_error(sess_rc));
618 continue;
619 }
620
621 /*
622 * If the keyboard answered with NAK, it returned no data.
623 * This implies that no change happened since last query.
624 */
625 if (actual_size == 0) {
626 usb_log_debug("Keyboard returned NAK\n");
627 continue;
628 }
629
630 /*
631 * TODO: Process pressed keys.
632 */
633 usb_log_debug("Calling usbhid_kbd_process_data()\n");
634 usbhid_kbd_process_data(kbd_dev, buffer, actual_size);
635
636 async_usleep(kbd_dev->hid_dev->poll_interval);
637 }
638
639 // not reached
640 assert(0);
641}
642
643/*----------------------------------------------------------------------------*/
644
645static int usbhid_kbd_fibril(void *arg)
646{
647 if (arg == NULL) {
648 usb_log_error("No device!\n");
649 return EINVAL;
650 }
651
652 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
653
654 usbhid_kbd_poll(kbd_dev);
655
656 // at the end, properly destroy the KBD structure
657 usbhid_kbd_free(&kbd_dev);
658 assert(kbd_dev == NULL);
659
660 return EOK;
661}
662
663/*----------------------------------------------------------------------------*/
664/* API functions */
665/*----------------------------------------------------------------------------*/
666
667int usbhid_kbd_try_add_device(ddf_dev_t *dev)
668{
669 /*
670 * Create default function.
671 */
672 ddf_fun_t *kbd_fun = ddf_fun_create(dev, fun_exposed, "keyboard");
673 if (kbd_fun == NULL) {
674 usb_log_error("Could not create DDF function node.\n");
675 return ENOMEM;
676 }
677
678 /*
679 * Initialize device (get and process descriptors, get address, etc.)
680 */
681 usb_log_info("Initializing USB/HID KBD device...\n");
682
683 usbhid_kbd_t *kbd_dev = usbhid_kbd_new();
684 if (kbd_dev == NULL) {
685 usb_log_error("Error while creating USB/HID KBD device "
686 "structure.\n");
687 ddf_fun_destroy(kbd_fun);
688 return EINVAL; // TODO: some other code??
689 }
690
691 int rc = usbhid_kbd_init(kbd_dev, dev);
692
693 if (rc != EOK) {
694 usb_log_error("Failed to initialize USB/HID KBD device.\n");
695 ddf_fun_destroy(kbd_fun);
696 usbhid_kbd_free(&kbd_dev);
697 return rc;
698 }
699
700 usb_log_info("USB/HID KBD device structure initialized.\n");
701
702 /*
703 * Store the initialized keyboard device and keyboard ops
704 * to the DDF function.
705 */
706 kbd_fun->driver_data = kbd_dev;
707 kbd_fun->ops = &keyboard_ops;
708
709 rc = ddf_fun_bind(kbd_fun);
710 if (rc != EOK) {
711 usb_log_error("Could not bind DDF function.\n");
712 // TODO: Can / should I destroy the DDF function?
713 ddf_fun_destroy(kbd_fun);
714 usbhid_kbd_free(&kbd_dev);
715 return rc;
716 }
717
718 rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
719 if (rc != EOK) {
720 usb_log_error("Could not add DDF function to class 'keyboard'"
721 "\n");
722 // TODO: Can / should I destroy the DDF function?
723 ddf_fun_destroy(kbd_fun);
724 usbhid_kbd_free(&kbd_dev);
725 return rc;
726 }
727
728 /*
729 * Create new fibril for handling this keyboard
730 */
731 fid_t fid = fibril_create(usbhid_kbd_fibril, kbd_dev);
732 if (fid == 0) {
733 usb_log_error("Failed to start fibril for KBD device\n");
734 return ENOMEM;
735 }
736 fibril_add_ready(fid);
737
738 (void)keyboard_ops;
739
740 /*
741 * Hurrah, device is initialized.
742 */
743 return EOK;
744}
745
746/**
747 * @}
748 */
Note: See TracBrowser for help on using the repository browser.