Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
394b701c MP |
2 | /* |
3 | * RapidIO driver support | |
4 | * | |
5 | * Copyright 2005 MontaVista Software, Inc. | |
6 | * Matt Porter <mporter@kernel.crashing.org> | |
394b701c MP |
7 | */ |
8 | ||
9 | #include <linux/init.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/rio.h> | |
12 | #include <linux/rio_ids.h> | |
48d6b4dd | 13 | #include <linux/rio_drv.h> |
394b701c MP |
14 | |
15 | #include "rio.h" | |
16 | ||
17 | /** | |
18 | * rio_match_device - Tell if a RIO device has a matching RIO device id structure | |
19 | * @id: the RIO device id structure to match against | |
20 | * @rdev: the RIO device structure to match against | |
21 | * | |
22 | * Used from driver probe and bus matching to check whether a RIO device | |
23 | * matches a device id structure provided by a RIO driver. Returns the | |
24 | * matching &struct rio_device_id or %NULL if there is no match. | |
25 | */ | |
26 | static const struct rio_device_id *rio_match_device(const struct rio_device_id | |
27 | *id, | |
28 | const struct rio_dev *rdev) | |
29 | { | |
30 | while (id->vid || id->asm_vid) { | |
31 | if (((id->vid == RIO_ANY_ID) || (id->vid == rdev->vid)) && | |
32 | ((id->did == RIO_ANY_ID) || (id->did == rdev->did)) && | |
33 | ((id->asm_vid == RIO_ANY_ID) | |
34 | || (id->asm_vid == rdev->asm_vid)) | |
35 | && ((id->asm_did == RIO_ANY_ID) | |
36 | || (id->asm_did == rdev->asm_did))) | |
37 | return id; | |
38 | id++; | |
39 | } | |
40 | return NULL; | |
41 | } | |
42 | ||
43 | /** | |
44 | * rio_dev_get - Increments the reference count of the RIO device structure | |
45 | * | |
46 | * @rdev: RIO device being referenced | |
47 | * | |
48 | * Each live reference to a device should be refcounted. | |
49 | * | |
50 | * Drivers for RIO devices should normally record such references in | |
51 | * their probe() methods, when they bind to a device, and release | |
52 | * them by calling rio_dev_put(), in their disconnect() methods. | |
53 | */ | |
54 | struct rio_dev *rio_dev_get(struct rio_dev *rdev) | |
55 | { | |
56 | if (rdev) | |
57 | get_device(&rdev->dev); | |
58 | ||
59 | return rdev; | |
60 | } | |
61 | ||
62 | /** | |
63 | * rio_dev_put - Release a use of the RIO device structure | |
64 | * | |
65 | * @rdev: RIO device being disconnected | |
66 | * | |
67 | * Must be called when a user of a device is finished with it. | |
68 | * When the last user of the device calls this function, the | |
69 | * memory of the device is freed. | |
70 | */ | |
71 | void rio_dev_put(struct rio_dev *rdev) | |
72 | { | |
73 | if (rdev) | |
74 | put_device(&rdev->dev); | |
75 | } | |
76 | ||
77 | /** | |
7b089c8b | 78 | * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure |
394b701c MP |
79 | * @dev: the RIO device structure to match against |
80 | * | |
81 | * return 0 and set rio_dev->driver when drv claims rio_dev, else error | |
82 | */ | |
83 | static int rio_device_probe(struct device *dev) | |
84 | { | |
85 | struct rio_driver *rdrv = to_rio_driver(dev->driver); | |
86 | struct rio_dev *rdev = to_rio_dev(dev); | |
87 | int error = -ENODEV; | |
88 | const struct rio_device_id *id; | |
89 | ||
90 | if (!rdev->driver && rdrv->probe) { | |
91 | if (!rdrv->id_table) | |
92 | return error; | |
93 | id = rio_match_device(rdrv->id_table, rdev); | |
94 | rio_dev_get(rdev); | |
95 | if (id) | |
96 | error = rdrv->probe(rdev, id); | |
97 | if (error >= 0) { | |
98 | rdev->driver = rdrv; | |
99 | error = 0; | |
a7de3902 | 100 | } else |
394b701c | 101 | rio_dev_put(rdev); |
394b701c MP |
102 | } |
103 | return error; | |
104 | } | |
105 | ||
106 | /** | |
107 | * rio_device_remove - Remove a RIO device from the system | |
108 | * | |
109 | * @dev: the RIO device structure to match against | |
110 | * | |
111 | * Remove a RIO device from the system. If it has an associated | |
112 | * driver, then run the driver remove() method. Then update | |
113 | * the reference count. | |
114 | */ | |
fc7a6209 | 115 | static void rio_device_remove(struct device *dev) |
394b701c MP |
116 | { |
117 | struct rio_dev *rdev = to_rio_dev(dev); | |
118 | struct rio_driver *rdrv = rdev->driver; | |
119 | ||
120 | if (rdrv) { | |
121 | if (rdrv->remove) | |
122 | rdrv->remove(rdev); | |
123 | rdev->driver = NULL; | |
124 | } | |
125 | ||
126 | rio_dev_put(rdev); | |
394b701c MP |
127 | } |
128 | ||
83dc2cbc AB |
129 | static void rio_device_shutdown(struct device *dev) |
130 | { | |
131 | struct rio_dev *rdev = to_rio_dev(dev); | |
132 | struct rio_driver *rdrv = rdev->driver; | |
133 | ||
134 | dev_dbg(dev, "RIO: %s\n", __func__); | |
135 | ||
136 | if (rdrv && rdrv->shutdown) | |
137 | rdrv->shutdown(rdev); | |
138 | } | |
139 | ||
394b701c MP |
140 | /** |
141 | * rio_register_driver - register a new RIO driver | |
142 | * @rdrv: the RIO driver structure to register | |
143 | * | |
7b089c8b | 144 | * Adds a &struct rio_driver to the list of registered drivers. |
394b701c MP |
145 | * Returns a negative value on error, otherwise 0. If no error |
146 | * occurred, the driver remains registered even if no device | |
147 | * was claimed during registration. | |
148 | */ | |
149 | int rio_register_driver(struct rio_driver *rdrv) | |
150 | { | |
151 | /* initialize common driver fields */ | |
152 | rdrv->driver.name = rdrv->name; | |
153 | rdrv->driver.bus = &rio_bus_type; | |
394b701c MP |
154 | |
155 | /* register with core */ | |
156 | return driver_register(&rdrv->driver); | |
157 | } | |
158 | ||
159 | /** | |
160 | * rio_unregister_driver - unregister a RIO driver | |
161 | * @rdrv: the RIO driver structure to unregister | |
162 | * | |
163 | * Deletes the &struct rio_driver from the list of registered RIO | |
164 | * drivers, gives it a chance to clean up by calling its remove() | |
165 | * function for each device it was responsible for, and marks those | |
166 | * devices as driverless. | |
167 | */ | |
168 | void rio_unregister_driver(struct rio_driver *rdrv) | |
169 | { | |
170 | driver_unregister(&rdrv->driver); | |
171 | } | |
172 | ||
a11650e1 AB |
173 | void rio_attach_device(struct rio_dev *rdev) |
174 | { | |
175 | rdev->dev.bus = &rio_bus_type; | |
a11650e1 AB |
176 | } |
177 | EXPORT_SYMBOL_GPL(rio_attach_device); | |
178 | ||
394b701c | 179 | /** |
7b089c8b | 180 | * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure |
394b701c MP |
181 | * @dev: the standard device structure to match against |
182 | * @drv: the standard driver structure containing the ids to match against | |
183 | * | |
184 | * Used by a driver to check whether a RIO device present in the | |
185 | * system is in its list of supported devices. Returns 1 if | |
186 | * there is a matching &struct rio_device_id or 0 if there is | |
187 | * no match. | |
188 | */ | |
189 | static int rio_match_bus(struct device *dev, struct device_driver *drv) | |
190 | { | |
191 | struct rio_dev *rdev = to_rio_dev(dev); | |
192 | struct rio_driver *rdrv = to_rio_driver(drv); | |
193 | const struct rio_device_id *id = rdrv->id_table; | |
194 | const struct rio_device_id *found_id; | |
195 | ||
196 | if (!id) | |
197 | goto out; | |
198 | ||
199 | found_id = rio_match_device(id, rdev); | |
200 | ||
201 | if (found_id) | |
202 | return 1; | |
203 | ||
204 | out:return 0; | |
205 | } | |
206 | ||
3bdbb62f AB |
207 | static int rio_uevent(struct device *dev, struct kobj_uevent_env *env) |
208 | { | |
209 | struct rio_dev *rdev; | |
210 | ||
211 | if (!dev) | |
212 | return -ENODEV; | |
213 | ||
214 | rdev = to_rio_dev(dev); | |
215 | if (!rdev) | |
216 | return -ENODEV; | |
217 | ||
218 | if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X", | |
219 | rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did)) | |
220 | return -ENOMEM; | |
221 | return 0; | |
222 | } | |
223 | ||
2aaf308b AB |
224 | struct class rio_mport_class = { |
225 | .name = "rapidio_port", | |
226 | .owner = THIS_MODULE, | |
227 | .dev_groups = rio_mport_groups, | |
394b701c | 228 | }; |
2aaf308b | 229 | EXPORT_SYMBOL_GPL(rio_mport_class); |
394b701c MP |
230 | |
231 | struct bus_type rio_bus_type = { | |
232 | .name = "rapidio", | |
233 | .match = rio_match_bus, | |
6d39c80b | 234 | .dev_groups = rio_dev_groups, |
ed1d2da2 | 235 | .bus_groups = rio_bus_groups, |
fc3d3ddd RK |
236 | .probe = rio_device_probe, |
237 | .remove = rio_device_remove, | |
83dc2cbc | 238 | .shutdown = rio_device_shutdown, |
3bdbb62f | 239 | .uevent = rio_uevent, |
394b701c MP |
240 | }; |
241 | ||
242 | /** | |
243 | * rio_bus_init - Register the RapidIO bus with the device model | |
244 | * | |
2aaf308b | 245 | * Registers the RIO mport device class and RIO bus type with the Linux |
394b701c MP |
246 | * device model. |
247 | */ | |
248 | static int __init rio_bus_init(void) | |
249 | { | |
2aaf308b AB |
250 | int ret; |
251 | ||
252 | ret = class_register(&rio_mport_class); | |
253 | if (!ret) { | |
254 | ret = bus_register(&rio_bus_type); | |
255 | if (ret) | |
256 | class_unregister(&rio_mport_class); | |
257 | } | |
258 | return ret; | |
394b701c MP |
259 | } |
260 | ||
261 | postcore_initcall(rio_bus_init); | |
262 | ||
263 | EXPORT_SYMBOL_GPL(rio_register_driver); | |
264 | EXPORT_SYMBOL_GPL(rio_unregister_driver); | |
265 | EXPORT_SYMBOL_GPL(rio_bus_type); | |
266 | EXPORT_SYMBOL_GPL(rio_dev_get); | |
267 | EXPORT_SYMBOL_GPL(rio_dev_put); |