]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/greybus/module.c
greybus: Random spell fixes
[karo-tx-linux.git] / drivers / staging / greybus / module.c
1 /*
2  * Greybus modules
3  *
4  * Copyright 2014 Google Inc.
5  *
6  * Released under the GPLv2 only.
7  */
8
9 #include "greybus.h"
10
11 /* XXX This could be per-host device */
12 static DEFINE_SPINLOCK(gb_modules_lock);
13
14 static int gb_module_match_one_id(struct gb_module *gmod,
15                                 const struct greybus_module_id *id)
16 {
17         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
18             (id->vendor != gmod->vendor))
19                 return 0;
20
21         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
22             (id->product != gmod->product))
23                 return 0;
24
25         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
26             (id->unique_id != gmod->unique_id))
27                 return 0;
28
29         return 1;
30 }
31
32 const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
33                                 const struct greybus_module_id *id)
34 {
35         if (id == NULL)
36                 return NULL;
37
38         for (; id->vendor || id->product || id->unique_id ||
39                         id->driver_info; id++) {
40                 if (gb_module_match_one_id(gmod, id))
41                         return id;
42         }
43
44         return NULL;
45 }
46
47 struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id)
48 {
49         struct gb_module *module;
50
51         list_for_each_entry(module, &hd->modules, links)
52                 if (module->module_id == module_id)
53                         return module;
54
55         return NULL;
56 }
57
58 static void greybus_module_release(struct device *dev)
59 {
60         struct gb_module *gmod = to_gb_module(dev);
61
62         kfree(gmod);
63 }
64
65 struct device_type greybus_module_type = {
66         .name =         "greybus_module",
67         .release =      greybus_module_release,
68 };
69
70 /*
71  * A Greybus module represents a user-replicable component on an Ara
72  * phone.
73  *
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.
78  */
79 struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
80 {
81         struct gb_module *gmod;
82         int retval;
83
84         gmod = gb_module_find(hd, module_id);
85         if (gmod) {
86                 dev_err(hd->parent, "Duplicate module id %d will not be created\n",
87                         module_id);
88                 return NULL;
89         }
90
91         gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
92         if (!gmod)
93                 return NULL;
94
95         gmod->hd = hd;          /* XXX refcount? */
96         gmod->module_id = module_id;
97         INIT_LIST_HEAD(&gmod->interfaces);
98
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);
106
107         retval = device_add(&gmod->dev);
108         if (retval) {
109                 pr_err("failed to add module device for id 0x%02hhx\n",
110                         module_id);
111                 put_device(&gmod->dev);
112                 kfree(gmod);
113                 return NULL;
114         }
115
116         spin_lock_irq(&gb_modules_lock);
117         list_add_tail(&gmod->links, &hd->modules);
118         spin_unlock_irq(&gb_modules_lock);
119
120         return gmod;
121 }
122
123 /*
124  * Tear down a previously set up module.
125  */
126 void gb_module_destroy(struct gb_module *gmod)
127 {
128         if (WARN_ON(!gmod))
129                 return;
130
131         spin_lock_irq(&gb_modules_lock);
132         list_del(&gmod->links);
133         spin_unlock_irq(&gb_modules_lock);
134
135         /* XXX Do something with gmod->gb_tty */
136
137         gb_interface_destroy(gmod);
138
139         kfree(gmod->product_string);
140         kfree(gmod->vendor_string);
141         /* kref_put(module->hd); */
142
143         device_del(&gmod->dev);
144 }
145
146 /**
147  * gb_add_module
148  *
149  * Pass in a buffer that _should_ contain a Greybus module manifest
150  * and register a greybus device structure with the kernel core.
151  */
152 void gb_add_module(struct greybus_host_device *hd, u8 module_id,
153                    u8 *data, int size)
154 {
155         struct gb_module *gmod;
156
157         gmod = gb_module_create(hd, module_id);
158         if (!gmod) {
159                 dev_err(hd->parent, "failed to create module\n");
160                 return;
161         }
162
163         /*
164          * Parse the manifest and build up our data structures
165          * representing what's in it.
166          */
167         if (!gb_manifest_parse(gmod, data, size)) {
168                 dev_err(hd->parent, "manifest error\n");
169                 goto err_module;
170         }
171
172         /*
173          * XXX
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).
179          */
180
181         return;
182
183 err_module:
184         gb_module_destroy(gmod);
185 }
186
187 void gb_remove_module(struct greybus_host_device *hd, u8 module_id)
188 {
189         struct gb_module *gmod = gb_module_find(hd, module_id);
190
191         if (gmod)
192                 gb_module_destroy(gmod);
193         else
194                 dev_err(hd->parent, "module id %d not found\n", module_id);
195 }
196
197 void gb_remove_modules(struct greybus_host_device *hd)
198 {
199         struct gb_module *gmod, *temp;
200
201         list_for_each_entry_safe(gmod, temp, &hd->modules, links)
202                 gb_module_destroy(gmod);
203 }