source: mainline/uspace/drv/usbhid/kbddev.c@ dc75234

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dc75234 was ac8285d, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Fix comparison vs. assignment

  • Property mode set to 100644
File size: 20.1 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 assert(kbd_dev->console_phone != -1);
292
293 async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key,
294 ev.mods, ev.c);
295}
296
297/*----------------------------------------------------------------------------*/
298
299static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev,
300 uint8_t modifiers)
301{
302 /*
303 * TODO: why the USB keyboard has NUM_, SCROLL_ and CAPS_LOCK
304 * both as modifiers and as keys with their own scancodes???
305 *
306 * modifiers should be sent as normal keys to usbhid_parse_scancode()!!
307 * so maybe it would be better if I received it from report parser in
308 * that way
309 */
310
311 int i;
312 for (i = 0; i < USB_HID_MOD_COUNT; ++i) {
313 if ((modifiers & usb_hid_modifiers_consts[i]) &&
314 !(kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
315 // modifier pressed
316 if (usbhid_modifiers_keycodes[i] != 0) {
317 usbhid_kbd_push_ev(kbd_dev, KEY_PRESS,
318 usbhid_modifiers_keycodes[i]);
319 }
320 } else if (!(modifiers & usb_hid_modifiers_consts[i]) &&
321 (kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
322 // modifier released
323 if (usbhid_modifiers_keycodes[i] != 0) {
324 usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE,
325 usbhid_modifiers_keycodes[i]);
326 }
327 } // no change
328 }
329
330 kbd_dev->modifiers = modifiers;
331}
332
333/*----------------------------------------------------------------------------*/
334
335static void usbhid_kbd_check_key_changes(usbhid_kbd_t *kbd_dev,
336 const uint8_t *key_codes)
337{
338 // TODO: phantom state!!
339
340 unsigned int key;
341 unsigned int i, j;
342
343 // TODO: quite dummy right now, think of better implementation
344
345 /*
346 * 1) Key releases
347 */
348 for (j = 0; j < kbd_dev->keycode_count; ++j) {
349 // try to find the old key in the new key list
350 i = 0;
351 while (i < kbd_dev->keycode_count
352 && key_codes[i] != kbd_dev->keycodes[j]) {
353 ++i;
354 }
355
356 if (i == kbd_dev->keycode_count) {
357 // not found, i.e. the key was released
358 key = usbhid_parse_scancode(kbd_dev->keycodes[j]);
359 usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
360 usb_log_debug2("\nKey released: %d\n", key);
361 } else {
362 // found, nothing happens
363 }
364 }
365
366 /*
367 * 1) Key presses
368 */
369 for (i = 0; i < kbd_dev->keycode_count; ++i) {
370 // try to find the new key in the old key list
371 j = 0;
372 while (j < kbd_dev->keycode_count
373 && kbd_dev->keycodes[j] != key_codes[i]) {
374 ++j;
375 }
376
377 if (j == kbd_dev->keycode_count) {
378 // not found, i.e. new key pressed
379 key = usbhid_parse_scancode(key_codes[i]);
380 usb_log_debug2("\nKey pressed: %d (keycode: %d)\n", key,
381 key_codes[i]);
382 usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key);
383 } else {
384 // found, nothing happens
385 }
386 }
387
388 memcpy(kbd_dev->keycodes, key_codes, kbd_dev->keycode_count);
389
390 usb_log_debug2("\nNew stored keycodes: ");
391 for (i = 0; i < kbd_dev->keycode_count; ++i) {
392 usb_log_debug2("%d ", kbd_dev->keycodes[i]);
393 }
394}
395
396/*----------------------------------------------------------------------------*/
397/* Callbacks for parser */
398/*----------------------------------------------------------------------------*/
399
400static void usbhid_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
401 uint8_t modifiers, void *arg)
402{
403 if (arg == NULL) {
404 usb_log_warning("Missing argument in callback "
405 "usbhid_process_keycodes().\n");
406 return;
407 }
408
409 usb_log_debug2("Got keys from parser: ");
410 unsigned i;
411 for (i = 0; i < count; ++i) {
412 usb_log_debug2("%d ", key_codes[i]);
413 }
414 usb_log_debug2("\n");
415
416 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
417 assert(kbd_dev != NULL);
418
419 if (count != kbd_dev->keycode_count) {
420 usb_log_warning("Number of received keycodes (%d) differs from"
421 " expected number (%d).\n", count, kbd_dev->keycode_count);
422 return;
423 }
424
425 usbhid_kbd_check_modifier_changes(kbd_dev, modifiers);
426 usbhid_kbd_check_key_changes(kbd_dev, key_codes);
427}
428
429/*----------------------------------------------------------------------------*/
430/* General kbd functions */
431/*----------------------------------------------------------------------------*/
432
433static void usbhid_kbd_process_data(usbhid_kbd_t *kbd_dev,
434 uint8_t *buffer, size_t actual_size)
435{
436 usb_hid_report_in_callbacks_t *callbacks =
437 (usb_hid_report_in_callbacks_t *)malloc(
438 sizeof(usb_hid_report_in_callbacks_t));
439
440 callbacks->keyboard = usbhid_kbd_process_keycodes;
441
442 //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
443 // NULL);
444 /*usb_log_debug2("Calling usb_hid_boot_keyboard_input_report() with size"
445 " %zu\n", actual_size);*/
446 //dump_buffer("bufffer: ", buffer, actual_size);
447
448 int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
449 callbacks, kbd_dev);
450
451 if (rc != EOK) {
452 usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
453 "%s\n", str_error(rc));
454 }
455}
456
457/*----------------------------------------------------------------------------*/
458/* HID/KBD structure manipulation */
459/*----------------------------------------------------------------------------*/
460
461static usbhid_kbd_t *usbhid_kbd_new(void)
462{
463 usbhid_kbd_t *kbd_dev =
464 (usbhid_kbd_t *)malloc(sizeof(usbhid_kbd_t));
465
466 if (kbd_dev == NULL) {
467 usb_log_fatal("No memory!\n");
468 return NULL;
469 }
470
471 memset(kbd_dev, 0, sizeof(usbhid_kbd_t));
472
473 kbd_dev->hid_dev = usbhid_dev_new();
474 if (kbd_dev->hid_dev == NULL) {
475 usb_log_fatal("Could not create HID device structure.\n");
476 return NULL;
477 }
478
479 kbd_dev->console_phone = -1;
480 kbd_dev->initialized = 0;
481
482 return kbd_dev;
483}
484
485/*----------------------------------------------------------------------------*/
486
487static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
488{
489 if (kbd_dev == NULL || *kbd_dev == NULL) {
490 return;
491 }
492
493 // hangup phone to the console
494 async_hangup((*kbd_dev)->console_phone);
495
496 if ((*kbd_dev)->hid_dev != NULL) {
497 usbhid_dev_free(&(*kbd_dev)->hid_dev);
498 assert((*kbd_dev)->hid_dev == NULL);
499 }
500
501 free(*kbd_dev);
502 *kbd_dev = NULL;
503}
504
505/*----------------------------------------------------------------------------*/
506
507static int usbhid_kbd_init(usbhid_kbd_t *kbd_dev, ddf_dev_t *dev)
508{
509 int rc;
510
511 usb_log_info("Initializing HID/KBD structure...\n");
512
513 if (kbd_dev == NULL) {
514 usb_log_error("Failed to init keyboard structure: no structure"
515 " given.\n");
516 return EINVAL;
517 }
518
519 if (dev == NULL) {
520 usb_log_error("Failed to init keyboard structure: no device"
521 " given.\n");
522 return EINVAL;
523 }
524
525 if (kbd_dev->initialized) {
526 usb_log_warning("Keyboard structure already initialized.\n");
527 return EINVAL;
528 }
529
530 rc = usbhid_dev_init(kbd_dev->hid_dev, dev, &poll_endpoint_description);
531
532 if (rc != EOK) {
533 usb_log_error("Failed to initialize HID device structure: %s\n",
534 str_error(rc));
535 return rc;
536 }
537
538 assert(kbd_dev->hid_dev->initialized);
539
540 // save the size of the report (boot protocol report by default)
541 kbd_dev->keycode_count = BOOTP_REPORT_SIZE;
542 kbd_dev->keycodes = (uint8_t *)calloc(
543 kbd_dev->keycode_count, sizeof(uint8_t));
544
545 if (kbd_dev->keycodes == NULL) {
546 usb_log_fatal("No memory!\n");
547 return rc;
548 }
549
550 kbd_dev->modifiers = 0;
551 kbd_dev->mods = DEFAULT_ACTIVE_MODS;
552 kbd_dev->lock_keys = 0;
553
554 /*
555 * Set boot protocol.
556 * Set LEDs according to initial setup.
557 */
558 assert(kbd_dev->hid_dev != NULL);
559 assert(kbd_dev->hid_dev->initialized);
560 usbhid_req_set_protocol(kbd_dev->hid_dev, USB_HID_PROTOCOL_BOOT);
561
562 usbhid_kbd_set_led(kbd_dev);
563
564 kbd_dev->initialized = 1;
565 usb_log_info("HID/KBD device structure initialized.\n");
566
567 return EOK;
568}
569
570/*----------------------------------------------------------------------------*/
571/* HID/KBD polling */
572/*----------------------------------------------------------------------------*/
573
574static void usbhid_kbd_poll(usbhid_kbd_t *kbd_dev)
575{
576 int rc, sess_rc;
577 uint8_t buffer[BOOTP_BUFFER_SIZE];
578 size_t actual_size;
579
580 usb_log_info("Polling keyboard...\n");
581
582 if (!kbd_dev->initialized) {
583 usb_log_error("HID/KBD device not initialized!\n");
584 return;
585 }
586
587 assert(kbd_dev->hid_dev != NULL);
588 assert(kbd_dev->hid_dev->initialized);
589
590 while (true) {
591 async_usleep(1000 * 10);
592
593 sess_rc = usb_endpoint_pipe_start_session(
594 &kbd_dev->hid_dev->poll_pipe);
595 if (sess_rc != EOK) {
596 usb_log_warning("Failed to start a session: %s.\n",
597 str_error(sess_rc));
598 continue;
599 }
600
601 rc = usb_endpoint_pipe_read(&kbd_dev->hid_dev->poll_pipe,
602 buffer, BOOTP_BUFFER_SIZE, &actual_size);
603
604 sess_rc = usb_endpoint_pipe_end_session(
605 &kbd_dev->hid_dev->poll_pipe);
606
607 if (rc != EOK) {
608 usb_log_warning("Error polling the keyboard: %s.\n",
609 str_error(rc));
610 continue;
611 }
612
613 if (sess_rc != EOK) {
614 usb_log_warning("Error closing session: %s.\n",
615 str_error(sess_rc));
616 continue;
617 }
618
619 /*
620 * If the keyboard answered with NAK, it returned no data.
621 * This implies that no change happened since last query.
622 */
623 if (actual_size == 0) {
624 usb_log_debug("Keyboard returned NAK\n");
625 continue;
626 }
627
628 /*
629 * TODO: Process pressed keys.
630 */
631 usb_log_debug("Calling usbhid_kbd_process_data()\n");
632 usbhid_kbd_process_data(kbd_dev, buffer, actual_size);
633 }
634
635 // not reached
636 assert(0);
637}
638
639/*----------------------------------------------------------------------------*/
640
641static int usbhid_kbd_fibril(void *arg)
642{
643 if (arg == NULL) {
644 usb_log_error("No device!\n");
645 return EINVAL;
646 }
647
648 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
649
650 usbhid_kbd_poll(kbd_dev);
651
652 // at the end, properly destroy the KBD structure
653 usbhid_kbd_free(&kbd_dev);
654 assert(kbd_dev == NULL);
655
656 return EOK;
657}
658
659/*----------------------------------------------------------------------------*/
660/* API functions */
661/*----------------------------------------------------------------------------*/
662
663int usbhid_kbd_try_add_device(ddf_dev_t *dev)
664{
665 /*
666 * Create default function.
667 */
668 ddf_fun_t *kbd_fun = ddf_fun_create(dev, fun_exposed, "keyboard");
669 if (kbd_fun == NULL) {
670 usb_log_error("Could not create DDF function node.\n");
671 return ENOMEM;
672 }
673
674 /*
675 * Initialize device (get and process descriptors, get address, etc.)
676 */
677 usb_log_info("Initializing USB/HID KBD device...\n");
678
679 usbhid_kbd_t *kbd_dev = usbhid_kbd_new();
680 if (kbd_dev == NULL) {
681 usb_log_error("Error while creating USB/HID KBD device "
682 "structure.\n");
683 ddf_fun_destroy(kbd_fun);
684 return EINVAL; // TODO: some other code??
685 }
686
687 int rc = usbhid_kbd_init(kbd_dev, dev);
688
689 if (rc != EOK) {
690 usb_log_error("Failed to initialize USB/HID KBD device.\n");
691 ddf_fun_destroy(kbd_fun);
692 usbhid_kbd_free(&kbd_dev);
693 return rc;
694 }
695
696 usb_log_info("USB/HID KBD device structure initialized.\n");
697
698 /*
699 * Store the initialized keyboard device and keyboard ops
700 * to the DDF function.
701 */
702 kbd_fun->driver_data = kbd_dev;
703 kbd_fun->ops = &keyboard_ops;
704
705 rc = ddf_fun_bind(kbd_fun);
706 if (rc != EOK) {
707 usb_log_error("Could not bind DDF function.\n");
708 // TODO: Can / should I destroy the DDF function?
709 ddf_fun_destroy(kbd_fun);
710 usbhid_kbd_free(&kbd_dev);
711 return rc;
712 }
713
714 rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
715 if (rc != EOK) {
716 usb_log_error("Could not add DDF function to class 'keyboard'"
717 "\n");
718 // TODO: Can / should I destroy the DDF function?
719 ddf_fun_destroy(kbd_fun);
720 usbhid_kbd_free(&kbd_dev);
721 return rc;
722 }
723
724 /*
725 * Create new fibril for handling this keyboard
726 */
727 fid_t fid = fibril_create(usbhid_kbd_fibril, kbd_dev);
728 if (fid == 0) {
729 usb_log_error("Failed to start fibril for KBD device\n");
730 return ENOMEM;
731 }
732 fibril_add_ready(fid);
733
734 (void)keyboard_ops;
735
736 /*
737 * Hurrah, device is initialized.
738 */
739 return EOK;
740}
741
742/**
743 * @}
744 */
Note: See TracBrowser for help on using the repository browser.