Merge remote branch 'origin' into secretlab/next-devicetree

Merging in current state of Linus' tree to deal with merge conflicts and
build failures in vio.c after merge.

Conflicts:
	drivers/i2c/busses/i2c-cpm.c
	drivers/i2c/busses/i2c-mpc.c
	drivers/net/gianfar.c

Also fixed up one line in arch/powerpc/kernel/vio.c to use the
correct node pointer.

Signed-off-by: Grant Likely <[email protected]>
This commit is contained in:
Grant Likely 2010-05-22 00:36:56 -06:00
commit cf9b59e9d3
6983 changed files with 473508 additions and 213620 deletions

View file

@ -49,26 +49,6 @@ config PCMCIA_LOAD_CIS
If unsure, say Y.
config PCMCIA_IOCTL
bool "PCMCIA control ioctl (obsolete)"
depends on PCMCIA && ARM && !SMP && !PREEMPT
default y
help
If you say Y here, the deprecated ioctl interface to the PCMCIA
subsystem will be built. It is needed by the deprecated pcmcia-cs
tools (cardmgr, cardctl) to function properly.
You should use the new pcmciautils package instead (see
<file:Documentation/Changes> for location and details).
This config option will most likely be removed from kernel 2.6.35,
the associated code from kernel 2.6.36.
As the PCMCIA ioctl is not locking safe, it depends on !SMP and
!PREEMPT.
If unsure, say N.
config CARDBUS
bool "32-bit CardBus support"
depends on PCI
@ -234,7 +214,8 @@ config PCMCIA_PXA2XX
depends on ARM && ARCH_PXA && PCMCIA
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2)
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
|| MACH_VPAC270)
select PCMCIA_SOC_COMMON
help
Say Y here to include support for the PXA2xx PCMCIA controller
@ -317,7 +298,7 @@ config ELECTRA_CF
PA Semi Electra eval board.
config PCCARD_NONSTATIC
tristate
bool
config PCCARD_IODYN
bool

View file

@ -2,15 +2,18 @@
# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
#
pcmcia_core-y += cs.o rsrc_mgr.o socket_sysfs.o
pcmcia_core-y += cs.o socket_sysfs.o
pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o
obj-$(CONFIG_PCCARD) += pcmcia_core.o
pcmcia-y += ds.o pcmcia_resource.o cistpl.o
pcmcia-y += ds.o pcmcia_resource.o cistpl.o pcmcia_cis.o
pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o
obj-$(CONFIG_PCMCIA) += pcmcia.o
obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o
pcmcia_rsrc-y += rsrc_mgr.o
pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o
pcmcia_rsrc-$(CONFIG_PCCARD_IODYN) += rsrc_iodyn.o
obj-$(CONFIG_PCCARD) += pcmcia_rsrc.o
# socket drivers
@ -66,6 +69,7 @@ pxa2xx-obj-$(CONFIG_MACH_PALMTC) += pxa2xx_palmtc.o
pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)

View file

@ -113,7 +113,7 @@ static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
if (bfin_cf_present(cf->cd_pfx)) {
*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
s->irq.AssignedIRQ = 0;
s->pcmcia_irq = 0;
s->pci_irq = cf->irq;
} else

View file

@ -94,7 +94,6 @@ int __ref cb_alloc(struct pcmcia_socket *s)
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
s->irq.AssignedIRQ = s->pci_irq;
return 0;
}

View file

