diff options
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
| -rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 169 | 
1 files changed, 134 insertions, 35 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index d5db95644b6..b2df04199a2 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -43,6 +43,39 @@ module_param(io_speed, int, 0444);  static u8 pcmcia_used_irq[NR_IRQS];  #endif +static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, +				   unsigned long end, struct pcmcia_socket *s) +{ +	if (s->resource_ops->adjust_io_region) +		return s->resource_ops->adjust_io_region(res, start, end, s); +	return -ENOMEM; +} + +static struct resource *pcmcia_find_io_region(unsigned long base, int num, +					      unsigned long align, +					      struct pcmcia_socket *s) +{ +	if (s->resource_ops->find_io) +		return s->resource_ops->find_io(base, num, align, s); +	return NULL; +} + +int pcmcia_validate_mem(struct pcmcia_socket *s) +{ +	if (s->resource_ops->validate_mem) +		return s->resource_ops->validate_mem(s); +	/* if there is no callback, we can assume that everything is OK */ +	return 0; +} + +struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, +				 int low, struct pcmcia_socket *s) +{ +	if (s->resource_ops->find_mem) +		return s->resource_ops->find_mem(base, num, align, low, s); +	return NULL; +} +  /** alloc_io_space   * @@ -158,14 +191,18 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,  		return -EINVAL;  	s = p_dev->socket; + +	mutex_lock(&s->ops_mutex);  	c = p_dev->function_config;  	if (!(c->state & CONFIG_LOCKED)) {  		dev_dbg(&s->dev, "Configuration isnt't locked\n"); +		mutex_unlock(&s->ops_mutex);  		return -EACCES;  	}  	addr = (c->ConfigBase + reg->Offset) >> 1; +	mutex_unlock(&s->ops_mutex);  	switch (reg->Action) {  	case CS_READ: @@ -190,6 +227,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,  			memreq_t *req)  {  	struct pcmcia_socket *s = p_dev->socket; +	int ret;  	wh--;  	if (wh >= MAX_WIN) @@ -198,12 +236,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,  		dev_dbg(&s->dev, "failure: requested page is zero\n");  		return -EINVAL;  	} +	mutex_lock(&s->ops_mutex);  	s->win[wh].card_start = req->CardOffset; -	if (s->ops->set_mem_map(s, &s->win[wh]) != 0) { -		dev_dbg(&s->dev, "failed to set_mem_map\n"); -		return -EIO; -	} -	return 0; +	ret = s->ops->set_mem_map(s, &s->win[wh]); +	if (ret) +		dev_warn(&s->dev, "failed to set_mem_map\n"); +	mutex_unlock(&s->ops_mutex); +	return ret;  } /* pcmcia_map_mem_page */  EXPORT_SYMBOL(pcmcia_map_mem_page); @@ -219,14 +258,18 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,  	config_t *c;  	s = p_dev->socket; + +	mutex_lock(&s->ops_mutex);  	c = p_dev->function_config;  	if (!(s->state & SOCKET_PRESENT)) {  		dev_dbg(&s->dev, "No card present\n"); +		mutex_unlock(&s->ops_mutex);  		return -ENODEV;  	}  	if (!(c->state & CONFIG_LOCKED)) {  		dev_dbg(&s->dev, "Configuration isnt't locked\n"); +		mutex_unlock(&s->ops_mutex);  		return -EACCES;  	} @@ -251,10 +294,12 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,  	    (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {  		if (mod->Vpp1 != mod->Vpp2) {  			dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n"); +			mutex_unlock(&s->ops_mutex);  			return -EINVAL;  		}  		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; @@ -262,6 +307,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,  	} 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"); +		mutex_unlock(&s->ops_mutex);  		return -EINVAL;  	} @@ -286,6 +332,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,  			s->ops->set_io_map(s, &io_on);  		}  	} +	mutex_unlock(&s->ops_mutex);  	return 0;  } /* modify_configuration */ @@ -296,9 +343,11 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)  {  	pccard_io_map io = { 0, 0, 0, 0, 1 };  	struct pcmcia_socket *s = p_dev->socket; -	config_t *c = p_dev->function_config; +	config_t *c;  	int i; +	mutex_lock(&s->ops_mutex); +	c = p_dev->function_config;  	if (p_dev->_locked) {  		p_dev->_locked = 0;  		if (--(s->lock_count) == 0) { @@ -321,6 +370,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)  				s->ops->set_io_map(s, &io);  			}  	} +	mutex_unlock(&s->ops_mutex);  	return 0;  } /* pcmcia_release_configuration */ @@ -337,10 +387,14 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)  static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)  {  	struct pcmcia_socket *s = p_dev->socket; -	config_t *c = p_dev->function_config; +	int ret = -EINVAL; +	config_t *c; + +	mutex_lock(&s->ops_mutex); +	c = p_dev->function_config;  	if (!p_dev->_io) -		return -EINVAL; +		goto out;  	p_dev->_io = 0; @@ -348,7 +402,7 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)  	    (c->io.NumPorts1 != req->NumPorts1) ||  	    (c->io.BasePort2 != req->BasePort2) ||  	    (c->io.NumPorts2 != req->NumPorts2)) -		return -EINVAL; +		goto out;  	c->state &= ~CONFIG_IO_REQ; @@ -356,28 +410,38 @@ static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)  	if (req->NumPorts2)  		release_io_space(s, req->BasePort2, req->NumPorts2); -	return 0; +out: +	mutex_unlock(&s->ops_mutex); + +	return ret;  } /* pcmcia_release_io */  static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)  {  	struct pcmcia_socket *s = p_dev->socket; -	config_t *c = p_dev->function_config; +	config_t *c; +	int ret = -EINVAL; + +	mutex_lock(&s->ops_mutex); + +	c = p_dev->function_config;  	if (!p_dev->_irq) -		return -EINVAL; +		goto out; +  	p_dev->_irq = 0;  	if (c->state & CONFIG_LOCKED) -		return -EACCES; +		goto out; +  	if (c->irq.Attributes != req->Attributes) {  		dev_dbg(&s->dev, "IRQ attributes must match assigned ones\n"); -		return -EINVAL; +		goto out;  	}  	if (s->irq.AssignedIRQ != req->AssignedIRQ) {  		dev_dbg(&s->dev, "IRQ must match assigned one\n"); -		return -EINVAL; +		goto out;  	}  	if (--s->irq.Config == 0) {  		c->state &= ~CONFIG_IRQ_REQ; @@ -390,8 +454,12 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)  #ifdef CONFIG_PCMCIA_PROBE  	pcmcia_used_irq[req->AssignedIRQ]--;  #endif +	ret = 0; -	return 0; +out: +	mutex_unlock(&s->ops_mutex); + +	return ret;  } /* pcmcia_release_irq */ @@ -404,10 +472,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)  	if (wh >= MAX_WIN)  		return -EINVAL; +	mutex_lock(&s->ops_mutex);  	win = &s->win[wh];  	if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) {  		dev_dbg(&s->dev, "not releasing unknown window\n"); +		mutex_unlock(&s->ops_mutex);  		return -EINVAL;  	} @@ -423,6 +493,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)  		win->res = NULL;  	}  	p_dev->_win &= ~CLIENT_WIN_REQ(wh); +	mutex_unlock(&s->ops_mutex);  	return 0;  } /* pcmcia_release_window */ @@ -445,8 +516,11 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,  		dev_dbg(&s->dev, "IntType may not be INT_CARDBUS\n");  		return -EINVAL;  	} + +	mutex_lock(&s->ops_mutex);  	c = p_dev->function_config;  	if (c->state & CONFIG_LOCKED) { +		mutex_unlock(&s->ops_mutex);  		dev_dbg(&s->dev, "Configuration is locked\n");  		return -EACCES;  	} @@ -454,6 +528,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,  	/* 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; @@ -476,6 +551,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; @@ -524,6 +600,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,  	/* Configure I/O windows */  	if (c->state & CONFIG_IO_REQ) { +		mutex_lock(&s->ops_mutex);  		iomap.speed = io_speed;  		for (i = 0; i < MAX_IO_WIN; i++)  			if (s->io[i].res) { @@ -542,6 +619,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,  				s->ops->set_io_map(s, &iomap);  				s->io[i].Config++;  			} +		mutex_unlock(&s->ops_mutex);  	}  	c->state |= CONFIG_LOCKED; @@ -560,54 +638,65 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)  {  	struct pcmcia_socket *s = p_dev->socket;  	config_t *c; +	int ret = -EINVAL; + +	mutex_lock(&s->ops_mutex);  	if (!(s->state & SOCKET_PRESENT)) {  		dev_dbg(&s->dev, "No card present\n"); -		return -ENODEV; +		goto out;  	}  	if (!req) -		return -EINVAL; +		goto out; +  	c = p_dev->function_config;  	if (c->state & CONFIG_LOCKED) {  		dev_dbg(&s->dev, "Configuration is locked\n"); -		return -EACCES; +		goto out;  	}  	if (c->state & CONFIG_IO_REQ) {  		dev_dbg(&s->dev, "IO already configured\n"); -		return -EBUSY; +		goto out;  	}  	if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {  		dev_dbg(&s->dev, "bad attribute setting for IO region 1\n"); -		return -EINVAL; +		goto out;  	}  	if ((req->NumPorts2 > 0) &&  	    (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {  		dev_dbg(&s->dev, "bad attribute setting for IO region 2\n"); -		return -EINVAL; +		goto out;  	}  	dev_dbg(&s->dev, "trying to allocate resource 1\n"); -	if (alloc_io_space(s, req->Attributes1, &req->BasePort1, -			   req->NumPorts1, req->IOAddrLines)) { +	ret = alloc_io_space(s, req->Attributes1, &req->BasePort1, +			     req->NumPorts1, req->IOAddrLines); +	if (ret) {  		dev_dbg(&s->dev, "allocation of resource 1 failed\n"); -		return -EBUSY; +		goto out;  	}  	if (req->NumPorts2) {  		dev_dbg(&s->dev, "trying to allocate resource 2\n"); -		if (alloc_io_space(s, req->Attributes2, &req->BasePort2, -				   req->NumPorts2, req->IOAddrLines)) { +		ret = alloc_io_space(s, req->Attributes2, &req->BasePort2, +				     req->NumPorts2, req->IOAddrLines); +		if (ret) {  			dev_dbg(&s->dev, "allocation of resource 2 failed\n");  			release_io_space(s, req->BasePort1, req->NumPorts1); -			return -EBUSY; +			goto out;  		}  	}  	c->io = *req;  	c->state |= CONFIG_IO_REQ;  	p_dev->_io = 1; -	return 0; +	dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret); + +out: +	mutex_unlock(&s->ops_mutex); + +	return ret;  } /* pcmcia_request_io */  EXPORT_SYMBOL(pcmcia_request_io); @@ -636,18 +725,20 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)  	int ret = -EINVAL, irq = 0;  	int type; +	mutex_lock(&s->ops_mutex); +  	if (!(s->state & SOCKET_PRESENT)) {  		dev_dbg(&s->dev, "No card present\n"); -		return -ENODEV; +		goto out;  	}  	c = p_dev->function_config;  	if (c->state & CONFIG_LOCKED) {  		dev_dbg(&s->dev, "Configuration is locked\n"); -		return -EACCES; +		goto out;  	}  	if (c->state & CONFIG_IRQ_REQ) {  		dev_dbg(&s->dev, "IRQ already configured\n"); -		return -EBUSY; +		goto out;  	}  	/* Decide what type of interrupt we are registering */ @@ -708,7 +799,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)  	if (ret && !s->irq.AssignedIRQ) {  		if (!s->pci_irq) {  			dev_printk(KERN_INFO, &s->dev, "no IRQ found\n"); -			return ret; +			goto out;  		}  		type = IRQF_SHARED;  		irq = s->pci_irq; @@ -720,7 +811,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)  		if (ret) {  			dev_printk(KERN_INFO, &s->dev,  				"request_irq() failed\n"); -			return ret; +			goto out;  		}  	} @@ -743,7 +834,10 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)  	pcmcia_used_irq[irq]++;  #endif -	return 0; +	ret = 0; +out: +	mutex_unlock(&s->ops_mutex); +	return ret;  } /* pcmcia_request_irq */  EXPORT_SYMBOL(pcmcia_request_irq); @@ -796,6 +890,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha  		return -EINVAL;  	} +	mutex_lock(&s->ops_mutex);  	win = &s->win[w];  	if (!(s->features & SS_CAP_STATIC_MAP)) { @@ -803,6 +898,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha  						      (req->Attributes & WIN_MAP_BELOW_1MB), s);  		if (!win->res) {  			dev_dbg(&s->dev, "allocating mem region failed\n"); +			mutex_unlock(&s->ops_mutex);  			return -EINVAL;  		}  	} @@ -821,8 +917,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha  	if (req->Attributes & WIN_USE_WAIT)  		win->flags |= MAP_USE_WAIT;  	win->card_start = 0; +  	if (s->ops->set_mem_map(s, win) != 0) {  		dev_dbg(&s->dev, "failed to set memory mapping\n"); +		mutex_unlock(&s->ops_mutex);  		return -EIO;  	}  	s->state |= SOCKET_WIN_REQ(w); @@ -833,6 +931,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha  	else  		req->Base = win->res->start; +	mutex_unlock(&s->ops_mutex);  	*wh = w + 1;  	return 0;  |