blob: a54bfd7c25e1388868b8929c5e7e7f9a816833dd [file] [log] [blame]
Samuel Iglesias Gonsalvezd3465872012-05-09 15:27:19 +02001/*
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
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/module.h>
16#include <linux/mutex.h>
17#include "ipack.h"
18
19#define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
20#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
21
22/* used when allocating bus numbers */
23#define IPACK_MAXBUS 64
24
25static DEFINE_MUTEX(ipack_mutex);
26
27struct ipack_busmap {
28 unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))];
29};
30static struct ipack_busmap busmap;
31
32static int ipack_bus_match(struct device *device, struct device_driver *driver)
33{
34 int ret;
35 struct ipack_device *dev = to_ipack_dev(device);
36 struct ipack_driver *drv = to_ipack_driver(driver);
37
38 if (!drv->ops->match)
39 return -EINVAL;
40
41 ret = drv->ops->match(dev);
42 if (ret)
43 dev->driver = drv;
44
45 return 0;
46}
47
48static int ipack_bus_probe(struct device *device)
49{
50 struct ipack_device *dev = to_ipack_dev(device);
51
52 if (!dev->driver->ops->probe)
53 return -EINVAL;
54
55 return dev->driver->ops->probe(dev);
56}
57
58static int ipack_bus_remove(struct device *device)
59{
60 struct ipack_device *dev = to_ipack_dev(device);
61
62 if (!dev->driver->ops->remove)
63 return -EINVAL;
64
65 dev->driver->ops->remove(dev);
66 return 0;
67}
68
69static struct bus_type ipack_bus_type = {
70 .name = "ipack",
71 .probe = ipack_bus_probe,
72 .match = ipack_bus_match,
73 .remove = ipack_bus_remove,
74};
75
76static int ipack_assign_bus_number(void)
77{
78 int busnum;
79
80 mutex_lock(&ipack_mutex);
81 busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1);
82
83 if (busnum >= IPACK_MAXBUS) {
84 pr_err("too many buses\n");
85 busnum = -1;
86 goto error_find_busnum;
87 }
88
89 set_bit(busnum, busmap.busmap);
90
91error_find_busnum:
92 mutex_unlock(&ipack_mutex);
93 return busnum;
94}
95
96int ipack_bus_register(struct ipack_bus_device *bus)
97{
98 int bus_nr;
99
100 bus_nr = ipack_assign_bus_number();
101 if (bus_nr < 0)
102 return -1;
103
104 bus->bus_nr = bus_nr;
105 return 0;
106}
107EXPORT_SYMBOL_GPL(ipack_bus_register);
108
109int ipack_bus_unregister(struct ipack_bus_device *bus)
110{
111 mutex_lock(&ipack_mutex);
112 clear_bit(bus->bus_nr, busmap.busmap);
113 mutex_unlock(&ipack_mutex);
114 return 0;
115}
116EXPORT_SYMBOL_GPL(ipack_bus_unregister);
117
118int ipack_driver_register(struct ipack_driver *edrv)
119{
120 edrv->driver.bus = &ipack_bus_type;
121 return driver_register(&edrv->driver);
122}
123EXPORT_SYMBOL_GPL(ipack_driver_register);
124
125void ipack_driver_unregister(struct ipack_driver *edrv)
126{
127 driver_unregister(&edrv->driver);
128}
129EXPORT_SYMBOL_GPL(ipack_driver_unregister);
130
131static void ipack_device_release(struct device *dev)
132{
133}
134
135int ipack_device_register(struct ipack_device *dev)
136{
137 int ret;
138
139 dev->dev.bus = &ipack_bus_type;
140 dev->dev.release = ipack_device_release;
141 dev_set_name(&dev->dev,
142 "%s.%u.%u", dev->board_name, dev->bus_nr, dev->slot);
143
144 ret = device_register(&dev->dev);
145 if (ret < 0) {
146 pr_err("error registering the device.\n");
147 dev->driver->ops->remove(dev);
148 }
149
150 return ret;
151}
152EXPORT_SYMBOL_GPL(ipack_device_register);
153
154void ipack_device_unregister(struct ipack_device *dev)
155{
156 device_unregister(&dev->dev);
157}
158EXPORT_SYMBOL_GPL(ipack_device_unregister);
159
160static int __init ipack_init(void)
161{
162 return bus_register(&ipack_bus_type);
163}
164
165static void __exit ipack_exit(void)
166{
167 bus_unregister(&ipack_bus_type);
168}
169
170module_init(ipack_init);
171module_exit(ipack_exit);
172
173MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
174MODULE_LICENSE("GPL");
175MODULE_DESCRIPTION("Industry-pack bus core");