summaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-01-07 14:40:05 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-01-07 14:40:05 +0000
commit123656d4cc8c946f578ebd18c2050f5251720428 (patch)
tree3d5432eff034a3b9cfdc98b37e245abe5695342d /drivers/pcmcia
parenta62c80e559809e6c7851ec04d30575e85ad6f6ed (diff)
parent0aec63e67c69545ca757a73a66f5dcf05fa484bf (diff)
Merge with Linus' kernel.
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/Kconfig32
-rw-r--r--drivers/pcmcia/au1000_generic.c21
-rw-r--r--drivers/pcmcia/cistpl.c36
-rw-r--r--drivers/pcmcia/cs.c112
-rw-r--r--drivers/pcmcia/cs_internal.h4
-rw-r--r--drivers/pcmcia/ds.c401
-rw-r--r--drivers/pcmcia/hd64465_ss.c13
-rw-r--r--drivers/pcmcia/i82092.c73
-rw-r--r--drivers/pcmcia/i82092aa.h1
-rw-r--r--drivers/pcmcia/i82365.c83
-rw-r--r--drivers/pcmcia/m32r_cfc.c32
-rw-r--r--drivers/pcmcia/m32r_pcc.c20
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c114
-rw-r--r--drivers/pcmcia/pd6729.c74
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c3
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c3
-rw-r--r--drivers/pcmcia/rsrc_mgr.c108
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c140
-rw-r--r--drivers/pcmcia/soc_common.c23
-rw-r--r--drivers/pcmcia/socket_sysfs.c30
-rw-r--r--drivers/pcmcia/tcic.c61
-rw-r--r--drivers/pcmcia/ti113x.h4
-rw-r--r--drivers/pcmcia/vrc4171_card.c70
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c43
-rw-r--r--drivers/pcmcia/yenta_socket.c140
25 files changed, 616 insertions, 1025 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 309eb557f9a3..1f4ad0e7836e 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -116,6 +116,31 @@ config YENTA
If unsure, say Y.
+config YENTA_O2
+ default y
+ bool "Special initialization for O2Micro bridges" if EMBEDDED
+ depends on YENTA
+
+config YENTA_RICOH
+ default y
+ bool "Special initialization for Ricoh bridges" if EMBEDDED
+ depends on YENTA
+
+config YENTA_TI
+ default y
+ bool "Special initialization for TI and EnE bridges" if EMBEDDED
+ depends on YENTA
+
+config YENTA_ENE_TUNE
+ default y
+ bool "Auto-tune EnE bridges for CB cards" if EMBEDDED
+ depends on YENTA_TI && CARDBUS
+
+config YENTA_TOSHIBA
+ default y
+ bool "Special initialization for Toshiba ToPIC bridges" if EMBEDDED
+ depends on YENTA
+
config PD6729
tristate "Cirrus PD6729 compatible bridge support"
depends on PCMCIA && PCI
@@ -157,7 +182,7 @@ config TCIC
config PCMCIA_M8XX
tristate "MPC8xx PCMCIA support"
depends on PCMCIA && PPC && 8xx
- select PCCARD_NONSTATIC
+ select PCCARD_IODYN
help
Say Y here to include support for PowerPC 8xx series PCMCIA
controller.
@@ -200,7 +225,7 @@ config PCMCIA_PXA2XX
config PCMCIA_PROBE
bool
- default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X
+ default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X && !PARISC
config M32R_PCC
bool "M32R PCMCIA I/F"
@@ -241,6 +266,9 @@ config OMAP_CF
config PCCARD_NONSTATIC
tristate
+config PCCARD_IODYN
+ bool
+
endif # PCCARD
endmenu
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 87302c548c24..971a35281649 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -241,23 +241,6 @@ au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
return 0;
}
-/* au1x00_pcmcia_get_socket()
- * Implements the get_socket() operation for the in-kernel PCMCIA
- * service (formerly SS_GetSocket in Card Services). Not a very
- * exciting routine.
- *
- * Returns: 0
- */
-static int
-au1x00_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
-{
- struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-
- debug("for sock %u\n", skt->nr);
- *state = skt->cs_state;
- return 0;
-}
-
/* au1x00_pcmcia_set_socket()
* Implements the set_socket() operation for the in-kernel PCMCIA
* service (formerly SS_SetSocket in Card Services). We more or
@@ -352,7 +335,6 @@ static struct pccard_operations au1x00_pcmcia_operations = {
.init = au1x00_pcmcia_sock_init,
.suspend = au1x00_pcmcia_suspend,
.get_status = au1x00_pcmcia_get_status,
- .get_socket = au1x00_pcmcia_get_socket,
.set_socket = au1x00_pcmcia_set_socket,
.set_io_map = au1x00_pcmcia_set_io_map,
.set_mem_map = au1x00_pcmcia_set_mem_map,
@@ -372,13 +354,12 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops,
struct skt_dev_info *sinfo;
int ret, i;
- sinfo = kmalloc(sizeof(struct skt_dev_info), GFP_KERNEL);
+ sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL);
if (!sinfo) {
ret = -ENOMEM;
goto out;
}
- memset(sinfo, 0, sizeof(struct skt_dev_info));
sinfo->nskt = nr;
/*
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 2dc3e611a9a3..120fa8da6392 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -60,9 +60,9 @@ static const u_int exponent[] = {
/* Parameters that can be set with 'insmod' */
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
-
-INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */
+/* 16-bit CIS? */
+static int cis_width;
+module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s)
{
@@ -463,7 +463,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
/* Get indirect link from the MFC tuple */
read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link);
- ofs = le32_to_cpu(*(u_int *)(link+1));
+ ofs = le32_to_cpu(*(__le32 *)(link+1));
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
@@ -671,8 +671,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
if (tuple->TupleDataLen < 5)
return CS_BAD_TUPLE;
p = (u_char *)tuple->TupleData;
- csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
- csum->len = le16_to_cpu(*(u_short *)(p + 2));
+ csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2;
+ csum->len = le16_to_cpu(*(__le16 *)(p + 2));
csum->sum = *(p+4);
return CS_SUCCESS;
}
@@ -683,7 +683,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+ link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData);
return CS_SUCCESS;
}
@@ -702,7 +702,7 @@ static int parse_longlink_mfc(tuple_t *tuple,
return CS_BAD_TUPLE;
for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++;
- link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+ link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4;
}
return CS_SUCCESS;
}
@@ -789,10 +789,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{
- u_short *p;
+ __le16 *p;
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- p = (u_short *)tuple->TupleData;
+ p = (__le16 *)tuple->TupleData;
m->manf = le16_to_cpu(p[0]);
m->card = le16_to_cpu(p[1]);
return CS_SUCCESS;
@@ -1093,7 +1093,7 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x20:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
@@ -1101,9 +1101,9 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x40:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
entry->mem.win[0].card_addr =
- le16_to_cpu(*(u_short *)(p+2)) << 8;
+ le16_to_cpu(*(__le16 *)(p+2)) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q) return CS_BAD_TUPLE;
@@ -1140,7 +1140,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
p = (u_char *)tuple->TupleData;
bar->attr = *p;
p += 2;
- bar->size = le32_to_cpu(*(u_int *)p);
+ bar->size = le32_to_cpu(*(__le32 *)p);
return CS_SUCCESS;
}
@@ -1153,7 +1153,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
return CS_BAD_TUPLE;
config->last_idx = *(++p);
p++;
- config->base = le32_to_cpu(*(u_int *)p);
+ config->base = le32_to_cpu(*(__le32 *)p);
config->subtuples = tuple->TupleDataLen - 6;
return CS_SUCCESS;
}
@@ -1269,7 +1269,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
v2->vers = p[0];
v2->comply = p[1];
- v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+ v2->dindex = le16_to_cpu(*(__le16 *)(p+2));
v2->vspec8 = p[6];
v2->vspec9 = p[7];
v2->nhdr = p[8];
@@ -1310,8 +1310,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
fmt->type = p[0];
fmt->edc = p[1];
- fmt->offset = le32_to_cpu(*(u_int *)(p+2));
- fmt->length = le32_to_cpu(*(u_int *)(p+6));
+ fmt->offset = le32_to_cpu(*(__le32 *)(p+2));
+ fmt->length = le32_to_cpu(*(__le32 *)(p+6));
return CS_SUCCESS;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index a30aa74304a2..613f2f1fbfdd 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -309,41 +309,6 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
}
EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
-
-/**
- * socket_setup() and shutdown_socket() are called by the main event
- * handler when card insertion and removal events are received.
- * socket_setup() turns on socket power and resets the socket, in two stages.
- * shutdown_socket() unconfigures a socket and turns off socket power.
- */
-static void shutdown_socket(struct pcmcia_socket *s)
-{
- cs_dbg(s, 1, "shutdown_socket\n");
-
- /* Blank out the socket state */
- s->socket = dead_socket;
- s->ops->init(s);
- s->ops->set_socket(s, &s->socket);
- s->irq.AssignedIRQ = s->irq.Config = 0;
- s->lock_count = 0;
- destroy_cis_cache(s);
-#ifdef CONFIG_CARDBUS
- cb_free(s);
-#endif
- s->functions = 0;
- kfree(s->config);
- s->config = NULL;
-
- {
- int status;
- s->ops->get_status(s, &status);
- if (status & SS_POWERON) {
- printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
- }
- }
-} /* shutdown_socket */
-
-
/**
* The central event handler. Send_event() sends an event to the
* 16-bit subsystem, which then calls the relevant device drivers.
@@ -383,17 +348,6 @@ static void socket_remove_drivers(struct pcmcia_socket *skt)
send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
}
-static void socket_shutdown(struct pcmcia_socket *skt)
-{
- cs_dbg(skt, 4, "shutdown\n");
-
- socket_remove_drivers(skt);
- skt->state &= SOCKET_INUSE|SOCKET_PRESENT;
- msleep(shutdown_delay * 10);
- skt->state &= SOCKET_INUSE;
- shutdown_socket(skt);
-}
-
static int socket_reset(struct pcmcia_socket *skt)
{
int status, i;
@@ -424,6 +378,45 @@ static int socket_reset(struct pcmcia_socket *skt)
return CS_GENERAL_FAILURE;
}
+/**
+ * socket_setup() and socket_shutdown() are called by the main event handler
+ * when card insertion and removal events are received.
+ * socket_setup() turns on socket power and resets the socket, in two stages.
+ * socket_shutdown() unconfigures a socket and turns off socket power.
+ */
+static void socket_shutdown(struct pcmcia_socket *s)
+{
+ int status;
+
+ cs_dbg(s, 4, "shutdown\n");
+
+ socket_remove_drivers(s);
+ s->state &= SOCKET_INUSE | SOCKET_PRESENT;
+ msleep(shutdown_delay * 10);
+ s->state &= SOCKET_INUSE;
+
+ /* Blank out the socket state */
+ s->socket = dead_socket;
+ s->ops->init(s);
+ s->ops->set_socket(s, &s->socket);
+ s->irq.AssignedIRQ = s->irq.Config = 0;
+ s->lock_count = 0;
+ destroy_cis_cache(s);
+#ifdef CONFIG_CARDBUS
+ cb_free(s);
+#endif
+ s->functions = 0;
+ kfree(s->config);
+ s->config = NULL;
+
+ s->ops->get_status(s, &status);
+ if (status & SS_POWERON) {
+ printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+ }
+
+ cs_socket_put(s);
+}
+
static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
{
int status, i;
@@ -529,7 +522,6 @@ static int socket_insert(struct pcmcia_socket *skt)
send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
} else {
socket_shutdown(skt);
- cs_socket_put(skt);
}
return ret;
@@ -593,7 +585,6 @@ static int socket_resume(struct pcmcia_socket *skt)
}
} else {
socket_shutdown(skt);
- cs_socket_put(skt);
}
skt->state &= ~SOCKET_SUSPEND;
@@ -605,7 +596,6 @@ static void socket_remove(struct pcmcia_socket *skt)
{
printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock);
socket_shutdown(skt);
- cs_socket_put(skt);
}
/*
@@ -780,8 +770,13 @@ int pccard_reset_card(struct pcmcia_socket *skt)
ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
if (ret == 0) {
send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
- if (socket_reset(skt) == CS_SUCCESS)
+ if (skt->callback)
+ skt->callback->suspend(skt);
+ if (socket_reset(skt) == CS_SUCCESS) {
send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+ if (skt->callback)
+ skt->callback->resume(skt);
+ }
}
ret = CS_SUCCESS;
@@ -812,6 +807,11 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
ret = CS_UNSUPPORTED_FUNCTION;
break;
}
+ if (skt->callback) {
+ ret = skt->callback->suspend(skt);
+ if (ret)
+ break;
+ }
ret = socket_suspend(skt);
} while (0);
up(&skt->skt_sem);
@@ -838,6 +838,8 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
break;
}
ret = socket_resume(skt);
+ if (!ret && skt->callback)
+ skt->callback->resume(skt);
} while (0);
up(&skt->skt_sem);
@@ -901,14 +903,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_hotplug(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
int i = 0, length = 0;
- if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "SOCKET_NO=%u", s->sock))
+ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
+ &length, "SOCKET_NO=%u", s->sock))
return -ENOMEM;
envp[i] = NULL;
@@ -927,7 +929,7 @@ static void pcmcia_release_socket_class(struct class *data)
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
- .hotplug = pcmcia_socket_hotplug,
+ .uevent = pcmcia_socket_uevent,
.release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
};
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 55867bc7f199..7b37eba35bf1 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -117,7 +117,7 @@ int verify_cis_cache(struct pcmcia_socket *s);
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse);
/* In rsrc_mgr */
-void pcmcia_validate_mem(struct pcmcia_socket *s);
+int pcmcia_validate_mem(struct pcmcia_socket *s);
struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
struct pcmcia_socket *s);
int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
@@ -143,6 +143,8 @@ struct pcmcia_callback{
struct module *owner;
int (*event) (struct pcmcia_socket *s, event_t event, int priority);
void (*requery) (struct pcmcia_socket *s);
+ int (*suspend) (struct pcmcia_socket *s);
+ int (*resume) (struct pcmcia_socket *s);
};
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7f8219f3fd9e..0252582b91cd 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -57,8 +57,6 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644);
spinlock_t pcmcia_dev_list_lock;
-static int unbind_request(struct pcmcia_socket *s);
-
/*====================================================================*/
/* code which was in cs.c before */
@@ -205,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
unsigned int i;
u32 hash;
- if (!p_drv->attach || !p_drv->event || !p_drv->detach)
+ if (!p_drv->probe || !p_drv->remove)
printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
"function\n", p_drv->drv.name);
@@ -266,12 +264,10 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
if (fw->size >= CISTPL_MAX_CIS_SIZE)
goto release;
- cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+ cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
if (!cis)
goto release;
- memset(cis, 0, sizeof(cisdump_t));
-
cis->Length = fw->size + 1;
memcpy(cis->Data, fw->data, fw->size);
@@ -363,6 +359,7 @@ static int pcmcia_device_probe(struct device * dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
+ struct pcmcia_socket *s;
int ret = 0;
dev = get_device(dev);
@@ -371,25 +368,38 @@ static int pcmcia_device_probe(struct device * dev)
p_dev = to_pcmcia_dev(dev);
p_drv = to_pcmcia_drv(dev->driver);
+ s = p_dev->socket;
- if (!try_module_get(p_drv->owner)) {
+ if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) {
ret = -EINVAL;
goto put_dev;
}
- if (p_drv->attach) {
- p_dev->instance = p_drv->attach();
- if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) {
- printk(KERN_NOTICE "ds: unable to create instance "
- "of '%s'!\n", p_drv->drv.name);
- ret = -EINVAL;
+ p_dev->state &= ~CLIENT_UNBOUND;
+
+ /* set up the device configuration, if it hasn't been done before */
+ if (!s->functions) {
+ cistpl_longlink_mfc_t mfc;
+ if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC,
+ &mfc) == CS_SUCCESS)
+ s->functions = mfc.nfn;
+ else
+ s->functions = 1;
+ s->config = kzalloc(sizeof(config_t) * s->functions,
+ GFP_KERNEL);
+ if (!s->config) {
+ ret = -ENOMEM;
+ goto put_module;
}
}
+ ret = p_drv->probe(p_dev);
+
+ put_module:
if (ret)
module_put(p_drv->owner);
put_dev:
- if ((ret) || !(p_drv->attach))
+ if (ret)
put_device(dev);
return (ret);
}
@@ -399,24 +409,66 @@ static int pcmcia_device_remove(struct device * dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
+ int i;
/* detach the "instance" */
p_dev = to_pcmcia_dev(dev);
p_drv = to_pcmcia_drv(dev->driver);
+ if (!p_drv)
+ return 0;
- if (p_drv) {
- if ((p_drv->detach) && (p_dev->instance)) {
- p_drv->detach(p_dev->instance);
- /* from pcmcia_probe_device */
- put_device(&p_dev->dev);
- }
- module_put(p_drv->owner);
- }
+ if (p_drv->remove)
+ p_drv->remove(p_dev);
+
+ /* check for proper unloading */
+ if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+ printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
+ p_drv->drv.name);
+
+ for (i = 0; i < MAX_WIN; i++)
+ if (p_dev->state & CLIENT_WIN_REQ(i))
+ printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
+ p_drv->drv.name);
+
+ /* references from pcmcia_probe_device */
+ p_dev->state = CLIENT_UNBOUND;
+ pcmcia_put_dev(p_dev);
+ module_put(p_drv->owner);
return 0;
}
+/*
+ * Removes a PCMCIA card from the device tree and socket list.
+ */
+static void pcmcia_card_remove(struct pcmcia_socket *s)
+{
+ struct pcmcia_device *p_dev;
+ unsigned long flags;
+
+ ds_dbg(2, "unbind_request(%d)\n", s->sock);
+
+ s->device_count = 0;
+
+ for (;;) {
+ /* unregister all pcmcia_devices registered with this socket*/
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ if (list_empty(&s->devices_list)) {
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ return;
+ }
+ p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
+ list_del(&p_dev->socket_device_list);
+ p_dev->state |= CLIENT_STALE;
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ device_unregister(&p_dev->dev);
+ }
+
+ return;
+} /* unbind_request */
+
/*
* pcmcia_device_query -- determine information about a pcmcia device
@@ -517,10 +569,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
if (s->device_count == 2)
goto err_put;
- p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+ p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
if (!p_dev)
goto err_put;
- memset(p_dev, 0, sizeof(struct pcmcia_device));
p_dev->socket = s;
p_dev->device_no = (s->device_count++);
@@ -583,7 +634,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
if (!(s->resource_setup_done))
return -EAGAIN; /* try again, but later... */
- pcmcia_validate_mem(s);
+ if (pcmcia_validate_mem(s))
+ return -EAGAIN; /* try again, but later... */
+
ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
if (ret || !cisinfo.Chains) {
ds_dbg(0, "invalid CIS or invalid resources\n");
@@ -779,8 +832,8 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
#ifdef CONFIG_HOTPLUG
-static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
{
struct pcmcia_device *p_dev;
int i, length = 0;
@@ -800,31 +853,31 @@ static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
i = 0;
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "SOCKET_NO=%u",
- p_dev->socket->sock))
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "SOCKET_NO=%u",
+ p_dev->socket->sock))
return -ENOMEM;
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE_NO=%02X",
- p_dev->device_no))
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DEVICE_NO=%02X",
+ p_dev->device_no))
return -ENOMEM;
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
- "pa%08Xpb%08Xpc%08Xpd%08X",
- p_dev->has_manf_id ? p_dev->manf_id : 0,
- p_dev->has_card_id ? p_dev->card_id : 0,
- p_dev->has_func_id ? p_dev->func_id : 0,
- p_dev->func,
- p_dev->device_no,
- hash[0],
- hash[1],
- hash[2],
- hash[3]))
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ "pa%08Xpb%08Xpc%08Xpd%08X",
+ p_dev->has_manf_id ? p_dev->manf_id : 0,
+ p_dev->has_card_id ? p_dev->card_id : 0,
+ p_dev->has_func_id ? p_dev->func_id : 0,
+ p_dev->func,
+ p_dev->device_no,
+ hash[0],
+ hash[1],
+ hash[2],
+ hash[3]))
return -ENOMEM;
envp[i] = NULL;
@@ -834,7 +887,7 @@ static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
#else
-static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
return -ENODEV;
@@ -918,55 +971,84 @@ static struct device_attribute pcmcia_dev_attrs[] = {
__ATTR_NULL,
};
+/* PM support, also needed for reset */
-/*======================================================================
+static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ struct pcmcia_driver *p_drv = NULL;
- The card status event handler.
-
-======================================================================*/
+ if (dev->driver)
+ p_drv = to_pcmcia_drv(dev->driver);
-struct send_event_data {
- struct pcmcia_socket *skt;
- event_t event;
- int priority;
-};
+ if (p_drv && p_drv->suspend)
+ return p_drv->suspend(p_dev);
-static int send_event_callback(struct device *dev, void * _data)
+ return 0;
+}
+
+
+static int pcmcia_dev_resume(struct device * dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- struct pcmcia_driver *p_drv;
- struct send_event_data *data = _data;
+ struct pcmcia_driver *p_drv = NULL;
- /* we get called for all sockets, but may only pass the event
- * for drivers _on the affected socket_ */
- if (p_dev->socket != data->skt)
- return 0;
+ if (dev->driver)
+ p_drv = to_pcmcia_drv(dev->driver);
- p_drv = to_pcmcia_drv(p_dev->dev.driver);
- if (!p_drv)
+ if (p_drv && p_drv->resume)
+ return p_drv->resume(p_dev);
+
+ return 0;
+}
+
+
+static int pcmcia_bus_suspend_callback(struct device *dev, void * _data)
+{
+ struct pcmcia_socket *skt = _data;
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+ if (p_dev->socket != skt)
return 0;
- if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+}
+
+static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
+{
+ struct pcmcia_socket *skt = _data;
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+
+ if (p_dev->socket != skt)
return 0;
- if (p_drv->event)
- return p_drv->event(data->event, data->priority,
- &p_dev->event_callback_args);
+ dpm_runtime_resume(dev);
+
+ return 0;
+}
+static int pcmcia_bus_resume(struct pcmcia_socket *skt)
+{
+ bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
return 0;
}
-static int send_event(struct pcmcia_socket *s, event_t event, int priority)
+static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
{
- struct send_event_data private;
+ if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
+ pcmcia_bus_suspend_callback)) {
+ pcmcia_bus_resume(skt);
+ return -EIO;
+ }
+ return 0;
+}
- private.skt = s;
- private.event = event;
- private.priority = priority;
- return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
-} /* send_event */
+/*======================================================================
+ The card status event handler.
+
+======================================================================*/
/* Normally, the event is passed to individual drivers after
* informing userspace. Only for CS_EVENT_CARD_REMOVAL this
@@ -976,20 +1058,17 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
{
struct pcmcia_socket *s = pcmcia_get_socket(skt);
- int ret = 0;
ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
event, priority, skt);
-
- switch (event) {
+ switch (event) {
case CS_EVENT_CARD_REMOVAL:
s->pcmcia_state.present = 0;
- send_event(skt, event, priority);
- unbind_request(skt);
+ pcmcia_card_remove(skt);
handle_event(skt, event);
break;
-
+
case CS_EVENT_CARD_INSERTION:
s->pcmcia_state.present = 1;
pcmcia_card_add(skt);
@@ -997,12 +1076,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
break;
case CS_EVENT_EJECTION_REQUEST:
- ret = send_event(skt, event, priority);
break;
+ case CS_EVENT_PM_SUSPEND:
+ case CS_EVENT_PM_RESUME:
+ case CS_EVENT_RESET_PHYSICAL:
+ case CS_EVENT_CARD_RESET:
default:
handle_event(skt, event);
- send_event(skt, event, priority);
break;
}
@@ -1012,152 +1093,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
} /* ds_event */
-
-int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
-{
- struct pcmcia_socket *s = NULL;
- struct pcmcia_device *p_dev = NULL;
- struct pcmcia_driver *p_drv = NULL;
-
- /* Look for unbound client with matching dev_info */
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
- unsigned long flags;
-
- if (s->state & SOCKET_CARDBUS)
- continue;
-
- s = pcmcia_get_socket(s);
- if (!s)
- continue;
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- p_dev = pcmcia_get_dev(p_dev);
- if (!p_dev)
- continue;
- if (!(p_dev->state & CLIENT_UNBOUND) ||
- (!p_dev->dev.driver)) {
- pcmcia_put_dev(p_dev);
- continue;
- }
- p_drv = t