diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/pata_pcmcia.c | 171 |
1 files changed, 80 insertions, 91 deletions
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 41b4361bbf6e..8cccd1b81ee2 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c | |||
@@ -148,6 +148,69 @@ static struct ata_port_operations pcmcia_8bit_port_ops = { | |||
148 | #define CS_CHECK(fn, ret) \ | 148 | #define CS_CHECK(fn, ret) \ |
149 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 149 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
150 | 150 | ||
151 | |||
152 | struct pcmcia_config_check { | ||
153 | config_info_t conf; | ||
154 | cistpl_cftable_entry_t dflt; | ||
155 | unsigned long ctl_base; | ||
156 | int skip_vcc; | ||
157 | int is_kme; | ||
158 | }; | ||
159 | |||
160 | static int pcmcia_check_one_config(struct pcmcia_device *pdev, | ||
161 | cistpl_cftable_entry_t *cfg, | ||
162 | void *priv_data) | ||
163 | { | ||
164 | struct pcmcia_config_check *stk = priv_data; | ||
165 | |||
166 | /* Check for matching Vcc, unless we're desperate */ | ||
167 | if (!stk->skip_vcc) { | ||
168 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
169 | if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
170 | goto next_entry; | ||
171 | } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
172 | if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
173 | goto next_entry; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
178 | pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
179 | else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
180 | pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
181 | |||
182 | if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { | ||
183 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; | ||
184 | pdev->conf.ConfigIndex = cfg->index; | ||
185 | pdev->io.BasePort1 = io->win[0].base; | ||
186 | pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
187 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
188 | pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
189 | if (io->nwin == 2) { | ||
190 | pdev->io.NumPorts1 = 8; | ||
191 | pdev->io.BasePort2 = io->win[1].base; | ||
192 | pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1; | ||
193 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
194 | goto next_entry; | ||
195 | stk->ctl_base = pdev->io.BasePort2; | ||
196 | } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { | ||
197 | pdev->io.NumPorts1 = io->win[0].len; | ||
198 | pdev->io.NumPorts2 = 0; | ||
199 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
200 | goto next_entry; | ||
201 | stk->ctl_base = pdev->io.BasePort1 + 0x0e; | ||
202 | } else | ||
203 | goto next_entry; | ||
204 | /* If we've got this far, we're done */ | ||
205 | return 0; | ||
206 | } | ||
207 | next_entry: | ||
208 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
209 | memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); | ||
210 | |||
211 | return -ENODEV; | ||
212 | } | ||
213 | |||
151 | /** | 214 | /** |
152 | * pcmcia_init_one - attach a PCMCIA interface | 215 | * pcmcia_init_one - attach a PCMCIA interface |
153 | * @pdev: pcmcia device | 216 | * @pdev: pcmcia device |
@@ -161,19 +224,11 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) | |||
161 | struct ata_host *host; | 224 | struct ata_host *host; |
162 | struct ata_port *ap; | 225 | struct ata_port *ap; |
163 | struct ata_pcmcia_info *info; | 226 | struct ata_pcmcia_info *info; |
164 | tuple_t tuple; | 227 | struct pcmcia_config_check *stk = NULL; |
165 | struct { | 228 | int last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p; |
166 | unsigned short buf[128]; | ||
167 | cisparse_t parse; | ||
168 | config_info_t conf; | ||
169 | cistpl_cftable_entry_t dflt; | ||
170 | } *stk = NULL; | ||
171 | cistpl_cftable_entry_t *cfg; | ||
172 | int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p; | ||
173 | unsigned long io_base, ctl_base; | 229 | unsigned long io_base, ctl_base; |
174 | void __iomem *io_addr, *ctl_addr; | 230 | void __iomem *io_addr, *ctl_addr; |
175 | int n_ports = 1; | 231 | int n_ports = 1; |
176 | |||
177 | struct ata_port_operations *ops = &pcmcia_port_ops; | 232 | struct ata_port_operations *ops = &pcmcia_port_ops; |
178 | 233 | ||
179 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 234 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
@@ -193,96 +248,30 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) | |||
193 | pdev->conf.Attributes = CONF_ENABLE_IRQ; | 248 | pdev->conf.Attributes = CONF_ENABLE_IRQ; |
194 | pdev->conf.IntType = INT_MEMORY_AND_IO; | 249 | pdev->conf.IntType = INT_MEMORY_AND_IO; |
195 | 250 | ||
196 | /* Allocate resoure probing structures */ | ||
197 | |||
198 | stk = kzalloc(sizeof(*stk), GFP_KERNEL); | ||
199 | if (!stk) | ||
200 | goto out1; | ||
201 | |||
202 | cfg = &stk->parse.cftable_entry; | ||
203 | |||
204 | /* Tuples we are walking */ | ||
205 | tuple.TupleData = (cisdata_t *)&stk->buf; | ||
206 | tuple.TupleOffset = 0; | ||
207 | tuple.TupleDataMax = 255; | ||
208 | tuple.Attributes = 0; | ||
209 | |||
210 | /* See if we have a manufacturer identifier. Use it to set is_kme for | 251 | /* See if we have a manufacturer identifier. Use it to set is_kme for |
211 | vendor quirks */ | 252 | vendor quirks */ |
212 | is_kme = ((pdev->manf_id == MANFID_KME) && | 253 | is_kme = ((pdev->manf_id == MANFID_KME) && |
213 | ((pdev->card_id == PRODID_KME_KXLC005_A) || | 254 | ((pdev->card_id == PRODID_KME_KXLC005_A) || |
214 | (pdev->card_id == PRODID_KME_KXLC005_B))); | 255 | (pdev->card_id == PRODID_KME_KXLC005_B))); |
215 | 256 | ||
216 | /* Not sure if this is right... look up the current Vcc */ | 257 | /* Allocate resoure probing structures */ |
217 | CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf)); | ||
218 | /* link->conf.Vcc = stk->conf.Vcc; */ | ||
219 | |||
220 | pass = io_base = ctl_base = 0; | ||
221 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
222 | tuple.Attributes = 0; | ||
223 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple)); | ||
224 | 258 | ||
225 | /* Now munch the resources looking for a suitable set */ | 259 | stk = kzalloc(sizeof(*stk), GFP_KERNEL); |
226 | while (1) { | 260 | if (!stk) |
227 | if (pcmcia_get_tuple_data(pdev, &tuple) != 0) | 261 | goto out1; |
228 | goto next_entry; | 262 | stk->is_kme = is_kme; |
229 | if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0) | ||
230 | goto next_entry; | ||
231 | /* Check for matching Vcc, unless we're desperate */ | ||
232 | if (!pass) { | ||
233 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
234 | if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
235 | goto next_entry; | ||
236 | } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
237 | if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
238 | goto next_entry; | ||
239 | } | ||
240 | } | ||
241 | 263 | ||
242 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | 264 | /* Not sure if this is right... look up the current Vcc */ |
243 | pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | 265 | CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf)); |
244 | else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | 266 | stk->skip_vcc = io_base = ctl_base = 0; |
245 | pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | 267 | if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) { |
246 | 268 | memset(&stk->dflt, 0, sizeof(stk->dflt)); | |
247 | if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { | 269 | stk->skip_vcc = 1; |
248 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; | 270 | if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) |
249 | pdev->conf.ConfigIndex = cfg->index; | 271 | goto failed; /* No suitable config found */ |
250 | pdev->io.BasePort1 = io->win[0].base; | ||
251 | pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
252 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
253 | pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
254 | if (io->nwin == 2) { | ||
255 | pdev->io.NumPorts1 = 8; | ||
256 | pdev->io.BasePort2 = io->win[1].base; | ||
257 | pdev->io.NumPorts2 = (is_kme) ? 2 : 1; | ||
258 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
259 | goto next_entry; | ||
260 | io_base = pdev->io.BasePort1; | ||
261 | ctl_base = pdev->io.BasePort2; | ||
262 | } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { | ||
263 | pdev->io.NumPorts1 = io->win[0].len; | ||
264 | pdev->io.NumPorts2 = 0; | ||
265 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
266 | goto next_entry; | ||
267 | io_base = pdev->io.BasePort1; | ||
268 | ctl_base = pdev->io.BasePort1 + 0x0e; | ||
269 | } else | ||
270 | goto next_entry; | ||
271 | /* If we've got this far, we're done */ | ||
272 | break; | ||
273 | } | ||
274 | next_entry: | ||
275 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
276 | memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); | ||
277 | if (pass) { | ||
278 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple)); | ||
279 | } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) { | ||
280 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple)); | ||
281 | memset(&stk->dflt, 0, sizeof(stk->dflt)); | ||
282 | pass++; | ||
283 | } | ||
284 | } | 272 | } |
285 | 273 | io_base = pdev->io.BasePort1; | |
274 | ctl_base = stk->ctl_base; | ||
286 | CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); | 275 | CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); |
287 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); | 276 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); |
288 | 277 | ||