Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus driver for the Raw protocol
0004  *
0005  * Copyright 2015 Google Inc.
0006  * Copyright 2015 Linaro Ltd.
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/sizes.h>
0012 #include <linux/cdev.h>
0013 #include <linux/fs.h>
0014 #include <linux/idr.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/greybus.h>
0017 
0018 struct gb_raw {
0019     struct gb_connection *connection;
0020 
0021     struct list_head list;
0022     int list_data;
0023     struct mutex list_lock;
0024     dev_t dev;
0025     struct cdev cdev;
0026     struct device *device;
0027 };
0028 
0029 struct raw_data {
0030     struct list_head entry;
0031     u32 len;
0032     u8 data[];
0033 };
0034 
0035 static struct class *raw_class;
0036 static int raw_major;
0037 static const struct file_operations raw_fops;
0038 static DEFINE_IDA(minors);
0039 
0040 /* Number of minor devices this driver supports */
0041 #define NUM_MINORS  256
0042 
0043 /* Maximum size of any one send data buffer we support */
0044 #define MAX_PACKET_SIZE (PAGE_SIZE * 2)
0045 
0046 /*
0047  * Maximum size of the data in the receive buffer we allow before we start to
0048  * drop messages on the floor
0049  */
0050 #define MAX_DATA_SIZE   (MAX_PACKET_SIZE * 8)
0051 
0052 /*
0053  * Add the raw data message to the list of received messages.
0054  */
0055 static int receive_data(struct gb_raw *raw, u32 len, u8 *data)
0056 {
0057     struct raw_data *raw_data;
0058     struct device *dev = &raw->connection->bundle->dev;
0059     int retval = 0;
0060 
0061     if (len > MAX_PACKET_SIZE) {
0062         dev_err(dev, "Too big of a data packet, rejected\n");
0063         return -EINVAL;
0064     }
0065 
0066     mutex_lock(&raw->list_lock);
0067     if ((raw->list_data + len) > MAX_DATA_SIZE) {
0068         dev_err(dev, "Too much data in receive buffer, now dropping packets\n");
0069         retval = -EINVAL;
0070         goto exit;
0071     }
0072 
0073     raw_data = kmalloc(sizeof(*raw_data) + len, GFP_KERNEL);
0074     if (!raw_data) {
0075         retval = -ENOMEM;
0076         goto exit;
0077     }
0078 
0079     raw->list_data += len;
0080     raw_data->len = len;
0081     memcpy(&raw_data->data[0], data, len);
0082 
0083     list_add_tail(&raw_data->entry, &raw->list);
0084 exit:
0085     mutex_unlock(&raw->list_lock);
0086     return retval;
0087 }
0088 
0089 static int gb_raw_request_handler(struct gb_operation *op)
0090 {
0091     struct gb_connection *connection = op->connection;
0092     struct device *dev = &connection->bundle->dev;
0093     struct gb_raw *raw = greybus_get_drvdata(connection->bundle);
0094     struct gb_raw_send_request *receive;
0095     u32 len;
0096 
0097     if (op->type != GB_RAW_TYPE_SEND) {
0098         dev_err(dev, "unknown request type 0x%02x\n", op->type);
0099         return -EINVAL;
0100     }
0101 
0102     /* Verify size of payload */
0103     if (op->request->payload_size < sizeof(*receive)) {
0104         dev_err(dev, "raw receive request too small (%zu < %zu)\n",
0105             op->request->payload_size, sizeof(*receive));
0106         return -EINVAL;
0107     }
0108     receive = op->request->payload;
0109     len = le32_to_cpu(receive->len);
0110     if (len != (int)(op->request->payload_size - sizeof(__le32))) {
0111         dev_err(dev, "raw receive request wrong size %d vs %d\n", len,
0112             (int)(op->request->payload_size - sizeof(__le32)));
0113         return -EINVAL;
0114     }
0115     if (len == 0) {
0116         dev_err(dev, "raw receive request of 0 bytes?\n");
0117         return -EINVAL;
0118     }
0119 
0120     return receive_data(raw, len, receive->data);
0121 }
0122 
0123 static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
0124 {
0125     struct gb_connection *connection = raw->connection;
0126     struct gb_raw_send_request *request;
0127     int retval;
0128 
0129     request = kmalloc(len + sizeof(*request), GFP_KERNEL);
0130     if (!request)
0131         return -ENOMEM;
0132 
0133     if (copy_from_user(&request->data[0], data, len)) {
0134         kfree(request);
0135         return -EFAULT;
0136     }
0137 
0138     request->len = cpu_to_le32(len);
0139 
0140     retval = gb_operation_sync(connection, GB_RAW_TYPE_SEND,
0141                    request, len + sizeof(*request),
0142                    NULL, 0);
0143 
0144     kfree(request);
0145     return retval;
0146 }
0147 
0148 static int gb_raw_probe(struct gb_bundle *bundle,
0149             const struct greybus_bundle_id *id)
0150 {
0151     struct greybus_descriptor_cport *cport_desc;
0152     struct gb_connection *connection;
0153     struct gb_raw *raw;
0154     int retval;
0155     int minor;
0156 
0157     if (bundle->num_cports != 1)
0158         return -ENODEV;
0159 
0160     cport_desc = &bundle->cport_desc[0];
0161     if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)
0162         return -ENODEV;
0163 
0164     raw = kzalloc(sizeof(*raw), GFP_KERNEL);
0165     if (!raw)
0166         return -ENOMEM;
0167 
0168     connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
0169                       gb_raw_request_handler);
0170     if (IS_ERR(connection)) {
0171         retval = PTR_ERR(connection);
0172         goto error_free;
0173     }
0174 
0175     INIT_LIST_HEAD(&raw->list);
0176     mutex_init(&raw->list_lock);
0177 
0178     raw->connection = connection;
0179     greybus_set_drvdata(bundle, raw);
0180 
0181     minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
0182     if (minor < 0) {
0183         retval = minor;
0184         goto error_connection_destroy;
0185     }
0186 
0187     raw->dev = MKDEV(raw_major, minor);
0188     cdev_init(&raw->cdev, &raw_fops);
0189 
0190     retval = gb_connection_enable(connection);
0191     if (retval)
0192         goto error_remove_ida;
0193 
0194     retval = cdev_add(&raw->cdev, raw->dev, 1);
0195     if (retval)
0196         goto error_connection_disable;
0197 
0198     raw->device = device_create(raw_class, &connection->bundle->dev,
0199                     raw->dev, raw, "gb!raw%d", minor);
0200     if (IS_ERR(raw->device)) {
0201         retval = PTR_ERR(raw->device);
0202         goto error_del_cdev;
0203     }
0204 
0205     return 0;
0206 
0207 error_del_cdev:
0208     cdev_del(&raw->cdev);
0209 
0210 error_connection_disable:
0211     gb_connection_disable(connection);
0212 
0213 error_remove_ida:
0214     ida_simple_remove(&minors, minor);
0215 
0216 error_connection_destroy:
0217     gb_connection_destroy(connection);
0218 
0219 error_free:
0220     kfree(raw);
0221     return retval;
0222 }
0223 
0224 static void gb_raw_disconnect(struct gb_bundle *bundle)
0225 {
0226     struct gb_raw *raw = greybus_get_drvdata(bundle);
0227     struct gb_connection *connection = raw->connection;
0228     struct raw_data *raw_data;
0229     struct raw_data *temp;
0230 
0231     // FIXME - handle removing a connection when the char device node is open.
0232     device_destroy(raw_class, raw->dev);
0233     cdev_del(&raw->cdev);
0234     gb_connection_disable(connection);
0235     ida_simple_remove(&minors, MINOR(raw->dev));
0236     gb_connection_destroy(connection);
0237 
0238     mutex_lock(&raw->list_lock);
0239     list_for_each_entry_safe(raw_data, temp, &raw->list, entry) {
0240         list_del(&raw_data->entry);
0241         kfree(raw_data);
0242     }
0243     mutex_unlock(&raw->list_lock);
0244 
0245     kfree(raw);
0246 }
0247 
0248 /*
0249  * Character device node interfaces.
0250  *
0251  * Note, we are using read/write to only allow a single read/write per message.
0252  * This means for read(), you have to provide a big enough buffer for the full
0253  * message to be copied into.  If the buffer isn't big enough, the read() will
0254  * fail with -ENOSPC.
0255  */
0256 
0257 static int raw_open(struct inode *inode, struct file *file)
0258 {
0259     struct cdev *cdev = inode->i_cdev;
0260     struct gb_raw *raw = container_of(cdev, struct gb_raw, cdev);
0261 
0262     file->private_data = raw;
0263     return 0;
0264 }
0265 
0266 static ssize_t raw_write(struct file *file, const char __user *buf,
0267              size_t count, loff_t *ppos)
0268 {
0269     struct gb_raw *raw = file->private_data;
0270     int retval;
0271 
0272     if (!count)
0273         return 0;
0274 
0275     if (count > MAX_PACKET_SIZE)
0276         return -E2BIG;
0277 
0278     retval = gb_raw_send(raw, count, buf);
0279     if (retval)
0280         return retval;
0281 
0282     return count;
0283 }
0284 
0285 static ssize_t raw_read(struct file *file, char __user *buf, size_t count,
0286             loff_t *ppos)
0287 {
0288     struct gb_raw *raw = file->private_data;
0289     int retval = 0;
0290     struct raw_data *raw_data;
0291 
0292     mutex_lock(&raw->list_lock);
0293     if (list_empty(&raw->list))
0294         goto exit;
0295 
0296     raw_data = list_first_entry(&raw->list, struct raw_data, entry);
0297     if (raw_data->len > count) {
0298         retval = -ENOSPC;
0299         goto exit;
0300     }
0301 
0302     if (copy_to_user(buf, &raw_data->data[0], raw_data->len)) {
0303         retval = -EFAULT;
0304         goto exit;
0305     }
0306 
0307     list_del(&raw_data->entry);
0308     raw->list_data -= raw_data->len;
0309     retval = raw_data->len;
0310     kfree(raw_data);
0311 
0312 exit:
0313     mutex_unlock(&raw->list_lock);
0314     return retval;
0315 }
0316 
0317 static const struct file_operations raw_fops = {
0318     .owner      = THIS_MODULE,
0319     .write      = raw_write,
0320     .read       = raw_read,
0321     .open       = raw_open,
0322     .llseek     = noop_llseek,
0323 };
0324 
0325 static const struct greybus_bundle_id gb_raw_id_table[] = {
0326     { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
0327     { }
0328 };
0329 MODULE_DEVICE_TABLE(greybus, gb_raw_id_table);
0330 
0331 static struct greybus_driver gb_raw_driver = {
0332     .name       = "raw",
0333     .probe      = gb_raw_probe,
0334     .disconnect = gb_raw_disconnect,
0335     .id_table   = gb_raw_id_table,
0336 };
0337 
0338 static int raw_init(void)
0339 {
0340     dev_t dev;
0341     int retval;
0342 
0343     raw_class = class_create(THIS_MODULE, "gb_raw");
0344     if (IS_ERR(raw_class)) {
0345         retval = PTR_ERR(raw_class);
0346         goto error_class;
0347     }
0348 
0349     retval = alloc_chrdev_region(&dev, 0, NUM_MINORS, "gb_raw");
0350     if (retval < 0)
0351         goto error_chrdev;
0352 
0353     raw_major = MAJOR(dev);
0354 
0355     retval = greybus_register(&gb_raw_driver);
0356     if (retval)
0357         goto error_gb;
0358 
0359     return 0;
0360 
0361 error_gb:
0362     unregister_chrdev_region(dev, NUM_MINORS);
0363 error_chrdev:
0364     class_destroy(raw_class);
0365 error_class:
0366     return retval;
0367 }
0368 module_init(raw_init);
0369 
0370 static void __exit raw_exit(void)
0371 {
0372     greybus_deregister(&gb_raw_driver);
0373     unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS);
0374     class_destroy(raw_class);
0375     ida_destroy(&minors);
0376 }
0377 module_exit(raw_exit);
0378 
0379 MODULE_LICENSE("GPL v2");