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

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

Assert replaced with condition

The assert was originally there for debugging purposes. However, there is
no guarantee that the console will create the callback phone immediatelly.
It may be busy doing other things and impatient user may be already tapping
the keyboard. It is definitely better to discard some keys than to crash
the driver ;-).

  • 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 async_usleep(1000 * 10);
596
597 sess_rc = usb_endpoint_pipe_start_session(
598 &kbd_dev->hid_dev->poll_pipe);
599 if (sess_rc != EOK) {
600 usb_log_warning("Failed to start a session: %s.\n",
601 str_error(sess_rc));
602 continue;
603 }
604
605 rc = usb_endpoint_pipe_read(&kbd_dev->hid_dev->poll_pipe,
606 buffer, BOOTP_BUFFER_SIZE, &actual_size);
607
608 sess_rc = usb_endpoint_pipe_end_session(
609 &kbd_dev->hid_dev->poll_pipe);
610
611 if (rc != EOK) {
612 usb_log_warning("Error polling the keyboard: %s.\n",
613 str_error(rc));
614 continue;
615 }
616
617 if (sess_rc != EOK) {
618 usb_log_warning("Error closing session: %s.\n",
619 str_error(sess_rc));
620 continue;
621 }
622
623 /*
624 * If the keyboard answered with NAK, it returned no data.
625 * This implies that no change happened since last query.
626 */
627 if (actual_size == 0) {
628 usb_log_debug("Keyboard returned NAK\n");
629 continue;
630 }
631
632 /*
633 * TODO: Process pressed keys.
634 */
635 usb_log_debug("Calling usbhid_kbd_process_data()\n");
636 usbhid_kbd_process_data(kbd_dev, buffer, actual_size);
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.