aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2006-01-10 14:50:39 -0500
committerDominik Brodowski <linux@dominikbrodowski.net>2006-03-31 10:02:06 -0500
commit360b65b95bae96f854a2413093ee9b79c31203ae (patch)
treeff5f2dea6055c9616fdec44b7309fc81b8f116ed
parent855cdf134dfcf2ecb92ac4ad675cf655d8ceb678 (diff)
[PATCH] pcmcia: make config_t independent, add reference counting
Handle config_t structs independent of struct pcmcia_socket, and add reference counting for them. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
-rw-r--r--drivers/pcmcia/cs.c2
-rw-r--r--drivers/pcmcia/cs_internal.h2
-rw-r--r--drivers/pcmcia/ds.c70
-rw-r--r--include/pcmcia/ss.h1
4 files changed, 45 insertions, 30 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 613f2f1fbfdd..45cffbf285c2 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -406,8 +406,6 @@ static void socket_shutdown(struct pcmcia_socket *s)
406 cb_free(s); 406 cb_free(s);
407#endif 407#endif
408 s->functions = 0; 408 s->functions = 0;
409 kfree(s->config);
410 s->config = NULL;
411 409
412 s->ops->get_status(s, &status); 410 s->ops->get_status(s, &status);
413 if (status & SS_POWERON) { 411 if (status & SS_POWERON) {
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 88c96aee0f45..01c32af559bf 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -16,6 +16,7 @@
16#define _LINUX_CS_INTERNAL_H 16#define _LINUX_CS_INTERNAL_H
17 17
18#include <linux/config.h> 18#include <linux/config.h>
19#include <linux/kref.h>
19 20
20/* Flags in client state */ 21/* Flags in client state */
21#define CLIENT_CONFIG_LOCKED 0x0001 22#define CLIENT_CONFIG_LOCKED 0x0001
@@ -40,6 +41,7 @@ typedef struct region_t {
40 41
41/* Each card function gets one of these guys */ 42/* Each card function gets one of these guys */
42typedef struct config_t { 43typedef struct config_t {
44 struct kref ref;
43 u_int state; 45 u_int state;
44 u_int Attributes; 46 u_int Attributes;
45 u_int IntType; 47 u_int IntType;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5166f00cfe3a..37ba1246c282 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -23,6 +23,7 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/crc32.h> 24#include <linux/crc32.h>
25#include <linux/firmware.h> 25#include <linux/firmware.h>
26#include <linux/kref.h>
26 27
27#define IN_CARD_SERVICES 28#define IN_CARD_SERVICES
28#include <pcmcia/cs_types.h> 29#include <pcmcia/cs_types.h>
@@ -343,12 +344,19 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev)
343 put_device(&p_dev->dev); 344 put_device(&p_dev->dev);
344} 345}
345 346
347static void pcmcia_release_function(struct kref *ref)
348{
349 struct config_t *c = container_of(ref, struct config_t, ref);
350 kfree(c);
351}
352
346static void pcmcia_release_dev(struct device *dev) 353static void pcmcia_release_dev(struct device *dev)
347{ 354{
348 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); 355 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
349 ds_dbg(1, "releasing dev %p\n", p_dev); 356 ds_dbg(1, "releasing dev %p\n", p_dev);
350 pcmcia_put_socket(p_dev->socket); 357 pcmcia_put_socket(p_dev->socket);
351 kfree(p_dev->devname); 358 kfree(p_dev->devname);
359 kref_put(&p_dev->function_config->ref, pcmcia_release_function);
352 kfree(p_dev); 360 kfree(p_dev);
353} 361}
354 362
@@ -377,30 +385,14 @@ static int pcmcia_device_probe(struct device * dev)
377 p_drv = to_pcmcia_drv(dev->driver); 385 p_drv = to_pcmcia_drv(dev->driver);
378 s = p_dev->socket; 386 s = p_dev->socket;
379 387
380 if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { 388 if ((!p_drv->probe) || (!p_dev->function_config) ||
389 (!try_module_get(p_drv->owner))) {
381 ret = -EINVAL; 390 ret = -EINVAL;
382 goto put_dev; 391 goto put_dev;
383 } 392 }
384 393
385 p_dev->state &= ~CLIENT_UNBOUND; 394 p_dev->state &= ~CLIENT_UNBOUND;
386 395
387 /* set up the device configuration, if it hasn't been done before */
388 if (!s->functions) {
389 cistpl_longlink_mfc_t mfc;
390 if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC,
391 &mfc) == CS_SUCCESS)
392 s->functions = mfc.nfn;
393 else
394 s->functions = 1;
395 s->config = kzalloc(sizeof(config_t) * s->functions,
396 GFP_KERNEL);
397 if (!s->config) {
398 ret = -ENOMEM;
399 goto put_module;
400 }
401 }
402 p_dev->function_config = &s->config[p_dev->func];
403
404 ret = p_drv->probe(p_dev); 396 ret = p_drv->probe(p_dev);
405 if (ret) 397 if (ret)
406 goto put_module; 398 goto put_module;
@@ -576,7 +568,7 @@ static DECLARE_MUTEX(device_add_lock);
576 568
577struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) 569struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
578{ 570{
579 struct pcmcia_device *p_dev; 571 struct pcmcia_device *p_dev, *tmp_dev;
580 unsigned long flags; 572 unsigned long flags;
581 int bus_id_len; 573 int bus_id_len;
582 574
@@ -597,6 +589,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
597 p_dev->socket = s; 589 p_dev->socket = s;
598 p_dev->device_no = (s->device_count++); 590 p_dev->device_no = (s->device_count++);
599 p_dev->func = function; 591 p_dev->func = function;
592 if (s->functions < function)
593 s->functions = function;
600 594
601 p_dev->dev.bus = &pcmcia_bus_type; 595 p_dev->dev.bus = &pcmcia_bus_type;
602 p_dev->dev.parent = s->dev.dev; 596 p_dev->dev.parent = s->dev.dev;
@@ -611,28 +605,50 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
611 /* compat */ 605 /* compat */
612 p_dev->state = CLIENT_UNBOUND; 606 p_dev->state = CLIENT_UNBOUND;
613 607
614 /* Add to the list in pcmcia_bus_socket */ 608
615 spin_lock_irqsave(&pcmcia_dev_list_lock, flags); 609 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
610
611 /*
612 * p_dev->function_config must be the same for all card functions.
613 * Note that this is serialized by the device_add_lock, so that
614 * only one such struct will be created.
615 */
616 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
617 if (p_dev->func == tmp_dev->func) {
618 p_dev->function_config = tmp_dev->function_config;
619 kref_get(&p_dev->function_config->ref);
620 }
621
622 /* Add to the list in pcmcia_bus_socket */
616 list_add_tail(&p_dev->socket_device_list, &s->devices_list); 623 list_add_tail(&p_dev->socket_device_list, &s->devices_list);
624
617 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); 625 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
618 626
627 if (!p_dev->function_config) {
628 p_dev->function_config = kzalloc(sizeof(struct config_t),
629 GFP_KERNEL);
630 if (!p_dev->function_config)
631 goto err_unreg;
632 kref_init(&p_dev->function_config->ref);
633 }
634
619 printk(KERN_NOTICE "pcmcia: registering new device %s\n", 635 printk(KERN_NOTICE "pcmcia: registering new device %s\n",
620 p_dev->devname); 636 p_dev->devname);
621 637
622 pcmcia_device_query(p_dev); 638 pcmcia_device_query(p_dev);
623 639
624 if (device_register(&p_dev->dev)) { 640 if (device_register(&p_dev->dev))
625 spin_lock_irqsave(&pcmcia_dev_list_lock, flags); 641 goto err_unreg;
626 list_del(&p_dev->socket_device_list);
627 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
628
629 goto err_free;
630 }
631 642
632 up(&device_add_lock); 643 up(&device_add_lock);
633 644
634 return p_dev; 645 return p_dev;
635 646
647 err_unreg:
648 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
649 list_del(&p_dev->socket_device_list);
650 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
651
636 err_free: 652 err_free:
637 kfree(p_dev->devname); 653 kfree(p_dev->devname);
638 kfree(p_dev); 654 kfree(p_dev);
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 2889a69a7a8f..6529ccc76514 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -186,7 +186,6 @@ struct pcmcia_socket {
186 u_short lock_count; 186 u_short lock_count;
187 pccard_mem_map cis_mem; 187 pccard_mem_map cis_mem;
188 void __iomem *cis_virt; 188 void __iomem *cis_virt;
189 struct config_t *config;
190 struct { 189 struct {
191 u_int AssignedIRQ; 190 u_int AssignedIRQ;
192 u_int Config; 191 u_int Config;