From bb2ef9c39db2e3c2562b4e439b2b00dc42e2c026 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 26 Jul 2015 09:54:23 +0300 Subject: mei: bus: add and call callback on notify event Enable drivers on mei client bus to subscribe to asynchronous event notifications. Introduce events_mask to the existing callback infrastructure so it is possible to handle both RX and event notification. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 50 ++++++++++++++++++++++++++++++++++++++++++---- drivers/misc/mei/client.c | 2 ++ drivers/misc/mei/mei_dev.h | 1 + 3 files changed, 49 insertions(+), 4 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 3ab08e522fb8..eef1c6b46ad8 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -222,7 +222,33 @@ static void mei_bus_event_work(struct work_struct *work) cldev->events = 0; /* Prepare for the next read */ - mei_cl_read_start(cldev->cl, 0, NULL); + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) + mei_cl_read_start(cldev->cl, 0, NULL); +} + +/** + * mei_cl_bus_notify_event - schedule notify cb on bus client + * + * @cl: host client + */ +void mei_cl_bus_notify_event(struct mei_cl *cl) +{ + struct mei_cl_device *cldev = cl->cldev; + + if (!cldev || !cldev->event_cb) + return; + + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF))) + return; + + if (!cl->notify_ev) + return; + + set_bit(MEI_CL_EVENT_NOTIF, &cldev->events); + + schedule_work(&cldev->event_work); + + cl->notify_ev = false; } /** @@ -237,6 +263,9 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) if (!cldev || !cldev->event_cb) return; + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX))) + return; + set_bit(MEI_CL_EVENT_RX, &cldev->events); schedule_work(&cldev->event_work); @@ -247,6 +276,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * * @cldev: me client devices * @event_cb: callback function + * @events_mask: requested events bitmask * @context: driver context data * * Return: 0 on success @@ -254,6 +284,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * <0 on other errors */ int mei_cl_register_event_cb(struct mei_cl_device *cldev, + unsigned long events_mask, mei_cl_event_cb_t event_cb, void *context) { int ret; @@ -262,13 +293,24 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev, return -EALREADY; cldev->events = 0; + cldev->events_mask = events_mask; cldev->event_cb = event_cb; cldev->event_context = context; INIT_WORK(&cldev->event_work, mei_bus_event_work); - ret = mei_cl_read_start(cldev->cl, 0, NULL); - if (ret && ret != -EBUSY) - return ret; + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { + ret = mei_cl_read_start(cldev->cl, 0, NULL); + if (ret && ret != -EBUSY) + return ret; + } + + if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) { + mutex_lock(&cldev->cl->dev->device_lock); + ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0); + mutex_unlock(&cldev->cl->dev->device_lock); + if (ret) + return ret; + } return 0; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index db2436aee2dc..5fcd70bcdf96 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1375,6 +1375,8 @@ void mei_cl_notify(struct mei_cl *cl) if (cl->ev_async) kill_fasync(&cl->ev_async, SIGIO, POLL_PRI); + + mei_cl_bus_notify_event(cl); } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index c960aaa538c0..e25ee16c658e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -345,6 +345,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); +void mei_cl_bus_notify_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *bus); int mei_cl_bus_init(void); void mei_cl_bus_exit(void); -- cgit v1.2.3