diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 15:25:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 15:25:06 -0400 |
commit | 1685e633b396b0f3dabbc9fa5d65dfefe6435250 (patch) | |
tree | ee83e26e2468ca1518a1b065c690159e12c8def9 /drivers/pcmcia/pcmcia_resource.c | |
parent | 1cfd2bda8c486ae0e7a8005354758ebb68172bca (diff) | |
parent | 127c03cdbad9bd5af5d7f33bd31a1015a90cb77f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6:
pcmcia: avoid buffer overflow in pcmcia_setup_isa_irq
pcmcia: do not request windows if you don't need to
pcmcia: insert PCMCIA device resources into resource tree
pcmcia: export resource information to sysfs
pcmcia: use struct resource for PCMCIA devices, part 2
pcmcia: remove memreq_t
pcmcia: move local definitions out of include/pcmcia/cs.h
pcmcia: do not use io_req_t when calling pcmcia_request_io()
pcmcia: do not use io_req_t after call to pcmcia_request_io()
pcmcia: use struct resource for PCMCIA devices
pcmcia: clean up cs.h
pcmcia: use pcmica_{read,write}_config_byte
pcmcia: remove cs_types.h
pcmcia: remove unused flag, simplify headers
pcmcia: remove obsolete CS_EVENT_ definitions
pcmcia: split up central event handler
pcmcia: simplify event callback
pcmcia: remove obsolete ioctl
Conflicts in:
- drivers/staging/comedi/drivers/*
- drivers/staging/wlags49_h2/wl_cs.c
due to dev_info_t and whitespace changes
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 331 |
1 files changed, 183 insertions, 148 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index a4cd9adfcbc0..54aa1c238cb3 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | #include <asm/irq.h> | 26 | #include <asm/irq.h> |
27 | 27 | ||
28 | #include <pcmcia/cs_types.h> | ||
29 | #include <pcmcia/ss.h> | 28 | #include <pcmcia/ss.h> |
30 | #include <pcmcia/cs.h> | 29 | #include <pcmcia/cs.h> |
31 | #include <pcmcia/cistpl.h> | 30 | #include <pcmcia/cistpl.h> |
@@ -57,77 +56,107 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, | |||
57 | } | 56 | } |
58 | 57 | ||
59 | 58 | ||
59 | static void release_io_space(struct pcmcia_socket *s, struct resource *res) | ||
60 | { | ||
61 | resource_size_t num = resource_size(res); | ||
62 | int i; | ||
63 | |||
64 | dev_dbg(&s->dev, "release_io_space for %pR\n", res); | ||
65 | |||
66 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
67 | if (!s->io[i].res) | ||
68 | continue; | ||
69 | if ((s->io[i].res->start <= res->start) && | ||
70 | (s->io[i].res->end >= res->end)) { | ||
71 | s->io[i].InUse -= num; | ||
72 | if (res->parent) | ||
73 | release_resource(res); | ||
74 | res->start = res->end = 0; | ||
75 | res->flags = IORESOURCE_IO; | ||
76 | /* Free the window if no one else is using it */ | ||
77 | if (s->io[i].InUse == 0) { | ||
78 | release_resource(s->io[i].res); | ||
79 | kfree(s->io[i].res); | ||
80 | s->io[i].res = NULL; | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } /* release_io_space */ | ||
85 | |||
60 | /** alloc_io_space | 86 | /** alloc_io_space |
61 | * | 87 | * |
62 | * Special stuff for managing IO windows, because they are scarce | 88 | * Special stuff for managing IO windows, because they are scarce |
63 | */ | 89 | */ |
64 | 90 | static int alloc_io_space(struct pcmcia_socket *s, struct resource *res, | |
65 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, | 91 | unsigned int lines) |
66 | unsigned int *base, unsigned int num, u_int lines) | ||
67 | { | 92 | { |
68 | unsigned int align; | 93 | unsigned int align; |
94 | unsigned int base = res->start; | ||
95 | unsigned int num = res->end; | ||
96 | int ret; | ||
69 | 97 | ||
70 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | 98 | res->flags |= IORESOURCE_IO; |
99 | |||
100 | dev_dbg(&s->dev, "alloc_io_space request for %pR, %d lines\n", | ||
101 | res, lines); | ||
102 | |||
103 | align = base ? (lines ? 1<<lines : 0) : 1; | ||
71 | if (align && (align < num)) { | 104 | if (align && (align < num)) { |
72 | if (*base) { | 105 | if (base) { |
73 | dev_dbg(&s->dev, "odd IO request: num %#x align %#x\n", | 106 | dev_dbg(&s->dev, "odd IO request\n"); |
74 | num, align); | ||
75 | align = 0; | 107 | align = 0; |
76 | } else | 108 | } else |
77 | while (align && (align < num)) | 109 | while (align && (align < num)) |
78 | align <<= 1; | 110 | align <<= 1; |
79 | } | 111 | } |
80 | if (*base & ~(align-1)) { | 112 | if (base & ~(align-1)) { |
81 | dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n", | 113 | dev_dbg(&s->dev, "odd IO request\n"); |
82 | *base, align); | ||
83 | align = 0; | 114 | align = 0; |
84 | } | 115 | } |
85 | 116 | ||
86 | return s->resource_ops->find_io(s, attr, base, num, align); | 117 | ret = s->resource_ops->find_io(s, res->flags, &base, num, align, |
87 | } /* alloc_io_space */ | 118 | &res->parent); |
88 | 119 | if (ret) { | |
120 | dev_dbg(&s->dev, "alloc_io_space request failed (%d)\n", ret); | ||
121 | return -EINVAL; | ||
122 | } | ||
89 | 123 | ||
90 | static void release_io_space(struct pcmcia_socket *s, unsigned int base, | 124 | res->start = base; |
91 | unsigned int num) | 125 | res->end = res->start + num - 1; |
92 | { | ||
93 | int i; | ||
94 | 126 | ||
95 | for (i = 0; i < MAX_IO_WIN; i++) { | 127 | if (res->parent) { |
96 | if (!s->io[i].res) | 128 | ret = request_resource(res->parent, res); |
97 | continue; | 129 | if (ret) { |
98 | if ((s->io[i].res->start <= base) && | 130 | dev_warn(&s->dev, |
99 | (s->io[i].res->end >= base+num-1)) { | 131 | "request_resource %pR failed: %d\n", res, ret); |
100 | s->io[i].InUse -= num; | 132 | res->parent = NULL; |
101 | /* Free the window if no one else is using it */ | 133 | release_io_space(s, res); |
102 | if (s->io[i].InUse == 0) { | ||
103 | release_resource(s->io[i].res); | ||
104 | kfree(s->io[i].res); | ||
105 | s->io[i].res = NULL; | ||
106 | } | ||
107 | } | 134 | } |
108 | } | 135 | } |
109 | } /* release_io_space */ | 136 | dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res); |
137 | return ret; | ||
138 | } /* alloc_io_space */ | ||
110 | 139 | ||
111 | 140 | ||
112 | /** pccard_access_configuration_register | 141 | /** |
142 | * pcmcia_access_config() - read or write card configuration registers | ||
113 | * | 143 | * |
114 | * Access_configuration_register() reads and writes configuration | 144 | * pcmcia_access_config() reads and writes configuration registers in |
115 | * registers in attribute memory. Memory window 0 is reserved for | 145 | * attribute memory. Memory window 0 is reserved for this and the tuple |
116 | * this and the tuple reading services. | 146 | * reading services. Drivers must use pcmcia_read_config_byte() or |
147 | * pcmcia_write_config_byte(). | ||
117 | */ | 148 | */ |
118 | 149 | static int pcmcia_access_config(struct pcmcia_device *p_dev, | |
119 | int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, | 150 | off_t where, u8 *val, |
120 | conf_reg_t *reg) | 151 | int (*accessf) (struct pcmcia_socket *s, |
152 | int attr, unsigned int addr, | ||
153 | unsigned int len, void *ptr)) | ||
121 | { | 154 | { |
122 | struct pcmcia_socket *s; | 155 | struct pcmcia_socket *s; |
123 | config_t *c; | 156 | config_t *c; |
124 | int addr; | 157 | int addr; |
125 | u_char val; | ||
126 | int ret = 0; | 158 | int ret = 0; |
127 | 159 | ||
128 | if (!p_dev || !p_dev->function_config) | ||
129 | return -EINVAL; | ||
130 | |||
131 | s = p_dev->socket; | 160 | s = p_dev->socket; |
132 | 161 | ||
133 | mutex_lock(&s->ops_mutex); | 162 | mutex_lock(&s->ops_mutex); |
@@ -139,44 +168,57 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, | |||
139 | return -EACCES; | 168 | return -EACCES; |
140 | } | 169 | } |
141 | 170 | ||
142 | addr = (c->ConfigBase + reg->Offset) >> 1; | 171 | addr = (c->ConfigBase + where) >> 1; |
172 | |||
173 | ret = accessf(s, 1, addr, 1, val); | ||
143 | 174 | ||
144 | switch (reg->Action) { | ||
145 | case CS_READ: | ||
146 | ret = pcmcia_read_cis_mem(s, 1, addr, 1, &val); | ||
147 | reg->Value = val; | ||
148 | break; | ||
149 | case CS_WRITE: | ||
150 | val = reg->Value; | ||
151 | pcmcia_write_cis_mem(s, 1, addr, 1, &val); | ||
152 | break; | ||
153 | default: | ||
154 | dev_dbg(&s->dev, "Invalid conf register request\n"); | ||
155 | ret = -EINVAL; | ||
156 | break; | ||
157 | } | ||
158 | mutex_unlock(&s->ops_mutex); | 175 | mutex_unlock(&s->ops_mutex); |
176 | |||
159 | return ret; | 177 | return ret; |
160 | } /* pcmcia_access_configuration_register */ | 178 | } /* pcmcia_access_config */ |
161 | EXPORT_SYMBOL(pcmcia_access_configuration_register); | 179 | |
180 | |||
181 | /** | ||
182 | * pcmcia_read_config_byte() - read a byte from a card configuration register | ||
183 | * | ||
184 | * pcmcia_read_config_byte() reads a byte from a configuration register in | ||
185 | * attribute memory. | ||
186 | */ | ||
187 | int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val) | ||
188 | { | ||
189 | return pcmcia_access_config(p_dev, where, val, pcmcia_read_cis_mem); | ||
190 | } | ||
191 | EXPORT_SYMBOL(pcmcia_read_config_byte); | ||
192 | |||
193 | |||
194 | /** | ||
195 | * pcmcia_write_config_byte() - write a byte to a card configuration register | ||
196 | * | ||
197 | * pcmcia_write_config_byte() writes a byte to a configuration register in | ||
198 | * attribute memory. | ||
199 | */ | ||
200 | int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val) | ||
201 | { | ||
202 | return pcmcia_access_config(p_dev, where, &val, pcmcia_write_cis_mem); | ||
203 | } | ||
204 | EXPORT_SYMBOL(pcmcia_write_config_byte); | ||
162 | 205 | ||
163 | 206 | ||
164 | int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, | 207 | int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, |
165 | memreq_t *req) | 208 | unsigned int offset) |
166 | { | 209 | { |
167 | struct pcmcia_socket *s = p_dev->socket; | 210 | struct pcmcia_socket *s = p_dev->socket; |
211 | struct resource *res = wh; | ||
212 | unsigned int w; | ||
168 | int ret; | 213 | int ret; |
169 | 214 | ||
170 | wh--; | 215 | w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1; |
171 | if (wh >= MAX_WIN) | 216 | if (w >= MAX_WIN) |
172 | return -EINVAL; | 217 | return -EINVAL; |
173 | if (req->Page != 0) { | 218 | |
174 | dev_dbg(&s->dev, "failure: requested page is zero\n"); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | mutex_lock(&s->ops_mutex); | 219 | mutex_lock(&s->ops_mutex); |
178 | s->win[wh].card_start = req->CardOffset; | 220 | s->win[w].card_start = offset; |
179 | ret = s->ops->set_mem_map(s, &s->win[wh]); | 221 | ret = s->ops->set_mem_map(s, &s->win[w]); |
180 | if (ret) | 222 | if (ret) |
181 | dev_warn(&s->dev, "failed to set_mem_map\n"); | 223 | dev_warn(&s->dev, "failed to set_mem_map\n"); |
182 | mutex_unlock(&s->ops_mutex); | 224 | mutex_unlock(&s->ops_mutex); |
@@ -316,31 +358,25 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev) | |||
316 | * don't bother checking the port ranges against the current socket | 358 | * don't bother checking the port ranges against the current socket |
317 | * values. | 359 | * values. |
318 | */ | 360 | */ |
319 | static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) | 361 | static int pcmcia_release_io(struct pcmcia_device *p_dev) |
320 | { | 362 | { |
321 | struct pcmcia_socket *s = p_dev->socket; | 363 | struct pcmcia_socket *s = p_dev->socket; |
322 | int ret = -EINVAL; | 364 | int ret = -EINVAL; |
323 | config_t *c; | 365 | config_t *c; |
324 | 366 | ||
325 | mutex_lock(&s->ops_mutex); | 367 | mutex_lock(&s->ops_mutex); |
326 | c = p_dev->function_config; | ||
327 | |||
328 | if (!p_dev->_io) | 368 | if (!p_dev->_io) |
329 | goto out; | 369 | goto out; |
330 | 370 | ||
331 | p_dev->_io = 0; | 371 | c = p_dev->function_config; |
332 | 372 | ||
333 | if ((c->io.BasePort1 != req->BasePort1) || | 373 | release_io_space(s, &c->io[0]); |
334 | (c->io.NumPorts1 != req->NumPorts1) || | ||
335 | (c->io.BasePort2 != req->BasePort2) || | ||
336 | (c->io.NumPorts2 != req->NumPorts2)) | ||
337 | goto out; | ||
338 | 374 | ||
339 | c->state &= ~CONFIG_IO_REQ; | 375 | if (c->io[1].end) |
376 | release_io_space(s, &c->io[1]); | ||
340 | 377 | ||
341 | release_io_space(s, req->BasePort1, req->NumPorts1); | 378 | p_dev->_io = 0; |
342 | if (req->NumPorts2) | 379 | c->state &= ~CONFIG_IO_REQ; |
343 | release_io_space(s, req->BasePort2, req->NumPorts2); | ||
344 | 380 | ||
345 | out: | 381 | out: |
346 | mutex_unlock(&s->ops_mutex); | 382 | mutex_unlock(&s->ops_mutex); |
@@ -349,19 +385,22 @@ out: | |||
349 | } /* pcmcia_release_io */ | 385 | } /* pcmcia_release_io */ |
350 | 386 | ||
351 | 387 | ||
352 | int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) | 388 | int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) |
353 | { | 389 | { |
354 | struct pcmcia_socket *s = p_dev->socket; | 390 | struct pcmcia_socket *s = p_dev->socket; |
355 | pccard_mem_map *win; | 391 | pccard_mem_map *win; |
392 | unsigned int w; | ||
393 | |||
394 | dev_dbg(&p_dev->dev, "releasing window %pR\n", res); | ||
356 | 395 | ||
357 | wh--; | 396 | w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1; |
358 | if (wh >= MAX_WIN) | 397 | if (w >= MAX_WIN) |
359 | return -EINVAL; | 398 | return -EINVAL; |
360 | 399 | ||
361 | mutex_lock(&s->ops_mutex); | 400 | mutex_lock(&s->ops_mutex); |
362 | win = &s->win[wh]; | 401 | win = &s->win[w]; |
363 | 402 | ||
364 | if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { | 403 | if (!(p_dev->_win & CLIENT_WIN_REQ(w))) { |
365 | dev_dbg(&s->dev, "not releasing unknown window\n"); | 404 | dev_dbg(&s->dev, "not releasing unknown window\n"); |
366 | mutex_unlock(&s->ops_mutex); | 405 | mutex_unlock(&s->ops_mutex); |
367 | return -EINVAL; | 406 | return -EINVAL; |
@@ -370,15 +409,16 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) | |||
370 | /* Shut down memory window */ | 409 | /* Shut down memory window */ |
371 | win->flags &= ~MAP_ACTIVE; | 410 | win->flags &= ~MAP_ACTIVE; |
372 | s->ops->set_mem_map(s, win); | 411 | s->ops->set_mem_map(s, win); |
373 | s->state &= ~SOCKET_WIN_REQ(wh); | 412 | s->state &= ~SOCKET_WIN_REQ(w); |
374 | 413 | ||
375 | /* Release system memory */ | 414 | /* Release system memory */ |
376 | if (win->res) { | 415 | if (win->res) { |
416 | release_resource(res); | ||
377 | release_resource(win->res); | 417 | release_resource(win->res); |
378 | kfree(win->res); | 418 | kfree(win->res); |
379 | win->res = NULL; | 419 | win->res = NULL; |
380 | } | 420 | } |
381 | p_dev->_win &= ~CLIENT_WIN_REQ(wh); | 421 | p_dev->_win &= ~CLIENT_WIN_REQ(w); |
382 | mutex_unlock(&s->ops_mutex); | 422 | mutex_unlock(&s->ops_mutex); |
383 | 423 | ||
384 | return 0; | 424 | return 0; |
@@ -473,13 +513,13 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, | |||
473 | pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); | 513 | pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); |
474 | } | 514 | } |
475 | if (req->Present & PRESENT_IOBASE_0) { | 515 | if (req->Present & PRESENT_IOBASE_0) { |
476 | u_char b = c->io.BasePort1 & 0xff; | 516 | u8 b = c->io[0].start & 0xff; |
477 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); | 517 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); |
478 | b = (c->io.BasePort1 >> 8) & 0xff; | 518 | b = (c->io[0].start >> 8) & 0xff; |
479 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); | 519 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); |
480 | } | 520 | } |
481 | if (req->Present & PRESENT_IOSIZE) { | 521 | if (req->Present & PRESENT_IOSIZE) { |
482 | u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; | 522 | u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1; |
483 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); | 523 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); |
484 | } | 524 | } |
485 | 525 | ||
@@ -513,28 +553,29 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, | |||
513 | EXPORT_SYMBOL(pcmcia_request_configuration); | 553 | EXPORT_SYMBOL(pcmcia_request_configuration); |
514 | 554 | ||
515 | 555 | ||
516 | /** pcmcia_request_io | 556 | /** |
557 | * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices | ||
517 | * | 558 | * |
518 | * Request_io() reserves ranges of port addresses for a socket. | 559 | * pcmcia_request_io() attepts to reserve the IO port ranges specified in |
519 | * I have not implemented range sharing or alias addressing. | 560 | * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The |
561 | * "start" value is the requested start of the IO port resource; "end" | ||
562 | * reflects the number of ports requested. The number of IO lines requested | ||
563 | * is specified in &struct pcmcia_device @p_dev->io_lines. | ||
520 | */ | 564 | */ |
521 | int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) | 565 | int pcmcia_request_io(struct pcmcia_device *p_dev) |
522 | { | 566 | { |
523 | struct pcmcia_socket *s = p_dev->socket; | 567 | struct pcmcia_socket *s = p_dev->socket; |
524 | config_t *c; | 568 | config_t *c = p_dev->function_config; |
525 | int ret = -EINVAL; | 569 | int ret = -EINVAL; |
526 | 570 | ||
527 | mutex_lock(&s->ops_mutex); | 571 | mutex_lock(&s->ops_mutex); |
572 | dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]); | ||
528 | 573 | ||
529 | if (!(s->state & SOCKET_PRESENT)) { | 574 | if (!(s->state & SOCKET_PRESENT)) { |
530 | dev_dbg(&s->dev, "No card present\n"); | 575 | dev_dbg(&s->dev, "pcmcia_request_io: No card present\n"); |
531 | goto out; | 576 | goto out; |
532 | } | 577 | } |
533 | 578 | ||
534 | if (!req) | ||
535 | goto out; | ||
536 | |||
537 | c = p_dev->function_config; | ||
538 | if (c->state & CONFIG_LOCKED) { | 579 | if (c->state & CONFIG_LOCKED) { |
539 | dev_dbg(&s->dev, "Configuration is locked\n"); | 580 | dev_dbg(&s->dev, "Configuration is locked\n"); |
540 | goto out; | 581 | goto out; |
@@ -543,40 +584,25 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) | |||
543 | dev_dbg(&s->dev, "IO already configured\n"); | 584 | dev_dbg(&s->dev, "IO already configured\n"); |
544 | goto out; | 585 | goto out; |
545 | } | 586 | } |
546 | if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) { | ||
547 | dev_dbg(&s->dev, "bad attribute setting for IO region 1\n"); | ||
548 | goto out; | ||
549 | } | ||
550 | if ((req->NumPorts2 > 0) && | ||
551 | (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) { | ||
552 | dev_dbg(&s->dev, "bad attribute setting for IO region 2\n"); | ||
553 | goto out; | ||
554 | } | ||
555 | 587 | ||
556 | dev_dbg(&s->dev, "trying to allocate resource 1\n"); | 588 | ret = alloc_io_space(s, &c->io[0], p_dev->io_lines); |
557 | ret = alloc_io_space(s, req->Attributes1, &req->BasePort1, | 589 | if (ret) |
558 | req->NumPorts1, req->IOAddrLines); | ||
559 | if (ret) { | ||
560 | dev_dbg(&s->dev, "allocation of resource 1 failed\n"); | ||
561 | goto out; | 590 | goto out; |
562 | } | ||
563 | 591 | ||
564 | if (req->NumPorts2) { | 592 | if (c->io[1].end) { |
565 | dev_dbg(&s->dev, "trying to allocate resource 2\n"); | 593 | ret = alloc_io_space(s, &c->io[1], p_dev->io_lines); |
566 | ret = alloc_io_space(s, req->Attributes2, &req->BasePort2, | ||
567 | req->NumPorts2, req->IOAddrLines); | ||
568 | if (ret) { | 594 | if (ret) { |
569 | dev_dbg(&s->dev, "allocation of resource 2 failed\n"); | 595 | release_io_space(s, &c->io[0]); |
570 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
571 | goto out; | 596 | goto out; |
572 | } | 597 | } |
573 | } | 598 | } else |
599 | c->io[1].start = 0; | ||
574 | 600 | ||
575 | c->io = *req; | ||
576 | c->state |= CONFIG_IO_REQ; | 601 | c->state |= CONFIG_IO_REQ; |
577 | p_dev->_io = 1; | 602 | p_dev->_io = 1; |
578 | dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret); | ||
579 | 603 | ||
604 | dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR", | ||
605 | &c->io[0], &c->io[1]); | ||
580 | out: | 606 | out: |
581 | mutex_unlock(&s->ops_mutex); | 607 | mutex_unlock(&s->ops_mutex); |
582 | 608 | ||
@@ -651,7 +677,7 @@ EXPORT_SYMBOL(__pcmcia_request_exclusive_irq); | |||
651 | #ifdef CONFIG_PCMCIA_PROBE | 677 | #ifdef CONFIG_PCMCIA_PROBE |
652 | 678 | ||
653 | /* mask of IRQs already reserved by other cards, we should avoid using them */ | 679 | /* mask of IRQs already reserved by other cards, we should avoid using them */ |
654 | static u8 pcmcia_used_irq[NR_IRQS]; | 680 | static u8 pcmcia_used_irq[32]; |
655 | 681 | ||
656 | static irqreturn_t test_action(int cpl, void *dev_id) | 682 | static irqreturn_t test_action(int cpl, void *dev_id) |
657 | { | 683 | { |
@@ -674,6 +700,9 @@ static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) | |||
674 | for (try = 0; try < 64; try++) { | 700 | for (try = 0; try < 64; try++) { |
675 | irq = try % 32; | 701 | irq = try % 32; |
676 | 702 | ||
703 | if (irq > NR_IRQS) | ||
704 | continue; | ||
705 | |||
677 | /* marked as available by driver, not blocked by userspace? */ | 706 | /* marked as available by driver, not blocked by userspace? */ |
678 | if (!((mask >> irq) & 1)) | 707 | if (!((mask >> irq) & 1)) |
679 | continue; | 708 | continue; |
@@ -767,23 +796,18 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
767 | struct pcmcia_socket *s = p_dev->socket; | 796 | struct pcmcia_socket *s = p_dev->socket; |
768 | pccard_mem_map *win; | 797 | pccard_mem_map *win; |
769 | u_long align; | 798 | u_long align; |
799 | struct resource *res; | ||
770 | int w; | 800 | int w; |
771 | 801 | ||
772 | if (!(s->state & SOCKET_PRESENT)) { | 802 | if (!(s->state & SOCKET_PRESENT)) { |
773 | dev_dbg(&s->dev, "No card present\n"); | 803 | dev_dbg(&s->dev, "No card present\n"); |
774 | return -ENODEV; | 804 | return -ENODEV; |
775 | } | 805 | } |
776 | if (req->Attributes & (WIN_PAGED | WIN_SHARED)) { | ||
777 | dev_dbg(&s->dev, "bad attribute setting for iomem region\n"); | ||
778 | return -EINVAL; | ||
779 | } | ||
780 | 806 | ||
781 | /* Window size defaults to smallest available */ | 807 | /* Window size defaults to smallest available */ |
782 | if (req->Size == 0) | 808 | if (req->Size == 0) |
783 | req->Size = s->map_size; | 809 | req->Size = s->map_size; |
784 | align = (((s->features & SS_CAP_MEM_ALIGN) || | 810 | align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size; |
785 | (req->Attributes & WIN_STRICT_ALIGN)) ? | ||
786 | req->Size : s->map_size); | ||
787 | if (req->Size & (s->map_size-1)) { | 811 | if (req->Size & (s->map_size-1)) { |
788 | dev_dbg(&s->dev, "invalid map size\n"); | 812 | dev_dbg(&s->dev, "invalid map size\n"); |
789 | return -EINVAL; | 813 | return -EINVAL; |
@@ -797,20 +821,21 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
797 | align = 0; | 821 | align = 0; |
798 | 822 | ||
799 | /* Allocate system memory window */ | 823 | /* Allocate system memory window */ |
824 | mutex_lock(&s->ops_mutex); | ||
800 | for (w = 0; w < MAX_WIN; w++) | 825 | for (w = 0; w < MAX_WIN; w++) |
801 | if (!(s->state & SOCKET_WIN_REQ(w))) | 826 | if (!(s->state & SOCKET_WIN_REQ(w))) |
802 | break; | 827 | break; |
803 | if (w == MAX_WIN) { | 828 | if (w == MAX_WIN) { |
804 | dev_dbg(&s->dev, "all windows are used already\n"); | 829 | dev_dbg(&s->dev, "all windows are used already\n"); |
830 | mutex_unlock(&s->ops_mutex); | ||
805 | return -EINVAL; | 831 | return -EINVAL; |
806 | } | 832 | } |
807 | 833 | ||
808 | mutex_lock(&s->ops_mutex); | ||
809 | win = &s->win[w]; | 834 | win = &s->win[w]; |
810 | 835 | ||
811 | if (!(s->features & SS_CAP_STATIC_MAP)) { | 836 | if (!(s->features & SS_CAP_STATIC_MAP)) { |
812 | win->res = pcmcia_find_mem_region(req->Base, req->Size, align, | 837 | win->res = pcmcia_find_mem_region(req->Base, req->Size, align, |
813 | (req->Attributes & WIN_MAP_BELOW_1MB), s); | 838 | 0, s); |
814 | if (!win->res) { | 839 | if (!win->res) { |
815 | dev_dbg(&s->dev, "allocating mem region failed\n"); | 840 | dev_dbg(&s->dev, "allocating mem region failed\n"); |
816 | mutex_unlock(&s->ops_mutex); | 841 | mutex_unlock(&s->ops_mutex); |
@@ -821,16 +846,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
821 | 846 | ||
822 | /* Configure the socket controller */ | 847 | /* Configure the socket controller */ |
823 | win->map = w+1; | 848 | win->map = w+1; |
824 | win->flags = 0; | 849 | win->flags = req->Attributes; |
825 | win->speed = req->AccessSpeed; | 850 | win->speed = req->AccessSpeed; |
826 | if (req->Attributes & WIN_MEMORY_TYPE) | ||
827 | win->flags |= MAP_ATTRIB; | ||
828 | if (req->Attributes & WIN_ENABLE) | ||
829 | win->flags |= MAP_ACTIVE; | ||
830 | if (req->Attributes & WIN_DATA_WIDTH_16) | ||
831 | win->flags |= MAP_16BIT; | ||
832 | if (req->Attributes & WIN_USE_WAIT) | ||
833 | win->flags |= MAP_USE_WAIT; | ||
834 | win->card_start = 0; | 851 | win->card_start = 0; |
835 | 852 | ||
836 | if (s->ops->set_mem_map(s, win) != 0) { | 853 | if (s->ops->set_mem_map(s, win) != 0) { |
@@ -846,8 +863,21 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
846 | else | 863 | else |
847 | req->Base = win->res->start; | 864 | req->Base = win->res->start; |
848 | 865 | ||
866 | /* convert to new-style resources */ | ||
867 | res = p_dev->resource[w + MAX_IO_WIN]; | ||
868 | res->start = req->Base; | ||
869 | res->end = req->Base + req->Size - 1; | ||
870 | res->flags &= ~IORESOURCE_BITS; | ||
871 | res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2); | ||
872 | res->flags |= IORESOURCE_MEM; | ||
873 | res->parent = win->res; | ||
874 | if (win->res) | ||
875 | request_resource(&iomem_resource, res); | ||
876 | |||
877 | dev_dbg(&s->dev, "request_window results in %pR\n", res); | ||
878 | |||
849 | mutex_unlock(&s->ops_mutex); | 879 | mutex_unlock(&s->ops_mutex); |
850 | *wh = w + 1; | 880 | *wh = res; |
851 | 881 | ||
852 | return 0; | 882 | return 0; |
853 | } /* pcmcia_request_window */ | 883 | } /* pcmcia_request_window */ |
@@ -855,13 +885,18 @@ EXPORT_SYMBOL(pcmcia_request_window); | |||
855 | 885 | ||
856 | void pcmcia_disable_device(struct pcmcia_device *p_dev) | 886 | void pcmcia_disable_device(struct pcmcia_device *p_dev) |
857 | { | 887 | { |
888 | int i; | ||
889 | for (i = 0; i < MAX_WIN; i++) { | ||
890 | struct resource *res = p_dev->resource[MAX_IO_WIN + i]; | ||
891 | if (res->flags & WIN_FLAGS_REQ) | ||
892 | pcmcia_release_window(p_dev, res); | ||
893 | } | ||
894 | |||
858 | pcmcia_release_configuration(p_dev); | 895 | pcmcia_release_configuration(p_dev); |
859 | pcmcia_release_io(p_dev, &p_dev->io); | 896 | pcmcia_release_io(p_dev); |
860 | if (p_dev->_irq) { | 897 | if (p_dev->_irq) { |
861 | free_irq(p_dev->irq, p_dev->priv); | 898 | free_irq(p_dev->irq, p_dev->priv); |
862 | p_dev->_irq = 0; | 899 | p_dev->_irq = 0; |
863 | } | 900 | } |
864 | if (p_dev->win) | ||
865 | pcmcia_release_window(p_dev, p_dev->win); | ||
866 | } | 901 | } |
867 | EXPORT_SYMBOL(pcmcia_disable_device); | 902 | EXPORT_SYMBOL(pcmcia_disable_device); |