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