All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <gregkh@linuxfoundation.org>
To: Arnd Bergmann <arnd@arndb.de>, linux-kernel@vger.kernel.org
Cc: Johan Hovold <johan@hovoldconsulting.com>,
	Rui Miguel Silva <rmfrfs@gmail.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Sandeep Patil <sspatil@google.com>,
	Matt Porter <mporter@kernel.crashing.org>,
	John Stultz <john.stultz@linaro.org>,
	Rob Herring <robh@kernel.org>,
	Viresh Kumar <viresh.kumar@linaro.org>,
	Alex Elder <elder@linaro.org>, David Lin <dtwlin@google.com>,
	"Bryan O'Donoghue" <pure.logic@nexus-software.ie>,
	Vaibhav Agarwal <vaibhav.agarwal@linaro.org>,
	Mark Greer <mgreer@animalcreek.com>
Subject: [patch 18/32] greybus: raw driver
Date: Fri, 16 Sep 2016 16:11:15 +0200	[thread overview]
Message-ID: <20160916141115.GF1252@kroah.com> (raw)
In-Reply-To: <20160916064058.GA17821@kroah.com>


This driver implements the Greybus raw protocol.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/greybus/raw.c |  381 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 381 insertions(+)

--- /dev/null
+++ b/drivers/greybus/raw.c
@@ -0,0 +1,381 @@
+/*
+ * Greybus driver for the Raw protocol
+ *
+ * Copyright 2015 Google Inc.
+ * Copyright 2015 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sizes.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/uaccess.h>
+
+#include "greybus.h"
+
+struct gb_raw {
+	struct gb_connection *connection;
+
+	struct list_head list;
+	int list_data;
+	struct mutex list_lock;
+	dev_t dev;
+	struct cdev cdev;
+	struct device *device;
+};
+
+struct raw_data {
+	struct list_head entry;
+	u32 len;
+	u8 data[0];
+};
+
+static struct class *raw_class;
+static int raw_major;
+static const struct file_operations raw_fops;
+static DEFINE_IDA(minors);
+
+/* Number of minor devices this driver supports */
+#define NUM_MINORS	256
+
+/* Maximum size of any one send data buffer we support */
+#define MAX_PACKET_SIZE	(PAGE_SIZE * 2)
+
+/*
+ * Maximum size of the data in the receive buffer we allow before we start to
+ * drop messages on the floor
+ */
+#define MAX_DATA_SIZE	(MAX_PACKET_SIZE * 8)
+
+/*
+ * Add the raw data message to the list of received messages.
+ */
+static int receive_data(struct gb_raw *raw, u32 len, u8 *data)
+{
+	struct raw_data *raw_data;
+	struct device *dev = &raw->connection->bundle->dev;
+	int retval = 0;
+
+	if (len > MAX_PACKET_SIZE) {
+		dev_err(dev, "Too big of a data packet, rejected\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&raw->list_lock);
+	if ((raw->list_data + len) > MAX_DATA_SIZE) {
+		dev_err(dev, "Too much data in receive buffer, now dropping packets\n");
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	raw_data = kmalloc(sizeof(*raw_data) + len, GFP_KERNEL);
+	if (!raw_data) {
+		retval = -ENOMEM;
+		goto exit;
+	}
+
+	raw->list_data += len;
+	raw_data->len = len;
+	memcpy(&raw_data->data[0], data, len);
+
+	list_add_tail(&raw_data->entry, &raw->list);
+exit:
+	mutex_unlock(&raw->list_lock);
+	return retval;
+}
+
+static int gb_raw_request_handler(struct gb_operation *op)
+{
+	struct gb_connection *connection = op->connection;
+	struct device *dev = &connection->bundle->dev;
+	struct gb_raw *raw = greybus_get_drvdata(connection->bundle);
+	struct gb_raw_send_request *receive;
+	u32 len;
+
+	if (op->type != GB_RAW_TYPE_SEND) {
+		dev_err(dev, "unknown request type 0x%02x\n", op->type);
+		return -EINVAL;
+	}
+
+	/* Verify size of payload */
+	if (op->request->payload_size < sizeof(*receive)) {
+		dev_err(dev, "raw receive request too small (%zu < %zu)\n",
+			op->request->payload_size, sizeof(*receive));
+		return -EINVAL;
+	}
+	receive = op->request->payload;
+	len = le32_to_cpu(receive->len);
+	if (len != (int)(op->request->payload_size - sizeof(__le32))) {
+		dev_err(dev, "raw receive request wrong size %d vs %d\n", len,
+			(int)(op->request->payload_size - sizeof(__le32)));
+		return -EINVAL;
+	}
+	if (len == 0) {
+		dev_err(dev, "raw receive request of 0 bytes?\n");
+		return -EINVAL;
+	}
+
+	return receive_data(raw, len, receive->data);
+}
+
+static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
+{
+	struct gb_connection *connection = raw->connection;
+	struct gb_raw_send_request *request;
+	int retval;
+
+	request = kmalloc(len + sizeof(*request), GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	if (copy_from_user(&request->data[0], data, len)) {
+		kfree(request);
+		return -EFAULT;
+	}
+
+	request->len = cpu_to_le32(len);
+
+	retval = gb_operation_sync(connection, GB_RAW_TYPE_SEND,
+				   request, len + sizeof(*request),
+				   NULL, 0);
+
+	kfree(request);
+	return retval;
+}
+
+static int gb_raw_probe(struct gb_bundle *bundle,
+			const struct greybus_bundle_id *id)
+{
+	struct greybus_descriptor_cport *cport_desc;
+	struct gb_connection *connection;
+	struct gb_raw *raw;
+	int retval;
+	int minor;
+
+	if (bundle->num_cports != 1)
+		return -ENODEV;
+
+	cport_desc = &bundle->cport_desc[0];
+	if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)
+		return -ENODEV;
+
+	raw = kzalloc(sizeof(*raw), GFP_KERNEL);
+	if (!raw)
+		return -ENOMEM;
+
+	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
+					  gb_raw_request_handler);
+	if (IS_ERR(connection)) {
+		retval = PTR_ERR(connection);
+		goto error_free;
+	}
+
+	INIT_LIST_HEAD(&raw->list);
+	mutex_init(&raw->list_lock);
+
+	raw->connection = connection;
+	greybus_set_drvdata(bundle, raw);
+
+	minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
+	if (minor < 0) {
+		retval = minor;
+		goto error_connection_destroy;
+	}
+
+	raw->dev = MKDEV(raw_major, minor);
+	cdev_init(&raw->cdev, &raw_fops);
+
+	retval = gb_connection_enable(connection);
+	if (retval)
+		goto error_remove_ida;
+
+	retval = cdev_add(&raw->cdev, raw->dev, 1);
+	if (retval)
+		goto error_connection_disable;
+
+	raw->device = device_create(raw_class, &connection->bundle->dev,
+				    raw->dev, raw, "gb!raw%d", minor);
+	if (IS_ERR(raw->device)) {
+		retval = PTR_ERR(raw->device);
+		goto error_del_cdev;
+	}
+
+	return 0;
+
+error_del_cdev:
+	cdev_del(&raw->cdev);
+
+error_connection_disable:
+	gb_connection_disable(connection);
+
+error_remove_ida:
+	ida_simple_remove(&minors, minor);
+
+error_connection_destroy:
+	gb_connection_destroy(connection);
+
+error_free:
+	kfree(raw);
+	return retval;
+}
+
+static void gb_raw_disconnect(struct gb_bundle *bundle)
+{
+	struct gb_raw *raw = greybus_get_drvdata(bundle);
+	struct gb_connection *connection = raw->connection;
+	struct raw_data *raw_data;
+	struct raw_data *temp;
+
+	// FIXME - handle removing a connection when the char device node is open.
+	device_destroy(raw_class, raw->dev);
+	cdev_del(&raw->cdev);
+	gb_connection_disable(connection);
+	ida_simple_remove(&minors, MINOR(raw->dev));
+	gb_connection_destroy(connection);
+
+	mutex_lock(&raw->list_lock);
+	list_for_each_entry_safe(raw_data, temp, &raw->list, entry) {
+		list_del(&raw_data->entry);
+		kfree(raw_data);
+	}
+	mutex_unlock(&raw->list_lock);
+
+	kfree(raw);
+}
+
+/*
+ * Character device node interfaces.
+ *
+ * Note, we are using read/write to only allow a single read/write per message.
+ * This means for read(), you have to provide a big enough buffer for the full
+ * message to be copied into.  If the buffer isn't big enough, the read() will
+ * fail with -ENOSPC.
+ */
+
+static int raw_open(struct inode *inode, struct file *file)
+{
+	struct cdev *cdev = inode->i_cdev;
+	struct gb_raw *raw = container_of(cdev, struct gb_raw, cdev);
+
+	file->private_data = raw;
+	return 0;
+}
+
+static ssize_t raw_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct gb_raw *raw = file->private_data;
+	int retval;
+
+	if (!count)
+		return 0;
+
+	if (count > MAX_PACKET_SIZE)
+		return -E2BIG;
+
+	retval = gb_raw_send(raw, count, buf);
+	if (retval)
+		return retval;
+
+	return count;
+}
+
+static ssize_t raw_read(struct file *file, char __user *buf, size_t count,
+			loff_t *ppos)
+{
+	struct gb_raw *raw = file->private_data;
+	int retval = 0;
+	struct raw_data *raw_data;
+
+	mutex_lock(&raw->list_lock);
+	if (list_empty(&raw->list))
+		goto exit;
+
+	raw_data = list_first_entry(&raw->list, struct raw_data, entry);
+	if (raw_data->len > count) {
+		retval = -ENOSPC;
+		goto exit;
+	}
+
+	if (copy_to_user(buf, &raw_data->data[0], raw_data->len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+
+	list_del(&raw_data->entry);
+	raw->list_data -= raw_data->len;
+	retval = raw_data->len;
+	kfree(raw_data);
+
+exit:
+	mutex_unlock(&raw->list_lock);
+	return retval;
+}
+
+static const struct file_operations raw_fops = {
+	.owner		= THIS_MODULE,
+	.write		= raw_write,
+	.read		= raw_read,
+	.open		= raw_open,
+	.llseek		= noop_llseek,
+};
+
+static const struct greybus_bundle_id gb_raw_id_table[] = {
+	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
+	{ }
+};
+MODULE_DEVICE_TABLE(greybus, gb_raw_id_table);
+
+static struct greybus_driver gb_raw_driver = {
+	.name		= "raw",
+	.probe		= gb_raw_probe,
+	.disconnect	= gb_raw_disconnect,
+	.id_table	= gb_raw_id_table,
+};
+
+static int raw_init(void)
+{
+	dev_t dev;
+	int retval;
+
+	raw_class = class_create(THIS_MODULE, "gb_raw");
+	if (IS_ERR(raw_class)) {
+		retval = PTR_ERR(raw_class);
+		goto error_class;
+	}
+
+	retval = alloc_chrdev_region(&dev, 0, NUM_MINORS, "gb_raw");
+	if (retval < 0)
+		goto error_chrdev;
+
+	raw_major = MAJOR(dev);
+
+	retval = greybus_register(&gb_raw_driver);
+	if (retval)
+		goto error_gb;
+
+	return 0;
+
+error_gb:
+	unregister_chrdev_region(dev, NUM_MINORS);
+error_chrdev:
+	class_destroy(raw_class);
+error_class:
+	return retval;
+}
+module_init(raw_init);
+
+static void __exit raw_exit(void)
+{
+	greybus_deregister(&gb_raw_driver);
+	unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS);
+	class_destroy(raw_class);
+	ida_destroy(&minors);
+}
+module_exit(raw_exit);
+
+MODULE_LICENSE("GPL v2");

  parent reply	other threads:[~2016-09-16 14:11 UTC|newest]

Thread overview: 84+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-14 10:09 [GIT PULL] Greybus driver subsystem for 4.9-rc1 Greg KH
2016-09-14 17:36 ` Mark Rutland
2016-09-14 17:36   ` Mark Rutland
2016-09-14 18:07   ` Greg KH
2016-09-14 18:07     ` Greg KH
2016-09-14 18:29     ` Greg KH
2016-09-14 18:29       ` Greg KH
2016-09-14 19:05       ` Joe Perches
2016-09-14 19:05         ` Joe Perches
2016-09-15  9:35       ` Bryan O'Donoghue
2016-09-15  9:35         ` Bryan O'Donoghue
2016-09-15 10:13         ` Mark Rutland
2016-09-15 10:13           ` Mark Rutland
2016-09-15 10:35           ` Bryan O'Donoghue
2016-09-15 10:35             ` Bryan O'Donoghue
2016-09-15 10:47             ` Bryan O'Donoghue
2016-09-15 10:47               ` Bryan O'Donoghue
2016-09-15 11:20             ` Mark Rutland
2016-09-15 11:20               ` Mark Rutland
2016-09-15 11:48               ` Bryan O'Donoghue
2016-09-15 11:48                 ` Bryan O'Donoghue
2016-09-15 12:46                 ` Mark Rutland
2016-09-15 12:46                   ` Mark Rutland
2016-09-15 15:40                   ` Bryan O'Donoghue
2016-09-15 15:40                     ` Bryan O'Donoghue
2016-09-15 15:47                     ` Mark Rutland
2016-09-15 15:47                       ` Mark Rutland
2016-09-15 16:09                       ` Bryan O'Donoghue
2016-09-15 16:09                         ` Bryan O'Donoghue
2016-09-14 20:07     ` Rob Herring
2016-09-14 20:07       ` Rob Herring
2016-09-15 10:17       ` Greg KH
2016-09-15 10:17         ` Greg KH
2016-09-15 11:02         ` Bryan O'Donoghue
2016-09-15 11:02           ` Bryan O'Donoghue
     [not found] ` <20160915122141.650632149@bubbles.kroah.org>
     [not found]   ` <20160915122234.640367870@bubbles.kroah.org>
2016-09-15 13:16     ` [patch 11/32] greybus: camera driver Laurent Pinchart
2016-09-15 14:45 ` [GIT PULL] Greybus driver subsystem for 4.9-rc1 Mark Brown
2016-09-16  6:05   ` Greg KH
2016-09-16 10:18     ` Mark Brown
2016-09-16 13:22       ` Greg KH
2016-09-16 14:24         ` Greg KH
2016-09-20  6:41           ` Greg KH
2016-09-20  7:12             ` Vaibhav Agarwal
2016-09-16 12:18     ` Arnd Bergmann
2016-09-21 13:02     ` Mark Rutland
2016-09-21 14:13       ` Greg KH
2016-09-16  6:40 ` [patch 00/32] Greybus driver subsystem Greg KH
2016-09-16  6:41   ` [patch 02/32] greybus: interface control logic Greg KH
2016-09-16 13:22   ` [patch 03/32] greybus: operations logic Greg KH
2016-09-16 13:23   ` [patch 04/32] greybus: host driver framework Greg KH
2016-09-16 13:23   ` [patch 05/32] greybus: trace.h Greg KH
2016-09-16 13:23   ` [patch 06/32] greybus: svc driver/watchdog Greg KH
2016-09-16 13:23   ` [patch 07/32] greybus: core code Greg KH
2016-09-16 13:24   ` [patch 08/32] greybus: bootrom driver Greg KH
2016-09-16 13:24   ` [patch 09/32] greybus: firmware download class driver Greg KH
2016-09-16 13:24   ` [patch 10/32] greybus: audio driver Greg KH
2016-09-16 13:25   ` [patch 11/32] greybus: camera driver Greg KH
2016-09-16 13:25   ` [patch 12/32] greybus: es2 host driver Greg KH
2016-10-07 13:43     ` Pavel Machek
2016-09-16 14:09   ` [patch 13/32] greybus: HID driver Greg KH
2016-09-16 14:10   ` [patch 14/32] greybus: LED driver Greg KH
2016-10-07 13:36     ` Pavel Machek
2016-10-07 13:41       ` Greg KH
2016-09-16 14:10   ` [patch 15/32] greybus: logging driver Greg KH
2016-09-16 14:10   ` [patch 16/32] greybus: loopback driver Greg KH
2016-09-16 14:10   ` [patch 17/32] greybus: power supply driver Greg KH
2016-10-07 13:49     ` Pavel Machek
2016-10-07 14:12       ` Greg KH
2016-10-07 18:15         ` Pavel Machek
2016-09-16 14:11   ` Greg KH [this message]
2016-09-16 14:11   ` [patch 19/32] greybus: timesync driver Greg KH
2016-09-16 14:11   ` [patch 20/32] greybus: vibrator driver Greg KH
2016-09-16 14:19   ` [patch 21/32] greybus: arche platform driver Greg KH
2016-09-16 14:20   ` [patch 22/32] greybus: bridged phy bus code Greg KH
2016-09-16 14:20   ` [patch 23/32] greybus: bridged phy gpio driver Greg KH
2016-09-16 14:20   ` [patch 24/32] greybus: bridged phy i2c driver Greg KH
2016-09-16 14:20   ` [patch 25/32] greybus: bridged phy pwm driver Greg KH
2016-09-16 14:21   ` [patch 26/32] greybus: bridged phy sdio driver Greg KH
2016-09-16 14:21   ` [patch 27/32] greybus: bridged phy spi driver Greg KH
2016-09-16 14:21   ` [patch 28/32] greybus: bridged phy uart driver Greg KH
2016-09-16 14:21   ` [patch 29/32] greybus: bridged phy usb driver Greg KH
2016-09-16 14:22   ` [patch 30/32] greybus: tools Greg KH
2016-09-16 14:22   ` [patch 31/32] greybus: documentation Greg KH
2016-09-16 14:22   ` [patch 32/32] greybus: add to the build Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160916141115.GF1252@kroah.com \
    --to=gregkh@linuxfoundation.org \
    --cc=arnd@arndb.de \
    --cc=dtwlin@google.com \
    --cc=elder@linaro.org \
    --cc=johan@hovoldconsulting.com \
    --cc=john.stultz@linaro.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mgreer@animalcreek.com \
    --cc=mporter@kernel.crashing.org \
    --cc=pure.logic@nexus-software.ie \
    --cc=rmfrfs@gmail.com \
    --cc=robh@kernel.org \
    --cc=sspatil@google.com \
    --cc=vaibhav.agarwal@linaro.org \
    --cc=viresh.kumar@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.