@ -129,6 +129,8 @@ static void __iomem *set_cis_map(struct pcmcia_socket *s,
/**
* pcmcia_read_cis_mem() - low-level function to read CIS memory
*
* must be called with ops_mutex held
*/
int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
@ -138,7 +140,6 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
mutex_lock(&s->ops_mutex);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
locations in common memory */
@ -153,7 +154,6 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
memset(ptr, 0xff, len);
mutex_unlock(&s->ops_mutex);
return -1;
}
@ -184,7 +184,6 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
memset(ptr, 0xff, len);
mutex_unlock(&s->ops_mutex);
return -1;
}
end = sys + s->map_size;
@ -198,7 +197,6 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
addr = 0;
}
}
mutex_unlock(&s->ops_mutex);
dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
*(u_char *)(ptr+0), *(u_char *)(ptr+1),
*(u_char *)(ptr+2), *(u_char *)(ptr+3));
@ -209,7 +207,8 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
/**
* pcmcia_write_cis_mem() - low-level function to write CIS memory
*
* Probably only useful for writing one-byte registers.
* Probably only useful for writing one-byte registers. Must be called
* with ops_mutex held.
*/
void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
@ -220,7 +219,6 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
dev_dbg(&s->dev,
"pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
mutex_lock(&s->ops_mutex);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
locations in common memory */
@ -234,7 +232,6 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
((cis_width) ? MAP_16BIT : 0));
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
mutex_unlock(&s->ops_mutex);
return; /* FIXME: Error */
}
@ -260,7 +257,6 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
sys = set_cis_map(s, card_offset, flags);
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
mutex_unlock(&s->ops_mutex);
return; /* FIXME: error */
}
@ -275,7 +271,6 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
addr = 0;
}
}
mutex_unlock(&s->ops_mutex);
}
@ -314,7 +309,6 @@ static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
return 0;
}
}
mutex_unlock(&s->ops_mutex);
ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
@ -326,11 +320,11 @@ static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
cis->len = len;
cis->attr = attr;
memcpy(cis->cache, ptr, len);
mutex_lock(&s->ops_mutex);
list_add(&cis->node, &s->cis_cache);
mutex_unlock(&s->ops_mutex);
}
}
mutex_unlock(&s->ops_mutex);
return ret;
}
@ -386,6 +380,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
"no memory for verifying CIS\n");
return -ENOMEM;
}
mutex_lock(&s->ops_mutex);
list_for_each_entry(cis, &s->cis_cache, node) {
int len = cis->len;
@ -395,10 +390,12 @@ int verify_cis_cache(struct pcmcia_socket *s)
ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
if (ret || memcmp(buf, cis->cache, len) != 0) {
kfree(buf);
mutex_unlock(&s->ops_mutex);
return -1;
}
}
kfree(buf);
mutex_unlock(&s->ops_mutex);
return 0;
}
@ -1361,106 +1358,6 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
EXPORT_SYMBOL(pcmcia_parse_tuple);
/**
* pccard_read_tuple() - internal CIS tuple access
* @s: the struct pcmcia_socket where the card is inserted
* @function: the device function we loop for
* @code: which CIS code shall we look for?
* @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
*
* pccard_read_tuple() reads out one tuple and attempts to parse it
*/
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, void *parse)
{
tuple_t tuple;
cisdata_t *buf;
int ret;
buf = kmalloc(256, GFP_KERNEL);
if (buf == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
return -ENOMEM;
}
tuple.DesiredTuple = code;
tuple.Attributes = 0;
if (function == BIND_FN_ALL)
tuple.Attributes = TUPLE_RETURN_COMMON;
ret = pccard_get_first_tuple(s, function, &tuple);
if (ret != 0)
goto done;
tuple.TupleData = buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
ret = pccard_get_tuple_data(s, &tuple);
if (ret != 0)
goto done;
ret = pcmcia_parse_tuple(&tuple, parse);
done:
kfree(buf);
return ret;
}
/**
* pccard_loop_tuple() - loop over tuples in the CIS
* @s: the struct pcmcia_socket where the card is inserted
* @function: the device function we loop for
* @code: which CIS code shall we look for?
* @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
* @priv_data: private data to be passed to the loop_tuple function.
* @loop_tuple: function to call for each CIS entry of type @function. IT
* gets passed the raw tuple, the paresed tuple (if @parse is
* set) and @priv_data.
*
* pccard_loop_tuple() loops over all CIS entries of type @function, and
* calls the @loop_tuple function for each entry. If the call to @loop_tuple
* returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
*/
int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, cisparse_t *parse, void *priv_data,
int (*loop_tuple) (tuple_t *tuple,
cisparse_t *parse,
void *priv_data))
{
tuple_t tuple;
cisdata_t *buf;
int ret;
buf = kzalloc(256, GFP_KERNEL);
if (buf == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
return -ENOMEM;
}
tuple.TupleData = buf;
tuple.TupleDataMax = 255;
tuple.TupleOffset = 0;
tuple.DesiredTuple = code;
tuple.Attributes = 0;
ret = pccard_get_first_tuple(s, function, &tuple);
while (!ret) {
if (pccard_get_tuple_data(s, &tuple))
goto next_entry;
if (parse)
if (pcmcia_parse_tuple(&tuple, parse))
goto next_entry;
ret = loop_tuple(&tuple, parse, priv_data);
if (!ret)
break;
next_entry:
ret = pccard_get_next_tuple(s, function, &tuple);
}
kfree(buf);
return ret;
}
/**
* pccard_validate_cis() - check whether card has a sensible CIS
* @s: the struct pcmcia_socket we are to check
@ -1484,6 +1381,11 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
if (!s)
return -EINVAL;
if (s->functions) {
WARN_ON(1);
return -EINVAL;
}
/* We do not want to validate the CIS cache... */
mutex_lock(&s->ops_mutex);
destroy_cis_cache(s);
@ -1629,7 +1531,7 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
}
static ssize_t pccard_show_cis(struct kobject *kobj,
static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
@ -1639,7 +1541,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
count = 0;
else {
struct pcmcia_socket *s;
unsigned int chains;
unsigned int chains = 1;
if (off + count > size)
count = size - off;
@ -1648,7 +1550,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
if (pccard_validate_cis(s, &chains))
if (!s->functions && pccard_validate_cis(s, &chains))
return -EIO;
if (!chains)
return -ENODATA;
@ -1660,7 +1562,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
}
static ssize_t pccard_store_cis(struct kobject *kobj,
static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{

View file

@ -337,7 +337,6 @@ static void socket_shutdown(struct pcmcia_socket *s)
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;
kfree(s->fake_cis);
s->fake_cis = NULL;
@ -671,20 +670,22 @@ static int pccardd(void *__skt)
socket_remove(skt);
if (sysfs_events & PCMCIA_UEVENT_INSERT)
socket_insert(skt);
if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
!(skt->state & SOCKET_CARDBUS)) {
ret = socket_resume(skt);
if (!ret && skt->callback)
skt->callback->resume(skt);
}
if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
!(skt->state & SOCKET_CARDBUS)) {
if (skt->callback)
ret = skt->callback->suspend(skt);
else
ret = 0;
if (!ret)
if (!ret) {
socket_suspend(skt);
msleep(100);
}
}
if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
!(skt->state & SOCKET_CARDBUS)) {
ret = socket_resume(skt);
if (!ret && skt->callback)
skt->callback->resume(skt);
}
if ((sysfs_events & PCMCIA_UEVENT_REQUERY) &&
!(skt->state & SOCKET_CARDBUS)) {

View file

@ -52,13 +52,11 @@ struct cis_cache_entry {
struct pccard_resource_ops {
int (*validate_mem) (struct pcmcia_socket *s);
int (*adjust_io_region) (struct resource *res,
unsigned long r_start,
unsigned long r_end,
struct pcmcia_socket *s);
struct resource* (*find_io) (unsigned long base, int num,
unsigned long align,
struct pcmcia_socket *s);
int (*find_io) (struct pcmcia_socket *s,
unsigned int attr,
unsigned int *base,
unsigned int num,
unsigned int align);
struct resource* (*find_mem) (unsigned long base, unsigned long num,
unsigned long align, int low,
struct pcmcia_socket *s);
@ -88,6 +86,14 @@ struct pccard_resource_ops {
#define SOCKET_CARDBUS_CONFIG 0x10000
/*
* Stuff internal to module "pcmcia_rsrc":
*/
extern int static_init(struct pcmcia_socket *s);
extern struct resource *pcmcia_make_resource(unsigned long start,
unsigned long end,
int flags, const char *name);
/*
* Stuff internal to module "pcmcia_core":
*/
@ -149,6 +155,8 @@ extern struct resource *pcmcia_find_mem_region(u_long base,
int low,
struct pcmcia_socket *s);
void pcmcia_cleanup_irq(struct pcmcia_socket *s);
int pcmcia_setup_irq(struct pcmcia_device *p_dev);
/* cistpl.c */
extern struct bin_attribute pccard_cis_attr;

View file

@ -146,7 +146,6 @@ static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
{
int ret;
unsigned long flags;
if (sock->stschg_irq != -1) {
ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
@ -162,8 +161,6 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
* active one disabled.
*/
if (sock->board_type == BOARD_TYPE_DB1200) {
local_irq_save(flags);
ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
IRQF_DISABLED, "pcmcia_insert", sock);
if (ret)
@ -173,17 +170,14 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
IRQF_DISABLED, "pcmcia_eject", sock);
if (ret) {
free_irq(sock->insert_irq, sock);
local_irq_restore(flags);
goto out1;
}
/* disable the currently active one */
/* enable the currently silent one */
if (db1200_card_inserted(sock))
disable_irq_nosync(sock->insert_irq);
enable_irq(sock->eject_irq);
else
disable_irq_nosync(sock->eject_irq);
local_irq_restore(flags);
enable_irq(sock->insert_irq);
} else {
/* all other (older) Db1x00 boards use a GPIO to show
* card detection status: use both-edge triggers.

View file

@ -335,7 +335,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
p_dev->_removed = 1;
mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "unregistering device\n");
@ -372,8 +371,6 @@ static int pcmcia_device_remove(struct device *dev)
if (p_drv->remove)
p_drv->remove(p_dev);
p_dev->dev_node = NULL;
/* check for proper unloading */
if (p_dev->_irq || p_dev->_io || p_dev->_locked)
dev_printk(KERN_INFO, dev,
@ -480,15 +477,6 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
}
/* device_add_lock is needed to avoid double registration by cardmgr and kernel.
* Serializes pcmcia_device_add; will most likely be removed in future.
*
* While it has the caveat that adding new PCMCIA devices inside(!) device_register()
* won't work, this doesn't matter much at the moment: the driver core doesn't
* support it either.
*/
static DEFINE_MUTEX(device_add_lock);
struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
{
struct pcmcia_device *p_dev, *tmp_dev;
@ -498,8 +486,6 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
if (!s)
return NULL;
mutex_lock(&device_add_lock);
pr_debug("adding device to %d, function %d\n", s->sock, function);
p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
@ -539,8 +525,8 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
/*
* 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.
* Note that this is serialized by ops_mutex, 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) {
@ -553,28 +539,31 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
/* Add to the list in pcmcia_bus_socket */
list_add(&p_dev->socket_device_list, &s->devices_list);
mutex_unlock(&s->ops_mutex);
if (pcmcia_setup_irq(p_dev))
dev_warn(&p_dev->dev,
"IRQ setup failed -- device might not work\n");
if (!p_dev->function_config) {
dev_dbg(&p_dev->dev, "creating config_t\n");
p_dev->function_config = kzalloc(sizeof(struct config_t),
GFP_KERNEL);
if (!p_dev->function_config)
if (!p_dev->function_config) {
mutex_unlock(&s->ops_mutex);
goto err_unreg;
}
kref_init(&p_dev->function_config->ref);
}
mutex_unlock(&s->ops_mutex);
dev_printk(KERN_NOTICE, &p_dev->dev,
"pcmcia: registering new device %s\n",
p_dev->devname);
"pcmcia: registering new device %s (IRQ: %d)\n",
p_dev->devname, p_dev->irq);
pcmcia_device_query(p_dev);
if (device_register(&p_dev->dev))
goto err_unreg;
mutex_unlock(&device_add_lock);
return p_dev;
err_unreg:
@ -592,7 +581,6 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
kfree(p_dev->devname);
kfree(p_dev);
err_put:
mutex_unlock(&device_add_lock);
pcmcia_put_socket(s);
return NULL;
@ -654,14 +642,7 @@ static int pcmcia_requery_callback(struct device *dev, void * _data)
static void pcmcia_requery(struct pcmcia_socket *s)
{
int present, has_pfc;
mutex_lock(&s->ops_mutex);
present = s->pcmcia_state.present;
mutex_unlock(&s->ops_mutex);
if (!present)
return;
int has_pfc;
if (s->functions == 0) {
pcmcia_card_add(s);
@ -687,12 +668,10 @@ static void pcmcia_requery(struct pcmcia_socket *s)
new_funcs = mfc.nfn;
else
new_funcs = 1;
if (old_funcs > new_funcs) {
if (old_funcs != new_funcs) {
/* we need to re-start */
pcmcia_card_remove(s, NULL);
pcmcia_card_add(s);
} else if (new_funcs > old_funcs) {
s->functions = new_funcs;
pcmcia_device_add(s, 1);
}
}
@ -728,6 +707,8 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
struct pcmcia_socket *s = dev->socket;
const struct firmware *fw;
int ret = -ENOMEM;
cistpl_longlink_mfc_t mfc;
int old_funcs, new_funcs = 1;
if (!filename)
return -EINVAL;
@ -750,6 +731,14 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
goto release;
}
/* we need to re-start if the number of functions changed */
old_funcs = s->functions;
if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
&mfc))
new_funcs = mfc.nfn;
if (old_funcs != new_funcs)
ret = -EBUSY;
/* update information */
pcmcia_device_query(dev);
@ -820,11 +809,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
if (dev->device_no != did->device_no)
return 0;
dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
mutex_lock(&dev->socket->ops_mutex);
dev->socket->pcmcia_state.has_pfc = 1;
mutex_unlock(&dev->socket->ops_mutex);
if (dev->device_no != did->device_no)
return 0;
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
@ -835,7 +825,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
/* if this is a pseudo-multi-function device,
* we need explicit matches */
if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
if (dev->socket->pcmcia_state.has_pfc)
return 0;
if (dev->device_no)
return 0;
@ -858,10 +848,8 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
dev_dbg(&dev->dev, "device needs a fake CIS\n");
if (!dev->socket->fake_cis)
pcmcia_load_firmware(dev, did->cisfile);
if (!dev->socket->fake_cis)
return 0;
if (pcmcia_load_firmware(dev, did->cisfile))
return 0;
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
@ -1254,20 +1242,19 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
switch (event) {
case CS_EVENT_CARD_REMOVAL:
mutex_lock(&s->ops_mutex);
s->pcmcia_state.present = 0;
mutex_unlock(&s->ops_mutex);
atomic_set(&skt->present, 0);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
mutex_lock(&s->ops_mutex);
destroy_cis_cache(s);
pcmcia_cleanup_irq(s);
mutex_unlock(&s->ops_mutex);
break;
case CS_EVENT_CARD_INSERTION:
atomic_set(&skt->present, 1);
mutex_lock(&s->ops_mutex);
s->pcmcia_state.has_pfc = 0;
s->pcmcia_state.present = 1;
destroy_cis_cache(s); /* to be on the safe side... */
mutex_unlock(&s->ops_mutex);
pcmcia_card_add(skt);
@ -1286,6 +1273,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
destroy_cis_cache(skt);
kfree(skt->fake_cis);
skt->fake_cis = NULL;
s->functions = 0;
mutex_unlock(&s->ops_mutex);
/* now, add the new card */
ds_event(skt, CS_EVENT_CARD_INSERTION,
@ -1307,7 +1295,13 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
return 0;
} /* ds_event */
/*
* NOTE: This is racy. There's no guarantee the card will still be
* physically present, even if the call to this function returns
* non-NULL. Furthermore, the device driver most likely is unbound
* almost immediately, so the timeframe where pcmcia_dev_present
* returns NULL is probably really really small.
*/
struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
{
struct pcmcia_device *p_dev;
@ -1317,22 +1311,9 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
if (!p_dev)
return NULL;
mutex_lock(&p_dev->socket->ops_mutex);
if (!p_dev->socket->pcmcia_state.present)
goto out;
if (atomic_read(&p_dev->socket->present) != 0)
ret = p_dev;
if (p_dev->socket->pcmcia_state.dead)
goto out;
if (p_dev->_removed)
goto out;
if (p_dev->suspended)
goto out;
ret = p_dev;
out:
mutex_unlock(&p_dev->socket->ops_mutex);
pcmcia_put_dev(p_dev);
return ret;
}
@ -1382,6 +1363,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
return ret;
}
atomic_set(&socket->present, 0);
return 0;
}
@ -1393,10 +1376,6 @@ static void pcmcia_bus_remove_socket(struct device *dev,
if (!socket)
return;
mutex_lock(&socket->ops_mutex);
socket->pcmcia_state.dead = 1;
mutex_unlock(&socket->ops_mutex);
pccard_register_pcmcia(socket, NULL);
/* unregister any unbound devices */

View file

@ -117,7 +117,7 @@ static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp)
*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
cf = container_of(s, struct omap_cf_socket, socket);
s->irq.AssignedIRQ = 0;
s->pcmcia_irq = 0;
s->pci_irq = cf->irq;
} else
*sp = 0;

356
drivers/pcmcia/pcmcia_cis.c Normal file
View file

@ -0,0 +1,356 @@
/*
* PCMCIA high-level CIS access 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) 1999 David A. Hinds
* Copyright (C) 2004-2009 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/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/ds.h>
#include "cs_internal.h"
/**
* pccard_read_tuple() - internal CIS tuple access
* @s: the struct pcmcia_socket where the card is inserted
* @function: the device function we loop for
* @code: which CIS code shall we look for?
* @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
*
* pccard_read_tuple() reads out one tuple and attempts to parse it
*/
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, void *parse)
{
tuple_t tuple;
cisdata_t *buf;
int ret;
buf = kmalloc(256, GFP_KERNEL);
if (buf == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
return -ENOMEM;
}
tuple.DesiredTuple = code;
tuple.Attributes = 0;
if (function == BIND_FN_ALL)
tuple.Attributes = TUPLE_RETURN_COMMON;
ret = pccard_get_first_tuple(s, function, &tuple);
if (ret != 0)
goto done;
tuple.TupleData = buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
ret = pccard_get_tuple_data(s, &tuple);
if (ret != 0)
goto done;
ret = pcmcia_parse_tuple(&tuple, parse);
done:
kfree(buf);
return ret;
}
/**
* pccard_loop_tuple() - loop over tuples in the CIS
* @s: the struct pcmcia_socket where the card is inserted
* @function: the device function we loop for
* @code: which CIS code shall we look for?
* @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
* @priv_data: private data to be passed to the loop_tuple function.
* @loop_tuple: function to call for each CIS entry of type @function. IT
* gets passed the raw tuple, the paresed tuple (if @parse is
* set) and @priv_data.
*
* pccard_loop_tuple() loops over all CIS entries of type @function, and
* calls the @loop_tuple function for each entry. If the call to @loop_tuple
* returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
*/
int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, cisparse_t *parse, void *priv_data,
int (*loop_tuple) (tuple_t *tuple,
cisparse_t *parse,
void *priv_data))
{
tuple_t tuple;
cisdata_t *buf;
int ret;
buf = kzalloc(256, GFP_KERNEL);
if (buf == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
return -ENOMEM;
}
tuple.TupleData = buf;
tuple.TupleDataMax = 255;
tuple.TupleOffset = 0;
tuple.DesiredTuple = code;
tuple.Attributes = 0;
ret = pccard_get_first_tuple(s, function, &tuple);
while (!ret) {
if (pccard_get_tuple_data(s, &tuple))
goto next_entry;
if (parse)
if (pcmcia_parse_tuple(&tuple, parse))
goto next_entry;
ret = loop_tuple(&tuple, parse, priv_data);
if (!ret)
break;
next_entry:
ret = pccard_get_next_tuple(s, function, &tuple);
}
kfree(buf);
return ret;
}
struct pcmcia_cfg_mem {
struct pcmcia_device *p_dev;
void *priv_data;
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data);
cisparse_t parse;
cistpl_cftable_entry_t dflt;
};
/**
* pcmcia_do_loop_config() - internal helper for pcmcia_loop_config()
*
* pcmcia_do_loop_config() is the internal callback for the call from
* pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred
* by a struct pcmcia_cfg_mem.
*/
static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
{
cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
struct pcmcia_cfg_mem *cfg_mem = priv;
/* default values */
cfg_mem->p_dev->conf.ConfigIndex = cfg->index;
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
cfg_mem->dflt = *cfg;
return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt,
cfg_mem->p_dev->socket->socket.Vcc,
cfg_mem->priv_data);
}
/**
* pcmcia_loop_config() - loop over configuration options
* @p_dev: the struct pcmcia_device which we need to loop for.
* @conf_check: function to call for each configuration option.
* It gets passed the struct pcmcia_device, the CIS data
* describing the configuration option, and private data
* being passed to pcmcia_loop_config()
* @priv_data: private data to be passed to the conf_check function.
*
* pcmcia_loop_config() loops over all configuration options, and calls
* the driver-specific conf_check() for each one, checking whether
* it is a valid one. Returns 0 on success or errorcode otherwise.
*/
int pcmcia_loop_config(struct pcmcia_device *p_dev,
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data),
void *priv_data)
{
struct pcmcia_cfg_mem *cfg_mem;
int ret;
cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
if (cfg_mem == NULL)
return -ENOMEM;
cfg_mem->p_dev = p_dev;
cfg_mem->conf_check = conf_check;
cfg_mem->priv_data = priv_data;
ret = pccard_loop_tuple(p_dev->socket, p_dev->func,
CISTPL_CFTABLE_ENTRY, &cfg_mem->parse,
cfg_mem, pcmcia_do_loop_config);
kfree(cfg_mem);
return ret;
}
EXPORT_SYMBOL(pcmcia_loop_config);
struct pcmcia_loop_mem {
struct pcmcia_device *p_dev;
void *priv_data;
int (*loop_tuple) (struct pcmcia_device *p_dev,
tuple_t *tuple,
void *priv_data);
};
/**
* pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
*
* pcmcia_do_loop_tuple() is the internal callback for the call from
* pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
* by a struct pcmcia_cfg_mem.
*/
static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
{
struct pcmcia_loop_mem *loop = priv;
return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
};
/**
* pcmcia_loop_tuple() - loop over tuples in the CIS
* @p_dev: the struct pcmcia_device which we need to loop for.
* @code: which CIS code shall we look for?
* @priv_data: private data to be passed to the loop_tuple function.
* @loop_tuple: function to call for each CIS entry of type @function. IT
* gets passed the raw tuple and @priv_data.
*
* pcmcia_loop_tuple() loops over all CIS entries of type @function, and
* calls the @loop_tuple function for each entry. If the call to @loop_tuple
* returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
*/
int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
int (*loop_tuple) (struct pcmcia_device *p_dev,
tuple_t *tuple,
void *priv_data),
void *priv_data)
{
struct pcmcia_loop_mem loop = {
.p_dev = p_dev,
.loop_tuple = loop_tuple,
.priv_data = priv_data};
return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
&loop, pcmcia_do_loop_tuple);
}
EXPORT_SYMBOL(pcmcia_loop_tuple);
struct pcmcia_loop_get {
size_t len;
cisdata_t **buf;
};
/**
* pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple()
*
* pcmcia_do_get_tuple() is the internal callback for the call from
* pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in
* the first tuple, return 0 unconditionally. Create a memory buffer large
* enough to hold the content of the tuple, and fill it with the tuple data.
* The caller is responsible to free the buffer.
*/
static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
void *priv)
{
struct pcmcia_loop_get *get = priv;
*get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL);
if (*get->buf) {
get->len = tuple->TupleDataLen;
memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen);
} else
dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n");
return 0;
}
/**
* pcmcia_get_tuple() - get first tuple from CIS
* @p_dev: the struct pcmcia_device which we need to loop for.
* @code: which CIS code shall we look for?
* @buf: pointer to store the buffer to.
*
* pcmcia_get_tuple() gets the content of the first CIS entry of type @code.
* It returns the buffer length (or zero). The caller is responsible to free
* the buffer passed in @buf.
*/
size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
unsigned char **buf)
{
struct pcmcia_loop_get get = {
.len = 0,
.buf = buf,
};
*get.buf = NULL;
pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
return get.len;
}
EXPORT_SYMBOL(pcmcia_get_tuple);
/**
* pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis()
*
* pcmcia_do_get_mac() is the internal callback for the call from
* pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the
* tuple contains a proper LAN_NODE_ID of length 6, and copy the data
* to struct net_device->dev_addr[i].
*/
static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
void *priv)
{
struct net_device *dev = priv;
int i;
if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
return -EINVAL;
if (tuple->TupleDataLen < ETH_ALEN + 2) {
dev_warn(&p_dev->dev, "Invalid CIS tuple length for "
"LAN_NODE_ID\n");
return -EINVAL;
}
if (tuple->TupleData[1] != ETH_ALEN) {
dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n");
return -EINVAL;
}
for (i = 0; i < 6; i++)
dev->dev_addr[i] = tuple->TupleData[i+2];
return 0;
}
/**
* pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
* @p_dev: the struct pcmcia_device for which we want the address.
* @dev: a properly prepared struct net_device to store the info to.
*
* pcmcia_get_mac_from_cis() reads out the hardware MAC address from
* CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which
* must be set up properly by the driver (see examples!).
*/
int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
{
return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
}
EXPORT_SYMBOL(pcmcia_get_mac_from_cis);

