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