[PATCH] pnp: card_probe(): fix memory leak
[pandora-kernel.git] / drivers / pnp / card.c
1 /*
2  * card.c - contains functions for managing groups of PnP devices
3  *
4  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
5  *
6  */
7
8 #include <linux/config.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/pnp.h>
12 #include "base.h"
13
14 LIST_HEAD(pnp_cards);
15 static LIST_HEAD(pnp_card_drivers);
16
17
18 static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
19 {
20         const struct pnp_card_device_id * drv_id = drv->id_table;
21         while (*drv_id->id){
22                 if (compare_pnp_id(card->id,drv_id->id)) {
23                         int i = 0;
24                         for (;;) {
25                                 int found;
26                                 struct pnp_dev *dev;
27                                 if (i == PNP_MAX_DEVICES || ! *drv_id->devs[i].id)
28                                         return drv_id;
29                                 found = 0;
30                                 card_for_each_dev(card, dev) {
31                                         if (compare_pnp_id(dev->id, drv_id->devs[i].id)) {
32                                                 found = 1;
33                                                 break;
34                                         }
35                                 }
36                                 if (! found)
37                                         break;
38                                 i++;
39                         }
40                 }
41                 drv_id++;
42         }
43         return NULL;
44 }
45
46 static void card_remove(struct pnp_dev * dev)
47 {
48         dev->card_link = NULL;
49 }
50
51 static void card_remove_first(struct pnp_dev * dev)
52 {
53         struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
54         if (!dev->card || !drv)
55                 return;
56         if (drv->remove)
57                 drv->remove(dev->card_link);
58         drv->link.remove = &card_remove;
59         kfree(dev->card_link);
60         card_remove(dev);
61 }
62
63 static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
64 {
65         const struct pnp_card_device_id *id;
66         struct pnp_card_link *clink;
67         struct pnp_dev *dev;
68
69         if (!drv->probe)
70                 return 0;
71         id = match_card(drv,card);
72         if (!id)
73                 return 0;
74
75         clink = pnp_alloc(sizeof(*clink));
76         if (!clink)
77                 return 0;
78         clink->card = card;
79         clink->driver = drv;
80         clink->pm_state = PMSG_ON;
81
82         if (drv->probe(clink, id) >= 0)
83                 return 1;
84
85         /* Recovery */
86         card_for_each_dev(card, dev) {
87                 if (dev->card_link == clink)
88                         pnp_release_card_device(dev);
89         }
90         kfree(clink);
91         return 0;
92 }
93
94 /**
95  * pnp_add_card_id - adds an EISA id to the specified card
96  * @id: pointer to a pnp_id structure
97  * @card: pointer to the desired card
98  *
99  */
100
101 int pnp_add_card_id(struct pnp_id *id, struct pnp_card * card)
102 {
103         struct pnp_id * ptr;
104         if (!id)
105                 return -EINVAL;
106         if (!card)
107                 return -EINVAL;
108         id->next = NULL;
109         ptr = card->id;
110         while (ptr && ptr->next)
111                 ptr = ptr->next;
112         if (ptr)
113                 ptr->next = id;
114         else
115                 card->id = id;
116         return 0;
117 }
118
119 static void pnp_free_card_ids(struct pnp_card * card)
120 {
121         struct pnp_id * id;
122         struct pnp_id *next;
123         if (!card)
124                 return;
125         id = card->id;
126         while (id) {
127                 next = id->next;
128                 kfree(id);
129                 id = next;
130         }
131 }
132
133 static void pnp_release_card(struct device *dmdev)
134 {
135         struct pnp_card * card = to_pnp_card(dmdev);
136         pnp_free_card_ids(card);
137         kfree(card);
138 }
139
140
141 static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf)
142 {
143         char *str = buf;
144         struct pnp_card *card = to_pnp_card(dmdev);
145         str += sprintf(str,"%s\n", card->name);
146         return (str - buf);
147 }
148
149 static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL);
150
151 static ssize_t pnp_show_card_ids(struct device *dmdev, struct device_attribute *attr, char *buf)
152 {
153         char *str = buf;
154         struct pnp_card *card = to_pnp_card(dmdev);
155         struct pnp_id * pos = card->id;
156
157         while (pos) {
158                 str += sprintf(str,"%s\n", pos->id);
159                 pos = pos->next;
160         }
161         return (str - buf);
162 }
163
164 static DEVICE_ATTR(card_id,S_IRUGO,pnp_show_card_ids,NULL);
165
166 static int pnp_interface_attach_card(struct pnp_card *card)
167 {
168         device_create_file(&card->dev,&dev_attr_name);
169         device_create_file(&card->dev,&dev_attr_card_id);
170         return 0;
171 }
172
173 /**
174  * pnp_add_card - adds a PnP card to the PnP Layer
175  * @card: pointer to the card to add
176  */
177
178 int pnp_add_card(struct pnp_card * card)
179 {
180         int error;
181         struct list_head * pos, * temp;
182         if (!card || !card->protocol)
183                 return -EINVAL;
184
185         sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
186         card->dev.parent = &card->protocol->dev;
187         card->dev.bus = NULL;
188         card->dev.release = &pnp_release_card;
189         error = device_register(&card->dev);
190
191         if (error == 0) {
192                 pnp_interface_attach_card(card);
193                 spin_lock(&pnp_lock);
194                 list_add_tail(&card->global_list, &pnp_cards);
195                 list_add_tail(&card->protocol_list, &card->protocol->cards);
196                 spin_unlock(&pnp_lock);
197
198                 /* we wait until now to add devices in order to ensure the drivers
199                  * will be able to use all of the related devices on the card
200                  * without waiting any unresonable length of time */
201                 list_for_each(pos,&card->devices){
202                         struct pnp_dev *dev = card_to_pnp_dev(pos);
203                         __pnp_add_device(dev);
204                 }
205
206                 /* match with card drivers */
207                 list_for_each_safe(pos,temp,&pnp_card_drivers){
208                         struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
209                         card_probe(card,drv);
210                 }
211         } else
212                 pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
213         return error;
214 }
215
216 /**
217  * pnp_remove_card - removes a PnP card from the PnP Layer
218  * @card: pointer to the card to remove
219  */
220
221 void pnp_remove_card(struct pnp_card * card)
222 {
223         struct list_head *pos, *temp;
224         if (!card)
225                 return;
226         device_unregister(&card->dev);
227         spin_lock(&pnp_lock);
228         list_del(&card->global_list);
229         list_del(&card->protocol_list);
230         spin_unlock(&pnp_lock);
231         list_for_each_safe(pos,temp,&card->devices){
232                 struct pnp_dev *dev = card_to_pnp_dev(pos);
233                 pnp_remove_card_device(dev);
234         }
235 }
236
237 /**
238  * pnp_add_card_device - adds a device to the specified card
239  * @card: pointer to the card to add to
240  * @dev: pointer to the device to add
241  */
242
243 int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
244 {
245         if (!card || !dev || !dev->protocol)
246                 return -EINVAL;
247         dev->dev.parent = &card->dev;
248         dev->card_link = NULL;
249         snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", dev->protocol->number,
250                  card->number,dev->number);
251         spin_lock(&pnp_lock);
252         dev->card = card;
253         list_add_tail(&dev->card_list, &card->devices);
254         spin_unlock(&pnp_lock);
255         return 0;
256 }
257
258 /**
259  * pnp_remove_card_device- removes a device from the specified card
260  * @dev: pointer to the device to remove
261  */
262
263 void pnp_remove_card_device(struct pnp_dev * dev)
264 {
265         spin_lock(&pnp_lock);
266         dev->card = NULL;
267         list_del(&dev->card_list);
268         spin_unlock(&pnp_lock);
269         __pnp_remove_device(dev);
270 }
271
272 /**
273  * pnp_request_card_device - Searches for a PnP device under the specified card
274  * @clink: pointer to the card link, cannot be NULL
275  * @id: pointer to a PnP ID structure that explains the rules for finding the device
276  * @from: Starting place to search from. If NULL it will start from the begining.
277  */
278
279 struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char * id, struct pnp_dev * from)
280 {
281         struct list_head * pos;
282         struct pnp_dev * dev;
283         struct pnp_card_driver * drv;
284         struct pnp_card * card;
285         if (!clink || !id)
286                 goto done;
287         card = clink->card;
288         drv = clink->driver;
289         if (!from) {
290                 pos = card->devices.next;
291         } else {
292                 if (from->card != card)
293                         goto done;
294                 pos = from->card_list.next;
295         }
296         while (pos != &card->devices) {
297                 dev = card_to_pnp_dev(pos);
298                 if ((!dev->card_link) && compare_pnp_id(dev->id,id))
299                         goto found;
300                 pos = pos->next;
301         }
302
303 done:
304         return NULL;
305
306 found:
307         down_write(&dev->dev.bus->subsys.rwsem);
308         dev->card_link = clink;
309         dev->dev.driver = &drv->link.driver;
310         if (pnp_bus_type.probe(&dev->dev)) {
311                 dev->dev.driver = NULL;
312                 dev->card_link = NULL;
313                 up_write(&dev->dev.bus->subsys.rwsem);
314                 return NULL;
315         }
316         device_bind_driver(&dev->dev);
317         up_write(&dev->dev.bus->subsys.rwsem);
318
319         return dev;
320 }
321
322 /**
323  * pnp_release_card_device - call this when the driver no longer needs the device
324  * @dev: pointer to the PnP device stucture
325  */
326
327 void pnp_release_card_device(struct pnp_dev * dev)
328 {
329         struct pnp_card_driver * drv = dev->card_link->driver;
330         if (!drv)
331                 return;
332         down_write(&dev->dev.bus->subsys.rwsem);
333         drv->link.remove = &card_remove;
334         device_release_driver(&dev->dev);
335         drv->link.remove = &card_remove_first;
336         up_write(&dev->dev.bus->subsys.rwsem);
337 }
338
339 /*
340  * suspend/resume callbacks
341  */
342 static int card_suspend(struct pnp_dev *dev, pm_message_t state)
343 {
344         struct pnp_card_link *link = dev->card_link;
345         if (link->pm_state.event == state.event)
346                 return 0;
347         link->pm_state = state;
348         return link->driver->suspend(link, state);
349 }
350
351 static int card_resume(struct pnp_dev *dev)
352 {
353         struct pnp_card_link *link = dev->card_link;
354         if (link->pm_state.event == PM_EVENT_ON)
355                 return 0;
356         link->pm_state = PMSG_ON;
357         link->driver->resume(link);
358         return 0;
359 }
360
361 /**
362  * pnp_register_card_driver - registers a PnP card driver with the PnP Layer
363  * @drv: pointer to the driver to register
364  */
365
366 int pnp_register_card_driver(struct pnp_card_driver * drv)
367 {
368         int error;
369         struct list_head *pos, *temp;
370
371         drv->link.name = drv->name;
372         drv->link.id_table = NULL;      /* this will disable auto matching */
373         drv->link.flags = drv->flags;
374         drv->link.probe = NULL;
375         drv->link.remove = &card_remove_first;
376         drv->link.suspend = drv->suspend ? card_suspend : NULL;
377         drv->link.resume = drv->resume ? card_resume : NULL;
378
379         error = pnp_register_driver(&drv->link);
380         if (error < 0)
381                 return error;
382
383         spin_lock(&pnp_lock);
384         list_add_tail(&drv->global_list, &pnp_card_drivers);
385         spin_unlock(&pnp_lock);
386
387         list_for_each_safe(pos,temp,&pnp_cards){
388                 struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
389                 card_probe(card,drv);
390         }
391         return 0;
392 }
393
394 /**
395  * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
396  * @drv: pointer to the driver to unregister
397  */
398
399 void pnp_unregister_card_driver(struct pnp_card_driver * drv)
400 {
401         spin_lock(&pnp_lock);
402         list_del(&drv->global_list);
403         spin_unlock(&pnp_lock);
404         pnp_unregister_driver(&drv->link);
405 }
406
407 #if 0
408 EXPORT_SYMBOL(pnp_add_card);
409 EXPORT_SYMBOL(pnp_remove_card);
410 EXPORT_SYMBOL(pnp_add_card_device);
411 EXPORT_SYMBOL(pnp_remove_card_device);
412 EXPORT_SYMBOL(pnp_add_card_id);
413 #endif  /*  0  */
414 EXPORT_SYMBOL(pnp_request_card_device);
415 EXPORT_SYMBOL(pnp_release_card_device);
416 EXPORT_SYMBOL(pnp_register_card_driver);
417 EXPORT_SYMBOL(pnp_unregister_card_driver);