View file

@ -301,7 +301,9 @@ static int pccard_get_status(struct pcmcia_socket *s,
(c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
u_char reg;
if (c->CardValues & PRESENT_PIN_REPLACE) {
mutex_lock(&s->ops_mutex);
pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
mutex_unlock(&s->ops_mutex);
status->CardState |=
(reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
status->CardState |=
@ -315,7 +317,9 @@ static int pccard_get_status(struct pcmcia_socket *s,
status->CardState |= CS_EVENT_READY_CHANGE;
}
if (c->CardValues & PRESENT_EXT_STATUS) {
mutex_lock(&s->ops_mutex);
pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
mutex_unlock(&s->ops_mutex);
status->CardState |=
(reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
}
@ -351,7 +355,7 @@ static int pccard_get_configuration_info(struct pcmcia_socket *s,
if (s->state & SOCKET_CARDBUS_CONFIG) {
config->Attributes = CONF_VALID_CLIENT;
config->IntType = INT_CARDBUS;
config->AssignedIRQ = s->irq.AssignedIRQ;
config->AssignedIRQ = s->pcmcia_irq;
if (config->AssignedIRQ)
config->Attributes |= CONF_ENABLE_IRQ;
if (s->io[0].res) {
@ -391,7 +395,7 @@ static int pccard_get_configuration_info(struct pcmcia_socket *s,
config->ExtStatus = c->ExtStatus;
config->Present = config->CardValues = c->CardValues;
config->IRQAttributes = c->irq.Attributes;
config->AssignedIRQ = s->irq.AssignedIRQ;
config->AssignedIRQ = s->pcmcia_irq;
config->BasePort1 = c->io.BasePort1;
config->NumPorts1 = c->io.NumPorts1;
config->Attributes1 = c->io.Attributes1;
@ -571,7 +575,6 @@ static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
{
dev_node_t *node;
struct pcmcia_device *p_dev;
struct pcmcia_driver *p_drv;
int ret = 0;
@ -633,21 +636,13 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int
goto err_put;
}
if (first)
node = p_dev->dev_node;
else
for (node = p_dev->dev_node; node; node = node->next)
if (node == bind_info->next)
break;
if (!node) {
if (!first) {
ret = -ENODEV;
goto err_put;
}
strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
bind_info->major = node->major;
bind_info->minor = node->minor;
bind_info->next = node->next;
strlcpy(bind_info->name, dev_name(&p_dev->dev), DEV_NAME_LEN);
bind_info->next = NULL;
err_put:
pcmcia_put_dev(p_dev);
@ -711,7 +706,7 @@ static int ds_open(struct inode *inode, struct file *file)
warning_printed = 1;
}
if (s->pcmcia_state.present)
if (atomic_read(&s->present))
queue_event(user, CS_EVENT_CARD_INSERTION);
out:
unlock_kernel();
@ -770,9 +765,6 @@ static ssize_t ds_read(struct file *file, char __user *buf,
return -EIO;
s = user->socket;
if (s->pcmcia_state.dead)
return -EIO;
ret = wait_event_interruptible(s->queue, !queue_empty(user));
if (ret == 0)
ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
@ -838,8 +830,6 @@ static int ds_ioctl(struct inode *inode, struct file *file,
return -EIO;
s = user->socket;
if (s->pcmcia_state.dead)
return -EIO;
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
if (size > sizeof(ds_ioctl_arg_t))

View file

@ -23,6 +23,8 @@
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <asm/irq.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@ -38,29 +40,6 @@ static int io_speed;
module_param(io_speed, int, 0444);
#ifdef CONFIG_PCMCIA_PROBE
#include <asm/irq.h>
/* mask of IRQs already reserved by other cards, we should avoid using them */
static u8 pcmcia_used_irq[NR_IRQS];
#endif
static int pcmcia_adjust_io_region(struct resource *res, unsigned long start,
unsigned long end, struct pcmcia_socket *s)
{
if (s->resource_ops->adjust_io_region)
return s->resource_ops->adjust_io_region(res, start, end, s);
return -ENOMEM;
}
static struct resource *pcmcia_find_io_region(unsigned long base, int num,
unsigned long align,
struct pcmcia_socket *s)
{
if (s->resource_ops->find_io)
return s->resource_ops->find_io(base, num, align, s);
return NULL;
}
int pcmcia_validate_mem(struct pcmcia_socket *s)
{
if (s->resource_ops->validate_mem)
@ -86,8 +65,7 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
unsigned int *base, unsigned int num, u_int lines)
{
int i;
unsigned int try, align;
unsigned int align;
align = (*base) ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
@ -104,50 +82,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
*base, align);
align = 0;
}
if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
*base = s->io_offset | (*base & 0x0fff);
return 0;
}
/* Check for an already-allocated window that must conflict with
* what was asked for. It is a hack because it does not catch all
* potential conflicts, just the most obvious ones.
*/
for (i = 0; i < MAX_IO_WIN; i++)
if ((s->io[i].res) && *base &&
((s->io[i].res->start & (align-1)) == *base))
return 1;
for (i = 0; i < MAX_IO_WIN; i++) {
if (!s->io[i].res) {
s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
if (s->io[i].res) {
*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].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS))
continue;
/* Try to extend top of window */
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].InUse += num;
break;
}
/* Try to extend bottom of window */
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) {
*base = try;
s->io[i].InUse += num;
break;
}
}
return (i == MAX_IO_WIN);
return s->resource_ops->find_io(s, attr, base, num, align);
} /* alloc_io_space */
@ -187,6 +123,7 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
config_t *c;
int addr;
u_char val;
int ret = 0;
if (!p_dev || !p_dev->function_config)
return -EINVAL;
@ -203,11 +140,10 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
}
addr = (c->ConfigBase + reg->Offset) >> 1;
mutex_unlock(&s->ops_mutex);
switch (reg->Action) {
case CS_READ:
pcmcia_read_cis_mem(s, 1, addr, 1, &val);
ret = pcmcia_read_cis_mem(s, 1, addr, 1, &val);
reg->Value = val;
break;
case CS_WRITE:
@ -216,10 +152,11 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
break;
default:
dev_dbg(&s->dev, "Invalid conf register request\n");
return -EINVAL;
ret = -EINVAL;
break;
}
return 0;
mutex_unlock(&s->ops_mutex);
return ret;
} /* pcmcia_access_configuration_register */
EXPORT_SYMBOL(pcmcia_access_configuration_register);
@ -275,19 +212,9 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
goto unlock;
}
if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
if (mod->Attributes & CONF_ENABLE_IRQ) {
c->Attributes |= CONF_ENABLE_IRQ;
s->socket.io_irq = s->irq.AssignedIRQ;
} else {
c->Attributes &= ~CONF_ENABLE_IRQ;
s->socket.io_irq = 0;
}
s->ops->set_socket(s, &s->socket);
}
if (mod->Attributes & CONF_VCC_CHANGE_VALID) {
dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n");
if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) {
dev_dbg(&s->dev,
"changing Vcc or IRQ is not allowed at this time\n");
ret = -EINVAL;
goto unlock;
}
@ -422,52 +349,6 @@ out:
} /* pcmcia_release_io */
static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
{
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
int ret = -EINVAL;
mutex_lock(&s->ops_mutex);
c = p_dev->function_config;
if (!p_dev->_irq)
goto out;
p_dev->_irq = 0;
if (c->state & CONFIG_LOCKED)
goto out;
if (c->irq.Attributes != req->Attributes) {
dev_dbg(&s->dev, "IRQ attributes must match assigned ones\n");
goto out;
}
if (s->irq.AssignedIRQ != req->AssignedIRQ) {
dev_dbg(&s->dev, "IRQ must match assigned one\n");
goto out;
}
if (--s->irq.Config == 0) {
c->state &= ~CONFIG_IRQ_REQ;
s->irq.AssignedIRQ = 0;
}
if (req->Handler)
free_irq(req->AssignedIRQ, p_dev->priv);
#ifdef CONFIG_PCMCIA_PROBE
pcmcia_used_irq[req->AssignedIRQ]--;
#endif
ret = 0;
out:
mutex_unlock(&s->ops_mutex);
return ret;
} /* pcmcia_release_irq */
int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
{
struct pcmcia_socket *s = p_dev->socket;
@ -551,12 +432,11 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (req->Attributes & CONF_ENABLE_SPKR)
s->socket.flags |= SS_SPKR_ENA;
if (req->Attributes & CONF_ENABLE_IRQ)
s->socket.io_irq = s->irq.AssignedIRQ;
s->socket.io_irq = s->pcmcia_irq;
else
s->socket.io_irq = 0;
s->ops->set_socket(s, &s->socket);
s->lock_count++;
mutex_unlock(&s->ops_mutex);
/* Set up CIS configuration registers */
base = c->ConfigBase = req->ConfigBase;
@ -574,9 +454,9 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
if (req->Present & PRESENT_IOBASE_0)
c->Option |= COR_ADDR_DECODE;
}
if (c->state & CONFIG_IRQ_REQ)
if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
c->Option |= COR_LEVEL_REQ;
if ((req->Attributes & CONF_ENABLE_IRQ) &&
!(req->Attributes & CONF_ENABLE_PULSE_IRQ))
c->Option |= COR_LEVEL_REQ;
pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
mdelay(40);
}
@ -605,7 +485,6 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
/* Configure I/O windows */
if (c->state & CONFIG_IO_REQ) {
mutex_lock(&s->ops_mutex);
iomap.speed = io_speed;
for (i = 0; i < MAX_IO_WIN; i++)
if (s->io[i].res) {
@ -624,11 +503,11 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
s->ops->set_io_map(s, &iomap);
s->io[i].Config++;
}
mutex_unlock(&s->ops_mutex);
}
c->state |= CONFIG_LOCKED;
p_dev->_locked = 1;
mutex_unlock(&s->ops_mutex);
return 0;
} /* pcmcia_request_configuration */
EXPORT_SYMBOL(pcmcia_request_configuration);
@ -706,137 +585,176 @@ out:
EXPORT_SYMBOL(pcmcia_request_io);
/** pcmcia_request_irq
/**
* pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device
*
* Request_irq() reserves an irq for this client.
*
* Also, since Linux only reserves irq's when they are actually
* hooked, we don't guarantee that an irq will still be available
* when the configuration is locked. Now that I think about it,
* there might be a way to fix this using a dummy handler.
* pcmcia_request_irq() is a wrapper around request_irq which will allow
* the PCMCIA core to clean up the registration in pcmcia_disable_device().
* Drivers are free to use request_irq() directly, but then they need to
* call free_irq themselfves, too. Also, only IRQF_SHARED capable IRQ
* handlers are allowed.
*/
#ifdef CONFIG_PCMCIA_PROBE
static irqreturn_t test_action(int cpl, void *dev_id)
int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
irq_handler_t handler)
{
return IRQ_NONE;
int ret;
if (!p_dev->irq)
return -EINVAL;
ret = request_irq(p_dev->irq, handler, IRQF_SHARED,
p_dev->devname, p_dev->priv);
if (!ret)
p_dev->_irq = 1;
return ret;
}
#endif
EXPORT_SYMBOL(pcmcia_request_irq);
int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
/**
* pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first
*
* pcmcia_request_exclusive_irq() is a wrapper around request_irq which
* attempts first to request an exclusive IRQ. If it fails, it also accepts
* a shared IRQ, but prints out a warning. PCMCIA drivers should allow for
* IRQ sharing and either use request_irq directly (then they need to call
* free_irq themselves, too), or the pcmcia_request_irq() function.
*/
int __must_check
__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
irq_handler_t handler)
{
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
int ret = -EINVAL, irq = 0;
int type;
int ret;
mutex_lock(&s->ops_mutex);
if (!p_dev->irq)
return -EINVAL;
if (!(s->state & SOCKET_PRESENT)) {
dev_dbg(&s->dev, "No card present\n");
goto out;
}
c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
dev_dbg(&s->dev, "Configuration is locked\n");
goto out;
}
if (c->state & CONFIG_IRQ_REQ) {
dev_dbg(&s->dev, "IRQ already configured\n");
goto out;
}
/* Decide what type of interrupt we are registering */
type = 0;
if (s->functions > 1) /* All of this ought to be handled higher up */
type = IRQF_SHARED;
else if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
type = IRQF_SHARED;
else
printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
#ifdef CONFIG_PCMCIA_PROBE
if (s->irq.AssignedIRQ != 0) {
/* If the interrupt is already assigned, it must be the same */
irq = s->irq.AssignedIRQ;
} else {
int try;
u32 mask = s->irq_mask;
void *data = p_dev; /* something unique to this device */
for (try = 0; try < 64; try++) {
irq = try % 32;
/* marked as available by driver, and not blocked by userspace? */
if (!((mask >> irq) & 1))
continue;
/* avoid an IRQ which is already used by a PCMCIA card */
if ((try < 32) && pcmcia_used_irq[irq])
continue;
/* register the correct driver, if possible, of check whether
* registering a dummy handle works, i.e. if the IRQ isn't
* marked as used by the kernel resource management core */
ret = request_irq(irq,
(req->Handler) ? req->Handler : test_action,
type,
p_dev->devname,
(req->Handler) ? p_dev->priv : data);
if (!ret) {
if (!req->Handler)
free_irq(irq, data);
break;
}
}
}
#endif
/* only assign PCI irq if no IRQ already assigned */
if (ret && !s->irq.AssignedIRQ) {
if (!s->pci_irq) {
dev_printk(KERN_INFO, &s->dev, "no IRQ found\n");
goto out;
}
type = IRQF_SHARED;
irq = s->pci_irq;
}
if (ret && req->Handler) {
ret = request_irq(irq, req->Handler, type,
p_dev->devname, p_dev->priv);
if (ret) {
dev_printk(KERN_INFO, &s->dev,
"request_irq() failed\n");
goto out;
}
}
/* Make sure the fact the request type was overridden is passed back */
if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
ret = request_irq(p_dev->irq, handler, 0, p_dev->devname, p_dev->priv);
if (ret) {
ret = pcmcia_request_irq(p_dev, handler);
dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
"request for exclusive IRQ could not be fulfilled.\n");
dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
"needs updating to supported shared IRQ lines.\n");
}
c->irq.Attributes = req->Attributes;
s->irq.AssignedIRQ = req->AssignedIRQ = irq;
s->irq.Config++;
if (ret)
dev_printk(KERN_INFO, &p_dev->dev, "request_irq() failed\n");
else
p_dev->_irq = 1;
return ret;
} /* pcmcia_request_exclusive_irq */
EXPORT_SYMBOL(__pcmcia_request_exclusive_irq);
c->state |= CONFIG_IRQ_REQ;
p_dev->_irq = 1;
#ifdef CONFIG_PCMCIA_PROBE
pcmcia_used_irq[irq]++;
#endif
ret = 0;
out:
mutex_unlock(&s->ops_mutex);
/* mask of IRQs already reserved by other cards, we should avoid using them */
static u8 pcmcia_used_irq[NR_IRQS];
static irqreturn_t test_action(int cpl, void *dev_id)
{
return IRQ_NONE;
}
/**
* pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used
* @p_dev - the associated PCMCIA device
*
* locking note: must be called with ops_mutex locked.
*/
static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
{
struct pcmcia_socket *s = p_dev->socket;
unsigned int try, irq;
u32 mask = s->irq_mask;
int ret = -ENODEV;
for (try = 0; try < 64; try++) {
irq = try % 32;
/* marked as available by driver, not blocked by userspace? */
if (!((mask >> irq) & 1))
continue;
/* avoid an IRQ which is already used by another PCMCIA card */
if ((try < 32) && pcmcia_used_irq[irq])
continue;
/* register the correct driver, if possible, to check whether
* registering a dummy handle works, i.e. if the IRQ isn't
* marked as used by the kernel resource management core */
ret = request_irq(irq, test_action, type, p_dev->devname,
p_dev);
if (!ret) {
free_irq(irq, p_dev);
p_dev->irq = s->pcmcia_irq = irq;
pcmcia_used_irq[irq]++;
break;
}
}
return ret;
} /* pcmcia_request_irq */
EXPORT_SYMBOL(pcmcia_request_irq);
}
void pcmcia_cleanup_irq(struct pcmcia_socket *s)
{
pcmcia_used_irq[s->pcmcia_irq]--;
s->pcmcia_irq = 0;
}
#else /* CONFIG_PCMCIA_PROBE */
static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
{
return -EINVAL;
}
void pcmcia_cleanup_irq(struct pcmcia_socket *s)
{
s->pcmcia_irq = 0;
return;
}
#endif /* CONFIG_PCMCIA_PROBE */
/**
* pcmcia_setup_irq() - determine IRQ to be used for device
* @p_dev - the associated PCMCIA device
*
* locking note: must be called with ops_mutex locked.
*/
int pcmcia_setup_irq(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s = p_dev->socket;
if (p_dev->irq)
return 0;
/* already assigned? */
if (s->pcmcia_irq) {
p_dev->irq = s->pcmcia_irq;
return 0;
}
/* prefer an exclusive ISA irq */
if (!pcmcia_setup_isa_irq(p_dev, 0))
return 0;
/* but accept a shared ISA irq */
if (!pcmcia_setup_isa_irq(p_dev, IRQF_SHARED))
return 0;
/* but use the PCI irq otherwise */
if (s->pci_irq) {
p_dev->irq = s->pcmcia_irq = s->pci_irq;
return 0;
}
return -EINVAL;
}
/** pcmcia_request_window
@ -939,237 +857,9 @@ 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->_irq)
free_irq(p_dev->irq, p_dev->priv);
if (p_dev->win)
pcmcia_release_window(p_dev, p_dev->win);
}
EXPORT_SYMBOL(pcmcia_disable_device);
struct pcmcia_cfg_mem {
struct pcmcia_device *p_dev;
void *priv_data;
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data);
cisparse_t parse;
cistpl_cftable_entry_t dflt;
};
/**
* pcmcia_do_loop_config() - internal helper for pcmcia_loop_config()
*
* pcmcia_do_loop_config() is the internal callback for the call from
* pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred
* by a struct pcmcia_cfg_mem.
*/
static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
{
cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
struct pcmcia_cfg_mem *cfg_mem = priv;
/* default values */
cfg_mem->p_dev->conf.ConfigIndex = cfg->index;
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
cfg_mem->dflt = *cfg;
return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt,
cfg_mem->p_dev->socket->socket.Vcc,
cfg_mem->priv_data);
}
/**
* pcmcia_loop_config() - loop over configuration options
* @p_dev: the struct pcmcia_device which we need to loop for.
* @conf_check: function to call for each configuration option.
* It gets passed the struct pcmcia_device, the CIS data
* describing the configuration option, and private data
* being passed to pcmcia_loop_config()
* @priv_data: private data to be passed to the conf_check function.
*
* pcmcia_loop_config() loops over all configuration options, and calls
* the driver-specific conf_check() for each one, checking whether
* it is a valid one. Returns 0 on success or errorcode otherwise.
*/
int pcmcia_loop_config(struct pcmcia_device *p_dev,
int (*conf_check) (struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data),
void *priv_data)
{
struct pcmcia_cfg_mem *cfg_mem;
int ret;
cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
if (cfg_mem == NULL)
return -ENOMEM;
cfg_mem->p_dev = p_dev;
cfg_mem->conf_check = conf_check;
cfg_mem->priv_data = priv_data;
ret = pccard_loop_tuple(p_dev->socket, p_dev->func,
CISTPL_CFTABLE_ENTRY, &cfg_mem->parse,
cfg_mem, pcmcia_do_loop_config);
kfree(cfg_mem);
return ret;
}
EXPORT_SYMBOL(pcmcia_loop_config);
struct pcmcia_loop_mem {
struct pcmcia_device *p_dev;
void *priv_data;
int (*loop_tuple) (struct pcmcia_device *p_dev,
tuple_t *tuple,
void *priv_data);
};
/**
* pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
*
* pcmcia_do_loop_tuple() is the internal callback for the call from
* pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
* by a struct pcmcia_cfg_mem.
*/
static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
{
struct pcmcia_loop_mem *loop = priv;
return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
};
/**
* pcmcia_loop_tuple() - loop over tuples in the CIS
* @p_dev: the struct pcmcia_device which we need to loop for.
* @code: which CIS code shall we look for?
* @priv_data: private data to be passed to the loop_tuple function.
* @loop_tuple: function to call for each CIS entry of type @function. IT
* gets passed the raw tuple and @priv_data.
*
* pcmcia_loop_tuple() loops over all CIS entries of type @function, and
* calls the @loop_tuple function for each entry. If the call to @loop_tuple
* returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
*/
int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
int (*loop_tuple) (struct pcmcia_device *p_dev,
tuple_t *tuple,
void *priv_data),
void *priv_data)
{
struct pcmcia_loop_mem loop = {
.p_dev = p_dev,
.loop_tuple = loop_tuple,
.priv_data = priv_data};
return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
&loop, pcmcia_do_loop_tuple);
}
EXPORT_SYMBOL(pcmcia_loop_tuple);
struct pcmcia_loop_get {
size_t len;
cisdata_t **buf;
};
/**
* pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple()
*
* pcmcia_do_get_tuple() is the internal callback for the call from
* pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in
* the first tuple, return 0 unconditionally. Create a memory buffer large
* enough to hold the content of the tuple, and fill it with the tuple data.
* The caller is responsible to free the buffer.
*/
static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
void *priv)
{
struct pcmcia_loop_get *get = priv;
*get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL);
if (*get->buf) {
get->len = tuple->TupleDataLen;
memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen);
} else
dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n");
return 0;
}
/**
* pcmcia_get_tuple() - get first tuple from CIS
* @p_dev: the struct pcmcia_device which we need to loop for.
* @code: which CIS code shall we look for?
* @buf: pointer to store the buffer to.
*
* pcmcia_get_tuple() gets the content of the first CIS entry of type @code.
* It returns the buffer length (or zero). The caller is responsible to free
* the buffer passed in @buf.
*/
size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
unsigned char **buf)
{
struct pcmcia_loop_get get = {
.len = 0,
.buf = buf,
};
*get.buf = NULL;
pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
return get.len;
}
EXPORT_SYMBOL(pcmcia_get_tuple);
/**
* pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis()
*
* pcmcia_do_get_mac() is the internal callback for the call from
* pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the
* tuple contains a proper LAN_NODE_ID of length 6, and copy the data
* to struct net_device->dev_addr[i].
*/
static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
void *priv)
{
struct net_device *dev = priv;
int i;
if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
return -EINVAL;
if (tuple->TupleDataLen < ETH_ALEN + 2) {
dev_warn(&p_dev->dev, "Invalid CIS tuple length for "
"LAN_NODE_ID\n");
return -EINVAL;
}
if (tuple->TupleData[1] != ETH_ALEN) {
dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n");
return -EINVAL;
}
for (i = 0; i < 6; i++)
dev->dev_addr[i] = tuple->TupleData[i+2];
return 0;
}
/**
* pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
* @p_dev: the struct pcmcia_device for which we want the address.
* @dev: a properly prepared struct net_device to store the info to.
*
* pcmcia_get_mac_from_cis() reads out the hardware MAC address from
* CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which
* must be set up properly by the driver (see examples!).
*/
int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
{
return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
}
EXPORT_SYMBOL(pcmcia_get_mac_from_cis);

