Changes in uspace/drv/usbhid/main.c [0f21c0c:1c6c4092] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhid/main.c
r0f21c0c r1c6c4092 36 36 */ 37 37 38 #include <driver.h> 39 #include <ipc/driver.h> 40 #include <ipc/kbd.h> 41 #include <io/keycode.h> 42 #include <io/console.h> 38 #include <ddf/driver.h> 39 #include <usb/debug.h> 43 40 #include <errno.h> 44 #include <str_error.h>45 #include <fibril.h>46 #include <usb/debug.h>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 41 59 #define BUFFER_SIZE 8 42 #include "kbddev.h" 43 44 /*----------------------------------------------------------------------------*/ 45 60 46 #define NAME "usbhid" 61 47 62 #define GUESSED_POLL_ENDPOINT 1 48 /*----------------------------------------------------------------------------*/ 63 49 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) 50 static int usbhid_add_device(ddf_dev_t *dev) 89 51 { 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); 52 usb_log_debug("usbhid_add_device()\n"); 124 53 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 */ 54 int rc = usbhid_kbd_try_add_device(dev); 213 55 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; 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"); 59 return EREFUSED; 233 60 } 234 61 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-paste247 */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 now253 * 3)254 */255 256 /*257 * Callbacks for parser258 */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 / release271 272 // TODO: NOT WORKING273 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 functions285 */286 static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev)287 {288 // iterate over all configurations and interfaces289 // TODO: more configurations!!290 unsigned i;291 for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) {292 // TODO: endianness293 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 descriptor298 kbd_dev->conf->interfaces[i].report_desc = (uint8_t *)malloc(length);299 300 // get the descriptor from the device301 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 descriptors333 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 descriptor340 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");374 return EREFUSED;375 }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 number409 * as the endpoint for polling410 */411 412 62 return EOK; 413 63 } 414 64 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 } 65 /*----------------------------------------------------------------------------*/ 610 66 611 67 static driver_ops_t kbd_driver_ops = { 612 .add_device = usb kbd_add_device,68 .add_device = usbhid_add_device, 613 69 }; 70 71 /*----------------------------------------------------------------------------*/ 614 72 615 73 static driver_t kbd_driver = { … … 618 76 }; 619 77 78 /*----------------------------------------------------------------------------*/ 79 620 80 int main(int argc, char *argv[]) 621 81 { 622 usb_log_enable(USB_LOG_LEVEL_INFO, "usbhid");623 return d river_main(&kbd_driver);82 usb_log_enable(USB_LOG_LEVEL_INFO, NAME); 83 return ddf_driver_main(&kbd_driver); 624 84 } 625 85
Note:
See TracChangeset
for help on using the changeset viewer.