]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/staging/greybus/core.c
greybus: Random spell fixes
[karo-tx-linux.git] / drivers / staging / greybus / core.c
index a13cf9f050593f76afc3ff44fe2d8c92bdbc6321..9203ebd2db7fd9198c3991580a18e667fe7c69eb 100644 (file)
@@ -22,7 +22,7 @@ static bool nogreybus;
 #ifdef MODULE
 module_param(nogreybus, bool, 0444);
 #else
-core_param(nogreybus, bool, 0444);
+core_param(nogreybus, nogreybus, bool, 0444);
 #endif
 int greybus_disabled(void)
 {
@@ -30,86 +30,79 @@ int greybus_disabled(void)
 }
 EXPORT_SYMBOL_GPL(greybus_disabled);
 
-static int greybus_match_one_id(struct greybus_device *gdev,
-                               const struct greybus_module_id *id)
+static int greybus_module_match(struct device *dev, struct device_driver *drv)
 {
-       struct greybus_descriptor_module_id *module_id;
-       struct greybus_descriptor_serial_number *serial_num;
-
-       module_id = &gdev->module_id;
-       serial_num = &gdev->serial_number;
-
-       if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
-           (id->vendor != le16_to_cpu(module_id->vendor)))
-               return 0;
-
-       if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
-           (id->product != le16_to_cpu(module_id->product)))
-               return 0;
-
-       if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
-           (id->serial_number != le64_to_cpu(serial_num->serial_number)))
-               return 0;
-
-       return 1;
-}
-
-static const struct greybus_module_id *greybus_match_id(
-               struct greybus_device *gdev,
-               const struct greybus_module_id *id)
-{
-       if (id == NULL)
-               return NULL;
-
-       for (; id->vendor || id->product || id->serial_number ||
-              id->driver_info ; id++) {
-               if (greybus_match_one_id(gdev, id))
-                       return id;
-       }
-
-       return NULL;
-}
-
-static int greybus_device_match(struct device *dev, struct device_driver *drv)
-{
-       struct greybus_driver *driver = to_greybus_driver(dev->driver);
-       struct greybus_device *gdev = to_greybus_device(dev);
+       struct greybus_driver *driver = to_greybus_driver(drv);
+       struct gb_module *gmod = to_gb_module(dev);
        const struct greybus_module_id *id;
 
-       id = greybus_match_id(gdev, driver->id_table);
+       id = gb_module_match_id(gmod, driver->id_table);
        if (id)
                return 1;
-       /* FIXME - Dyanmic ids? */
+       /* FIXME - Dynamic ids? */
        return 0;
 }
 
 static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       /* struct greybus_device *gdev = to_greybus_device(dev); */
+       struct gb_module *gmod = NULL;
+       struct gb_interface *interface = NULL;
+       struct gb_connection *connection = NULL;
+
+       if (is_gb_module(dev)) {
+               gmod = to_gb_module(dev);
+       } else if (is_gb_interface(dev)) {
+               interface = to_gb_interface(dev);
+               gmod = interface->gmod;
+       } else if (is_gb_connection(dev)) {
+               connection = to_gb_connection(dev);
+               interface = connection->interface;
+               gmod = interface->gmod;
+       } else {
+               dev_WARN(dev, "uevent for unknown greybus device \"type\"!\n");
+               return -EINVAL;
+       }
+
+       if (connection) {
+               // FIXME
+               // add a uevent that can "load" a connection type
+               return 0;
+       }
+
+       if (interface) {
+               // FIXME
+               // add a uevent that can "load" a interface type
+               // This is what we need to bind a driver to so use the info
+               // in gmod here as well
+               return 0;
+       }
 
-       /* FIXME - add some uevents here... */
+       // FIXME
+       // "just" a module, be vague here, nothing binds to a module except
+       // the greybus core, so there's not much, if anything, we need to
+       // advertise.
        return 0;
 }
 
