Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/evdev/cdev.c
Show First 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | evdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) | ||||
/* Initialize ring buffer */ | /* Initialize ring buffer */ | ||||
client->ec_buffer_size = buffer_size; | client->ec_buffer_size = buffer_size; | ||||
client->ec_buffer_head = 0; | client->ec_buffer_head = 0; | ||||
client->ec_buffer_tail = 0; | client->ec_buffer_tail = 0; | ||||
client->ec_buffer_ready = 0; | client->ec_buffer_ready = 0; | ||||
client->ec_evdev = evdev; | client->ec_evdev = evdev; | ||||
if (!bit_test(evdev->ev_flags, EVDEV_FLAG_LOCKLESS)) { | |||||
mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF); | mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF); | ||||
knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx); | knlist_init_mtx(&client->ec_selp.si_note, | ||||
&client->ec_buffer_mtx); | |||||
} else | |||||
knlist_init_mtx(&client->ec_selp.si_note, evdev->ev_lock); | |||||
/* Avoid race with evdev_unregister */ | /* Avoid race with evdev_unregister */ | ||||
EVDEV_LOCK(evdev); | EVDEV_LOCK(evdev); | ||||
if (dev->si_drv1 == NULL) | if (dev->si_drv1 == NULL) | ||||
ret = ENODEV; | ret = ENODEV; | ||||
else | else | ||||
ret = evdev_register_client(evdev, client); | ret = evdev_register_client(evdev, client); | ||||
Show All 25 Lines | evdev_dtor(void *data) | ||||
if (!client->ec_revoked) | if (!client->ec_revoked) | ||||
evdev_dispose_client(client->ec_evdev, client); | evdev_dispose_client(client->ec_evdev, client); | ||||
EVDEV_UNLOCK(client->ec_evdev); | EVDEV_UNLOCK(client->ec_evdev); | ||||
knlist_clear(&client->ec_selp.si_note, 0); | knlist_clear(&client->ec_selp.si_note, 0); | ||||
seldrain(&client->ec_selp); | seldrain(&client->ec_selp); | ||||
knlist_destroy(&client->ec_selp.si_note); | knlist_destroy(&client->ec_selp.si_note); | ||||
funsetown(&client->ec_sigio); | funsetown(&client->ec_sigio); | ||||
if (EVDEV_CLIENT_LOCKQ_EXISTS(client)) | |||||
mtx_destroy(&client->ec_buffer_mtx); | mtx_destroy(&client->ec_buffer_mtx); | ||||
free(client, M_EVDEV); | free(client, M_EVDEV); | ||||
} | } | ||||
static int | static int | ||||
evdev_read(struct cdev *dev, struct uio *uio, int ioflag) | evdev_read(struct cdev *dev, struct uio *uio, int ioflag) | ||||
{ | { | ||||
struct evdev_client *client; | struct evdev_client *client; | ||||
struct input_event event; | struct input_event event; | ||||
Show All 32 Lines | evdev_read(struct cdev *dev, struct uio *uio, int ioflag) | ||||
while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) { | while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) { | ||||
memcpy(&event, &client->ec_buffer[client->ec_buffer_head], | memcpy(&event, &client->ec_buffer[client->ec_buffer_head], | ||||
sizeof(struct input_event)); | sizeof(struct input_event)); | ||||
client->ec_buffer_head = | client->ec_buffer_head = | ||||
(client->ec_buffer_head + 1) % client->ec_buffer_size; | (client->ec_buffer_head + 1) % client->ec_buffer_size; | ||||
remaining--; | remaining--; | ||||
if (!EVDEV_CLIENT_LOCKQ_SLEEPABLE(client)) | |||||
EVDEV_CLIENT_UNLOCKQ(client); | EVDEV_CLIENT_UNLOCKQ(client); | ||||
ret = uiomove(&event, sizeof(struct input_event), uio); | ret = uiomove(&event, sizeof(struct input_event), uio); | ||||
if (!EVDEV_CLIENT_LOCKQ_SLEEPABLE(client)) | |||||
EVDEV_CLIENT_LOCKQ(client); | EVDEV_CLIENT_LOCKQ(client); | ||||
} | } | ||||
EVDEV_CLIENT_UNLOCKQ(client); | EVDEV_CLIENT_UNLOCKQ(client); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, | ||||
ret = devfs_get_cdevpriv((void **)&client); | ret = devfs_get_cdevpriv((void **)&client); | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
if (client->ec_revoked || evdev == NULL) | if (client->ec_revoked || evdev == NULL) | ||||
return (ENODEV); | return (ENODEV); | ||||
/* | |||||
* Fix evdev state corrupted with discarding of kdb events. | |||||
* EVIOCGKEY and EVIOCGLED ioctls can suffer from this. | |||||
*/ | |||||
if (evdev->ev_kdb_active) { | |||||
EVDEV_LOCK(evdev); | |||||
if (evdev->ev_kdb_active) { | |||||
evdev->ev_kdb_active = false; | |||||
evdev_restore_after_kdb(evdev); | |||||
} | |||||
EVDEV_UNLOCK(evdev); | |||||
} | |||||
/* file I/O ioctl handling */ | /* file I/O ioctl handling */ | ||||
switch (cmd) { | switch (cmd) { | ||||
case FIOSETOWN: | case FIOSETOWN: | ||||
return (fsetown(*(int *)data, &client->ec_sigio)); | return (fsetown(*(int *)data, &client->ec_sigio)); | ||||
case FIOGETOWN: | case FIOGETOWN: | ||||
*(int *)data = fgetown(&client->ec_sigio); | *(int *)data = fgetown(&client->ec_sigio); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 455 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
evdev_client_filter_queue(struct evdev_client *client, uint16_t type) | evdev_client_filter_queue(struct evdev_client *client, uint16_t type) | ||||
{ | { | ||||
struct input_event *event; | struct input_event *event; | ||||
size_t head, tail, count, i; | size_t head, tail, count, i; | ||||
bool last_was_syn = false; | bool last_was_syn = false; | ||||
if (EVDEV_CLIENT_LOCKQ_EXISTS(client)) | |||||
EVDEV_CLIENT_LOCKQ(client); | EVDEV_CLIENT_LOCKQ(client); | ||||
i = head = client->ec_buffer_head; | i = head = client->ec_buffer_head; | ||||
tail = client->ec_buffer_tail; | tail = client->ec_buffer_tail; | ||||
count = client->ec_buffer_size; | count = client->ec_buffer_size; | ||||
client->ec_buffer_ready = client->ec_buffer_tail; | client->ec_buffer_ready = client->ec_buffer_tail; | ||||
while (i != client->ec_buffer_tail) { | while (i != client->ec_buffer_tail) { | ||||
event = &client->ec_buffer[i]; | event = &client->ec_buffer[i]; | ||||
Show All 19 Lines | last_was_syn = (event->type == EV_SYN && | ||||
event->code == SYN_REPORT); | event->code == SYN_REPORT); | ||||
tail = (tail + 1) % count; | tail = (tail + 1) % count; | ||||
} | } | ||||
client->ec_buffer_head = i; | client->ec_buffer_head = i; | ||||
client->ec_buffer_tail = tail; | client->ec_buffer_tail = tail; | ||||
if (EVDEV_CLIENT_LOCKQ_EXISTS(client)) | |||||
EVDEV_CLIENT_UNLOCKQ(client); | EVDEV_CLIENT_UNLOCKQ(client); | ||||
} | } |