diff options
Diffstat (limited to 'drivers/ide/legacy/ide-cs.c')
-rw-r--r-- | drivers/ide/legacy/ide-cs.c | 157 |
1 files changed, 76 insertions, 81 deletions
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 21bfac137844..8580becf226a 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c | |||
@@ -220,103 +220,98 @@ out_release: | |||
220 | #define CS_CHECK(fn, ret) \ | 220 | #define CS_CHECK(fn, ret) \ |
221 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 221 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
222 | 222 | ||
223 | struct pcmcia_config_check { | ||
224 | config_info_t conf; | ||
225 | cistpl_cftable_entry_t dflt; | ||
226 | unsigned long ctl_base; | ||
227 | int skip_vcc; | ||
228 | int is_kme; | ||
229 | }; | ||
230 | |||
231 | static int pcmcia_check_one_config(struct pcmcia_device *pdev, | ||
232 | cistpl_cftable_entry_t *cfg, | ||
233 | void *priv_data) | ||
234 | { | ||
235 | struct pcmcia_config_check *stk = priv_data; | ||
236 | |||
237 | /* Check for matching Vcc, unless we're desperate */ | ||
238 | if (!stk->skip_vcc) { | ||
239 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
240 | if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
241 | goto next_entry; | ||
242 | } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
243 | if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
244 | goto next_entry; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
249 | pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
250 | else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
251 | pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
252 | |||
253 | if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { | ||
254 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; | ||
255 | pdev->conf.ConfigIndex = cfg->index; | ||
256 | pdev->io.BasePort1 = io->win[0].base; | ||
257 | pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
258 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
259 | pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
260 | if (io->nwin == 2) { | ||
261 | pdev->io.NumPorts1 = 8; | ||
262 | pdev->io.BasePort2 = io->win[1].base; | ||
263 | pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1; | ||
264 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
265 | goto next_entry; | ||
266 | stk->ctl_base = pdev->io.BasePort2; | ||
267 | } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { | ||
268 | pdev->io.NumPorts1 = io->win[0].len; | ||
269 | pdev->io.NumPorts2 = 0; | ||
270 | if (pcmcia_request_io(pdev, &pdev->io) != 0) | ||
271 | goto next_entry; | ||
272 | stk->ctl_base = pdev->io.BasePort1 + 0x0e; | ||
273 | } else | ||
274 | goto next_entry; | ||
275 | /* If we've got this far, we're done */ | ||
276 | return 0; | ||
277 | } | ||
278 | next_entry: | ||
279 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
280 | memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); | ||
281 | |||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
223 | static int ide_config(struct pcmcia_device *link) | 285 | static int ide_config(struct pcmcia_device *link) |
224 | { | 286 | { |
225 | ide_info_t *info = link->priv; | 287 | ide_info_t *info = link->priv; |
226 | tuple_t tuple; | 288 | struct pcmcia_config_check *stk = NULL; |
227 | struct { | 289 | int last_ret = 0, last_fn = 0, is_kme = 0; |
228 | u_short buf[128]; | ||
229 | cisparse_t parse; | ||
230 | config_info_t conf; | ||
231 | cistpl_cftable_entry_t dflt; | ||
232 | } *stk = NULL; | ||
233 | cistpl_cftable_entry_t *cfg; | ||
234 | int pass, last_ret = 0, last_fn = 0, is_kme = 0; | ||
235 | unsigned long io_base, ctl_base; | 290 | unsigned long io_base, ctl_base; |
236 | struct ide_host *host; | 291 | struct ide_host *host; |
237 | 292 | ||
238 | DEBUG(0, "ide_config(0x%p)\n", link); | 293 | DEBUG(0, "ide_config(0x%p)\n", link); |
239 | 294 | ||
240 | stk = kzalloc(sizeof(*stk), GFP_KERNEL); | ||
241 | if (!stk) goto err_mem; | ||
242 | cfg = &stk->parse.cftable_entry; | ||
243 | |||
244 | tuple.TupleData = (cisdata_t *)&stk->buf; | ||
245 | tuple.TupleOffset = 0; | ||
246 | tuple.TupleDataMax = 255; | ||
247 | tuple.Attributes = 0; | ||
248 | |||
249 | is_kme = ((link->manf_id == MANFID_KME) && | 295 | is_kme = ((link->manf_id == MANFID_KME) && |
250 | ((link->card_id == PRODID_KME_KXLC005_A) || | 296 | ((link->card_id == PRODID_KME_KXLC005_A) || |
251 | (link->card_id == PRODID_KME_KXLC005_B))); | 297 | (link->card_id == PRODID_KME_KXLC005_B))); |
252 | 298 | ||
299 | stk = kzalloc(sizeof(*stk), GFP_KERNEL); | ||
300 | if (!stk) | ||
301 | goto err_mem; | ||
302 | stk->is_kme = is_kme; | ||
303 | |||
253 | /* Not sure if this is right... look up the current Vcc */ | 304 | /* Not sure if this is right... look up the current Vcc */ |
254 | CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); | 305 | CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); |
255 | 306 | stk->skip_vcc = io_base = ctl_base = 0; | |
256 | pass = io_base = ctl_base = 0; | 307 | if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) { |
257 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
258 | tuple.Attributes = 0; | ||
259 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
260 | while (1) { | ||
261 | if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry; | ||
262 | if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry; | ||
263 | |||
264 | /* Check for matching Vcc, unless we're desperate */ | ||
265 | if (!pass) { | ||
266 | if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
267 | if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
268 | goto next_entry; | ||
269 | } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { | ||
270 | if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) | ||
271 | goto next_entry; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
276 | link->conf.Vpp = | ||
277 | cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
278 | else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
279 | link->conf.Vpp = | ||
280 | stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
281 | |||
282 | if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { | ||
283 | cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; | ||
284 | link->conf.ConfigIndex = cfg->index; | ||
285 | link->io.BasePort1 = io->win[0].base; | ||
286 | link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; | ||
287 | if (!(io->flags & CISTPL_IO_16BIT)) | ||
288 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
289 | if (io->nwin == 2) { | ||
290 | link->io.NumPorts1 = 8; | ||
291 | link->io.BasePort2 = io->win[1].base; | ||
292 | link->io.NumPorts2 = (is_kme) ? 2 : 1; | ||
293 | if (pcmcia_request_io(link, &link->io) != 0) | ||
294 | goto next_entry; | ||
295 | io_base = link->io.BasePort1; | ||
296 | ctl_base = link->io.BasePort2; | ||
297 | } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { | ||
298 | link->io.NumPorts1 = io->win[0].len; | ||
299 | link->io.NumPorts2 = 0; | ||
300 | if (pcmcia_request_io(link, &link->io) != 0) | ||
301 | goto next_entry; | ||
302 | io_base = link->io.BasePort1; | ||
303 | ctl_base = link->io.BasePort1 + 0x0e; | ||
304 | } else goto next_entry; | ||
305 | /* If we've got this far, we're done */ | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | next_entry: | ||
310 | if (cfg->flags & CISTPL_CFTABLE_DEFAULT) | ||
311 | memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); | ||
312 | if (pass) { | ||
313 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); | ||
314 | } else if (pcmcia_get_next_tuple(link, &tuple) != 0) { | ||
315 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); | ||
316 | memset(&stk->dflt, 0, sizeof(stk->dflt)); | 308 | memset(&stk->dflt, 0, sizeof(stk->dflt)); |
317 | pass++; | 309 | stk->skip_vcc = 1; |
318 | } | 310 | if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) |
311 | goto failed; /* No suitable config found */ | ||
319 | } | 312 | } |
313 | io_base = link->io.BasePort1; | ||
314 | ctl_base = stk->ctl_base; | ||
320 | 315 | ||
321 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); | 316 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); |
322 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); | 317 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); |