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 21 Lines | |||||
{ | { | ||||
struct evdev_client *client = (struct evdev_client *)data; | struct evdev_client *client = (struct evdev_client *)data; | ||||
EVDEV_LOCK(client->ec_evdev); | EVDEV_LOCK(client->ec_evdev); | ||||
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); | /* | ||||
* Take kqueue lock explicitly. Otherwise lockless mode will trigger | |||||
* knlist_cleardel() 'Mutex owned' assertion as devfs can call | |||||
* evdev_dtor() with Giant lock already taken. | |||||
*/ | |||||
EVDEV_CLIENT_LOCKQ(client); | |||||
knlist_clear(&client->ec_selp.si_note, 1); | |||||
EVDEV_CLIENT_UNLOCKQ(client); | |||||
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 612 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); | ||||
} | } |