diff options
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 128 |
1 files changed, 63 insertions, 65 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index bf16a1cf7399..14b1a951e1b6 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -226,92 +226,90 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res, EXPORT_SYMBOL(pcmcia_map_mem_page); -/** pcmcia_modify_configuration +/** + * pcmcia_fixup_iowidth() - reduce io width to 8bit * - * Modify a locked socket configuration + * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the + * IO width to 8bit after having called pcmcia_request_configuration() + * previously. */ -int pcmcia_modify_configuration(struct pcmcia_device *p_dev, - modconf_t *mod) +int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev) { - struct pcmcia_socket *s; - config_t *c; - int ret; - - s = p_dev->socket; + struct pcmcia_socket *s = p_dev->socket; + pccard_io_map io_off = { 0, 0, 0, 0, 1 }; + pccard_io_map io_on; + int i, ret = 0; mutex_lock(&s->ops_mutex); - c = p_dev->function_config; - if (!(s->state & SOCKET_PRESENT)) { - dev_dbg(&p_dev->dev, "No card present\n"); - ret = -ENODEV; - goto unlock; - } - if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isnt't locked\n"); + dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n"); + + if (!(s->state & SOCKET_PRESENT) || + !(p_dev->function_config->state & CONFIG_LOCKED)) { + dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); ret = -EACCES; goto unlock; } - if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) { - dev_dbg(&p_dev->dev, - "changing Vcc or IRQ is not allowed at this time\n"); - ret = -EINVAL; - goto unlock; - } + io_on.speed = io_speed; + for (i = 0; i < MAX_IO_WIN; i++) { + if (!s->io[i].res) + continue; + io_off.map = i; + io_on.map = i; - /* We only allow changing Vpp1 and Vpp2 to the same value */ - if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && - (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - if (mod->Vpp1 != mod->Vpp2) { - dev_dbg(&p_dev->dev, - "Vpp1 and Vpp2 must be the same\n"); - ret = -EINVAL; - goto unlock; - } - s->socket.Vpp = mod->Vpp1; - if (s->ops->set_socket(s, &s->socket)) { - dev_printk(KERN_WARNING, &p_dev->dev, - "Unable to set VPP\n"); - ret = -EIO; - goto unlock; - } - } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || - (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - dev_dbg(&p_dev->dev, - "changing Vcc is not allowed at this time\n"); - ret = -EINVAL; - goto unlock; + io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; + io_on.start = s->io[i].res->start; + io_on.stop = s->io[i].res->end; + + s->ops->set_io_map(s, &io_off); + mdelay(40); + s->ops->set_io_map(s, &io_on); } +unlock: + mutex_unlock(&s->ops_mutex); - if (mod->Attributes & CONF_IO_CHANGE_WIDTH) { - pccard_io_map io_off = { 0, 0, 0, 0, 1 }; - pccard_io_map io_on; - int i; + return ret; +} +EXPORT_SYMBOL(pcmcia_fixup_iowidth); - io_on.speed = io_speed; - for (i = 0; i < MAX_IO_WIN; i++) { - if (!s->io[i].res) - continue; - io_off.map = i; - io_on.map = i; - io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; - io_on.start = s->io[i].res->start; - io_on.stop = s->io[i].res->end; +/** + * pcmcia_fixup_vpp() - set Vpp to a new voltage level + * + * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to + * a new voltage level between calls to pcmcia_request_configuration() + * and pcmcia_disable_device(). + */ +int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp) +{ + struct pcmcia_socket *s = p_dev->socket; + int ret = 0; - s->ops->set_io_map(s, &io_off); - mdelay(40); - s->ops->set_io_map(s, &io_on); - } + mutex_lock(&s->ops_mutex); + + dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp); + + if (!(s->state & SOCKET_PRESENT) || + !(p_dev->function_config->state & CONFIG_LOCKED)) { + dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); + ret = -EACCES; + goto unlock; } - ret = 0; + + s->socket.Vpp = new_vpp; + if (s->ops->set_socket(s, &s->socket)) { + dev_warn(&p_dev->dev, "Unable to set VPP\n"); + ret = -EIO; + goto unlock; + } + unlock: mutex_unlock(&s->ops_mutex); return ret; -} /* modify_configuration */ -EXPORT_SYMBOL(pcmcia_modify_configuration); +} +EXPORT_SYMBOL(pcmcia_fixup_vpp); int pcmcia_release_configuration(struct pcmcia_device *p_dev) |