Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 360b65b9 authored by Dominik Brodowski's avatar Dominik Brodowski
Browse files

[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: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent 855cdf13
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -406,8 +406,6 @@ static void socket_shutdown(struct pcmcia_socket *s)
	cb_free(s);
#endif
	s->functions = 0;
	kfree(s->config);
	s->config = NULL;

	s->ops->get_status(s, &status);
	if (status & SS_POWERON) {
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#define _LINUX_CS_INTERNAL_H

#include <linux/config.h>
#include <linux/kref.h>

/* Flags in client state */
#define CLIENT_CONFIG_LOCKED	0x0001
@@ -40,6 +41,7 @@ typedef struct region_t {

/* Each card function gets one of these guys */
typedef struct config_t {
	struct kref	ref;
    u_int		state;
    u_int		Attributes;
    u_int		IntType;
+43 −27
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/kref.h>

#define IN_CARD_SERVICES
#include <pcmcia/cs_types.h>
@@ -343,12 +344,19 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev)
		put_device(&p_dev->dev);
}

static void pcmcia_release_function(struct kref *ref)
{
	struct config_t *c = container_of(ref, struct config_t, ref);
	kfree(c);
}

static void pcmcia_release_dev(struct device *dev)
{
	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
	ds_dbg(1, "releasing dev %p\n", p_dev);
	pcmcia_put_socket(p_dev->socket);
	kfree(p_dev->devname);
	kref_put(&p_dev->function_config->ref, pcmcia_release_function);
	kfree(p_dev);
}

@@ -377,30 +385,14 @@ static int pcmcia_device_probe(struct device * dev)
	p_drv = to_pcmcia_drv(dev->driver);
	s = p_dev->socket;

	if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) {
	if ((!p_drv->probe) || (!p_dev->function_config) ||
	    (!try_module_get(p_drv->owner))) {
		ret = -EINVAL;
		goto put_dev;
	}

	p_dev->state &= ~CLIENT_UNBOUND;

	/* set up the device configuration, if it hasn't been done before */
	if (!s->functions) {
		cistpl_longlink_mfc_t mfc;
		if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC,
				      &mfc) == CS_SUCCESS)
			s->functions = mfc.nfn;
		else
			s->functions = 1;
		s->config = kzalloc(sizeof(config_t) * s->functions,
				    GFP_KERNEL);
		if (!s->config) {
			ret = -ENOMEM;
			goto put_module;
		}
	}
	p_dev->function_config = &s->config[p_dev->func];

	ret = p_drv->probe(p_dev);
	if (ret)
		goto put_module;
@@ -576,7 +568,7 @@ static DECLARE_MUTEX(device_add_lock);

struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
{
	struct pcmcia_device *p_dev;
	struct pcmcia_device *p_dev, *tmp_dev;
	unsigned long flags;
	int bus_id_len;

@@ -597,6 +589,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
	p_dev->socket = s;
	p_dev->device_no = (s->device_count++);
	p_dev->func   = function;
	if (s->functions < function)
		s->functions = function;

	p_dev->dev.bus = &pcmcia_bus_type;
	p_dev->dev.parent = s->dev.dev;
@@ -611,28 +605,50 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
	/* compat */
	p_dev->state = CLIENT_UNBOUND;

	/* Add to the list in pcmcia_bus_socket */

	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);

	/*
	 * p_dev->function_config must be the same for all card functions.
	 * Note that this is serialized by the device_add_lock, so that
	 * only one such struct will be created.
	 */
        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
                if (p_dev->func == tmp_dev->func) {
			p_dev->function_config = tmp_dev->function_config;
			kref_get(&p_dev->function_config->ref);
		}

	/* Add to the list in pcmcia_bus_socket */
	list_add_tail(&p_dev->socket_device_list, &s->devices_list);

	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);

	if (!p_dev->function_config) {
		p_dev->function_config = kzalloc(sizeof(struct config_t),
						 GFP_KERNEL);
		if (!p_dev->function_config)
			goto err_unreg;
		kref_init(&p_dev->function_config->ref);
	}

	printk(KERN_NOTICE "pcmcia: registering new device %s\n",
	       p_dev->devname);

	pcmcia_device_query(p_dev);

	if (device_register(&p_dev->dev)) {
		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
		list_del(&p_dev->socket_device_list);
		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);

		goto err_free;
       }
	if (device_register(&p_dev->dev))
		goto err_unreg;

	up(&device_add_lock);

	return p_dev;

 err_unreg:
	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
	list_del(&p_dev->socket_device_list);
	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);

 err_free:
	kfree(p_dev->devname);
	kfree(p_dev);
+0 −1
Original line number Diff line number Diff line
@@ -186,7 +186,6 @@ struct pcmcia_socket {
	u_short				lock_count;
	pccard_mem_map			cis_mem;
	void __iomem 			*cis_virt;
	struct config_t			*config;
	struct {
		u_int			AssignedIRQ;
		u_int			Config;