greybus: raw: convert to bundle driver
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 15 Feb 2016 05:17:27 +0000 (10:47 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 15 Feb 2016 22:52:24 +0000 (14:52 -0800)
Convert the legacy raw protocol driver to a bundle driver.

This also fixes a potential crash should a (malicious) module have sent
an early request before the private data had been initialised.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/legacy.c
drivers/staging/greybus/raw.c

index 057029dc3ee482b60b58c0b0aaeeffd85db15893..23ea45879d254cd8c86ea32e3324fb151e46d4ce 100644 (file)
@@ -247,7 +247,6 @@ static const struct greybus_bundle_id legacy_id_table[] = {
        { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
        { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) },
        { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOOPBACK) },
-       { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
        { }
 };
 MODULE_DEVICE_TABLE(greybus, legacy_id_table);
index ed17ba3ca0b3e44af173efda618f1a498953ca4f..338139e815af256bd29c72c67d3baf8909ad0df4 100644 (file)
@@ -88,16 +88,16 @@ exit:
        return retval;
 }
 
-static int gb_raw_receive(u8 type, struct gb_operation *op)
+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 = connection->private;
+       struct gb_raw *raw = greybus_get_drvdata(connection->bundle);
        struct gb_raw_send_request *receive;
        u32 len;
 
-       if (type != GB_RAW_TYPE_SEND) {
-               dev_err(dev, "unknown request type %d\n", type);
+       if (op->type != GB_RAW_TYPE_SEND) {
+               dev_err(dev, "unknown request type %d\n", op->type);
                return -EINVAL;
        }
 
@@ -147,34 +147,56 @@ static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
        return retval;
 }
 
-static int gb_raw_connection_init(struct gb_connection *connection)
+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;
 
-       raw->connection = connection;
-       connection->private = raw;
+       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_free;
+               goto error_connection_destroy;
        }
 
        raw->dev = MKDEV(raw_major, minor);
        cdev_init(&raw->cdev, &raw_fops);
-       retval = cdev_add(&raw->cdev, raw->dev, 1);
+
+       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)) {
@@ -187,24 +209,34 @@ static int gb_raw_connection_init(struct gb_connection *connection)
 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_connection_exit(struct gb_connection *connection)
+static void gb_raw_disconnect(struct gb_bundle *bundle)
 {
-       struct gb_raw *raw = connection->private;
+       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);
@@ -215,16 +247,6 @@ static void gb_raw_connection_exit(struct gb_connection *connection)
        kfree(raw);
 }
 
-static struct gb_protocol raw_protocol = {
-       .name                   = "raw",
-       .id                     = GREYBUS_PROTOCOL_RAW,
-       .major                  = GB_RAW_VERSION_MAJOR,
-       .minor                  = GB_RAW_VERSION_MINOR,
-       .connection_init        = gb_raw_connection_init,
-       .connection_exit        = gb_raw_connection_exit,
-       .request_recv           = gb_raw_receive,
-};
-
 /*
  * Character device node interfaces.
  *
@@ -302,6 +324,19 @@ static const struct file_operations raw_fops = {
        .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;
@@ -317,10 +352,9 @@ static int raw_init(void)
        if (retval < 0)
                goto error_chrdev;
 
-
        raw_major = MAJOR(dev);
 
-       retval = gb_protocol_register(&raw_protocol);
+       retval = greybus_register(&gb_raw_driver);
        if (retval)
                goto error_gb;
 
@@ -337,7 +371,7 @@ module_init(raw_init);
 
 static void __exit raw_exit(void)
 {
-       gb_protocol_deregister(&raw_protocol);
+       greybus_deregister(&gb_raw_driver);
        unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS);
        class_destroy(raw_class);
        ida_destroy(&minors);