-static struct bus_type greybus_bus_type = {
+struct bus_type greybus_bus_type = {
        .name =         "greybus",
-       .match =        greybus_device_match,
+       .match =        greybus_module_match,
        .uevent =       greybus_uevent,
 };
 
 static int greybus_probe(struct device *dev)
 {
        struct greybus_driver *driver = to_greybus_driver(dev->driver);
-       struct greybus_device *gdev = to_greybus_device(dev);
+       struct gb_module *gmod = to_gb_module(dev);
        const struct greybus_module_id *id;
        int retval;
 
        /* match id */
-       id = greybus_match_id(gdev, driver->id_table);
+       id = gb_module_match_id(gmod, driver->id_table);
        if (!id)
                return -ENODEV;
 
-       retval = driver->probe(gdev, id);
+       retval = driver->probe(gmod, id);
        if (retval)
                return retval;
 
@@ -119,9 +112,9 @@ static int greybus_probe(struct device *dev)
 static int greybus_remove(struct device *dev)
 {
        struct greybus_driver *driver = to_greybus_driver(dev->driver);
-       struct greybus_device *gdev = to_greybus_device(dev);
+       struct gb_module *gmod = to_gb_module(dev);
 
-       driver->disconnect(gdev);
+       driver->disconnect(gmod);
        return 0;
 }
 
@@ -155,329 +148,6 @@ void greybus_deregister(struct greybus_driver *driver)
 EXPORT_SYMBOL_GPL(greybus_deregister);
 
 
-static void greybus_module_release(struct device *dev)
-{
-       struct greybus_device *gdev = to_greybus_device(dev);
-       int i;
-
-       for (i = 0; i < gdev->num_strings; ++i)
-               kfree(gdev->string[i]);
-       for (i = 0; i < gdev->num_cports; ++i)
-               kfree(gdev->cport[i]);
-       kfree(gdev);
-}
-
-
-const u8 *greybus_string(struct greybus_device *gdev, int id)
-{
-       int i;
-       struct gdev_string *string;
-
-       if (!gdev)
-               return NULL;
-
-       for (i = 0; i < gdev->num_strings; ++i) {
-               string = gdev->string[i];
-               if (string->id == id)
-                       return &string->string[0];
-       }
-       return NULL;
-}
-
-static struct device_type greybus_module_type = {
-       .name =         "greybus_module",
-       .release =      greybus_module_release,
-};
-
-static int gb_init_subdevs(struct greybus_device *gdev,
-                          const struct greybus_module_id *id)
-{
-       int retval;
-
-       /* Allocate all of the different "sub device types" for this device */
-       retval = gb_i2c_probe(gdev, id);
-       if (retval)
-               goto error_i2c;
-
-       retval = gb_gpio_probe(gdev, id);
-       if (retval)
-               goto error_gpio;
-
-       retval = gb_sdio_probe(gdev, id);
-       if (retval)
-               goto error_sdio;
-
-       retval = gb_tty_probe(gdev, id);
-       if (retval)
-               goto error_tty;
-
-       retval = gb_battery_probe(gdev, id);
-       if (retval)
-               goto error_battery;
-       return 0;
-
-error_battery:
-       gb_tty_disconnect(gdev);
-
-error_tty:
-       gb_sdio_disconnect(gdev);
-
-error_sdio:
-       gb_gpio_disconnect(gdev);
-
-error_gpio:
-       gb_i2c_disconnect(gdev);
-
-error_i2c:
-       return retval;
-}
-
-static const struct greybus_module_id fake_gb_id = {
-       GREYBUS_DEVICE(0x42, 0x42)
-};
-
-static int create_function(struct greybus_device *gdev,
-                          struct greybus_descriptor_function *function,
-                          size_t desc_size)
-{
-       if (desc_size != sizeof(*function)) {
-               dev_err(gdev->dev.parent, "invalid function header size %zu\n",
-                       desc_size);
-               return -EINVAL;
-       }
-       memcpy(&gdev->function, function, desc_size);
-       return 0;
-}
-
-static int create_module_id(struct greybus_device *gdev,
-                           struct greybus_descriptor_module_id *module_id,
-                           size_t desc_size)
-{
-       if (desc_size != sizeof(*module_id)) {
-               dev_err(gdev->dev.parent, "invalid module header size %zu\n",
-                       desc_size);
-               return -EINVAL;
-       }
-       memcpy(&gdev->module_id, module_id, desc_size);
-       return 0;
-}
-
-static int create_serial_number(struct greybus_device *gdev,
-                               struct greybus_descriptor_serial_number *serial_num,
-                               size_t desc_size)
-{
-       if (desc_size != sizeof(*serial_num)) {
-               dev_err(gdev->dev.parent, "invalid serial number header size %zu\n",
-                       desc_size);
-               return -EINVAL;
-       }
-       memcpy(&gdev->serial_number, serial_num, desc_size);
-       return 0;
-}
-
-static int create_string(struct greybus_device *gdev,
-                        struct greybus_descriptor_string *string,
-                        size_t desc_size)
-{
-       int string_size;
-       struct gdev_string *gdev_string;
-
-       if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
-               dev_err(gdev->dev.parent,
-                       "too many strings for this module!\n");
-               return -EINVAL;
-       }
-
-       if (desc_size < sizeof(*string)) {
-               dev_err(gdev->dev.parent, "invalid string header size %zu\n",
-                       desc_size);
-               return -EINVAL;
-       }
-
-       string_size = le16_to_cpu(string->length);
-       gdev_string = kzalloc(sizeof(*gdev_string) + string_size + 1, GFP_KERNEL);
-       if (!gdev_string)
-               return -ENOMEM;
-
-       gdev_string->length = string_size;
-       gdev_string->id = string->id;
-       memcpy(&gdev_string->string, &string->string, string_size);
-
-       gdev->string[gdev->num_strings] = gdev_string;
-       gdev->num_strings++;
-
-       return 0;
-}
-
-static int create_cport(struct greybus_device *gdev,
-                       struct greybus_descriptor_cport *cport,
-                       size_t desc_size)
-{
-       struct gdev_cport *gdev_cport;
-
-       if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
-               dev_err(gdev->dev.parent, "too many cports for this module!\n");
-               return -EINVAL;
-       }
-
-       if (desc_size != sizeof(*cport)) {
-               dev_err(gdev->dev.parent,
-                       "invalid serial number header size %zu\n", desc_size);
-               return -EINVAL;
-       }
-
-       gdev_cport = kzalloc(sizeof(*gdev_cport), GFP_KERNEL);
-       if (!gdev_cport)
-               return -ENOMEM;
-
-       gdev_cport->number = le16_to_cpu(cport->number);
-       gdev_cport->size = le16_to_cpu(cport->size);
-       gdev_cport->speed = cport->speed;
-
-       gdev->cport[gdev->num_cports] = gdev_cport;
-       gdev->num_cports++;
-
-       return 0;
-}
-
-/**
- * greybus_new_module:
- *
- * Pass in a buffer that _should_ contain a Greybus module manifest
- * and spit out a greybus device structure.
- */
-struct greybus_device *greybus_new_module(struct device *parent,
-                                         int module_number, u8 *data, int size)
-{
-       struct greybus_device *gdev;
-       struct greybus_manifest *manifest;
-       int retval;
-       int overall_size;
-       u8 version_major;
-       u8 version_minor;
-
-       /* we have to have at _least_ the manifest header */
-       if (size <= sizeof(manifest->header))
-               return NULL;
-
-       gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
-       if (!gdev)
-               return NULL;
-
-       gdev->module_number = module_number;
-       gdev->dev.parent = parent;
-       gdev->dev.driver = NULL;
-       gdev->dev.bus = &greybus_bus_type;
-       gdev->dev.type = &greybus_module_type;
-       gdev->dev.groups = greybus_module_groups;
-       gdev->dev.dma_mask = parent->dma_mask;
-       device_initialize(&gdev->dev);
-       dev_set_name(&gdev->dev, "%d", module_number);
-
-       manifest = (struct greybus_manifest *)data;
-       overall_size = le16_to_cpu(manifest->header.size);
-       if (overall_size != size) {
-               dev_err(parent, "size != manifest header size, %d != %d\n",
-                       size, overall_size);
-               goto error;
-       }
-
-       version_major = manifest->header.version_major;
-       version_minor = manifest->header.version_minor;
-
-       /* Validate major/minor number */
-       if ((version_major != GREYBUS_VERSION_MAJOR) ||
-           (version_minor != GREYBUS_VERSION_MINOR)) {
-               dev_err(parent,
-                       "Invalid greybus versions, expected %d.%d, got %d.%d\n",
-                       GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR,
-                       version_major, version_minor);
-               goto error;
-       }
-
-       size -= sizeof(manifest->header);
-       data += sizeof(manifest->header);
-       while (size > 0) {
-               struct greybus_descriptor *desc;
-               u16 desc_size;
-               size_t data_size;
-
-               if (size < sizeof(desc->header)) {
-                       dev_err(parent, "remaining size %d too small\n", size);
-                       goto error;
-               }
-               desc = (struct greybus_descriptor *)data;
-               desc_size = le16_to_cpu(desc->header.size);
-               if (size < desc_size) {
-                       dev_err(parent, "descriptor size %d too big\n",
-                               desc_size);
-                       goto error;
-               }
-               data_size = (size_t)desc_size - sizeof(desc->header);
-
-               switch (le16_to_cpu(desc->header.type)) {
-               case GREYBUS_TYPE_FUNCTION:
-                       retval = create_function(gdev, &desc->function,
-                                                data_size);
-                       break;
-
-               case GREYBUS_TYPE_MODULE_ID:
-                       retval = create_module_id(gdev, &desc->module_id,
-                                                 data_size);
-                       break;
-
-               case GREYBUS_TYPE_SERIAL_NUMBER:
-                       retval = create_serial_number(gdev,
-                                                     &desc->serial_number,
-                                                     data_size);
-                       break;
-
-               case GREYBUS_TYPE_STRING:
-                       retval = create_string(gdev, &desc->string, data_size);
-                       break;
-
-               case GREYBUS_TYPE_CPORT:
-                       retval = create_cport(gdev, &desc->cport, data_size);
-                       break;
-
-               case GREYBUS_TYPE_INVALID:
-               default:
-                       dev_err(parent, "invalid descriptor type %d\n",
-                               desc->header.type);
-                       goto error;
-               }
-               if (retval)
-                       goto error;
-               size -= desc_size;
-               data += desc_size;
-       }
-
-       retval = gb_init_subdevs(gdev, &fake_gb_id);
-       if (retval)
-               goto error;
-
-       // FIXME device_add(&gdev->dev);
-
-
-       return gdev;
-error:
-       put_device(&gdev->dev);
-       greybus_module_release(&gdev->dev);
-       return NULL;
-}
-
-void greybus_remove_device(struct greybus_device *gdev)
-{
-       /* tear down all of the "sub device types" for this device */
-       gb_i2c_disconnect(gdev);
-       gb_gpio_disconnect(gdev);
-       gb_sdio_disconnect(gdev);
-       gb_tty_disconnect(gdev);
-       gb_battery_disconnect(gdev);
-
-       // FIXME - device_remove(&gdev->dev);
-}
-
 static DEFINE_MUTEX(hd_mutex);
 
 static void free_hd(struct kref *kref)
