source: mainline/uspace/drv/usbhid/kbddev.c@ 1efe89b

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

Setting idle rate + minor changes.

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