View file

@ -0,0 +1,229 @@
/*
* linux/drivers/pcmcia/pxa2xx_vpac270.c
*
* Driver for Voipac PXA270 PCMCIA and CF sockets
*
* Copyright (C) 2010
* Marek Vasut <marek.vasut@gmail.com>
*
* 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/module.h>
#include <linux/platform_device.h>
#include <asm/mach-types.h>
#include <mach/gpio.h>
#include <mach/vpac270.h>
#include "soc_common.h"
static struct pcmcia_irqs cd_irqs[] = {
{
.sock = 0,
.irq = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD),
.str = "PCMCIA CD"
},
{
.sock = 1,
.irq = IRQ_GPIO(GPIO17_VPAC270_CF_CD),
.str = "CF CD"
},
};
static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
int ret;
if (skt->nr == 0) {
ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD");
if (ret)
goto err1;
ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD);
if (ret)
goto err2;
ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY");
if (ret)
goto err2;
ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY);
if (ret)
goto err3;
ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN");
if (ret)
goto err3;
ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0);
if (ret)
goto err4;
ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET");
if (ret)
goto err4;
ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0);
if (ret)
goto err5;
skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
err5:
gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
err4:
gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
err3:
gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
err2:
gpio_free(GPIO84_VPAC270_PCMCIA_CD);
err1:
return ret;
} else {
ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD");
if (ret)
goto err6;
ret = gpio_direction_input(GPIO17_VPAC270_CF_CD);
if (ret)
goto err7;
ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY");
if (ret)
goto err7;
ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY);
if (ret)
goto err8;
ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET");
if (ret)
goto err8;
ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0);
if (ret)
goto err9;
skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
err9:
gpio_free(GPIO16_VPAC270_CF_RESET);
err8:
gpio_free(GPIO12_VPAC270_CF_RDY);
err7:
gpio_free(GPIO17_VPAC270_CF_CD);
err6:
return ret;
}
}
static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
gpio_free(GPIO84_VPAC270_PCMCIA_CD);
gpio_free(GPIO16_VPAC270_CF_RESET);
gpio_free(GPIO12_VPAC270_CF_RDY);
gpio_free(GPIO17_VPAC270_CF_CD);
}
static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
if (skt->nr == 0) {
state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
state->ready = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
} else {
state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
state->ready = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
}
state->bvd1 = 1;
state->bvd2 = 1;
state->wrprot = 0;
state->vs_3v = 1;
state->vs_Xv = 0;
}
static int
vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
if (skt->nr == 0) {
gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
(state->flags & SS_RESET));
gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
!(state->Vcc == 33 || state->Vcc == 50));
} else {
gpio_set_value(GPIO16_VPAC270_CF_RESET,
(state->flags & SS_RESET));
}
return 0;
}
static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
{
}
static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
}
static struct pcmcia_low_level vpac270_pcmcia_ops = {
.owner = THIS_MODULE,
.first = 0,
.nr = 2,
.hw_init = vpac270_pcmcia_hw_init,
.hw_shutdown = vpac270_pcmcia_hw_shutdown,
.socket_state = vpac270_pcmcia_socket_state,
.configure_socket = vpac270_pcmcia_configure_socket,
.socket_init = vpac270_pcmcia_socket_init,
.socket_suspend = vpac270_pcmcia_socket_suspend,
};
static struct platform_device *vpac270_pcmcia_device;
static int __init vpac270_pcmcia_init(void)
{
int ret;
if (!machine_is_vpac270())
return -ENODEV;
vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
if (!vpac270_pcmcia_device)
return -ENOMEM;
ret = platform_device_add_data(vpac270_pcmcia_device,
&vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
if (!ret)
ret = platform_device_add(vpac270_pcmcia_device);
if (ret)
platform_device_put(vpac270_pcmcia_device);
return ret;
}
static void __exit vpac270_pcmcia_exit(void)
{
platform_device_unregister(vpac270_pcmcia_device);
}
module_init(vpac270_pcmcia_init);
module_exit(vpac270_pcmcia_exit);
MODULE_AUTHOR("Marek Vasut <[email protected]>");
MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
MODULE_ALIAS("platform:pxa2xx-pcmcia");
MODULE_LICENSE("GPL");

172
drivers/pcmcia/rsrc_iodyn.c Normal file
View file

@ -0,0 +1,172 @@
/*
* rsrc_iodyn.c -- Resource management routines for MEM-static sockets.
*
* 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.
*
* 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.
*
* (C) 1999 David A. Hinds
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
struct pcmcia_align_data {
unsigned long mask;
unsigned long offset;
};
static resource_size_t pcmcia_align(void *align_data,
const struct resource *res,
resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
resource_size_t start;
start = (res->start & ~data->mask) + data->offset;
if (start < res->start)
start += data->mask + 1;
#ifdef CONFIG_X86
if (res->flags & IORESOURCE_IO) {
if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
}
#endif
#ifdef CONFIG_M68K
if (res->flags & IORESOURCE_IO) {
if ((res->start + size - 1) >= 1024)
start = res->end;
}
#endif
return start;
}
static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
unsigned long base, int num,
unsigned long align)
{
struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
dev_name(&s->dev));
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
data.mask = align - 1;
data.offset = base & data.mask;
#ifdef CONFIG_PCI
if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
min, 0, pcmcia_align, &data);
} else
#endif
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
1, pcmcia_align, &data);
if (ret != 0) {
kfree(res);
res = NULL;
}
return res;
}
static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
unsigned int align)
{
int i, ret = 0;
/* Check for an already-allocated window that must conflict with
* what was asked for. It is a hack because it does not catch all
* potential conflicts, just the most obvious ones.
*/
for (i = 0; i < MAX_IO_WIN; i++) {
if (!s->io[i].res)
continue;
if (!*base)
continue;
if ((s->io[i].res->start & (align-1)) == *base)
return -EBUSY;
}
for (i = 0; i < MAX_IO_WIN; i++) {
struct resource *res = s->io[i].res;
unsigned int try;
if (res && (res->flags & IORESOURCE_BITS) !=
(attr & IORESOURCE_BITS))
continue;
if (!res) {
if (align == 0)
align = 0x10000;
res = s->io[i].res = __iodyn_find_io_region(s, *base,
num, align);
if (!res)
return -EINVAL;
*base = res->start;
s->io[i].res->flags =
((res->flags & ~IORESOURCE_BITS) |
(attr & IORESOURCE_BITS));
s->io[i].InUse = num;
return 0;
}
/* Try to extend top of window */
try = res->end + 1;
if ((*base == 0) || (*base == try)) {
if (adjust_resource(s->io[i].res, res->start,
res->end - res->start + num + 1))
continue;
*base = try;
s->io[i].InUse += num;
return 0;
}
/* Try to extend bottom of window */
try = res->start - num;
if ((*base == 0) || (*base == try)) {
if (adjust_resource(s->io[i].res,
res->start - num,
res->end - res->start + num + 1))
continue;
*base = try;
s->io[i].InUse += num;
return 0;
}
}
return -EINVAL;
}
struct pccard_resource_ops pccard_iodyn_ops = {
.validate_mem = NULL,
.find_io = iodyn_find_io,
.find_mem = NULL,
.add_io = NULL,
.add_mem = NULL,
.init = static_init,
.exit = NULL,
};
EXPORT_SYMBOL(pccard_iodyn_ops);

