1305706Sgonzo/*- 2305706Sgonzo * Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org> 3324768Swulf * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org> 4305706Sgonzo * All rights reserved. 5305706Sgonzo * 6305706Sgonzo * Redistribution and use in source and binary forms, with or without 7305706Sgonzo * modification, are permitted provided that the following conditions 8305706Sgonzo * are met: 9305706Sgonzo * 1. Redistributions of source code must retain the above copyright 10305706Sgonzo * notice, this list of conditions and the following disclaimer. 11305706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12305706Sgonzo * notice, this list of conditions and the following disclaimer in the 13305706Sgonzo * documentation and/or other materials provided with the distribution. 14305706Sgonzo * 15305706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16305706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17305706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18305706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19305706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20305706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21305706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22305706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23305706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24305706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25305706Sgonzo * SUCH DAMAGE. 26305706Sgonzo * 27305706Sgonzo * $FreeBSD: stable/11/sys/dev/evdev/cdev.c 359907 2020-04-13 22:21:01Z wulf $ 28305706Sgonzo */ 29305706Sgonzo 30305706Sgonzo#include "opt_evdev.h" 31305706Sgonzo 32324768Swulf#include <sys/param.h> 33305706Sgonzo#include <sys/bitstring.h> 34305706Sgonzo#include <sys/conf.h> 35305706Sgonzo#include <sys/filio.h> 36305706Sgonzo#include <sys/fcntl.h> 37324768Swulf#include <sys/kernel.h> 38324768Swulf#include <sys/malloc.h> 39324768Swulf#include <sys/poll.h> 40324768Swulf#include <sys/proc.h> 41305706Sgonzo#include <sys/selinfo.h> 42324768Swulf#include <sys/systm.h> 43305706Sgonzo#include <sys/time.h> 44324768Swulf#include <sys/uio.h> 45305706Sgonzo 46305706Sgonzo#include <dev/evdev/evdev.h> 47305706Sgonzo#include <dev/evdev/evdev_private.h> 48324768Swulf#include <dev/evdev/input.h> 49305706Sgonzo 50359907Swulf#ifdef COMPAT_FREEBSD32 51359907Swulf#include <sys/mount.h> 52359907Swulf#include <sys/sysent.h> 53359907Swulf#include <compat/freebsd32/freebsd32.h> 54359907Swulfstruct input_event32 { 55359907Swulf struct timeval32 time; 56359907Swulf uint16_t type; 57359907Swulf uint16_t code; 58359907Swulf int32_t value; 59359907Swulf}; 60359907Swulf#endif 61359907Swulf 62305706Sgonzo#ifdef EVDEV_DEBUG 63307760Sgonzo#define debugf(client, fmt, args...) printf("evdev cdev: "fmt"\n", ##args) 64305706Sgonzo#else 65305706Sgonzo#define debugf(client, fmt, args...) 66305706Sgonzo#endif 67305706Sgonzo 68305706Sgonzo#define DEF_RING_REPORTS 8 69305706Sgonzo 70305706Sgonzostatic d_open_t evdev_open; 71305706Sgonzostatic d_read_t evdev_read; 72305706Sgonzostatic d_write_t evdev_write; 73305706Sgonzostatic d_ioctl_t evdev_ioctl; 74305706Sgonzostatic d_poll_t evdev_poll; 75305706Sgonzostatic d_kqfilter_t evdev_kqfilter; 76305706Sgonzo 77305706Sgonzostatic int evdev_kqread(struct knote *kn, long hint); 78305706Sgonzostatic void evdev_kqdetach(struct knote *kn); 79305706Sgonzostatic void evdev_dtor(void *); 80305706Sgonzostatic int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t); 81305706Sgonzostatic void evdev_client_filter_queue(struct evdev_client *, uint16_t); 82305706Sgonzo 83305706Sgonzostatic struct cdevsw evdev_cdevsw = { 84305706Sgonzo .d_version = D_VERSION, 85305706Sgonzo .d_open = evdev_open, 86305706Sgonzo .d_read = evdev_read, 87305706Sgonzo .d_write = evdev_write, 88305706Sgonzo .d_ioctl = evdev_ioctl, 89305706Sgonzo .d_poll = evdev_poll, 90305706Sgonzo .d_kqfilter = evdev_kqfilter, 91305706Sgonzo .d_name = "evdev", 92305706Sgonzo}; 93305706Sgonzo 94305706Sgonzostatic struct filterops evdev_cdev_filterops = { 95305706Sgonzo .f_isfd = 1, 96305706Sgonzo .f_attach = NULL, 97305706Sgonzo .f_detach = evdev_kqdetach, 98305706Sgonzo .f_event = evdev_kqread, 99305706Sgonzo}; 100305706Sgonzo 101305706Sgonzostatic int 102305706Sgonzoevdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 103305706Sgonzo{ 104305706Sgonzo struct evdev_dev *evdev = dev->si_drv1; 105305706Sgonzo struct evdev_client *client; 106305706Sgonzo size_t buffer_size; 107305706Sgonzo int ret; 108305706Sgonzo 109305706Sgonzo if (evdev == NULL) 110305706Sgonzo return (ENODEV); 111305706Sgonzo 112305706Sgonzo /* Initialize client structure */ 113305706Sgonzo buffer_size = evdev->ev_report_size * DEF_RING_REPORTS; 114305706Sgonzo client = malloc(offsetof(struct evdev_client, ec_buffer) + 115305706Sgonzo sizeof(struct input_event) * buffer_size, 116305706Sgonzo M_EVDEV, M_WAITOK | M_ZERO); 117305706Sgonzo 118305706Sgonzo /* Initialize ring buffer */ 119305706Sgonzo client->ec_buffer_size = buffer_size; 120305706Sgonzo client->ec_buffer_head = 0; 121305706Sgonzo client->ec_buffer_tail = 0; 122305706Sgonzo client->ec_buffer_ready = 0; 123305706Sgonzo 124305706Sgonzo client->ec_evdev = evdev; 125305706Sgonzo mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF); 126305706Sgonzo knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx); 127305706Sgonzo 128305706Sgonzo /* Avoid race with evdev_unregister */ 129305706Sgonzo EVDEV_LOCK(evdev); 130305706Sgonzo if (dev->si_drv1 == NULL) 131305706Sgonzo ret = ENODEV; 132305706Sgonzo else 133305706Sgonzo ret = evdev_register_client(evdev, client); 134305706Sgonzo 135305706Sgonzo if (ret != 0) 136305706Sgonzo evdev_revoke_client(client); 137305706Sgonzo /* 138305706Sgonzo * Unlock evdev here because non-sleepable lock held 139305706Sgonzo * while calling devfs_set_cdevpriv upsets WITNESS 140305706Sgonzo */ 141305706Sgonzo EVDEV_UNLOCK(evdev); 142305706Sgonzo 143305706Sgonzo if (!ret) 144305706Sgonzo ret = devfs_set_cdevpriv(client, evdev_dtor); 145305706Sgonzo 146305706Sgonzo if (ret != 0) { 147305706Sgonzo debugf(client, "cannot register evdev client"); 148305706Sgonzo evdev_dtor(client); 149305706Sgonzo } 150305706Sgonzo 151305706Sgonzo return (ret); 152305706Sgonzo} 153305706Sgonzo 154305706Sgonzostatic void 155305706Sgonzoevdev_dtor(void *data) 156305706Sgonzo{ 157305706Sgonzo struct evdev_client *client = (struct evdev_client *)data; 158305706Sgonzo 159305706Sgonzo EVDEV_LOCK(client->ec_evdev); 160305706Sgonzo if (!client->ec_revoked) 161305706Sgonzo evdev_dispose_client(client->ec_evdev, client); 162305706Sgonzo EVDEV_UNLOCK(client->ec_evdev); 163305706Sgonzo 164305706Sgonzo knlist_clear(&client->ec_selp.si_note, 0); 165305706Sgonzo seldrain(&client->ec_selp); 166305706Sgonzo knlist_destroy(&client->ec_selp.si_note); 167305706Sgonzo funsetown(&client->ec_sigio); 168305706Sgonzo mtx_destroy(&client->ec_buffer_mtx); 169305706Sgonzo free(client, M_EVDEV); 170305706Sgonzo} 171305706Sgonzo 172305706Sgonzostatic int 173305706Sgonzoevdev_read(struct cdev *dev, struct uio *uio, int ioflag) 174305706Sgonzo{ 175305706Sgonzo struct evdev_client *client; 176359907Swulf union { 177359907Swulf struct input_event t; 178359907Swulf#ifdef COMPAT_FREEBSD32 179359907Swulf struct input_event32 t32; 180359907Swulf#endif 181359907Swulf } event; 182359907Swulf struct input_event *head; 183359907Swulf size_t evsize; 184305706Sgonzo int ret = 0; 185305706Sgonzo int remaining; 186305706Sgonzo 187305706Sgonzo ret = devfs_get_cdevpriv((void **)&client); 188305706Sgonzo if (ret != 0) 189305706Sgonzo return (ret); 190305706Sgonzo 191305706Sgonzo debugf(client, "read %zd bytes by thread %d", uio->uio_resid, 192305706Sgonzo uio->uio_td->td_tid); 193305706Sgonzo 194305706Sgonzo if (client->ec_revoked) 195305706Sgonzo return (ENODEV); 196305706Sgonzo 197359907Swulf#ifdef COMPAT_FREEBSD32 198359907Swulf if (SV_CURPROC_FLAG(SV_ILP32)) 199359907Swulf evsize = sizeof(struct input_event32); 200359907Swulf else 201359907Swulf#endif 202359907Swulf evsize = sizeof(struct input_event); 203359907Swulf 204305706Sgonzo /* Zero-sized reads are allowed for error checking */ 205359907Swulf if (uio->uio_resid != 0 && uio->uio_resid < evsize) 206305706Sgonzo return (EINVAL); 207305706Sgonzo 208359907Swulf remaining = uio->uio_resid / evsize; 209305706Sgonzo 210305706Sgonzo EVDEV_CLIENT_LOCKQ(client); 211305706Sgonzo 212305706Sgonzo if (EVDEV_CLIENT_EMPTYQ(client)) { 213305706Sgonzo if (ioflag & O_NONBLOCK) 214305706Sgonzo ret = EWOULDBLOCK; 215305706Sgonzo else { 216305706Sgonzo if (remaining != 0) { 217305706Sgonzo client->ec_blocked = true; 218305706Sgonzo ret = mtx_sleep(client, &client->ec_buffer_mtx, 219305706Sgonzo PCATCH, "evread", 0); 220359907Swulf if (ret == 0 && client->ec_revoked) 221359907Swulf ret = ENODEV; 222305706Sgonzo } 223305706Sgonzo } 224305706Sgonzo } 225305706Sgonzo 226305706Sgonzo while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) { 227359907Swulf head = client->ec_buffer + client->ec_buffer_head; 228359907Swulf#ifdef COMPAT_FREEBSD32 229359907Swulf if (SV_CURPROC_FLAG(SV_ILP32)) { 230359907Swulf bzero(&event.t32, sizeof(struct input_event32)); 231359907Swulf TV_CP(*head, event.t32, time); 232359907Swulf CP(*head, event.t32, type); 233359907Swulf CP(*head, event.t32, code); 234359907Swulf CP(*head, event.t32, value); 235359907Swulf } else 236359907Swulf#endif 237359907Swulf bcopy(head, &event.t, evsize); 238359907Swulf 239305706Sgonzo client->ec_buffer_head = 240305706Sgonzo (client->ec_buffer_head + 1) % client->ec_buffer_size; 241305706Sgonzo remaining--; 242305706Sgonzo 243305706Sgonzo EVDEV_CLIENT_UNLOCKQ(client); 244359907Swulf ret = uiomove(&event, evsize, uio); 245305706Sgonzo EVDEV_CLIENT_LOCKQ(client); 246305706Sgonzo } 247305706Sgonzo 248305706Sgonzo EVDEV_CLIENT_UNLOCKQ(client); 249305706Sgonzo 250305706Sgonzo return (ret); 251305706Sgonzo} 252305706Sgonzo 253305706Sgonzostatic int 254305706Sgonzoevdev_write(struct cdev *dev, struct uio *uio, int ioflag) 255305706Sgonzo{ 256305706Sgonzo struct evdev_dev *evdev = dev->si_drv1; 257305706Sgonzo struct evdev_client *client; 258359907Swulf union { 259359907Swulf struct input_event t; 260359907Swulf#ifdef COMPAT_FREEBSD32 261359907Swulf struct input_event32 t32; 262359907Swulf#endif 263359907Swulf } event; 264359907Swulf size_t evsize; 265305706Sgonzo int ret = 0; 266305706Sgonzo 267305706Sgonzo ret = devfs_get_cdevpriv((void **)&client); 268305706Sgonzo if (ret != 0) 269305706Sgonzo return (ret); 270305706Sgonzo 271305706Sgonzo debugf(client, "write %zd bytes by thread %d", uio->uio_resid, 272305706Sgonzo uio->uio_td->td_tid); 273305706Sgonzo 274305706Sgonzo if (client->ec_revoked || evdev == NULL) 275305706Sgonzo return (ENODEV); 276305706Sgonzo 277359907Swulf#ifdef COMPAT_FREEBSD32 278359907Swulf if (SV_CURPROC_FLAG(SV_ILP32)) 279359907Swulf evsize = sizeof(struct input_event32); 280359907Swulf else 281359907Swulf#endif 282359907Swulf evsize = sizeof(struct input_event); 283359907Swulf 284359907Swulf if (uio->uio_resid % evsize != 0) { 285305706Sgonzo debugf(client, "write size not multiple of input_event size"); 286305706Sgonzo return (EINVAL); 287305706Sgonzo } 288305706Sgonzo 289305706Sgonzo while (uio->uio_resid > 0 && ret == 0) { 290359907Swulf ret = uiomove(&event, evsize, uio); 291359907Swulf if (ret == 0) { 292359907Swulf#ifdef COMPAT_FREEBSD32 293359907Swulf if (SV_CURPROC_FLAG(SV_ILP32)) 294359907Swulf ret = evdev_inject_event(evdev, event.t32.type, 295359907Swulf event.t32.code, event.t32.value); 296359907Swulf else 297359907Swulf#endif 298359907Swulf ret = evdev_inject_event(evdev, event.t.type, 299359907Swulf event.t.code, event.t.value); 300359907Swulf } 301305706Sgonzo } 302305706Sgonzo 303305706Sgonzo return (ret); 304305706Sgonzo} 305305706Sgonzo 306305706Sgonzostatic int 307305706Sgonzoevdev_poll(struct cdev *dev, int events, struct thread *td) 308305706Sgonzo{ 309305706Sgonzo struct evdev_client *client; 310305706Sgonzo int ret; 311305706Sgonzo int revents = 0; 312305706Sgonzo 313305706Sgonzo ret = devfs_get_cdevpriv((void **)&client); 314305706Sgonzo if (ret != 0) 315305706Sgonzo return (POLLNVAL); 316305706Sgonzo 317305706Sgonzo debugf(client, "poll by thread %d", td->td_tid); 318305706Sgonzo 319305706Sgonzo if (client->ec_revoked) 320305706Sgonzo return (POLLHUP); 321305706Sgonzo 322305706Sgonzo if (events & (POLLIN | POLLRDNORM)) { 323305706Sgonzo EVDEV_CLIENT_LOCKQ(client); 324305706Sgonzo if (!EVDEV_CLIENT_EMPTYQ(client)) 325305706Sgonzo revents = events & (POLLIN | POLLRDNORM); 326305706Sgonzo else { 327305706Sgonzo client->ec_selected = true; 328305706Sgonzo selrecord(td, &client->ec_selp); 329305706Sgonzo } 330305706Sgonzo EVDEV_CLIENT_UNLOCKQ(client); 331305706Sgonzo } 332305706Sgonzo 333305706Sgonzo return (revents); 334305706Sgonzo} 335305706Sgonzo 336305706Sgonzostatic int 337305706Sgonzoevdev_kqfilter(struct cdev *dev, struct knote *kn) 338305706Sgonzo{ 339305706Sgonzo struct evdev_client *client; 340305706Sgonzo int ret; 341305706Sgonzo 342305706Sgonzo ret = devfs_get_cdevpriv((void **)&client); 343305706Sgonzo if (ret != 0) 344305706Sgonzo return (ret); 345305706Sgonzo 346305706Sgonzo if (client->ec_revoked) 347305706Sgonzo return (ENODEV); 348305706Sgonzo 349305706Sgonzo switch(kn->kn_filter) { 350305706Sgonzo case EVFILT_READ: 351305706Sgonzo kn->kn_fop = &evdev_cdev_filterops; 352305706Sgonzo break; 353305706Sgonzo default: 354305706Sgonzo return(EINVAL); 355305706Sgonzo } 356305706Sgonzo kn->kn_hook = (caddr_t)client; 357305706Sgonzo 358305706Sgonzo knlist_add(&client->ec_selp.si_note, kn, 0); 359305706Sgonzo return (0); 360305706Sgonzo} 361305706Sgonzo 362305706Sgonzostatic int 363305706Sgonzoevdev_kqread(struct knote *kn, long hint) 364305706Sgonzo{ 365305706Sgonzo struct evdev_client *client; 366305706Sgonzo int ret; 367305706Sgonzo 368305706Sgonzo client = (struct evdev_client *)kn->kn_hook; 369305706Sgonzo 370305706Sgonzo EVDEV_CLIENT_LOCKQ_ASSERT(client); 371305706Sgonzo 372305706Sgonzo if (client->ec_revoked) { 373305706Sgonzo kn->kn_flags |= EV_EOF; 374305706Sgonzo ret = 1; 375305706Sgonzo } else { 376305706Sgonzo kn->kn_data = EVDEV_CLIENT_SIZEQ(client) * 377305706Sgonzo sizeof(struct input_event); 378305706Sgonzo ret = !EVDEV_CLIENT_EMPTYQ(client); 379305706Sgonzo } 380305706Sgonzo return (ret); 381305706Sgonzo} 382305706Sgonzo 383305706Sgonzostatic void 384305706Sgonzoevdev_kqdetach(struct knote *kn) 385305706Sgonzo{ 386305706Sgonzo struct evdev_client *client; 387305706Sgonzo 388305706Sgonzo client = (struct evdev_client *)kn->kn_hook; 389305706Sgonzo knlist_remove(&client->ec_selp.si_note, kn, 0); 390305706Sgonzo} 391305706Sgonzo 392305706Sgonzostatic int 393305706Sgonzoevdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 394305706Sgonzo struct thread *td) 395305706Sgonzo{ 396305706Sgonzo struct evdev_dev *evdev = dev->si_drv1; 397305706Sgonzo struct evdev_client *client; 398305706Sgonzo struct input_keymap_entry *ke; 399305706Sgonzo int ret, len, limit, type_num; 400305706Sgonzo uint32_t code; 401305706Sgonzo size_t nvalues; 402305706Sgonzo 403305706Sgonzo ret = devfs_get_cdevpriv((void **)&client); 404305706Sgonzo if (ret != 0) 405305706Sgonzo return (ret); 406305706Sgonzo 407305706Sgonzo if (client->ec_revoked || evdev == NULL) 408305706Sgonzo return (ENODEV); 409305706Sgonzo 410305706Sgonzo /* file I/O ioctl handling */ 411305706Sgonzo switch (cmd) { 412305706Sgonzo case FIOSETOWN: 413305706Sgonzo return (fsetown(*(int *)data, &client->ec_sigio)); 414305706Sgonzo 415305706Sgonzo case FIOGETOWN: 416305706Sgonzo *(int *)data = fgetown(&client->ec_sigio); 417305706Sgonzo return (0); 418305706Sgonzo 419305706Sgonzo case FIONBIO: 420305706Sgonzo return (0); 421305706Sgonzo 422305706Sgonzo case FIOASYNC: 423305706Sgonzo if (*(int *)data) 424305706Sgonzo client->ec_async = true; 425305706Sgonzo else 426305706Sgonzo client->ec_async = false; 427305706Sgonzo 428305706Sgonzo return (0); 429305706Sgonzo 430305706Sgonzo case FIONREAD: 431305706Sgonzo EVDEV_CLIENT_LOCKQ(client); 432305706Sgonzo *(int *)data = 433305706Sgonzo EVDEV_CLIENT_SIZEQ(client) * sizeof(struct input_event); 434305706Sgonzo EVDEV_CLIENT_UNLOCKQ(client); 435305706Sgonzo return (0); 436305706Sgonzo } 437305706Sgonzo 438305706Sgonzo len = IOCPARM_LEN(cmd); 439305706Sgonzo debugf(client, "ioctl called: cmd=0x%08lx, data=%p", cmd, data); 440305706Sgonzo 441305706Sgonzo /* evdev fixed-length ioctls handling */ 442305706Sgonzo switch (cmd) { 443305706Sgonzo case EVIOCGVERSION: 444305706Sgonzo *(int *)data = EV_VERSION; 445305706Sgonzo return (0); 446305706Sgonzo 447305706Sgonzo case EVIOCGID: 448305706Sgonzo debugf(client, "EVIOCGID: bus=%d vendor=0x%04x product=0x%04x", 449305706Sgonzo evdev->ev_id.bustype, evdev->ev_id.vendor, 450305706Sgonzo evdev->ev_id.product); 451305706Sgonzo memcpy(data, &evdev->ev_id, sizeof(struct input_id)); 452305706Sgonzo return (0); 453305706Sgonzo 454305706Sgonzo case EVIOCGREP: 455305706Sgonzo if (!evdev_event_supported(evdev, EV_REP)) 456305706Sgonzo return (ENOTSUP); 457305706Sgonzo 458305706Sgonzo memcpy(data, evdev->ev_rep, sizeof(evdev->ev_rep)); 459305706Sgonzo return (0); 460305706Sgonzo 461305706Sgonzo case EVIOCSREP: 462305706Sgonzo if (!evdev_event_supported(evdev, EV_REP)) 463305706Sgonzo return (ENOTSUP); 464305706Sgonzo 465305706Sgonzo evdev_inject_event(evdev, EV_REP, REP_DELAY, ((int *)data)[0]); 466305706Sgonzo evdev_inject_event(evdev, EV_REP, REP_PERIOD, 467305706Sgonzo ((int *)data)[1]); 468305706Sgonzo return (0); 469305706Sgonzo 470305706Sgonzo case EVIOCGKEYCODE: 471305706Sgonzo /* Fake unsupported ioctl */ 472305706Sgonzo return (0); 473305706Sgonzo 474305706Sgonzo case EVIOCGKEYCODE_V2: 475305706Sgonzo if (evdev->ev_methods == NULL || 476305706Sgonzo evdev->ev_methods->ev_get_keycode == NULL) 477305706Sgonzo return (ENOTSUP); 478305706Sgonzo 479305706Sgonzo ke = (struct input_keymap_entry *)data; 480305706Sgonzo evdev->ev_methods->ev_get_keycode(evdev, evdev->ev_softc, ke); 481305706Sgonzo return (0); 482305706Sgonzo 483305706Sgonzo case EVIOCSKEYCODE: 484305706Sgonzo /* Fake unsupported ioctl */ 485305706Sgonzo return (0); 486305706Sgonzo 487305706Sgonzo case EVIOCSKEYCODE_V2: 488305706Sgonzo if (evdev->ev_methods == NULL || 489305706Sgonzo evdev->ev_methods->ev_set_keycode == NULL) 490305706Sgonzo return (ENOTSUP); 491305706Sgonzo 492305706Sgonzo ke = (struct input_keymap_entry *)data; 493305706Sgonzo evdev->ev_methods->ev_set_keycode(evdev, evdev->ev_softc, ke); 494305706Sgonzo return (0); 495305706Sgonzo 496305706Sgonzo case EVIOCGABS(0) ... EVIOCGABS(ABS_MAX): 497305706Sgonzo if (evdev->ev_absinfo == NULL) 498305706Sgonzo return (EINVAL); 499305706Sgonzo 500305706Sgonzo memcpy(data, &evdev->ev_absinfo[cmd - EVIOCGABS(0)], 501305706Sgonzo sizeof(struct input_absinfo)); 502305706Sgonzo return (0); 503305706Sgonzo 504305706Sgonzo case EVIOCSABS(0) ... EVIOCSABS(ABS_MAX): 505305706Sgonzo if (evdev->ev_absinfo == NULL) 506305706Sgonzo return (EINVAL); 507305706Sgonzo 508305706Sgonzo code = cmd - EVIOCSABS(0); 509305706Sgonzo /* mt-slot number can not be changed */ 510305706Sgonzo if (code == ABS_MT_SLOT) 511305706Sgonzo return (EINVAL); 512305706Sgonzo 513305706Sgonzo EVDEV_LOCK(evdev); 514305706Sgonzo evdev_set_absinfo(evdev, code, (struct input_absinfo *)data); 515305706Sgonzo EVDEV_UNLOCK(evdev); 516305706Sgonzo return (0); 517305706Sgonzo 518305706Sgonzo case EVIOCSFF: 519305706Sgonzo case EVIOCRMFF: 520305706Sgonzo case EVIOCGEFFECTS: 521305706Sgonzo /* Fake unsupported ioctls */ 522305706Sgonzo return (0); 523305706Sgonzo 524305706Sgonzo case EVIOCGRAB: 525305706Sgonzo EVDEV_LOCK(evdev); 526305706Sgonzo if (*(int *)data) 527305706Sgonzo ret = evdev_grab_client(evdev, client); 528305706Sgonzo else 529305706Sgonzo ret = evdev_release_client(evdev, client); 530305706Sgonzo EVDEV_UNLOCK(evdev); 531305706Sgonzo return (ret); 532305706Sgonzo 533305706Sgonzo case EVIOCREVOKE: 534305706Sgonzo if (*(int *)data != 0) 535305706Sgonzo return (EINVAL); 536305706Sgonzo 537305706Sgonzo EVDEV_LOCK(evdev); 538305706Sgonzo if (dev->si_drv1 != NULL && !client->ec_revoked) { 539305706Sgonzo evdev_dispose_client(evdev, client); 540305706Sgonzo evdev_revoke_client(client); 541305706Sgonzo } 542305706Sgonzo EVDEV_UNLOCK(evdev); 543305706Sgonzo return (0); 544305706Sgonzo 545305706Sgonzo case EVIOCSCLOCKID: 546305706Sgonzo switch (*(int *)data) { 547305706Sgonzo case CLOCK_REALTIME: 548305706Sgonzo client->ec_clock_id = EV_CLOCK_REALTIME; 549305706Sgonzo return (0); 550305706Sgonzo case CLOCK_MONOTONIC: 551305706Sgonzo client->ec_clock_id = EV_CLOCK_MONOTONIC; 552305706Sgonzo return (0); 553305706Sgonzo default: 554305706Sgonzo return (EINVAL); 555305706Sgonzo } 556305706Sgonzo } 557305706Sgonzo 558305706Sgonzo /* evdev variable-length ioctls handling */ 559305706Sgonzo switch (IOCBASECMD(cmd)) { 560305706Sgonzo case EVIOCGNAME(0): 561305706Sgonzo strlcpy(data, evdev->ev_name, len); 562305706Sgonzo return (0); 563305706Sgonzo 564305706Sgonzo case EVIOCGPHYS(0): 565305706Sgonzo if (evdev->ev_shortname[0] == 0) 566305706Sgonzo return (ENOENT); 567305706Sgonzo 568305706Sgonzo strlcpy(data, evdev->ev_shortname, len); 569305706Sgonzo return (0); 570305706Sgonzo 571305706Sgonzo case EVIOCGUNIQ(0): 572305706Sgonzo if (evdev->ev_serial[0] == 0) 573305706Sgonzo return (ENOENT); 574305706Sgonzo 575305706Sgonzo strlcpy(data, evdev->ev_serial, len); 576305706Sgonzo return (0); 577305706Sgonzo 578305706Sgonzo case EVIOCGPROP(0): 579305706Sgonzo limit = MIN(len, bitstr_size(INPUT_PROP_CNT)); 580305706Sgonzo memcpy(data, evdev->ev_prop_flags, limit); 581305706Sgonzo return (0); 582305706Sgonzo 583305706Sgonzo case EVIOCGMTSLOTS(0): 584305706Sgonzo if (evdev->ev_mt == NULL) 585305706Sgonzo return (EINVAL); 586305706Sgonzo if (len < sizeof(uint32_t)) 587305706Sgonzo return (EINVAL); 588305706Sgonzo code = *(uint32_t *)data; 589305706Sgonzo if (!ABS_IS_MT(code)) 590305706Sgonzo return (EINVAL); 591305706Sgonzo 592305706Sgonzo nvalues = 593305706Sgonzo MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1); 594305706Sgonzo for (int i = 0; i < nvalues; i++) 595305706Sgonzo ((int32_t *)data)[i + 1] = 596305706Sgonzo evdev_get_mt_value(evdev, i, code); 597305706Sgonzo return (0); 598305706Sgonzo 599305706Sgonzo case EVIOCGKEY(0): 600305706Sgonzo limit = MIN(len, bitstr_size(KEY_CNT)); 601305706Sgonzo EVDEV_LOCK(evdev); 602305706Sgonzo evdev_client_filter_queue(client, EV_KEY); 603305706Sgonzo memcpy(data, evdev->ev_key_states, limit); 604305706Sgonzo EVDEV_UNLOCK(evdev); 605305706Sgonzo return (0); 606305706Sgonzo 607305706Sgonzo case EVIOCGLED(0): 608305706Sgonzo limit = MIN(len, bitstr_size(LED_CNT)); 609305706Sgonzo EVDEV_LOCK(evdev); 610305706Sgonzo evdev_client_filter_queue(client, EV_LED); 611305706Sgonzo memcpy(data, evdev->ev_led_states, limit); 612305706Sgonzo EVDEV_UNLOCK(evdev); 613305706Sgonzo return (0); 614305706Sgonzo 615305706Sgonzo case EVIOCGSND(0): 616305706Sgonzo limit = MIN(len, bitstr_size(SND_CNT)); 617305706Sgonzo EVDEV_LOCK(evdev); 618305706Sgonzo evdev_client_filter_queue(client, EV_SND); 619305706Sgonzo memcpy(data, evdev->ev_snd_states, limit); 620305706Sgonzo EVDEV_UNLOCK(evdev); 621305706Sgonzo return (0); 622305706Sgonzo 623305706Sgonzo case EVIOCGSW(0): 624305706Sgonzo limit = MIN(len, bitstr_size(SW_CNT)); 625305706Sgonzo EVDEV_LOCK(evdev); 626305706Sgonzo evdev_client_filter_queue(client, EV_SW); 627305706Sgonzo memcpy(data, evdev->ev_sw_states, limit); 628305706Sgonzo EVDEV_UNLOCK(evdev); 629305706Sgonzo return (0); 630305706Sgonzo 631305706Sgonzo case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0): 632305706Sgonzo type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0); 633305706Sgonzo debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num, 634305706Sgonzo data, len); 635305706Sgonzo return (evdev_ioctl_eviocgbit(evdev, type_num, len, data)); 636305706Sgonzo } 637305706Sgonzo 638305706Sgonzo return (EINVAL); 639305706Sgonzo} 640305706Sgonzo 641305706Sgonzostatic int 642305706Sgonzoevdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data) 643305706Sgonzo{ 644305706Sgonzo unsigned long *bitmap; 645305706Sgonzo int limit; 646305706Sgonzo 647305706Sgonzo switch (type) { 648305706Sgonzo case 0: 649305706Sgonzo bitmap = evdev->ev_type_flags; 650305706Sgonzo limit = EV_CNT; 651305706Sgonzo break; 652305706Sgonzo case EV_KEY: 653305706Sgonzo bitmap = evdev->ev_key_flags; 654305706Sgonzo limit = KEY_CNT; 655305706Sgonzo break; 656305706Sgonzo case EV_REL: 657305706Sgonzo bitmap = evdev->ev_rel_flags; 658305706Sgonzo limit = REL_CNT; 659305706Sgonzo break; 660305706Sgonzo case EV_ABS: 661305706Sgonzo bitmap = evdev->ev_abs_flags; 662305706Sgonzo limit = ABS_CNT; 663305706Sgonzo break; 664305706Sgonzo case EV_MSC: 665305706Sgonzo bitmap = evdev->ev_msc_flags; 666305706Sgonzo limit = MSC_CNT; 667305706Sgonzo break; 668305706Sgonzo case EV_LED: 669305706Sgonzo bitmap = evdev->ev_led_flags; 670305706Sgonzo limit = LED_CNT; 671305706Sgonzo break; 672305706Sgonzo case EV_SND: 673305706Sgonzo bitmap = evdev->ev_snd_flags; 674305706Sgonzo limit = SND_CNT; 675305706Sgonzo break; 676305706Sgonzo case EV_SW: 677305706Sgonzo bitmap = evdev->ev_sw_flags; 678305706Sgonzo limit = SW_CNT; 679305706Sgonzo break; 680305706Sgonzo case EV_FF: 681305706Sgonzo /* 682305706Sgonzo * We don't support EV_FF now, so let's 683305706Sgonzo * just fake it returning only zeros. 684305706Sgonzo */ 685305706Sgonzo bzero(data, len); 686305706Sgonzo return (0); 687305706Sgonzo default: 688305706Sgonzo return (ENOTTY); 689305706Sgonzo } 690305706Sgonzo 691305706Sgonzo /* 692305706Sgonzo * Clear ioctl data buffer in case it's bigger than 693305706Sgonzo * bitmap size 694305706Sgonzo */ 695305706Sgonzo bzero(data, len); 696305706Sgonzo 697305706Sgonzo limit = bitstr_size(limit); 698305706Sgonzo len = MIN(limit, len); 699305706Sgonzo memcpy(data, bitmap, len); 700305706Sgonzo return (0); 701305706Sgonzo} 702305706Sgonzo 703305706Sgonzovoid 704305706Sgonzoevdev_revoke_client(struct evdev_client *client) 705305706Sgonzo{ 706305706Sgonzo 707305706Sgonzo EVDEV_LOCK_ASSERT(client->ec_evdev); 708305706Sgonzo 709305706Sgonzo client->ec_revoked = true; 710305706Sgonzo} 711305706Sgonzo 712305706Sgonzovoid 713305706Sgonzoevdev_notify_event(struct evdev_client *client) 714305706Sgonzo{ 715305706Sgonzo 716305706Sgonzo EVDEV_CLIENT_LOCKQ_ASSERT(client); 717305706Sgonzo 718305706Sgonzo if (client->ec_blocked) { 719305706Sgonzo client->ec_blocked = false; 720305706Sgonzo wakeup(client); 721305706Sgonzo } 722305706Sgonzo if (client->ec_selected) { 723305706Sgonzo client->ec_selected = false; 724305706Sgonzo selwakeup(&client->ec_selp); 725305706Sgonzo } 726305706Sgonzo KNOTE_LOCKED(&client->ec_selp.si_note, 0); 727305706Sgonzo 728305706Sgonzo if (client->ec_async && client->ec_sigio != NULL) 729305706Sgonzo pgsigio(&client->ec_sigio, SIGIO, 0); 730305706Sgonzo} 731305706Sgonzo 732305706Sgonzoint 733305706Sgonzoevdev_cdev_create(struct evdev_dev *evdev) 734305706Sgonzo{ 735305706Sgonzo struct make_dev_args mda; 736305706Sgonzo int ret, unit = 0; 737305706Sgonzo 738305706Sgonzo make_dev_args_init(&mda); 739305706Sgonzo mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME; 740305706Sgonzo mda.mda_devsw = &evdev_cdevsw; 741305706Sgonzo mda.mda_uid = UID_ROOT; 742305706Sgonzo mda.mda_gid = GID_WHEEL; 743305706Sgonzo mda.mda_mode = 0600; 744305706Sgonzo mda.mda_si_drv1 = evdev; 745305706Sgonzo 746305706Sgonzo /* Try to coexist with cuse-backed input/event devices */ 747305706Sgonzo while ((ret = make_dev_s(&mda, &evdev->ev_cdev, "input/event%d", unit)) 748305706Sgonzo == EEXIST) 749305706Sgonzo unit++; 750305706Sgonzo 751305706Sgonzo if (ret == 0) 752305706Sgonzo evdev->ev_unit = unit; 753305706Sgonzo 754305706Sgonzo return (ret); 755305706Sgonzo} 756305706Sgonzo 757305706Sgonzoint 758305706Sgonzoevdev_cdev_destroy(struct evdev_dev *evdev) 759305706Sgonzo{ 760305706Sgonzo 761305706Sgonzo destroy_dev(evdev->ev_cdev); 762305706Sgonzo return (0); 763305706Sgonzo} 764305706Sgonzo 765305706Sgonzostatic void 766305706Sgonzoevdev_client_gettime(struct evdev_client *client, struct timeval *tv) 767305706Sgonzo{ 768305706Sgonzo 769305706Sgonzo switch (client->ec_clock_id) { 770305706Sgonzo case EV_CLOCK_BOOTTIME: 771305706Sgonzo /* 772305706Sgonzo * XXX: FreeBSD does not support true POSIX monotonic clock. 773305706Sgonzo * So aliase EV_CLOCK_BOOTTIME to EV_CLOCK_MONOTONIC. 774305706Sgonzo */ 775305706Sgonzo case EV_CLOCK_MONOTONIC: 776305706Sgonzo microuptime(tv); 777305706Sgonzo break; 778305706Sgonzo 779305706Sgonzo case EV_CLOCK_REALTIME: 780305706Sgonzo default: 781305706Sgonzo microtime(tv); 782305706Sgonzo break; 783305706Sgonzo } 784305706Sgonzo} 785305706Sgonzo 786305706Sgonzovoid 787305706Sgonzoevdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code, 788305706Sgonzo int32_t value) 789305706Sgonzo{ 790305706Sgonzo struct timeval time; 791305706Sgonzo size_t count, head, tail, ready; 792305706Sgonzo 793305706Sgonzo EVDEV_CLIENT_LOCKQ_ASSERT(client); 794305706Sgonzo head = client->ec_buffer_head; 795305706Sgonzo tail = client->ec_buffer_tail; 796305706Sgonzo ready = client->ec_buffer_ready; 797305706Sgonzo count = client->ec_buffer_size; 798305706Sgonzo 799305706Sgonzo /* If queue is full drop its content and place SYN_DROPPED event */ 800305706Sgonzo if ((tail + 1) % count == head) { 801305706Sgonzo debugf(client, "client %p: buffer overflow", client); 802305706Sgonzo 803305706Sgonzo head = (tail + count - 1) % count; 804305706Sgonzo client->ec_buffer[head] = (struct input_event) { 805305706Sgonzo .type = EV_SYN, 806305706Sgonzo .code = SYN_DROPPED, 807305706Sgonzo .value = 0 808305706Sgonzo }; 809305706Sgonzo /* 810305706Sgonzo * XXX: Here is a small race window from now till the end of 811305706Sgonzo * report. The queue is empty but client has been already 812305706Sgonzo * notified of data readyness. Can be fixed in two ways: 813305706Sgonzo * 1. Implement bulk insert so queue lock would not be dropped 814305706Sgonzo * till the SYN_REPORT event. 815305706Sgonzo * 2. Insert SYN_REPORT just now and skip remaining events 816305706Sgonzo */ 817305706Sgonzo client->ec_buffer_head = head; 818305706Sgonzo client->ec_buffer_ready = head; 819305706Sgonzo } 820305706Sgonzo 821305706Sgonzo client->ec_buffer[tail].type = type; 822305706Sgonzo client->ec_buffer[tail].code = code; 823305706Sgonzo client->ec_buffer[tail].value = value; 824305706Sgonzo client->ec_buffer_tail = (tail + 1) % count; 825305706Sgonzo 826305706Sgonzo /* Allow users to read events only after report has been completed */ 827305706Sgonzo if (type == EV_SYN && code == SYN_REPORT) { 828305706Sgonzo evdev_client_gettime(client, &time); 829305706Sgonzo for (; ready != client->ec_buffer_tail; 830305706Sgonzo ready = (ready + 1) % count) 831305706Sgonzo client->ec_buffer[ready].time = time; 832305706Sgonzo client->ec_buffer_ready = client->ec_buffer_tail; 833305706Sgonzo } 834305706Sgonzo} 835305706Sgonzo 836305706Sgonzovoid 837305706Sgonzoevdev_client_dumpqueue(struct evdev_client *client) 838305706Sgonzo{ 839305706Sgonzo struct input_event *event; 840305706Sgonzo size_t i, head, tail, ready, size; 841305706Sgonzo 842305706Sgonzo head = client->ec_buffer_head; 843305706Sgonzo tail = client->ec_buffer_tail; 844305706Sgonzo ready = client->ec_buffer_ready; 845305706Sgonzo size = client->ec_buffer_size; 846305706Sgonzo 847305706Sgonzo printf("evdev client: %p\n", client); 848305706Sgonzo printf("event queue: head=%zu ready=%zu tail=%zu size=%zu\n", 849305706Sgonzo head, ready, tail, size); 850305706Sgonzo 851305706Sgonzo printf("queue contents:\n"); 852305706Sgonzo 853305706Sgonzo for (i = 0; i < size; i++) { 854305706Sgonzo event = &client->ec_buffer[i]; 855305706Sgonzo printf("%zu: ", i); 856305706Sgonzo 857305706Sgonzo if (i < head || i > tail) 858305706Sgonzo printf("unused\n"); 859305706Sgonzo else 860305706Sgonzo printf("type=%d code=%d value=%d ", event->type, 861305706Sgonzo event->code, event->value); 862305706Sgonzo 863305706Sgonzo if (i == head) 864305706Sgonzo printf("<- head\n"); 865305706Sgonzo else if (i == tail) 866305706Sgonzo printf("<- tail\n"); 867305706Sgonzo else if (i == ready) 868305706Sgonzo printf("<- ready\n"); 869305706Sgonzo else 870305706Sgonzo printf("\n"); 871305706Sgonzo } 872305706Sgonzo} 873305706Sgonzo 874305706Sgonzostatic void 875305706Sgonzoevdev_client_filter_queue(struct evdev_client *client, uint16_t type) 876305706Sgonzo{ 877305706Sgonzo struct input_event *event; 878305706Sgonzo size_t head, tail, count, i; 879305706Sgonzo bool last_was_syn = false; 880305706Sgonzo 881305706Sgonzo EVDEV_CLIENT_LOCKQ(client); 882305706Sgonzo 883305706Sgonzo i = head = client->ec_buffer_head; 884305706Sgonzo tail = client->ec_buffer_tail; 885305706Sgonzo count = client->ec_buffer_size; 886305706Sgonzo client->ec_buffer_ready = client->ec_buffer_tail; 887305706Sgonzo 888305706Sgonzo while (i != client->ec_buffer_tail) { 889305706Sgonzo event = &client->ec_buffer[i]; 890305706Sgonzo i = (i + 1) % count; 891305706Sgonzo 892305706Sgonzo /* Skip event of given type */ 893305706Sgonzo if (event->type == type) 894305706Sgonzo continue; 895305706Sgonzo 896305706Sgonzo /* Remove empty SYN_REPORT events */ 897305706Sgonzo if (event->type == EV_SYN && event->code == SYN_REPORT) { 898305706Sgonzo if (last_was_syn) 899305706Sgonzo continue; 900305706Sgonzo else 901305706Sgonzo client->ec_buffer_ready = (tail + 1) % count; 902305706Sgonzo } 903305706Sgonzo 904305706Sgonzo /* Rewrite entry */ 905305706Sgonzo memcpy(&client->ec_buffer[tail], event, 906305706Sgonzo sizeof(struct input_event)); 907305706Sgonzo 908305706Sgonzo last_was_syn = (event->type == EV_SYN && 909305706Sgonzo event->code == SYN_REPORT); 910305706Sgonzo 911305706Sgonzo tail = (tail + 1) % count; 912305706Sgonzo } 913305706Sgonzo 914305706Sgonzo client->ec_buffer_head = i; 915305706Sgonzo client->ec_buffer_tail = tail; 916305706Sgonzo 917305706Sgonzo EVDEV_CLIENT_UNLOCKQ(client); 918305706Sgonzo} 919