/*
* rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP 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/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
MODULE_LICENSE("GPL");
/* 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(probe_mem, 1); /* memory probe? */
#ifdef CONFIG_PCMCIA_PROBE
INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
INT_MODULE_PARM(mem_limit, 0x10000);
#endif
/* for io_db and mem_db */
struct resource_map {
u_long base, num;
struct resource_map *next;
};
struct socket_data {
struct resource_map mem_db;
struct resource_map io_db;
unsigned int rsrc_mem_probe;
};
static DEFINE_MUTEX(rsrc_mutex);
#define MEM_PROBE_LOW (1 << 0)
#define MEM_PROBE_HIGH (1 << 1)
/*======================================================================
Linux resource management extensions
======================================================================*/
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)
{
struct resource *res, *parent;
parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
res = make_resource(base, size, type | IORESOURCE_BUSY, name);
if (res) {
#ifdef CONFIG_PCI
if (s && s->cb_dev)
parent = pci_find_parent_resource(s->cb_dev, res);
#endif
if (!parent || request_resource(parent, res)) {
kfree(res);
res = NULL;
}
}
return res;
}
static void free_region(struct resource *res)
{
if (res) {
release_resource(res);
kfree(res);
}
}
/*======================================================================
These manage the internal databases of available resources.
======================================================================*/
static int add_interval(struct resource_map *map, u_long base, u_long num)
{
struct resource_map *p, *q;
for (p = map; ; p = p->next) {
if ((p != map) && (p->base+p->num-1 >= base))
return -1;
if ((p->next == map) || (p->next->base > base+num-1))
break;
}
q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
if (!q) {
printk(KERN_WARNING "out of memory to update resources\n");
return -ENOMEM;
}
q->base = base; q->num = num;
q->next = p->next; p->next = q;
return 0;
}
/*====================================================================*/
static int sub_interval(struct resource_map *map, u_long base, u_long num)
{
struct resource_