4 * Copyright 2014 Google Inc.
6 * Released under the GPLv2 only.
11 /* XXX This could be per-host device */
12 static DEFINE_SPINLOCK(gb_modules_lock);
14 static int gb_module_match_one_id(struct gb_module *gmod,
15 const struct greybus_module_id *id)
17 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
18 (id->vendor != gmod->vendor))
21 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
22 (id->product != gmod->product))
25 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
26 (id->unique_id != gmod->unique_id))
32 const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
33 const struct greybus_module_id *id)
38 for (; id->vendor || id->product || id->unique_id ||
39 id->driver_info; id++) {
40 if (gb_module_match_one_id(gmod, id))
47 struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id)
49 struct gb_module *module;
51 list_for_each_entry(module, &hd->modules, links)
52 if (module->module_id == module_id)
58 static void greybus_module_release(struct device *dev)
60 struct gb_module *gmod = to_gb_module(dev);
65 struct device_type greybus_module_type = {
66 .name = "greybus_module",
67 .release = greybus_module_release,
71 * A Greybus module represents a user-replicable component on an Ara
74 * Create a gb_module structure to represent a discovered module.
75 * The position within the Endo is encoded in the "module_id" argument.
76 * Returns a pointer to the new module or a null pointer if a
77 * failure occurs due to memory exhaustion.
79 struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
81 struct gb_module *gmod;
84 gmod = gb_module_find(hd, module_id);
86 dev_err(hd->parent, "Duplicate module id %d will not be created\n",
91 gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
95 gmod->hd = hd; /* XXX refcount? */
96 gmod->module_id = module_id;
97 INIT_LIST_HEAD(&gmod->interfaces);
99 gmod->dev.parent = hd->parent;
100 gmod->dev.bus = &greybus_bus_type;
101 gmod->dev.type = &greybus_module_type;
102 gmod->dev.groups = greybus_module_groups;
103 gmod->dev.dma_mask = hd->parent->dma_mask;
104 device_initialize(&gmod->dev);
105 dev_set_name(&gmod->dev, "%d", module_id);
107 retval = device_add(&gmod->dev);
109 pr_err("failed to add module device for id 0x%02hhx\n",
111 put_device(&gmod->dev);
116 spin_lock_irq(&gb_modules_lock);
117 list_add_tail(&gmod->links, &hd->modules);
118 spin_unlock_irq(&gb_modules_lock);
124 * Tear down a previously set up module.
126 void gb_module_destroy(struct gb_module *gmod)
131 spin_lock_irq(&gb_modules_lock);
132 list_del(&gmod->links);
133 spin_unlock_irq(&gb_modules_lock);
135 /* XXX Do something with gmod->gb_tty */
137 gb_interface_destroy(gmod);
139 kfree(gmod->product_string);
140 kfree(gmod->vendor_string);
141 /* kref_put(module->hd); */
143 device_del(&gmod->dev);
149 * Pass in a buffer that _should_ contain a Greybus module manifest
150 * and register a greybus device structure with the kernel core.
152 void gb_add_module(struct greybus_host_device *hd, u8 module_id,
155 struct gb_module *gmod;
157 gmod = gb_module_create(hd, module_id);
159 dev_err(hd->parent, "failed to create module\n");
164 * Parse the manifest and build up our data structures
165 * representing what's in it.
167 if (!gb_manifest_parse(gmod, data, size)) {
168 dev_err(hd->parent, "manifest error\n");
174 * We've successfully parsed the manifest. Now we need to
175 * allocate CPort Id's for connecting to the CPorts found on
176 * other modules. For each of these, establish a connection
177 * between the local and remote CPorts (including
178 * configuring the switch to allow them to communicate).
184 gb_module_destroy(gmod);
187 void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
189 struct gb_module *gmod = gb_module_find(hd, module_id);
192 gb_module_destroy(gmod);
194 dev_err(hd->parent, "module id %d not found\n", module_id);
197 void gb_remove_modules(struct greybus_host_device *hd)
199 struct gb_module *gmod, *temp;
201 list_for_each_entry_safe(gmod, temp, &hd->modules, links)
202 gb_module_destroy(gmod);