1 /* Keyboard/mouse input server. */ 2 #include <minix/drivers.h> 3 #include <minix/chardriver.h> 4 #include <minix/ds.h> 5 #include <sys/ioctl.h> 6 #include <sys/kbdio.h> 7 8 #include "input.h" 9 10 #define INPUT_DEBUG 0 11 12 static int input_open(devminor_t, int, endpoint_t); 13 static int input_close(devminor_t); 14 static ssize_t input_read(devminor_t, u64_t, endpoint_t, cp_grant_id_t, size_t, 15 int, cdev_id_t); 16 static int input_ioctl(devminor_t, unsigned long, endpoint_t, cp_grant_id_t, 17 int, endpoint_t, cdev_id_t); 18 static int input_cancel(devminor_t, endpoint_t, cdev_id_t); 19 static int input_select(devminor_t, unsigned int, endpoint_t); 20 static void input_other(message *, int); 21 22 static struct input_dev devs[INPUT_DEV_MAX]; 23 24 #define input_dev_active(dev) ((dev)->owner != NONE || \ 25 (dev)->minor == KBDMUX_MINOR || \ 26 (dev)->minor == MOUSEMUX_MINOR) 27 #define input_dev_buf_empty(dev) ((dev)->count == 0) 28 #define input_dev_buf_full(dev) ((dev)->count == EVENTBUF_SIZE) 29 30 /* Entry points to the input driver. */ 31 static struct chardriver input_tab = { 32 .cdr_open = input_open, 33 .cdr_close = input_close, 34 .cdr_read = input_read, 35 .cdr_ioctl = input_ioctl, 36 .cdr_cancel = input_cancel, 37 .cdr_select = input_select, 38 .cdr_other = input_other 39 }; 40 41 /* 42 * Map a minor number to an input device structure. 43 */ 44 static struct input_dev * 45 input_map(devminor_t minor) 46 { 47 /* 48 * The minor device numbers were chosen not to be equal to the array 49 * slots, so that more keyboards can be added without breaking backward 50 * compatibility later. 51 */ 52 if (minor == KBDMUX_MINOR) 53 return &devs[KBDMUX_DEV]; 54 else if (minor >= KBD0_MINOR && minor < KBD0_MINOR + KBD_MINORS) 55 return &devs[FIRST_KBD_DEV + (minor - KBD0_MINOR)]; 56 else if (minor == MOUSEMUX_MINOR) 57 return &devs[MOUSEMUX_DEV]; 58 else if (minor >= MOUSE0_MINOR && minor < MOUSE0_MINOR + MOUSE_MINORS) 59 return &devs[FIRST_MOUSE_DEV + (minor - MOUSE0_MINOR)]; 60 else 61 return NULL; 62 } 63 64 /* 65 * Map an input device structure index to a minor number. 66 */ 67 static devminor_t 68 input_revmap(int id) 69 { 70 if (id == KBDMUX_DEV) 71 return KBDMUX_MINOR; 72 else if (id >= FIRST_KBD_DEV && id <= LAST_KBD_DEV) 73 return KBD0_MINOR + (id - FIRST_KBD_DEV); 74 else if (id == MOUSEMUX_DEV) 75 return MOUSEMUX_MINOR; 76 else if (id >= FIRST_MOUSE_DEV && id <= LAST_MOUSE_DEV) 77 return MOUSE0_MINOR + (id - FIRST_MOUSE_DEV); 78 else 79 panic("reverse-mapping invalid ID %d", id); 80 } 81 82 /* 83 * Open an input device. 84 */ 85 static int 86 input_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt)) 87 { 88 struct input_dev *input_dev; 89 90 if ((input_dev = input_map(minor)) == NULL) 91 return ENXIO; 92 93 if (!input_dev_active(input_dev)) 94 return ENXIO; 95 96 if (input_dev->opened) 97 return EBUSY; 98 99 input_dev->opened = TRUE; 100 101 return OK; 102 } 103 104 /* 105 * Close an input device. 106 */ 107 static int 108 input_close(devminor_t minor) 109 { 110 struct input_dev *input_dev; 111 112 if ((input_dev = input_map(minor)) == NULL) 113 return ENXIO; 114 115 if (!input_dev->opened) { 116 printf("INPUT: closing already-closed device %d\n", minor); 117 return EINVAL; 118 } 119 120 input_dev->opened = FALSE; 121 input_dev->tail = 0; 122 input_dev->count = 0; 123 124 return OK; 125 } 126 127 /* 128 * Copy input events to a reader. 129 */ 130 static ssize_t 131 input_copy_events(endpoint_t endpt, cp_grant_id_t grant, 132 unsigned int event_count, struct input_dev *input_dev) 133 { 134 int r, nbytes, wrap_left; 135 size_t event_size = sizeof(*input_dev->eventbuf); 136 137 if (input_dev->count < event_count) 138 panic("input_copy_events: not enough input is ready"); 139 140 wrap_left = input_dev->tail + event_count - EVENTBUF_SIZE; 141 nbytes = (wrap_left <= 0 ? event_count : 142 EVENTBUF_SIZE - input_dev->tail) * event_size; 143 144 if ((r = sys_safecopyto(endpt, grant, 0, 145 (vir_bytes)(input_dev->eventbuf + input_dev->tail), nbytes)) != OK) 146 return r; 147 148 /* Copy possible remaining part if we wrap over. */ 149 if (wrap_left > 0 && (r = sys_safecopyto(endpt, grant, nbytes, 150 (vir_bytes) input_dev->eventbuf, wrap_left * event_size)) != OK) 151 return r; 152 153 input_dev->tail = (input_dev->tail + event_count) % EVENTBUF_SIZE; 154 input_dev->count -= event_count; 155 156 return event_size * event_count; /* bytes copied */ 157 } 158 159 /* 160 * Read from an input device. 161 */ 162 static ssize_t 163 input_read(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt, 164 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) 165 { 166 unsigned int event_count; 167 struct input_dev *input_dev; 168 169 if ((input_dev = input_map(minor)) == NULL) 170 return ENXIO; 171 172 /* We cannot accept more than one pending read request at once. */ 173 if (!input_dev_active(input_dev) || input_dev->suspended) 174 return EIO; 175 176 /* The caller's buffer must have room for at least one whole event. */ 177 event_count = size / sizeof(*input_dev->eventbuf); 178 if (event_count == 0) 179 return EIO; 180 181 /* No data available? Suspend the caller, unless we shouldn't block. */ 182 if (input_dev_buf_empty(input_dev)) { 183 if (flags & CDEV_NONBLOCK) 184 return EAGAIN; 185 186 input_dev->suspended = TRUE; 187 input_dev->caller = endpt; 188 input_dev->grant = grant; 189 input_dev->req_id = id; 190 191 /* We should now wake up any selector, but that's lame.. */ 192 return EDONTREPLY; 193 } 194 195 if (event_count > input_dev->count) 196 event_count = input_dev->count; 197 198 return input_copy_events(endpt, grant, event_count, input_dev); 199 } 200 201 /* 202 * Set keyboard LEDs on one or all keyboards. 203 */ 204 static void 205 input_set_leds(devminor_t minor, unsigned int mask) 206 { 207 struct input_dev *dev; 208 message m; 209 int i, r; 210 211 /* Prepare the request message */ 212 memset(&m, 0, sizeof(m)); 213 214 m.m_type = INPUT_SETLEDS; 215 m.m_input_linputdriver_setleds.led_mask = mask; 216 217 /* 218 * Send the request to all matching keyboard devices. As side effect, 219 * this approach discards the request on mouse devices. 220 */ 221 for (i = FIRST_KBD_DEV; i <= LAST_KBD_DEV; i++) { 222 dev = &devs[i]; 223 224 if (minor != KBDMUX_MINOR && minor != dev->minor) 225 continue; 226 227 /* Save the new state; the driver might (re)start later. */ 228 dev->leds = mask; 229 230 if (dev->owner != NONE) { 231 if ((r = asynsend3(dev->owner, &m, AMF_NOREPLY)) != OK) 232 printf("INPUT: asynsend to %u failed (%d)\n", 233 dev->owner, r); 234 } 235 } 236 } 237 238 /* 239 * Process an IOCTL request. 240 */ 241 static int 242 input_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, 243 cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) 244 { 245 struct input_dev *input_dev; 246 kio_leds_t leds; 247 unsigned int mask; 248 int r; 249 250 if ((input_dev = input_map(minor)) == NULL) 251 return ENXIO; 252 253 if (!input_dev_active(input_dev)) 254 return EIO; 255 256 switch (request) { 257 case KIOCSLEDS: 258 if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds, 259 sizeof(leds))) != OK) 260 return r; 261 262 mask = 0; 263 if (leds.kl_bits & KBD_LEDS_NUM) 264 mask |= (1 << INPUT_LED_NUMLOCK); 265 if (leds.kl_bits & KBD_LEDS_CAPS) 266 mask |= (1 << INPUT_LED_CAPSLOCK); 267 if (leds.kl_bits & KBD_LEDS_SCROLL) 268 mask |= (1 << INPUT_LED_SCROLLLOCK); 269 270 input_set_leds(minor, mask); 271 272 return OK; 273 274 default: 275 return ENOTTY; 276 } 277 } 278 279 /* 280 * Cancel a suspended read request. 281 */ 282 static int 283 input_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) 284 { 285 struct input_dev *input_dev; 286 287 if ((input_dev = input_map(minor)) == NULL) 288 return ENXIO; 289 290 if (input_dev->suspended && input_dev->caller == endpt && 291 input_dev->req_id == id) { 292 input_dev->suspended = FALSE; 293 294 return EINTR; 295 } 296 297 return EDONTREPLY; 298 } 299 300 /* 301 * Perform a select call on an input device. 302 */ 303 static int 304 input_select(devminor_t minor, unsigned int ops, endpoint_t endpt) 305 { 306 struct input_dev *input_dev; 307 int ready_ops; 308 309 if ((input_dev = input_map(minor)) == NULL) 310 return ENXIO; 311 312 ready_ops = 0; 313 314 if (ops & CDEV_OP_RD) { 315 if (!input_dev_active(input_dev) || input_dev->suspended) 316 ready_ops |= CDEV_OP_RD; /* immediate error */ 317 else if (!input_dev_buf_empty(input_dev)) 318 ready_ops |= CDEV_OP_RD; /* data available */ 319 else if (ops & CDEV_NOTIFY) 320 input_dev->selector = endpt; /* report later */ 321 } 322 323 if (ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR; /* immediate error */ 324 325 return ready_ops; 326 } 327 328 /* 329 * An input device receives an input event. Enqueue it, and possibly unsuspend 330 * a read request or wake up a selector. 331 */ 332 static void 333 input_process(struct input_dev *input_dev, const message *m) 334 { 335 unsigned int next; 336 int r; 337 338 if (input_dev_buf_full(input_dev)) { 339 /* Overflow. Overwrite the oldest event. */ 340 input_dev->tail = (input_dev->tail + 1) % EVENTBUF_SIZE; 341 input_dev->count--; 342 343 #if INPUT_DEBUG 344 printf("INPUT: overflow on device %u\n", input_dev - devs); 345 #endif 346 } 347 next = (input_dev->tail + input_dev->count) % EVENTBUF_SIZE; 348 input_dev->eventbuf[next].page = m->m_linputdriver_input_event.page; 349 input_dev->eventbuf[next].code = m->m_linputdriver_input_event.code; 350 input_dev->eventbuf[next].value = m->m_linputdriver_input_event.value; 351 input_dev->eventbuf[next].flags = m->m_linputdriver_input_event.flags; 352 input_dev->eventbuf[next].devid = m->m_linputdriver_input_event.id; 353 input_dev->eventbuf[next].rsvd[0] = 0; 354 input_dev->eventbuf[next].rsvd[1] = 0; 355 input_dev->count++; 356 357 /* 358 * There is new input. Revive a suspended reader if there was one. 359 * Otherwise see if we should reply to a select query. 360 */ 361 if (input_dev->suspended) { 362 r = input_copy_events(input_dev->caller, input_dev->grant, 1, 363 input_dev); 364 chardriver_reply_task(input_dev->caller, input_dev->req_id, r); 365 input_dev->suspended = FALSE; 366 } else if (input_dev->selector != NONE) { 367 chardriver_reply_select(input_dev->selector, input_dev->minor, 368 CDEV_OP_RD); 369 input_dev->selector = NONE; 370 } 371 } 372 373 /* 374 * An input event has arrived from a driver. 375 */ 376 static void 377 input_event(message *m) 378 { 379 struct input_dev *input_dev, *mux_dev; 380 int r, id; 381 382 /* Unlike minor numbers, device IDs are in fact array indices. */ 383 id = m->m_linputdriver_input_event.id; 384 if (id < 0 || id >= INPUT_DEV_MAX) 385 return; 386 387 /* The sender must owner the device. */ 388 input_dev = &devs[id]; 389 if (input_dev->owner != m->m_source) 390 return; 391 392 /* Input events are also delivered to the respective multiplexer. */ 393 if (input_dev->minor >= KBD0_MINOR && 394 input_dev->minor < KBD0_MINOR + KBD_MINORS) 395 mux_dev = &devs[KBDMUX_DEV]; 396 else 397 mux_dev = &devs[MOUSEMUX_DEV]; 398 399 /* 400 * Try to deliver the event to the input device or otherwise the 401 * corresponding multiplexer. If neither are opened, forward the event 402 * to TTY. 403 */ 404 if (input_dev->opened) 405 input_process(input_dev, m); 406 else if (mux_dev->opened) 407 input_process(mux_dev, m); 408 else { 409 message fwd; 410 mess_input_tty_event *tty_event = &(fwd.m_input_tty_event); 411 412 fwd.m_type = TTY_INPUT_EVENT; 413 tty_event->id = m->m_linputdriver_input_event.id; 414 tty_event->page = m->m_linputdriver_input_event.page; 415 tty_event->code = m->m_linputdriver_input_event.code; 416 tty_event->value = m->m_linputdriver_input_event.value; 417 tty_event->flags = m->m_linputdriver_input_event.flags; 418 419 if ((r = ipc_send(TTY_PROC_NR, &fwd)) != OK) 420 printf("INPUT: send to TTY failed (%d)\n", r); 421 } 422 } 423 424 /* 425 * Allocate a device structure for an input driver of the given type, and 426 * return its ID. If the given label already owns a device ID of the right 427 * type, update that entry instead. If no device ID could be allocated, return 428 * INVALID_INPUT_ID. 429 */ 430 static int 431 input_alloc_id(int mouse, endpoint_t owner, const char *label) 432 { 433 int n, id, start, end; 434 435 if (!mouse) { 436 start = FIRST_KBD_DEV; 437 end = LAST_KBD_DEV; 438 } else { 439 start = FIRST_MOUSE_DEV; 440 end = LAST_MOUSE_DEV; 441 } 442 443 id = INVALID_INPUT_ID; 444 for (n = start; n <= end; n++) { 445 if (devs[n].owner != NONE) { 446 if (!strcmp(devs[n].label, label)) { 447 devs[n].owner = owner; 448 return n; 449 } 450 /* Do not allocate the ID of a disconnected but open device. */ 451 } else if (!devs[n].opened && id == INVALID_INPUT_ID) { 452 id = n; 453 } 454 } 455 456 if (id != INVALID_INPUT_ID) { 457 devs[id].owner = owner; 458 strlcpy(devs[id].label, label, sizeof(devs[id].label)); 459 460 #if INPUT_DEBUG 461 printf("INPUT: connected device %u to %u (%s)\n", id, 462 owner, label); 463 #endif 464 } else { 465 printf("INPUT: out of %s slots for new driver %d\n", 466 mouse ? "mouse" : "keyboard", owner); 467 } 468 469 return id; 470 } 471 472 /* 473 * Register keyboard and/or a mouse devices for a driver. 474 */ 475 static void 476 input_connect(endpoint_t owner, char *labelp, int typemask) 477 { 478 message m; 479 char label[DS_MAX_KEYLEN]; 480 int r, kbd_id, mouse_id; 481 482 #if INPUT_DEBUG 483 printf("INPUT: connect request from %u (%s) for mask %x\n", owner, 484 labelp, typemask); 485 #endif 486 487 /* Check the driver's label. */ 488 if ((r = ds_retrieve_label_name(label, owner)) != OK) { 489 printf("INPUT: unable to get label for %u: %d\n", owner, r); 490 return; 491 } 492 if (strcmp(label, labelp)) { 493 printf("INPUT: ignoring driver %s label %s\n", label, labelp); 494 return; 495 } 496 497 kbd_id = INVALID_INPUT_ID; 498 mouse_id = INVALID_INPUT_ID; 499 500 /* 501 * We ignore allocation failures here, thus possibly sending invalid 502 * IDs to the driver even for either or both the devices types it 503 * requested. As a result, the driver will not send us input for these 504 * device types, possibly effectively disabling the driver altogether. 505 * Theoretically we could still admit events to the multiplexers for 506 * such drivers, but that would lead to unexpected behavior with 507 * respect to keyboard LEDs, for example. 508 */ 509 if (typemask & INPUT_DEV_KBD) 510 kbd_id = input_alloc_id(FALSE /*mouse*/, owner, label); 511 if (typemask & INPUT_DEV_MOUSE) 512 mouse_id = input_alloc_id(TRUE /*mouse*/, owner, label); 513 514 memset(&m, 0, sizeof(m)); 515 516 m.m_type = INPUT_CONF; 517 m.m_input_linputdriver_input_conf.kbd_id = kbd_id; 518 m.m_input_linputdriver_input_conf.mouse_id = mouse_id; 519 m.m_input_linputdriver_input_conf.rsvd1_id = INVALID_INPUT_ID; /* reserved (joystick?) */ 520 m.m_input_linputdriver_input_conf.rsvd2_id = INVALID_INPUT_ID; /* reserved for future use */ 521 522 if ((r = asynsend3(owner, &m, AMF_NOREPLY)) != OK) 523 printf("INPUT: asynsend to %u failed (%d)\n", owner, r); 524 525 /* If a keyboard was registered, also set its initial LED state. */ 526 if (kbd_id != INVALID_INPUT_ID) 527 input_set_leds(devs[kbd_id].minor, devs[kbd_id].leds); 528 } 529 530 /* 531 * Disconnect a device. 532 */ 533 static void 534 input_disconnect(struct input_dev *input_dev) 535 { 536 #if INPUT_DEBUG 537 printf("INPUT: disconnected device %u\n", input_dev - devs); 538 #endif 539 540 if (input_dev->suspended) { 541 chardriver_reply_task(input_dev->caller, input_dev->req_id, 542 EIO); 543 input_dev->suspended = FALSE; 544 } 545 546 if (input_dev->selector != NONE) { 547 chardriver_reply_select(input_dev->selector, input_dev->minor, 548 CDEV_OP_RD); 549 input_dev->selector = NONE; 550 } 551 552 input_dev->owner = NONE; 553 } 554 555 /* 556 * Check for driver status changes in the data store. 557 */ 558 static void 559 input_check(void) 560 { 561 char key[DS_MAX_KEYLEN], *label; 562 const char *driver_prefix = "drv.inp."; 563 u32_t value; 564 size_t len; 565 int i, r, type; 566 endpoint_t owner; 567 568 len = strlen(driver_prefix); 569 570 /* Check for new (input driver) entries. */ 571 while (ds_check(key, &type, &owner) == OK) { 572 if ((r = ds_retrieve_u32(key, &value)) != OK) { 573 printf("INPUT: ds_retrieve_u32 failed (%d)\n", r); 574 continue; 575 } 576 577 /* Only check for input driver registration events. */ 578 if (strncmp(key, driver_prefix, len)) 579 continue; 580 581 /* The prefix is followed by the driver's own label. */ 582 label = &key[len]; 583 584 input_connect(owner, label, value); 585 } 586 587 /* Check for removed (label) entries. */ 588 for (i = 0; i < INPUT_DEV_MAX; i++) { 589 /* This also skips the multiplexers. */ 590 if (devs[i].owner == NONE) 591 continue; 592 593 r = ds_retrieve_label_endpt(devs[i].label, &owner); 594 595 if (r == OK) 596 devs[i].owner = owner; /* not really necessary */ 597 else if (r == ESRCH) 598 input_disconnect(&devs[i]); 599 else 600 printf("INPUT: ds_retrieve_label_endpt failed (%d)\n", 601 r); 602 } 603 } 604 605 /* 606 * Process messages not part of the character driver protocol. 607 */ 608 static void 609 input_other(message *m, int ipc_status) 610 { 611 if (is_ipc_notify(ipc_status)) { 612 switch (m->m_source) { 613 case DS_PROC_NR: 614 input_check(); 615 break; 616 default: 617 printf("INPUT: unexpected notify from %d\n", 618 m->m_source); 619 } 620 return; 621 } 622 623 /* An input event from a registered driver. */ 624 switch (m->m_type) { 625 case INPUT_EVENT: 626 input_event(m); 627 628 break; 629 630 case INPUT_SETLEDS: 631 if (m->m_source == TTY_PROC_NR) { 632 input_set_leds(KBDMUX_MINOR, m->m_input_linputdriver_setleds.led_mask); 633 634 break; 635 } 636 /* FALLTHROUGH */ 637 default: 638 printf("INPUT: unexpected message %d from %d\n", 639 m->m_type, m->m_source); 640 } 641 } 642 643 /* 644 * Initialize the input server. 645 */ 646 static int 647 input_init(int UNUSED(type), sef_init_info_t *UNUSED(info)) 648 { 649 message m; 650 int i, r; 651 652 /* Initialize input device structures. */ 653 for (i = 0; i < INPUT_DEV_MAX; i++) { 654 devs[i].minor = input_revmap(i); 655 devs[i].owner = NONE; 656 devs[i].tail = 0; 657 devs[i].count = 0; 658 devs[i].opened = FALSE; 659 devs[i].suspended = FALSE; 660 devs[i].selector = NONE; 661 devs[i].leds = 0; 662 } 663 664 /* Subscribe to driver registration events for input drivers. */ 665 if ((r = ds_subscribe("drv\\.inp\\..*", DSF_INITIAL)) != OK) 666 panic("INPUT: can't subscribe to driver events (%d)", r); 667 668 /* Announce our presence to VFS. */ 669 chardriver_announce(); 670 671 /* Announce our presence to TTY. */ 672 memset(&m, 0, sizeof(m)); 673 674 m.m_type = TTY_INPUT_UP; 675 676 if ((r = ipc_send(TTY_PROC_NR, &m)) != OK) 677 printf("INPUT: send to TTY failed (%d)\n", r); 678 679 return OK; 680 } 681 682 /* 683 * Set callbacks and invoke SEF startup. 684 */ 685 static void 686 input_startup(void) 687 { 688 sef_setcb_init_fresh(input_init); 689 690 sef_startup(); 691 } 692 693 /* 694 * Main program of the input server. 695 */ 696 int 697 main(void) 698 { 699 input_startup(); 700 701 chardriver_task(&input_tab); 702 703 return 0; 704 } 705