| /* |
| * Google LWIS Event Utilities |
| * |
| * Copyright (c) 2018 Google, LLC |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #ifndef LWIS_EVENT_H_ |
| #define LWIS_EVENT_H_ |
| |
| #include <linux/list.h> |
| |
| #include "lwis_commands.h" |
| |
| /* |
| * LWIS Event Defines |
| */ |
| |
| /* |
| * LWIS Forward Declarations |
| */ |
| struct lwis_client; |
| struct lwis_device; |
| |
| /* |
| * LWIS Event Structures |
| */ |
| /* |
| * struct lwis_device_event_state |
| * This struct keeps track of device-specific event state and controls |
| */ |
| struct lwis_device_event_state { |
| int64_t event_id; |
| int64_t enable_counter; |
| int64_t event_counter; |
| bool has_subscriber; |
| struct hlist_node node; |
| }; |
| |
| /* |
| * struct lwis_device_event_state_history |
| * For debugging purposes, keeps track of event states and the time an event |
| * triggered. |
| */ |
| |
| struct lwis_device_event_state_history { |
| struct lwis_device_event_state state; |
| int64_t timestamp; |
| }; |
| |
| /* |
| * struct lwis_client_event_state |
| * This struct keeps track of client-specific event state and controls |
| */ |
| struct lwis_client_event_state { |
| struct lwis_event_control event_control; |
| struct hlist_node node; |
| struct list_head clearance_node; |
| }; |
| |
| /* |
| * struct lwis_event_entry |
| * This struct can be used to keep track of events inside the client event |
| * queue, or the device events that are waiting to be emitted. These two |
| * types of events are mutually exclusive, i.e. an event can only be one, |
| * but not both, of those queues. |
| */ |
| struct lwis_event_entry { |
| struct lwis_event_info event_info; |
| struct list_head node; |
| }; |
| |
| /* |
| * LWIS Event Typedefs and Enums |
| */ |
| |
| /* |
| * LWIS Event Interface Functions |
| */ |
| |
| /* |
| * lwis_client_event_control_set: Updates the client and device event states |
| * with the new control configuration from userspace |
| * |
| * Locks: lwisclient->event_lock |
| * Alloc: Maybe |
| * Assumes: lwisclient->lock may be locked |
| * Returns: 0 on success |
| */ |
| int lwis_client_event_control_set(struct lwis_client *lwisclient, |
| const struct lwis_event_control *control); |
| |
| /* |
| * lwis_client_event_control_get: Finds and returns the current event state |
| * for a particular event id |
| * |
| * Locks: lwisclient->event_lock |
| * Alloc: Maybe |
| * Assumes: lwisclient->lock may be locked |
| * Returns: 0 on success |
| */ |
| int lwis_client_event_control_get(struct lwis_client *lwisclient, int64_t event_id, |
| struct lwis_event_control *control); |
| |
| /* |
| * lwis_client_event_pop_front: Removes an event from the client event queue |
| * that is ready to be copied to userspace. |
| * |
| * if event is not NULL, the caller takes ownership of *event and must free it |
| * if event is NULL, this function will free the popped event object |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: 0 on success, -ENOENT if queue empty |
| */ |
| int lwis_client_event_pop_front(struct lwis_client *lwis_client, struct lwis_event_entry **event); |
| |
| /* |
| * lwis_client_event_peek_front: Get the front element of the queue without |
| * removing it |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: 0 on success, -ENOENT if queue empty |
| */ |
| int lwis_client_event_peek_front(struct lwis_client *lwis_client, struct lwis_event_entry **event); |
| |
| /* |
| * lwis_client_event_queue_clear: Clear all entries inside the event queue. |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: void |
| */ |
| void lwis_client_event_queue_clear(struct lwis_client *lwis_client); |
| |
| /* |
| * lwis_client_event_pop_front: Removes an event from the client event queue |
| * that is ready to be copied to userspace. |
| * |
| * if event is not NULL, the caller takes ownership of *event and must free it |
| * if event is NULL, this function will free the popped event object |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: 0 on success, -ENOENT if queue empty |
| */ |
| int lwis_client_error_event_pop_front(struct lwis_client *lwis_client, |
| struct lwis_event_entry **event); |
| |
| /* |
| * lwis_client_event_peek_front: Get the front element of the queue without |
| * removing it |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: 0 on success, -ENOENT if queue empty |
| */ |
| int lwis_client_error_event_peek_front(struct lwis_client *lwis_client, |
| struct lwis_event_entry **event); |
| |
| /* |
| * lwis_client_error_event_queue_clear: Clear all entries inside the event |
| * queue. |
| * |
| * Locks: lwis_client->event_lock |
| * |
| * Alloc: No |
| * Returns: void |
| */ |
| void lwis_client_error_event_queue_clear(struct lwis_client *lwis_client); |
| |
| /* |
| * lwis_client_event_states_clear: Frees all items in lwisclient->event_states |
| * and clears the hash table. Used for client shutdown only. |
| * |
| * Locks: lwisclient->event_lock |
| * Indirect Locks: lwisdevice->lock |
| * Assumes: lwisclient->lock is locked |
| * Alloc: Free only |
| * Returns: 0 on success |
| */ |
| int lwis_client_event_states_clear(struct lwis_client *lwisclient); |
| |
| /* |
| * lwis_device_event_states_clear: Frees all items in lwisdev->event_states |
| * and clears the hash table. Used for device shutdown only. |
| * |
| * Assumes: lwisdev->lock is locked |
| * Returns: 0 on success |
| */ |
| int lwis_device_event_states_clear_locked(struct lwis_device *lwisdev); |
| |
| /* |
| * lwis_device_event_flags_updated: Notifies the device that the given event_id |
| * has new flags, which allows the device to register/unregister IRQs, and |
| * keep track if event is still relevant |
| * |
| * Locks: lwisdevice->lock |
| * |
| * Returns: 0 on success |
| */ |
| int lwis_device_event_flags_updated(struct lwis_device *lwis_dev, int64_t event_id, |
| uint64_t old_flags, uint64_t new_flags); |
| |
| /* |
| * lwis_device_event_enable: Handles when a device event needs to be |
| * enabled or disabled. Actually implements the generic device events, and calls |
| * into other parts to see if they care about the event as well. |
| * |
| * Locks: lwisdevice->lock |
| * Alloc: May allocate |
| * Returns: 0 on success (event enabled/disabled) |
| * -EINVAL if event unknown |
| */ |
| int lwis_device_event_enable(struct lwis_device *lwis_dev, int64_t event_id, bool enabled); |
| |
| /* |
| * lwis_device_event_emit: Emits an event to all the relevant clients of the |
| * device |
| * |
| * Locks: lwis_dev->lock and then lwis_client->event_lock |
| * Alloc: May allocate (GFP_ATOMIC or GFP_NOWAIT only) |
| * Returns: 0 on success |
| */ |
| int lwis_device_event_emit(struct lwis_device *lwis_dev, int64_t event_id, void *payload, |
| size_t payload_size, bool in_irq); |
| |
| /* |
| * lwis_device_external_event_emit: Emits an subscribed event to device. |
| * The difference to lwis_device_event_emit is |
| * 1. Directly assign event count to lwis_dev |
| * 2. Won't have subscriber |
| * 3. No payload to clients, only deliver event id and event count |
| * 4. Not supported chain transaction |
| */ |
| void lwis_device_external_event_emit(struct lwis_device *lwis_dev, int64_t event_id, |
| int64_t event_counter, int64_t timestamp, bool in_irq); |
| |
| /* |
| * lwis_device_error_event_emit: Emits an error event for all clients. |
| * The difference to lwis_device_event_emit is that this directly sends the |
| * error event to userspace without needing client to enable this event, |
| * because all error events should be propagated to userspace such that |
| * userspace can do the proper error handling. |
| * |
| * Also, no transactions will be triggered by error events. |
| */ |
| void lwis_device_error_event_emit(struct lwis_device *lwis_dev, int64_t event_id, void *payload, |
| size_t payload_size); |
| |
| /* |
| * lwis_device_event_state_find_or_create: Looks through the provided device's |
| * event state list and tries to find a lwis_device_event_state object with the |
| * matching event_id. If not found, function returns NULL pointer. |
| * |
| * Locks: lwis_dev->lock |
| * Alloc: Maybe |
| * Returns: device event state object if found, NULL otherwise. |
| */ |
| struct lwis_device_event_state *lwis_device_event_state_find(struct lwis_device *lwis_dev, |
| int64_t event_id); |
| |
| /* |
| * lwis_device_event_state_find_or_create: Looks through the provided device's |
| * event state list and tries to find a lwis_device_event_state object with the |
| * matching event_id. If not found, creates the object with 0 flags and adds it |
| * to the list |
| * |
| * Locks: lwis_dev->lock |
| * Alloc: Maybe |
| * Returns: device event state object on success, errno on error |
| */ |
| struct lwis_device_event_state *lwis_device_event_state_find_or_create(struct lwis_device *lwis_dev, |
| int64_t event_id); |
| |
| /* |
| * lwis_client_event_state_find_or_create: Looks through the provided client's |
| * event state list and tries to find a lwis_client_event_state object with the |
| * matching event_id. If not found, creates the object with 0 flags and adds it |
| * to the list |
| * |
| * Locks: lwis_client->event_lock |
| * Alloc: Maybe |
| * Returns: client event state object on success, errno on error |
| */ |
| struct lwis_client_event_state * |
| lwis_client_event_state_find_or_create(struct lwis_client *lwis_client, int64_t event_id); |
| |
| /* |
| * lwis_pending_event_push: Push triggered event into a local pending queue to |
| * defer processing until all the current event is done |
| * |
| * Alloc: Maybe |
| * Returns: 0 on success |
| */ |
| int lwis_pending_event_push(struct list_head *pending_events, int64_t event_id, void *payload, |
| size_t payload_size); |
| |
| /* |
| * lwis_pending_events_emit: If pending queue is not empty, start processing |
| * and emitting the events in queue |
| * |
| * Returns: 0 on success |
| */ |
| int lwis_pending_events_emit(struct lwis_device *lwis_dev, struct list_head *pending_events, |
| bool in_irq); |
| |
| /* |
| * lwis_device_event_update_subscriber: The function to notify an event has been subscribed/unsubscribed. |
| * Returns: 0 on success, -EINVAL if event id not found in trigger device. |
| */ |
| int lwis_device_event_update_subscriber(struct lwis_device *lwis_dev, int64_t event_id, |
| bool has_subscriber); |
| |
| #endif /* LWIS_EVENT_H_ */ |