brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · 71de677 Raw
382 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Greybus driver for the Raw protocol4 *5 * Copyright 2015 Google Inc.6 * Copyright 2015 Linaro Ltd.7 */8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/slab.h>11#include <linux/sizes.h>12#include <linux/cdev.h>13#include <linux/fs.h>14#include <linux/idr.h>15#include <linux/uaccess.h>16#include <linux/greybus.h>17 18struct gb_raw {19	struct gb_connection *connection;20 21	struct list_head list;22	int list_data;23	struct mutex list_lock;24	dev_t dev;25	struct cdev cdev;26	struct device *device;27};28 29struct raw_data {30	struct list_head entry;31	u32 len;32	u8 data[] __counted_by(len);33};34 35static const struct class raw_class = {36	.name = "gb_raw",37};38 39static int raw_major;40static const struct file_operations raw_fops;41static DEFINE_IDA(minors);42 43/* Number of minor devices this driver supports */44#define NUM_MINORS	25645 46/* Maximum size of any one send data buffer we support */47#define MAX_PACKET_SIZE	(PAGE_SIZE * 2)48 49/*50 * Maximum size of the data in the receive buffer we allow before we start to51 * drop messages on the floor52 */53#define MAX_DATA_SIZE	(MAX_PACKET_SIZE * 8)54 55/*56 * Add the raw data message to the list of received messages.57 */58static int receive_data(struct gb_raw *raw, u32 len, u8 *data)59{60	struct raw_data *raw_data;61	struct device *dev = &raw->connection->bundle->dev;62	int retval = 0;63 64	if (len > MAX_PACKET_SIZE) {65		dev_err(dev, "Too big of a data packet, rejected\n");66		return -EINVAL;67	}68 69	mutex_lock(&raw->list_lock);70	if ((raw->list_data + len) > MAX_DATA_SIZE) {71		dev_err(dev, "Too much data in receive buffer, now dropping packets\n");72		retval = -EINVAL;73		goto exit;74	}75 76	raw_data = kmalloc(struct_size(raw_data, data, len), GFP_KERNEL);77	if (!raw_data) {78		retval = -ENOMEM;79		goto exit;80	}81 82	raw->list_data += len;83	raw_data->len = len;84	memcpy(&raw_data->data[0], data, len);85 86	list_add_tail(&raw_data->entry, &raw->list);87exit:88	mutex_unlock(&raw->list_lock);89	return retval;90}91 92static int gb_raw_request_handler(struct gb_operation *op)93{94	struct gb_connection *connection = op->connection;95	struct device *dev = &connection->bundle->dev;96	struct gb_raw *raw = greybus_get_drvdata(connection->bundle);97	struct gb_raw_send_request *receive;98	u32 len;99 100	if (op->type != GB_RAW_TYPE_SEND) {101		dev_err(dev, "unknown request type 0x%02x\n", op->type);102		return -EINVAL;103	}104 105	/* Verify size of payload */106	if (op->request->payload_size < sizeof(*receive)) {107		dev_err(dev, "raw receive request too small (%zu < %zu)\n",108			op->request->payload_size, sizeof(*receive));109		return -EINVAL;110	}111	receive = op->request->payload;112	len = le32_to_cpu(receive->len);113	if (len != (int)(op->request->payload_size - sizeof(__le32))) {114		dev_err(dev, "raw receive request wrong size %d vs %d\n", len,115			(int)(op->request->payload_size - sizeof(__le32)));116		return -EINVAL;117	}118	if (len == 0) {119		dev_err(dev, "raw receive request of 0 bytes?\n");120		return -EINVAL;121	}122 123	return receive_data(raw, len, receive->data);124}125 126static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)127{128	struct gb_connection *connection = raw->connection;129	struct gb_raw_send_request *request;130	int retval;131 132	request = kmalloc(len + sizeof(*request), GFP_KERNEL);133	if (!request)134		return -ENOMEM;135 136	if (copy_from_user(&request->data[0], data, len)) {137		kfree(request);138		return -EFAULT;139	}140 141	request->len = cpu_to_le32(len);142 143	retval = gb_operation_sync(connection, GB_RAW_TYPE_SEND,144				   request, len + sizeof(*request),145				   NULL, 0);146 147	kfree(request);148	return retval;149}150 151static int gb_raw_probe(struct gb_bundle *bundle,152			const struct greybus_bundle_id *id)153{154	struct greybus_descriptor_cport *cport_desc;155	struct gb_connection *connection;156	struct gb_raw *raw;157	int retval;158	int minor;159 160	if (bundle->num_cports != 1)161		return -ENODEV;162 163	cport_desc = &bundle->cport_desc[0];164	if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)165		return -ENODEV;166 167	raw = kzalloc(sizeof(*raw), GFP_KERNEL);168	if (!raw)169		return -ENOMEM;170 171	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),172					  gb_raw_request_handler);173	if (IS_ERR(connection)) {174		retval = PTR_ERR(connection);175		goto error_free;176	}177 178	INIT_LIST_HEAD(&raw->list);179	mutex_init(&raw->list_lock);180 181	raw->connection = connection;182	greybus_set_drvdata(bundle, raw);183 184	minor = ida_alloc(&minors, GFP_KERNEL);185	if (minor < 0) {186		retval = minor;187		goto error_connection_destroy;188	}189 190	raw->dev = MKDEV(raw_major, minor);191	cdev_init(&raw->cdev, &raw_fops);192 193	retval = gb_connection_enable(connection);194	if (retval)195		goto error_remove_ida;196 197	retval = cdev_add(&raw->cdev, raw->dev, 1);198	if (retval)199		goto error_connection_disable;200 201	raw->device = device_create(&raw_class, &connection->bundle->dev,202				    raw->dev, raw, "gb!raw%d", minor);203	if (IS_ERR(raw->device)) {204		retval = PTR_ERR(raw->device);205		goto error_del_cdev;206	}207 208	return 0;209 210error_del_cdev:211	cdev_del(&raw->cdev);212 213error_connection_disable:214	gb_connection_disable(connection);215 216error_remove_ida:217	ida_free(&minors, minor);218 219error_connection_destroy:220	gb_connection_destroy(connection);221 222error_free:223	kfree(raw);224	return retval;225}226 227static void gb_raw_disconnect(struct gb_bundle *bundle)228{229	struct gb_raw *raw = greybus_get_drvdata(bundle);230	struct gb_connection *connection = raw->connection;231	struct raw_data *raw_data;232	struct raw_data *temp;233 234	// FIXME - handle removing a connection when the char device node is open.235	device_destroy(&raw_class, raw->dev);236	cdev_del(&raw->cdev);237	gb_connection_disable(connection);238	ida_free(&minors, MINOR(raw->dev));239	gb_connection_destroy(connection);240 241	mutex_lock(&raw->list_lock);242	list_for_each_entry_safe(raw_data, temp, &raw->list, entry) {243		list_del(&raw_data->entry);244		kfree(raw_data);245	}246	mutex_unlock(&raw->list_lock);247 248	kfree(raw);249}250 251/*252 * Character device node interfaces.253 *254 * Note, we are using read/write to only allow a single read/write per message.255 * This means for read(), you have to provide a big enough buffer for the full256 * message to be copied into.  If the buffer isn't big enough, the read() will257 * fail with -ENOSPC.258 */259 260static int raw_open(struct inode *inode, struct file *file)261{262	struct cdev *cdev = inode->i_cdev;263	struct gb_raw *raw = container_of(cdev, struct gb_raw, cdev);264 265	file->private_data = raw;266	return 0;267}268 269static ssize_t raw_write(struct file *file, const char __user *buf,270			 size_t count, loff_t *ppos)271{272	struct gb_raw *raw = file->private_data;273	int retval;274 275	if (!count)276		return 0;277 278	if (count > MAX_PACKET_SIZE)279		return -E2BIG;280 281	retval = gb_raw_send(raw, count, buf);282	if (retval)283		return retval;284 285	return count;286}287 288static ssize_t raw_read(struct file *file, char __user *buf, size_t count,289			loff_t *ppos)290{291	struct gb_raw *raw = file->private_data;292	int retval = 0;293	struct raw_data *raw_data;294 295	mutex_lock(&raw->list_lock);296	if (list_empty(&raw->list))297		goto exit;298 299	raw_data = list_first_entry(&raw->list, struct raw_data, entry);300	if (raw_data->len > count) {301		retval = -ENOSPC;302		goto exit;303	}304 305	if (copy_to_user(buf, &raw_data->data[0], raw_data->len)) {306		retval = -EFAULT;307		goto exit;308	}309 310	list_del(&raw_data->entry);311	raw->list_data -= raw_data->len;312	retval = raw_data->len;313	kfree(raw_data);314 315exit:316	mutex_unlock(&raw->list_lock);317	return retval;318}319 320static const struct file_operations raw_fops = {321	.owner		= THIS_MODULE,322	.write		= raw_write,323	.read		= raw_read,324	.open		= raw_open,325	.llseek		= noop_llseek,326};327 328static const struct greybus_bundle_id gb_raw_id_table[] = {329	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },330	{ }331};332MODULE_DEVICE_TABLE(greybus, gb_raw_id_table);333 334static struct greybus_driver gb_raw_driver = {335	.name		= "raw",336	.probe		= gb_raw_probe,337	.disconnect	= gb_raw_disconnect,338	.id_table	= gb_raw_id_table,339};340 341static int raw_init(void)342{343	dev_t dev;344	int retval;345 346	retval = class_register(&raw_class);347	if (retval)348		goto error_class;349 350	retval = alloc_chrdev_region(&dev, 0, NUM_MINORS, "gb_raw");351	if (retval < 0)352		goto error_chrdev;353 354	raw_major = MAJOR(dev);355 356	retval = greybus_register(&gb_raw_driver);357	if (retval)358		goto error_gb;359 360	return 0;361 362error_gb:363	unregister_chrdev_region(dev, NUM_MINORS);364error_chrdev:365	class_unregister(&raw_class);366error_class:367	return retval;368}369module_init(raw_init);370 371static void __exit raw_exit(void)372{373	greybus_deregister(&gb_raw_driver);374	unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS);375	class_unregister(&raw_class);376	ida_destroy(&minors);377}378module_exit(raw_exit);379 380MODULE_DESCRIPTION("Greybus driver for the Raw protocol");381MODULE_LICENSE("GPL v2");382