Blame view

drivers/pcmcia/rsrc_iodyn.c 3.75 KB
49b1153ad   Dominik Brodowski   pcmcia: move all ...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * rsrc_iodyn.c -- Resource management routines for MEM-static 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
   */
6d59622e5   Tejun Heo   pcmcia: update gf...
14
  #include <linux/slab.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
15
16
  #include <linux/module.h>
  #include <linux/kernel.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
17
  #include <pcmcia/ss.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  #include <pcmcia/cistpl.h>
  #include "cs_internal.h"
  
  
  struct pcmcia_align_data {
  	unsigned long	mask;
  	unsigned long	offset;
  };
  
  static resource_size_t pcmcia_align(void *align_data,
  				const struct resource *res,
  				resource_size_t size, resource_size_t align)
  {
  	struct pcmcia_align_data *data = align_data;
  	resource_size_t start;
  
  	start = (res->start & ~data->mask) + data->offset;
  	if (start < res->start)
  		start += data->mask + 1;
  
  #ifdef CONFIG_X86
  	if (res->flags & IORESOURCE_IO) {
  		if (start & 0x300)
  			start = (start + 0x3ff) & ~0x3ff;
  	}
  #endif
  
  #ifdef CONFIG_M68K
  	if (res->flags & IORESOURCE_IO) {
  		if ((res->start + size - 1) >= 1024)
  			start = res->end;
  	}
  #endif
  
  	return start;
  }
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
54
55
56
  static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
  					unsigned long base, int num,
  					unsigned long align)
49b1153ad   Dominik Brodowski   pcmcia: move all ...
57
58
59
60
61
62
  {
  	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
  						dev_name(&s->dev));
  	struct pcmcia_align_data data;
  	unsigned long min = base;
  	int ret;
49b1153ad   Dominik Brodowski   pcmcia: move all ...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  	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;
  }
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
81
82
  static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
  			unsigned int *base, unsigned int num,
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
83
  			unsigned int align, struct resource **parent)
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  {
  	int i, ret = 0;
  
  	/* Check for an already-allocated window that must conflict with
  	 * what was asked for.  It is a hack because it does not catch all
  	 * potential conflicts, just the most obvious ones.
  	 */
  	for (i = 0; i < MAX_IO_WIN; i++) {
  		if (!s->io[i].res)
  			continue;
  
  		if (!*base)
  			continue;
  
  		if ((s->io[i].res->start & (align-1)) == *base)
  			return -EBUSY;
  	}
  
  	for (i = 0; i < MAX_IO_WIN; i++) {
  		struct resource *res = s->io[i].res;
  		unsigned int try;
  
  		if (res && (res->flags & IORESOURCE_BITS) !=
  			(attr & IORESOURCE_BITS))
  			continue;
  
  		if (!res) {
  			if (align == 0)
  				align = 0x10000;
  
  			res = s->io[i].res = __iodyn_find_io_region(s, *base,
  								num, align);
  			if (!res)
  				return -EINVAL;
  
  			*base = res->start;
  			s->io[i].res->flags =
  				((res->flags & ~IORESOURCE_BITS) |
  					(attr & IORESOURCE_BITS));
  			s->io[i].InUse = num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
124
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
125
126
127
128
129
130
131
  			return 0;
  		}
  
  		/* Try to extend top of window */
  		try = res->end + 1;
  		if ((*base == 0) || (*base == try)) {
  			if (adjust_resource(s->io[i].res, res->start,
28f65c11f   Joe Perches   treewide: Convert...
132
  					    resource_size(res) + num))
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
133
134
135
  				continue;
  			*base = try;
  			s->io[i].InUse += num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
136
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
137
138
139
140
141
142
143
  			return 0;
  		}
  
  		/* Try to extend bottom of window */
  		try = res->start - num;
  		if ((*base == 0) || (*base == try)) {
  			if (adjust_resource(s->io[i].res,
28f65c11f   Joe Perches   treewide: Convert...
144
145
  					    res->start - num,
  					    resource_size(res) + num))
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
146
147
148
  				continue;
  			*base = try;
  			s->io[i].InUse += num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
149
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
150
151
152
153
154
155
  			return 0;
  		}
  	}
  
  	return -EINVAL;
  }
49b1153ad   Dominik Brodowski   pcmcia: move all ...
156
157
  struct pccard_resource_ops pccard_iodyn_ops = {
  	.validate_mem = NULL,
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
158
  	.find_io = iodyn_find_io,
49b1153ad   Dominik Brodowski   pcmcia: move all ...
159
  	.find_mem = NULL,
49b1153ad   Dominik Brodowski   pcmcia: move all ...
160
161
162
163
  	.init = static_init,
  	.exit = NULL,
  };
  EXPORT_SYMBOL(pccard_iodyn_ops);