svn commit: r267369 - user/jceel/soc2014_evdev/head/sys/dev/evdev
Jakub Wojciech Klama
jceel at FreeBSD.org
Wed Jun 11 18:45:48 UTC 2014
Author: jceel
Date: Wed Jun 11 18:45:47 2014
New Revision: 267369
URL: http://svnweb.freebsd.org/changeset/base/267369
Log:
Add support for more ioctls and change behavior of EVIOCG(LED|KEY|SW|SND) so
when called, events of corresponding type are removed from the input queue.
Modified:
user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c
user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c
user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c Wed Jun 11 18:24:51 2014 (r267368)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c Wed Jun 11 18:45:47 2014 (r267369)
@@ -294,13 +294,18 @@ evdev_ioctl(struct cdev *dev, u_long cmd
{
struct evdev_cdev_softc *sc = dev->si_drv1;
struct evdev_dev *evdev = sc->ecs_evdev;
- //struct input_id id;
- int len, num, limit;
+ struct evdev_cdev_state *state;
+ struct input_keymap_entry *ke;
+ int ret, len, num, limit;
len = IOCPARM_LEN(cmd);
cmd = IOCBASECMD(cmd);
num = IOCNUM(cmd);
+ ret = devfs_get_cdevpriv((void **)&state);
+ if (ret != 0)
+ return (ret);
+
debugf("cdev: ioctl called: cmd=0x%08lx, data=%p", cmd, data);
switch (cmd) {
@@ -309,28 +314,38 @@ evdev_ioctl(struct cdev *dev, u_long cmd
break;
case EVIOCGID:
+ memcpy(data, &evdev->ev_id, sizeof(struct input_id));
break;
case EVIOCGREP:
- break;
+ return ENOTSUP;
case EVIOCSREP:
- break;
+ return ENOTSUP;
case EVIOCGKEYCODE:
- break;
+ return ENOTSUP;
case EVIOCGKEYCODE_V2:
+ if (evdev->ev_methods->ev_get_keycode == NULL)
+ return ENOTSUP;
+
+ ke = (struct keymap_entry *)data;
+ evdev->ev_methods->ev_get_keycode(evdev, evdev->ev_softc, ke);
break;
case EVIOCSKEYCODE:
- break;
+ return ENOTSUP;
case EVIOCSKEYCODE_V2:
+ if (evdev->ev_methods->ev_set_keycode == NULL)
+ return ENOTSUP;
+
+ ke = (struct keymap_entry *)data;
+ evdev->ev_methods->ev_set_keycode(evdev, evdev->ev_softc, ke);
break;
case EVIOCGNAME(0):
- debugf("EVIOCGNAME: data=%p, ev_name=%s, len=%d", data, evdev->ev_name, len);
strlcpy(data, evdev->ev_name, len);
break;
@@ -348,26 +363,40 @@ evdev_ioctl(struct cdev *dev, u_long cmd
break;
case EVIOCGKEY(0):
+ evdev_client_filter_queue(state->ecs_client, EV_KEY);
limit = MIN(len, howmany(KEY_CNT, 8));
memcpy(data, evdev->ev_key_states, limit);
break;
case EVIOCGLED(0):
+ evdev_client_filter_queue(state->ecs_client, EV_LED);
limit = MIN(len, howmany(LED_CNT, 8));
memcpy(data, evdev->ev_led_states, limit);
break;
case EVIOCGSND(0):
+ evdev_client_filter_queue(state->ecs_client, EV_SND);
limit = MIN(len, howmany(SND_CNT, 8));
memcpy(data, evdev->ev_snd_states, limit);
break;
case EVIOCGSW(0):
+ evdev_client_filter_queue(state->ecs_client, EV_SW);
limit = MIN(len, howmany(SW_CNT, 8));
memcpy(data, evdev->ev_sw_states, limit);
break;
+
+ case EVIOCGRAB:
+ if (data)
+ evdev_grab_client(state->ecs_client);
+ else
+ evdev_release_client(state->ecs_client);
+ break;
+
+ case EVIOCREVOKE:
+ break;
}
if (IOCGROUP(cmd) != 'E')
@@ -390,7 +419,9 @@ evdev_ioctl(struct cdev *dev, u_long cmd
/* Handle EVIOCSABS variants */
if (num >= IOCNUM(EVIOCSABS(0)) && num < IOCNUM(EVIOCSABS(ABS_CNT))) {
int index = num - IOCNUM(EVIOCSABS(0));
+ EVDEV_LOCK(evdev);
memcpy(&evdev->ev_absinfo[index], data, len);
+ EVDEV_UNLOCK(evdev);
}
return (0);
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jun 11 18:24:51 2014 (r267368)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jun 11 18:45:47 2014 (r267369)
@@ -44,6 +44,8 @@
#define debugf(fmt, args...)
#endif
+#define DEF_RING_SIZE 16
+
MALLOC_DEFINE(M_EVDEV, "evdev", "evdev memory");
static inline void changebit(uint32_t *array, int, int);
@@ -76,6 +78,7 @@ evdev_register(device_t dev, struct evde
/* Initialize internal structures */
evdev->ev_dev = dev;
+ mtx_init(&evdev->ev_mtx, "evmtx", "evdev", MTX_DEF);
strlcpy(evdev->ev_shortname, device_get_nameunit(dev), NAMELEN);
LIST_INIT(&evdev->ev_clients);
@@ -228,6 +231,19 @@ evdev_push_event(struct evdev_dev *evdev
}
int
+evdev_inject_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+ int32_t value)
+{
+
+ if (evdev->ev_methods->ev_event != NULL) {
+ evdev->ev_methods->ev_event(evdev, evdev->ev_softc, type,
+ code, value);
+ }
+
+ return (0);
+}
+
+int
evdev_sync(struct evdev_dev *evdev)
{
@@ -241,14 +257,16 @@ evdev_register_client(struct evdev_dev *
/* Initialize client structure */
client = malloc(sizeof(struct evdev_client), M_EVDEV, M_WAITOK | M_ZERO);
- mtx_init(&client->ec_buffer_mtx, "evmtx", "evdev", MTX_DEF);
+ mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF);
client->ec_evdev = evdev;
/* Initialize ring buffer */
- client->ec_buffer = malloc(sizeof(struct input_event) * 10, M_EVDEV, M_WAITOK | M_ZERO);
- client->ec_buffer_size = 10;
+ client->ec_buffer = malloc(sizeof(struct input_event) * DEF_RING_SIZE,
+ M_EVDEV, M_WAITOK | M_ZERO);
+ client->ec_buffer_size = DEF_RING_SIZE;
client->ec_buffer_head = 0;
client->ec_buffer_tail = 0;
+ client->ec_enabled = true;
debugf("adding new client for device %s", evdev->ev_shortname);
@@ -283,15 +301,68 @@ evdev_dispose_client(struct evdev_client
return (0);
}
+int
+evdev_grab_client(struct evdev_client *client)
+{
+ struct evdev_dev *evdev = client->ec_evdev;
+ struct evdev_client *iter;
+
+ EVDEV_LOCK(evdev);
+ if (evdev->ev_grabbed) {
+ EVDEV_UNLOCK(evdev);
+ return (EBUSY);
+ }
+
+ evdev->ev_grabbed = true;
+
+ /* Disable all other clients */
+ LIST_FOREACH(iter, &evdev->ev_clients, ec_link) {
+ if (iter != client)
+ iter->ec_enabled = false;
+ }
+
+ EVDEV_UNLOCK(evdev);
+ return (0);
+}
+
+int
+evdev_release_client(struct evdev_client *client)
+{
+ struct evdev_dev *evdev = client->ec_evdev;
+ struct evdev_client *iter;
+
+ EVDEV_LOCK(evdev);
+ if (!evdev->ev_grabbed) {
+ EVDEV_UNLOCK(evdev);
+ return (EINVAL);
+ }
+
+ evdev->ev_grabbed = false;
+
+ /* Enable all other clients */
+ LIST_FOREACH(iter, &evdev->ev_clients, ec_link) {
+ iter->ec_enabled = true;
+ }
+
+ EVDEV_UNLOCK(evdev);
+ return (0);
+}
+
static void
evdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code,
int32_t value)
{
int count, head, tail;
- mtx_lock(&client->ec_buffer_mtx);
+
+ EVDEV_CLIENT_LOCKQ(client);
head = client->ec_buffer_head;
tail = client->ec_buffer_tail;
count = client->ec_buffer_size;
+
+ if (!client->ec_enabled) {
+ EVDEV_CLIENT_UNLOCKQ(client);
+ return;
+ }
/* If queue is full, overwrite last element with SYN_DROPPED event */
if ((tail + 1) % count == head) {
@@ -303,7 +374,7 @@ evdev_client_push(struct evdev_client *c
client->ec_buffer[tail].code = SYN_DROPPED;
wakeup(client);
- mtx_unlock(&client->ec_buffer_mtx);
+ EVDEV_CLIENT_UNLOCKQ(client);
return;
}
@@ -314,6 +385,82 @@ evdev_client_push(struct evdev_client *c
client->ec_buffer_tail = (tail + 1) % count;
wakeup(client);
- mtx_unlock(&client->ec_buffer_mtx);
+ EVDEV_CLIENT_UNLOCKQ(client);
}
+void
+evdev_client_dumpqueue(struct evdev_client *client)
+{
+ struct input_event *event;
+ int i, head, tail, size;
+
+ head = client->ec_buffer_head;
+ tail = client->ec_buffer_tail;
+ size = client->ec_buffer_size;
+
+ printf("evdev client: %p\n", client);
+ printf("evdev provider name: %s\n", client->ec_evdev->ev_name);
+ printf("event queue: head=%d tail=%d size=%d\n", tail, head, size);
+
+ printf("queue contents:\n");
+
+ for (i = 0; i < size; i++) {
+ event = &client->ec_buffer[i];
+ printf("%d: ", i);
+
+ if (i < head || i > tail)
+ printf("unused\n");
+ else
+ printf("type=%d code=%d value=%d ", event->type,
+ event->code, event->value);
+
+ if (i == head)
+ printf("<- head\n");
+ else if (i == tail)
+ printf("<- tail\n");
+ else
+ printf("\n");
+ }
+}
+
+void
+evdev_client_filter_queue(struct evdev_client *client, uint16_t type)
+{
+ struct input_event *event;
+ int head, tail, count, i;
+ bool last_was_syn = false;
+
+ EVDEV_CLIENT_LOCKQ(client);
+
+ i = head = client->ec_buffer_head;
+ tail = client->ec_buffer_tail;
+ count = client->ec_buffer_size;
+
+ while (i != client->ec_buffer_tail) {
+ event = &client->ec_buffer[i];
+ i = (i + 1) % count;
+
+ /* Skip event of given type */
+ if (event->type == type)
+ continue;
+
+ /* Remove empty SYN_REPORT events */
+ if (event->type == EV_SYN && event->code == SYN_REPORT &&
+ last_was_syn)
+ continue;
+
+ /* Rewrite entry */
+ memcpy(&client->ec_buffer[tail], event,
+ sizeof(struct input_event));
+
+ last_was_syn = (event->type == EV_SYN &&
+ event->code == SYN_REPORT);
+
+ tail = (tail + 1) % count;
+ }
+
+ client->ec_buffer_head = i;
+ client->ec_buffer_tail = tail;
+
+ EVDEV_CLIENT_UNLOCKQ(client);
+}
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jun 11 18:24:51 2014 (r267368)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jun 11 18:45:47 2014 (r267369)
@@ -42,7 +42,10 @@ struct evdev_client;
typedef int (evdev_open_t)(struct evdev_dev *, void *);
typedef void (evdev_close_t)(struct evdev_dev *, void *);
-typedef void (evdev_event_t)(struct evdev_dev *, void *, uint16_t, uint16_t, int32_t);
+typedef void (evdev_event_t)(struct evdev_dev *, void *, uint16_t,
+ uint16_t, int32_t);
+typedef void (evdev_keycode_t)(struct evdev_dev *, void *,
+ struct input_keymap_entry *);
typedef void (evdev_client_event_t)(struct evdev_client *, void *);
struct evdev_methods
@@ -50,6 +53,8 @@ struct evdev_methods
evdev_open_t *ev_open;
evdev_close_t *ev_close;
evdev_event_t *ev_event;
+ evdev_keycode_t *ev_get_keycode;
+ evdev_keycode_t *ev_set_keycode;
};
struct evdev_dev
@@ -60,6 +65,9 @@ struct evdev_dev
device_t ev_dev;
void * ev_softc;
struct cdev * ev_cdev;
+ struct mtx ev_mtx;
+ struct input_id ev_id;
+ bool ev_grabbed;
/* Supported features: */
uint32_t ev_type_flags[howmany(EV_CNT, 32)];
@@ -78,6 +86,10 @@ struct evdev_dev
uint32_t ev_snd_states[howmany(SND_CNT, 32)];
uint32_t ev_sw_states[howmany(SW_CNT, 32)];
+ /* Keyboard delay/repeat: */
+ int ev_kbd_delay;
+ int ev_kbd_repeat;
+
/* Counters: */
uint64_t ev_event_count;
int ev_clients_count;
@@ -88,6 +100,9 @@ struct evdev_dev
LIST_HEAD(, evdev_client) ev_clients;
};
+#define EVDEV_LOCK(evdev) mtx_lock(&(evdev)->ev_mtx)
+#define EVDEV_UNLOCK(evdev) mtx_unlock(&(evdev)->ev_mtx)
+
struct evdev_client
{
struct evdev_dev * ec_evdev;
@@ -118,8 +133,8 @@ void evdev_set_methods(struct evdev_dev
void evdev_set_softc(struct evdev_dev *, void *);
int evdev_register(device_t, struct evdev_dev *);
int evdev_unregister(device_t, struct evdev_dev *);
-int evdev_push_event(struct evdev_dev *, uint16_t type, uint16_t code,
- int32_t value);
+int evdev_push_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
+int evdev_inject_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
int evdev_sync(struct evdev_dev *);
int evdev_cdev_create(struct evdev_dev *);
int evdev_cdev_destroy(struct evdev_dev *);
@@ -136,9 +151,13 @@ void evdev_set_absinfo(struct evdev_dev
/* Client interface: */
int evdev_register_client(struct evdev_dev *, struct evdev_client **);
int evdev_dispose_client(struct evdev_client *);
+int evdev_grab_client(struct evdev_client *);
+int evdev_release_client(struct evdev_client *);
+void evdev_client_filter_queue(struct evdev_client *, uint16_t);
/* Utility functions: */
uint16_t evdev_hid2key(int);
uint16_t evdev_at2key(int);
+void evdev_client_dumpqueue(struct evdev_client *);
#endif /* _DEV_EVDEV_EVDEV_H */
More information about the svn-src-user
mailing list