source: mainline/uspace/drv/usbhid/kbddev.c@ 6bb456c

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

Idle rate set to infinity, no sleep in polling + minor changes.

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