@@ -487,6 +157,7 @@ static void free_hd(struct kref *kref)
        hd = container_of(kref, struct greybus_host_device, kref);
 
        kfree(hd);
+       mutex_unlock(&hd_mutex);
 }
 
 struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
@@ -494,6 +165,16 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
 {
        struct greybus_host_device *hd;
 
+       /*
+        * Validate that the driver implements all of the callbacks
+        * so that we don't have to every time we make them.
+        */
+       if ((!driver->buffer_send) || (!driver->buffer_cancel) ||
+           (!driver->submit_svc)) {
+               pr_err("Must implement all greybus_host_driver callbacks!\n");
+               return NULL;
+       }
+
        hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
        if (!hd)
                return NULL;
@@ -501,6 +182,9 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
        kref_init(&hd->kref);
        hd->parent = parent;
        hd->driver = driver;
+       INIT_LIST_HEAD(&hd->modules);
+       INIT_LIST_HEAD(&hd->connections);
+       ida_init(&hd->cport_id_map);
 
        return hd;
 }
@@ -508,15 +192,19 @@ EXPORT_SYMBOL_GPL(greybus_create_hd);
 
 void greybus_remove_hd(struct greybus_host_device *hd)
 {
+       /* Tear down all modules that happen to be associated with this host
+        * controller */
+       gb_remove_modules(hd);
        kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
 }
 EXPORT_SYMBOL_GPL(greybus_remove_hd);
 