View file

@ -22,7 +22,7 @@
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
static int static_init(struct pcmcia_socket *s)
int static_init(struct pcmcia_socket *s)
{
/* the good thing about SS_CAP_STATIC_MAP sockets is
* that they don't need a resource database */
@ -32,11 +32,35 @@ static int static_init(struct pcmcia_socket *s)
return 0;
}
struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
int flags, const char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res) {
res->name = name;
res->start = start;
res->end = start + end - 1;
res->flags = flags;
}
return res;
}
static int static_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
unsigned int align)
{
if (!s->io_offset)
return -EINVAL;
*base = s->io_offset | (*base & 0x0fff);
return 0;
}
struct pccard_resource_ops pccard_static_ops = {
.validate_mem = NULL,
.adjust_io_region = NULL,
.find_io = NULL,
.find_io = static_find_io,
.find_mem = NULL,
.add_io = NULL,
.add_mem = NULL,
@ -46,104 +70,6 @@ struct pccard_resource_ops pccard_static_ops = {
EXPORT_SYMBOL(pccard_static_ops);
#ifdef CONFIG_PCCARD_IODYN
static struct resource *
make_resource(unsigned long b, unsigned long n, int flags, char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res) {
res->name = name;
res->start = b;
res->end = b + n - 1;
res->flags = flags;
}
return res;
}
struct pcmcia_align_data {
unsigned long mask;
unsigned long offset;
};
static resource_size_t pcmcia_align(void *align_data,
const struct resource *res,
resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
resource_size_t start;
start = (res->start & ~data->mask) + data->offset;
if (start < res->start)
start += data->mask + 1;
#ifdef CONFIG_X86
if (res->flags & IORESOURCE_IO) {
if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
}
#endif
#ifdef CONFIG_M68K
if (res->flags & IORESOURCE_IO) {
if ((res->start + size - 1) >= 1024)
start = res->end;
}
#endif
return start;
}
static int iodyn_adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s)
{
return adjust_resource(res, r_start, r_end - r_start + 1);
}
static struct resource *iodyn_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO,
dev_name(&s->dev));
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
if (align == 0)
align = 0x10000;
data.mask = align - 1;
data.offset = base & data.mask;
#ifdef CONFIG_PCI
if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
min, 0, pcmcia_align, &data);
} else
#endif
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
1, pcmcia_align, &data);
if (ret != 0) {
kfree(res);
res = NULL;
}
return res;
}
struct pccard_resource_ops pccard_iodyn_ops = {
.validate_mem = NULL,
.adjust_io_region = iodyn_adjust_io_region,
.find_io = iodyn_find_io_region,
.find_mem = NULL,
.add_io = NULL,
.add_mem = NULL,
.init = static_init,
.exit = NULL,
};
EXPORT_SYMBOL(pccard_iodyn_ops);
#endif /* CONFIG_PCCARD_IODYN */
MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
MODULE_LICENSE("GPL");
MODULE_ALIAS("rsrc_nonstatic");

