printk("timeout!\n");
}
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct gb_connection *connection = to_gb_connection(dev);
+
+ return sprintf(buf, "%d", connection->state);
+}
+static DEVICE_ATTR_RO(state);
+
+static ssize_t protocol_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct gb_connection *connection = to_gb_connection(dev);
+
+ return sprintf(buf, "%d", connection->protocol);
+}
+static DEVICE_ATTR_RO(protocol);
+
+static struct attribute *connection_attrs[] = {
+ &dev_attr_state.attr,
+ &dev_attr_protocol.attr,
+ NULL,
+};
+
+ATTRIBUTE_GROUPS(connection);
+
+static void gb_connection_release(struct device *dev)
+{
+ struct gb_connection *connection = to_gb_connection(dev);
+
+ kfree(connection);
+}
+
+static struct device_type greybus_connection_type = {
+ .name = "greybus_connection",
+ .release = gb_connection_release,
+};
+
/*
* Set up a Greybus connection, representing the bidirectional link
* between a CPort on a (local) Greybus host device and a CPort on
{
struct gb_connection *connection;
struct greybus_host_device *hd;
+ int retval;
connection = kzalloc(sizeof(*connection), GFP_KERNEL);
if (!connection)
connection->protocol = protocol;
connection->state = GB_CONNECTION_STATE_DISABLED;
+ connection->dev.parent = &interface->dev;
+ connection->dev.driver = NULL;
+ connection->dev.bus = &greybus_bus_type;
+ connection->dev.type = &greybus_connection_type;
+ connection->dev.groups = connection_groups;
+ device_initialize(&connection->dev);
+ dev_set_name(&connection->dev, "%s:%d",
+ dev_name(&interface->dev), cport_id);
+
+ retval = device_add(&connection->dev);
+ if (retval) {
+ kfree(connection);
+ return NULL;
+ }
+
spin_lock_irq(&gb_connections_lock);
_gb_hd_connection_insert(hd, connection);
list_add_tail(&connection->interface_links, &interface->connections);
spin_unlock_irq(&gb_connections_lock);
gb_connection_hd_cport_id_free(connection);
- /* kref_put(connection->interface); */
- /* kref_put(connection->hd); */
- kfree(connection);
+
+ device_del(&connection->dev);
}
u16 gb_connection_operation_id(struct gb_connection *connection)
struct gb_connection {
struct greybus_host_device *hd;
struct gb_interface *interface;
+ struct device dev;
u16 hd_cport_id;
u16 interface_cport_id;
void *private;
};
+#define to_gb_connection(d) container_of(d, struct gb_connection, dev)
struct gb_connection *gb_connection_create(struct gb_interface *interface,
u16 cport_id, enum greybus_protocol protocol);
/* struct gb_module *gmod = to_gb_module(dev); */
/* FIXME - add some uevents here... */
+
+ /* FIXME - be sure to check the type to know how to handle modules and
+ * interfaces differently */
+
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);
-
- gb_module_destroy(gmod);
-}
-
-static struct device_type greybus_module_type = {
- .name = "greybus_module",
- .release = greybus_module_release,
-};
-
static const struct greybus_module_id fake_greybus_module_id = {
GREYBUS_DEVICE(0x42, 0x42)
};
u8 *data, int size)
{
struct gb_module *gmod;
- int retval;
gmod = gb_module_create(hd, module_id);
if (!gmod) {
* 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 err_device;
-
return;
-err_device:
- put_device(&gmod->dev);
-err_module:
- greybus_module_release(&gmod->dev);
-}
-
-static void gb_delete_module(struct gb_module *gmod)
-{
- /* FIXME - tear down interfaces first */
- device_del(&gmod->dev);
+err_module:
+ gb_module_destroy(gmod);
}
void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
}
if (found)
- gb_delete_module(gmod);
+ gb_module_destroy(gmod);
else
dev_err(hd->parent, "module id %d remove error\n", module_id);
}
struct gb_module *gmod, *temp;
list_for_each_entry_safe(gmod, temp, &hd->modules, links) {
- gb_delete_module(gmod);
+ gb_module_destroy(gmod);
}
}
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);
}
void *context);
void gb_deregister_cport_complete(u16 cport_id);
+extern struct bus_type greybus_bus_type;
extern const struct attribute_group *greybus_module_groups[];
int gb_i2c_device_init(struct gb_connection *connection);
#include "greybus.h"
+static ssize_t device_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct gb_interface *interface = to_gb_interface(dev);
+
+ return sprintf(buf, "%d", interface->device_id);
+}
+static DEVICE_ATTR_RO(device_id);
+
+static struct attribute *interface_attrs[] = {
+ &dev_attr_device_id.attr,
+ NULL,
+};
+
+ATTRIBUTE_GROUPS(interface);
+
+static void gb_interface_release(struct device *dev)
+{
+ struct gb_interface *interface = to_gb_interface(dev);
+
+ kfree(interface);
+}
+
+static struct device_type greybus_interface_type = {
+ .name = "greybus_interface",
+ .release = gb_interface_release,
+};
+
+
/* XXX This could be per-host device or per-module */
static DEFINE_SPINLOCK(gb_interfaces_lock);
gb_interface_create(struct gb_module *gmod, u8 interface_id)
{
struct gb_interface *interface;
+ int retval;
interface = kzalloc(sizeof(*interface), GFP_KERNEL);
if (!interface)
interface->gmod = gmod; /* XXX refcount? */
interface->id = interface_id;
+ interface->device_id = 0xff; /* Invalid device id to start with */
INIT_LIST_HEAD(&interface->connections);
+ /* Build up the interface device structures and register it with the
+ * driver core */
+ interface->dev.parent = &gmod->dev;
+ interface->dev.driver = NULL;
+ interface->dev.bus = &greybus_bus_type;
+ interface->dev.type = &greybus_interface_type;
+ interface->dev.groups = interface_groups;
+ device_initialize(&interface->dev);
+ dev_set_name(&interface->dev, "%d:%d", gmod->module_id, interface_id);
+
+ retval = device_add(&interface->dev);
+ if (retval) {
+ kfree(interface);
+ return NULL;
+ }
+
spin_lock_irq(&gb_interfaces_lock);
list_add_tail(&interface->links, &gmod->interfaces);
spin_unlock_irq(&gb_interfaces_lock);
/*
* Tear down a previously set up interface.
*/
-void gb_interface_destroy(struct gb_interface *interface)
+void gb_interface_destroy(struct gb_module *gmod)
{
- if (WARN_ON(!interface))
+ struct gb_interface *interface;
+ struct gb_interface *temp;
+
+ if (WARN_ON(!gmod))
return;
spin_lock_irq(&gb_interfaces_lock);
- list_del(&interface->links);
+ list_for_each_entry_safe(interface, temp, &gmod->interfaces, links) {
+ list_del(&interface->links);
+ gb_interface_connections_exit(interface);
+ device_del(&interface->dev);
+ }
spin_unlock_irq(&gb_interfaces_lock);
-
- gb_interface_connections_exit(interface);
-
- /* kref_put(gmod); */
- kfree(interface);
}
struct gb_interface *gb_interface_find(struct gb_module *module,
{
struct gb_interface *interface;
+ spin_lock_irq(&gb_interfaces_lock);
list_for_each_entry(interface, &module->interfaces, links)
- if (interface->id == interface_id)
+ if (interface->id == interface_id) {
+ spin_unlock_irq(&gb_interfaces_lock);
return interface;
+ }
+ spin_unlock_irq(&gb_interfaces_lock);
return NULL;
}
#include <linux/list.h>
struct gb_interface {
+ struct device dev;
struct gb_module *gmod;
u8 id;
u8 device_id;
struct list_head links; /* module->interfaces */
};
+#define to_gb_interface(d) container_of(d, struct gb_interface, dev)
struct gb_interface *gb_interface_create(struct gb_module *gmod, u8 module_id);
-void gb_interface_destroy(struct gb_interface *interface);
+void gb_interface_destroy(struct gb_module *gmod);
struct gb_interface *gb_interface_find(struct gb_module *gmod, u8 interface_id);
return NULL;
}
-static void gb_module_interfaces_exit(struct gb_module *gmod)
+static void greybus_module_release(struct device *dev)
{
- struct gb_interface *interface;
- struct gb_interface *next;
+ struct gb_module *gmod = to_gb_module(dev);
- list_for_each_entry_safe(interface, next, &gmod->interfaces, links)
- gb_interface_destroy(interface);
+ kfree(gmod);
}
+static struct device_type greybus_module_type = {
+ .name = "greybus_module",
+ .release = greybus_module_release,
+};
+
/*
* A Greybus module represents a user-replacable component on an Ara
* phone.
struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
{
struct gb_module *gmod;
+ int retval;
gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
if (!gmod)
list_add_tail(&gmod->links, &hd->modules);
spin_unlock_irq(&gb_modules_lock);
+ 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) {
+ put_device(&gmod->dev);
+ return NULL;
+ }
+
return gmod;
}
list_del(&gmod->links);
spin_unlock_irq(&gb_modules_lock);
- gb_module_interfaces_exit(gmod);
/* XXX Do something with gmod->gb_tty */
- put_device(&gmod->dev);
- /* kfree(gmod->dev->name); */
+ gb_interface_destroy(gmod);
kfree(gmod->product_string);
kfree(gmod->vendor_string);
/* kref_put(module->hd); */
-
- kfree(gmod);
+ device_del(&gmod->dev);
}
struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id)