// Raw input event devices -- /dev/input/event0 and /dev/input/event1. // // Everything that produces input feeds this: the PS/2 keyboard and mouse, and // the USB HID driver. The console keeps its own path and is unaffected; these // nodes are a *second* consumer of the same interrupts, so a program can read // keys while the shell still gets characters. // // Two devices rather than one because they are two devices. A compositor // grabs the pointer and leaves the keyboard alone, or the other way round, and // merging them into a single stream makes that impossible to express. #include "core/types.h" #include "core/defs.h" #include "core/param.h" #include "arch/mmu.h" #include "core/proc.h" #include "core/spinlock.h" #include "core/sleeplock.h" #include "fs/fs.h" #include "fs/file.h" #include "dev/input.h" #include "core/uaccess.h" #include "gfx/gfx.h" #include "uapi/errno.h" #define NEVENT 256 // per device; ~10 seconds of frantic typing struct input_dev { struct spinlock lock; struct input_event ev[NEVENT]; uint r, w; // free-running; the difference is the count // Exclusive grab (EVIOCGRAB). While set, keys still arrive here but stop // being handed to the console's line discipline. // // Without this a full-screen program does not really own the keyboard: it // reads /dev/input/event0 *and* the shell behind it reads the same keystrokes // off the tty. The observed failure was a full-screen program quietly typing // its entire session into the shell underneath, so the first Enter after // exiting ran whatever had accumulated. The grab is also exactly what a // compositor needs, which is why it lives here rather than in any one client. int grabbed; // How many descriptors are open on this device. // // Events are only queued while this is non-zero, and the backlog is dropped // on the first open. Both halves matter: without them the ring is a log of // every key pressed since boot, and the next program to open the device is // handed the lot as though the user had just typed it. int opens; // What the device has said, for the EVIOCG* queries. `caps` is every type // and code it can produce: its defaults, set in inputinit(), and anything // it has actually reported since -- a USB tablet makes the mouse device // absolute the first time it moves. `keys` is which keys and buttons are // down right now, and `abs` where each absolute axis last was. Tracked // whether or not anybody has the device open; a program that opens it with // a key held needs to know. uchar caps[EV_MAX + 1][(KEY_MAX + 1) / 8]; uchar keys[(KEY_MAX + 1) / 8]; int32 abs[2]; }; static struct input_dev idev[NINPUTDEV]; static int input_up; extern uint ticks; void inputinit(void) { int i; for(i = 0; i < NINPUTDEV; i++) initlock(&idev[i].lock, "input"); // Every key a PS/2 or USB keyboard here can produce is below 0x80, but a // keyboard advertises the whole first page on Linux too, and both Xorg's // evdev and libinput call a device a keyboard by finding letter keys in it. struct input_dev *k = &idev[INPUT_KBD], *m = &idev[INPUT_MOUSE]; for(i = 1; i < 0x100; i++) k->caps[EV_KEY][i / 8] |= 1 << (i % 8); k->caps[0][0] = (1 << EV_SYN) | (1 << EV_KEY); k->caps[0][EV_REP / 8] |= 1 << (EV_REP % 8); m->caps[0][0] = (1 << EV_SYN) | (1 << EV_KEY) | (1 << EV_REL); for(i = BTN_LEFT; i <= BTN_MIDDLE; i++) m->caps[EV_KEY][i / 8] |= 1 << (i % 8); m->caps[EV_REL][0] = (1 << REL_X) | (1 << REL_Y); m->caps[EV_REL][REL_WHEEL / 8] |= 1 << (REL_WHEEL % 8); // Producers run from interrupt handlers and can fire before this point in // boot. Until the locks exist, an event has nowhere safe to go. __sync_synchronize(); input_up = 1; } // Append one event. Called from interrupt context, so it never sleeps and // never blocks on a full ring. void input_report(int dev, int type, int code, int value) { struct input_dev *d; struct input_event *e; if(!input_up || dev < 0 || dev >= NINPUTDEV) return; d = &idev[dev]; if(type > 0 && type <= EV_MAX && code >= 0 && code <= KEY_MAX){ d->caps[0][type / 8] |= 1 << (type % 8); d->caps[type][code / 8] |= 1 << (code % 8); if(type == EV_KEY){ if(value) d->keys[code / 8] |= 1 << (code % 8); else d->keys[code / 8] &= ~(1 << (code % 8)); } if(type == EV_ABS && code < 2) d->abs[code] = value; } // Nobody is listening, so there is nowhere for this to go. Linux does the // same: an evdev device with no clients does not accumulate. if(d->opens == 0) return; acquire(&d->lock); // A full ring drops the *oldest* event, not the newest. Dropping the newest // is the obvious choice and it is wrong: the event most likely to be lost is // then a key release, and a lost release leaves the key held down forever // as far as every reader is concerned. Losing the oldest costs history, not // state. if(d->w - d->r >= NEVENT) d->r++; e = &d->ev[d->w % NEVENT]; e->time.tv_sec = ticks / HZ; e->time.tv_usec = (ticks % HZ) * USEC_PER_TICK; e->type = (uint16)type; e->code = (uint16)code; e->value = (int32)value; d->w++; release(&d->lock); } // End a report. A reader that acts on each event as it arrives will see a // diagonal mouse move as two separate moves; the SYN is how it knows the two // axes belong to the same physical motion. void input_sync(int dev) { if(!input_up || dev < 0 || dev >= NINPUTDEV) return; input_report(dev, EV_SYN, SYN_REPORT, 0); wakeup(&idev[dev]); } int input_ready(int dev) { int n; if(!input_up || dev < 0 || dev >= NINPUTDEV) return 0; acquire(&idev[dev].lock); n = idev[dev].w != idev[dev].r; release(&idev[dev].lock); return n; } // A descriptor has been opened on this device. // // The backlog is discarded, which is the whole point. Events queued before a // program opened the device were meant for whoever had it *then* -- almost // always the shell, which already consumed them as a command line. Replaying // them into the new owner means a program is handed the keystrokes that // launched it, as input, the instant it starts. That was a real crash and not a // cosmetic one: the replayed characters were interpreted as commands, and one of // them asked for a mode the program had not initialised yet. // // Linux gets this for free by giving every open its own client queue. One // shared ring plus "start from now" is the same answer for a single reader, // which is the case that exists. void inputopen(struct inode *ip) { int dev = ip->minor; if(dev < 0 || dev >= NINPUTDEV) return; acquire(&idev[dev].lock); idev[dev].opens++; idev[dev].r = idev[dev].w; // start from now, not from boot release(&idev[dev].lock); } // The devsw ready hook: would a read block? int inputready(struct inode *ip) { return input_ready(ip->minor); } // Is this device grabbed? Asked by the keyboard drivers before they hand a // character to the console. int input_is_grabbed(int dev) { if(!input_up || dev < 0 || dev >= NINPUTDEV) return 0; return idev[dev].grabbed; } // EVIOCGRAB. Linux's semantics: one holder at a time, and it is not an error // to grab what you already hold. int input_grab(int dev, int on) { if(!input_up || dev < 0 || dev >= NINPUTDEV) return -ENODEV; on = on ? 1 : 0; if(idev[dev].grabbed != on){ idev[dev].grabbed = on; // Said out loud. A grabbed keyboard is a console that has gone deaf on // purpose, and that is indistinguishable from one that has gone deaf by // accident unless the kernel says which it was. cprintf("input: event%d %s by pid %d\n", dev, on ? "grabbed" : "released", myproc() ? myproc()->pid : -1); } return 0; } // The last descriptor on this device is going away. // // Releasing the grab here is not tidiness, it is the difference between a // crashed game and a machine you have to reboot: a program that grabs the // keyboard and dies without ungrabbing would leave the console permanently // deaf. The close hook makes the release unconditional. void inputclose(struct inode *ip) { int dev = ip->minor; if(dev < 0 || dev >= NINPUTDEV) return; if(idev[dev].opens > 0) idev[dev].opens--; if(idev[dev].grabbed){ idev[dev].grabbed = 0; cprintf("input: event%d grab released\n", dev); } } // Copy `n` bytes of `src` out for a variable-length query: at most the // caller's buffer, and the return value is how much went, as Linux's is. static int evioc_out(addr_t arg, uint cap, const void *src, uint n) { if(n > cap) n = cap; void *dst = user_ptr(arg, n ? n : 1); if(!dst) return -EFAULT; memmove(dst, src, n); return (int)n; } static int evioc_str(addr_t arg, uint cap, const char *s) { return evioc_out(arg, cap, s, strlen(s) + 1); } // ioctl on /dev/input/eventN. See the EVIOC* block in include/dev/input.h. int input_ioctl(struct inode *ip, int request, addr_t arg) { int dev = ip->minor; uint r = (uint)request; if(dev < 0 || dev >= NINPUTDEV) return -ENODEV; struct input_dev *d = &idev[dev]; switch(r){ case EVIOCGRAB: // Linux passes the flag *by value* in the argument, not by pointer. return input_grab(dev, (int)arg); case EVIOCREVOKE: // A session manager taking the device back from a client on a VT // switch. With one reader per device, dropping the grab is the part // that has an effect. return input_grab(dev, 0); case EVIOCGVERSION: { int *v = user_ptr(arg, sizeof *v); if(!v) return -EFAULT; *v = 0x010001; return 0; } case EVIOCGID: { struct input_id *id = user_ptr(arg, sizeof *id); if(!id) return -EFAULT; id->bustype = BUS_I8042; id->vendor = 0x0001; id->product = dev == INPUT_KBD ? 0x0001 : 0x0002; id->version = 0x0100; return 0; } case EVIOCGREP: { uint *rep = user_ptr(arg, 2 * sizeof *rep); if(!rep) return -EFAULT; rep[0] = 250; // delay, ms rep[1] = 33; // period, ms return 0; } case EVIOCSREP: case EVIOCSCLOCKID: // Repeat is the reader's business here -- the kernel queues no repeat // events -- and the clock is the only one there is. Accepted, so that a // program setting either at startup carries on. return 0; } if(EVIOC_TYPE(r) != 'E' || EVIOC_DIR(r) != 2) return -ENOTTY; uint nr = EVIOC_NR(r), cap = EVIOC_SIZE(r); int got; if(nr >= EVIOCNR_GABS && nr < EVIOCNR_GABS + ABS_MAX + 1){ struct input_absinfo *a = user_ptr(arg, sizeof *a); uint axis = nr - EVIOCNR_GABS; if(!a) return -EFAULT; memset(a, 0, sizeof *a); // Absolute positions arrive already in pixels; see mouse_set_abs(). if(axis < 2){ a->value = d->abs[axis]; a->maximum = (axis == 0 ? (int)gfx_width() : (int)gfx_height()) - 1; if(a->maximum < 1) a->maximum = axis == 0 ? 799 : 599; } return 0; } acquire(&d->lock); if(nr >= EVIOCNR_GBIT && nr <= EVIOCNR_GBIT + EV_MAX){ uint type = nr - EVIOCNR_GBIT; // EVIOCGBIT(0) is the bitmap of event types, which is one byte's worth // of interest in a field Linux sizes for EV_MAX. uint len = type == 0 ? (EV_MAX + 1) / 8 : type == EV_KEY ? (KEY_MAX + 1) / 8 : type == EV_REL ? (REL_MAX + 1) / 8 : type == EV_ABS ? (ABS_MAX + 1) / 8 : 8; uchar buf[(KEY_MAX + 1) / 8]; memmove(buf, d->caps[type], len); release(&d->lock); return evioc_out(arg, cap, buf, len); } if(nr == EVIOCNR_GKEY){ uchar buf[(KEY_MAX + 1) / 8]; memmove(buf, d->keys, sizeof buf); release(&d->lock); return evioc_out(arg, cap, buf, sizeof buf); } release(&d->lock); switch(nr){ case EVIOCNR_GNAME: return evioc_str(arg, cap, dev == INPUT_KBD ? "SchOS keyboard" : "SchOS pointer"); case EVIOCNR_GPHYS: return evioc_str(arg, cap, dev == INPUT_KBD ? "isa0060/serio0/input0" : "isa0060/serio1/input0"); case EVIOCNR_GUNIQ: return evioc_str(arg, cap, ""); case EVIOCNR_GPROP: { uchar prop[4] = { 0 }; if(dev == INPUT_MOUSE) prop[0] = 1 << INPUT_PROP_POINTER; return evioc_out(arg, cap, prop, sizeof prop); } case EVIOCNR_GLED: case EVIOCNR_GSND: case EVIOCNR_GSW: { // None of these exist here: all off. uchar zero[8] = { 0 }; got = evioc_out(arg, cap, zero, sizeof zero); return got; } } return -ENOTTY; } // A read returns whole events only. Handing back a partial struct would // desynchronise the reader permanently -- every later event would be split // across two reads and reassembled wrong. int inputread(struct inode *ip, uint64 off, char *dst, int n) { struct input_dev *d; int got = 0; int dev = ip->minor; if(dev < 0 || dev >= NINPUTDEV) return -ENODEV; if(n < (int)sizeof(struct input_event)) return -EINVAL; d = &idev[dev]; acquire(&d->lock); while(d->r == d->w){ if(myproc()->killed){ release(&d->lock); return -EINTR; } sleep(d, &d->lock); } while(d->r != d->w && got + (int)sizeof(struct input_event) <= n){ memmove(dst + got, &d->ev[d->r % NEVENT], sizeof(struct input_event)); d->r++; got += sizeof(struct input_event); } release(&d->lock); return got; } // evdev accepts writes to set keyboard LEDs. There are no LEDs to set here, // and a program that writes one should not see an error for it. int inputwrite(struct inode *ip, uint64 off, char *src, int n) { return n; } // --------------------------------------------------------------------------- // Producers // --------------------------------------------------------------------------- // AT scancode set 1, E0-prefixed. The unprefixed bytes need no table at all: // Linux's keycodes were numbered from this set and still match it below 0x54. // These are the ones that do not. static const struct { uint8 sc; uint8 key; } e0map[] = { {0x1C, 96}, // KP_ENTER {0x1D, KEY_RIGHTCTRL}, {0x35, 98}, // KP_SLASH {0x38, KEY_RIGHTALT}, {0x47, KEY_HOME}, {0x48, KEY_UP}, {0x49, KEY_PAGEUP}, {0x4B, KEY_LEFT}, {0x4D, KEY_RIGHT}, {0x4F, KEY_END}, {0x50, KEY_DOWN}, {0x51, KEY_PAGEDOWN}, {0x52, KEY_INSERT}, {0x53, KEY_DELETE}, {0x5B, KEY_LEFTMETA}, {0x5C, KEY_RIGHTMETA}, }; // One byte from the PS/2 port, before it has been turned into a character. void input_ps2_scancode(int raw, int e0) { int code = raw & 0x7F; int down = (raw & 0x80) ? 0 : 1; int key = 0; unsigned i; if(e0){ for(i = 0; i < sizeof(e0map)/sizeof(e0map[0]); i++) if(e0map[i].sc == code){ key = e0map[i].key; break; } if(key == 0) return; // an E0 key nothing has a name for } else { if(code == 0 || code > 0x58) return; key = code; } input_report(INPUT_KBD, EV_KEY, key, down); input_sync(INPUT_KBD); } // USB HID usage -> Linux keycode. The mapping is not derivable: HID numbers // keys by position on a US layout starting at 'a', and the AT set numbers them // by the order IBM wired the matrix. The table is the same one Linux carries // for the same reason. static const uint8 hid_keycode[] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, }; // The eight modifier bits in a boot report, in bit order. static const uint8 hid_modkey[8] = { KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, }; int input_hid_keycode(int usage) { if(usage >= 0xE0 && usage <= 0xE7) return hid_modkey[usage - 0xE0]; if(usage < 0 || usage >= (int)sizeof(hid_keycode)) return 0; return hid_keycode[usage]; } void input_key(int usage, int down) { int key = input_hid_keycode(usage); if(key == 0) return; input_report(INPUT_KBD, EV_KEY, key, down); input_sync(INPUT_KBD); } // One mouse report: relative motion plus the current button state. `buttons` // is a bitmask in the order both PS/2 and HID boot protocol use -- left, // right, middle -- which is why neither caller has to reorder it. // An absolute pointer: where it is, not how far it moved. // // A relative device can never agree with the host's cursor inside a VM -- the // two accumulate independently and drift apart, which is exactly the symptom // usb-tablet exists to remove. Reported as EV_ABS so a reader can tell the // difference and treat the value as authoritative rather than as a delta. void input_mouse_abs(int x, int y, int buttons) { static int last; static int lastx = -1, lasty = -1; static const int btncode[3] = { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE }; int i; if(x != lastx){ input_report(INPUT_MOUSE, EV_ABS, ABS_X, x); lastx = x; } if(y != lasty){ input_report(INPUT_MOUSE, EV_ABS, ABS_Y, y); lasty = y; } for(i = 0; i < 3; i++){ int now = (buttons >> i) & 1, was = (last >> i) & 1; if(now != was) input_report(INPUT_MOUSE, EV_KEY, btncode[i], now); } last = buttons; input_report(INPUT_MOUSE, EV_SYN, SYN_REPORT, 0); } void input_mouse(int dx, int dy, int buttons) { static int last; static const int btncode[3] = { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE }; int i; if(dx) input_report(INPUT_MOUSE, EV_REL, REL_X, dx); if(dy) input_report(INPUT_MOUSE, EV_REL, REL_Y, dy); // Only transitions. A button held down for a second is one press event, not // a hundred -- a reader that has to filter repeats itself cannot tell a held // button from a very fast double-click. for(i = 0; i < 3; i++){ int now = (buttons >> i) & 1; if(now != ((last >> i) & 1)) input_report(INPUT_MOUSE, EV_KEY, btncode[i], now); } last = buttons; input_sync(INPUT_MOUSE); }