-
 static int __init gb_init(void)
 {
        int retval;
 
+       BUILD_BUG_ON(HOST_DEV_CPORT_ID_MAX >= (long)CPORT_ID_BAD);
+
        retval = gb_debugfs_init();
        if (retval) {
                pr_err("debugfs failed\n");
@@ -535,29 +223,27 @@ static int __init gb_init(void)
                goto error_ap;
        }
 
-       retval = gb_gbuf_init();
+       retval = gb_operation_init();
        if (retval) {
-               pr_err("gb_gbuf_init failed\n");
-               goto error_gbuf;
+               pr_err("gb_operation_init failed\n");
+               goto error_operation;
        }
 
-       retval = gb_tty_init();
-       if (retval) {
-               pr_err("gb_tty_init failed\n");
-               goto error_tty;
+       if (!gb_protocol_init()) {
+               /* This only fails for duplicate protocol registration */
+               retval = -EEXIST;
+               pr_err("gb_protocol_init failed\n");
+               goto error_protocol;
        }
 
-       return 0;
-
-error_tty:
-       gb_gbuf_exit();
+       return 0;       /* Success */
 
-error_gbuf:
+error_protocol:
+       gb_operation_exit();
+error_operation:
        gb_ap_exit();
-
 error_ap:
        bus_unregister(&greybus_bus_type);
-
 error_bus:
        gb_debugfs_cleanup();
 
@@ -566,8 +252,8 @@ error_bus:
 
 static void __exit gb_exit(void)
 {
-       gb_tty_exit();
-       gb_gbuf_exit();
+       gb_protocol_exit();
+       gb_operation_exit();
        gb_ap_exit();
        bus_unregister(&greybus_bus_type);
        gb_debugfs_cleanup();