in pcmcia_resource.c [477:609]
int pcmcia_enable_device(struct pcmcia_device *p_dev)
{
int i;
unsigned int base;
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
pccard_io_map iomap;
unsigned char status = 0;
unsigned char ext_status = 0;
unsigned char option = 0;
unsigned int flags = p_dev->config_flags;
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "Configuration is locked\n");
return -EACCES;
}
/* Do power control. We don't allow changes in Vcc. */
s->socket.Vpp = p_dev->vpp;
if (s->ops->set_socket(s, &s->socket)) {
mutex_unlock(&s->ops_mutex);
dev_warn(&p_dev->dev, "Unable to set socket state\n");
return -EINVAL;
}
/* Pick memory or I/O card, DMA mode, interrupt */
if (p_dev->_io || flags & CONF_ENABLE_IRQ)
flags |= CONF_ENABLE_IOCARD;
if (flags & CONF_ENABLE_IOCARD)
s->socket.flags |= SS_IOCARD;
if (flags & CONF_ENABLE_ZVCARD)
s->socket.flags |= SS_ZVCARD | SS_IOCARD;
if (flags & CONF_ENABLE_SPKR) {
s->socket.flags |= SS_SPKR_ENA;
status = CCSR_AUDIO_ENA;
if (!(p_dev->config_regs & PRESENT_STATUS))
dev_warn(&p_dev->dev, "speaker requested, but "
"PRESENT_STATUS not set!\n");
}
if (flags & CONF_ENABLE_IRQ)
s->socket.io_irq = s->pcmcia_irq;
else
s->socket.io_irq = 0;
if (flags & CONF_ENABLE_ESR) {
p_dev->config_regs |= PRESENT_EXT_STATUS;
ext_status = ESR_REQ_ATTN_ENA;
}
s->ops->set_socket(s, &s->socket);
s->lock_count++;
dev_dbg(&p_dev->dev,
"enable_device: V %d, flags %x, base %x, regs %x, idx %x\n",
p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs,
p_dev->config_index);
/* Set up CIS configuration registers */
base = p_dev->config_base;
if (p_dev->config_regs & PRESENT_COPY) {
u16 tmp = 0;
dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n");
pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp);
}
if (p_dev->config_regs & PRESENT_PIN_REPLACE) {
u16 tmp = 0;
dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n");
pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp);
}
if (p_dev->config_regs & PRESENT_OPTION) {
if (s->functions == 1) {
option = p_dev->config_index & COR_CONFIG_MASK;
} else {
option = p_dev->config_index & COR_MFC_CONFIG_MASK;
option |= COR_FUNC_ENA|COR_IREQ_ENA;
if (p_dev->config_regs & PRESENT_IOBASE_0)
option |= COR_ADDR_DECODE;
}
if ((flags & CONF_ENABLE_IRQ) &&
!(flags & CONF_ENABLE_PULSE_IRQ))
option |= COR_LEVEL_REQ;
pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
msleep(40);
}
if (p_dev->config_regs & PRESENT_STATUS)
pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
if (p_dev->config_regs & PRESENT_EXT_STATUS)
pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1,
&ext_status);
if (p_dev->config_regs & PRESENT_IOBASE_0) {
u8 b = c->io[0].start & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
b = (c->io[0].start >> 8) & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
}
if (p_dev->config_regs & PRESENT_IOSIZE) {
u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
}
/* Configure I/O windows */
if (c->state & CONFIG_IO_REQ) {
iomap.speed = io_speed;
for (i = 0; i < MAX_IO_WIN; i++)
if (s->io[i].res) {
iomap.map = i;
iomap.flags = MAP_ACTIVE;
switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) {
case IO_DATA_PATH_WIDTH_16:
iomap.flags |= MAP_16BIT; break;
case IO_DATA_PATH_WIDTH_AUTO:
iomap.flags |= MAP_AUTOSZ; break;
default:
break;
}
iomap.start = s->io[i].res->start;
iomap.stop = s->io[i].res->end;
s->ops->set_io_map(s, &iomap);
s->io[i].Config++;
}
}
c->state |= CONFIG_LOCKED;
p_dev->_locked = 1;
mutex_unlock(&s->ops_mutex);
return 0;
} /* pcmcia_enable_device */