summaryrefslogtreecommitdiff
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/Kconfig7
-rw-r--r--drivers/pcmcia/Makefile3
-rw-r--r--drivers/pcmcia/at91_cf.c365
-rw-r--r--drivers/pcmcia/cistpl.c1
-rw-r--r--drivers/pcmcia/cs.c43
-rw-r--r--drivers/pcmcia/cs_internal.h19
-rw-r--r--drivers/pcmcia/ds.c249
-rw-r--r--drivers/pcmcia/ds_internal.h4
-rw-r--r--drivers/pcmcia/i82092.c1
-rw-r--r--drivers/pcmcia/i82365.c1
-rw-r--r--drivers/pcmcia/pcmcia_compat.c65
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c81
-rw-r--r--drivers/pcmcia/pcmcia_resource.c228
-rw-r--r--drivers/pcmcia/pd6729.c1
-rw-r--r--drivers/pcmcia/rsrc_mgr.c5
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c41
-rw-r--r--drivers/pcmcia/sa1100_cerf.c1
-rw-r--r--drivers/pcmcia/socket_sysfs.c10
-rw-r--r--drivers/pcmcia/ti113x.h1
19 files changed, 767 insertions, 359 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 1f4ad0e7836e..cba6c9eef28e 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -263,6 +263,13 @@ config OMAP_CF
Say Y here to support the CompactFlash controller on OMAP.
Note that this doesn't support "True IDE" mode.
+config AT91_CF
+ tristate "AT91 CompactFlash Controller"
+ depends on PCMCIA && ARCH_AT91RM9200
+ help
+ Say Y here to support the CompactFlash controller on AT91 chips.
+ Or choose M to compile the driver as a module named "at91_cf".
+
config PCCARD_NONSTATIC
tristate
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index bcecf5133b7e..4276965517f2 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -10,7 +10,7 @@ pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o
obj-$(CONFIG_PCCARD) += pcmcia_core.o
-pcmcia-y += ds.o pcmcia_compat.o pcmcia_resource.o
+pcmcia-y += ds.o pcmcia_resource.o
pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o
obj-$(CONFIG_PCMCIA) += pcmcia.o
@@ -36,6 +36,7 @@ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o
obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o
obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
obj-$(CONFIG_OMAP_CF) += omap_cf.o
+obj-$(CONFIG_AT91_CF) += at91_cf.o
sa11xx_core-y += soc_common.o sa11xx_base.o
pxa2xx_core-y += soc_common.o pxa2xx_base.o
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
new file mode 100644
index 000000000000..67cc5f7d0c90
--- /dev/null
+++ b/drivers/pcmcia/at91_cf.c
@@ -0,0 +1,365 @@
+/*
+ * at91_cf.c -- AT91 CompactFlash controller driver
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/at91rm9200.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+
+#define CF_SIZE 0x30000000 /* CS5+CS6: unavailable */
+
+/*
+ * A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW;
+ * some other bit in {A24,A22..A11} is nREG to flag memory access
+ * (vs attributes). So more than 2KB/region would just be waste.
+ */
+#define CF_ATTR_PHYS (AT91_CF_BASE)
+#define CF_IO_PHYS (AT91_CF_BASE + (1 << 23))
+#define CF_MEM_PHYS (AT91_CF_BASE + 0x017ff800)
+
+/*--------------------------------------------------------------------------*/
+
+static const char driver_name[] = "at91_cf";
+
+struct at91_cf_socket {
+ struct pcmcia_socket socket;
+
+ unsigned present:1;
+
+ struct platform_device *pdev;
+ struct at91_cf_data *board;
+};
+
+#define SZ_2K (2 * SZ_1K)
+
+static inline int at91_cf_present(struct at91_cf_socket *cf)
+{
+ return !at91_get_gpio_value(cf->board->det_pin);
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int at91_cf_ss_init(struct pcmcia_socket *s)
+{
+ return 0;
+}
+
+static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r)
+{
+ struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf;
+
+ if (irq == cf->board->det_pin) {
+ unsigned present = at91_cf_present(cf);
+
+ /* kick pccard as needed */
+ if (present != cf->present) {
+ cf->present = present;
+ pr_debug("%s: card %s\n", driver_name, present ? "present" : "gone");
+ pcmcia_parse_events(&cf->socket, SS_DETECT);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+ struct at91_cf_socket *cf;
+
+ if (!sp)
+ return -EINVAL;
+
+ cf = container_of(s, struct at91_cf_socket, socket);
+
+ /* NOTE: we assume 3VCARD, not XVCARD... */
+ if (at91_cf_present(cf)) {
+ int rdy = cf->board->irq_pin; /* RDY/nIRQ */
+ int vcc = cf->board->vcc_pin;
+
+ *sp = SS_DETECT | SS_3VCARD;
+ if (!rdy || at91_get_gpio_value(rdy))
+ *sp |= SS_READY;
+ if (!vcc || at91_get_gpio_value(vcc))
+ *sp |= SS_POWERON;
+ } else
+ *sp = 0;
+
+ return 0;
+}
+
+static int at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+ struct at91_cf_socket *cf;
+
+ cf = container_of(sock, struct at91_cf_socket, socket);
+
+ /* switch Vcc if needed and possible */
+ if (cf->board->vcc_pin) {
+ switch (s->Vcc) {
+ case 0:
+ at91_set_gpio_value(cf->board->vcc_pin, 0);
+ break;
+ case 33:
+ at91_set_gpio_value(cf->board->vcc_pin, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* toggle reset if needed */
+ at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET);
+
+ pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
+ driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+ return 0;
+}
+
+static int at91_cf_ss_suspend(struct pcmcia_socket *s)
+{
+ return at91_cf_set_socket(s, &dead_socket);
+}
+
+/* we already mapped the I/O region */
+static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+ struct at91_cf_socket *cf;
+ u32 csr;
+
+ cf = container_of(s, struct at91_cf_socket, socket);
+ io->flags &= (MAP_ACTIVE | MAP_16BIT | MAP_AUTOSZ);
+
+ /*
+ * Use 16 bit accesses unless/until we need 8-bit i/o space.
+ * Always set CSR4 ... PCMCIA won't always unmap things.
+ */
+ csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW;
+
+ /*
+ * NOTE: this CF controller ignores IOIS16, so we can't really do
+ * MAP_AUTOSZ. The 16bit mode allows single byte access on either
+ * D0-D7 (even addr) or D8-D15 (odd), so it's close enough for many
+ * purposes (and handles ide-cs).
+ *
+ * The 8bit mode is needed for odd byte access on D0-D7. It seems
+ * some cards only like that way to get at the odd byte, despite
+ * CF 3.0 spec table 35 also giving the D8-D15 option.
+ */
+ if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) {
+ csr |= AT91_SMC_DBW_8;
+ pr_debug("%s: 8bit i/o bus\n", driver_name);
+ } else {
+ csr |= AT91_SMC_DBW_16;
+ pr_debug("%s: 16bit i/o bus\n", driver_name);
+ }
+ at91_sys_write(AT91_SMC_CSR(4), csr);
+
+ io->start = cf->socket.io_offset;
+ io->stop = io->start + SZ_2K - 1;
+
+ return 0;
+}
+
+/* pcmcia layer maps/unmaps mem regions */
+static int at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+ struct at91_cf_socket *cf;
+
+ if (map->card_start)
+ return -EINVAL;
+
+ cf = container_of(s, struct at91_cf_socket, socket);
+
+ map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
+ if (map->flags & MAP_ATTRIB)
+ map->static_start = CF_ATTR_PHYS;
+ else
+ map->static_start = CF_MEM_PHYS;
+
+ return 0;
+}
+
+static struct pccard_operations at91_cf_ops = {
+ .init = at91_cf_ss_init,
+ .suspend = at91_cf_ss_suspend,
+ .get_status = at91_cf_get_status,
+ .set_socket = at91_cf_set_socket,
+ .set_io_map = at91_cf_set_io_map,
+ .set_mem_map = at91_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init at91_cf_probe(struct device *dev)
+{
+ struct at91_cf_socket *cf;
+ struct at91_cf_data *board = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ unsigned int csa;
+ int status;
+
+ if (!board || !board->det_pin || !board->rst_pin)
+ return -ENODEV;
+
+ cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
+ if (!cf)
+ return -ENOMEM;
+
+ cf->board = board;
+ cf->pdev = pdev;
+ dev_set_drvdata(dev, cf);
+
+ /* CF takes over CS4, CS5, CS6 */
+ csa = at91_sys_read(AT91_EBI_CSA);
+ at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
+
+ /* force poweron defaults for these pins ... */
+ (void) at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */
+ (void) at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */
+ (void) at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */
+ (void) at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */
+
+ /* nWAIT is _not_ a default setting */
+ (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
+
+ /*
+ * Static memory controller timing adjustments.
+ * REVISIT: these timings are in terms of MCK cycles, so
+ * when MCK changes (cpufreq etc) so must these values...
+ */
+ at91_sys_write(AT91_SMC_CSR(4), AT91_SMC_ACSS_STD | AT91_SMC_DBW_16 | AT91_SMC_BAT | AT91_SMC_WSEN
+ | AT91_SMC_NWS_(32) /* wait states */
+ | AT91_SMC_RWSETUP_(6) /* setup time */
+ | AT91_SMC_RWHOLD_(4) /* hold time */
+ );
+
+ /* must be a GPIO; ergo must trigger on both edges */
+ status = request_irq(board->det_pin, at91_cf_irq,
+ SA_SAMPLE_RANDOM, driver_name, cf);
+ if (status < 0)
+ goto fail0;
+
+ /*
+ * The card driver will request this irq later as needed.
+ * but it causes lots of "irqNN: nobody cared" messages
+ * unless we report that we handle everything (sigh).
+ * (Note: DK board doesn't wire the IRQ pin...)
+ */
+ if (board->irq_pin) {
+ status = request_irq(board->irq_pin, at91_cf_irq,
+ SA_SHIRQ, driver_name, cf);
+ if (status < 0)
+ goto fail0a;
+ cf->socket.pci_irq = board->irq_pin;
+ }
+ else
+ cf->socket.pci_irq = NR_IRQS + 1;
+
+ /* pcmcia layer only remaps "real" memory not iospace */
+ cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K);
+ if (!cf->socket.io_offset)
+ goto fail1;
+
+ /* reserve CS4, CS5, and CS6 regions; but use just CS4 */
+ if (!request_mem_region(AT91_CF_BASE, CF_SIZE, driver_name))
+ goto fail1;
+
+ pr_info("%s: irqs det #%d, io #%d\n", driver_name,
+ board->det_pin, board->irq_pin);
+
+ cf->socket.owner = THIS_MODULE;
+ cf->socket.dev.dev = dev;
+ cf->socket.ops = &at91_cf_ops;
+ cf->socket.resource_ops = &pccard_static_ops;
+ cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+ | SS_CAP_MEM_ALIGN;
+ cf->socket.map_size = SZ_2K;
+ cf->socket.io[0].NumPorts = SZ_2K;
+
+ status = pcmcia_register_socket(&cf->socket);
+ if (status < 0)
+ goto fail2;
+
+ return 0;
+
+fail2:
+ iounmap((void __iomem *) cf->socket.io_offset);
+ release_mem_region(AT91_CF_BASE, CF_SIZE);
+fail1:
+ if (board->irq_pin)
+ free_irq(board->irq_pin, cf);
+fail0a:
+ free_irq(board->det_pin, cf);
+fail0:
+ at91_sys_write(AT91_EBI_CSA, csa);
+ kfree(cf);
+ return status;
+}
+
+static int __exit at91_cf_remove(struct device *dev)
+{
+ struct at91_cf_socket *cf = dev_get_drvdata(dev);
+ unsigned int csa;
+
+ pcmcia_unregister_socket(&cf->socket);
+ free_irq(cf->board->irq_pin, cf);
+ free_irq(cf->board->det_pin, cf);
+ iounmap((void __iomem *) cf->socket.io_offset);
+ release_mem_region(AT91_CF_BASE, CF_SIZE);
+
+ csa = at91_sys_read(AT91_EBI_CSA);
+ at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A);
+
+ kfree(cf);
+ return 0;
+}
+
+static struct device_driver at91_cf_driver = {
+ .name = (char *) driver_name,
+ .bus = &platform_bus_type,
+ .probe = at91_cf_probe,
+ .remove = __exit_p(at91_cf_remove),
+ .suspend = pcmcia_socket_dev_suspend,
+ .resume = pcmcia_socket_dev_resume,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init at91_cf_init(void)
+{
+ return driver_register(&at91_cf_driver);
+}
+module_init(at91_cf_init);
+
+static void __exit at91_cf_exit(void)
+{
+ driver_unregister(&at91_cf_driver);
+}
+module_exit(at91_cf_exit);
+
+MODULE_DESCRIPTION("AT91 Compact Flash Driver");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 120fa8da6392..912c03e5eb0a 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -12,7 +12,6 @@
* (C) 1999 David A. Hinds
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 613f2f1fbfdd..3162998579c1 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -16,7 +16,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
@@ -111,9 +110,9 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
if (socket->dev.dev != dev)
continue;
- down(&socket->skt_sem);
+ mutex_lock(&socket->skt_mutex);
socket_suspend(socket);
- up(&socket->skt_sem);
+ mutex_unlock(&socket->skt_mutex);
}
up_read(&pcmcia_socket_list_rwsem);
@@ -129,9 +128,9 @@ int pcmcia_socket_dev_resume(struct device *dev)
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
if (socket->dev.dev != dev)
continue;
- down(&socket->skt_sem);
+ mutex_lock(&socket->skt_mutex);
socket_resume(socket);
- up(&socket->skt_sem);
+ mutex_unlock(&socket->skt_mutex);
}
up_read(&pcmcia_socket_list_rwsem);
@@ -237,7 +236,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
init_completion(&socket->socket_released);
init_completion(&socket->thread_done);
init_waitqueue_head(&socket->thread_wait);
- init_MUTEX(&socket->skt_sem);
+ mutex_init(&socket->skt_mutex);
spin_lock_init(&socket->thread_lock);
ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
@@ -406,8 +405,6 @@ static void socket_shutdown(struct pcmcia_socket *s)
cb_free(s);
#endif
s->functions = 0;
- kfree(s->config);
- s->config = NULL;
s->ops->get_status(s, &status);
if (status & SS_POWERON) {
@@ -664,7 +661,7 @@ static int pccardd(void *__skt)
spin_unlock_irqrestore(&skt->thread_lock, flags);
if (events) {
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
if (events & SS_DETECT)
socket_detect_change(skt);
if (events & SS_BATDEAD)
@@ -673,7 +670,7 @@ static int pccardd(void *__skt)
send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
if (events & SS_READY)
send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
continue;
}
@@ -717,8 +714,8 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
{
int ret = 0;
- /* s->skt_sem also protects s->callback */
- down(&s->skt_sem);
+ /* s->skt_mutex also protects s->callback */
+ mutex_lock(&s->skt_mutex);
if (c) {
/* registration */
@@ -734,7 +731,7 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
} else
s->callback = NULL;
err:
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
return ret;
}
@@ -752,7 +749,7 @@ int pccard_reset_card(struct pcmcia_socket *skt)
cs_dbg(skt, 1, "resetting socket\n");
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
do {
if (!(skt->state & SOCKET_PRESENT)) {
ret = CS_NO_CARD;
@@ -781,7 +778,7 @@ int pccard_reset_card(struct pcmcia_socket *skt)
ret = CS_SUCCESS;
} while (0);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
return ret;
} /* reset_card */
@@ -797,7 +794,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
cs_dbg(skt, 1, "suspending socket\n");
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
do {
if (!(skt->state & SOCKET_PRESENT)) {
ret = CS_NO_CARD;
@@ -814,7 +811,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
}
ret = socket_suspend(skt);
} while (0);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
return ret;
} /* suspend_card */
@@ -827,7 +824,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
cs_dbg(skt, 1, "waking up socket\n");
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
do {
if (!(skt->state & SOCKET_PRESENT)) {
ret = CS_NO_CARD;
@@ -841,7 +838,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
if (!ret && skt->callback)
skt->callback->resume(skt);
} while (0);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
return ret;
} /* resume_card */
@@ -855,7 +852,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
cs_dbg(skt, 1, "user eject request\n");
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
do {
if (!(skt->state & SOCKET_PRESENT)) {
ret = -ENODEV;
@@ -871,7 +868,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
socket_remove(skt);
ret = 0;
} while (0);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
return ret;
} /* eject_card */
@@ -884,7 +881,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
cs_dbg(skt, 1, "user insert request\n");
- down(&skt->skt_sem);
+ mutex_lock(&skt->skt_mutex);
do {
if (skt->state & SOCKET_PRESENT) {
ret = -EBUSY;
@@ -896,7 +893,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
}
ret = 0;
} while (0);
- up(&skt->skt_sem);
+ mutex_unlock(&skt->skt_mutex);
return ret;
} /* insert_card */
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 7b37eba35bf1..d6164cd583fd 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -15,7 +15,7 @@
#ifndef _LINUX_CS_INTERNAL_H
#define _LINUX_CS_INTERNAL_H
-#include <linux/config.h>
+#include <linux/kref.h>
/* Flags in client state */
#define CLIENT_CONFIG_LOCKED 0x0001
@@ -23,7 +23,7 @@
#define CLIENT_IO_REQ 0x0004
#define CLIENT_UNBOUND 0x0008
#define CLIENT_STALE 0x0010
-#define CLIENT_WIN_REQ(i) (0x20<<(i))
+#define CLIENT_WIN_REQ(i) (0x1<<(i))
#define CLIENT_CARDBUS 0x8000
#define REGION_MAGIC 0xE3C9
@@ -31,7 +31,7 @@ typedef struct region_t {
u_short region_magic;
u_short state;
dev_info_t dev_info;
- client_handle_t mtd;
+ struct pcmcia_device *mtd;
u_int MediaID;
region_info_t info;
} region_t;
@@ -40,12 +40,12 @@ typedef struct region_t {
/* Each card function gets one of these guys */
typedef struct config_t {
+ struct kref ref;
u_int state;
u_int Attributes;
u_int IntType;
u_int ConfigBase;
u_char Status, Pin, Copy, Option, ExtStatus;
- u_int Present;
u_int CardValues;
io_req_t io;
struct {
@@ -95,12 +95,6 @@ static inline void cs_socket_put(struct pcmcia_socket *skt)
}
}
-#define CHECK_SOCKET(s) \
- (((s) >= sockets) || (socket_table[s]->ops == NULL))
-
-#define SOCKET(h) (h->socket)
-#define CONFIG(h) (&SOCKET(h)->config[(h)->func])
-
/* In cardbus.c */
int cb_alloc(struct pcmcia_socket *s);
void cb_free(struct pcmcia_socket *s);
@@ -133,10 +127,9 @@ extern struct class_interface pccard_sysfs_interface;
extern struct rw_semaphore pcmcia_socket_list_rwsem;
extern struct list_head pcmcia_socket_list;
int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req);
-int pccard_get_configuration_info(struct pcmcia_socket *s, unsigned int function, config_info_t *config);
+int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config);
int pccard_reset_card(struct pcmcia_socket *skt);
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status);
-int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg);
+int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status);
struct pcmcia_callback{
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index bb96ce1db08c..ae10d1eed65e 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -10,10 +10,9 @@
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* (C) 1999 David A. Hinds
- * (C) 2003 - 2005 Dominik Brodowski
+ * (C) 2003 - 2006 Dominik Brodowski
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -23,6 +22,7 @@
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
+#include <linux/kref.h>
#define IN_CARD_SERVICES
#include <pcmcia/cs_types.h>
@@ -343,12 +343,19 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev)
put_device(&p_dev->dev);
}
+static void pcmcia_release_function(struct kref *ref)
+{
+ struct config_t *c = container_of(ref, struct config_t, ref);
+ kfree(c);
+}
+
static void pcmcia_release_dev(struct device *dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
ds_dbg(1, "releasing dev %p\n", p_dev);
pcmcia_put_socket(p_dev->socket);
kfree(p_dev->devname);
+ kref_put(&p_dev->function_config->ref, pcmcia_release_function);
kfree(p_dev);
}
@@ -377,29 +384,12 @@ static int pcmcia_device_probe(struct device * dev)
p_drv = to_pcmcia_drv(dev->driver);
s = p_dev->socket;
- if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) {
+ if ((!p_drv->probe) || (!p_dev->function_config) ||
+ (!try_module_get(p_drv->owner))) {
ret = -EINVAL;
goto put_dev;
}
- 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);
if (ret)
goto put_module;
@@ -425,15 +415,61 @@ static int pcmcia_device_probe(struct device * dev)
}
+/*
+ * Removes a PCMCIA card from the device tree and socket list.
+ */
+static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
+{
+ struct pcmcia_device *p_dev;
+ struct pcmcia_device *tmp;
+ unsigned long flags;
+
+ ds_dbg(2, "unbind_request(%d)\n", s->sock);
+
+
+ if (!leftover)
+ s->device_count = 0;
+ else
+ s->device_count = 1;
+
+ /* unregister all pcmcia_devices registered with this socket, except leftover */
+ list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
+ if (p_dev == leftover)
+ continue;
+
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_del(&p_dev->socket_device_list);
+ p_dev->_removed=1;
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ device_unregister(&p_dev->dev);
+ }
+
+ return;
+}
+
+
static int pcmcia_device_remove(struct device * dev)
{
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
+ struct pcmcia_device_id *did;
int i;
- /* detach the "instance" */
p_dev = to_pcmcia_dev(dev);
p_drv = to_pcmcia_drv(dev->driver);
+
+ /* If we're removing the primary module driving a
+ * pseudo multi-function card, we need to unbind
+ * all devices
+ */
+ did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
+ if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
+ (p_dev->socket->device_count != 0) &&
+ (p_dev->device_no == 0))
+ pcmcia_card_remove(p_dev->socket, p_dev);
+
+ /* detach the "instance" */
if (!p_drv)
return 0;
@@ -441,17 +477,16 @@ static int pcmcia_device_remove(struct device * dev)
p_drv->remove(p_dev);
/* check for proper unloading */
- if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+ if (p_dev->_irq || p_dev->_io || p_dev->_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))
+ if (p_dev->_win & 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);
@@ -460,37 +495,6 @@ static int pcmcia_device_remove(struct device * dev)
/*
- * 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
*/
static int pcmcia_device_query(struct pcmcia_device *p_dev)
@@ -546,7 +550,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
tmp = vers1->str + vers1->ofs[i];
length = strlen(tmp) + 1;
- if ((length < 3) || (length > 255))
+ if ((length < 2) || (length > 255))
continue;
p_dev->prod_id[i] = kmalloc(sizeof(char) * length,
@@ -571,11 +575,11 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
* won't work, this doesn't matter much at the moment: the driver core doesn't
* support it either.
*/
-static DECLARE_MUTEX(device_add_lock);
+static DEFINE_MUTEX(device_add_lock);
struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
{
- struct pcmcia_device *p_dev;
+ struct pcmcia_device *p_dev, *tmp_dev;
unsigned long flags;
int bus_id_len;
@@ -583,7 +587,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
if (!s)
return NULL;
- down(&device_add_lock);
+ mutex_lock(&device_add_lock);
/* max of 2 devices per card */
if (s->device_count == 2)
@@ -596,6 +600,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
p_dev->socket = s;
p_dev->device_no = (s->device_count++);
p_dev->func = function;
+ if (s->functions <= function)
+ s->functions = function + 1;
p_dev->dev.bus = &pcmcia_bus_type;
p_dev->dev.parent = s->dev.dev;
@@ -608,36 +614,55 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
/* compat */
- p_dev->state = CLIENT_UNBOUND;
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+
+ /*
+ * p_dev->function_config must be the same for all card functions.
+ * Note that this is serialized by the device_add_lock, so that
+ * only one such struct will be created.
+ */
+ list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
+ if (p_dev->func == tmp_dev->func) {
+ p_dev->function_config = tmp_dev->function_config;
+ kref_get(&p_dev->function_config->ref);
+ }
/* Add to the list in pcmcia_bus_socket */
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ if (!p_dev->function_config) {
+ p_dev->function_config = kzalloc(sizeof(struct config_t),
+ GFP_KERNEL);
+ if (!p_dev->function_config)
+ goto err_unreg;
+ kref_init(&p_dev->function_config->ref);
+ }
+
printk(KERN_NOTICE "pcmcia: registering new device %s\n",
p_dev->devname);
pcmcia_device_query(p_dev);
- if (device_register(&p_dev->dev)) {
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_del(&p_dev->socket_device_list);
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
- goto err_free;
- }
+ if (device_register(&p_dev->dev))
+ goto err_unreg;
- up(&device_add_lock);
+ mutex_unlock(&device_add_lock);
return p_dev;
+ err_unreg:
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_del(&p_dev->socket_device_list);
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
err_free:
kfree(p_dev->devname);
kfree(p_dev);
s->device_count--;
err_put:
- up(&device_add_lock);
+ mutex_unlock(&device_add_lock);
pcmcia_put_socket(s);
return NULL;
@@ -696,7 +721,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
int no_devices=0;
unsigned long flags;
- /* must be called with skt_sem held */
+ /* must be called with skt_mutex held */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
if (list_empty(&skt->devices_list))
no_devices=1;
@@ -819,9 +844,11 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
struct pcmcia_device_id *did = p_drv->id_table;
+#ifdef CONFIG_PCMCIA_IOCTL
/* matching by cardmgr */
if (p_dev->cardmgr == p_drv)
return 1;
+#endif
while (did && did->match_flags) {
if (pcmcia_devmatch(p_dev, did))
@@ -927,7 +954,7 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->dev.power.power_state.event != PM_EVENT_ON)
+ if (p_dev->suspended)
return sprintf(buf, "off\n");
else
return sprintf(buf, "on\n");
@@ -942,11 +969,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
if (!count)
return -EINVAL;
- if ((p_dev->dev.power.power_state.event == PM_EVENT_ON) &&
- (!strncmp(buf, "off", 3)))
+ if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
- else if ((p_dev->dev.power.power_state.event != PM_EVENT_ON) &&
- (!strncmp(buf, "on", 2)))
+ else if (p_dev->suspended && !strncmp(buf, "on", 2))
dpm_runtime_resume(dev);
return ret ? ret : count;
@@ -982,9 +1007,9 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
if (!count)
return -EINVAL;
- down(&p_dev->socket->skt_sem);
+ mutex_lock(&p_dev->socket->skt_mutex);
p_dev->allow_func_id_match = 1;
- up(&p_dev->socket->skt_sem);
+ mutex_unlock(&p_dev->socket->skt_mutex);
bus_rescan_devices(&pcmcia_bus_type);
@@ -1012,14 +1037,27 @@ 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;
+ int ret = 0;
if (dev->driver)
p_drv = to_pcmcia_drv(dev->driver);
- if (p_drv && p_drv->suspend)
- return p_drv->suspend(p_dev);
+ if (!p_drv)
+ goto out;
- return 0;
+ if (p_drv->suspend) {
+ ret = p_drv->suspend(p_dev);
+ if (ret)
+ goto out;
+ }
+
+ if (p_dev->device_no == p_dev->func)
+ pcmcia_release_configuration(p_dev);
+
+ out:
+ if (!ret)
+ p_dev->suspended = 1;
+ return ret;
}
@@ -1027,14 +1065,27 @@ static int pcmcia_dev_resume(struct device * dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
struct pcmcia_driver *p_drv = NULL;
+ int ret = 0;
if (dev->driver)
p_drv = to_pcmcia_drv(dev->driver);
- if (p_drv && p_drv->resume)
- return p_drv->resume(p_dev);
+ if (!p_drv)
+ goto out;
- return 0;
+ if (p_dev->device_no == p_dev->func) {
+ ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+ if (ret)
+ goto out;
+ }
+
+ if (p_drv->resume)
+ ret = p_drv->resume(p_dev);
+
+ out:
+ if (!ret)
+ p_dev->suspended = 0;
+ return ret;
}
@@ -1100,7 +1151,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
switch (event) {
case CS_EVENT_CARD_REMOVAL:
s->pcmcia_state.present = 0;
- pcmcia_card_remove(skt);
+ pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
break;
@@ -1128,6 +1179,32 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
} /* ds_event */
+struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev)
+{
+ struct pcmcia_device *p_dev;
+ struct pcmcia_device *ret = NULL;
+
+ p_dev = pcmcia_get_dev(_p_dev);
+ if (!p_dev)
+ return NULL;
+
+ if (!p_dev->socket->pcmcia_state.present)
+ goto out;
+
+ if (p_dev->_removed)
+ goto out;
+
+ if (p_dev->suspended)
+ goto out;
+
+ ret = p_dev;
+ out:
+ pcmcia_put_dev(p_dev);
+ return ret;
+}
+EXPORT_SYMBOL(pcmcia_dev_present);
+
+
static struct pcmcia_callback pcmcia_bus_callback = {
.owner = THIS_MODULE,
.event = ds_event,
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
index d359bd25a51c..3a2b25e6ed73 100644
--- a/drivers/pcmcia/ds_internal.h
+++ b/drivers/pcmcia/ds_internal.h
@@ -8,6 +8,8 @@ extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+
#ifdef CONFIG_PCMCIA_IOCTL
extern void __init pcmcia_setup_ioctl(void);
extern void __exit pcmcia_cleanup_ioctl(void);
@@ -15,7 +17,7 @@ extern void handle_event(struct pcmcia_socket *s, event_t event);
extern int handle_request(struct pcmcia_socket *s, event_t event);
#else
static inline void __init pcmcia_setup_ioctl(void) { return; }
-static inline void __init pcmcia_cleanup_ioctl(void) { return; }
+static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
#endif
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 7979c85df3dc..d5f03a338c6c 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 35a92d1e4945..bd0308e89815 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/string.h>
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c
deleted file mode 100644
index ebb161c4f819..000000000000
--- a/drivers/pcmcia/pcmcia_compat.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * PCMCIA 16-bit compatibility functions
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
- *
- * Copyright (C) 2004 Dominik Brodowski
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#define IN_CARD_SERVICES
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ss.h>
-
-#include "cs_internal.h"
-
-int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
- return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_first_tuple);
-
-int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
- return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_next_tuple);
-
-int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
- return pccard_get_tuple_data(p_dev->socket, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_tuple_data);
-
-int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse)
-{
- return pccard_parse_tuple(tuple, parse);
-}
-EXPORT_SYMBOL(pcmcia_parse_tuple);
-
-int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info)
-{
- return pccard_validate_cis(p_dev->socket, p_dev->func, info);
-}
-EXPORT_SYMBOL(pcmcia_validate_cis);
-
-
-int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req)
-{
- return pccard_reset_card(p_dev->socket);
-}
-EXPORT_SYMBOL(pcmcia_reset_card);
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 80969f7e7a0b..c53db7ceda5e 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -18,7 +18,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -70,10 +69,26 @@ extern int ds_pc_debug;
#define ds_dbg(lvl, fmt, arg...) do { } while (0)
#endif
+static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
+ unsigned int function)
+{
+ struct pcmcia_device *p_dev = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+ if (p_dev->func == function) {
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ return pcmcia_get_dev(p_dev);
+ }
+ }
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ return NULL;
+}
/* backwards-compatible accessing of driver --- by name! */
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
+static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
{
struct device_driver *drv;
struct pcmcia_driver *p_drv;
@@ -214,7 +229,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
* by userspace before, we need to
* return the "instance". */
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- bind_info->instance = p_dev->instance;
+ bind_info->instance = p_dev;
ret = -EBUSY;
goto err_put_module;
} else {
@@ -253,9 +268,9 @@ rescan:
/*
* Prevent this racing with a card insertion.
*/
- down(&s->skt_sem);
+ mutex_lock(&s->skt_mutex);
bus_rescan_devices(&pcmcia_bus_type);
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
/* check whether the driver indeed matched. I don't care if this
* is racy or not, because it can only happen on cardmgr access
@@ -289,6 +304,7 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
{
dev_node_t *node;
struct pcmcia_device *p_dev;
+ struct pcmcia_driver *p_drv;
unsigned long flags;
int ret = 0;
@@ -343,16 +359,16 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
found:
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- if ((!p_dev->instance) ||
- (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+ p_drv = to_pcmcia_drv(p_dev->dev.driver);
+ if (p_drv && !p_dev->_locked) {
ret = -EAGAIN;
goto err_put;
}
if (first)
- node = p_dev->instance->dev;
+ node = p_dev->dev_node;
else
- for (node = p_dev->instance->dev; node; node = node->next)
+ for (node = p_dev->dev_node; node; node = node->next)
if (node == bind_info->next)
break;
if (!node) {
@@ -583,14 +599,16 @@ static int ds_ioctl(struct inode * inode, struct file * file,
if (buf->config.Function &&
(buf->config.Function >= s->functions))
ret = CS_BAD_ARGS;
- else
- ret = pccard_get_configuration_info(s,
- buf->config.Function, &buf->config);
+ else {
+ struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
+ ret = pccard_get_configuration_info(s, p_dev, &buf->config);
+ pcmcia_put_dev(p_dev);
+ }
break;
case DS_GET_FIRST_TUPLE:
- down(&s->skt_sem);
+ mutex_lock(&s->skt_mutex);
pcmcia_validate_mem(s);
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
break;
case DS_GET_NEXT_TUPLE:
@@ -609,16 +627,19 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = pccard_reset_card(s);
break;
case DS_GET_STATUS:
- if (buf->status.Function &&
- (buf->status.Function >= s->functions))
- ret = CS_BAD_ARGS;
- else
- ret = pccard_get_status(s, buf->status.Function, &buf->status);
- break;
+ if (buf->status.Function &&
+ (buf->status.Function >= s->functions))
+ ret = CS_BAD_ARGS;
+ else {
+ struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
+ ret = pccard_get_status(s, p_dev, &buf->status);
+ pcmcia_put_dev(p_dev);
+ }
+ break;
case DS_VALIDATE_CIS:
- down(&s->skt_sem);
+ mutex_lock(&s->skt_mutex);
pcmcia_validate_mem(s);
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
break;
case DS_SUSPEND_CARD:
@@ -638,12 +659,16 @@ static int ds_ioctl(struct inode * inode, struct file * file,
err = -EPERM;
goto free_out;
}
- if (buf->conf_reg.Function &&
- (buf->conf_reg.Function >= s->functions))
- ret = CS_BAD_ARGS;
- else
- ret = pccard_access_configuration_register(s,
- buf->conf_reg.Function, &buf->conf_reg);
+
+ ret = CS_BAD_ARGS;
+
+ if (!(buf->conf_reg.Function &&
+ (buf->conf_reg.Function >= s->functions))) {
+ struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
+ if (p_dev)
+ ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
+ pcmcia_put_dev(p_dev);
+ }
break;
case DS_GET_FIRST_REGION:
case DS_GET_NEXT_REGION:
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 89022ad5b520..45063b4e5b78 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
@@ -89,7 +88,7 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
}
if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
*base = s->io_offset | (*base & 0x0fff);
- s->io[0].Attributes = attr;
+ s->io[0].res->flags = (s->io[0].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
return 0;
}
/* Check for an already-allocated window that must conflict with
@@ -97,38 +96,36 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
* potential conflicts, just the most obvious ones.
*/
for (i = 0; i < MAX_IO_WIN; i++)
- if ((s->io[i].NumPorts != 0) &&
- ((s->io[i].BasePort & (align-1)) == *base))
+ if ((s->io[i].res) &&
+ ((s->io[i].res->start & (align-1)) == *base))
return 1;
for (i = 0; i < MAX_IO_WIN; i++) {
- if (s->io[i].NumPorts == 0) {
+ if (!s->io[i].res) {
s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
if (s->io[i].res) {
- s->io[i].Attributes = attr;
- s->io[i].BasePort = *base = s->io[i].res->start;
- s->io[i].NumPorts = s->io[i].InUse = num;
+ *base = s->io[i].res->start;
+ s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
+ s->io[i].InUse = num;
break;
} else
return 1;
- } else if (s->io[i].Attributes != attr)
+ } else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS))
continue;
/* Try to extend top of window */
- try = s->io[i].BasePort + s->io[i].NumPorts;
+ try = s->io[i].res->end + 1;
if ((*base == 0) || (*base == try))
if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
s->io[i].res->end + num, s) == 0) {
*base = try;
- s->io[i].NumPorts += num;
s->io[i].InUse += num;
break;
}
/* Try to extend bottom of window */
- try = s->io[i].BasePort - num;
+ try = s->io[i].res->start - num;
if ((*base == 0) || (*base == try))
if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
s->io[i].res->end, s) == 0) {
- s->io[i].BasePort = *base = try;
- s->io[i].NumPorts += num;
+ *base = try;
s->io[i].InUse += num;
break;
}
@@ -143,12 +140,13 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
int i;
for (i = 0; i < MAX_IO_WIN; i++) {
- if ((s->io[i].BasePort <= base) &&
- (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+ if (!s->io[i].res)
+ continue;
+ if ((s->io[i].res->start <= base) &&
+ (s->io[i].res->end >= base+num-1)) {
s->io[i].InUse -= num;
/* Free the window if no one else is using it */
if (s->io[i].InUse == 0) {
- s->io[i].NumPorts = 0;
release_resource(s->io[i].res);
kfree(s->io[i].res);
s->io[i].res = NULL;
@@ -165,21 +163,19 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
* this and the tuple reading services.
*/
-int pccard_access_configuration_register(struct pcmcia_socket *s,
- unsigned int function,
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
conf_reg_t *reg)
{
+ struct pcmcia_socket *s;
config_t *c;
int addr;
u_char val;
- if (!s || !s->config)
+ if (!p_dev || !p_dev->function_config)
return CS_NO_CARD;
- c = &s->config[function];
-
- if (c == NULL)
- return CS_NO_CARD;
+ s = p_dev->socket;
+ c = p_dev->function_config;
if (!(c->state & CONFIG_LOCKED))
return CS_CONFIGURATION_LOCKED;
@@ -200,20 +196,12 @@ int pccard_access_configuration_register(struct pcmcia_socket *s,
break;
}
return CS_SUCCESS;
-} /* pccard_access_configuration_register */
-
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
- conf_reg_t *reg)
-{
- return pccard_access_configuration_register(p_dev->socket,
- p_dev->func, reg);
-}
+} /* pcmcia_access_configuration_register */
EXPORT_SYMBOL(pcmcia_access_configuration_register);
-
int pccard_get_configuration_info(struct pcmcia_socket *s,
- unsigned int function,
+ struct pcmcia_device *p_dev,
config_info_t *config)
{
config_t *c;
@@ -221,7 +209,7 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- config->Function = function;
+ config->Function = p_dev->func;
#ifdef CONFIG_CARDBUS
if (s->state & SOCKET_CARDBUS) {
@@ -235,14 +223,14 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
config->AssignedIRQ = s->irq.AssignedIRQ;
if (config->AssignedIRQ)
config->Attributes |= CONF_ENABLE_IRQ;
- config->BasePort1 = s->io[0].BasePort;
- config->NumPorts1 = s->io[0].NumPorts;
+ config->BasePort1 = s->io[0].res->start;
+ config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
}
return CS_SUCCESS;
}
#endif
- c = (s->config != NULL) ? &s->config[function] : NULL;
+ c = (p_dev) ? p_dev->function_config : NULL;
if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
config->Attributes = 0;
@@ -271,7 +259,7 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
config_info_t *config)
{
- return pccard_get_configuration_info(p_dev->socket, p_dev->func,
+ return pccard_get_configuration_info(p_dev->socket, p_dev,
config);
}
EXPORT_SYMBOL(pcmcia_get_configuration_info);
@@ -317,7 +305,7 @@ EXPORT_SYMBOL(pcmcia_get_window);
* SocketState yet: I haven't seen any point for it.
*/
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
+int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev,
cs_status_t *status)
{
config_t *c;
@@ -334,11 +322,12 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- c = (s->config != NULL) ? &s->config[function] : NULL;
+ c = (p_dev) ? p_dev->function_config : NULL;
+
if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
(c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
u_char reg;
- if (c->Present & PRESENT_PIN_REPLACE) {
+ if (c->CardValues & PRESENT_PIN_REPLACE) {
pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
status->CardState |=
(reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
@@ -352,7 +341,7 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
/* No PRR? Then assume we're always ready */
status->CardState |= CS_EVENT_READY_CHANGE;
}
- if (c->Present & PRESENT_EXT_STATUS) {
+ if (c->CardValues & PRESENT_EXT_STATUS) {
pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
status->CardState |=
(reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
@@ -370,11 +359,9 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
return CS_SUCCESS;
} /* pccard_get_status */
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status)
{
- struct pcmcia_socket *s;
- s = SOCKET(handle);
- return pccard_get_status(s, handle->func, status);
+ return pccard_get_status(p_dev->socket, p_dev, status);
}
EXPORT_SYMBOL(pcmcia_get_status);
@@ -422,7 +409,8 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
config_t *c;
s = p_dev->socket;
- c = CONFIG(p_dev);
+ c = p_dev->function_config;
+
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
if (!(c->state & CONFIG_LOCKED))
@@ -454,6 +442,28 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
(mod->Attributes & CONF_VPP2_CHANGE_VALID))
return CS_BAD_VPP;
+ if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
+ pccard_io_map io_off = { 0, 0, 0, 0, 1 };
+ pccard_io_map io_on;
+ int i;
+
+ 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;
+
+ s->ops->set_io_map(s, &io_off);
+ mdelay(40);
+ s->ops->set_io_map(s, &io_on);
+ }
+ }
+
return CS_SUCCESS;
} /* modify_configuration */
EXPORT_SYMBOL(pcmcia_modify_configuration);
@@ -463,23 +473,23 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
{
pccard_io_map io = { 0, 0, 0, 0, 1 };
struct pcmcia_socket *s = p_dev->socket;
+ config_t *c = p_dev->function_config;
int i;
- if (!(p_dev->state & CLIENT_CONFIG_LOCKED))
- return CS_BAD_HANDLE;
- p_dev->state &= ~CLIENT_CONFIG_LOCKED;
-
- if (!(p_dev->state & CLIENT_STALE)) {
- config_t *c = CONFIG(p_dev);
+ if (p_dev->_locked) {
+ p_dev->_locked = 0;
if (--(s->lock_count) == 0) {
s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
s->socket.Vpp = 0;
s->socket.io_irq = 0;
s->ops->set_socket(s, &s->socket);
}
+ }
+ if (c->state & CONFIG_LOCKED) {
+ c->state &= ~CONFIG_LOCKED;
if (c->state & CONFIG_IO_REQ)
for (i = 0; i < MAX_IO_WIN; i++) {
- if (s->io[i].NumPorts == 0)
+ if (!s->io[i].res)
continue;
s->io[i].Config--;
if (s->io[i].Config != 0)
@@ -487,12 +497,10 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
io.map = i;
s->ops->set_io_map(s, &io);
}
- c->state &= ~CONFIG_LOCKED;
}
return CS_SUCCESS;
} /* pcmcia_release_configuration */
-EXPORT_SYMBOL(pcmcia_release_configuration);
/** pcmcia_release_io
@@ -503,25 +511,23 @@ EXPORT_SYMBOL(pcmcia_release_configuration);
* don't bother checking the port ranges against the current socket
* values.
*/
-int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
+ config_t *c = p_dev->function_config;
- if (!(p_dev->state & CLIENT_IO_REQ))
+ if (!p_dev->_io )
return CS_BAD_HANDLE;
- p_dev->state &= ~CLIENT_IO_REQ;
-
- if (!(p_dev->state & CLIENT_STALE)) {
- config_t *c = CONFIG(p_dev);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if ((c->io.BasePort1 != req->BasePort1) ||
- (c->io.NumPorts1 != req->NumPorts1) ||
- (c->io.BasePort2 != req->BasePort2) ||
- (c->io.NumPorts2 != req->NumPorts2))
- return CS_BAD_ARGS;
- c->state &= ~CONFIG_IO_REQ;
- }
+
+ p_dev->_io = 0;
+
+ if ((c->io.BasePort1 != req->BasePort1) ||
+ (c->io.NumPorts1 != req->NumPorts1) ||
+ (c->io.BasePort2 != req->BasePort2) ||
+ (c->io.NumPorts2 != req->NumPorts2))
+ return CS_BAD_ARGS;
+
+ c->state &= ~CONFIG_IO_REQ;
release_io_space(s, req->BasePort1, req->NumPorts1);
if (req->NumPorts2)
@@ -529,28 +535,26 @@ int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
return CS_SUCCESS;
} /* pcmcia_release_io */
-EXPORT_SYMBOL(pcmcia_release_io);
-int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
+static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
- if (!(p_dev->state & CLIENT_IRQ_REQ))
+ config_t *c= p_dev->function_config;
+
+ if (!p_dev->_irq)
return CS_BAD_HANDLE;
- p_dev->state &= ~CLIENT_IRQ_REQ;
-
- if (!(p_dev->state & CLIENT_STALE)) {
- config_t *c = CONFIG(p_dev);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if (c->irq.Attributes != req->Attributes)
- return CS_BAD_ATTRIBUTE;
- if (s->irq.AssignedIRQ != req->AssignedIRQ)
- return CS_BAD_IRQ;
- if (--s->irq.Config == 0) {
- c->state &= ~CONFIG_IRQ_REQ;
- s->irq.AssignedIRQ = 0;
- }
+ p_dev->_irq = 0;
+
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->irq.Attributes != req->Attributes)
+ return CS_BAD_ATTRIBUTE;
+ if (s->irq.AssignedIRQ != req->AssignedIRQ)
+ return CS_BAD_IRQ;
+ if (--s->irq.Config == 0) {
+ c->state &= ~CONFIG_IRQ_REQ;
+ s->irq.AssignedIRQ = 0;
}
if (req->Attributes & IRQ_HANDLE_PRESENT) {
@@ -563,7 +567,6 @@ int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
return CS_SUCCESS;
} /* pcmcia_release_irq */
-EXPORT_SYMBOL(pcmcia_release_irq);
int pcmcia_release_window(window_handle_t win)
@@ -573,7 +576,7 @@ int pcmcia_release_window(window_handle_t win)
if ((win == NULL) || (win->magic != WINDOW_MAGIC))
return CS_BAD_HANDLE;
s = win->sock;
- if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+ if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))
return CS_BAD_HANDLE;
/* Shut down memory window */
@@ -587,7 +590,7 @@ int pcmcia_release_window(window_handle_t win)
kfree(win->ctl.res);
win->ctl.res = NULL;
}
- win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+ win->handle->_win &= ~CLIENT_WIN_REQ(win->index);
win->magic = 0;
@@ -610,16 +613,12 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (req->IntType & INT_CARDBUS)
return CS_UNSUPPORTED_MODE;
- c = CONFIG(p_dev);
+ c = p_dev->function_config;
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
/* Do power control. We don't allow changes in Vcc. */
- if (s->socket.Vcc != req->Vcc)
- return CS_BAD_VCC;
- if (req->Vpp1 != req->Vpp2)
- return CS_BAD_VPP;
- s->socket.Vpp = req->Vpp1;
+ s->socket.Vpp = req->Vpp;
if (s->ops->set_socket(s, &s->socket))
return CS_BAD_VPP;
@@ -643,7 +642,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
/* Set up CIS configuration registers */
base = c->ConfigBase = req->ConfigBase;
- c->Present = c->CardValues = req->Present;
+ c->CardValues = req->Present;
if (req->Present & PRESENT_COPY) {
c->Copy = req->Copy;
pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
@@ -690,10 +689,10 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (c->state & CONFIG_IO_REQ) {
iomap.speed = io_speed;
for (i = 0; i < MAX_IO_WIN; i++)
- if (s->io[i].NumPorts != 0) {
+ if (s->io[i].res) {
iomap.map = i;
iomap.flags = MAP_ACTIVE;
- switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+ 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:
@@ -701,15 +700,15 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
default:
break;
}
- iomap.start = s->io[i].BasePort;
- iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+ 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->state |= CLIENT_CONFIG_LOCKED;
+ p_dev->_locked = 1;
return CS_SUCCESS;
} /* pcmcia_request_configuration */
EXPORT_SYMBOL(pcmcia_request_configuration);
@@ -730,7 +729,7 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
if (!req)
return CS_UNSUPPORTED_MODE;
- c = CONFIG(p_dev);
+ c = p_dev->function_config;
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if (c->state & CONFIG_IO_REQ)
@@ -755,7 +754,7 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
c->io = *req;
c->state |= CONFIG_IO_REQ;
- p_dev->state |= CLIENT_IO_REQ;
+ p_dev->_io = 1;
return CS_SUCCESS;
} /* pcmcia_request_io */
EXPORT_SYMBOL(pcmcia_request_io);
@@ -786,7 +785,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
- c = CONFIG(p_dev);
+ c = p_dev->function_config;
if (c->state & CONFIG_LOCKED)
return CS_CONFIGURATION_LOCKED;
if (c->state & CONFIG_IRQ_REQ)
@@ -851,7 +850,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
s->irq.Config++;
c->state |= CONFIG_IRQ_REQ;
- p_dev->state |= CLIENT_IRQ_REQ;
+ p_dev->_irq = 1;
#ifdef CONFIG_PCMCIA_PROBE
pcmcia_used_irq[irq]++;
@@ -911,7 +910,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
if (!win->ctl.res)
return CS_IN_USE;
}
- (*p_dev)->state |= CLIENT_WIN_REQ(w);
+ (*p_dev)->_win |= CLIENT_WIN_REQ(w);
/* Configure the socket controller */
win->ctl.map = w+1;
@@ -941,3 +940,14 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h
return CS_SUCCESS;
} /* pcmcia_request_window */
EXPORT_SYMBOL(pcmcia_request_window);
+
+void pcmcia_disable_device(struct pcmcia_device *p_dev) {
+ pcmcia_release_configuration(p_dev);
+ pcmcia_release_io(p_dev, &p_dev->io);
+ pcmcia_release_irq(p_dev, &p_dev->irq);
+ if (&p_dev->win)
+ pcmcia_release_window(p_dev->win);
+
+ p_dev->dev_node = NULL;
+}
+EXPORT_SYMBOL(pcmcia_disable_device);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index f2789afb22b2..16d1ea7b0a18 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 514609369836..81dfc2cac2b4 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -12,7 +12,6 @@
* (C) 1999 David A. Hinds
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -22,6 +21,8 @@
#include "cs_internal.h"
+#ifdef CONFIG_PCMCIA_IOCTL
+
#ifdef CONFIG_PCMCIA_PROBE
static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
@@ -98,6 +99,8 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
}
EXPORT_SYMBOL(pcmcia_adjust_resource_info);
+#endif
+
int pcmcia_validate_mem(struct pcmcia_socket *s)
{
if (s->resource_ops->validate_mem)
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 5301ac60358f..0f8b157c9717 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -12,7 +12,6 @@
* (C) 1999 David A. Hinds
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -61,7 +60,7 @@ struct socket_data {
unsigned int rsrc_mem_probe;
};
-static DECLARE_MUTEX(rsrc_sem);
+static DEFINE_MUTEX(rsrc_mutex);
#define MEM_PROBE_LOW (1 << 0)
#define MEM_PROBE_HIGH (1 << 1)
@@ -484,7 +483,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
/*
- * Locking note: Must be called with skt_sem held!
+ * Locking note: Must be called with skt_mutex held!
*/
static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
{
@@ -495,7 +494,7 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
if (!probe_mem)
return 0;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
if (s->features & SS_CAP_PAGE_REGS)
probe_mask = MEM_PROBE_HIGH;
@@ -507,7 +506,7 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
s_data->rsrc_mem_probe |= probe_mask;
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -585,7 +584,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
struct socket_data *s_data = s->resource_data;
int ret = -ENOMEM;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
unsigned long start = m->base;
unsigned long end = m->base + m->num - 1;
@@ -596,7 +595,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
ret = adjust_resource(res, r_start, r_end - r_start + 1);
break;
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -630,7 +629,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
data.offset = base & data.mask;
data.map = &s_data->io_db;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
#ifdef CONFIG_PCI
if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
@@ -639,7 +638,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
#endif
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
1, pcmcia_align, &data);
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
if (ret != 0) {
kfree(res);
@@ -672,7 +671,7 @@ static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
min = 0x100000UL + base;
}
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
#ifdef CONFIG_PCI
if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
@@ -682,7 +681,7 @@ static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
#endif
ret = allocate_resource(&iomem_resource, res, num, min,
max, 1, pcmcia_align, &data);
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
if (ret == 0 || low)
break;
low = 1;
@@ -705,7 +704,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
if (end < start)
return -EINVAL;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
switch (action) {
case ADD_MANAGED_RESOURCE:
ret = add_interval(&data->mem_db, start, size);
@@ -723,7 +722,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
default:
ret = -EINVAL;
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -741,7 +740,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
if (end > IO_SPACE_LIMIT)
return -EINVAL;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
switch (action) {
case ADD_MANAGED_RESOURCE:
if (add_interval(&data->io_db, start, size) != 0) {
@@ -760,7 +759,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
ret = -EINVAL;
break;
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return ret;
}
@@ -867,7 +866,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
struct socket_data *data = s->resource_data;
struct resource_map *p, *q;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
for (p = data->mem_db.next; p != &data->mem_db; p = q) {
q = p->next;
kfree(p);
@@ -876,7 +875,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
q = p->next;
kfree(p);
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
}
@@ -901,7 +900,7 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
struct resource_map *p;
ssize_t ret = 0;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
data = s->resource_data;
for (p = data->io_db.next; p != &data->io_db; p = p->next) {
@@ -913,7 +912,7 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
((unsigned long) p->base + p->num - 1));
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return (ret);
}
@@ -953,7 +952,7 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
struct resource_map *p;
ssize_t ret = 0;
- down(&rsrc_sem);
+ mutex_lock(&rsrc_mutex);
data = s->resource_data;
for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
@@ -965,7 +964,7 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
((unsigned long) p->base + p->num - 1));
}
- up(&rsrc_sem);
+ mutex_unlock(&rsrc_mutex);
return (ret);
}
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 2b3c2895b43d..eb89928f2338 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -5,7 +5,6 @@
* Based off the Assabet.
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 5ab1cdef7c48..c5d7476da471 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -12,7 +12,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
@@ -25,6 +24,7 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -183,7 +183,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
s->resource_setup_done = 1;
spin_unlock_irqrestore(&s->lock, flags);
- down(&s->skt_sem);
+ mutex_lock(&s->skt_mutex);
if ((s->callback) &&
(s->state & SOCKET_PRESENT) &&
!(s->state & SOCKET_CARDBUS)) {
@@ -192,7 +192,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
module_put(s->callback->owner);
}
}
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
return count;
}
@@ -322,7 +322,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
kfree(cis);
if (!ret) {
- down(&s->skt_sem);
+ mutex_lock(&s->skt_mutex);
if ((s->callback) && (s->state & SOCKET_PRESENT) &&
!(s->state & SOCKET_CARDBUS)) {
if (try_module_get(s->callback->owner)) {
@@ -330,7 +330,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
module_put(s->callback->owner);
}
}
- up(&s->skt_sem);
+ mutex_unlock(&s->skt_mutex);
}
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index d5b4ff74462e..7a3d1b8e16b9 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -30,7 +30,6 @@
#ifndef _LINUX_TI113X_H
#define _LINUX_TI113X_H
-#include <linux/config.h>
/* Register definitions for TI 113X PCI-to-CardBus bridges */