Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Greybus "Core" |
| 3 | * |
| 4 | * Copyright 2014 Google Inc. |
| 5 | * |
| 6 | * Released under the GPLv2 only. |
| 7 | */ |
| 8 | |
| 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 10 | |
| 11 | #include <linux/types.h> |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/moduleparam.h> |
| 14 | #include <linux/kernel.h> |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 15 | #include <linux/slab.h> |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 16 | #include <linux/device.h> |
| 17 | |
| 18 | #include "greybus.h" |
| 19 | |
| 20 | /* Allow greybus to be disabled at boot if needed */ |
| 21 | static bool nogreybus; |
| 22 | #ifdef MODULE |
| 23 | module_param(nogreybus, bool, 0444); |
| 24 | #else |
| 25 | core_param(nogreybus, bool, 0444); |
| 26 | #endif |
| 27 | int greybus_disabled(void) |
| 28 | { |
| 29 | return nogreybus; |
| 30 | } |
| 31 | EXPORT_SYMBOL_GPL(greybus_disabled); |
| 32 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 33 | static int greybus_module_match(struct device *dev, struct device_driver *drv) |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 34 | { |
| 35 | struct greybus_driver *driver = to_greybus_driver(dev->driver); |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 36 | struct gb_module *gmod = to_gb_module(dev); |
Greg Kroah-Hartman | 6584c8a | 2014-09-01 13:31:31 -0700 | [diff] [blame] | 37 | const struct greybus_module_id *id; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 38 | |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 39 | id = gb_module_match_id(gmod, driver->id_table); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 40 | if (id) |
| 41 | return 1; |
| 42 | /* FIXME - Dyanmic ids? */ |
| 43 | return 0; |
| 44 | } |
| 45 | |
| 46 | static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env) |
| 47 | { |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 48 | /* struct gb_module *gmod = to_gb_module(dev); */ |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 49 | |
| 50 | /* FIXME - add some uevents here... */ |
| 51 | return 0; |
| 52 | } |
| 53 | |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 54 | static struct bus_type greybus_bus_type = { |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 55 | .name = "greybus", |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 56 | .match = greybus_module_match, |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 57 | .uevent = greybus_uevent, |
| 58 | }; |
| 59 | |
| 60 | static int greybus_probe(struct device *dev) |
| 61 | { |
| 62 | struct greybus_driver *driver = to_greybus_driver(dev->driver); |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 63 | struct gb_module *gmod = to_gb_module(dev); |
Greg Kroah-Hartman | 6584c8a | 2014-09-01 13:31:31 -0700 | [diff] [blame] | 64 | const struct greybus_module_id *id; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 65 | int retval; |
| 66 | |
| 67 | /* match id */ |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 68 | id = gb_module_match_id(gmod, driver->id_table); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 69 | if (!id) |
| 70 | return -ENODEV; |
| 71 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 72 | retval = driver->probe(gmod, id); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 73 | if (retval) |
| 74 | return retval; |
| 75 | |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | static int greybus_remove(struct device *dev) |
| 80 | { |
| 81 | struct greybus_driver *driver = to_greybus_driver(dev->driver); |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 82 | struct gb_module *gmod = to_gb_module(dev); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 83 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 84 | driver->disconnect(gmod); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 85 | return 0; |
| 86 | } |
| 87 | |
| 88 | int greybus_register_driver(struct greybus_driver *driver, struct module *owner, |
| 89 | const char *mod_name) |
| 90 | { |
| 91 | int retval; |
| 92 | |
| 93 | if (greybus_disabled()) |
| 94 | return -ENODEV; |
| 95 | |
| 96 | driver->driver.name = driver->name; |
| 97 | driver->driver.probe = greybus_probe; |
| 98 | driver->driver.remove = greybus_remove; |
| 99 | driver->driver.owner = owner; |
| 100 | driver->driver.mod_name = mod_name; |
| 101 | |
| 102 | retval = driver_register(&driver->driver); |
| 103 | if (retval) |
| 104 | return retval; |
| 105 | |
| 106 | pr_info("registered new driver %s\n", driver->name); |
| 107 | return 0; |
| 108 | } |
| 109 | EXPORT_SYMBOL_GPL(greybus_register_driver); |
| 110 | |
| 111 | void greybus_deregister(struct greybus_driver *driver) |
| 112 | { |
| 113 | driver_unregister(&driver->driver); |
| 114 | } |
| 115 | EXPORT_SYMBOL_GPL(greybus_deregister); |
| 116 | |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 117 | |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 118 | static void greybus_module_release(struct device *dev) |
| 119 | { |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 120 | struct gb_module *gmod = to_gb_module(dev); |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 121 | int i; |
| 122 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 123 | for (i = 0; i < gmod->num_strings; ++i) |
| 124 | kfree(gmod->string[i]); |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 125 | kfree(gmod); |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 129 | static struct device_type greybus_module_type = { |
| 130 | .name = "greybus_module", |
| 131 | .release = greybus_module_release, |
| 132 | }; |
| 133 | |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 134 | /* XXX |
| 135 | * This needs to be driven by the list of functions that the |
| 136 | * manifest says are present. |
| 137 | */ |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 138 | static int gb_init_subdevs(struct gb_module *gmod, |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 139 | const struct greybus_module_id *id) |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 140 | { |
| 141 | int retval; |
| 142 | |
| 143 | /* Allocate all of the different "sub device types" for this device */ |
Alex Elder | c68adb2 | 2014-10-01 21:54:14 -0500 | [diff] [blame] | 144 | |
| 145 | /* XXX |
| 146 | * Decide what exactly we should get supplied for the i2c |
| 147 | * probe, and then work that back to what should be present |
| 148 | * in the manifest. |
| 149 | */ |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 150 | retval = gb_i2c_probe(gmod, id); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 151 | if (retval) |
| 152 | goto error_i2c; |
| 153 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 154 | retval = gb_gpio_probe(gmod, id); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 155 | if (retval) |
| 156 | goto error_gpio; |
| 157 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 158 | retval = gb_sdio_probe(gmod, id); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 159 | if (retval) |
| 160 | goto error_sdio; |
| 161 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 162 | retval = gb_tty_probe(gmod, id); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 163 | if (retval) |
| 164 | goto error_tty; |
Greg Kroah-Hartman | 33ea3a3 | 2014-09-07 15:39:34 -0700 | [diff] [blame] | 165 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 166 | retval = gb_battery_probe(gmod, id); |
Greg Kroah-Hartman | 33ea3a3 | 2014-09-07 15:39:34 -0700 | [diff] [blame] | 167 | if (retval) |
| 168 | goto error_battery; |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 169 | return 0; |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 170 | |
Greg Kroah-Hartman | 33ea3a3 | 2014-09-07 15:39:34 -0700 | [diff] [blame] | 171 | error_battery: |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 172 | gb_tty_disconnect(gmod); |
Greg Kroah-Hartman | 33ea3a3 | 2014-09-07 15:39:34 -0700 | [diff] [blame] | 173 | |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 174 | error_tty: |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 175 | gb_sdio_disconnect(gmod); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 176 | |
| 177 | error_sdio: |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 178 | gb_gpio_disconnect(gmod); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 179 | |
| 180 | error_gpio: |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 181 | gb_i2c_disconnect(gmod); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 182 | |
| 183 | error_i2c: |
| 184 | return retval; |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 185 | } |
| 186 | |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 187 | static const struct greybus_module_id fake_greybus_module_id = { |
Greg Kroah-Hartman | 3be03d4 | 2014-09-01 19:10:06 -0700 | [diff] [blame] | 188 | GREYBUS_DEVICE(0x42, 0x42) |
| 189 | }; |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 190 | |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 191 | |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 192 | /** |
Greg Kroah-Hartman | 4a833fd | 2014-09-21 19:17:55 -0700 | [diff] [blame] | 193 | * gb_add_module |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 194 | * |
Alex Elder | 05ad189 | 2014-09-09 13:55:03 -0500 | [diff] [blame] | 195 | * Pass in a buffer that _should_ contain a Greybus module manifest |
Greg Kroah-Hartman | 4a833fd | 2014-09-21 19:17:55 -0700 | [diff] [blame] | 196 | * and register a greybus device structure with the kernel core. |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 197 | */ |
Greg Kroah-Hartman | d0cfd10 | 2014-09-21 19:10:39 -0700 | [diff] [blame] | 198 | void gb_add_module(struct greybus_host_device *hd, u8 module_id, |
| 199 | u8 *data, int size) |
Greg Kroah-Hartman | 6779997 | 2014-09-21 18:17:36 -0700 | [diff] [blame] | 200 | { |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 201 | struct gb_module *gmod; |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 202 | int retval; |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 203 | |
Alex Elder | 937d0da | 2014-10-03 14:14:25 -0500 | [diff] [blame] | 204 | gmod = gb_module_create(hd, module_id); |
| 205 | if (!gmod) { |
| 206 | dev_err(hd->parent, "failed to create module\n"); |
| 207 | return; |
| 208 | } |
| 209 | |
Alex Elder | b09c94a | 2014-10-01 21:54:16 -0500 | [diff] [blame] | 210 | /* |
| 211 | * Parse the manifest and build up our data structures |
| 212 | * representing what's in it. |
| 213 | */ |
Alex Elder | 937d0da | 2014-10-03 14:14:25 -0500 | [diff] [blame] | 214 | if (!gb_manifest_parse(gmod, data, size)) { |
Alex Elder | b09c94a | 2014-10-01 21:54:16 -0500 | [diff] [blame] | 215 | dev_err(hd->parent, "manifest error\n"); |
Alex Elder | 937d0da | 2014-10-03 14:14:25 -0500 | [diff] [blame] | 216 | goto error; |
Alex Elder | b09c94a | 2014-10-01 21:54:16 -0500 | [diff] [blame] | 217 | } |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 218 | |
Alex Elder | 459164b | 2014-10-01 21:54:19 -0500 | [diff] [blame] | 219 | /* |
| 220 | * XXX |
| 221 | * We've successfully parsed the manifest. Now we need to |
| 222 | * allocate CPort Id's for connecting to the CPorts found on |
| 223 | * other modules. For each of these, establish a connection |
| 224 | * between the local and remote CPorts (including |
| 225 | * configuring the switch to allow them to communicate). |
| 226 | */ |
| 227 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 228 | gmod->dev.parent = hd->parent; |
| 229 | gmod->dev.driver = NULL; |
| 230 | gmod->dev.bus = &greybus_bus_type; |
| 231 | gmod->dev.type = &greybus_module_type; |
| 232 | gmod->dev.groups = greybus_module_groups; |
| 233 | gmod->dev.dma_mask = hd->parent->dma_mask; |
| 234 | device_initialize(&gmod->dev); |
| 235 | dev_set_name(&gmod->dev, "%d", module_id); |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 236 | |
Matt Porter | 32dff13 | 2014-10-03 13:38:24 -0400 | [diff] [blame] | 237 | retval = device_add(&gmod->dev); |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 238 | if (retval) |
| 239 | goto error; |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 240 | |
Matt Porter | 32dff13 | 2014-10-03 13:38:24 -0400 | [diff] [blame] | 241 | retval = gb_init_subdevs(gmod, &fake_greybus_module_id); |
| 242 | if (retval) |
| 243 | goto error_subdevs; |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 244 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 245 | //return gmod; |
Greg Kroah-Hartman | 4a833fd | 2014-09-21 19:17:55 -0700 | [diff] [blame] | 246 | return; |
Matt Porter | 32dff13 | 2014-10-03 13:38:24 -0400 | [diff] [blame] | 247 | |
| 248 | error_subdevs: |
| 249 | device_del(&gmod->dev); |
| 250 | |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 251 | error: |
Alex Elder | 937d0da | 2014-10-03 14:14:25 -0500 | [diff] [blame] | 252 | gb_module_destroy(gmod); |
| 253 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 254 | put_device(&gmod->dev); |
| 255 | greybus_module_release(&gmod->dev); |
Greg Kroah-Hartman | a239f67 | 2014-09-01 14:39:49 -0700 | [diff] [blame] | 256 | } |
| 257 | |
Greg Kroah-Hartman | 6779997 | 2014-09-21 18:17:36 -0700 | [diff] [blame] | 258 | void gb_remove_module(struct greybus_host_device *hd, u8 module_id) |
| 259 | { |
Matt Porter | d7f9be4 | 2014-10-03 14:32:35 -0400 | [diff] [blame] | 260 | struct gb_module *gmod; |
| 261 | bool found = false; |
| 262 | |
| 263 | list_for_each_entry(gmod, &hd->modules, links) |
| 264 | if (gmod->module_id == module_id) { |
| 265 | found = true; |
| 266 | break; |
| 267 | } |
| 268 | |
| 269 | if (found) |
| 270 | greybus_remove_device(gmod); |
| 271 | else |
| 272 | dev_err(hd->parent, "module id %d remove error\n", module_id); |
Greg Kroah-Hartman | 6779997 | 2014-09-21 18:17:36 -0700 | [diff] [blame] | 273 | } |
| 274 | |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 275 | void greybus_remove_device(struct gb_module *gmod) |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 276 | { |
| 277 | /* tear down all of the "sub device types" for this device */ |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 278 | gb_i2c_disconnect(gmod); |
| 279 | gb_gpio_disconnect(gmod); |
| 280 | gb_sdio_disconnect(gmod); |
| 281 | gb_tty_disconnect(gmod); |
| 282 | gb_battery_disconnect(gmod); |
Greg Kroah-Hartman | b94295e | 2014-09-01 18:34:28 -0700 | [diff] [blame] | 283 | |
Matt Porter | d7f9be4 | 2014-10-03 14:32:35 -0400 | [diff] [blame] | 284 | device_del(&gmod->dev); |
| 285 | put_device(&gmod->dev); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 286 | } |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 287 | |
Greg Kroah-Hartman | 68f1fc4 | 2014-09-07 13:12:11 -0700 | [diff] [blame] | 288 | static DEFINE_MUTEX(hd_mutex); |
| 289 | |
| 290 | static void free_hd(struct kref *kref) |
| 291 | { |
| 292 | struct greybus_host_device *hd; |
| 293 | |
| 294 | hd = container_of(kref, struct greybus_host_device, kref); |
| 295 | |
| 296 | kfree(hd); |
Alex Elder | a06df4b | 2014-10-16 06:35:26 -0500 | [diff] [blame^] | 297 | mutex_unlock(&hd_mutex); |
Greg Kroah-Hartman | 68f1fc4 | 2014-09-07 13:12:11 -0700 | [diff] [blame] | 298 | } |
| 299 | |
Greg Kroah-Hartman | a39879f | 2014-09-06 16:57:36 -0700 | [diff] [blame] | 300 | struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver, |
| 301 | struct device *parent) |
| 302 | { |
| 303 | struct greybus_host_device *hd; |
| 304 | |
| 305 | hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL); |
| 306 | if (!hd) |
| 307 | return NULL; |
| 308 | |
| 309 | kref_init(&hd->kref); |
Greg Kroah-Hartman | 772149b | 2014-09-14 12:27:28 -0700 | [diff] [blame] | 310 | hd->parent = parent; |
| 311 | hd->driver = driver; |
Alex Elder | e1e9dbd | 2014-10-01 21:54:11 -0500 | [diff] [blame] | 312 | INIT_LIST_HEAD(&hd->modules); |
Alex Elder | ee9ebe4 | 2014-10-06 06:53:08 -0500 | [diff] [blame] | 313 | hd->connections = RB_ROOT; |
Alex Elder | 177404b | 2014-10-03 14:14:24 -0500 | [diff] [blame] | 314 | ida_init(&hd->cport_id_map); |
Greg Kroah-Hartman | 25b7b6d | 2014-10-06 20:29:40 -0700 | [diff] [blame] | 315 | spin_lock_init(&hd->cport_id_map_lock); |
Alex Elder | 1bb3c72 | 2014-10-02 12:30:03 -0500 | [diff] [blame] | 316 | |
Greg Kroah-Hartman | a39879f | 2014-09-06 16:57:36 -0700 | [diff] [blame] | 317 | return hd; |
| 318 | } |
| 319 | EXPORT_SYMBOL_GPL(greybus_create_hd); |
| 320 | |
Greg Kroah-Hartman | 68f1fc4 | 2014-09-07 13:12:11 -0700 | [diff] [blame] | 321 | void greybus_remove_hd(struct greybus_host_device *hd) |
| 322 | { |
| 323 | kref_put_mutex(&hd->kref, free_hd, &hd_mutex); |
| 324 | } |
| 325 | EXPORT_SYMBOL_GPL(greybus_remove_hd); |
| 326 | |
Greg Kroah-Hartman | a39879f | 2014-09-06 16:57:36 -0700 | [diff] [blame] | 327 | |
Greg Kroah-Hartman | 503c1cd | 2014-08-30 16:21:03 -0700 | [diff] [blame] | 328 | static int __init gb_init(void) |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 329 | { |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 330 | int retval; |
| 331 | |
Alex Elder | 1bb3c72 | 2014-10-02 12:30:03 -0500 | [diff] [blame] | 332 | BUILD_BUG_ON(HOST_DEV_CPORT_ID_MAX >= (long)CPORT_ID_BAD); |
Alex Elder | 1bb3c72 | 2014-10-02 12:30:03 -0500 | [diff] [blame] | 333 | |
Greg Kroah-Hartman | de536e3 | 2014-08-31 16:17:04 -0700 | [diff] [blame] | 334 | retval = gb_debugfs_init(); |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 335 | if (retval) { |
| 336 | pr_err("debugfs failed\n"); |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 337 | return retval; |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 338 | } |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 339 | |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 340 | retval = bus_register(&greybus_bus_type); |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 341 | if (retval) { |
| 342 | pr_err("bus_register failed\n"); |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 343 | goto error_bus; |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 344 | } |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 345 | |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 346 | retval = gb_ap_init(); |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 347 | if (retval) { |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 348 | pr_err("gb_ap_init failed\n"); |
| 349 | goto error_ap; |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 350 | } |
Greg Kroah-Hartman | de536e3 | 2014-08-31 16:17:04 -0700 | [diff] [blame] | 351 | |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 352 | retval = gb_gbuf_init(); |
| 353 | if (retval) { |
| 354 | pr_err("gb_gbuf_init failed\n"); |
| 355 | goto error_gbuf; |
| 356 | } |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 357 | |
| 358 | retval = gb_tty_init(); |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 359 | if (retval) { |
| 360 | pr_err("gb_tty_init failed\n"); |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 361 | goto error_tty; |
Greg Kroah-Hartman | 168db1c | 2014-09-13 16:15:52 -0700 | [diff] [blame] | 362 | } |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 363 | |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 364 | return 0; |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 365 | |
| 366 | error_tty: |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 367 | gb_gbuf_exit(); |
Greg Kroah-Hartman | de536e3 | 2014-08-31 16:17:04 -0700 | [diff] [blame] | 368 | |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 369 | error_gbuf: |
| 370 | gb_ap_exit(); |
| 371 | |
| 372 | error_ap: |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 373 | bus_unregister(&greybus_bus_type); |
| 374 | |
| 375 | error_bus: |
Greg Kroah-Hartman | de536e3 | 2014-08-31 16:17:04 -0700 | [diff] [blame] | 376 | gb_debugfs_cleanup(); |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 377 | |
| 378 | return retval; |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 379 | } |
| 380 | |
Greg Kroah-Hartman | 503c1cd | 2014-08-30 16:21:03 -0700 | [diff] [blame] | 381 | static void __exit gb_exit(void) |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 382 | { |
Greg Kroah-Hartman | db6e1fd | 2014-08-30 16:47:26 -0700 | [diff] [blame] | 383 | gb_tty_exit(); |
Greg Kroah-Hartman | 45f3678 | 2014-09-14 11:40:35 -0700 | [diff] [blame] | 384 | gb_gbuf_exit(); |
| 385 | gb_ap_exit(); |
Greg Kroah-Hartman | 27fb831 | 2014-08-31 13:54:59 -0700 | [diff] [blame] | 386 | bus_unregister(&greybus_bus_type); |
Greg Kroah-Hartman | de536e3 | 2014-08-31 16:17:04 -0700 | [diff] [blame] | 387 | gb_debugfs_cleanup(); |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 388 | } |
| 389 | |
| 390 | module_init(gb_init); |
| 391 | module_exit(gb_exit); |
| 392 | |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 393 | MODULE_LICENSE("GPL"); |
| 394 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); |