diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-07-30 07:13:46 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-09-29 11:20:24 -0400 |
commit | 00990e7ce0b0e596fe41d9c64d6933ea70084003 (patch) | |
tree | 189e0dd92860feba84231c66955749574cac5d6d /drivers/pcmcia | |
parent | 440eed43e2a95bb842488755683716814da10f2b (diff) |
pcmcia: use autoconfiguration feature for ioports and iomem
When CONF_AUTO_SET_IO or CONF_AUTO_SET_IOMEM are set, the corresponding
fields in struct pcmcia_device *p_dev->resource[0,1,2] are set
accordinly. Drivers wishing to override certain settings may do so in
the callback function, but they no longer need to parse the CIS entries
stored in cistpl_cftable_entry_t themselves.
CC: netdev@vger.kernel.org
CC: linux-wireless@vger.kernel.org
CC: linux-ide@vger.kernel.org
CC: linux-usb@vger.kernel.org
CC: laforge@gnumonks.org
CC: linux-mtd@lists.infradead.org
CC: linux-bluetooth@vger.kernel.org
CC: alsa-devel@alsa-project.org
CC: linux-serial@vger.kernel.org
CC: Jiri Kosina <jkosina@suse.cz>
CC: linux-scsi@vger.kernel.org
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/pcmcia_cis.c | 78 |
1 files changed, 67 insertions, 11 deletions
diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c index 160da0697335..e2c92415b892 100644 --- a/drivers/pcmcia/pcmcia_cis.c +++ b/drivers/pcmcia/pcmcia_cis.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | 6 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. |
7 | * | 7 | * |
8 | * Copyright (C) 1999 David A. Hinds | 8 | * Copyright (C) 1999 David A. Hinds |
9 | * Copyright (C) 2004-2009 Dominik Brodowski | 9 | * Copyright (C) 2004-2010 Dominik Brodowski |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -125,13 +125,24 @@ next_entry: | |||
125 | return ret; | 125 | return ret; |
126 | } | 126 | } |
127 | 127 | ||
128 | |||
129 | /** | ||
130 | * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter | ||
131 | */ | ||
132 | static int pcmcia_io_cfg_data_width(unsigned int flags) | ||
133 | { | ||
134 | if (!(flags & CISTPL_IO_8BIT)) | ||
135 | return IO_DATA_PATH_WIDTH_16; | ||
136 | if (!(flags & CISTPL_IO_16BIT)) | ||
137 | return IO_DATA_PATH_WIDTH_8; | ||
138 | return IO_DATA_PATH_WIDTH_AUTO; | ||
139 | } | ||
140 | |||
141 | |||
128 | struct pcmcia_cfg_mem { | 142 | struct pcmcia_cfg_mem { |
129 | struct pcmcia_device *p_dev; | 143 | struct pcmcia_device *p_dev; |
144 | int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data); | ||
130 | void *priv_data; | 145 | void *priv_data; |
131 | int (*conf_check) (struct pcmcia_device *p_dev, | ||
132 | cistpl_cftable_entry_t *cfg, | ||
133 | cistpl_cftable_entry_t *dflt, | ||
134 | void *priv_data); | ||
135 | cisparse_t parse; | 146 | cisparse_t parse; |
136 | cistpl_cftable_entry_t dflt; | 147 | cistpl_cftable_entry_t dflt; |
137 | }; | 148 | }; |
@@ -184,16 +195,63 @@ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) | |||
184 | if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO)) | 195 | if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO)) |
185 | p_dev->config_flags |= CONF_ENABLE_SPKR; | 196 | p_dev->config_flags |= CONF_ENABLE_SPKR; |
186 | 197 | ||
187 | return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt, | 198 | |
188 | cfg_mem->priv_data); | 199 | /* IO window settings? */ |
200 | if (flags & CONF_AUTO_SET_IO) { | ||
201 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; | ||
202 | int i = 0; | ||
203 | |||
204 | p_dev->resource[0]->start = p_dev->resource[0]->end = 0; | ||
205 | p_dev->resource[1]->start = p_dev->resource[1]->end = 0; | ||
206 | if (io->nwin == 0) | ||
207 | return -ENODEV; | ||
208 | |||
209 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; | ||
210 | p_dev->resource[0]->flags |= | ||
211 | pcmcia_io_cfg_data_width(io->flags); | ||
212 | if (io->nwin > 1) { | ||
213 | /* For multifunction cards, by convention, we | ||
214 | * configure the network function with window 0, | ||
215 | * and serial with window 1 */ | ||
216 | i = (io->win[1].len > io->win[0].len); | ||
217 | p_dev->resource[1]->flags = p_dev->resource[0]->flags; | ||
218 | p_dev->resource[1]->start = io->win[1-i].base; | ||
219 | p_dev->resource[1]->end = io->win[1-i].len; | ||
220 | } | ||
221 | p_dev->resource[0]->start = io->win[i].base; | ||
222 | p_dev->resource[0]->end = io->win[i].len; | ||
223 | p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; | ||
224 | } | ||
225 | |||
226 | /* MEM window settings? */ | ||
227 | if (flags & CONF_AUTO_SET_IOMEM) { | ||
228 | /* so far, we only set one memory window */ | ||
229 | cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; | ||
230 | |||
231 | p_dev->resource[2]->start = p_dev->resource[2]->end = 0; | ||
232 | if (mem->nwin == 0) | ||
233 | return -ENODEV; | ||
234 | |||
235 | p_dev->resource[2]->start = mem->win[0].host_addr; | ||
236 | p_dev->resource[2]->end = mem->win[0].len; | ||
237 | if (p_dev->resource[2]->end < 0x1000) | ||
238 | p_dev->resource[2]->end = 0x1000; | ||
239 | p_dev->card_addr = mem->win[0].card_addr; | ||
240 | } | ||
241 | |||
242 | dev_dbg(&p_dev->dev, | ||
243 | "checking configuration %x: %pr %pr %pr (%d lines)\n", | ||
244 | p_dev->config_index, p_dev->resource[0], p_dev->resource[1], | ||
245 | p_dev->resource[2], p_dev->io_lines); | ||
246 | |||
247 | return cfg_mem->conf_check(p_dev, cfg_mem->priv_data); | ||
189 | } | 248 | } |
190 | 249 | ||
191 | /** | 250 | /** |
192 | * pcmcia_loop_config() - loop over configuration options | 251 | * pcmcia_loop_config() - loop over configuration options |
193 | * @p_dev: the struct pcmcia_device which we need to loop for. | 252 | * @p_dev: the struct pcmcia_device which we need to loop for. |
194 | * @conf_check: function to call for each configuration option. | 253 | * @conf_check: function to call for each configuration option. |
195 | * It gets passed the struct pcmcia_device, the CIS data | 254 | * It gets passed the struct pcmcia_device and private data |
196 | * describing the configuration option, and private data | ||
197 | * being passed to pcmcia_loop_config() | 255 | * being passed to pcmcia_loop_config() |
198 | * @priv_data: private data to be passed to the conf_check function. | 256 | * @priv_data: private data to be passed to the conf_check function. |
199 | * | 257 | * |
@@ -203,8 +261,6 @@ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) | |||
203 | */ | 261 | */ |
204 | int pcmcia_loop_config(struct pcmcia_device *p_dev, | 262 | int pcmcia_loop_config(struct pcmcia_device *p_dev, |
205 | int (*conf_check) (struct pcmcia_device *p_dev, | 263 | int (*conf_check) (struct pcmcia_device *p_dev, |
206 | cistpl_cftable_entry_t *cfg, | ||
207 | cistpl_cftable_entry_t *dflt, | ||
208 | void *priv_data), | 264 | void *priv_data), |
209 | void *priv_data) | 265 | void *priv_data) |
210 | { | 266 | { |