Commit a2e28fc1 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6:
  pcmcia: disable pcmcia ioctl for !ARM, prepare for removal
  pcmcia: CodingStyle fixes
  pcmcia: alchemy: fixup wrong comments
  pcmcia: remove irq_list parameter from pd6729
  yenta_socket: ENE CB712 CardBus bridge needs special treatment with Echo Audio Indigo soundcards
parents 03a2c4d7 a3f916f2
...@@ -117,19 +117,25 @@ Who: Mauro Carvalho Chehab <mchehab@infradead.org> ...@@ -117,19 +117,25 @@ Who: Mauro Carvalho Chehab <mchehab@infradead.org>
--------------------------- ---------------------------
What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl]) What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
When: November 2005 When: 2.6.35/2.6.36
Files: drivers/pcmcia/: pcmcia_ioctl.c Files: drivers/pcmcia/: pcmcia_ioctl.c
Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a
normal hotpluggable bus, and with it using the default kernel normal hotpluggable bus, and with it using the default kernel
infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
control ioctl needed by cardmgr and cardctl from pcmcia-cs is control ioctl needed by cardmgr and cardctl from pcmcia-cs is
unnecessary, and makes further cleanups and integration of the unnecessary and potentially harmful (it does not provide for
proper locking), and makes further cleanups and integration of the
PCMCIA subsystem into the Linux kernel device driver model more PCMCIA subsystem into the Linux kernel device driver model more
difficult. The features provided by cardmgr and cardctl are either difficult. The features provided by cardmgr and cardctl are either
handled by the kernel itself now or are available in the new handled by the kernel itself now or are available in the new
pcmciautils package available at pcmciautils package available at
http://kernel.org/pub/linux/utils/kernel/pcmcia/ http://kernel.org/pub/linux/utils/kernel/pcmcia/
Who: Dominik Brodowski <linux@brodo.de>
For all architectures except ARM, the associated config symbol
has been removed from kernel 2.6.34; for ARM, it will be likely
be removed from kernel 2.6.35. The actual code will then likely
be removed from kernel 2.6.36.
Who: Dominik Brodowski <linux@dominikbrodowski.net>
--------------------------- ---------------------------
......
...@@ -51,17 +51,23 @@ config PCMCIA_LOAD_CIS ...@@ -51,17 +51,23 @@ config PCMCIA_LOAD_CIS
config PCMCIA_IOCTL config PCMCIA_IOCTL
bool "PCMCIA control ioctl (obsolete)" bool "PCMCIA control ioctl (obsolete)"
depends on PCMCIA depends on PCMCIA && ARM && !SMP && !PREEMPT
default y default y
help help
If you say Y here, the deprecated ioctl interface to the PCMCIA If you say Y here, the deprecated ioctl interface to the PCMCIA
subsystem will be built. It is needed by cardmgr and cardctl subsystem will be built. It is needed by the deprecated pcmcia-cs
(pcmcia-cs) to function properly. tools (cardmgr, cardctl) to function properly.
You should use the new pcmciautils package instead (see You should use the new pcmciautils package instead (see
<file:Documentation/Changes> for location and details). <file:Documentation/Changes> for location and details).
If unsure, say Y. 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 config CARDBUS
bool "32-bit CardBus support" bool "32-bit CardBus support"
......
...@@ -71,7 +71,7 @@ int __ref cb_alloc(struct pcmcia_socket *s) ...@@ -71,7 +71,7 @@ int __ref cb_alloc(struct pcmcia_socket *s)
unsigned int max, pass; unsigned int max, pass;
s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
pci_fixup_cardbus(bus); pci_fixup_cardbus(bus);
max = bus->secondary; max = bus->secondary;
for (pass = 0; pass < 2; pass++) for (pass = 0; pass < 2; pass++)
......
...@@ -54,46 +54,44 @@ static const u_int exponent[] = { ...@@ -54,46 +54,44 @@ static const u_int exponent[] = {
/* Upper limit on reasonable # of tuples */ /* Upper limit on reasonable # of tuples */
#define MAX_TUPLES 200 #define MAX_TUPLES 200
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
/* 16-bit CIS? */ /* 16-bit CIS? */
static int cis_width; static int cis_width;
module_param(cis_width, int, 0444); module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s) void release_cis_mem(struct pcmcia_socket *s)
{ {
mutex_lock(&s->ops_mutex); mutex_lock(&s->ops_mutex);
if (s->cis_mem.flags & MAP_ACTIVE) { if (s->cis_mem.flags & MAP_ACTIVE) {
s->cis_mem.flags &= ~MAP_ACTIVE; s->cis_mem.flags &= ~MAP_ACTIVE;
s->ops->set_mem_map(s, &s->cis_mem); s->ops->set_mem_map(s, &s->cis_mem);
if (s->cis_mem.res) { if (s->cis_mem.res) {
release_resource(s->cis_mem.res); release_resource(s->cis_mem.res);
kfree(s->cis_mem.res); kfree(s->cis_mem.res);
s->cis_mem.res = NULL; s->cis_mem.res = NULL;
}
iounmap(s->cis_virt);
s->cis_virt = NULL;
} }
iounmap(s->cis_virt); mutex_unlock(&s->ops_mutex);
s->cis_virt = NULL;
}
mutex_unlock(&s->ops_mutex);
} }
/* /**
* Map the card memory at "card_offset" into virtual space. * set_cis_map() - map the card memory at "card_offset" into virtual space.
*
* If flags & MAP_ATTRIB, map the attribute space, otherwise * If flags & MAP_ATTRIB, map the attribute space, otherwise
* map the memory space. * map the memory space.
* *
* Must be called with ops_mutex held. * Must be called with ops_mutex held.
*/ */
static void __iomem * static void __iomem *set_cis_map(struct pcmcia_socket *s,
set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) unsigned int card_offset, unsigned int flags)
{ {
pccard_mem_map *mem = &s->cis_mem; pccard_mem_map *mem = &s->cis_mem;
int ret; int ret;
if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); mem->res = pcmcia_find_mem_region(0, s->map_size,
s->map_size, 0, s);
if (mem->res == NULL) { if (mem->res == NULL) {
dev_printk(KERN_NOTICE, &s->dev, dev_printk(KERN_NOTICE, &s->dev,
"cs: unable to map card memory!\n"); "cs: unable to map card memory!\n");
...@@ -124,165 +122,170 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag ...@@ -124,165 +122,170 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
return s->cis_virt; return s->cis_virt;
} }
/*======================================================================
Low-level functions to read and write CIS memory. I think the
write routine is only useful for writing one-byte registers.
======================================================================*/
/* Bits in attr field */ /* Bits in attr field */
#define IS_ATTR 1 #define IS_ATTR 1
#define IS_INDIRECT 8 #define IS_INDIRECT 8
/**
* pcmcia_read_cis_mem() - low-level function to read CIS memory
*/
int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr) u_int len, void *ptr)
{ {
void __iomem *sys, *end; void __iomem *sys, *end;
unsigned char *buf = ptr; unsigned char *buf = ptr;
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 */
u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
if (attr & IS_ATTR) {
addr *= 2;
flags = ICTRL0_AUTOINC;
}
sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
memset(ptr, 0xff, len);
mutex_unlock(&s->ops_mutex);
return -1;
}
writeb(flags, sys+CISREG_ICTRL0); mutex_lock(&s->ops_mutex);
writeb(addr & 0xff, sys+CISREG_IADDR0); if (attr & IS_INDIRECT) {
writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); /* Indirect accesses use a bunch of special registers at fixed
writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); locations in common memory */
writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
for ( ; len > 0; len--, buf++) if (attr & IS_ATTR) {
*buf = readb(sys+CISREG_IDATA0); addr *= 2;
} else { flags = ICTRL0_AUTOINC;
u_int inc = 1, card_offset, flags; }
if (addr > CISTPL_MAX_CIS_SIZE)
dev_dbg(&s->dev, "attempt to read CIS mem at addr %#x", addr);
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
card_offset = addr & ~(s->map_size-1); sys = set_cis_map(s, 0, MAP_ACTIVE |
while (len) { ((cis_width) ? MAP_16BIT : 0));
sys = set_cis_map(s, card_offset, flags); if (!sys) {
if (!sys) { dev_dbg(&s->dev, "could not map memory\n");
dev_dbg(&s->dev, "could not map memory\n"); memset(ptr, 0xff, len);
memset(ptr, 0xff, len); mutex_unlock(&s->ops_mutex);
mutex_unlock(&s->ops_mutex); return -1;
return -1; }
}
end = sys + s->map_size; writeb(flags, sys+CISREG_ICTRL0);
sys = sys + (addr & (s->map_size-1)); writeb(addr & 0xff, sys+CISREG_IADDR0);
for ( ; len > 0; len--, buf++, sys += inc) { writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
if (sys == end) writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
break; writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
*buf = readb(sys); for ( ; len > 0; len--, buf++)
} *buf = readb(sys+CISREG_IDATA0);
card_offset += s->map_size; } else {
addr = 0; u_int inc = 1, card_offset, flags;
if (addr > CISTPL_MAX_CIS_SIZE)
dev_dbg(&s->dev,
"attempt to read CIS mem at addr %#x", addr);
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
card_offset = addr & ~(s->map_size-1);
while (len) {
sys = set_cis_map(s, card_offset, flags);
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;
sys = sys + (addr & (s->map_size-1));
for ( ; len > 0; len--, buf++, sys += inc) {
if (sys == end)
break;
*buf = readb(sys);
}
card_offset += s->map_size;
addr = 0;
}
} }
} mutex_unlock(&s->ops_mutex);
mutex_unlock(&s->ops_mutex); dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", *(u_char *)(ptr+0), *(u_char *)(ptr+1),
*(u_char *)(ptr+0), *(u_char *)(ptr+1), *(u_char *)(ptr+2), *(u_char *)(ptr+3));
*(u_char *)(ptr+2), *(u_char *)(ptr+3)); return 0;
return 0;
} }
/**
* pcmcia_write_cis_mem() - low-level function to write CIS memory
*
* Probably only useful for writing one-byte registers.
*/
void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr) u_int len, void *ptr)
{ {
void __iomem *sys, *end; void __iomem *sys, *end;
unsigned char *buf = ptr; unsigned char *buf = ptr;
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 */
u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
if (attr & IS_ATTR) {
addr *= 2;
flags = ICTRL0_AUTOINC;
}
sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); dev_dbg(&s->dev,
if (!sys) { "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
dev_dbg(&s->dev, "could not map memory\n");
mutex_unlock(&s->ops_mutex);
return; /* FIXME: Error */
}
writeb(flags, sys+CISREG_ICTRL0); mutex_lock(&s->ops_mutex);
writeb(addr & 0xff, sys+CISREG_IADDR0); if (attr & IS_INDIRECT) {
writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); /* Indirect accesses use a bunch of special registers at fixed
writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); locations in common memory */
writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
for ( ; len > 0; len--, buf++) if (attr & IS_ATTR) {
writeb(*buf, sys+CISREG_IDATA0); addr *= 2;
} else { flags = ICTRL0_AUTOINC;
u_int inc = 1, card_offset, flags; }
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr & IS_ATTR) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
card_offset = addr & ~(s->map_size-1); sys = set_cis_map(s, 0, MAP_ACTIVE |
while (len) { ((cis_width) ? MAP_16BIT : 0));
sys = set_cis_map(s, card_offset, flags); if (!sys) {
if (!sys) { dev_dbg(&s->dev, "could not map memory\n");
dev_dbg(&s->dev, "could not map memory\n"); mutex_unlock(&s->ops_mutex);
mutex_unlock(&s->ops_mutex); return; /* FIXME: Error */
return; /* FIXME: error */ }
}
writeb(flags, sys+CISREG_ICTRL0);
end = sys + s->map_size; writeb(addr & 0xff, sys+CISREG_IADDR0);
sys = sys + (addr & (s->map_size-1)); writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
for ( ; len > 0; len--, buf++, sys += inc) { writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
if (sys == end) writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
break; for ( ; len > 0; len--, buf++)
writeb(*buf, sys); writeb(*buf, sys+CISREG_IDATA0);
} } else {
card_offset += s->map_size; u_int inc = 1, card_offset, flags;
addr = 0;
}
}
mutex_unlock(&s->ops_mutex);
}
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr & IS_ATTR) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
/*====================================================================== card_offset = addr & ~(s->map_size-1);
while (len) {
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 */
}
This is a wrapper around read_cis_mem, with the same interface, end = sys + s->map_size;
but which caches information, for cards whose CIS may not be sys = sys + (addr & (s->map_size-1));
readable all the time. for ( ; len > 0; len--, buf++, sys += inc) {
if (sys == end)
break;
writeb(*buf, sys);
}
card_offset += s->map_size;
addr = 0;
}
}
mutex_unlock(&s->ops_mutex);
}
======================================================================*/
/**
* read_cis_cache() - read CIS memory or its associated cache
*
* This is a wrapper around read_cis_mem, with the same interface,
* but which caches information, for cards whose CIS may not be
* readable all the time.
*/
static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
size_t len, void *ptr) size_t len, void *ptr)
{ {
...@@ -353,7 +356,6 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) ...@@ -353,7 +356,6 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
* This destroys the CIS cache but keeps any fake CIS alive. Must be * This destroys the CIS cache but keeps any fake CIS alive. Must be
* called with ops_mutex held. * called with ops_mutex held.
*/ */
void destroy_cis_cache(struct pcmcia_socket *s) void destroy_cis_cache(struct pcmcia_socket *s)
{ {
struct list_head *l, *n; struct list_head *l, *n;
...@@ -366,13 +368,9 @@ void destroy_cis_cache(struct pcmcia_socket *s) ...@@ -366,13 +368,9 @@ void destroy_cis_cache(struct pcmcia_socket *s)
} }
} }
/*====================================================================== /**
* verify_cis_cache() - does the CIS match what is in the CIS cache?
This verifies if the CIS of a card matches what is in the CIS */
cache.
======================================================================*/
int verify_cis_cache(struct pcmcia_socket *s) int verify_cis_cache(struct pcmcia_socket *s)
{ {
struct cis_cache_entry *cis; struct cis_cache_entry *cis;
...@@ -404,13 +402,12 @@ int verify_cis_cache(struct pcmcia_socket *s) ...@@ -404,13 +402,12 @@ int verify_cis_cache(struct pcmcia_socket *s)
return 0; return 0;
} }
/*====================================================================== /**
* pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS
For really bad cards, we provide a facility for uploading a *
replacement CIS. * For really bad cards, we provide a facility for uploading a
* replacement CIS.
======================================================================*/ */
int pcmcia_replace_cis(struct pcmcia_socket *s, int pcmcia_replace_cis(struct pcmcia_socket *s,
const u8 *data, const size_t len) const u8 *data, const size_t len)
{ {
...@@ -433,17 +430,13 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, ...@@ -433,17 +430,13 @@ int pcmcia_replace_cis(struct pcmcia_socket *s,
return 0; return 0;
} }
/*====================================================================== /* The high-level CIS tuple services */
The high-level CIS tuple services
======================================================================*/
typedef struct tuple_flags { typedef struct tuple_flags {
u_int link_space:4; u_int link_space:4;
u_int has_link:1; u_int has_link:1;
u_int mfc_fn:3; u_int mfc_fn:3;
u_int space:4; u_int space:4;
} tuple_flags; } tuple_flags;
#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
...@@ -451,982 +444,961 @@ typedef struct tuple_flags { ...@@ -451,982 +444,961 @@ typedef struct tuple_flags {
#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) #define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
#define SPACE(f) (((tuple_flags *)(&(f)))->space) #define SPACE(f) (((tuple_flags *)(&(f)))->space)
int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
tuple_t *tuple)
{ {
if (!s) if (!s)
return -EINVAL; return -EINVAL;
if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
return -ENODEV; return -ENODEV;
tuple->TupleLink = tuple->Flags = 0; tuple->TupleLink = tuple->Flags = 0;
/* Assume presence of a LONGLINK_C to address 0 */ /* Assume presence of a LONGLINK_C to address 0 */
tuple->CISOffset = tuple->LinkOffset = 0; tuple->CISOffset = tuple->LinkOffset = 0;
SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
cisdata_t req = tuple->DesiredTuple; cisdata_t req = tuple->DesiredTuple;
tuple->DesiredTuple = CISTPL_LONGLINK_MFC; tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
if (pccard_get_next_tuple(s, function, tuple) == 0) { if (pccard_get_next_tuple(s, function, tuple) == 0) {
tuple->DesiredTuple = CISTPL_LINKTARGET; tuple->DesiredTuple = CISTPL_LINKTARGET;
if (pccard_get_next_tuple(s, function, tuple) != 0) if (pccard_get_next_tuple(s, function, tuple) != 0)
return -ENOSPC; return -ENOSPC;
} else } else
tuple->CISOffset = tuple->TupleLink = 0; tuple->CISOffset = tuple->TupleLink = 0;
tuple->DesiredTuple = req; tuple->DesiredTuple = req;
} }
return pccard_get_next_tuple(s, function, tuple); return pccard_get_next_tuple(s, function, tuple);
} }
static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
{ {
u_char link[5]; u_char link[5];
u_int ofs; u_int ofs;
int ret; int ret;
if (MFC_FN(tuple->Flags)) { if (MFC_FN(tuple->Flags)) {
/* Get indirect link from the MFC tuple */ /* Get indirect link from the MFC tuple */
ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), ret = read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link); tuple->LinkOffset, 5, link);
if (ret) if (ret)
return -1;
ofs = get_unaligned_le32(link + 1);
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
MFC_FN(tuple->Flags)--;
} else if (HAS_LINK(tuple->Flags)) {
ofs = tuple->LinkOffset;
SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
HAS_LINK(tuple->Flags) = 0;
} else
return -1; return -1;
ofs = get_unaligned_le32(link + 1);
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); if (SPACE(tuple->Flags)) {
/* Move to the next indirect link */ /* This is ugly, but a common CIS error is to code the long
tuple->LinkOffset += 5; link offset incorrectly, so we check the right spot... */
MFC_FN(tuple->Flags)--; ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
} else if (HAS_LINK(tuple->Flags)) { if (ret)
ofs = tuple->LinkOffset; return -1;
SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
HAS_LINK(tuple->Flags) = 0; (strncmp(link+2, "CIS", 3) == 0))
} else { return ofs;
return -1; remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
} /* Then, we try the wrong spot... */
if (SPACE(tuple->Flags)) { ofs = ofs >> 1;
/* This is ugly, but a common CIS error is to code the long }
link offset incorrectly, so we check the right spot... */
ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
if (ret) if (ret)
return -1; return -1;
if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
(strncmp(link+2, "CIS", 3) == 0)) (strncmp(link+2, "CIS", 3) == 0))
return ofs; return ofs;
remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
/* Then, we try the wrong spot... */ return -1;
ofs = ofs >> 1;
}
ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
if (ret)
return -1;
if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
(strncmp(link+2, "CIS", 3) == 0))
return ofs;
remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
return -1;
} }
int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
tuple_t *tuple)
{ {
u_char link[2], tmp; u_char link[2], tmp;
int ofs, i, attr; int ofs, i, attr;
int ret; int ret;
if (!s)
return -EINVAL;
if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
return -ENODEV;
link[1] = tuple->TupleLink;
ofs = tuple->CISOffset + tuple->TupleLink;
attr = SPACE(tuple->Flags);
for (i = 0; i < MAX_TUPLES; i++) {
if (link[1] == 0xff) {
link[0] = CISTPL_END;
} else {
ret = read_cis_cache(s, attr, ofs, 2, link);
if (ret)
return -1;
if (link[0] == CISTPL_NULL) {
ofs++; continue;
}
}
/* End of chain? Follow long link if possible */ if (!s)
if (link[0] == CISTPL_END) { return -EINVAL;
ofs = follow_link(s, tuple); if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
if (ofs < 0) return -ENODEV;
return -ENOSPC;
attr = SPACE(tuple->Flags);
ret = read_cis_cache(s, attr, ofs, 2, link);
if (ret)
return -1;
}
/* Is this a link tuple? Make a note of it */ link[1] = tuple->TupleLink;
if ((link[0] == CISTPL_LONGLINK_A) || ofs = tuple->CISOffset + tuple->TupleLink;
(link[0] == CISTPL_LONGLINK_C) || attr = SPACE(tuple->Flags);
(link[0] == CISTPL_LONGLINK_MFC) ||
(link[0] == CISTPL_LINKTARGET) || for (i = 0; i < MAX_TUPLES; i++) {
(link[0] == CISTPL_INDIRECT) || if (link[1] == 0xff)
(link[0] == CISTPL_NO_LINK)) { link[0] = CISTPL_END;
switch (link[0]) { else {
case CISTPL_LONGLINK_A: ret = read_cis_cache(s, attr, ofs, 2, link);
HAS_LINK(tuple->Flags) = 1; if (ret)
LINK_SPACE(tuple->Flags) = attr | IS_ATTR; return -1;
ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); if (link[0] == CISTPL_NULL) {
if (ret) ofs++;
return -1; continue;
break; }
case CISTPL_LONGLINK_C:
HAS_LINK(tuple->Flags) = 1;
LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
if (ret)
return -1;
break;
case CISTPL_INDIRECT:
HAS_LINK(tuple->Flags) = 1;
LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
tuple->LinkOffset = 0;
break;
case CISTPL_LONGLINK_MFC:
tuple->LinkOffset = ofs + 3;
LINK_SPACE(tuple->Flags) = attr;
if (function == BIND_FN_ALL) {
/* Follow all the MFC links */
ret = read_cis_cache(s, attr, ofs+2, 1, &tmp);
if (ret)
return -1;
MFC_FN(tuple->Flags) = tmp;
} else {
/* Follow exactly one of the links */
MFC_FN(tuple->Flags) = 1;
tuple->LinkOffset += function * 5;
} }
break;
case CISTPL_NO_LINK:
HAS_LINK(tuple->Flags) = 0;
break;
}
if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
(tuple->DesiredTuple == RETURN_FIRST_TUPLE))
break;
} else
if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
break;
if (link[0] == tuple->DesiredTuple) /* End of chain? Follow long link if possible */
break; if (link[0] == CISTPL_END) {
ofs += link[1] + 2; ofs = follow_link(s, tuple);
} if (ofs < 0)
if (i == MAX_TUPLES) { return -ENOSPC;
dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n"); attr = SPACE(tuple->Flags);
return -ENOSPC; ret = read_cis_cache(s, attr, ofs, 2, link);
} if (ret)
return -1;
tuple->TupleCode = link[0]; }
tuple->TupleLink = link[1];
tuple->CISOffset = ofs + 2;
return 0;
}
/*====================================================================*/ /* Is this a link tuple? Make a note of it */
if ((link[0] == CISTPL_LONGLINK_A) ||
(link[0] == CISTPL_LONGLINK_C) ||
(link[0] == CISTPL_LONGLINK_MFC) ||
(link[0] == CISTPL_LINKTARGET) ||
(link[0] == CISTPL_INDIRECT) ||
(link[0] == CISTPL_NO_LINK)) {
switch (link[0]) {
case CISTPL_LONGLINK_A:
HAS_LINK(tuple->Flags) = 1;
LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
ret = read_cis_cache(s, attr, ofs+2, 4,
&tuple->LinkOffset);
if (ret)
return -1;
break;
case CISTPL_LONGLINK_C:
HAS_LINK(tuple->Flags) = 1;
LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
ret = read_cis_cache(s, attr, ofs+2, 4,
&tuple->LinkOffset);
if (ret)
return -1;
break;
case CISTPL_INDIRECT:
HAS_LINK(tuple->Flags) = 1;
LINK_SPACE(tuple->Flags) = IS_ATTR |
IS_INDIRECT;
tuple->LinkOffset = 0;
break;
case CISTPL_LONGLINK_MFC:
tuple->LinkOffset = ofs + 3;
LINK_SPACE(tuple->Flags) = attr;
if (function == BIND_FN_ALL) {
/* Follow all the MFC links */
ret = read_cis_cache(s, attr, ofs+2,
1, &tmp);
if (ret)
return -1;
MFC_FN(tuple->Flags) = tmp;
} else {
/* Follow exactly one of the links */
MFC_FN(tuple->Flags) = 1;
tuple->LinkOffset += function * 5;
}
break;
case CISTPL_NO_LINK:
HAS_LINK(tuple->Flags) = 0;
break;
}
if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
(tuple->DesiredTuple == RETURN_FIRST_TUPLE))
break;
} else
if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
break;
if (link[0] == tuple->DesiredTuple)
break;
ofs += link[1] + 2;
}
if (i == MAX_TUPLES) {
dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
return -ENOSPC;
}
#define _MIN(a, b) (((a) < (b)) ? (a) : (b)) tuple->TupleCode = link[0];
tuple->TupleLink = link[1];
tuple->CISOffset = ofs + 2;
return 0;
}
int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
{ {
u_int len; u_int len;
int ret; int ret;
if (!s) if (!s)
return -EINVAL; return -EINVAL;
if (tuple->TupleLink < tuple->TupleOffset) if (tuple->TupleLink < tuple->TupleOffset)
return -ENOSPC; return -ENOSPC;
len = tuple->TupleLink - tuple->TupleOffset; len = tuple->TupleLink - tuple->TupleOffset;
tuple->TupleDataLen = tuple->TupleLink; tuple->TupleDataLen = tuple->TupleLink;
if (len == 0) if (len == 0)
return 0;
ret = read_cis_cache(s, SPACE(tuple->Flags),
tuple->CISOffset + tuple->TupleOffset,
min(len, (u_int) tuple->TupleDataMax),
tuple->TupleData);
if (ret)
return -1;
return 0; return 0;
ret = read_cis_cache(s, SPACE(tuple->Flags),
tuple->CISOffset + tuple->TupleOffset,
_MIN(len, tuple->TupleDataMax), tuple->TupleData);
if (ret)
return -1;
return 0;
} }
/*====================================================================== /* Parsing routines for individual tuples */
Parsing routines for individual tuples
======================================================================*/
static int parse_device(tuple_t *tuple, cistpl_device_t *device) static int parse_device(tuple_t *tuple, cistpl_device_t *device)
{ {
int i; int i;
u_char scale; u_char scale;
u_char *p, *q; u_char *p, *q;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
device->ndev = 0; device->ndev = 0;
for (i = 0; i < CISTPL_MAX_DEVICES; i++) { for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
if (*p == 0xff) if (*p == 0xff)
break; break;
device->dev[i].type = (*p >> 4); device->dev[i].type = (*p >> 4);
device->dev[i].wp = (*p & 0x08) ? 1 : 0; device->dev[i].wp = (*p & 0x08) ? 1 : 0;
switch (*p & 0x07) { switch (*p & 0x07) {
case 0: case 0:
device->dev[i].speed = 0; device->dev[i].speed = 0;
break; break;
case 1: case 1:
device->dev[i].speed = 250; device->dev[i].speed = 250;
break; break;
case 2: case 2:
device->dev[i].speed = 200; device->dev[i].speed = 200;
break; break;
case 3: case 3:
device->dev[i].speed = 150; device->dev[i].speed = 150;
break; break;
case 4: case 4:
device->dev[i].speed = 100; device->dev[i].speed = 100;
break; break;
case 7: case 7:
if (++p == q)
return -EINVAL;
device->dev[i].speed = SPEED_CVT(*p);
while (*p & 0x80)
if (++p == q) if (++p == q)
return -EINVAL; return -EINVAL;
break; device->dev[i].speed = SPEED_CVT(*p);
default: while (*p & 0x80)
return -EINVAL; if (++p == q)
} return -EINVAL;
break;
default:
return -EINVAL;
}
if (++p == q) if (++p == q)
return -EINVAL; return -EINVAL;
if (*p == 0xff) if (*p == 0xff)
break; break;
scale = *p & 7; scale = *p & 7;
if (scale == 7) if (scale == 7)
return -EINVAL; return -EINVAL;
device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
device->ndev++; device->ndev++;
if (++p == q) if (++p == q)
break; break;
} }
return 0; return 0;
} }
/*====================================================================*/
static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
{ {
u_char *p; u_char *p;
if (tuple->TupleDataLen < 5) if (tuple->TupleDataLen < 5)
return -EINVAL; return -EINVAL;
p = (u_char *) tuple->TupleData; p = (u_char *) tuple->TupleData;
csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
csum->len = get_unaligned_le16(p + 2); csum->len = get_unaligned_le16(p + 2);
csum->sum = *(p + 4); csum->sum = *(p + 4);
return 0; return 0;
} }
/*====================================================================*/
static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
{ {
if (tuple->TupleDataLen < 4) if (tuple->TupleDataLen < 4)
return -EINVAL; return -EINVAL;
link->addr = get_unaligned_le32(tuple->TupleData); link->addr = get_unaligned_le32(tuple->TupleData);
return 0; return 0;
} }
/*====================================================================*/
static int parse_longlink_mfc(tuple_t *tuple, static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link)
cistpl_longlink_mfc_t *link)
{ {
u_char *p; u_char *p;
int i; int i;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
link->nfn = *p; p++; link->nfn = *p; p++;
if (tuple->TupleDataLen <= link->nfn*5) if (tuple->TupleDataLen <= link->nfn*5)
return -EINVAL; return -EINVAL;
for (i = 0; i < link->nfn; i++) { for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++; link->fn[i].space = *p; p++;
link->fn[i].addr = get_unaligned_le32(p); link->fn[i].addr = get_unaligned_le32(p);
p += 4; p += 4;
} }
return 0; return 0;
} }
/*====================================================================*/
static int parse_strings(u_char *p, u_char *q, int max, static int parse_strings(u_char *p, u_char *q, int max,
char *s, u_char *ofs, u_char *found) char *s, u_char *ofs, u_char *found)
{ {
int i, j, ns; int i, j, ns;
if (p == q) if (p == q)
return -EINVAL; return -EINVAL;
ns = 0; j = 0; ns = 0; j = 0;
for (i = 0; i < max; i++) { for (i = 0; i < max; i++) {
if (*p == 0xff) if (*p == 0xff)
break; break;
ofs[i] = j; ofs[i] = j;
ns++; ns++;
for (;;) { for (;;) {
s[j++] = (*p == 0xff) ? '\0' : *p; s[j++] = (*p == 0xff) ? '\0' : *p;
if ((*p == '\0') || (*p == 0xff)) if ((*p == '\0') || (*p == 0xff))
break; break;
if (++p == q) if (++p == q)
return -EINVAL; return -EINVAL;
}
if ((*p == 0xff) || (++p == q))
break;
} }
if ((*p == 0xff) || (++p == q)) if (found) {
break; *found = ns;
} return 0;
if (found) { }
*found = ns;
return 0;
} else {
return (ns == max) ? 0 : -EINVAL; return (ns == max) ? 0 : -EINVAL;
}
} }
/*====================================================================*/
static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
{ {
u_char *p, *q; u_char *p, *q;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
vers_1->major = *p; p++; vers_1->major = *p; p++;
vers_1->minor = *p; p++; vers_1->minor = *p; p++;
if (p >= q) if (p >= q)
return -EINVAL; return -EINVAL;
return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
vers_1->str, vers_1->ofs, &vers_1->ns); vers_1->str, vers_1->ofs, &vers_1->ns);
} }
/*====================================================================*/
static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
{ {
u_char *p, *q; u_char *p, *q;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
altstr->str, altstr->ofs, &altstr->ns); altstr->str, altstr->ofs, &altstr->ns);
} }
/*====================================================================*/
static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
{ {
u_char *p, *q; u_char *p, *q;
int nid; int nid;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
if (p > q-2) if (p > q-2)
break; break;
jedec->id[nid].mfr = p[0]; jedec->id[nid].mfr = p[0];
jedec->id[nid].info = p[1]; jedec->id[nid].info = p[1];
p += 2; p += 2;
} }
jedec->nid = nid; jedec->nid = nid;
return 0; return 0;
} }
/*====================================================================*/
static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{ {
if (tuple->TupleDataLen < 4) if (tuple->TupleDataLen < 4)
return -EINVAL; return -EINVAL;
m->manf = get_unaligned_le16(tuple->TupleData); m->manf = get_unaligned_le16(tuple->TupleData);
m->card = get_unaligned_le16(tuple->TupleData + 2); m->card = get_unaligned_le16(tuple->TupleData + 2);
return 0; return 0;
} }
/*====================================================================*/
static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
{ {
u_char *p; u_char *p;
if (tuple->TupleDataLen < 2) if (tuple->TupleDataLen < 2)
return -EINVAL; return -EINVAL;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
f->func = p[0]; f->func = p[0];
f->sysinit = p[1]; f->sysinit = p[1];
return 0; return 0;
} }
/*====================================================================*/
static int parse_funce(tuple_t *tuple, cistpl_funce_t *f) static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
{ {
u_char *p; u_char *p;
int i; int i;
if (tuple->TupleDataLen < 1) if (tuple->TupleDataLen < 1)
return -EINVAL; return -EINVAL;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
f->type = p[0]; f->type = p[0];
for (i = 1; i < tuple->TupleDataLen; i++) for (i = 1; i < tuple->TupleDataLen; i++)
f->data[i-1] = p[i]; f->data[i-1] = p[i];
return 0; return 0;
} }
/*====================================================================*/
static int parse_config(tuple_t *tuple, cistpl_config_t *config) static int parse_config(tuple_t *tuple, cistpl_config_t *config)
{ {
int rasz, rmsz, i; int rasz, rmsz, i;
u_char *p; u_char *p;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
rasz = *p & 0x03; rasz = *p & 0x03;
rmsz = (*p & 0x3c) >> 2; rmsz = (*p & 0x3c) >> 2;
if (tuple->TupleDataLen < rasz+rmsz+4) if (tuple->TupleDataLen < rasz+rmsz+4)
return -EINVAL; return -EINVAL;
config->last_idx = *(++p); config->last_idx = *(++p);
p++; p++;
config->base = 0; config->base = 0;
for (i = 0; i <= rasz; i++) for (i = 0; i <= rasz; i++)
config->base += p[i] << (8*i); config->base += p[i] << (8*i);
p += rasz+1; p += rasz+1;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
config->rmask[i] = 0; config->rmask[i] = 0;
for (i = 0; i <= rmsz; i++) for (i = 0; i <= rmsz; i++)
config->rmask[i>>2] += p[i] << (8*(i%4)); config->rmask[i>>2] += p[i] << (8*(i%4));
config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
return 0; return 0;
} }
/*====================================================================== /* The following routines are all used to parse the nightmarish
* config table entries.
*/
static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr)
{
int i;
u_int scale;
The following routines are all used to parse the nightmarish if (p == q)
config table entries. return NULL;
pwr->present = *p;
pwr->flags = 0;
p++;
for (i = 0; i < 7; i++)
if (pwr->present & (1<<i)) {
if (p == q)
return NULL;
pwr->param[i] = POWER_CVT(*p);
scale = POWER_SCALE(*p);
while (*p & 0x80) {
if (++p == q)
return NULL;
if ((*p & 0x7f) < 100)
pwr->param[i] +=
(*p & 0x7f) * scale / 100;
else if (*p == 0x7d)
pwr->flags |= CISTPL_POWER_HIGHZ_OK;
else if (*p == 0x7e)
pwr->param[i] = 0;
else if (*p == 0x7f)
pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
else
return NULL;
}
p++;
}
return p;
}
======================================================================*/
static u_char *parse_power(u_char *p, u_char *q, static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing)
cistpl_power_t *pwr)
{ {
int i; u_char scale;
u_int scale;
if (p == q)
if (p == q) return NULL;
return NULL; scale = *p;
pwr->present = *p; if ((scale & 3) != 3) {
pwr->flags = 0;
p++;
for (i = 0; i < 7; i++)
if (pwr->present & (1<<i)) {
if (p == q)
return NULL;
pwr->param[i] = POWER_CVT(*p);
scale = POWER_SCALE(*p);
while (*p & 0x80) {
if (++p == q) if (++p == q)
return NULL; return NULL;
if ((*p & 0x7f) < 100) timing->wait = SPEED_CVT(*p);
pwr->param[i] += (*p & 0x7f) * scale / 100; timing->waitscale = exponent[scale & 3];
else if (*p == 0x7d) } else
pwr->flags |= CISTPL_POWER_HIGHZ_OK; timing->wait = 0;
else if (*p == 0x7e) scale >>= 2;
pwr->param[i] = 0; if ((scale & 7) != 7) {
else if (*p == 0x7f) if (++p == q)
pwr->flags |= CISTPL_POWER_HIGHZ_REQ; return NULL;
else timing->ready = SPEED_CVT(*p);
return NULL; timing->rdyscale = exponent[scale & 7];
} } else
p++; timing->ready = 0;
} scale >>= 3;
return p; if (scale != 7) {
if (++p == q)
return NULL;
timing->reserved = SPEED_CVT(*p);
timing->rsvscale = exponent[scale];
} else
timing->reserved = 0;
p++;
return p;
} }
/*====================================================================*/
static u_char *parse_timing(u_char *p, u_char *q, static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
cistpl_timing_t *timing)
{ {
u_char scale; int i, j, bsz, lsz;
if (p == q) if (p == q)
return NULL;
scale = *p;
if ((scale & 3) != 3) {
if (++p == q)
return NULL;
timing->wait = SPEED_CVT(*p);
timing->waitscale = exponent[scale & 3];
} else
timing->wait = 0;
scale >>= 2;
if ((scale & 7) != 7) {
if (++p == q)
return NULL; return NULL;
timing->ready = SPEED_CVT(*p); io->flags = *p;
timing->rdyscale = exponent[scale & 7];
} else if (!(*p & 0x80)) {
timing->ready = 0; io->nwin = 1;
scale >>= 3; io->win[0].base = 0;
if (scale != 7) { io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
return p+1;
}
if (++p == q) if (++p == q)
return NULL; return NULL;
timing->reserved = SPEED_CVT(*p); io->nwin = (*p & 0x0f) + 1;
timing->rsvscale = exponent[scale]; bsz = (*p & 0x30) >> 4;
} else if (bsz == 3)
timing->reserved = 0; bsz++;
p++; lsz = (*p & 0xc0) >> 6;
return p; if (lsz == 3)
} lsz++;
p++;
/*====================================================================*/
static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) for (i = 0; i < io->nwin; i++) {
{ io->win[i].base = 0;
int i, j, bsz, lsz; io->win[i].len = 1;
for (j = 0; j < bsz; j++, p++) {
if (p == q) if (p == q)
return NULL; return NULL;
io->flags = *p; io->win[i].base += *p << (j*8);
}
if (!(*p & 0x80)) { for (j = 0; j < lsz; j++, p++) {
io->nwin = 1; if (p == q)
io->win[0].base = 0; return NULL;
io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); io->win[i].len += *p << (j*8);
return p+1; }
}
if (++p == q)
return NULL;
io->nwin = (*p & 0x0f) + 1;
bsz = (*p & 0x30) >> 4;
if (bsz == 3)
bsz++;
lsz = (*p & 0xc0) >> 6;
if (lsz == 3)
lsz++;
p++;
for (i = 0; i < io->nwin; i++) {
io->win[i].base = 0;
io->win[i].len = 1;
for (j = 0; j < bsz; j++, p++) {
if (p == q)
return NULL;
io->win[i].base += *p << (j*8);
}
for (j = 0; j < lsz; j++, p++) {
if (p == q)
return NULL;
io->win[i].len += *p << (j*8);
} }
} return p;
return p;
} }
/*====================================================================*/
static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
{ {
int i, j, asz, lsz, has_ha; int i, j, asz, lsz, has_ha;
u_int len, ca, ha; u_int len, ca, ha;
if (p == q) if (p == q)
return NULL; return NULL;
mem->nwin = (*p & 0x07) + 1; mem->nwin = (*p & 0x07) + 1;
lsz = (*p & 0x18) >> 3; lsz = (*p & 0x18) >> 3;
asz = (*p & 0x60) >> 5; asz = (*p & 0x60) >> 5;
has_ha = (*p & 0x80); has_ha = (*p & 0x80);
if (++p == q) if (++p == q)
return NULL; return NULL;
for (i = 0; i < mem->nwin; i++) { for (i = 0; i < mem->nwin; i++) {
len = ca = ha = 0; len = ca = ha = 0;
for (j = 0; j < lsz; j++, p++) { for (j = 0; j < lsz; j++, p++) {
if (p == q) if (p == q)
return NULL; return NULL;
len += *p << (j*8); len += *p << (j*8);
} }
for (j = 0; j < asz; j++, p++) { for (j = 0; j < asz; j++, p++) {
if (p == q) if (p == q)
return NULL; return NULL;
ca += *p << (j*8); ca += *p << (j*8);
}
if (has_ha)
for (j = 0; j < asz; j++, p++) {
if (p == q)
return NULL;
ha += *p << (j*8);
}
mem->win[i].len = len << 8;
mem->win[i].card_addr = ca << 8;
mem->win[i].host_addr = ha << 8;
} }
if (has_ha) return p;
for (j = 0; j < asz; j++, p++) {
if (p == q)
return NULL;
ha += *p << (j*8);
}
mem->win[i].len = len << 8;
mem->win[i].card_addr = ca << 8;
mem->win[i].host_addr = ha << 8;
}
return p;
} }
/*====================================================================*/
static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
{ {
if (p == q) if (p == q)
return NULL;
irq->IRQInfo1 = *p; p++;
if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
if (p+2 > q)
return NULL; return NULL;
irq->IRQInfo2 = (p[1]<<8) + p[0]; irq->IRQInfo1 = *p; p++;
p += 2; if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
} if (p+2 > q)
return p; return NULL;
irq->IRQInfo2 = (p[1]<<8) + p[0];
p += 2;
}
return p;
} }
/*====================================================================*/
static int parse_cftable_entry(tuple_t *tuple, static int parse_cftable_entry(tuple_t *tuple,
cistpl_cftable_entry_t *entry) cistpl_cftable_entry_t *entry)
{ {
u_char *p, *q, features; u_char *p, *q, features;
p = tuple->TupleData; p = tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
entry->index = *p & 0x3f; entry->index = *p & 0x3f;
entry->flags = 0; entry->flags = 0;
if (*p & 0x40)
entry->flags |= CISTPL_CFTABLE_DEFAULT;
if (*p & 0x80) {
if (++p == q)
return -EINVAL;
if (*p & 0x10)
entry->flags |= CISTPL_CFTABLE_BVDS;
if (*p & 0x20)
entry->flags |= CISTPL_CFTABLE_WP;
if (*p & 0x40) if (*p & 0x40)
entry->flags |= CISTPL_CFTABLE_RDYBSY; entry->flags |= CISTPL_CFTABLE_DEFAULT;
if (*p & 0x80) if (*p & 0x80) {
entry->flags |= CISTPL_CFTABLE_MWAIT; if (++p == q)
entry->interface = *p & 0x0f; return -EINVAL;
} else if (*p & 0x10)
entry->interface = 0; entry->flags |= CISTPL_CFTABLE_BVDS;
if (*p & 0x20)
/* Process optional features */ entry->flags |= CISTPL_CFTABLE_WP;
if (++p == q) if (*p & 0x40)
return -EINVAL; entry->flags |= CISTPL_CFTABLE_RDYBSY;
features = *p; p++; if (*p & 0x80)
entry->flags |= CISTPL_CFTABLE_MWAIT;
/* Power options */ entry->interface = *p & 0x0f;
if ((features & 3) > 0) { } else
p = parse_power(p, q, &entry->vcc); entry->interface = 0;
if (p == NULL)
return -EINVAL;
} else
entry->vcc.present = 0;
if ((features & 3) > 1) {
p = parse_power(p, q, &entry->vpp1);
if (p == NULL)
return -EINVAL;
} else
entry->vpp1.present = 0;
if ((features & 3) > 2) {
p = parse_power(p, q, &entry->vpp2);
if (p == NULL)
return -EINVAL;
} else
entry->vpp2.present = 0;
/* Timing options */ /* Process optional features */
if (features & 0x04) { if (++p == q)
p = parse_timing(p, q, &entry->timing);
if (p == NULL)
return -EINVAL;
} else {
entry->timing.wait = 0;
entry->timing.ready = 0;
entry->timing.reserved = 0;
}
/* I/O window options */
if (features & 0x08) {
p = parse_io(p, q, &entry->io);
if (p == NULL)
return -EINVAL; return -EINVAL;
} else features = *p; p++;
entry->io.nwin = 0;
/* Interrupt options */ /* Power options */
if (features & 0x10) { if ((features & 3) > 0) {
p = parse_irq(p, q, &entry->irq); p = parse_power(p, q, &entry->vcc);
if (p == NULL) if (p == NULL)
return -EINVAL; return -EINVAL;
} else } else
entry->irq.IRQInfo1 = 0; entry->vcc.present = 0;
if ((features & 3) > 1) {
switch (features & 0x60) { p = parse_power(p, q, &entry->vpp1);
case 0x00: if (p == NULL)
entry->mem.nwin = 0; return -EINVAL;
break; } else
case 0x20: entry->vpp1.present = 0;
entry->mem.nwin = 1; if ((features & 3) > 2) {
entry->mem.win[0].len = get_unaligned_le16(p) << 8; p = parse_power(p, q, &entry->vpp2);
entry->mem.win[0].card_addr = 0; if (p == NULL)
entry->mem.win[0].host_addr = 0; return -EINVAL;
p += 2; } else
if (p > q) entry->vpp2.present = 0;
return -EINVAL;
break;
case 0x40:
entry->mem.nwin = 1;
entry->mem.win[0].len = get_unaligned_le16(p) << 8;
entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q)
return -EINVAL;
break;
case 0x60:
p = parse_mem(p, q, &entry->mem);
if (p == NULL)
return -EINVAL;
break;
}
/* Misc features */ /* Timing options */
if (features & 0x80) { if (features & 0x04) {
if (p == q) p = parse_timing(p, q, &entry->timing);
return -EINVAL; if (p == NULL)
entry->flags |= (*p << 8); return -EINVAL;
while (*p & 0x80) } else {
if (++p == q) entry->timing.wait = 0;
return -EINVAL; entry->timing.ready = 0;
p++; entry->timing.reserved = 0;
} }
entry->subtuples = q-p; /* I/O window options */
if (features & 0x08) {
p = parse_io(p, q, &entry->io);
if (p == NULL)
return -EINVAL;
} else
entry->io.nwin = 0;
/* Interrupt options */
if (features & 0x10) {
p = parse_irq(p, q, &entry->irq);
if (p == NULL)
return -EINVAL;
} else
entry->irq.IRQInfo1 = 0;
switch (features & 0x60) {
case 0x00:
entry->mem.nwin = 0;
break;
case 0x20:
entry->mem.nwin = 1;
entry->mem.win[0].len = get_unaligned_le16(p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
if (p > q)
return -EINVAL;
break;
case 0x40:
entry->mem.nwin = 1;
entry->mem.win[0].len = get_unaligned_le16(p) << 8;
entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q)
return -EINVAL;
break;
case 0x60:
p = parse_mem(p, q, &entry->mem);
if (p == NULL)
return -EINVAL;
break;
}
/* Misc features */
if (features & 0x80) {
if (p == q)
return -EINVAL;
entry->flags |= (*p << 8);
while (*p & 0x80)
if (++p == q)
return -EINVAL;
p++;
}
entry->subtuples = q-p;
return 0; return 0;
} }
/*====================================================================*/
static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
{ {
u_char *p, *q; u_char *p, *q;
int n; int n;
p = (u_char *)tuple->TupleData; p = (u_char *)tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
for (n = 0; n < CISTPL_MAX_DEVICES; n++) { for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
if (p > q-6) if (p > q-6)
break; break;
geo->geo[n].buswidth = p[0]; geo->geo[n].buswidth = p[0];
geo->geo[n].erase_block = 1 << (p[1]-1); geo->geo[n].erase_block = 1 << (p[1]-1);
geo->geo[n].read_block = 1 << (p[2]-1); geo->geo[n].read_block = 1 << (p[2]-1);
geo->geo[n].write_block = 1 << (p[3]-1); geo->geo[n].write_block = 1 << (p[3]-1);
geo->geo[n].partition = 1 << (p[4]-1); geo->geo[n].partition = 1 << (p[4]-1);
geo->geo[n].interleave = 1 << (p[5]-1); geo->geo[n].interleave = 1 << (p[5]-1);
p += 6; p += 6;
} }
geo->ngeo = n; geo->ngeo = n;
return 0; return 0;
} }
/*====================================================================*/
static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
{ {
u_char *p, *q; u_char *p, *q;
if (tuple->TupleDataLen < 10) if (tuple->TupleDataLen < 10)
return -EINVAL; return -EINVAL;
p = tuple->TupleData; p = tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
v2->vers = p[0]; v2->vers = p[0];
v2->comply = p[1]; v2->comply = p[1];
v2->dindex = get_unaligned_le16(p + 2); v2->dindex = get_unaligned_le16(p + 2);
v2->vspec8 = p[6]; v2->vspec8 = p[6];
v2->vspec9 = p[7]; v2->vspec9 = p[7];
v2->nhdr = p[8]; v2->nhdr = p[8];
p += 9; p += 9;
return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
} }
/*====================================================================*/
static int parse_org(tuple_t *tuple, cistpl_org_t *org) static int parse_org(tuple_t *tuple, cistpl_org_t *org)
{ {
u_char *p, *q; u_char *p, *q;
int i; int i;
p = tuple->TupleData; p = tuple->TupleData;
q = p + tuple->TupleDataLen; q = p + tuple->TupleDataLen;
if (p == q) if (p == q)
return -EINVAL; return -EINVAL;
org->data_org = *p; org->data_org = *p;
if (++p == q)
return -EINVAL;
for (i = 0; i < 30; i++) {
org->desc[i] = *p;
if (*p == '\0')
break;
if (++p == q) if (++p == q)
return -EINVAL; return -EINVAL;
} for (i = 0; i < 30; i++) {
return 0; org->desc[i] = *p;
if (*p == '\0')
break;
if (++p == q)
return -EINVAL;
}
return 0;
} }
/*====================================================================*/
static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
{ {
u_char *p; u_char *p;
if (tuple->TupleDataLen < 10) if (tuple->TupleDataLen < 10)
return -EINVAL; return -EINVAL;
p = tuple->TupleData; p = tuple->TupleData;
fmt->type = p[0]; fmt->type = p[0];
fmt->edc = p[1]; fmt->edc = p[1];
fmt->offset = get_unaligned_le32(p + 2); fmt->offset = get_unaligned_le32(p + 2);
fmt->length = get_unaligned_le32(p + 6); fmt->length = get_unaligned_le32(p + 6);
return 0; return 0;
} }
/*====================================================================*/
int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
{ {
int ret = 0; int ret = 0;
if (tuple->TupleDataLen > tuple->TupleDataMax) if (tuple->TupleDataLen > tuple->TupleDataMax)
return -EINVAL; return -EINVAL;
switch (tuple->TupleCode) { switch (tuple->TupleCode) {
case CISTPL_DEVICE: case CISTPL_DEVICE:
case CISTPL_DEVICE_A: case CISTPL_DEVICE_A:
ret = parse_device(tuple, &parse->device); ret = parse_device(tuple, &parse->device);
break; break;
case CISTPL_CHECKSUM: case CISTPL_CHECKSUM:
ret = parse_checksum(tuple, &parse->checksum); ret = parse_checksum(tuple, &parse->checksum);
break; break;
case CISTPL_LONGLINK_A: case CISTPL_LONGLINK_A:
case CISTPL_LONGLINK_C: case CISTPL_LONGLINK_C:
ret = parse_longlink(tuple, &parse->longlink); ret = parse_longlink(tuple, &parse->longlink);
break; break;
case CISTPL_LONGLINK_MFC: case CISTPL_LONGLINK_MFC:
ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
break; break;
case CISTPL_VERS_1: case CISTPL_VERS_1:
ret = parse_vers_1(tuple, &parse->version_1); ret = parse_vers_1(tuple, &parse->version_1);
break; break;
case CISTPL_ALTSTR: case CISTPL_ALTSTR:
ret = parse_altstr(tuple, &parse->altstr); ret = parse_altstr(tuple, &parse->altstr);
break; break;
case CISTPL_JEDEC_A: case CISTPL_JEDEC_A:
case CISTPL_JEDEC_C: case CISTPL_JEDEC_C:
ret = parse_jedec(tuple, &parse->jedec); ret = parse_jedec(tuple, &parse->jedec);
break; break;
case CISTPL_MANFID: case CISTPL_MANFID:
ret = parse_manfid(tuple, &parse->manfid); ret = parse_manfid(tuple, &parse->manfid);
break; break;
case CISTPL_FUNCID: case CISTPL_FUNCID:
ret = parse_funcid(tuple, &parse->funcid); ret = parse_funcid(tuple, &parse->funcid);
break; break;
case CISTPL_FUNCE: case CISTPL_FUNCE:
ret = parse_funce(tuple, &parse->funce); ret = parse_funce(tuple, &parse->funce);
break; break;
case CISTPL_CONFIG: case CISTPL_CONFIG:
ret = parse_config(tuple, &parse->config); ret = parse_config(tuple, &parse->config);
break; break;
case CISTPL_CFTABLE_ENTRY: case CISTPL_CFTABLE_ENTRY:
ret = parse_cftable_entry(tuple, &parse->cftable_entry); ret = parse_cftable_entry(tuple, &parse->cftable_entry);
break; break;
case CISTPL_DEVICE_GEO: case CISTPL_DEVICE_GEO:
case CISTPL_DEVICE_GEO_A: case CISTPL_DEVICE_GEO_A:
ret = parse_device_geo(tuple, &parse->device_geo); ret = parse_device_geo(tuple, &parse->device_geo);
break; break;
case CISTPL_VERS_2: case CISTPL_VERS_2:
ret = parse_vers_2(tuple, &parse->vers_2); ret = parse_vers_2(tuple, &parse->vers_2);
break; break;
case CISTPL_ORG: case CISTPL_ORG:
ret = parse_org(tuple, &parse->org); ret = parse_org(tuple, &parse->org);
break; break;
case CISTPL_FORMAT: case CISTPL_FORMAT:
case CISTPL_FORMAT_A: case CISTPL_FORMAT_A:
ret = parse_format(tuple, &parse->format); ret = parse_format(tuple, &parse->format);
break; break;
case CISTPL_NO_LINK: case CISTPL_NO_LINK:
case CISTPL_LINKTARGET: case CISTPL_LINKTARGET:
ret = 0; ret = 0;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
if (ret) if (ret)
pr_debug("parse_tuple failed %d\n", ret); pr_debug("parse_tuple failed %d\n", ret);
return ret; return ret;
} }
EXPORT_SYMBOL(pcmcia_parse_tuple); EXPORT_SYMBOL(pcmcia_parse_tuple);
/*======================================================================
This is used internally by Card Services to look up CIS stuff. /**
* pccard_read_tuple() - internal CIS tuple access
======================================================================*/ * @s: the struct pcmcia_socket where the card is inserted
* @function: the device function we loop for
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse) * @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; tuple_t tuple;
cisdata_t *buf; cisdata_t *buf;
int ret; int ret;
buf = kmalloc(256, GFP_KERNEL); buf = kmalloc(256, GFP_KERNEL);
if (buf == NULL) { if (buf == NULL) {
dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n"); dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
return -ENOMEM; return -ENOMEM;
} }
tuple.DesiredTuple = code; tuple.DesiredTuple = code;
tuple.Attributes = 0; tuple.Attributes = 0;
if (function == BIND_FN_ALL) if (function == BIND_FN_ALL)
tuple.Attributes = TUPLE_RETURN_COMMON; tuple.Attributes = TUPLE_RETURN_COMMON;
ret = pccard_get_first_tuple(s, function, &tuple); ret = pccard_get_first_tuple(s, function, &tuple);
if (ret != 0) if (ret != 0)
goto done; goto done;
tuple.TupleData = buf; tuple.TupleData = buf;
tuple.TupleOffset = 0; tuple.TupleOffset = 0;
tuple.TupleDataMax = 255; tuple.TupleDataMax = 255;
ret = pccard_get_tuple_data(s, &tuple); ret = pccard_get_tuple_data(s, &tuple);
if (ret != 0) if (ret != 0)
goto done; goto done;
ret = pcmcia_parse_tuple(&tuple, parse); ret = pcmcia_parse_tuple(&tuple, parse);
done: done:
kfree(buf); kfree(buf);
return ret; return ret;
} }
......
...@@ -42,7 +42,6 @@ struct db1x_pcmcia_sock { ...@@ -42,7 +42,6 @@ struct db1x_pcmcia_sock {
int nr; /* socket number */ int nr; /* socket number */
void *virt_io; void *virt_io;
/* the "pseudo" addresses of the PCMCIA space. */
phys_addr_t phys_io; phys_addr_t phys_io;
phys_addr_t phys_attr; phys_addr_t phys_attr;
phys_addr_t phys_mem; phys_addr_t phys_mem;
...@@ -437,7 +436,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) ...@@ -437,7 +436,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
* This includes IRQs for Carddetection/ejection, the card * This includes IRQs for Carddetection/ejection, the card
* itself and optional status change detection. * itself and optional status change detection.
* Also, the memory areas covered by a socket. For these * Also, the memory areas covered by a socket. For these
* we require the 32bit "pseudo" addresses (see the au1000.h * we require the real 36bit addresses (see the au1000.h
* header for more information). * header for more information).
*/ */
...@@ -459,11 +458,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) ...@@ -459,11 +458,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
ret = -ENODEV; ret = -ENODEV;
/* /* 36bit PCMCIA Attribute area address */
* pseudo-attr: The 32bit address of the PCMCIA attribute space
* for this socket (usually the 36bit address shifted 4 to the
* right).
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
if (!r) { if (!r) {
printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n", printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
...@@ -472,10 +467,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) ...@@ -472,10 +467,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
} }
sock->phys_attr = r->start; sock->phys_attr = r->start;
/* /* 36bit PCMCIA Memory area address */
* pseudo-mem: The 32bit address of the PCMCIA memory space for
* this socket (usually the 36bit address shifted 4 to the right)
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
if (!r) { if (!r) {
printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n", printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
...@@ -484,10 +476,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) ...@@ -484,10 +476,7 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
} }
sock->phys_mem = r->start; sock->phys_mem = r->start;
/* /* 36bit PCMCIA IO area address */
* pseudo-io: The 32bit address of the PCMCIA IO space for this
* socket (usually the 36bit address shifted 4 to the right).
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
if (!r) { if (!r) {
printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n", printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
......
...@@ -48,23 +48,13 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>"); ...@@ -48,23 +48,13 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
* Specifies the interrupt delivery mode. The default (1) is to use PCI * Specifies the interrupt delivery mode. The default (1) is to use PCI
* interrupts; a value of 0 selects ISA interrupts. This must be set for * interrupts; a value of 0 selects ISA interrupts. This must be set for
* correct operation of PCI card readers. * correct operation of PCI card readers.
*
* irq_list=i,j,...
* This list limits the set of interrupts that can be used by PCMCIA
* cards.
* The default list is 3,4,5,7,9,10,11.
* (irq_list parameter is not used, if irq_mode = 1)
*/ */
static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */ static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
static int irq_list[16];
static unsigned int irq_list_count = 0;
module_param(irq_mode, int, 0444); module_param(irq_mode, int, 0444);
module_param_array(irq_list, int, &irq_list_count, 0444);
MODULE_PARM_DESC(irq_mode, MODULE_PARM_DESC(irq_mode,
"interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1"); "interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1");
MODULE_PARM_DESC(irq_list, "interrupts that can be used by PCMCIA cards");
static DEFINE_SPINLOCK(port_lock); static DEFINE_SPINLOCK(port_lock);
...@@ -605,13 +595,7 @@ static u_int __devinit pd6729_isa_scan(void) ...@@ -605,13 +595,7 @@ static u_int __devinit pd6729_isa_scan(void)
return 0; return 0;
} }
if (irq_list_count == 0) mask0 = PD67_MASK;
mask0 = 0xffff;
else
for (i = mask0 = 0; i < irq_list_count; i++)
mask0 |= (1<<irq_list[i]);
mask0 &= PD67_MASK;
/* just find interrupts that aren't in use */ /* just find interrupts that aren't in use */
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
......
...@@ -79,9 +79,8 @@ static resource_size_t pcmcia_align(void *align_data, ...@@ -79,9 +79,8 @@ static resource_size_t pcmcia_align(void *align_data,
#ifdef CONFIG_X86 #ifdef CONFIG_X86
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
if (start & 0x300) { if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff; start = (start + 0x3ff) & ~0x3ff;
}
} }
#endif #endif
......
...@@ -218,11 +218,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) ...@@ -218,11 +218,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
ret = -ENODEV; ret = -ENODEV;
/* /* 36bit PCMCIA Attribute area address */
* pseudo-attr: The 32bit address of the PCMCIA attribute space
* for this socket (usually the 36bit address shifted 4 to the
* right).
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
if (!r) { if (!r) {
dev_err(&pdev->dev, "missing 'pcmcia-attr' resource!\n"); dev_err(&pdev->dev, "missing 'pcmcia-attr' resource!\n");
...@@ -230,10 +226,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) ...@@ -230,10 +226,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
} }
sock->phys_attr = r->start; sock->phys_attr = r->start;
/* /* 36bit PCMCIA Memory area address */
* pseudo-mem: The 32bit address of the PCMCIA memory space for
* this socket (usually the 36bit address shifted 4 to the right)
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
if (!r) { if (!r) {
dev_err(&pdev->dev, "missing 'pcmcia-mem' resource!\n"); dev_err(&pdev->dev, "missing 'pcmcia-mem' resource!\n");
...@@ -241,10 +234,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) ...@@ -241,10 +234,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
} }
sock->phys_mem = r->start; sock->phys_mem = r->start;
/* /* 36bit PCMCIA IO area address */
* pseudo-io: The 32bit address of the PCMCIA IO space for this
* socket (usually the 36bit address shifted 4 to the right).
*/
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
if (!r) { if (!r) {
dev_err(&pdev->dev, "missing 'pcmcia-io' resource!\n"); dev_err(&pdev->dev, "missing 'pcmcia-io' resource!\n");
......
...@@ -1408,10 +1408,10 @@ static struct pci_device_id yenta_table[] = { ...@@ -1408,10 +1408,10 @@ static struct pci_device_id yenta_table[] = {
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7510, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7610, TI12XX),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_710, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_712, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_720, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_722, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE),
CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment