0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/slab.h>
0013 #include <linux/module.h>
0014 #include <linux/kernel.h>
0015
0016 #include <pcmcia/ss.h>
0017 #include <pcmcia/cistpl.h>
0018 #include "cs_internal.h"
0019
0020
0021 struct pcmcia_align_data {
0022 unsigned long mask;
0023 unsigned long offset;
0024 };
0025
0026 static resource_size_t pcmcia_align(void *align_data,
0027 const struct resource *res,
0028 resource_size_t size, resource_size_t align)
0029 {
0030 struct pcmcia_align_data *data = align_data;
0031 resource_size_t start;
0032
0033 start = (res->start & ~data->mask) + data->offset;
0034 if (start < res->start)
0035 start += data->mask + 1;
0036
0037 #ifdef CONFIG_X86
0038 if (res->flags & IORESOURCE_IO) {
0039 if (start & 0x300)
0040 start = (start + 0x3ff) & ~0x3ff;
0041 }
0042 #endif
0043
0044 #ifdef CONFIG_M68K
0045 if (res->flags & IORESOURCE_IO) {
0046 if ((res->start + size - 1) >= 1024)
0047 start = res->end;
0048 }
0049 #endif
0050
0051 return start;
0052 }
0053
0054
0055 static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
0056 unsigned long base, int num,
0057 unsigned long align)
0058 {
0059 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
0060 dev_name(&s->dev));
0061 struct pcmcia_align_data data;
0062 unsigned long min = base;
0063 int ret;
0064
0065 data.mask = align - 1;
0066 data.offset = base & data.mask;
0067
0068 #ifdef CONFIG_PCI
0069 if (s->cb_dev) {
0070 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
0071 min, 0, pcmcia_align, &data);
0072 } else
0073 #endif
0074 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
0075 1, pcmcia_align, &data);
0076
0077 if (ret != 0) {
0078 kfree(res);
0079 res = NULL;
0080 }
0081 return res;
0082 }
0083
0084 static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
0085 unsigned int *base, unsigned int num,
0086 unsigned int align, struct resource **parent)
0087 {
0088 int i, ret = 0;
0089
0090
0091
0092
0093
0094 for (i = 0; i < MAX_IO_WIN; i++) {
0095 if (!s->io[i].res)
0096 continue;
0097
0098 if (!*base)
0099 continue;
0100
0101 if ((s->io[i].res->start & (align-1)) == *base)
0102 return -EBUSY;
0103 }
0104
0105 for (i = 0; i < MAX_IO_WIN; i++) {
0106 struct resource *res = s->io[i].res;
0107 unsigned int try;
0108
0109 if (res && (res->flags & IORESOURCE_BITS) !=
0110 (attr & IORESOURCE_BITS))
0111 continue;
0112
0113 if (!res) {
0114 if (align == 0)
0115 align = 0x10000;
0116
0117 res = s->io[i].res = __iodyn_find_io_region(s, *base,
0118 num, align);
0119 if (!res)
0120 return -EINVAL;
0121
0122 *base = res->start;
0123 s->io[i].res->flags =
0124 ((res->flags & ~IORESOURCE_BITS) |
0125 (attr & IORESOURCE_BITS));
0126 s->io[i].InUse = num;
0127 *parent = res;
0128 return 0;
0129 }
0130
0131
0132 try = res->end + 1;
0133 if ((*base == 0) || (*base == try)) {
0134 if (adjust_resource(s->io[i].res, res->start,
0135 resource_size(res) + num))
0136 continue;
0137 *base = try;
0138 s->io[i].InUse += num;
0139 *parent = res;
0140 return 0;
0141 }
0142
0143
0144 try = res->start - num;
0145 if ((*base == 0) || (*base == try)) {
0146 if (adjust_resource(s->io[i].res,
0147 res->start - num,
0148 resource_size(res) + num))
0149 continue;
0150 *base = try;
0151 s->io[i].InUse += num;
0152 *parent = res;
0153 return 0;
0154 }
0155 }
0156
0157 return -EINVAL;
0158 }
0159
0160
0161 struct pccard_resource_ops pccard_iodyn_ops = {
0162 .validate_mem = NULL,
0163 .find_io = iodyn_find_io,
0164 .find_mem = NULL,
0165 .init = static_init,
0166 .exit = NULL,
0167 };
0168 EXPORT_SYMBOL(pccard_iodyn_ops);