greybus: connection: drop parent parameter from connection create
[linux-2.6-block.git] / drivers / staging / greybus / interface.c
CommitLineData
e1e9dbdd 1/*
4ab9b3c2 2 * Greybus interface code
e1e9dbdd
AE
3 *
4 * Copyright 2014 Google Inc.
a46e9671 5 * Copyright 2014 Linaro Ltd.
e1e9dbdd
AE
6 *
7 * Released under the GPLv2 only.
8 */
9
10#include "greybus.h"
11
4ab9b3c2
GKH
12/* interface sysfs attributes */
13#define gb_interface_attr(field, type) \
14static ssize_t field##_show(struct device *dev, \
15 struct device_attribute *attr, \
16 char *buf) \
ab88eb58 17{ \
4ab9b3c2 18 struct gb_interface *intf = to_gb_interface(dev); \
505c9d27 19 return scnprintf(buf, PAGE_SIZE, "%"#type"\n", intf->field); \
ab88eb58
GKH
20} \
21static DEVICE_ATTR_RO(field)
22
320421a8 23gb_interface_attr(interface_id, u);
9f59263a
JH
24gb_interface_attr(vendor_id, x);
25gb_interface_attr(product_id, x);
4ab9b3c2
GKH
26gb_interface_attr(vendor_string, s);
27gb_interface_attr(product_string, s);
ab88eb58 28
4ab9b3c2 29static struct attribute *interface_attrs[] = {
320421a8 30 &dev_attr_interface_id.attr,
9f59263a
JH
31 &dev_attr_vendor_id.attr,
32 &dev_attr_product_id.attr,
ab88eb58
GKH
33 &dev_attr_vendor_string.attr,
34 &dev_attr_product_string.attr,
35 NULL,
36};
4ab9b3c2 37ATTRIBUTE_GROUPS(interface);
ab88eb58
GKH
38
39
e1e9dbdd 40/* XXX This could be per-host device */
4901175f 41static DEFINE_SPINLOCK(gb_interfaces_lock);
e1e9dbdd 42
df671553
GKH
43// FIXME, odds are you don't want to call this function, rework the caller to
44// not need it please.
2537636a 45struct gb_interface *gb_interface_find(struct gb_host_device *hd,
c9d9d0d4 46 u8 interface_id)
9ca4d62f 47{
4ab9b3c2 48 struct gb_interface *intf;
9ca4d62f 49
1cd56a80 50 list_for_each_entry(intf, &hd->interfaces, links)
c9d9d0d4 51 if (intf->interface_id == interface_id)
4ab9b3c2 52 return intf;
9ca4d62f
VK
53
54 return NULL;
55}
56
51b5d8d7 57static void gb_interface_release(struct device *dev)
697e55d3 58{
4ab9b3c2 59 struct gb_interface *intf = to_gb_interface(dev);
697e55d3 60
eeb6a6ff
JH
61 kfree(intf->product_string);
62 kfree(intf->vendor_string);
63
4ab9b3c2 64 kfree(intf);
697e55d3
AE
65}
66
4ab9b3c2
GKH
67struct device_type greybus_interface_type = {
68 .name = "greybus_interface",
51b5d8d7 69 .release = gb_interface_release,
f0f61b90
GKH
70};
71
6c68da26
VK
72/*
73 * Create kernel structures corresponding to a bundle and connection for
7a24a3f6 74 * managing control/svc CPort.
6c68da26 75 */
7a24a3f6 76int gb_create_bundle_connection(struct gb_interface *intf, u8 class)
6c68da26
VK
77{
78 struct gb_bundle *bundle;
7a24a3f6
VK
79 u32 ida_start, ida_end;
80 u8 bundle_id, protocol_id;
81 u16 cport_id;
82
83 if (class == GREYBUS_CLASS_CONTROL) {
84 protocol_id = GREYBUS_PROTOCOL_CONTROL;
85 bundle_id = GB_CONTROL_BUNDLE_ID;
86 cport_id = GB_CONTROL_CPORT_ID;
87 ida_start = 0;
144670c2 88 ida_end = intf->hd->num_cports - 1;
7a24a3f6
VK
89 } else if (class == GREYBUS_CLASS_SVC) {
90 protocol_id = GREYBUS_PROTOCOL_SVC;
91 bundle_id = GB_SVC_BUNDLE_ID;
92 cport_id = GB_SVC_CPORT_ID;
93 ida_start = GB_SVC_CPORT_ID;
94 ida_end = GB_SVC_CPORT_ID + 1;
95 } else {
96 WARN_ON(1);
97 return -EINVAL;
98 }
6c68da26 99
7a24a3f6 100 bundle = gb_bundle_create(intf, bundle_id, class);
6c68da26
VK
101 if (!bundle)
102 return -EINVAL;
103
582b3a13 104 if (!gb_connection_create_range(bundle->intf->hd, bundle,
7a24a3f6
VK
105 cport_id, protocol_id, ida_start,
106 ida_end))
6c68da26
VK
107 return -EINVAL;
108
6c68da26
VK
109 return 0;
110}
111
e1e9dbdd 112/*
464dc8cb 113 * A Greybus module represents a user-replaceable component on an Ara
4ab9b3c2
GKH
114 * phone. An interface is the physical connection on that module. A
115 * module may have more than one interface.
e1e9dbdd 116 *
c9d9d0d4
VK
117 * Create a gb_interface structure to represent a discovered interface.
118 * The position of interface within the Endo is encoded in "interface_id"
119 * argument.
120 *
df671553 121 * Returns a pointer to the new interfce or a null pointer if a
e1e9dbdd
AE
122 * failure occurs due to memory exhaustion.
123 */
2537636a 124struct gb_interface *gb_interface_create(struct gb_host_device *hd,
6c68da26 125 u8 interface_id)
e1e9dbdd 126{
df671553 127 struct gb_module *module;
4ab9b3c2 128 struct gb_interface *intf;
f0f61b90 129 int retval;
e1e9dbdd 130
51e93aea 131 module = gb_module_find(hd, endo_get_module_id(hd->endo, interface_id));
df671553
GKH
132 if (!module)
133 return NULL;
134
4ab9b3c2
GKH
135 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
136 if (!intf)
71e49380 137 goto put_module;
e1e9dbdd 138
4ab9b3c2 139 intf->hd = hd; /* XXX refcount? */
df671553 140 intf->module = module;
c9d9d0d4 141 intf->interface_id = interface_id;
4ab9b3c2 142 INIT_LIST_HEAD(&intf->bundles);
86cad666 143 INIT_LIST_HEAD(&intf->manifest_descs);
e1e9dbdd 144
c3add788
VK
145 /* Invalid device id to start with */
146 intf->device_id = GB_DEVICE_ID_BAD;
147
df671553 148 intf->dev.parent = &module->dev;
4ab9b3c2
GKH
149 intf->dev.bus = &greybus_bus_type;
150 intf->dev.type = &greybus_interface_type;
151 intf->dev.groups = interface_groups;
2adaefb1 152 intf->dev.dma_mask = hd->dev.dma_mask;
4ab9b3c2 153 device_initialize(&intf->dev);
df671553 154 dev_set_name(&intf->dev, "%s:%d", dev_name(&module->dev), interface_id);
f0f61b90 155
4ab9b3c2 156 retval = device_add(&intf->dev);
f0f61b90 157 if (retval) {
35a84ba7 158 pr_err("failed to add interface %u\n", interface_id);
71e49380 159 goto free_intf;
f0f61b90
GKH
160 }
161
4901175f 162 spin_lock_irq(&gb_interfaces_lock);
928f2abd 163 list_add(&intf->links, &hd->interfaces);
4901175f 164 spin_unlock_irq(&gb_interfaces_lock);
0a68a16b 165
4ab9b3c2 166 return intf;
71e49380
VK
167
168free_intf:
169 put_device(&intf->dev);
71e49380
VK
170put_module:
171 put_device(&module->dev);
172 return NULL;
e1e9dbdd
AE
173}
174
175/*
febe2521 176 * Tear down a previously set up interface.
e1e9dbdd 177 */
80d1ede8 178void gb_interface_remove(struct gb_interface *intf)
e1e9dbdd 179{
2352a732 180 struct gb_module *module;
fe53b45c
AE
181 struct gb_bundle *bundle;
182 struct gb_bundle *next;
2352a732 183
4ab9b3c2 184 if (WARN_ON(!intf))
e1e9dbdd
AE
185 return;
186
4901175f 187 spin_lock_irq(&gb_interfaces_lock);
4ab9b3c2 188 list_del(&intf->links);
4901175f 189 spin_unlock_irq(&gb_interfaces_lock);
e1e9dbdd 190
fe53b45c
AE
191 list_for_each_entry_safe(bundle, next, &intf->bundles, links)
192 gb_bundle_destroy(bundle);
697e55d3 193
2352a732
VK
194 module = intf->module;
195 device_unregister(&intf->dev);
a4d9150c 196 put_device(&module->dev);
574341c6
AE
197}
198
2537636a 199void gb_interfaces_remove(struct gb_host_device *hd)
80d1ede8
VK
200{
201 struct gb_interface *intf, *temp;
202
203 list_for_each_entry_safe(intf, temp, &hd->interfaces, links)
204 gb_interface_remove(intf);
205}
206
676daaf4 207/**
b950dc28 208 * gb_interface_init
676daaf4 209 *
6c68da26
VK
210 * Create connection for control CPort and then request/parse manifest.
211 * Finally initialize all the bundles to set routes via SVC and initialize all
212 * connections.
676daaf4 213 */
6c68da26 214int gb_interface_init(struct gb_interface *intf, u8 device_id)
676daaf4 215{
6c68da26
VK
216 int ret, size;
217 void *manifest;
218
c3add788
VK
219 intf->device_id = device_id;
220
6c68da26 221 /* Establish control CPort connection */
7a24a3f6 222 ret = gb_create_bundle_connection(intf, GREYBUS_CLASS_CONTROL);
6c68da26
VK
223 if (ret) {
224 dev_err(&intf->dev, "Failed to create control CPort connection (%d)\n", ret);
225 return ret;
226 }
676daaf4 227
6c68da26
VK
228 /* Get manifest size using control protocol on CPort */
229 size = gb_control_get_manifest_size_operation(intf);
230 if (size <= 0) {
231 dev_err(&intf->dev, "%s: Failed to get manifest size (%d)\n",
232 __func__, size);
233 if (size)
234 return size;
235 else
236 return -EINVAL;
237 }
238
239 manifest = kmalloc(size, GFP_KERNEL);
240 if (!manifest)
241 return -ENOMEM;
242
243 /* Get manifest using control protocol on CPort */
244 ret = gb_control_get_manifest_operation(intf, manifest, size);
245 if (ret) {
246 dev_err(&intf->dev, "%s: Failed to get manifest\n", __func__);
247 goto free_manifest;
676daaf4
VK
248 }
249
250 /*
6c68da26
VK
251 * Parse the manifest and build up our data structures representing
252 * what's in it.
676daaf4 253 */
6c68da26
VK
254 if (!gb_manifest_parse(intf, manifest, size)) {
255 dev_err(&intf->dev, "%s: Failed to parse manifest\n", __func__);
256 ret = -EINVAL;
257 goto free_manifest;
676daaf4
VK
258 }
259
260 /*
261 * XXX
262 * We've successfully parsed the manifest. Now we need to
263 * allocate CPort Id's for connecting to the CPorts found on
264 * other modules. For each of these, establish a connection
265 * between the local and remote CPorts (including
266 * configuring the switch to allow them to communicate).
267 */
268
6c68da26
VK
269free_manifest:
270 kfree(manifest);
271 return ret;
676daaf4 272}