]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/greybus/interface.c
greybus: interface: Fetch interface id instead of module id during setup
[karo-tx-linux.git] / drivers / staging / greybus / interface.c
1 /*
2  * Greybus interface code
3  *
4  * Copyright 2014 Google Inc.
5  * Copyright 2014 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #include "greybus.h"
11
12 /* interface sysfs attributes */
13 #define gb_interface_attr(field, type)                                  \
14 static ssize_t field##_show(struct device *dev,                         \
15                             struct device_attribute *attr,              \
16                             char *buf)                                  \
17 {                                                                       \
18         struct gb_interface *intf = to_gb_interface(dev);               \
19         return sprintf(buf, "%"#type"\n", intf->field);                 \
20 }                                                                       \
21 static DEVICE_ATTR_RO(field)
22
23 gb_interface_attr(vendor, x);
24 gb_interface_attr(product, x);
25 gb_interface_attr(unique_id, llX);
26 gb_interface_attr(vendor_string, s);
27 gb_interface_attr(product_string, s);
28
29 static struct attribute *interface_attrs[] = {
30         &dev_attr_vendor.attr,
31         &dev_attr_product.attr,
32         &dev_attr_unique_id.attr,
33         &dev_attr_vendor_string.attr,
34         &dev_attr_product_string.attr,
35         NULL,
36 };
37 ATTRIBUTE_GROUPS(interface);
38
39
40 /* XXX This could be per-host device */
41 static DEFINE_SPINLOCK(gb_interfaces_lock);
42
43 static int gb_interface_match_one_id(struct gb_interface *intf,
44                                      const struct greybus_interface_id *id)
45 {
46         if ((id->match_flags & GREYBUS_ID_MATCH_VENDOR) &&
47             (id->vendor != intf->vendor))
48                 return 0;
49
50         if ((id->match_flags & GREYBUS_ID_MATCH_PRODUCT) &&
51             (id->product != intf->product))
52                 return 0;
53
54         if ((id->match_flags & GREYBUS_ID_MATCH_SERIAL) &&
55             (id->unique_id != intf->unique_id))
56                 return 0;
57
58         return 1;
59 }
60
61 const struct greybus_interface_id *
62 gb_interface_match_id(struct gb_interface *intf,
63                       const struct greybus_interface_id *id)
64 {
65         if (id == NULL)
66                 return NULL;
67
68         for (; id->vendor || id->product || id->unique_id ||
69                         id->driver_info; id++) {
70                 if (gb_interface_match_one_id(intf, id))
71                         return id;
72         }
73
74         return NULL;
75 }
76
77 // FIXME, odds are you don't want to call this function, rework the caller to
78 // not need it please.
79 struct gb_interface *gb_interface_find(struct greybus_host_device *hd,
80                                        u8 interface_id)
81 {
82         struct gb_interface *intf;
83
84         list_for_each_entry(intf, &hd->interfaces, links)
85                 if (intf->interface_id == interface_id)
86                         return intf;
87
88         return NULL;
89 }
90
91 static void greybus_interface_release(struct device *dev)
92 {
93         struct gb_interface *intf = to_gb_interface(dev);
94
95         kfree(intf);
96 }
97
98 struct device_type greybus_interface_type = {
99         .name =         "greybus_interface",
100         .release =      greybus_interface_release,
101 };
102
103 /*
104  * A Greybus module represents a user-replicable component on an Ara
105  * phone.  An interface is the physical connection on that module.  A
106  * module may have more than one interface.
107  *
108  * Create a gb_interface structure to represent a discovered interface.
109  * The position of interface within the Endo is encoded in "interface_id"
110  * argument.
111  *
112  * Returns a pointer to the new interfce or a null pointer if a
113  * failure occurs due to memory exhaustion.
114  */
115 static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
116                                                 u8 interface_id)
117 {
118         struct gb_module *module;
119         struct gb_interface *intf;
120         int retval;
121
122         intf = gb_interface_find(hd, interface_id);
123         if (intf) {
124                 dev_err(hd->parent, "Duplicate interface with interface-id: %d will not be created\n",
125                         interface_id);
126                 return NULL;
127         }
128
129         module = gb_module_find_or_create(hd, get_module_id(interface_id));
130         if (!module)
131                 return NULL;
132
133         intf = kzalloc(sizeof(*intf), GFP_KERNEL);
134         if (!intf)
135                 goto put_module;
136
137         intf->hd = hd;          /* XXX refcount? */
138         intf->module = module;
139         intf->interface_id = interface_id;
140         INIT_LIST_HEAD(&intf->bundles);
141         INIT_LIST_HEAD(&intf->manifest_descs);
142
143         intf->dev.parent = &module->dev;
144         intf->dev.bus = &greybus_bus_type;
145         intf->dev.type = &greybus_interface_type;
146         intf->dev.groups = interface_groups;
147         intf->dev.dma_mask = hd->parent->dma_mask;
148         device_initialize(&intf->dev);
149         dev_set_name(&intf->dev, "%s:%d", dev_name(&module->dev), interface_id);
150
151         retval = device_add(&intf->dev);
152         if (retval) {
153                 pr_err("failed to add interface device for id 0x%02hhx\n",
154                        interface_id);
155                 goto free_intf;
156         }
157
158         spin_lock_irq(&gb_interfaces_lock);
159         list_add_tail(&intf->links, &hd->interfaces);
160         spin_unlock_irq(&gb_interfaces_lock);
161
162         return intf;
163
164 free_intf:
165         put_device(&intf->dev);
166         kfree(intf);
167 put_module:
168         put_device(&module->dev);
169         return NULL;
170 }
171
172 /*
173  * Tear down a previously set up module.
174  */
175 static void gb_interface_destroy(struct gb_interface *intf)
176 {
177         struct gb_module *module;
178
179         if (WARN_ON(!intf))
180                 return;
181
182         spin_lock_irq(&gb_interfaces_lock);
183         list_del(&intf->links);
184         spin_unlock_irq(&gb_interfaces_lock);
185
186         gb_bundle_destroy(intf);
187
188         kfree(intf->product_string);
189         kfree(intf->vendor_string);
190         /* kref_put(module->hd); */
191
192         module = intf->module;
193         device_unregister(&intf->dev);
194         gb_module_remove(module);
195 }
196
197 /**
198  * gb_add_interface
199  *
200  * Pass in a buffer that _should_ contain a Greybus module manifest
201  * and register a greybus device structure with the kernel core.
202  */
203 void gb_add_interface(struct greybus_host_device *hd, u8 interface_id, u8 *data,
204                       int size)
205 {
206         struct gb_interface *intf;
207
208         intf = gb_interface_create(hd, interface_id);
209         if (!intf) {
210                 dev_err(hd->parent, "failed to create interface\n");
211                 return;
212         }
213
214         /*
215          * Parse the manifest and build up our data structures
216          * representing what's in it.
217          */
218         if (!gb_manifest_parse(intf, data, size)) {
219                 dev_err(hd->parent, "manifest error\n");
220                 goto err_parse;
221         }
222
223         /*
224          * XXX
225          * We've successfully parsed the manifest.  Now we need to
226          * allocate CPort Id's for connecting to the CPorts found on
227          * other modules.  For each of these, establish a connection
228          * between the local and remote CPorts (including
229          * configuring the switch to allow them to communicate).
230          */
231
232         return;
233
234 err_parse:
235         gb_interface_destroy(intf);
236 }
237
238 void gb_remove_interface(struct greybus_host_device *hd, u8 interface_id)
239 {
240         struct gb_interface *intf = gb_interface_find(hd, interface_id);
241
242         if (intf)
243                 gb_interface_destroy(intf);
244         else
245                 dev_err(hd->parent, "interface id %d not found\n",
246                         interface_id);
247 }
248
249 void gb_remove_interfaces(struct greybus_host_device *hd)
250 {
251         struct gb_interface *intf, *temp;
252
253         list_for_each_entry_safe(intf, temp, &hd->interfaces, links)
254                 gb_interface_destroy(intf);
255 }