-/*======================================================================
-
- PCMCIA Card Information Structure parser
-
- cistpl.c 1.99 2002/10/24 06:11:48
-
- The contents of this file are subject to the Mozilla Public
- License Version 1.1 (the "License"); you may not use this file
- except in compliance with the License. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- 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.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL"), in
- which case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the MPL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the MPL or the GPL.
-
-======================================================================*/
+/*
+ * cistpl.c -- 16-bit PCMCIA Card Information Structure parser
+ *
+ * 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/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
/* Parameters that can be set with 'insmod' */
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
-
-INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */
+/* 16-bit CIS? */
+static int cis_width;
+module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s)
{
- if (s->cis_mem.sys_start != 0) {
+ if (s->cis_mem.flags & MAP_ACTIVE) {
s->cis_mem.flags &= ~MAP_ACTIVE;
s->ops->set_mem_map(s, &s->cis_mem);
- if (!(s->features & SS_CAP_STATIC_MAP))
- release_mem_region(s->cis_mem.sys_start, s->map_size);
+ if (s->cis_mem.res) {
+ release_resource(s->cis_mem.res);
+ kfree(s->cis_mem.res);
+ s->cis_mem.res = NULL;
+ }
iounmap(s->cis_virt);
- s->cis_mem.sys_start = 0;
s->cis_virt = NULL;
}
}
+EXPORT_SYMBOL(release_cis_mem);
/*
* Map the card memory at "card_offset" into virtual space.
* If flags & MAP_ATTRIB, map the attribute space, otherwise
* map the memory space.
*/
-static unsigned char *
+static void __iomem *
set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
{
- pccard_mem_map *mem = &s->cis_mem;
- if (!(s->features & SS_CAP_STATIC_MAP) &&
- mem->sys_start == 0) {
- validate_mem(s);
- mem->sys_start = 0;
- if (find_mem_region(&mem->sys_start, s->map_size,
- s->map_size, 0, "card services", s)) {
- printk(KERN_NOTICE "cs: unable to map card memory!\n");
- return NULL;
+ pccard_mem_map *mem = &s->cis_mem;
+ int ret;
+
+ 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);
+ if (mem->res == NULL) {
+ printk(KERN_NOTICE "cs: unable to map card memory!\n");
+ return NULL;
+ }
+ s->cis_virt = NULL;
}
- mem->sys_stop = mem->sys_start+s->map_size-1;
- s->cis_virt = ioremap(mem->sys_start, s->map_size);
- }
- mem->card_start = card_offset;
- mem->flags = flags;
- s->ops->set_mem_map(s, mem);
- if (s->features & SS_CAP_STATIC_MAP) {
- if (s->cis_virt)
- iounmap(s->cis_virt);
- s->cis_virt = ioremap(mem->sys_start, s->map_size);
- }
- return s->cis_virt;
+
+ if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
+ s->cis_virt = ioremap(mem->res->start, s->map_size);
+
+ mem->card_start = card_offset;
+ mem->flags = flags;
+
+ ret = s->ops->set_mem_map(s, mem);
+ if (ret) {
+ iounmap(s->cis_virt);
+ s->cis_virt = NULL;
+ return NULL;
+ }
+
+ if (s->features & SS_CAP_STATIC_MAP) {
+ if (s->cis_virt)
+ iounmap(s->cis_virt);
+ s->cis_virt = ioremap(mem->static_start, s->map_size);
+ }
+
+ return s->cis_virt;
}
/*======================================================================
#define IS_ATTR 1
#define IS_INDIRECT 8
-int 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_char *sys, *end, *buf = ptr;
+ void __iomem *sys, *end;
+ unsigned char *buf = ptr;
- cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+ cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
*(u_char *)(ptr+2), *(u_char *)(ptr+3));
return 0;
}
+EXPORT_SYMBOL(pcmcia_read_cis_mem);
-void 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_char *sys, *end, *buf = ptr;
+ void __iomem *sys, *end;
+ unsigned char *buf = ptr;
- cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+ cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
}
}
}
+EXPORT_SYMBOL(pcmcia_write_cis_mem);
+
/*======================================================================
ret = read_cb_mem(s, attr, addr, len, ptr);
else
#endif
- ret = read_cis_mem(s, attr, addr, len, ptr);
+ ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
if (ret == 0) {
/* Copy data into the cache */
list_del(&cis->node);
kfree(cis);
}
+
+ /*
+ * If there was a fake CIS, destroy that as well.
+ */
+ kfree(s->fake_cis);
+ s->fake_cis = NULL;
}
+EXPORT_SYMBOL(destroy_cis_cache);
/*======================================================================
read_cb_mem(s, cis->attr, cis->addr, len, buf);
else
#endif
- read_cis_mem(s, cis->attr, cis->addr, len, buf);
+ pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
if (memcmp(buf, cis->cache, len) != 0) {
kfree(buf);
======================================================================*/
-int pcmcia_replace_cis(client_handle_t handle, cisdump_t *cis)
+int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (s->fake_cis != NULL) {
- kfree(s->fake_cis);
- s->fake_cis = NULL;
- }
+ kfree(s->fake_cis);
+ s->fake_cis = NULL;
if (cis->Length > CISTPL_MAX_CIS_SIZE)
return CS_BAD_SIZE;
s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
memcpy(s->fake_cis, cis->Data, cis->Length);
return CS_SUCCESS;
}
+EXPORT_SYMBOL(pcmcia_replace_cis);
/*======================================================================
#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
#define SPACE(f) (((tuple_flags *)(&(f)))->space)
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple);
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int func, tuple_t *tuple);
-int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
+ if (!s)
return CS_BAD_HANDLE;
- s = SOCKET(handle);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
tuple->TupleLink = tuple->Flags = 0;
!(tuple->Attributes & TUPLE_RETURN_COMMON)) {
cisdata_t req = tuple->DesiredTuple;
tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
- if (pcmcia_get_next_tuple(handle, tuple) == CS_SUCCESS) {
+ if (pccard_get_next_tuple(s, function, tuple) == CS_SUCCESS) {
tuple->DesiredTuple = CISTPL_LINKTARGET;
- if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
+ if (pccard_get_next_tuple(s, function, tuple) != CS_SUCCESS)
return CS_NO_MORE_ITEMS;
} else
tuple->CISOffset = tuple->TupleLink = 0;
tuple->DesiredTuple = req;
}
- return pcmcia_get_next_tuple(handle, tuple);
+ return pccard_get_next_tuple(s, function, tuple);
}
+EXPORT_SYMBOL(pccard_get_first_tuple);
static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
{
/* Get indirect link from the MFC tuple */
read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link);
- ofs = le32_to_cpu(*(u_int *)(link+1));
+ ofs = le32_to_cpu(*(__le32 *)(link+1));
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
return -1;
}
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
{
- struct pcmcia_socket *s;
u_char link[2], tmp;
int ofs, i, attr;
-
- if (CHECK_HANDLE(handle))
+
+ if (!s)
return CS_BAD_HANDLE;
- s = SOCKET(handle);
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
case CISTPL_LONGLINK_MFC:
tuple->LinkOffset = ofs + 3;
LINK_SPACE(tuple->Flags) = attr;
- if (handle->Function == BIND_FN_ALL) {
+ if (function == BIND_FN_ALL) {
/* Follow all the MFC links */
read_cis_cache(s, attr, ofs+2, 1, &tmp);
MFC_FN(tuple->Flags) = tmp;
} else {
/* Follow exactly one of the links */
MFC_FN(tuple->Flags) = 1;
- tuple->LinkOffset += handle->Function * 5;
+ tuple->LinkOffset += function * 5;
}
break;
case CISTPL_NO_LINK:
tuple->CISOffset = ofs + 2;
return CS_SUCCESS;
}
+EXPORT_SYMBOL(pccard_get_next_tuple);
/*====================================================================*/
#define _MIN(a, b) (((a) < (b)) ? (a) : (b))
-int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
{
- struct pcmcia_socket *s;
u_int len;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
+ if (!s)
+ return CS_BAD_HANDLE;
if (tuple->TupleLink < tuple->TupleOffset)
return CS_NO_MORE_ITEMS;
_MIN(len, tuple->TupleDataMax), tuple->TupleData);
return CS_SUCCESS;
}
+EXPORT_SYMBOL(pccard_get_tuple_data);
+
/*======================================================================
if (tuple->TupleDataLen < 5)
return CS_BAD_TUPLE;
p = (u_char *)tuple->TupleData;
- csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
- csum->len = le16_to_cpu(*(u_short *)(p + 2));
+ csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2;
+ csum->len = le16_to_cpu(*(__le16 *)(p + 2));
csum->sum = *(p+4);
return CS_SUCCESS;
}
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+ link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData);
return CS_SUCCESS;
}
return CS_BAD_TUPLE;
for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++;
- link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+ link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4;
}
return CS_SUCCESS;
}
static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{
- u_short *p;
+ __le16 *p;
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- p = (u_short *)tuple->TupleData;
+ p = (__le16 *)tuple->TupleData;
m->manf = le16_to_cpu(p[0]);
m->card = le16_to_cpu(p[1]);
return CS_SUCCESS;
break;
case 0x20:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
break;
case 0x40:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
entry->mem.win[0].card_addr =
- le16_to_cpu(*(u_short *)(p+2)) << 8;
+ le16_to_cpu(*(__le16 *)(p+2)) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q) return CS_BAD_TUPLE;
p = (u_char *)tuple->TupleData;
bar->attr = *p;
p += 2;
- bar->size = le32_to_cpu(*(u_int *)p);
+ bar->size = le32_to_cpu(*(__le32 *)p);
return CS_SUCCESS;
}
return CS_BAD_TUPLE;
config->last_idx = *(++p);
p++;
- config->base = le32_to_cpu(*(u_int *)p);
+ config->base = le32_to_cpu(*(__le32 *)p);
config->subtuples = tuple->TupleDataLen - 6;
return CS_SUCCESS;
}
v2->vers = p[0];
v2->comply = p[1];
- v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+ v2->dindex = le16_to_cpu(*(__le16 *)(p+2));
v2->vspec8 = p[6];
v2->vspec9 = p[7];
v2->nhdr = p[8];
fmt->type = p[0];
fmt->edc = p[1];
- fmt->offset = le32_to_cpu(*(u_int *)(p+2));
- fmt->length = le32_to_cpu(*(u_int *)(p+6));
+ fmt->offset = le32_to_cpu(*(__le32 *)(p+2));
+ fmt->length = le32_to_cpu(*(__le32 *)(p+6));
return CS_SUCCESS;
}
/*====================================================================*/
-int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse)
{
int ret = CS_SUCCESS;
}
return ret;
}
+EXPORT_SYMBOL(pccard_parse_tuple);
/*======================================================================
======================================================================*/
-int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
+int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse)
{
tuple_t tuple;
cisdata_t *buf;
return CS_OUT_OF_RESOURCE;
tuple.DesiredTuple = code;
tuple.Attributes = TUPLE_RETURN_COMMON;
- ret = pcmcia_get_first_tuple(handle, &tuple);
+ ret = pccard_get_first_tuple(s, function, &tuple);
if (ret != CS_SUCCESS) goto done;
tuple.TupleData = buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
- ret = pcmcia_get_tuple_data(handle, &tuple);
+ ret = pccard_get_tuple_data(s, &tuple);
if (ret != CS_SUCCESS) goto done;
- ret = pcmcia_parse_tuple(handle, &tuple, parse);
+ ret = pccard_parse_tuple(&tuple, parse);
done:
kfree(buf);
return ret;
}
+EXPORT_SYMBOL(pccard_read_tuple);
/*======================================================================
======================================================================*/
-int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info)
{
tuple_t *tuple;
cisparse_t *p;
int ret, reserved, dev_ok = 0, ident_ok = 0;
- if (CHECK_HANDLE(handle))
+ if (!s)
return CS_BAD_HANDLE;
+
tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
if (tuple == NULL)
return CS_OUT_OF_RESOURCE;
info->Chains = reserved = 0;
tuple->DesiredTuple = RETURN_FIRST_TUPLE;
tuple->Attributes = TUPLE_RETURN_COMMON;
- ret = pcmcia_get_first_tuple(handle, tuple);
+ ret = pccard_get_first_tuple(s, function, tuple);
if (ret != CS_SUCCESS)
goto done;
/* First tuple should be DEVICE; we should really have either that
or a CFTABLE_ENTRY of some sort */
if ((tuple->TupleCode == CISTPL_DEVICE) ||
- (read_tuple(handle, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) ||
- (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS))
+ (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) ||
+ (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS))
dev_ok++;
/* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
tuple, for card identification. Certain old D-Link and Linksys
cards have only a broken VERS_2 tuple; hence the bogus test. */
- if ((read_tuple(handle, CISTPL_MANFID, p) == CS_SUCCESS) ||
- (read_tuple(handle, CISTPL_VERS_1, p) == CS_SUCCESS) ||
- (read_tuple(handle, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS))
+ if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == CS_SUCCESS) ||
+ (pccard_read_tuple(s, function, CISTPL_VERS_1, p) == CS_SUCCESS) ||
+ (pccard_read_tuple(s, function, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS))
ident_ok++;
if (!dev_ok && !ident_ok)
goto done;
for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
- ret = pcmcia_get_next_tuple(handle, tuple);
+ ret = pccard_get_next_tuple(s, function, tuple);
if (ret != CS_SUCCESS) break;
if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
kfree(p);
return CS_SUCCESS;
}
-
+EXPORT_SYMBOL(pccard_validate_cis);