blob: 7a4c7dc2e9412387fb6e8d46bfea80ec53dcc78a [file] [log] [blame]
Alex Eldere1e9dbd2014-10-01 21:54:11 -05001/*
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -08002 * Greybus interface code
Alex Eldere1e9dbd2014-10-01 21:54:11 -05003 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 Linaro Ltd.
Alex Eldere1e9dbd2014-10-01 21:54:11 -05006 *
7 * Released under the GPLv2 only.
8 */
9
10#include "greybus.h"
11
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080012/* 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) \
Greg Kroah-Hartmanab88eb52014-12-11 17:10:59 -050017{ \
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080018 struct gb_interface *intf = to_gb_interface(dev); \
19 return sprintf(buf, "%"#type"\n", intf->field); \
Greg Kroah-Hartmanab88eb52014-12-11 17:10:59 -050020} \
21static DEVICE_ATTR_RO(field)
22
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080023gb_interface_attr(vendor, x);
24gb_interface_attr(product, x);
25gb_interface_attr(unique_id, llX);
26gb_interface_attr(vendor_string, s);
27gb_interface_attr(product_string, s);
Greg Kroah-Hartmanab88eb52014-12-11 17:10:59 -050028
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080029static struct attribute *interface_attrs[] = {
Greg Kroah-Hartmanab88eb52014-12-11 17:10:59 -050030 &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};
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080037ATTRIBUTE_GROUPS(interface);
Greg Kroah-Hartmanab88eb52014-12-11 17:10:59 -050038
39
Alex Eldere1e9dbd2014-10-01 21:54:11 -050040/* XXX This could be per-host device */
Greg Kroah-Hartman49011752014-12-19 14:56:37 -080041static DEFINE_SPINLOCK(gb_interfaces_lock);
Alex Eldere1e9dbd2014-10-01 21:54:11 -050042
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080043// FIXME, odds are you don't want to call this function, rework the caller to
44// not need it please.
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080045struct gb_interface *gb_interface_find(struct greybus_host_device *hd,
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +053046 u8 interface_id)
Viresh Kumar9ca4d622014-11-14 17:25:06 +053047{
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080048 struct gb_interface *intf;
Viresh Kumar9ca4d622014-11-14 17:25:06 +053049
Greg Kroah-Hartman1cd56a82014-12-19 14:56:36 -080050 list_for_each_entry(intf, &hd->interfaces, links)
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +053051 if (intf->interface_id == interface_id)
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080052 return intf;
Viresh Kumar9ca4d622014-11-14 17:25:06 +053053
54 return NULL;
55}
56
Viresh Kumar51b5d8d2015-05-20 17:33:51 +053057static void gb_interface_release(struct device *dev)
Alex Elder697e55d2014-10-20 23:01:04 -050058{
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080059 struct gb_interface *intf = to_gb_interface(dev);
Alex Elder697e55d2014-10-20 23:01:04 -050060
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080061 kfree(intf);
Alex Elder697e55d2014-10-20 23:01:04 -050062}
63
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080064struct device_type greybus_interface_type = {
65 .name = "greybus_interface",
Viresh Kumar51b5d8d2015-05-20 17:33:51 +053066 .release = gb_interface_release,
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080067};
68
Alex Eldere1e9dbd2014-10-01 21:54:11 -050069/*
Viresh Kumar696e0cc2014-11-21 11:26:30 +053070 * A Greybus module represents a user-replicable component on an Ara
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080071 * phone. An interface is the physical connection on that module. A
72 * module may have more than one interface.
Alex Eldere1e9dbd2014-10-01 21:54:11 -050073 *
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +053074 * Create a gb_interface structure to represent a discovered interface.
75 * The position of interface within the Endo is encoded in "interface_id"
76 * argument.
77 *
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080078 * Returns a pointer to the new interfce or a null pointer if a
Alex Eldere1e9dbd2014-10-01 21:54:11 -050079 * failure occurs due to memory exhaustion.
80 */
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080081static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +053082 u8 interface_id)
Alex Eldere1e9dbd2014-10-01 21:54:11 -050083{
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080084 struct gb_module *module;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080085 struct gb_interface *intf;
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080086 int retval;
Alex Eldere1e9dbd2014-10-01 21:54:11 -050087
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080088 intf = gb_interface_find(hd, interface_id);
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080089 if (intf) {
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +053090 dev_err(hd->parent, "Duplicate interface with interface-id: %d will not be created\n",
91 interface_id);
Greg Kroah-Hartman066799c2014-10-24 18:46:15 +080092 return NULL;
93 }
94
Viresh Kumar51e93ae2015-05-08 12:58:51 +053095 module = gb_module_find(hd, endo_get_module_id(hd->endo, interface_id));
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080096 if (!module)
97 return NULL;
98
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -080099 intf = kzalloc(sizeof(*intf), GFP_KERNEL);
100 if (!intf)
Viresh Kumar71e49382015-03-24 20:14:29 +0530101 goto put_module;
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500102
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800103 intf->hd = hd; /* XXX refcount? */
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -0800104 intf->module = module;
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530105 intf->interface_id = interface_id;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800106 INIT_LIST_HEAD(&intf->bundles);
Greg Kroah-Hartman86cad662014-12-23 15:16:50 -0800107 INIT_LIST_HEAD(&intf->manifest_descs);
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500108
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -0800109 intf->dev.parent = &module->dev;
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800110 intf->dev.bus = &greybus_bus_type;
111 intf->dev.type = &greybus_interface_type;
112 intf->dev.groups = interface_groups;
113 intf->dev.dma_mask = hd->parent->dma_mask;
114 device_initialize(&intf->dev);
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -0800115 dev_set_name(&intf->dev, "%s:%d", dev_name(&module->dev), interface_id);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800116
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800117 retval = device_add(&intf->dev);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800118 if (retval) {
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530119 pr_err("failed to add interface device for id 0x%02hhx\n",
120 interface_id);
Viresh Kumar71e49382015-03-24 20:14:29 +0530121 goto free_intf;
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800122 }
123
Greg Kroah-Hartman49011752014-12-19 14:56:37 -0800124 spin_lock_irq(&gb_interfaces_lock);
Greg Kroah-Hartman1cd56a82014-12-19 14:56:36 -0800125 list_add_tail(&intf->links, &hd->interfaces);
Greg Kroah-Hartman49011752014-12-19 14:56:37 -0800126 spin_unlock_irq(&gb_interfaces_lock);
Viresh Kumar0a68a162014-11-13 18:14:37 +0530127
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800128 return intf;
Viresh Kumar71e49382015-03-24 20:14:29 +0530129
130free_intf:
131 put_device(&intf->dev);
132 kfree(intf);
133put_module:
134 put_device(&module->dev);
135 return NULL;
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500136}
137
138/*
139 * Tear down a previously set up module.
140 */
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800141static void gb_interface_destroy(struct gb_interface *intf)
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500142{
Viresh Kumar2352a732015-04-02 17:53:47 +0530143 struct gb_module *module;
144
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800145 if (WARN_ON(!intf))
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500146 return;
147
Greg Kroah-Hartman49011752014-12-19 14:56:37 -0800148 spin_lock_irq(&gb_interfaces_lock);
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800149 list_del(&intf->links);
Greg Kroah-Hartman49011752014-12-19 14:56:37 -0800150 spin_unlock_irq(&gb_interfaces_lock);
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500151
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800152 gb_bundle_destroy(intf);
Alex Elder697e55d2014-10-20 23:01:04 -0500153
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800154 kfree(intf->product_string);
155 kfree(intf->vendor_string);
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500156 /* kref_put(module->hd); */
157
Viresh Kumar2352a732015-04-02 17:53:47 +0530158 module = intf->module;
159 device_unregister(&intf->dev);
Greg Kroah-Hartmana4d91502015-04-07 20:27:15 +0200160 put_device(&module->dev);
Alex Elder574341c2014-10-16 06:35:35 -0500161}
162
Viresh Kumar676daaf2014-11-14 17:25:07 +0530163/**
Viresh Kumar51b5d8d2015-05-20 17:33:51 +0530164 * gb_interface_add
Viresh Kumar676daaf2014-11-14 17:25:07 +0530165 *
Viresh Kumara93db2d2015-04-01 20:32:02 +0530166 * Pass in a buffer that _should_ contain a Greybus manifest
Viresh Kumar676daaf2014-11-14 17:25:07 +0530167 * and register a greybus device structure with the kernel core.
168 */
Viresh Kumar51b5d8d2015-05-20 17:33:51 +0530169void gb_interface_add(struct greybus_host_device *hd, u8 interface_id, u8 *data,
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530170 int size)
Viresh Kumar676daaf2014-11-14 17:25:07 +0530171{
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800172 struct gb_interface *intf;
Viresh Kumar676daaf2014-11-14 17:25:07 +0530173
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530174 intf = gb_interface_create(hd, interface_id);
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800175 if (!intf) {
176 dev_err(hd->parent, "failed to create interface\n");
Viresh Kumar676daaf2014-11-14 17:25:07 +0530177 return;
178 }
179
180 /*
181 * Parse the manifest and build up our data structures
182 * representing what's in it.
183 */
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800184 if (!gb_manifest_parse(intf, data, size)) {
Viresh Kumar676daaf2014-11-14 17:25:07 +0530185 dev_err(hd->parent, "manifest error\n");
Greg Kroah-Hartman13e6aac2014-12-19 14:56:35 -0800186 goto err_parse;
Viresh Kumar676daaf2014-11-14 17:25:07 +0530187 }
188
189 /*
190 * XXX
191 * We've successfully parsed the manifest. Now we need to
192 * allocate CPort Id's for connecting to the CPorts found on
193 * other modules. For each of these, establish a connection
194 * between the local and remote CPorts (including
195 * configuring the switch to allow them to communicate).
196 */
197
198 return;
199
Greg Kroah-Hartman13e6aac2014-12-19 14:56:35 -0800200err_parse:
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800201 gb_interface_destroy(intf);
Viresh Kumar676daaf2014-11-14 17:25:07 +0530202}
203
Viresh Kumar51b5d8d2015-05-20 17:33:51 +0530204void gb_interface_remove(struct greybus_host_device *hd, u8 interface_id)
Viresh Kumar676daaf2014-11-14 17:25:07 +0530205{
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530206 struct gb_interface *intf = gb_interface_find(hd, interface_id);
Viresh Kumar676daaf2014-11-14 17:25:07 +0530207
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800208 if (intf)
209 gb_interface_destroy(intf);
Viresh Kumar676daaf2014-11-14 17:25:07 +0530210 else
Viresh Kumarc9d9d0d2015-04-01 20:31:58 +0530211 dev_err(hd->parent, "interface id %d not found\n",
212 interface_id);
Viresh Kumar676daaf2014-11-14 17:25:07 +0530213}
214
Viresh Kumar51b5d8d2015-05-20 17:33:51 +0530215void gb_interfaces_remove(struct greybus_host_device *hd)
Viresh Kumar676daaf2014-11-14 17:25:07 +0530216{
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800217 struct gb_interface *intf, *temp;
Viresh Kumar676daaf2014-11-14 17:25:07 +0530218
Greg Kroah-Hartman1cd56a82014-12-19 14:56:36 -0800219 list_for_each_entry_safe(intf, temp, &hd->interfaces, links)
Greg Kroah-Hartman4ab9b3c2014-12-19 14:56:31 -0800220 gb_interface_destroy(intf);
Viresh Kumar676daaf2014-11-14 17:25:07 +0530221}