diff options
Diffstat (limited to 'drivers/serial/serial_cs.c')
| -rw-r--r-- | drivers/serial/serial_cs.c | 132 | 
1 files changed, 67 insertions, 65 deletions
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index a796a93fe39..42252034293 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -424,41 +424,45 @@ static int pfc_config(struct pcmcia_device *p_dev)  	return -ENODEV;  } -static int simple_config_check(struct pcmcia_device *p_dev, -			       cistpl_cftable_entry_t *cf, -			       cistpl_cftable_entry_t *dflt, -			       void *priv_data) +static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)  {  	static const int size_table[2] = { 8, 16 };  	int *try = priv_data; -	p_dev->io_lines = ((*try & 0x1) == 0) ? -			16 : cf->io.flags & CISTPL_IO_LINES_MASK; +	if (p_dev->resource[0]->start == 0) +		return -ENODEV; -	if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)]) -	    && (cf->io.win[0].base != 0)) { -		p_dev->resource[0]->start = cf->io.win[0].base; -		if (!pcmcia_request_io(p_dev)) -			return 0; -	} -	return -EINVAL; +	if ((*try & 0x1) == 0) +		p_dev->io_lines = 16; + +	if (p_dev->resource[0]->end != size_table[(*try >> 1)]) +		return -ENODEV; + +	p_dev->resource[0]->end = 8; +	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; +	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + +	return pcmcia_request_io(p_dev);  }  static int simple_config_check_notpicky(struct pcmcia_device *p_dev, -					cistpl_cftable_entry_t *cf, -					cistpl_cftable_entry_t *dflt,  					void *priv_data)  {  	static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };  	int j; -	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { -		for (j = 0; j < 5; j++) { -			p_dev->resource[0]->start = base[j]; -			p_dev->io_lines = base[j] ? 16 : 3; -			if (!pcmcia_request_io(p_dev)) -				return 0; -		} +	if (p_dev->io_lines > 3) +		return -ENODEV; + +	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; +	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; +	p_dev->resource[0]->end = 8; + +	for (j = 0; j < 5; j++) { +		p_dev->resource[0]->start = base[j]; +		p_dev->io_lines = base[j] ? 16 : 3; +		if (!pcmcia_request_io(p_dev)) +			return 0;  	}  	return -ENODEV;  } @@ -468,12 +472,9 @@ static int simple_config(struct pcmcia_device *link)  	struct serial_info *info = link->priv;  	int i = -ENODEV, try; -	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; -	link->resource[0]->end = 8; -  	/* First pass: look for a config entry that looks normal.  	 * Two tries: without IO aliases, then with aliases */ -	link->config_flags |= CONF_AUTO_SET_VPP; +	link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;  	for (try = 0; try < 4; try++)  		if (!pcmcia_loop_config(link, simple_config_check, &try))  			goto found_port; @@ -503,43 +504,44 @@ found_port:  	return setup_serial(link, info, link->resource[0]->start, link->irq);  } -static int multi_config_check(struct pcmcia_device *p_dev, -			      cistpl_cftable_entry_t *cf, -			      cistpl_cftable_entry_t *dflt, -			      void *priv_data) +static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)  { -	int *base2 = priv_data; +	int *multi = priv_data; + +	if (p_dev->resource[1]->end) +		return -EINVAL;  	/* The quad port cards have bad CIS's, so just look for a  	   window larger than 8 ports and assume it will be right */ -	if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { -		p_dev->resource[0]->start = cf->io.win[0].base; -		p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; -		if (!pcmcia_request_io(p_dev)) { -			*base2 = p_dev->resource[0]->start + 8; -			return 0; -		} -	} -	return -ENODEV; +	if (p_dev->resource[0]->end <= 8) +		return -EINVAL; + +	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; +	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; +	p_dev->resource[0]->end = *multi * 8; + +	if (pcmcia_request_io(p_dev)) +		return -ENODEV; +	return 0;  }  static int multi_config_check_notpicky(struct pcmcia_device *p_dev, -				       cistpl_cftable_entry_t *cf, -				       cistpl_cftable_entry_t *dflt,  				       void *priv_data)  {  	int *base2 = priv_data; -	if (cf->io.nwin == 2) { -		p_dev->resource[0]->start = cf->io.win[0].base; -		p_dev->resource[1]->start = cf->io.win[1].base; -		p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK; -		if (!pcmcia_request_io(p_dev)) { -			*base2 = p_dev->resource[1]->start; -			return 0; -		} -	} -	return -ENODEV; +	if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) +		return -ENODEV; + +	p_dev->resource[0]->end = p_dev->resource[1]->end = 8; +	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; +	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + +	if (pcmcia_request_io(p_dev)) +		return -ENODEV; + +	*base2 = p_dev->resource[0]->start + 8; +	return 0;  }  static int multi_config(struct pcmcia_device *link) @@ -547,12 +549,12 @@ static int multi_config(struct pcmcia_device *link)  	struct serial_info *info = link->priv;  	int i, base2 = 0; +	link->config_flags |= CONF_AUTO_SET_IO;  	/* First, look for a generic full-sized window */ -	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; -	link->resource[0]->end = info->multi * 8; -	if (pcmcia_loop_config(link, multi_config_check, &base2)) { +	if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) +		base2 = link->resource[0]->start + 8; +	else {  		/* If that didn't work, look for two windows */ -		link->resource[0]->end = link->resource[1]->end = 8;  		info->multi = 2;  		if (pcmcia_loop_config(link, multi_config_check_notpicky,  				       &base2)) { @@ -587,7 +589,7 @@ static int multi_config(struct pcmcia_device *link)  		    link->config_index == 3) {  			err = setup_serial(link, info, base2,  					link->irq); -			base2 = link->resource[0]->start;; +			base2 = link->resource[0]->start;  		} else {  			err = setup_serial(link, info, link->resource[0]->start,  					link->irq); @@ -611,18 +613,18 @@ static int multi_config(struct pcmcia_device *link)  	return 0;  } -static int serial_check_for_multi(struct pcmcia_device *p_dev, -				  cistpl_cftable_entry_t *cf, -				  cistpl_cftable_entry_t *dflt, -				  void *priv_data) +static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)  {  	struct serial_info *info = p_dev->priv; -	if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) -		info->multi = cf->io.win[0].len >> 3; +	if (!p_dev->resource[0]->end) +		return -EINVAL; + +	if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0)) +		info->multi = p_dev->resource[0]->end >> 3; -	if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && -		(cf->io.win[1].len == 8)) +	if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8) +		&& (p_dev->resource[1]->end == 8))  		info->multi = 2;  	return 0; /* break */  |