pcmcia: lock ops->set_socket
[linux-2.6-block.git] / drivers / pcmcia / pcmcia_resource.c
index 4e0aaec5cf992556d8ab2ab05a6051369403bb90..f365ecb9c5cd1b09d58871ed2d8e3b3c37cfdb67 100644 (file)
@@ -266,6 +266,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
        }
 
        if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+               mutex_lock(&s->ops_mutex);
                if (mod->Attributes & CONF_ENABLE_IRQ) {
                        c->Attributes |= CONF_ENABLE_IRQ;
                        s->socket.io_irq = s->irq.AssignedIRQ;
@@ -274,6 +275,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
                        s->socket.io_irq = 0;
                }
                s->ops->set_socket(s, &s->socket);
+               mutex_unlock(&s->ops_mutex);
        }
 
        if (mod->Attributes & CONF_VCC_CHANGE_VALID) {
@@ -288,12 +290,15 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
                        dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n");
                        return -EINVAL;
                }
+               mutex_lock(&s->ops_mutex);
                s->socket.Vpp = mod->Vpp1;
                if (s->ops->set_socket(s, &s->socket)) {
+                       mutex_unlock(&s->ops_mutex);
                        dev_printk(KERN_WARNING, &s->dev,
                                   "Unable to set VPP\n");
                        return -EIO;
                }
+               mutex_unlock(&s->ops_mutex);
        } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
                   (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
                dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
@@ -336,6 +341,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        config_t *c = p_dev->function_config;
        int i;
 
+       mutex_lock(&s->ops_mutex);
        if (p_dev->_locked) {
                p_dev->_locked = 0;
                if (--(s->lock_count) == 0) {
@@ -347,7 +353,6 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        }
        if (c->state & CONFIG_LOCKED) {
                c->state &= ~CONFIG_LOCKED;
-               mutex_lock(&s->ops_mutex);
                if (c->state & CONFIG_IO_REQ)
                        for (i = 0; i < MAX_IO_WIN; i++) {
                                if (!s->io[i].res)
@@ -358,8 +363,8 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
                                io.map = i;
                                s->ops->set_io_map(s, &io);
                        }
-               mutex_unlock(&s->ops_mutex);
        }
+       mutex_unlock(&s->ops_mutex);
 
        return 0;
 } /* pcmcia_release_configuration */
@@ -493,9 +498,11 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
                return -EACCES;
        }
 
+       mutex_lock(&s->ops_mutex);
        /* Do power control.  We don't allow changes in Vcc. */
        s->socket.Vpp = req->Vpp;
        if (s->ops->set_socket(s, &s->socket)) {
+               mutex_unlock(&s->ops_mutex);
                dev_printk(KERN_WARNING, &s->dev,
                           "Unable to set socket state\n");
                return -EINVAL;
@@ -518,6 +525,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
                s->socket.io_irq = 0;
        s->ops->set_socket(s, &s->socket);
        s->lock_count++;
+       mutex_unlock(&s->ops_mutex);
 
        /* Set up CIS configuration registers */
        base = c->ConfigBase = req->ConfigBase;
@@ -698,6 +706,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
                return -EBUSY;
        }
 
+       mutex_lock(&s->ops_mutex);
        /* Decide what type of interrupt we are registering */
        type = 0;
        if (s->functions > 1)           /* All of this ought to be handled higher up */
@@ -791,6 +800,8 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
        pcmcia_used_irq[irq]++;
 #endif
 
+       mutex_unlock(&s->ops_mutex);
+
        return 0;
 } /* pcmcia_request_irq */
 EXPORT_SYMBOL(pcmcia_request_irq);