]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/staging/ipack/ipack.c
Staging: ipack: Read the ID space during device registration.
[mirror_ubuntu-zesty-kernel.git] / drivers / staging / ipack / ipack.c
CommitLineData
d3465872
SIG
1/*
2 * Industry-pack bus support functions.
3 *
4 * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
5 * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
416289b1 9 * Software Foundation; version 2 of the License.
d3465872
SIG
10 */
11
d3465872 12#include <linux/module.h>
ec440335 13#include <linux/slab.h>
3b86bb2e 14#include <linux/idr.h>
d3465872
SIG
15#include "ipack.h"
16
17#define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
18#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
19
3b86bb2e 20static DEFINE_IDA(ipack_ida);
d3465872 21
ec440335
SIG
22static void ipack_device_release(struct device *dev)
23{
24 struct ipack_device *device = to_ipack_dev(dev);
187e4782 25 kfree(device->id);
ec440335
SIG
26 kfree(device);
27}
28
d3465872
SIG
29static int ipack_bus_match(struct device *device, struct device_driver *driver)
30{
31 int ret;
32 struct ipack_device *dev = to_ipack_dev(device);
33 struct ipack_driver *drv = to_ipack_driver(driver);
34
ec440335 35 if ((!drv->ops) || (!drv->ops->match))
d3465872
SIG
36 return -EINVAL;
37
38 ret = drv->ops->match(dev);
39 if (ret)
40 dev->driver = drv;
41
be98cc1d 42 return ret;
d3465872
SIG
43}
44
45static int ipack_bus_probe(struct device *device)
46{
47 struct ipack_device *dev = to_ipack_dev(device);
48
49 if (!dev->driver->ops->probe)
50 return -EINVAL;
51
52 return dev->driver->ops->probe(dev);
53}
54
55static int ipack_bus_remove(struct device *device)
56{
57 struct ipack_device *dev = to_ipack_dev(device);
58
59 if (!dev->driver->ops->remove)
60 return -EINVAL;
61
62 dev->driver->ops->remove(dev);
63 return 0;
64}
65
66static struct bus_type ipack_bus_type = {
67 .name = "ipack",
68 .probe = ipack_bus_probe,
69 .match = ipack_bus_match,
70 .remove = ipack_bus_remove,
71};
72
ec440335
SIG
73struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
74 struct ipack_bus_ops *ops)
d3465872
SIG
75{
76 int bus_nr;
ec440335
SIG
77 struct ipack_bus_device *bus;
78
79 bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL);
80 if (!bus)
81 return NULL;
d3465872 82
3b86bb2e 83 bus_nr = ida_simple_get(&ipack_ida, 0, 0, GFP_KERNEL);
ec440335
SIG
84 if (bus_nr < 0) {
85 kfree(bus);
86 return NULL;
87 }
d3465872
SIG
88
89 bus->bus_nr = bus_nr;
ec440335
SIG
90 bus->parent = parent;
91 bus->slots = slots;
92 bus->ops = ops;
93 return bus;
d3465872
SIG
94}
95EXPORT_SYMBOL_GPL(ipack_bus_register);
96
97int ipack_bus_unregister(struct ipack_bus_device *bus)
98{
3b86bb2e 99 ida_simple_remove(&ipack_ida, bus->bus_nr);
ec440335 100 kfree(bus);
d3465872
SIG
101 return 0;
102}
103EXPORT_SYMBOL_GPL(ipack_bus_unregister);
104
ec440335
SIG
105int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
106 char *name)
d3465872 107{
ec440335
SIG
108 edrv->driver.owner = owner;
109 edrv->driver.name = name;
d3465872
SIG
110 edrv->driver.bus = &ipack_bus_type;
111 return driver_register(&edrv->driver);
112}
113EXPORT_SYMBOL_GPL(ipack_driver_register);
114
115void ipack_driver_unregister(struct ipack_driver *edrv)
116{
117 driver_unregister(&edrv->driver);
118}
119EXPORT_SYMBOL_GPL(ipack_driver_unregister);
120
187e4782
JT
121static int ipack_device_read_id(struct ipack_device *dev)
122{
123 u8 __iomem *idmem;
124 int i;
125 int ret = 0;
126
127 ret = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
128 if (ret) {
129 dev_err(&dev->dev, "error mapping memory\n");
130 return ret;
131 }
132 idmem = dev->id_space.address;
133
134 /* Determine ID PROM Data Format. If we find the ids "IPAC" or "IPAH"
135 * we are dealing with a IndustryPack format 1 device. If we detect
136 * "VITA4 " (16 bit big endian formatted) we are dealing with a
137 * IndustryPack format 2 device */
138 if ((ioread8(idmem + 1) == 'I') &&
139 (ioread8(idmem + 3) == 'P') &&
140 (ioread8(idmem + 5) == 'A') &&
141 ((ioread8(idmem + 7) == 'C') ||
142 (ioread8(idmem + 7) == 'H'))) {
143 dev->id_format = IPACK_ID_VERSION_1;
144 dev->id_avail = ioread8(idmem + 0x15);
145 if ((dev->id_avail < 0x0c) || (dev->id_avail > 0x40)) {
146 dev_warn(&dev->dev, "invalid id size");
147 dev->id_avail = 0x0c;
148 }
149 } else if ((ioread8(idmem + 0) == 'I') &&
150 (ioread8(idmem + 1) == 'V') &&
151 (ioread8(idmem + 2) == 'A') &&
152 (ioread8(idmem + 3) == 'T') &&
153 (ioread8(idmem + 4) == ' ') &&
154 (ioread8(idmem + 5) == '4')) {
155 dev->id_format = IPACK_ID_VERSION_2;
156 dev->id_avail = ioread16be(idmem + 0x16);
157 if ((dev->id_avail < 0x1a) || (dev->id_avail > 0x40)) {
158 dev_warn(&dev->dev, "invalid id size");
159 dev->id_avail = 0x1a;
160 }
161 } else {
162 dev->id_format = IPACK_ID_VERSION_INVALID;
163 dev->id_avail = 0;
164 }
165
166 if (!dev->id_avail) {
167 ret = -ENODEV;
168 goto out;
169 }
170
171 /* Obtain the amount of memory required to store a copy of the complete
172 * ID ROM contents */
173 dev->id = kmalloc(dev->id_avail, GFP_KERNEL);
174 if (!dev->id) {
175 dev_err(&dev->dev, "dev->id alloc failed.\n");
176 ret = -ENOMEM;
177 goto out;
178 }
179 for (i = 0; i < dev->id_avail; i++) {
180 if (dev->id_format == IPACK_ID_VERSION_1)
181 dev->id[i] = ioread8(idmem + (i << 1) + 1);
182 else
183 dev->id[i] = ioread8(idmem + i);
184 }
185
186out:
187 dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
188
189 return ret;
190}
191
ec440335
SIG
192struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
193 int slot, int irqv)
d3465872
SIG
194{
195 int ret;
ec440335
SIG
196 struct ipack_device *dev;
197
198 dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
199 if (!dev)
200 return NULL;
d3465872
SIG
201
202 dev->dev.bus = &ipack_bus_type;
203 dev->dev.release = ipack_device_release;
ec440335
SIG
204 dev->dev.parent = bus->parent;
205 dev->slot = slot;
206 dev->bus_nr = bus->bus_nr;
207 dev->irq = irqv;
208 dev->bus = bus;
d3465872 209 dev_set_name(&dev->dev,
ec440335 210 "ipack-dev.%u.%u", dev->bus_nr, dev->slot);
d3465872 211
187e4782
JT
212 ret = ipack_device_read_id(dev);
213 if (ret < 0) {
214 dev_err(&dev->dev, "error reading device id section.\n");
215 kfree(dev);
216 return NULL;
217 }
218
d3465872
SIG
219 ret = device_register(&dev->dev);
220 if (ret < 0) {
187e4782 221 kfree(dev->id);
ec440335
SIG
222 kfree(dev);
223 return NULL;
d3465872
SIG
224 }
225
ec440335 226 return dev;
d3465872
SIG
227}
228EXPORT_SYMBOL_GPL(ipack_device_register);
229
230void ipack_device_unregister(struct ipack_device *dev)
231{
232 device_unregister(&dev->dev);
233}
234EXPORT_SYMBOL_GPL(ipack_device_unregister);
235
236static int __init ipack_init(void)
237{
3b86bb2e 238 ida_init(&ipack_ida);
d3465872
SIG
239 return bus_register(&ipack_bus_type);
240}
241
242static void __exit ipack_exit(void)
243{
244 bus_unregister(&ipack_bus_type);
3b86bb2e 245 ida_destroy(&ipack_ida);
d3465872
SIG
246}
247
248module_init(ipack_init);
249module_exit(ipack_exit);
250
251MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
252MODULE_LICENSE("GPL");
253MODULE_DESCRIPTION("Industry-pack bus core");