View file

@ -34,8 +34,10 @@
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
/* moved to rsrc_mgr.c
MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
MODULE_LICENSE("GPL");
*/
/* Parameters that can be set with 'insmod' */
@ -69,20 +71,6 @@ struct socket_data {
======================================================================*/
static struct resource *
make_resource(resource_size_t b, resource_size_t n, int flags, const char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res) {
res->name = name;
res->start = b;
res->end = b + n - 1;
res->flags = flags;
}
return res;
}
static struct resource *
claim_region(struct pcmcia_socket *s, resource_size_t base,
resource_size_t size, int type, char *name)
@ -90,7 +78,7 @@ claim_region(struct pcmcia_socket *s, resource_size_t base,
struct resource *res, *parent;
parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
res = make_resource(base, size, type | IORESOURCE_BUSY, name);
res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
if (res) {
#ifdef CONFIG_PCI
@ -214,7 +202,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
return;
}
for (i = base, most = 0; i < base+num; i += 8) {
res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res)
continue;
hole = inb(i);
@ -231,9 +219,14 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
bad = any = 0;
for (i = base; i < base+num; i += 8) {
res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res)
res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res) {
if (!any)
printk(" excluding");
if (!bad)
bad = any = i;
continue;
}
for (j = 0; j < 8; j++)
if (inb(i+j) != most)
break;
@ -253,6 +246,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
}
if (bad) {
if ((num > 16) && (bad == base) && (i == base+num)) {
sub_interval(&s_data->io_db, bad, i-bad);
printk(" nothing: probe failed.\n");
return;
} else {
@ -655,8 +649,9 @@ pcmcia_align(void *align_data, const struct resource *res,
* Adjust an existing IO region allocation, but making sure that we don't
* encroach outside the resources which the user supplied.
*/
static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s)
static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
unsigned long r_start,
unsigned long r_end)
{
struct resource_map *m;
struct socket_data *s_data = s->resource_data;
@ -669,8 +664,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
if (start > r_start || r_end > end)
continue;
ret = adjust_resource(res, r_start, r_end - r_start + 1);
break;
ret = 0;
}
return ret;
@ -689,18 +683,17 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
======================================================================*/
static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
unsigned long base, int num,
unsigned long align)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO, dev_name(&s->dev));
struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
dev_name(&s->dev));
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
if (align == 0)
align = 0x10000;
data.mask = align - 1;
data.offset = base & data.mask;
data.map = &s_data->io_db;
@ -721,10 +714,97 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
return res;
}
static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
unsigned int align)
{
int i, ret = 0;
/* Check for an already-allocated window that must conflict with
* what was asked for. It is a hack because it does not catch all
* potential conflicts, just the most obvious ones.
*/
for (i = 0; i < MAX_IO_WIN; i++) {
if (!s->io[i].res)
continue;
if (!*base)
continue;
if ((s->io[i].res->start & (align-1)) == *base)
return -EBUSY;
}
for (i = 0; i < MAX_IO_WIN; i++) {
struct resource *res = s->io[i].res;
unsigned int try;
if (res && (res->flags & IORESOURCE_BITS) !=
(attr & IORESOURCE_BITS))
continue;
if (!res) {
if (align == 0)
align = 0x10000;
res = s->io[i].res = __nonstatic_find_io_region(s,
*base, num,
align);
if (!res)
return -EINVAL;
*base = res->start;
s->io[i].res->flags =
((res->flags & ~IORESOURCE_BITS) |
(attr & IORESOURCE_BITS));
s->io[i].InUse = num;
return 0;
}
/* Try to extend top of window */
try = res->end + 1;
if ((*base == 0) || (*base == try)) {
ret = __nonstatic_adjust_io_region(s, res->start,
res->end + num);
if (!ret) {
ret = adjust_resource(s->io[i].res, res->start,
res->end - res->start + num + 1);
if (ret)
continue;
*base = try;
s->io[i].InUse += num;
return 0;
}
}
/* Try to extend bottom of window */
try = res->start - num;
if ((*base == 0) || (*base == try)) {
ret = __nonstatic_adjust_io_region(s,
res->start - num,
res->end);
if (!ret) {
ret = adjust_resource(s->io[i].res,
res->start - num,
res->end - res->start + num + 1);
if (ret)
continue;
*base = try;
s->io[i].InUse += num;
return 0;
}
}
}
return -EINVAL;
}
static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_MEM, dev_name(&s->dev));
struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
dev_name(&s->dev));
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min, max;
@ -804,7 +884,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{
struct socket_data *data = s->resource_data;
unsigned long size = end - start + 1;
unsigned long size;
int ret = 0;
#if defined(CONFIG_X86)
@ -814,6 +894,8 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
start = 0x100;
#endif
size = end - start + 1;
if (end < start)
return -EINVAL;
@ -853,23 +935,42 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
return -ENODEV;
#if defined(CONFIG_X86)
/* If this is the root bus, the risk of hitting
* some strange system devices which aren't protected
* by either ACPI resource tables or properly requested
* resources is too big. Therefore, don't do auto-adding
* of resources at the moment.
/* If this is the root bus, the risk of hitting some strange
* system devices is too high: If a driver isn't loaded, the
* resources are not claimed; even if a driver is loaded, it
* may not request all resources or even the wrong one. We
* can neither trust the rest of the kernel nor ACPI/PNP and
* CRS parsing to get it right. Therefore, use several
* safeguards:
*
* - Do not auto-add resources if the CardBus bridge is on
* the PCI root bus
*
* - Avoid any I/O ports < 0x100.
*
* - On PCI-PCI bridges, only use resources which are set up
* exclusively for the secondary PCI bus: the risk of hitting
* system devices is quite low, as they usually aren't
* connected to the secondary PCI bus.
*/
if (s->cb_dev->bus->number == 0)
return -EINVAL;
#endif
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
res = s->cb_dev->bus->resource[i];
#else
pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
#endif
if (!res)
continue;
if (res->flags & IORESOURCE_IO) {
/* safeguard against the root resource, where the
* risk of hitting any other device would be too
* high */
if (res == &ioport_resource)
continue;
dev_printk(KERN_INFO, &s->cb_dev->dev,
"pcmcia: parent PCI bridge window: %pR\n",
res);
@ -879,8 +980,12 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
}
if (res->flags & IORESOURCE_MEM) {
/* safeguard against the root resource, where the
* risk of hitting any other device would be too
* high */
if (res == &iomem_resource)
continue;
dev_printk(KERN_INFO, &s->cb_dev->dev,
"pcmcia: parent PCI bridge window: %pR\n",
res);
@ -948,8 +1053,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
struct pccard_resource_ops pccard_nonstatic_ops = {
.validate_mem = pcmcia_nonstatic_validate_mem,
.adjust_io_region = nonstatic_adjust_io_region,
.find_io = nonstatic_find_io_region,
.find_io = nonstatic_find_io,
.find_mem = nonstatic_find_mem_region,
.add_io = adjust_io,
.add_mem = adjust_memory,

View file

@ -1303,13 +1303,6 @@ static int yenta_dev_suspend_noirq(struct device *dev)
pci_read_config_dword(pdev, 17*4, &socket->saved_state[1]);
pci_disable_device(pdev);
/*
* Some laptops (IBM T22) do not like us putting the Cardbus
* bridge into D3. At a guess, some other laptop will
* probably require this, so leave it commented out for now.
*/
/* pci_set_power_state(dev, 3); */
return 0;
}