#ifdef MODULE
module_param(nogreybus, bool, 0444);
#else
-core_param(nogreybus, bool, 0444);
+core_param(nogreybus, nogreybus, bool, 0444);
#endif
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;
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;
}
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;
-
- // FIXME - check version major/minor here!
-
- 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)
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,
{
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;
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;
}
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");
goto error_bus;
}
- retval = gb_thread_init();
+ retval = gb_ap_init();
if (retval) {
- pr_err("gb_thread_init failed\n");
- goto error_thread;
+ pr_err("gb_ap_init failed\n");
+ goto error_ap;
}
- // FIXME - more gb core init goes here
-
- retval = gb_tty_init();
+ retval = gb_operation_init();
if (retval) {
- pr_err("gb_tty_init failed\n");
- goto error_tty;
+ pr_err("gb_operation_init failed\n");
+ goto error_operation;
}
- return 0;
+ if (!gb_protocol_init()) {
+ /* This only fails for duplicate protocol registration */
+ retval = -EEXIST;
+ pr_err("gb_protocol_init failed\n");
+ goto error_protocol;
+ }
-error_tty:
- gb_thread_destroy();
+ return 0; /* Success */
-error_thread:
+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_protocol_exit();
+ gb_operation_exit();
+ gb_ap_exit();
bus_unregister(&greybus_bus_type);
gb_debugfs_cleanup();
}