greybus: interface: drop the control bundle
[cascardo/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 scnprintf(buf, PAGE_SIZE, "%"#type"\n", intf->field);    \
20 }                                                                       \
21 static DEVICE_ATTR_RO(field)
22
23 gb_interface_attr(interface_id, u);
24 gb_interface_attr(vendor_id, x);
25 gb_interface_attr(product_id, x);
26 gb_interface_attr(vendor_string, s);
27 gb_interface_attr(product_string, s);
28
29 static struct attribute *interface_attrs[] = {
30         &dev_attr_interface_id.attr,
31         &dev_attr_vendor_id.attr,
32         &dev_attr_product_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 // FIXME, odds are you don't want to call this function, rework the caller to
44 // not need it please.
45 struct gb_interface *gb_interface_find(struct gb_host_device *hd,
46                                        u8 interface_id)
47 {
48         struct gb_interface *intf;
49
50         list_for_each_entry(intf, &hd->interfaces, links)
51                 if (intf->interface_id == interface_id)
52                         return intf;
53
54         return NULL;
55 }
56
57 static void gb_interface_release(struct device *dev)
58 {
59         struct gb_interface *intf = to_gb_interface(dev);
60
61         kfree(intf->product_string);
62         kfree(intf->vendor_string);
63
64         kfree(intf);
65 }
66
67 struct device_type greybus_interface_type = {
68         .name =         "greybus_interface",
69         .release =      gb_interface_release,
70 };
71
72 /*
73  * A Greybus module represents a user-replaceable component on an Ara
74  * phone.  An interface is the physical connection on that module.  A
75  * module may have more than one interface.
76  *
77  * Create a gb_interface structure to represent a discovered interface.
78  * The position of interface within the Endo is encoded in "interface_id"
79  * argument.
80  *
81  * Returns a pointer to the new interfce or a null pointer if a
82  * failure occurs due to memory exhaustion.
83  */
84 struct gb_interface *gb_interface_create(struct gb_host_device *hd,
85                                          u8 interface_id)
86 {
87         struct gb_interface *intf;
88         int retval;
89
90         intf = kzalloc(sizeof(*intf), GFP_KERNEL);
91         if (!intf)
92                 return NULL;
93
94         intf->hd = hd;          /* XXX refcount? */
95         intf->interface_id = interface_id;
96         INIT_LIST_HEAD(&intf->bundles);
97         INIT_LIST_HEAD(&intf->manifest_descs);
98
99         /* Invalid device id to start with */
100         intf->device_id = GB_DEVICE_ID_BAD;
101
102         intf->dev.parent = &hd->dev;
103         intf->dev.bus = &greybus_bus_type;
104         intf->dev.type = &greybus_interface_type;
105         intf->dev.groups = interface_groups;
106         intf->dev.dma_mask = hd->dev.dma_mask;
107         device_initialize(&intf->dev);
108         dev_set_name(&intf->dev, "%d-%d", hd->bus_id, interface_id);
109
110         retval = device_add(&intf->dev);
111         if (retval) {
112                 pr_err("failed to add interface %u\n", interface_id);
113                 goto free_intf;
114         }
115
116         spin_lock_irq(&gb_interfaces_lock);
117         list_add(&intf->links, &hd->interfaces);
118         spin_unlock_irq(&gb_interfaces_lock);
119
120         return intf;
121
122 free_intf:
123         put_device(&intf->dev);
124         return NULL;
125 }
126
127 /*
128  * Tear down a previously set up interface.
129  */
130 void gb_interface_remove(struct gb_interface *intf)
131 {
132         struct gb_bundle *bundle;
133         struct gb_bundle *next;
134
135         if (WARN_ON(!intf))
136                 return;
137
138         spin_lock_irq(&gb_interfaces_lock);
139         list_del(&intf->links);
140         spin_unlock_irq(&gb_interfaces_lock);
141
142         list_for_each_entry_safe(bundle, next, &intf->bundles, links)
143                 gb_bundle_destroy(bundle);
144
145         if (intf->control)
146                 gb_connection_destroy(intf->control->connection);
147
148         device_unregister(&intf->dev);
149 }
150
151 void gb_interfaces_remove(struct gb_host_device *hd)
152 {
153         struct gb_interface *intf, *temp;
154
155         list_for_each_entry_safe(intf, temp, &hd->interfaces, links)
156                 gb_interface_remove(intf);
157 }
158
159 /**
160  * gb_interface_init
161  *
162  * Create connection for control CPort and then request/parse manifest.
163  * Finally initialize all the bundles to set routes via SVC and initialize all
164  * connections.
165  */
166 int gb_interface_init(struct gb_interface *intf, u8 device_id)
167 {
168         struct gb_connection *connection;
169         int ret, size;
170         void *manifest;
171
172         intf->device_id = device_id;
173
174         /* Establish control CPort connection */
175         connection = gb_connection_create_dynamic(intf, NULL,
176                                                 GB_CONTROL_CPORT_ID,
177                                                 GREYBUS_PROTOCOL_CONTROL);
178         if (!connection) {
179                 dev_err(&intf->dev, "failed to create control connection\n");
180                 return -ENOMEM;
181         }
182
183         /* Get manifest size using control protocol on CPort */
184         size = gb_control_get_manifest_size_operation(intf);
185         if (size <= 0) {
186                 dev_err(&intf->dev, "%s: Failed to get manifest size (%d)\n",
187                         __func__, size);
188                 if (size)
189                         return size;
190                 else
191                         return -EINVAL;
192         }
193
194         manifest = kmalloc(size, GFP_KERNEL);
195         if (!manifest)
196                 return -ENOMEM;
197
198         /* Get manifest using control protocol on CPort */
199         ret = gb_control_get_manifest_operation(intf, manifest, size);
200         if (ret) {
201                 dev_err(&intf->dev, "%s: Failed to get manifest\n", __func__);
202                 goto free_manifest;
203         }
204
205         /*
206          * Parse the manifest and build up our data structures representing
207          * what's in it.
208          */
209         if (!gb_manifest_parse(intf, manifest, size)) {
210                 dev_err(&intf->dev, "%s: Failed to parse manifest\n", __func__);
211                 ret = -EINVAL;
212                 goto free_manifest;
213         }
214
215         /*
216          * XXX
217          * We've successfully parsed the manifest.  Now we need to
218          * allocate CPort Id's for connecting to the CPorts found on
219          * other modules.  For each of these, establish a connection
220          * between the local and remote CPorts (including
221          * configuring the switch to allow them to communicate).
222          */
223
224 free_manifest:
225         kfree(manifest);
226         return ret;
227 }