162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ACPI event handling for Wilco Embedded Controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019 Google LLC 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * The Wilco Embedded Controller can create custom events that 862306a36Sopenharmony_ci * are not handled as standard ACPI objects. These events can 962306a36Sopenharmony_ci * contain information about changes in EC controlled features, 1062306a36Sopenharmony_ci * such as errors and events in the dock or display. For example, 1162306a36Sopenharmony_ci * an event is triggered if the dock is plugged into a display 1262306a36Sopenharmony_ci * incorrectly. These events are needed for telemetry and 1362306a36Sopenharmony_ci * diagnostics reasons, and for possibly alerting the user. 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci * These events are triggered by the EC with an ACPI Notify(0x90), 1662306a36Sopenharmony_ci * and then the BIOS reads the event buffer from EC RAM via an 1762306a36Sopenharmony_ci * ACPI method. When the OS receives these events via ACPI, 1862306a36Sopenharmony_ci * it passes them along to this driver. The events are put into 1962306a36Sopenharmony_ci * a queue which can be read by a userspace daemon via a char device 2062306a36Sopenharmony_ci * that implements read() and poll(). The event queue acts as a 2162306a36Sopenharmony_ci * circular buffer of size 64, so if there are no userspace consumers 2262306a36Sopenharmony_ci * the kernel will not run out of memory. The char device will appear at 2362306a36Sopenharmony_ci * /dev/wilco_event{n}, where n is some small non-negative integer, 2462306a36Sopenharmony_ci * starting from 0. Standard ACPI events such as the battery getting 2562306a36Sopenharmony_ci * plugged/unplugged can also come through this path, but they are 2662306a36Sopenharmony_ci * dealt with via other paths, and are ignored here. 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci * To test, you can tail the binary data with 2962306a36Sopenharmony_ci * $ cat /dev/wilco_event0 | hexdump -ve '1/1 "%x\n"' 3062306a36Sopenharmony_ci * and then create an event by plugging/unplugging the battery. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/acpi.h> 3462306a36Sopenharmony_ci#include <linux/cdev.h> 3562306a36Sopenharmony_ci#include <linux/device.h> 3662306a36Sopenharmony_ci#include <linux/fs.h> 3762306a36Sopenharmony_ci#include <linux/idr.h> 3862306a36Sopenharmony_ci#include <linux/io.h> 3962306a36Sopenharmony_ci#include <linux/list.h> 4062306a36Sopenharmony_ci#include <linux/module.h> 4162306a36Sopenharmony_ci#include <linux/poll.h> 4262306a36Sopenharmony_ci#include <linux/spinlock.h> 4362306a36Sopenharmony_ci#include <linux/uaccess.h> 4462306a36Sopenharmony_ci#include <linux/wait.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* ACPI Notify event code indicating event data is available. */ 4762306a36Sopenharmony_ci#define EC_ACPI_NOTIFY_EVENT 0x90 4862306a36Sopenharmony_ci/* ACPI Method to execute to retrieve event data buffer from the EC. */ 4962306a36Sopenharmony_ci#define EC_ACPI_GET_EVENT "QSET" 5062306a36Sopenharmony_ci/* Maximum number of words in event data returned by the EC. */ 5162306a36Sopenharmony_ci#define EC_ACPI_MAX_EVENT_WORDS 6 5262306a36Sopenharmony_ci#define EC_ACPI_MAX_EVENT_SIZE \ 5362306a36Sopenharmony_ci (sizeof(struct ec_event) + (EC_ACPI_MAX_EVENT_WORDS) * sizeof(u16)) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* Node will appear in /dev/EVENT_DEV_NAME */ 5662306a36Sopenharmony_ci#define EVENT_DEV_NAME "wilco_event" 5762306a36Sopenharmony_ci#define EVENT_CLASS_NAME EVENT_DEV_NAME 5862306a36Sopenharmony_ci#define DRV_NAME EVENT_DEV_NAME 5962306a36Sopenharmony_ci#define EVENT_DEV_NAME_FMT (EVENT_DEV_NAME "%d") 6062306a36Sopenharmony_cistatic struct class event_class = { 6162306a36Sopenharmony_ci .name = EVENT_CLASS_NAME, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Keep track of all the device numbers used. */ 6562306a36Sopenharmony_ci#define EVENT_MAX_DEV 128 6662306a36Sopenharmony_cistatic int event_major; 6762306a36Sopenharmony_cistatic DEFINE_IDA(event_ida); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Size of circular queue of events. */ 7062306a36Sopenharmony_ci#define MAX_NUM_EVENTS 64 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * struct ec_event - Extended event returned by the EC. 7462306a36Sopenharmony_ci * @size: Number of 16bit words in structure after the size word. 7562306a36Sopenharmony_ci * @type: Extended event type, meaningless for us. 7662306a36Sopenharmony_ci * @event: Event data words. Max count is %EC_ACPI_MAX_EVENT_WORDS. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistruct ec_event { 7962306a36Sopenharmony_ci u16 size; 8062306a36Sopenharmony_ci u16 type; 8162306a36Sopenharmony_ci u16 event[]; 8262306a36Sopenharmony_ci} __packed; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define ec_event_num_words(ev) (ev->size - 1) 8562306a36Sopenharmony_ci#define ec_event_size(ev) (sizeof(*ev) + (ec_event_num_words(ev) * sizeof(u16))) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/** 8862306a36Sopenharmony_ci * struct ec_event_queue - Circular queue for events. 8962306a36Sopenharmony_ci * @capacity: Number of elements the queue can hold. 9062306a36Sopenharmony_ci * @head: Next index to write to. 9162306a36Sopenharmony_ci * @tail: Next index to read from. 9262306a36Sopenharmony_ci * @entries: Array of events. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistruct ec_event_queue { 9562306a36Sopenharmony_ci int capacity; 9662306a36Sopenharmony_ci int head; 9762306a36Sopenharmony_ci int tail; 9862306a36Sopenharmony_ci struct ec_event *entries[]; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* Maximum number of events to store in ec_event_queue */ 10262306a36Sopenharmony_cistatic int queue_size = 64; 10362306a36Sopenharmony_cimodule_param(queue_size, int, 0644); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic struct ec_event_queue *event_queue_new(int capacity) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct ec_event_queue *q; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci q = kzalloc(struct_size(q, entries, capacity), GFP_KERNEL); 11062306a36Sopenharmony_ci if (!q) 11162306a36Sopenharmony_ci return NULL; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci q->capacity = capacity; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return q; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline bool event_queue_empty(struct ec_event_queue *q) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci /* head==tail when both full and empty, but head==NULL when empty */ 12162306a36Sopenharmony_ci return q->head == q->tail && !q->entries[q->head]; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline bool event_queue_full(struct ec_event_queue *q) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci /* head==tail when both full and empty, but head!=NULL when full */ 12762306a36Sopenharmony_ci return q->head == q->tail && q->entries[q->head]; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct ec_event *event_queue_pop(struct ec_event_queue *q) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct ec_event *ev; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (event_queue_empty(q)) 13562306a36Sopenharmony_ci return NULL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ev = q->entries[q->tail]; 13862306a36Sopenharmony_ci q->entries[q->tail] = NULL; 13962306a36Sopenharmony_ci q->tail = (q->tail + 1) % q->capacity; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return ev; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * If full, overwrite the oldest event and return it so the caller 14662306a36Sopenharmony_ci * can kfree it. If not full, return NULL. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic struct ec_event *event_queue_push(struct ec_event_queue *q, 14962306a36Sopenharmony_ci struct ec_event *ev) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct ec_event *popped = NULL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (event_queue_full(q)) 15462306a36Sopenharmony_ci popped = event_queue_pop(q); 15562306a36Sopenharmony_ci q->entries[q->head] = ev; 15662306a36Sopenharmony_ci q->head = (q->head + 1) % q->capacity; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return popped; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void event_queue_free(struct ec_event_queue *q) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct ec_event *event; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci while ((event = event_queue_pop(q)) != NULL) 16662306a36Sopenharmony_ci kfree(event); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci kfree(q); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * struct event_device_data - Data for a Wilco EC device that responds to ACPI. 17362306a36Sopenharmony_ci * @events: Circular queue of EC events to be provided to userspace. 17462306a36Sopenharmony_ci * @queue_lock: Protect the queue from simultaneous read/writes. 17562306a36Sopenharmony_ci * @wq: Wait queue to notify processes when events are available or the 17662306a36Sopenharmony_ci * device has been removed. 17762306a36Sopenharmony_ci * @cdev: Char dev that userspace reads() and polls() from. 17862306a36Sopenharmony_ci * @dev: Device associated with the %cdev. 17962306a36Sopenharmony_ci * @exist: Has the device been not been removed? Once a device has been removed, 18062306a36Sopenharmony_ci * writes, reads, and new opens will fail. 18162306a36Sopenharmony_ci * @available: Guarantee only one client can open() file and read from queue. 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * There will be one of these structs for each ACPI device registered. This data 18462306a36Sopenharmony_ci * is the queue of events received from ACPI that still need to be read from 18562306a36Sopenharmony_ci * userspace, the device and char device that userspace is using, a wait queue 18662306a36Sopenharmony_ci * used to notify different threads when something has changed, plus a flag 18762306a36Sopenharmony_ci * on whether the ACPI device has been removed. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistruct event_device_data { 19062306a36Sopenharmony_ci struct ec_event_queue *events; 19162306a36Sopenharmony_ci spinlock_t queue_lock; 19262306a36Sopenharmony_ci wait_queue_head_t wq; 19362306a36Sopenharmony_ci struct device dev; 19462306a36Sopenharmony_ci struct cdev cdev; 19562306a36Sopenharmony_ci bool exist; 19662306a36Sopenharmony_ci atomic_t available; 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * enqueue_events() - Place EC events in queue to be read by userspace. 20162306a36Sopenharmony_ci * @adev: Device the events came from. 20262306a36Sopenharmony_ci * @buf: Buffer of event data. 20362306a36Sopenharmony_ci * @length: Length of event data buffer. 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * %buf contains a number of ec_event's, packed one after the other. 20662306a36Sopenharmony_ci * Each ec_event is of variable length. Start with the first event, copy it 20762306a36Sopenharmony_ci * into a persistent ec_event, store that entry in the queue, move on 20862306a36Sopenharmony_ci * to the next ec_event in buf, and repeat. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Return: 0 on success or negative error code on failure. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_cistatic int enqueue_events(struct acpi_device *adev, const u8 *buf, u32 length) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct event_device_data *dev_data = adev->driver_data; 21562306a36Sopenharmony_ci struct ec_event *event, *queue_event, *old_event; 21662306a36Sopenharmony_ci size_t num_words, event_size; 21762306a36Sopenharmony_ci u32 offset = 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci while (offset < length) { 22062306a36Sopenharmony_ci event = (struct ec_event *)(buf + offset); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci num_words = ec_event_num_words(event); 22362306a36Sopenharmony_ci event_size = ec_event_size(event); 22462306a36Sopenharmony_ci if (num_words > EC_ACPI_MAX_EVENT_WORDS) { 22562306a36Sopenharmony_ci dev_err(&adev->dev, "Too many event words: %zu > %d\n", 22662306a36Sopenharmony_ci num_words, EC_ACPI_MAX_EVENT_WORDS); 22762306a36Sopenharmony_ci return -EOVERFLOW; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Ensure event does not overflow the available buffer */ 23162306a36Sopenharmony_ci if ((offset + event_size) > length) { 23262306a36Sopenharmony_ci dev_err(&adev->dev, "Event exceeds buffer: %zu > %d\n", 23362306a36Sopenharmony_ci offset + event_size, length); 23462306a36Sopenharmony_ci return -EOVERFLOW; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Point to the next event in the buffer */ 23862306a36Sopenharmony_ci offset += event_size; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Copy event into the queue */ 24162306a36Sopenharmony_ci queue_event = kmemdup(event, event_size, GFP_KERNEL); 24262306a36Sopenharmony_ci if (!queue_event) 24362306a36Sopenharmony_ci return -ENOMEM; 24462306a36Sopenharmony_ci spin_lock(&dev_data->queue_lock); 24562306a36Sopenharmony_ci old_event = event_queue_push(dev_data->events, queue_event); 24662306a36Sopenharmony_ci spin_unlock(&dev_data->queue_lock); 24762306a36Sopenharmony_ci kfree(old_event); 24862306a36Sopenharmony_ci wake_up_interruptible(&dev_data->wq); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/** 25562306a36Sopenharmony_ci * event_device_notify() - Callback when EC generates an event over ACPI. 25662306a36Sopenharmony_ci * @adev: The device that the event is coming from. 25762306a36Sopenharmony_ci * @value: Value passed to Notify() in ACPI. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * This function will read the events from the device and enqueue them. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_cistatic void event_device_notify(struct acpi_device *adev, u32 value) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct acpi_buffer event_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 26462306a36Sopenharmony_ci union acpi_object *obj; 26562306a36Sopenharmony_ci acpi_status status; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (value != EC_ACPI_NOTIFY_EVENT) { 26862306a36Sopenharmony_ci dev_err(&adev->dev, "Invalid event: 0x%08x\n", value); 26962306a36Sopenharmony_ci return; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Execute ACPI method to get event data buffer. */ 27362306a36Sopenharmony_ci status = acpi_evaluate_object(adev->handle, EC_ACPI_GET_EVENT, 27462306a36Sopenharmony_ci NULL, &event_buffer); 27562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 27662306a36Sopenharmony_ci dev_err(&adev->dev, "Error executing ACPI method %s()\n", 27762306a36Sopenharmony_ci EC_ACPI_GET_EVENT); 27862306a36Sopenharmony_ci return; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci obj = (union acpi_object *)event_buffer.pointer; 28262306a36Sopenharmony_ci if (!obj) { 28362306a36Sopenharmony_ci dev_err(&adev->dev, "Nothing returned from %s()\n", 28462306a36Sopenharmony_ci EC_ACPI_GET_EVENT); 28562306a36Sopenharmony_ci return; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci if (obj->type != ACPI_TYPE_BUFFER) { 28862306a36Sopenharmony_ci dev_err(&adev->dev, "Invalid object returned from %s()\n", 28962306a36Sopenharmony_ci EC_ACPI_GET_EVENT); 29062306a36Sopenharmony_ci kfree(obj); 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci if (obj->buffer.length < sizeof(struct ec_event)) { 29462306a36Sopenharmony_ci dev_err(&adev->dev, "Invalid buffer length %d from %s()\n", 29562306a36Sopenharmony_ci obj->buffer.length, EC_ACPI_GET_EVENT); 29662306a36Sopenharmony_ci kfree(obj); 29762306a36Sopenharmony_ci return; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci enqueue_events(adev, obj->buffer.pointer, obj->buffer.length); 30162306a36Sopenharmony_ci kfree(obj); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int event_open(struct inode *inode, struct file *filp) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct event_device_data *dev_data; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci dev_data = container_of(inode->i_cdev, struct event_device_data, cdev); 30962306a36Sopenharmony_ci if (!dev_data->exist) 31062306a36Sopenharmony_ci return -ENODEV; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (atomic_cmpxchg(&dev_data->available, 1, 0) == 0) 31362306a36Sopenharmony_ci return -EBUSY; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Increase refcount on device so dev_data is not freed */ 31662306a36Sopenharmony_ci get_device(&dev_data->dev); 31762306a36Sopenharmony_ci stream_open(inode, filp); 31862306a36Sopenharmony_ci filp->private_data = dev_data; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic __poll_t event_poll(struct file *filp, poll_table *wait) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct event_device_data *dev_data = filp->private_data; 32662306a36Sopenharmony_ci __poll_t mask = 0; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci poll_wait(filp, &dev_data->wq, wait); 32962306a36Sopenharmony_ci if (!dev_data->exist) 33062306a36Sopenharmony_ci return EPOLLHUP; 33162306a36Sopenharmony_ci if (!event_queue_empty(dev_data->events)) 33262306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM | EPOLLPRI; 33362306a36Sopenharmony_ci return mask; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/** 33762306a36Sopenharmony_ci * event_read() - Callback for passing event data to userspace via read(). 33862306a36Sopenharmony_ci * @filp: The file we are reading from. 33962306a36Sopenharmony_ci * @buf: Pointer to userspace buffer to fill with one event. 34062306a36Sopenharmony_ci * @count: Number of bytes requested. Must be at least EC_ACPI_MAX_EVENT_SIZE. 34162306a36Sopenharmony_ci * @pos: File position pointer, irrelevant since we don't support seeking. 34262306a36Sopenharmony_ci * 34362306a36Sopenharmony_ci * Removes the first event from the queue, places it in the passed buffer. 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * If there are no events in the queue, then one of two things happens, 34662306a36Sopenharmony_ci * depending on if the file was opened in nonblocking mode: If in nonblocking 34762306a36Sopenharmony_ci * mode, then return -EAGAIN to say there's no data. If in blocking mode, then 34862306a36Sopenharmony_ci * block until an event is available. 34962306a36Sopenharmony_ci * 35062306a36Sopenharmony_ci * Return: Number of bytes placed in buffer, negative error code on failure. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic ssize_t event_read(struct file *filp, char __user *buf, size_t count, 35362306a36Sopenharmony_ci loff_t *pos) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct event_device_data *dev_data = filp->private_data; 35662306a36Sopenharmony_ci struct ec_event *event; 35762306a36Sopenharmony_ci ssize_t n_bytes_written = 0; 35862306a36Sopenharmony_ci int err; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* We only will give them the entire event at once */ 36162306a36Sopenharmony_ci if (count != 0 && count < EC_ACPI_MAX_EVENT_SIZE) 36262306a36Sopenharmony_ci return -EINVAL; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci spin_lock(&dev_data->queue_lock); 36562306a36Sopenharmony_ci while (event_queue_empty(dev_data->events)) { 36662306a36Sopenharmony_ci spin_unlock(&dev_data->queue_lock); 36762306a36Sopenharmony_ci if (filp->f_flags & O_NONBLOCK) 36862306a36Sopenharmony_ci return -EAGAIN; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci err = wait_event_interruptible(dev_data->wq, 37162306a36Sopenharmony_ci !event_queue_empty(dev_data->events) || 37262306a36Sopenharmony_ci !dev_data->exist); 37362306a36Sopenharmony_ci if (err) 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Device was removed as we waited? */ 37762306a36Sopenharmony_ci if (!dev_data->exist) 37862306a36Sopenharmony_ci return -ENODEV; 37962306a36Sopenharmony_ci spin_lock(&dev_data->queue_lock); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci event = event_queue_pop(dev_data->events); 38262306a36Sopenharmony_ci spin_unlock(&dev_data->queue_lock); 38362306a36Sopenharmony_ci n_bytes_written = ec_event_size(event); 38462306a36Sopenharmony_ci if (copy_to_user(buf, event, n_bytes_written)) 38562306a36Sopenharmony_ci n_bytes_written = -EFAULT; 38662306a36Sopenharmony_ci kfree(event); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return n_bytes_written; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int event_release(struct inode *inode, struct file *filp) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct event_device_data *dev_data = filp->private_data; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci atomic_set(&dev_data->available, 1); 39662306a36Sopenharmony_ci put_device(&dev_data->dev); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic const struct file_operations event_fops = { 40262306a36Sopenharmony_ci .open = event_open, 40362306a36Sopenharmony_ci .poll = event_poll, 40462306a36Sopenharmony_ci .read = event_read, 40562306a36Sopenharmony_ci .release = event_release, 40662306a36Sopenharmony_ci .llseek = no_llseek, 40762306a36Sopenharmony_ci .owner = THIS_MODULE, 40862306a36Sopenharmony_ci}; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/** 41162306a36Sopenharmony_ci * free_device_data() - Callback to free the event_device_data structure. 41262306a36Sopenharmony_ci * @d: The device embedded in our device data, which we have been ref counting. 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * This is called only after event_device_remove() has been called and all 41562306a36Sopenharmony_ci * userspace programs have called event_release() on all the open file 41662306a36Sopenharmony_ci * descriptors. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_cistatic void free_device_data(struct device *d) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct event_device_data *dev_data; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci dev_data = container_of(d, struct event_device_data, dev); 42362306a36Sopenharmony_ci event_queue_free(dev_data->events); 42462306a36Sopenharmony_ci kfree(dev_data); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic void hangup_device(struct event_device_data *dev_data) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci dev_data->exist = false; 43062306a36Sopenharmony_ci /* Wake up the waiting processes so they can close. */ 43162306a36Sopenharmony_ci wake_up_interruptible(&dev_data->wq); 43262306a36Sopenharmony_ci put_device(&dev_data->dev); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/** 43662306a36Sopenharmony_ci * event_device_add() - Callback when creating a new device. 43762306a36Sopenharmony_ci * @adev: ACPI device that we will be receiving events from. 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * This finds a free minor number for the device, allocates and initializes 44062306a36Sopenharmony_ci * some device data, and creates a new device and char dev node. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * The device data is freed in free_device_data(), which is called when 44362306a36Sopenharmony_ci * %dev_data->dev is release()ed. This happens after all references to 44462306a36Sopenharmony_ci * %dev_data->dev are dropped, which happens once both event_device_remove() 44562306a36Sopenharmony_ci * has been called and every open()ed file descriptor has been release()ed. 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_cistatic int event_device_add(struct acpi_device *adev) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct event_device_data *dev_data; 45262306a36Sopenharmony_ci int error, minor; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci minor = ida_alloc_max(&event_ida, EVENT_MAX_DEV-1, GFP_KERNEL); 45562306a36Sopenharmony_ci if (minor < 0) { 45662306a36Sopenharmony_ci error = minor; 45762306a36Sopenharmony_ci dev_err(&adev->dev, "Failed to find minor number: %d\n", error); 45862306a36Sopenharmony_ci return error; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); 46262306a36Sopenharmony_ci if (!dev_data) { 46362306a36Sopenharmony_ci error = -ENOMEM; 46462306a36Sopenharmony_ci goto free_minor; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Initialize the device data. */ 46862306a36Sopenharmony_ci adev->driver_data = dev_data; 46962306a36Sopenharmony_ci dev_data->events = event_queue_new(queue_size); 47062306a36Sopenharmony_ci if (!dev_data->events) { 47162306a36Sopenharmony_ci kfree(dev_data); 47262306a36Sopenharmony_ci error = -ENOMEM; 47362306a36Sopenharmony_ci goto free_minor; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci spin_lock_init(&dev_data->queue_lock); 47662306a36Sopenharmony_ci init_waitqueue_head(&dev_data->wq); 47762306a36Sopenharmony_ci dev_data->exist = true; 47862306a36Sopenharmony_ci atomic_set(&dev_data->available, 1); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Initialize the device. */ 48162306a36Sopenharmony_ci dev_data->dev.devt = MKDEV(event_major, minor); 48262306a36Sopenharmony_ci dev_data->dev.class = &event_class; 48362306a36Sopenharmony_ci dev_data->dev.release = free_device_data; 48462306a36Sopenharmony_ci dev_set_name(&dev_data->dev, EVENT_DEV_NAME_FMT, minor); 48562306a36Sopenharmony_ci device_initialize(&dev_data->dev); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Initialize the character device, and add it to userspace. */ 48862306a36Sopenharmony_ci cdev_init(&dev_data->cdev, &event_fops); 48962306a36Sopenharmony_ci error = cdev_device_add(&dev_data->cdev, &dev_data->dev); 49062306a36Sopenharmony_ci if (error) 49162306a36Sopenharmony_ci goto free_dev_data; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cifree_dev_data: 49662306a36Sopenharmony_ci hangup_device(dev_data); 49762306a36Sopenharmony_cifree_minor: 49862306a36Sopenharmony_ci ida_simple_remove(&event_ida, minor); 49962306a36Sopenharmony_ci return error; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void event_device_remove(struct acpi_device *adev) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct event_device_data *dev_data = adev->driver_data; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci cdev_device_del(&dev_data->cdev, &dev_data->dev); 50762306a36Sopenharmony_ci ida_simple_remove(&event_ida, MINOR(dev_data->dev.devt)); 50862306a36Sopenharmony_ci hangup_device(dev_data); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic const struct acpi_device_id event_acpi_ids[] = { 51262306a36Sopenharmony_ci { "GOOG000D", 0 }, 51362306a36Sopenharmony_ci { } 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, event_acpi_ids); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic struct acpi_driver event_driver = { 51862306a36Sopenharmony_ci .name = DRV_NAME, 51962306a36Sopenharmony_ci .class = DRV_NAME, 52062306a36Sopenharmony_ci .ids = event_acpi_ids, 52162306a36Sopenharmony_ci .ops = { 52262306a36Sopenharmony_ci .add = event_device_add, 52362306a36Sopenharmony_ci .notify = event_device_notify, 52462306a36Sopenharmony_ci .remove = event_device_remove, 52562306a36Sopenharmony_ci }, 52662306a36Sopenharmony_ci .owner = THIS_MODULE, 52762306a36Sopenharmony_ci}; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int __init event_module_init(void) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci dev_t dev_num = 0; 53262306a36Sopenharmony_ci int ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = class_register(&event_class); 53562306a36Sopenharmony_ci if (ret) { 53662306a36Sopenharmony_ci pr_err(DRV_NAME ": Failed registering class: %d\n", ret); 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* Request device numbers, starting with minor=0. Save the major num. */ 54162306a36Sopenharmony_ci ret = alloc_chrdev_region(&dev_num, 0, EVENT_MAX_DEV, EVENT_DEV_NAME); 54262306a36Sopenharmony_ci if (ret) { 54362306a36Sopenharmony_ci pr_err(DRV_NAME ": Failed allocating dev numbers: %d\n", ret); 54462306a36Sopenharmony_ci goto destroy_class; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci event_major = MAJOR(dev_num); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = acpi_bus_register_driver(&event_driver); 54962306a36Sopenharmony_ci if (ret < 0) { 55062306a36Sopenharmony_ci pr_err(DRV_NAME ": Failed registering driver: %d\n", ret); 55162306a36Sopenharmony_ci goto unregister_region; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ciunregister_region: 55762306a36Sopenharmony_ci unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV); 55862306a36Sopenharmony_cidestroy_class: 55962306a36Sopenharmony_ci class_unregister(&event_class); 56062306a36Sopenharmony_ci ida_destroy(&event_ida); 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void __exit event_module_exit(void) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci acpi_bus_unregister_driver(&event_driver); 56762306a36Sopenharmony_ci unregister_chrdev_region(MKDEV(event_major, 0), EVENT_MAX_DEV); 56862306a36Sopenharmony_ci class_unregister(&event_class); 56962306a36Sopenharmony_ci ida_destroy(&event_ida); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cimodule_init(event_module_init); 57362306a36Sopenharmony_cimodule_exit(event_module_exit); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ciMODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); 57662306a36Sopenharmony_ciMODULE_DESCRIPTION("Wilco EC ACPI event driver"); 57762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 57862306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 579