From 3b27e9421a1433689704fe0a02e926d4ba971121 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Wed, 7 Dec 2005 12:32:20 +0100 Subject: [PATCH] pcmcia: properly handle static mem, but dynamic io sockets Some PCMCIA sockets have statically mapped memory windows, but dynamically mapped IO windows. Using the "nonstatic" socket library is inpractical for them, as they do neither need a resource database (as we can trust the kernel resource database on m68k and ppc) nor lots of other features of that library. Let them get a small "iodyn" socket library (105 lines of code) instead. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_mgr.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'drivers/pcmcia/rsrc_mgr.c') diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index b02598a5a91..51460936983 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -166,3 +166,105 @@ struct pccard_resource_ops pccard_static_ops = { .exit = NULL, }; EXPORT_SYMBOL(pccard_static_ops); + + +#ifdef CONFIG_PCCARD_IODYN + +static struct resource * +make_resource(unsigned long b, unsigned long n, int flags, 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; +} + +struct pcmcia_align_data { + unsigned long mask; + unsigned long offset; +}; + +static void pcmcia_align(void *align_data, struct resource *res, + unsigned long size, unsigned long align) +{ + struct pcmcia_align_data *data = align_data; + unsigned long start; + + start = (res->start & ~data->mask) + data->offset; + if (start < res->start) + start += data->mask + 1; + res->start = start; + +#ifdef CONFIG_X86 + if (res->flags & IORESOURCE_IO) { + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +#endif + +#ifdef CONFIG_M68K + if (res->flags & IORESOURCE_IO) { + if ((res->start + size - 1) >= 1024) + res->start = res->end; + } +#endif +} + + +static int iodyn_adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s) +{ + return adjust_resource(res, r_start, r_end - r_start + 1); +} + + +static struct resource *iodyn_find_io_region(unsigned long base, int num, + unsigned long align, struct pcmcia_socket *s) +{ + struct resource *res = make_resource(0, num, IORESOURCE_IO, + s->dev.class_id); + struct pcmcia_align_data data; + unsigned long min = base; + int ret; + + if (align == 0) + align = 0x10000; + + data.mask = align - 1; + data.offset = base & data.mask; + +#ifdef CONFIG_PCI + if (s->cb_dev) { + ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, + min, 0, pcmcia_align, &data); + } else +#endif + ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, + 1, pcmcia_align, &data); + + if (ret != 0) { + kfree(res); + res = NULL; + } + return res; +} + +struct pccard_resource_ops pccard_iodyn_ops = { + .validate_mem = NULL, + .adjust_io_region = iodyn_adjust_io_region, + .find_io = iodyn_find_io_region, + .find_mem = NULL, + .adjust_resource = NULL, + .init = static_init, + .exit = NULL, +}; +EXPORT_SYMBOL(pccard_iodyn_ops); + +#endif /* CONFIG_PCCARD_IODYN */ -- cgit v1.2.3