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