Changes in uspace/drv/usbhid/main.c [1c6c4092:0f21c0c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhid/main.c
r1c6c4092 r0f21c0c 36 36 */ 37 37 38 #include <ddf/driver.h> 38 #include <driver.h> 39 #include <ipc/driver.h> 40 #include <ipc/kbd.h> 41 #include <io/keycode.h> 42 #include <io/console.h> 43 #include <errno.h> 44 #include <str_error.h> 45 #include <fibril.h> 39 46 #include <usb/debug.h> 40 #include <errno.h> 41 42 #include "kbddev.h" 43 44 /*----------------------------------------------------------------------------*/ 45 47 #include <usb/classes/classes.h> 48 #include <usb/classes/hid.h> 49 #include <usb/classes/hidparser.h> 50 #include <usb/request.h> 51 #include <usb/descriptor.h> 52 #include <io/console.h> 53 #include "hid.h" 54 #include "descparser.h" 55 #include "descdump.h" 56 #include "conv.h" 57 #include "layout.h" 58 59 #define BUFFER_SIZE 8 46 60 #define NAME "usbhid" 47 61 48 /*----------------------------------------------------------------------------*/ 49 50 static int usbhid_add_device(ddf_dev_t *dev) 51 { 52 usb_log_debug("usbhid_add_device()\n"); 53 54 int rc = usbhid_kbd_try_add_device(dev); 55 56 if (rc != EOK) { 57 usb_log_info("Device is not a supported keyboard.\n"); 58 usb_log_error("Failed to add HID device.\n"); 62 #define GUESSED_POLL_ENDPOINT 1 63 64 /** Keyboard polling endpoint description for boot protocol class. */ 65 static usb_endpoint_description_t poll_endpoint_description = { 66 .transfer_type = USB_TRANSFER_INTERRUPT, 67 .direction = USB_DIRECTION_IN, 68 .interface_class = USB_CLASS_HID, 69 .interface_subclass = USB_HID_SUBCLASS_BOOT, 70 .interface_protocol = USB_HID_PROTOCOL_KEYBOARD, 71 .flags = 0 72 }; 73 74 static void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *); 75 static device_ops_t keyboard_ops = { 76 .default_handler = default_connection_handler 77 }; 78 79 static int console_callback_phone = -1; 80 81 /** Default handler for IPC methods not handled by DDF. 82 * 83 * @param dev Device handling the call. 84 * @param icallid Call id. 85 * @param icall Call data. 86 */ 87 void default_connection_handler(device_t *dev, 88 ipc_callid_t icallid, ipc_call_t *icall) 89 { 90 sysarg_t method = IPC_GET_IMETHOD(*icall); 91 92 if (method == IPC_M_CONNECT_TO_ME) { 93 int callback = IPC_GET_ARG5(*icall); 94 95 if (console_callback_phone != -1) { 96 async_answer_0(icallid, ELIMIT); 97 return; 98 } 99 100 console_callback_phone = callback; 101 async_answer_0(icallid, EOK); 102 return; 103 } 104 105 async_answer_0(icallid, EINVAL); 106 } 107 108 #if 0 109 static void send_key(int key, int type, wchar_t c) { 110 async_msg_4(console_callback_phone, KBD_EVENT, type, key, 111 KM_NUM_LOCK, c); 112 } 113 #endif 114 115 /* 116 * TODO: Move somewhere else 117 */ 118 /* 119 #define BYTES_PER_LINE 12 120 121 static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length) 122 { 123 printf("%s\n", msg); 124 125 size_t i; 126 for (i = 0; i < length; i++) { 127 printf(" 0x%02X", buffer[i]); 128 if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0)) 129 || (i + 1 == length)) { 130 printf("\n"); 131 } 132 } 133 } 134 */ 135 /* 136 * Copy-paste from srv/hid/kbd/generic/kbd.c 137 */ 138 139 /** Currently active modifiers. 140 * 141 * TODO: put to device? 142 */ 143 static unsigned mods = KM_NUM_LOCK; 144 145 /** Currently pressed lock keys. We track these to tackle autorepeat. 146 * 147 * TODO: put to device? 148 */ 149 static unsigned lock_keys; 150 151 #define NUM_LAYOUTS 3 152 153 static layout_op_t *layout[NUM_LAYOUTS] = { 154 &us_qwerty_op, 155 &us_dvorak_op, 156 &cz_op 157 }; 158 159 static int active_layout = 0; 160 161 static void kbd_push_ev(int type, unsigned int key) 162 { 163 console_event_t ev; 164 unsigned mod_mask; 165 166 // TODO: replace by our own parsing?? or are the key codes identical?? 167 switch (key) { 168 case KC_LCTRL: mod_mask = KM_LCTRL; break; 169 case KC_RCTRL: mod_mask = KM_RCTRL; break; 170 case KC_LSHIFT: mod_mask = KM_LSHIFT; break; 171 case KC_RSHIFT: mod_mask = KM_RSHIFT; break; 172 case KC_LALT: mod_mask = KM_LALT; break; 173 case KC_RALT: mod_mask = KM_RALT; break; 174 default: mod_mask = 0; break; 175 } 176 177 if (mod_mask != 0) { 178 if (type == KEY_PRESS) 179 mods = mods | mod_mask; 180 else 181 mods = mods & ~mod_mask; 182 } 183 184 switch (key) { 185 case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break; 186 case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break; 187 case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break; 188 default: mod_mask = 0; break; 189 } 190 191 if (mod_mask != 0) { 192 if (type == KEY_PRESS) { 193 /* 194 * Only change lock state on transition from released 195 * to pressed. This prevents autorepeat from messing 196 * up the lock state. 197 */ 198 mods = mods ^ (mod_mask & ~lock_keys); 199 lock_keys = lock_keys | mod_mask; 200 201 /* Update keyboard lock indicator lights. */ 202 // TODO 203 //kbd_ctl_set_ind(mods); 204 } else { 205 lock_keys = lock_keys & ~mod_mask; 206 } 207 } 208 /* 209 printf("type: %d\n", type); 210 printf("mods: 0x%x\n", mods); 211 printf("keycode: %u\n", key); 212 */ 213 214 if (type == KEY_PRESS && (mods & KM_LCTRL) && 215 key == KC_F1) { 216 active_layout = 0; 217 layout[active_layout]->reset(); 218 return; 219 } 220 221 if (type == KEY_PRESS && (mods & KM_LCTRL) && 222 key == KC_F2) { 223 active_layout = 1; 224 layout[active_layout]->reset(); 225 return; 226 } 227 228 if (type == KEY_PRESS && (mods & KM_LCTRL) && 229 key == KC_F3) { 230 active_layout = 2; 231 layout[active_layout]->reset(); 232 return; 233 } 234 235 ev.type = type; 236 ev.key = key; 237 ev.mods = mods; 238 239 ev.c = layout[active_layout]->parse_ev(&ev); 240 241 printf("Sending key %d to the console\n", ev.key); 242 assert(console_callback_phone != -1); 243 async_msg_4(console_callback_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c); 244 } 245 /* 246 * End of copy-paste 247 */ 248 249 /* 250 * TODO: 251 * 1) key press / key release - how does the keyboard notify about release? 252 * 2) layouts (use the already defined), not important now 253 * 3) 254 */ 255 256 /* 257 * Callbacks for parser 258 */ 259 static void usbkbd_process_keycodes(const uint8_t *key_codes, size_t count, 260 uint8_t modifiers, void *arg) 261 { 262 printf("Got keys: "); 263 unsigned i; 264 for (i = 0; i < count; ++i) { 265 printf("%d ", key_codes[i]); 266 } 267 printf("\n"); 268 269 for (i = 0; i < count; ++i) { 270 // TODO: Key press / release 271 272 // TODO: NOT WORKING 273 unsigned int key = usbkbd_parse_scancode(key_codes[i]); 274 275 if (key == 0) { 276 continue; 277 } 278 kbd_push_ev(KEY_PRESS, key); 279 } 280 printf("\n"); 281 } 282 283 /* 284 * Kbd functions 285 */ 286 static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev) 287 { 288 // iterate over all configurations and interfaces 289 // TODO: more configurations!! 290 unsigned i; 291 for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) { 292 // TODO: endianness 293 uint16_t length = 294 kbd_dev->conf->interfaces[i].hid_desc.report_desc_info.length; 295 size_t actual_size = 0; 296 297 // allocate space for the report descriptor 298 kbd_dev->conf->interfaces[i].report_desc = (uint8_t *)malloc(length); 299 300 // get the descriptor from the device 301 int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe, 302 USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT, 303 i, 0, 304 kbd_dev->conf->interfaces[i].report_desc, length, 305 &actual_size); 306 307 if (rc != EOK) { 308 return rc; 309 } 310 311 assert(actual_size == length); 312 313 //dump_hid_class_descriptor(0, USB_DESCTYPE_HID_REPORT, 314 // kbd_dev->conf->interfaces[i].report_desc, length); 315 } 316 317 return EOK; 318 } 319 static int usbkbd_process_descriptors(usb_hid_dev_kbd_t *kbd_dev) 320 { 321 // get the first configuration descriptor (TODO: parse also other!) 322 usb_standard_configuration_descriptor_t config_desc; 323 324 int rc; 325 rc = usb_request_get_bare_configuration_descriptor(&kbd_dev->ctrl_pipe, 326 0, &config_desc); 327 328 if (rc != EOK) { 329 return rc; 330 } 331 332 // prepare space for all underlying descriptors 333 uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length); 334 if (descriptors == NULL) { 335 return ENOMEM; 336 } 337 338 size_t transferred = 0; 339 // get full configuration descriptor 340 rc = usb_request_get_full_configuration_descriptor(&kbd_dev->ctrl_pipe, 341 0, descriptors, 342 config_desc.total_length, &transferred); 343 344 if (rc != EOK) { 345 return rc; 346 } 347 if (transferred != config_desc.total_length) { 348 return ELIMIT; 349 } 350 351 /* 352 * Initialize the interrupt in endpoint. 353 */ 354 usb_endpoint_mapping_t endpoint_mapping[1] = { 355 { 356 .pipe = &kbd_dev->poll_pipe, 357 .description = &poll_endpoint_description, 358 .interface_no = 359 usb_device_get_assigned_interface(kbd_dev->device) 360 } 361 }; 362 rc = usb_endpoint_pipe_initialize_from_configuration( 363 endpoint_mapping, 1, 364 descriptors, config_desc.total_length, 365 &kbd_dev->wire); 366 if (rc != EOK) { 367 usb_log_error("Failed to initialize poll pipe: %s.\n", 368 str_error(rc)); 369 return rc; 370 } 371 if (!endpoint_mapping[0].present) { 372 usb_log_warning("Not accepting device, " \ 373 "not boot-protocol keyboard.\n"); 59 374 return EREFUSED; 60 375 } 61 376 377 378 379 380 kbd_dev->conf = (usb_hid_configuration_t *)calloc(1, 381 sizeof(usb_hid_configuration_t)); 382 if (kbd_dev->conf == NULL) { 383 free(descriptors); 384 return ENOMEM; 385 } 386 387 /*rc = usbkbd_parse_descriptors(descriptors, transferred, kbd_dev->conf); 388 free(descriptors); 389 if (rc != EOK) { 390 printf("Problem with parsing standard descriptors.\n"); 391 return rc; 392 } 393 394 // get and report descriptors*/ 395 rc = usbkbd_get_report_descriptor(kbd_dev); 396 if (rc != EOK) { 397 printf("Problem with parsing HID REPORT descriptor.\n"); 398 return rc; 399 } 400 401 //usbkbd_print_config(kbd_dev->conf); 402 403 /* 404 * TODO: 405 * 1) select one configuration (lets say the first) 406 * 2) how many interfaces?? how to select one?? 407 * ("The default setting for an interface is always alternate setting zero.") 408 * 3) find endpoint which is IN and INTERRUPT (parse), save its number 409 * as the endpoint for polling 410 */ 411 62 412 return EOK; 63 413 } 64 414 65 /*----------------------------------------------------------------------------*/ 415 static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev) 416 { 417 int rc; 418 419 usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)calloc(1, 420 sizeof(usb_hid_dev_kbd_t)); 421 422 if (kbd_dev == NULL) { 423 fprintf(stderr, NAME ": No memory!\n"); 424 return NULL; 425 } 426 427 kbd_dev->device = dev; 428 429 /* 430 * Initialize the backing connection to the host controller. 431 */ 432 rc = usb_device_connection_initialize_from_device(&kbd_dev->wire, dev); 433 if (rc != EOK) { 434 printf("Problem initializing connection to device: %s.\n", 435 str_error(rc)); 436 goto error_leave; 437 } 438 439 /* 440 * Initialize device pipes. 441 */ 442 rc = usb_endpoint_pipe_initialize_default_control(&kbd_dev->ctrl_pipe, 443 &kbd_dev->wire); 444 if (rc != EOK) { 445 printf("Failed to initialize default control pipe: %s.\n", 446 str_error(rc)); 447 goto error_leave; 448 } 449 450 /* 451 * will need all descriptors: 452 * 1) choose one configuration from configuration descriptors 453 * (set it to the device) 454 * 2) set endpoints from endpoint descriptors 455 */ 456 457 // TODO: get descriptors, parse descriptors and save endpoints 458 usb_endpoint_pipe_start_session(&kbd_dev->ctrl_pipe); 459 //usb_request_set_configuration(&kbd_dev->ctrl_pipe, 1); 460 rc = usbkbd_process_descriptors(kbd_dev); 461 usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe); 462 if (rc != EOK) { 463 goto error_leave; 464 } 465 466 return kbd_dev; 467 468 error_leave: 469 free(kbd_dev); 470 return NULL; 471 } 472 473 static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev, 474 uint8_t *buffer, size_t actual_size) 475 { 476 usb_hid_report_in_callbacks_t *callbacks = 477 (usb_hid_report_in_callbacks_t *)malloc( 478 sizeof(usb_hid_report_in_callbacks_t)); 479 callbacks->keyboard = usbkbd_process_keycodes; 480 481 //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 482 // NULL); 483 printf("Calling usb_hid_boot_keyboard_input_report() with size %zu\n", 484 actual_size); 485 //dump_buffer("bufffer: ", buffer, actual_size); 486 int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size, callbacks, 487 NULL); 488 if (rc != EOK) { 489 printf("Error in usb_hid_boot_keyboard_input_report(): %d\n", rc); 490 } 491 } 492 493 static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev) 494 { 495 int rc, sess_rc; 496 uint8_t buffer[BUFFER_SIZE]; 497 size_t actual_size; 498 499 printf("Polling keyboard...\n"); 500 501 while (true) { 502 async_usleep(1000 * 10); 503 504 sess_rc = usb_endpoint_pipe_start_session(&kbd_dev->poll_pipe); 505 if (sess_rc != EOK) { 506 printf("Failed to start a session: %s.\n", 507 str_error(sess_rc)); 508 continue; 509 } 510 511 rc = usb_endpoint_pipe_read(&kbd_dev->poll_pipe, buffer, 512 BUFFER_SIZE, &actual_size); 513 sess_rc = usb_endpoint_pipe_end_session(&kbd_dev->poll_pipe); 514 515 if (rc != EOK) { 516 printf("Error polling the keyboard: %s.\n", 517 str_error(rc)); 518 continue; 519 } 520 521 if (sess_rc != EOK) { 522 printf("Error closing session: %s.\n", 523 str_error(sess_rc)); 524 continue; 525 } 526 527 /* 528 * If the keyboard answered with NAK, it returned no data. 529 * This implies that no change happened since last query. 530 */ 531 if (actual_size == 0) { 532 printf("Keyboard returned NAK\n"); 533 continue; 534 } 535 536 /* 537 * TODO: Process pressed keys. 538 */ 539 printf("Calling usbkbd_process_interrupt_in()\n"); 540 usbkbd_process_interrupt_in(kbd_dev, buffer, actual_size); 541 } 542 543 // not reached 544 assert(0); 545 } 546 547 static int usbkbd_fibril_device(void *arg) 548 { 549 printf("!!! USB device fibril\n"); 550 551 if (arg == NULL) { 552 printf("No device!\n"); 553 return -1; 554 } 555 556 device_t *dev = (device_t *)arg; 557 558 // initialize device (get and process descriptors, get address, etc.) 559 usb_hid_dev_kbd_t *kbd_dev = usbkbd_init_device(dev); 560 if (kbd_dev == NULL) { 561 printf("Error while initializing device.\n"); 562 return -1; 563 } 564 565 usbkbd_poll_keyboard(kbd_dev); 566 567 return EOK; 568 } 569 570 static int usbkbd_add_device(device_t *dev) 571 { 572 /* For now, fail immediately. */ 573 //return ENOTSUP; 574 575 /* 576 * When everything is okay, connect to "our" HC. 577 * 578 * Not supported yet, skip.. 579 */ 580 // int phone = usb_drv_hc_connect_auto(dev, 0); 581 // if (phone < 0) { 582 // /* 583 // * Connecting to HC failed, roll-back and announce 584 // * failure. 585 // */ 586 // return phone; 587 // } 588 589 // dev->parent_phone = phone; 590 591 /* 592 * Create new fibril for handling this keyboard 593 */ 594 fid_t fid = fibril_create(usbkbd_fibril_device, dev); 595 if (fid == 0) { 596 printf("%s: failed to start fibril for HID device\n", NAME); 597 return ENOMEM; 598 } 599 fibril_add_ready(fid); 600 601 dev->ops = &keyboard_ops; 602 603 add_device_to_class(dev, "keyboard"); 604 605 /* 606 * Hurrah, device is initialized. 607 */ 608 return EOK; 609 } 66 610 67 611 static driver_ops_t kbd_driver_ops = { 68 .add_device = usb hid_add_device,612 .add_device = usbkbd_add_device, 69 613 }; 70 71 /*----------------------------------------------------------------------------*/72 614 73 615 static driver_t kbd_driver = { … … 76 618 }; 77 619 78 /*----------------------------------------------------------------------------*/79 80 620 int main(int argc, char *argv[]) 81 621 { 82 usb_log_enable(USB_LOG_LEVEL_INFO, NAME);83 return d df_driver_main(&kbd_driver);622 usb_log_enable(USB_LOG_LEVEL_INFO, "usbhid"); 623 return driver_main(&kbd_driver); 84 624 } 85 625
Note:
See TracChangeset
for help on using the changeset viewer.