From: lanshh Date: Fri, 14 Oct 2016 01:52:12 +0000 (+0800) Subject: hid: rkvr: add suspend and resume notifier for nanoc X-Git-Tag: firefly_0821_release~1366 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=commitdiff_plain;h=6ea399faa6d9e5263c9dd8f3404678748ad31deb hid: rkvr: add suspend and resume notifier for nanoc Change-Id: I870247058c363506400a20c57eb48566b7516c7d Signed-off-by: lanshh --- diff --git a/drivers/hid/hid-rkvr.c b/drivers/hid/hid-rkvr.c index d92656a12794..4360c28dd729 100644 --- a/drivers/hid/hid-rkvr.c +++ b/drivers/hid/hid-rkvr.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "hid-rkvr.h" #include "hid-ids.h" @@ -38,6 +40,10 @@ static struct class *rkvr_class; static struct hidraw *rkvr_hidraw_table[RKVR_HIDRAW_MAX_DEVICES]; +static struct hid_capability +{ + __u8 suspend_notify; +} rkvr_hid_capability[RKVR_HIDRAW_MAX_DEVICES]; static DEFINE_MUTEX(minors_lock); struct keymap_t { @@ -65,6 +71,8 @@ struct keymap_t { __u16 key_enter_pressed:1; __u16 key_enter_released:1; __u16 key_pressed:1; + __u16 psensor_on:1; + __u16 psensor_off:1; } __packed; union rkvr_data_t { @@ -556,6 +564,17 @@ static int rkvr_keys_event(struct hid_device *hdev, void *data, unsigned long le rkvr_send_key_event(input, KEY_ENTER, 1); rkvr_send_key_event(input, KEY_ENTER, 0); } + + if (rkvr_data->rkvr_data.key_map.psensor_on) { + hid_info(hdev, "event: psensor_on\n"); + rkvr_send_key_event(input, KEY_POWER, 1); + rkvr_send_key_event(input, KEY_POWER, 0); + } else if (rkvr_data->rkvr_data.key_map.psensor_off) { + hid_info(hdev, "event: psensor_off\n"); + rkvr_send_key_event(input, KEY_POWER, 1); + rkvr_send_key_event(input, KEY_POWER, 0); + } + return 0; } @@ -624,6 +643,26 @@ fail: return ret; } +static int rkvr_recv_report(struct device *dev, u8 type, u8 *data, int len) +{ + struct hid_device *hid = container_of(dev, struct hid_device, dev); + unsigned char report_number = type; + unsigned char report_type = HID_MISC_REPORT; + char buf[1 + sizeof(*data) * len]; + int readlen = 1 + sizeof(*data) * len; + int ret; + + ret = hid_hw_raw_request(hid, report_number, (unsigned char *)buf, readlen, report_type, HID_REQ_GET_REPORT); + if (ret != readlen) { + hid_info(hid, "rkvr_recv_report fail\n"); + return -1; + } + memcpy(data, &buf[1], len); + hid_info(hid, "rkvr_recv_report %02x\n", type); + + return 0; +} + /* * for enable sensor data ************************************ @@ -696,6 +735,20 @@ fail: return ret; } +static int hid_get_capability(struct device *dev, struct hid_capability *caps) +{ + struct hid_device *hid = container_of(dev, struct hid_device, dev); + u8 data = 0; + + caps->suspend_notify = 0; + if (!rkvr_recv_report(dev, RKVR_ID_CAPS, &data, 1)) { + hid_info(hid, "hid_get_capability %d\n", data); + caps->suspend_notify = data; + return 0; + } + return -1; +} + static void hid_report_fill_rw(unsigned char *buf, u8 reg, u8 *data, int len, int w) { if (w) @@ -954,6 +1007,9 @@ static int rkvr_connect(struct hid_device *hid) dev->minor = minor; dev->exist = 1; hid->hidraw = dev; /*struct hidraw * **/ + + hid_get_capability(&hid->dev, &rkvr_hid_capability[minor]); + mutex_unlock(&minors_lock); out: return result; @@ -1200,6 +1256,53 @@ int rkvr_sensor_register_callback(int (*callback)(char *, size_t, void *), void } EXPORT_SYMBOL_GPL(rkvr_sensor_register_callback); +static int rkvr_fb_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + int i; + unsigned char buf[3] = {HID_REPORT_ID_RKVR, RKVR_ID_IDLE, 0}; + struct hid_device *hid; + struct fb_event *event = data; + int blank_mode = *((int *)event->data); + + if (action != FB_EARLY_EVENT_BLANK && action != FB_EVENT_BLANK) + return NOTIFY_OK; + + mutex_lock(&minors_lock); + for (i = 0; i < RKVR_HIDRAW_MAX_DEVICES; i++) { + if (!rkvr_hidraw_table[i] || !rkvr_hidraw_table[i]->exist) + continue; + if (!rkvr_hid_capability[i].suspend_notify) { + continue; + } + hid = rkvr_hidraw_table[i]->hid; + if (action == FB_EARLY_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + break; + default: + rkvr_send_report(&hid->dev, buf, 3); + break; + } + } else if (action == FB_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + buf[2] = 1; + rkvr_send_report(&hid->dev, buf, 3); + break; + default: + break; + } + } + } + mutex_unlock(&minors_lock); + return NOTIFY_OK; +} + +static struct notifier_block rkvr_fb_notifier = { + .notifier_call = rkvr_fb_event_notify, +}; + static int rkvr_probe(struct hid_device *hdev, const struct hid_device_id *id) { int retval; @@ -1323,8 +1426,15 @@ static int __init rkvr_init(void) rkvr_major = MAJOR(dev_id); cdev_init(&rkvr_cdev, &rkvr_ops); cdev_add(&rkvr_cdev, dev_id, RKVR_HIDRAW_MAX_DEVICES); - return 0; + retval = fb_register_client(&rkvr_fb_notifier); + if (retval) { + pr_warn("rkvr_init - Can't register fb notifier\n"); + goto out_chardev; + } + return 0; +out_chardev: + unregister_chrdev_region(dev_id, RKVR_HIDRAW_MAX_DEVICES); out_register: hid_unregister_driver(&rkvr_driver); out_class: @@ -1337,6 +1447,7 @@ static void __exit rkvr_exit(void) { dev_t dev_id = MKDEV(rkvr_major, 0); + fb_unregister_client(&rkvr_fb_notifier); cdev_del(&rkvr_cdev); unregister_chrdev_region(dev_id, RKVR_HIDRAW_MAX_DEVICES); diff --git a/drivers/hid/hid-rkvr.h b/drivers/hid/hid-rkvr.h index 32d38ff7e4b6..138556358fc4 100644 --- a/drivers/hid/hid-rkvr.h +++ b/drivers/hid/hid-rkvr.h @@ -14,6 +14,7 @@ #define HID_REPORT_ID_RKVR 3 #define RKVR_ID_IDLE 1 #define RKVR_ID_SYNC 2 +#define RKVR_ID_CAPS 3 #define HID_REPORT_ID_R 4 #define HID_REPORT_ID_W 5 @@ -21,6 +22,7 @@ #define HID_REGR_REPORT (4 - 1) #define HID_REGW_REPORT (5 - 1) +#define HID_MISC_REPORT (6 - 1) #define HID_SYNCW_REPORT (7 - 1) #define HID_SYNCR_REPORT (8 - 1)