/*
* 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/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <pcmcia/ss.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
static const u_char mantissa[] = {
10, 12, 13, 15, 20, 25, 30, 35,
40, 45, 50, 55, 60, 70, 80, 90
};
static const u_int exponent[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
};
/* Convert an extended speed byte to a time in nanoseconds */
#define SPEED_CVT(v) \
(mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
/* Convert a power byte to a current in 0.1 microamps */
#define POWER_CVT(v) \
(mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
#define POWER_SCALE(v) (exponent[(v)&7])
/* Upper limit on reasonable # of tuples */
#define MAX_TUPLES 200
/* Bits in IRQInfo1 field */
#define IRQ_INFO2_VALID 0x10
/* 16-bit CIS? */
static int cis_width;
module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s)
{
mutex_lock(&s->ops_mutex);
if (s->cis_mem.flags & MAP_ACTIVE) {
s->cis_mem.flags &= ~MAP_ACTIVE;
s->ops->set_mem_map(s, &s->cis_mem);
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_virt = NULL;
}
mutex_unlock(&s->ops_mutex);
}
/**
* set_cis_map() - map the card memory at "card_offset" into virtual space.
*
* If flags & MAP_ATTRIB, map the attribute space, otherwise
* map the memory space.
*
* Must be called with ops_mutex held.
*/
static void __iomem *set_cis_map(struct pcmcia_socket *s,
unsigned int card_offset, unsigned int flags)
{
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) {
dev_notice(&s->dev, "cs: unable to map card memory!\n");
return NULL;
}
s->cis_virt = NULL;
}
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;
}
/* Bits in attr field */
#define IS_ATTR 1
#define IS_INDIRECT 8
/**
* 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)
{
void __iomem *sys, *end;
unsigned char *buf = ptr;
dev_dbg(&s->dev, "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
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));
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
memset(ptr, 0xff, len);
return -1;
}
writeb(flags, sys+CISREG_ICTRL0);
writeb(add
|