#ifdef MODULE
module_param(nogreybus, bool, 0444);
#else
-core_param(nogreybus, bool, 0444);
+core_param(nogreybus, nogreybus, bool, 0444);
#endif
int greybus_disabled(void)
{
static int greybus_module_match(struct device *dev, struct device_driver *drv)
{
- struct greybus_driver *driver = to_greybus_driver(dev->driver);
+ struct greybus_driver *driver = to_greybus_driver(drv);
struct gb_module *gmod = to_gb_module(dev);
const struct greybus_module_id *id;
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 gb_module *gmod = to_gb_module(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_module_match,
.uevent = greybus_uevent,
EXPORT_SYMBOL_GPL(greybus_deregister);
-static void greybus_module_release(struct device *dev)
-{
- struct gb_module *gmod = to_gb_module(dev);
- int i;
-
- for (i = 0; i < gmod->num_strings; ++i)
- kfree(gmod->string[i]);
- kfree(gmod);
-}
-
-
-static struct device_type greybus_module_type = {
- .name = "greybus_module",
- .release = greybus_module_release,
-};
-
-/* XXX
- * This needs to be driven by the list of functions that the
- * manifest says are present.
- */
-static int gb_init_subdevs(struct gb_module *gmod,
- const struct greybus_module_id *id)
-{
- int retval;
-
- /* Allocate all of the different "sub device types" for this device */
-
- /* XXX
- * Decide what exactly we should get supplied for the i2c
- * probe, and then work that back to what should be present
- * in the manifest.
- */
- retval = gb_i2c_probe(gmod, id);
- if (retval)
- goto error_i2c;
-
- retval = gb_gpio_probe(gmod, id);
- if (retval)
- goto error_gpio;
-
- retval = gb_sdio_probe(gmod, id);
- if (retval)
- goto error_sdio;
-
- retval = gb_tty_probe(gmod, id);
- if (retval)
- goto error_tty;
-
- retval = gb_battery_probe(gmod, id);
- if (retval)
- goto error_battery;
- return 0;
-
-error_battery:
- gb_tty_disconnect(gmod);
-
-error_tty:
- gb_sdio_disconnect(gmod);
-
-error_sdio:
- gb_gpio_disconnect(gmod);
-
-error_gpio:
- gb_i2c_disconnect(gmod);
-
-error_i2c:
- return retval;
-}
-
-static const struct greybus_module_id fake_greybus_module_id = {
- GREYBUS_DEVICE(0x42, 0x42)
-};
-
-
-/**
- * gb_add_module
- *
- * Pass in a buffer that _should_ contain a Greybus module manifest
- * and register a greybus device structure with the kernel core.
- */
-void gb_add_module(struct greybus_host_device *hd, u8 module_id,
- u8 *data, int size)
-{
- struct gb_module *gmod;
- int retval;
-
- gmod = gb_module_create(hd, module_id);
- if (!gmod) {
- dev_err(hd->parent, "failed to create module\n");
- return;
- }
-
- /*
- * Parse the manifest and build up our data structures
- * representing what's in it.
- */
- if (!gb_manifest_parse(gmod, data, size)) {
- dev_err(hd->parent, "manifest error\n");
- goto error;
- }
-
- /*
- * XXX
- * We've successfully parsed the manifest. Now we need to
- * allocate CPort Id's for connecting to the CPorts found on
- * other modules. For each of these, establish a connection
- * between the local and remote CPorts (including
- * configuring the switch to allow them to communicate).
- */
-
- gmod->dev.parent = hd->parent;
- gmod->dev.driver = NULL;
- gmod->dev.bus = &greybus_bus_type;
- gmod->dev.type = &greybus_module_type;
- gmod->dev.groups = greybus_module_groups;
- gmod->dev.dma_mask = hd->parent->dma_mask;
- device_initialize(&gmod->dev);
- dev_set_name(&gmod->dev, "%d", module_id);
-
- retval = device_add(&gmod->dev);
- if (retval)
- goto error;
-
- retval = gb_init_subdevs(gmod, &fake_greybus_module_id);
- if (retval)
- goto error_subdevs;
-
- //return gmod;
- return;
-
-error_subdevs:
- device_del(&gmod->dev);
-
-error:
- gb_module_destroy(gmod);
-
- put_device(&gmod->dev);
- greybus_module_release(&gmod->dev);
-}
-
-void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
-{
- struct gb_module *gmod;
- bool found = false;
-
- list_for_each_entry(gmod, &hd->modules, links)
- if (gmod->module_id == module_id) {
- found = true;
- break;
- }
-
- if (found)
- greybus_remove_device(gmod);
- else
- dev_err(hd->parent, "module id %d remove error\n", module_id);
-}
-
-void greybus_remove_device(struct gb_module *gmod)
-{
- /* tear down all of the "sub device types" for this device */
- gb_i2c_disconnect(gmod);
- gb_gpio_disconnect(gmod);
- gb_sdio_disconnect(gmod);
- gb_tty_disconnect(gmod);
- gb_battery_disconnect(gmod);
-
- device_del(&gmod->dev);
- put_device(&gmod->dev);
-}
-
static DEFINE_MUTEX(hd_mutex);
static void free_hd(struct kref *kref)
{
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;
hd->parent = parent;
hd->driver = driver;
INIT_LIST_HEAD(&hd->modules);
- hd->connections = RB_ROOT;
+ INIT_LIST_HEAD(&hd->connections);
ida_init(&hd->cport_id_map);
- spin_lock_init(&hd->cport_id_map_lock);
return 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;
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();
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();