From 30718c2495163495f78004b140c7a7cbd05f6aea Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 15 Aug 2015 11:38:38 -0400 Subject: [PATCH] Add profile implementation Still not populated with buttons, but it's a good start. Signed-off-by: Benjamin Tissoires --- src/etekcity.c | 77 ++++++++++++++++++++++++-------------- src/libratbag-private.h | 12 ++++++ src/libratbag.c | 82 ++++++++++++++++++++++++++++++++++++++++- src/libratbag.sym | 4 ++ tools/ratbag-command.c | 4 ++ 5 files changed, 149 insertions(+), 30 deletions(-) diff --git a/src/etekcity.c b/src/etekcity.c index 4bbe92ce..5eb0806a 100644 --- a/src/etekcity.c +++ b/src/etekcity.c @@ -22,6 +22,7 @@ */ #include "config.h" +#include #include #include #include @@ -30,6 +31,10 @@ #include "libratbag-private.h" #include "libratbag-hidraw.h" +#define ETEKCITY_PROFILE_MAX 4 + +#define ETEKCITY_REPORT_ID_KEY_MAPPING 7 + static char * print_key(__u8 key) { @@ -117,13 +122,44 @@ etekcity_set_config_profile(struct ratbag *ratbag, __u8 profile, __u8 type) return ret == sizeof(buf) ? 0 : ret; } +static void +etekcity_read_profile(struct ratbag_profile *profile, unsigned int index) +{ + struct ratbag *ratbag = profile->ratbag; + int i, rc; + __u8 buf[50]; + __u8 data; + + assert(index <= ETEKCITY_PROFILE_MAX); + + etekcity_set_config_profile(ratbag, index, 0x20); + rc = ratbag_hidraw_raw_request(ratbag, ETEKCITY_REPORT_ID_KEY_MAPPING, + buf, sizeof(buf), HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + + if (rc < 50) + return; + + log_debug(ratbag->libratbag, "profile: %d %s:%d\n", + buf[2], + __FILE__, __LINE__); + + for (i = 0; i < 16; i++) { + data = buf[3 + i * 3]; + if (data) + log_debug(ratbag->libratbag, + " - button%d: %s (%02x) %s:%d\n", + i, + print_key(data), + data, + __FILE__, __LINE__); + } +} + static int etekcity_probe(struct ratbag *ratbag, const struct ratbag_id id) { - int rc, current_profile; - int i; - __u8 data; - __u8 buf[256]; + int rc; + struct ratbag_profile *profile; log_debug(ratbag->libratbag, "data: %d\n", id.data); @@ -136,8 +172,11 @@ etekcity_probe(struct ratbag *ratbag, const struct ratbag_id id) return -ENODEV; } - rc = etekcity_current_profile(ratbag); - if (rc < 0) { + ratbag->num_profiles = ETEKCITY_PROFILE_MAX; + + profile = ratbag_get_active_profile(ratbag); + + if (!profile) { log_error(ratbag->libratbag, "Can't talk to the mouse: '%s' (%d)\n", strerror(-rc), @@ -145,32 +184,12 @@ etekcity_probe(struct ratbag *ratbag, const struct ratbag_id id) return -ENODEV; } - current_profile = rc; - log_info(ratbag->libratbag, "'%s' is in profile %d\n", ratbag_get_name(ratbag), - current_profile); + profile->index); - etekcity_set_config_profile(ratbag, current_profile, 0x20); - rc = ratbag_hidraw_raw_request(ratbag, 7, buf, sizeof(buf), - HID_FEATURE_REPORT, HID_REQ_GET_REPORT); - if (rc >= 40) { - log_debug(ratbag->libratbag, "profile: %d %s:%d\n", - buf[2], - __FILE__, __LINE__); - - for (i = 0; i < 16; i++) { - data = buf[3 + i * 3]; - if (data) - log_debug(ratbag->libratbag, - " - button%d: %s (%02x) %s:%d\n", - i, - print_key(data), - data, - __FILE__, __LINE__); - } - } + profile = ratbag_profile_unref(profile); return 0; } @@ -190,4 +209,6 @@ struct ratbag_driver etekcity_driver = { .name = "EtekCity", .table_ids = etekcity_table, .probe = etekcity_probe, + .read_profile = etekcity_read_profile, + .get_active_profile = etekcity_current_profile, }; diff --git a/src/libratbag-private.h b/src/libratbag-private.h index 59b46444..00f91fec 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -49,6 +49,9 @@ struct ratbag { struct input_id ids; struct ratbag_driver *driver; struct libratbag *libratbag; + + unsigned num_profiles; + struct list profiles; }; struct ratbag_id { @@ -61,11 +64,20 @@ struct ratbag_driver { const struct ratbag_id *table_ids; int (*probe)(struct ratbag *ratbag, const struct ratbag_id id); + void (*read_profile)(struct ratbag_profile *profile, unsigned int index); + int (*get_active_profile)(struct ratbag *ratbag); /* private */ struct list link; }; +struct ratbag_profile { + int refcount; + struct list link; + unsigned index; + struct ratbag *ratbag; +}; + void ratbag_device_init(struct ratbag *rb, int fd); void diff --git a/src/libratbag.c b/src/libratbag.c index 6fcd7a05..ff5fe3cd 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -194,6 +194,7 @@ ratbag_device_init(struct ratbag *rb, int fd) rb->evdev_fd = fd; rb->hidraw_fd = -1; rb->refcount = 1; + list_init(&rb->profiles); } static inline bool @@ -222,10 +223,13 @@ ratbag_find_driver(struct libratbag *libratbag, struct ratbag *ratbag, assert(driver->probe); matched_id.id = *dev_id; matched_id.data = matching_id->data; + ratbag->driver = driver; rc = driver->probe(ratbag, matched_id); if (rc == 0) return driver; + ratbag->driver = NULL; + if (rc != -ENODEV) return NULL; } @@ -285,8 +289,6 @@ ratbag_new_from_fd(struct libratbag *libratbag, int fd) goto err_udev; } - ratbag->driver = driver; - return ratbag; err_udev: @@ -384,3 +386,79 @@ libratbag_unref(struct libratbag *libratbag) return NULL; } + +static struct ratbag_profile * +ratbag_create_profile(struct ratbag *ratbag, unsigned int index) +{ + struct ratbag_profile *profile; + + profile = zalloc(sizeof(*profile)); + if (!profile) + return NULL; + + profile->refcount = 1; + profile->ratbag = ratbag; + profile->index = index; + + list_insert(&ratbag->profiles, &profile->link); + + assert(ratbag->driver->read_profile); + ratbag->driver->read_profile(profile, index); + + return profile; +} + +LIBRATBAG_EXPORT struct ratbag_profile * +ratbag_profile_ref(struct ratbag_profile *profile) +{ + profile->refcount++; + return profile; +} + +LIBRATBAG_EXPORT struct ratbag_profile * +ratbag_profile_unref(struct ratbag_profile *profile) +{ + if (profile == NULL) + return NULL; + + assert(profile->refcount > 0); + profile->refcount--; + if (profile->refcount > 0) + return profile; + + list_remove(&profile->link); + free(profile); + + return NULL; +} + +LIBRATBAG_EXPORT struct ratbag_profile * +ratbag_get_profile_by_index(struct ratbag *ratbag, unsigned int index) +{ + struct ratbag_profile *profile; + + list_for_each(profile, &ratbag->profiles, link) { + if (profile->index == index) { + assert(ratbag->driver->read_profile); + ratbag->driver->read_profile(profile, index); + return ratbag_profile_ref(profile); + } + } + + return ratbag_create_profile(ratbag, index); +} + +LIBRATBAG_EXPORT struct ratbag_profile * +ratbag_get_active_profile(struct ratbag *ratbag) +{ + int current_profile; + + assert(ratbag->driver->get_active_profile); + current_profile = ratbag->driver->get_active_profile(ratbag); + if (current_profile < 0) { + errno = -current_profile; + return NULL; + } + + return ratbag_get_profile_by_index(ratbag, current_profile); +} diff --git a/src/libratbag.sym b/src/libratbag.sym index 2d892fe7..1a50be4a 100644 --- a/src/libratbag.sym +++ b/src/libratbag.sym @@ -5,8 +5,12 @@ global: libratbag_create_context; libratbag_ref; libratbag_unref; + ratbag_get_active_profile; ratbag_get_name; + ratbag_get_profile_by_index; ratbag_new_from_fd; + ratbag_profile_ref; + ratbag_profile_unref; ratbag_unref; local: *; diff --git a/tools/ratbag-command.c b/tools/ratbag-command.c index 50fb9fe3..17b53953 100644 --- a/tools/ratbag-command.c +++ b/tools/ratbag-command.c @@ -49,6 +49,7 @@ main(int argc, char **argv) { struct ratbag *rb; struct libratbag *libratbag; + struct ratbag_profile *profile; char *path; int fd; int retval = 0; @@ -81,7 +82,10 @@ main(int argc, char **argv) fprintf(stderr, "Opened '%s' (%s).\n", ratbag_get_name(rb), path); + profile = ratbag_get_active_profile(rb); + out: + profile = ratbag_profile_unref(profile); rb = ratbag_unref(rb); libratbag_unref(libratbag); close(fd);