Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebe99d61 authored by Rui Miguel Silva's avatar Rui Miguel Silva Committed by Greg Kroah-Hartman
Browse files

greybus: svc: add key event handling



Add a new input device associated with the SVC to handle key events.
This new events are transfer over a new greybus svc operation which is
unidirectional.

It was selected the KEY_A for representing the KEY_ARA_BUTTON key code.

Signed-off-by: default avatarRui Miguel Silva <rui.silva@linaro.org>
Reviewed-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 4b874134
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -781,6 +781,7 @@ struct gb_spi_transfer_response {
#define GB_SVC_TYPE_ROUTE_DESTROY	0x0c
#define GB_SVC_TYPE_INTF_SET_PWRM	0x10
#define GB_SVC_TYPE_INTF_EJECT		0x11
#define GB_SVC_TYPE_KEY_EVENT		0x12

/*
 * SVC version request/response has the same payload as
@@ -930,6 +931,15 @@ struct gb_svc_intf_set_pwrm_response {
	__le16	result_code;
} __packed;

struct gb_svc_key_event_request {
	__le16  key_code;
#define GB_KEYCODE_ARA         0x00

	__u8    key_event;
#define GB_SVC_KEY_RELEASED    0x00
#define GB_SVC_KEY_PRESSED     0x01
} __packed;

/* RAW */

/* Version of the Greybus raw protocol we support */
+108 −6
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 * Released under the GPLv2 only.
 */

#include <linux/input.h>
#include <linux/workqueue.h>

#include "greybus.h"
@@ -15,6 +16,7 @@
#define CPORT_FLAGS_CSD_N       BIT(1)
#define CPORT_FLAGS_CSV_N       BIT(2)

#define SVC_KEY_ARA_BUTTON	KEY_A

struct gb_svc_deferred_request {
	struct work_struct work;
@@ -420,6 +422,13 @@ static int gb_svc_hello(struct gb_operation *op)
		return ret;
	}

	ret = input_register_device(svc->input);
	if (ret) {
		dev_err(&svc->dev, "failed to register input: %d\n", ret);
		device_del(&svc->dev);
		return ret;
	}

	return 0;
}

@@ -690,6 +699,53 @@ static int gb_svc_intf_reset_recv(struct gb_operation *op)
	return 0;
}

static int gb_svc_key_code_map(struct gb_svc *svc, u16 key_code, u16 *code)
{
	switch (key_code) {
	case GB_KEYCODE_ARA:
		*code = SVC_KEY_ARA_BUTTON;
		break;
	default:
		dev_warn(&svc->dev, "unknown keycode received: %u\n", key_code);
		return -EINVAL;
	}

	return 0;
}

static int gb_svc_key_event_recv(struct gb_operation *op)
{
	struct gb_svc *svc = op->connection->private;
	struct gb_message *request = op->request;
	struct gb_svc_key_event_request *key;
	u16 code;
	u8 event;
	int ret;

	if (request->payload_size < sizeof(*key)) {
		dev_warn(&svc->dev, "short key request received (%zu < %zu)\n",
			 request->payload_size, sizeof(*key));
		return -EINVAL;
	}

	key = request->payload;

	ret = gb_svc_key_code_map(svc, le16_to_cpu(key->key_code), &code);
	if (ret < 0)
		return ret;

	event = key->key_event;
	if ((event != GB_SVC_KEY_PRESSED) && (event != GB_SVC_KEY_RELEASED)) {
		dev_warn(&svc->dev, "unknown key event received: %u\n", event);
		return -EINVAL;
	}

	input_report_key(svc->input, code, (event == GB_SVC_KEY_PRESSED));
	input_sync(svc->input);

	return 0;
}

static int gb_svc_request_handler(struct gb_operation *op)
{
	struct gb_connection *connection = op->connection;
@@ -745,12 +801,42 @@ static int gb_svc_request_handler(struct gb_operation *op)
		return gb_svc_intf_hot_unplug_recv(op);
	case GB_SVC_TYPE_INTF_RESET:
		return gb_svc_intf_reset_recv(op);
	case GB_SVC_TYPE_KEY_EVENT:
		return gb_svc_key_event_recv(op);
	default:
		dev_warn(&svc->dev, "unsupported request 0x%02x\n", type);
		return -EINVAL;
	}
}

static struct input_dev *gb_svc_input_create(struct gb_svc *svc)
{
	struct input_dev *input_dev;

	input_dev = input_allocate_device();
	if (!input_dev)
		return ERR_PTR(-ENOMEM);

	input_dev->name = dev_name(&svc->dev);
	svc->input_phys = kasprintf(GFP_KERNEL, "greybus-%s/input0",
				    input_dev->name);
	if (!svc->input_phys)
		goto err_free_input;

	input_dev->phys = svc->input_phys;
	input_dev->dev.parent = &svc->dev;

	input_set_drvdata(input_dev, svc);

	input_set_capability(input_dev, EV_KEY, SVC_KEY_ARA_BUTTON);

	return input_dev;

err_free_input:
	input_free_device(svc->input);
	return ERR_PTR(-ENOMEM);
}

static void gb_svc_release(struct device *dev)
{
	struct gb_svc *svc = to_gb_svc(dev);
@@ -759,6 +845,7 @@ static void gb_svc_release(struct device *dev)
		gb_connection_destroy(svc->connection);
	ida_destroy(&svc->device_id_map);
	destroy_workqueue(svc->wq);
	kfree(svc->input_phys);
	kfree(svc);
}

@@ -794,17 +881,29 @@ struct gb_svc *gb_svc_create(struct gb_host_device *hd)
	svc->state = GB_SVC_STATE_RESET;
	svc->hd = hd;

	svc->input = gb_svc_input_create(svc);
	if (IS_ERR(svc->input)) {
		dev_err(&svc->dev, "failed to create input device: %ld\n",
			PTR_ERR(svc->input));
		goto err_put_device;
	}

	svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
							GREYBUS_PROTOCOL_SVC);
	if (!svc->connection) {
		dev_err(&svc->dev, "failed to create connection\n");
		put_device(&svc->dev);
		return NULL;
		goto err_free_input;
	}

	svc->connection->private = svc;

	return svc;

err_free_input:
	input_free_device(svc->input);
err_put_device:
	put_device(&svc->dev);
	return NULL;
}

int gb_svc_add(struct gb_svc *svc)
@@ -825,13 +924,16 @@ int gb_svc_add(struct gb_svc *svc)

void gb_svc_del(struct gb_svc *svc)
{
	gb_connection_disable(svc->connection);

	/*
	 * The SVC device may have been registered from the request handler.
	 * The SVC device and input device may have been registered
	 * from the request handler.
	 */
	if (device_is_registered(&svc->dev))
	if (device_is_registered(&svc->dev)) {
		input_unregister_device(svc->input);
		device_del(&svc->dev);

	gb_connection_disable(svc->connection);
	}

	flush_workqueue(svc->wq);
}
+3 −0
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ struct gb_svc {

	u8 protocol_major;
	u8 protocol_minor;

	struct input_dev        *input;
	char                    *input_phys;
};
#define to_gb_svc(d) container_of(d, struct gb_svc, d)