#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/ss.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
#define INT_MODULE_PARM(n, v) …
INT_MODULE_PARM(probe_mem, 1);
#ifdef CONFIG_PCMCIA_PROBE
INT_MODULE_PARM(probe_io, 1);
INT_MODULE_PARM(mem_limit, 0x10000);
#endif
struct resource_map { … };
struct socket_data { … };
#define MEM_PROBE_LOW …
#define MEM_PROBE_HIGH …
#define REMOVE_MANAGED_RESOURCE …
#define ADD_MANAGED_RESOURCE …
static struct resource *
claim_region(struct pcmcia_socket *s, resource_size_t base,
resource_size_t size, int type, char *name)
{ … }
static void free_region(struct resource *res)
{ … }
static int add_interval(struct resource_map *map, u_long base, u_long num)
{ … }
static int sub_interval(struct resource_map *map, u_long base, u_long num)
{ … }
#ifdef CONFIG_PCMCIA_PROBE
static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
unsigned int num)
{
struct resource *res;
struct socket_data *s_data = s->resource_data;
unsigned int i, j, bad;
int any;
u_char *b, hole, most;
dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
b = kzalloc(256, GFP_KERNEL);
if (!b) {
pr_cont("\n");
dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
return;
}
for (i = base, most = 0; i < base+num; i += 8) {
res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res)
continue;
hole = inb(i);
for (j = 1; j < 8; j++)
if (inb(i+j) != hole)
break;
free_region(res);
if ((j == 8) && (++b[hole] > b[most]))
most = hole;
if (b[most] == 127)
break;
}
kfree(b);
bad = any = 0;
for (i = base; i < base+num; i += 8) {
res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res) {
if (!any)
pr_cont(" excluding");
if (!bad)
bad = any = i;
continue;
}
for (j = 0; j < 8; j++)
if (inb(i+j) != most)
break;
free_region(res);
if (j < 8) {
if (!any)
pr_cont(" excluding");
if (!bad)
bad = any = i;
} else {
if (bad) {
sub_interval(&s_data->io_db, bad, i-bad);
pr_cont(" %#x-%#x", bad, i-1);
bad = 0;
}
}
}
if (bad) {
if ((num > 16) && (bad == base) && (i == base+num)) {
sub_interval(&s_data->io_db, bad, i-bad);
pr_cont(" nothing: probe failed.\n");
return;
} else {
sub_interval(&s_data->io_db, bad, i-bad);
pr_cont(" %#x-%#x", bad, i-1);
}
}
pr_cont("%s\n", !any ? " clean" : "");
}
#endif
static int readable(struct pcmcia_socket *s, struct resource *res,
unsigned int *count)
{ … }
static int checksum(struct pcmcia_socket *s, struct resource *res,
unsigned int *value)
{ … }
static int do_validate_mem(struct pcmcia_socket *s,
unsigned long base, unsigned long size,
int (*validate)(struct pcmcia_socket *s,
struct resource *res,
unsigned int *value))
{ … }
static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
int (*validate)(struct pcmcia_socket *s,
struct resource *res,
unsigned int *value),
int (*fallback)(struct pcmcia_socket *s,
struct resource *res,
unsigned int *value))
{ … }
#ifdef CONFIG_PCMCIA_PROBE
static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
{
struct socket_data *s_data = s->resource_data;
u_long ok;
if (m == &s_data->mem_db)
return 0;
ok = inv_probe(m->next, s);
if (ok) {
if (m->base >= 0x100000)
sub_interval(&s_data->mem_db, m->base, m->num);
return ok;
}
if (m->base < 0x100000)
return 0;
return do_mem_probe(s, m->base, m->num, readable, checksum);
}
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{
struct resource_map *m, mm;
static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
unsigned long b, i, ok = 0;
struct socket_data *s_data = s->resource_data;
if (probe_mask & MEM_PROBE_HIGH) {
if (inv_probe(s_data->mem_db.next, s) > 0)
return 0;
if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
return 0;
dev_notice(&s->dev,
"cs: warning: no high memory space available!\n");
return -ENODEV;
}
for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
mm = *m;
if (mm.base >= 0x100000)
continue;
if ((mm.base | mm.num) & 0xffff) {
ok += do_mem_probe(s, mm.base, mm.num, readable,
checksum);
continue;
}
for (i = 0; i < 4; i++) {
b = order[i] << 12;
if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
if (ok >= mem_limit)
sub_interval(&s_data->mem_db, b, 0x10000);
else
ok += do_mem_probe(s, b, 0x10000,
readable, checksum);
}
}
}
if (ok > 0)
return 0;
return -ENODEV;
}
#else
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{ … }
#endif
static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
{ … }
struct pcmcia_align_data { … };
static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
resource_size_t start)
{ … }
static resource_size_t
pcmcia_align(void *align_data, const struct resource *res,
resource_size_t size, resource_size_t align)
{ … }
static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
unsigned long r_start,
unsigned long r_end)
{ … }
static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
unsigned long base, int num,
unsigned long align)
{ … }
static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
unsigned int align, struct resource **parent)
{ … }
static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{ … }
static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{ … }
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{ … }
#ifdef CONFIG_PCI
static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
{ … }
#else
static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
{
return -ENODEV;
}
#endif
static int nonstatic_init(struct pcmcia_socket *s)
{ … }
static void nonstatic_release_resource_db(struct pcmcia_socket *s)
{ … }
struct pccard_resource_ops pccard_nonstatic_ops = …;
EXPORT_SYMBOL(…);
static ssize_t show_io_db(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static ssize_t store_io_db(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{ … }
static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
static ssize_t show_mem_db(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static ssize_t store_mem_db(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{ … }
static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
static struct attribute *pccard_rsrc_attributes[] = …;
static const struct attribute_group rsrc_attributes = …;
static int pccard_sysfs_add_rsrc(struct device *dev)
{ … }
static void pccard_sysfs_remove_rsrc(struct device *dev)
{ … }
static struct class_interface pccard_rsrc_interface __refdata = …;
static int __init nonstatic_sysfs_init(void)
{ … }
static void __exit nonstatic_sysfs_exit(void)
{ … }
module_init(…) …;
module_exit(nonstatic_sysfs_exit);