diff options
author | Carlos Chinea <carlos.chinea@nokia.com> | 2012-04-04 07:11:45 -0400 |
---|---|---|
committer | Carlos Chinea <carlos.chinea@nokia.com> | 2012-04-23 07:23:31 -0400 |
commit | 5a218ceba7b64f506bf4f004b04bb457c1805a62 (patch) | |
tree | f1f123391bbebd8c6136e9118bf8a2f6b0c49734 /drivers/hsi | |
parent | 66f75a5d028beaf67c931435fdc3e7823125730c (diff) |
HSI: hsi: Rework hsi_controller release
Use the proper release mechanism for hsi_controller and
hsi_ports structures. Free the structures through their
associated device release callbacks.
Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/hsi')
-rw-r--r-- | drivers/hsi/hsi.c | 108 |
1 files changed, 66 insertions, 42 deletions
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c index 4e2d79b79334..c17d12ca8e7f 100644 --- a/drivers/hsi/hsi.c +++ b/drivers/hsi/hsi.c | |||
@@ -140,12 +140,17 @@ static int hsi_remove_port(struct device *dev, void *data __maybe_unused) | |||
140 | return 0; | 140 | return 0; |
141 | } | 141 | } |
142 | 142 | ||
143 | static void hsi_controller_release(struct device *dev __maybe_unused) | 143 | static void hsi_controller_release(struct device *dev) |
144 | { | 144 | { |
145 | struct hsi_controller *hsi = to_hsi_controller(dev); | ||
146 | |||
147 | kfree(hsi->port); | ||
148 | kfree(hsi); | ||
145 | } | 149 | } |
146 | 150 | ||
147 | static void hsi_port_release(struct device *dev __maybe_unused) | 151 | static void hsi_port_release(struct device *dev) |
148 | { | 152 | { |
153 | kfree(to_hsi_port(dev)); | ||
149 | } | 154 | } |
150 | 155 | ||
151 | /** | 156 | /** |
@@ -172,18 +177,14 @@ int hsi_register_controller(struct hsi_controller *hsi) | |||
172 | 177 | ||
173 | hsi->device.type = &hsi_ctrl; | 178 | hsi->device.type = &hsi_ctrl; |
174 | hsi->device.bus = &hsi_bus_type; | 179 | hsi->device.bus = &hsi_bus_type; |
175 | hsi->device.release = hsi_controller_release; | 180 | err = device_add(&hsi->device); |
176 | err = device_register(&hsi->device); | ||
177 | if (err < 0) | 181 | if (err < 0) |
178 | return err; | 182 | return err; |
179 | for (i = 0; i < hsi->num_ports; i++) { | 183 | for (i = 0; i < hsi->num_ports; i++) { |
180 | hsi->port[i].device.parent = &hsi->device; | 184 | hsi->port[i]->device.parent = &hsi->device; |
181 | hsi->port[i].device.bus = &hsi_bus_type; | 185 | hsi->port[i]->device.bus = &hsi_bus_type; |
182 | hsi->port[i].device.release = hsi_port_release; | 186 | hsi->port[i]->device.type = &hsi_port; |
183 | hsi->port[i].device.type = &hsi_port; | 187 | err = device_add(&hsi->port[i]->device); |
184 | INIT_LIST_HEAD(&hsi->port[i].clients); | ||
185 | spin_lock_init(&hsi->port[i].clock); | ||
186 | err = device_register(&hsi->port[i].device); | ||
187 | if (err < 0) | 188 | if (err < 0) |
188 | goto out; | 189 | goto out; |
189 | } | 190 | } |
@@ -192,7 +193,9 @@ int hsi_register_controller(struct hsi_controller *hsi) | |||
192 | 193 | ||
193 | return 0; | 194 | return 0; |
194 | out: | 195 | out: |
195 | hsi_unregister_controller(hsi); | 196 | while (i-- > 0) |
197 | device_del(&hsi->port[i]->device); | ||
198 | device_del(&hsi->device); | ||
196 | 199 | ||
197 | return err; | 200 | return err; |
198 | } | 201 | } |
@@ -223,6 +226,29 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) | |||
223 | } | 226 | } |
224 | 227 | ||
225 | /** | 228 | /** |
229 | * hsi_put_controller - Free an HSI controller | ||
230 | * | ||
231 | * @hsi: Pointer to the HSI controller to freed | ||
232 | * | ||
233 | * HSI controller drivers should only use this function if they need | ||
234 | * to free their allocated hsi_controller structures before a successful | ||
235 | * call to hsi_register_controller. Other use is not allowed. | ||
236 | */ | ||
237 | void hsi_put_controller(struct hsi_controller *hsi) | ||
238 | { | ||
239 | unsigned int i; | ||
240 | |||
241 | if (!hsi) | ||
242 | return; | ||
243 | |||
244 | for (i = 0; i < hsi->num_ports; i++) | ||
245 | if (hsi->port && hsi->port[i]) | ||
246 | put_device(&hsi->port[i]->device); | ||
247 | put_device(&hsi->device); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(hsi_put_controller); | ||
250 | |||
251 | /** | ||
226 | * hsi_alloc_controller - Allocate an HSI controller and its ports | 252 | * hsi_alloc_controller - Allocate an HSI controller and its ports |
227 | * @n_ports: Number of ports on the HSI controller | 253 | * @n_ports: Number of ports on the HSI controller |
228 | * @flags: Kernel allocation flags | 254 | * @flags: Kernel allocation flags |
@@ -232,55 +258,53 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) | |||
232 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) | 258 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) |
233 | { | 259 | { |
234 | struct hsi_controller *hsi; | 260 | struct hsi_controller *hsi; |
235 | struct hsi_port *port; | 261 | struct hsi_port **port; |
236 | unsigned int i; | 262 | unsigned int i; |
237 | 263 | ||
238 | if (!n_ports) | 264 | if (!n_ports) |
239 | return NULL; | 265 | return NULL; |
240 | 266 | ||
241 | port = kzalloc(sizeof(*port)*n_ports, flags); | ||
242 | if (!port) | ||
243 | return NULL; | ||
244 | hsi = kzalloc(sizeof(*hsi), flags); | 267 | hsi = kzalloc(sizeof(*hsi), flags); |
245 | if (!hsi) | 268 | if (!hsi) |
246 | goto out; | 269 | return NULL; |
247 | for (i = 0; i < n_ports; i++) { | 270 | port = kzalloc(sizeof(*port)*n_ports, flags); |
248 | dev_set_name(&port[i].device, "port%d", i); | 271 | if (!port) { |
249 | port[i].num = i; | 272 | kfree(hsi); |
250 | port[i].async = hsi_dummy_msg; | 273 | return NULL; |
251 | port[i].setup = hsi_dummy_cl; | ||
252 | port[i].flush = hsi_dummy_cl; | ||
253 | port[i].start_tx = hsi_dummy_cl; | ||
254 | port[i].stop_tx = hsi_dummy_cl; | ||
255 | port[i].release = hsi_dummy_cl; | ||
256 | mutex_init(&port[i].lock); | ||
257 | } | 274 | } |
258 | hsi->num_ports = n_ports; | 275 | hsi->num_ports = n_ports; |
259 | hsi->port = port; | 276 | hsi->port = port; |
277 | hsi->device.release = hsi_controller_release; | ||
278 | device_initialize(&hsi->device); | ||
279 | |||
280 | for (i = 0; i < n_ports; i++) { | ||
281 | port[i] = kzalloc(sizeof(**port), flags); | ||
282 | if (port[i] == NULL) | ||
283 | goto out; | ||
284 | port[i]->num = i; | ||
285 | port[i]->async = hsi_dummy_msg; | ||
286 | port[i]->setup = hsi_dummy_cl; | ||
287 | port[i]->flush = hsi_dummy_cl; | ||
288 | port[i]->start_tx = hsi_dummy_cl; | ||
289 | port[i]->stop_tx = hsi_dummy_cl; | ||
290 | port[i]->release = hsi_dummy_cl; | ||
291 | mutex_init(&port[i]->lock); | ||
292 | INIT_LIST_HEAD(&hsi->port[i]->clients); | ||
293 | spin_lock_init(&hsi->port[i]->clock); | ||
294 | dev_set_name(&port[i]->device, "port%d", i); | ||
295 | hsi->port[i]->device.release = hsi_port_release; | ||
296 | device_initialize(&hsi->port[i]->device); | ||
297 | } | ||
260 | 298 | ||
261 | return hsi; | 299 | return hsi; |
262 | out: | 300 | out: |
263 | kfree(port); | 301 | hsi_put_controller(hsi); |
264 | 302 | ||
265 | return NULL; | 303 | return NULL; |
266 | } | 304 | } |
267 | EXPORT_SYMBOL_GPL(hsi_alloc_controller); | 305 | EXPORT_SYMBOL_GPL(hsi_alloc_controller); |
268 | 306 | ||
269 | /** | 307 | /** |
270 | * hsi_free_controller - Free an HSI controller | ||
271 | * @hsi: Pointer to HSI controller | ||
272 | */ | ||
273 | void hsi_free_controller(struct hsi_controller *hsi) | ||
274 | { | ||
275 | if (!hsi) | ||
276 | return; | ||
277 | |||
278 | kfree(hsi->port); | ||
279 | kfree(hsi); | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(hsi_free_controller); | ||
282 | |||
283 | /** | ||
284 | * hsi_free_msg - Free an HSI message | 308 | * hsi_free_msg - Free an HSI message |
285 | * @msg: Pointer to the HSI message | 309 | * @msg: Pointer to the HSI message |
286 | * | 310 | * |