| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * PCMCIA 16-bit resource management functions | 
|---|
| 4 | * | 
|---|
| 5 | * The initial developer of the original code is David A. Hinds | 
|---|
| 6 | * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds | 
|---|
| 7 | * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved. | 
|---|
| 8 | * | 
|---|
| 9 | * Copyright (C) 1999	     David A. Hinds | 
|---|
| 10 | * Copyright (C) 2004-2010   Dominik Brodowski | 
|---|
| 11 | */ | 
|---|
| 12 |  | 
|---|
| 13 | #include <linux/module.h> | 
|---|
| 14 | #include <linux/kernel.h> | 
|---|
| 15 | #include <linux/interrupt.h> | 
|---|
| 16 | #include <linux/delay.h> | 
|---|
| 17 | #include <linux/pci.h> | 
|---|
| 18 | #include <linux/device.h> | 
|---|
| 19 | #include <linux/netdevice.h> | 
|---|
| 20 | #include <linux/slab.h> | 
|---|
| 21 |  | 
|---|
| 22 | #include <asm/irq.h> | 
|---|
| 23 |  | 
|---|
| 24 | #include <pcmcia/ss.h> | 
|---|
| 25 | #include <pcmcia/cistpl.h> | 
|---|
| 26 | #include <pcmcia/cisreg.h> | 
|---|
| 27 | #include <pcmcia/ds.h> | 
|---|
| 28 |  | 
|---|
| 29 | #include "cs_internal.h" | 
|---|
| 30 |  | 
|---|
| 31 |  | 
|---|
| 32 | /* Access speed for IO windows */ | 
|---|
| 33 | static int io_speed; | 
|---|
| 34 | module_param(io_speed, int, 0444); | 
|---|
| 35 |  | 
|---|
| 36 |  | 
|---|
| 37 | int pcmcia_validate_mem(struct pcmcia_socket *s) | 
|---|
| 38 | { | 
|---|
| 39 | if (s->resource_ops->validate_mem) | 
|---|
| 40 | return s->resource_ops->validate_mem(s); | 
|---|
| 41 | /* if there is no callback, we can assume that everything is OK */ | 
|---|
| 42 | return 0; | 
|---|
| 43 | } | 
|---|
| 44 |  | 
|---|
| 45 | struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, | 
|---|
| 46 | int low, struct pcmcia_socket *s) | 
|---|
| 47 | { | 
|---|
| 48 | if (s->resource_ops->find_mem) | 
|---|
| 49 | return s->resource_ops->find_mem(base, num, align, low, s); | 
|---|
| 50 | return NULL; | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 |  | 
|---|
| 54 | /** | 
|---|
| 55 | * release_io_space() - release IO ports allocated with alloc_io_space() | 
|---|
| 56 | * @s: pcmcia socket | 
|---|
| 57 | * @res: resource to release | 
|---|
| 58 | * | 
|---|
| 59 | */ | 
|---|
| 60 | static void release_io_space(struct pcmcia_socket *s, struct resource *res) | 
|---|
| 61 | { | 
|---|
| 62 | resource_size_t num = resource_size(res); | 
|---|
| 63 | int i; | 
|---|
| 64 |  | 
|---|
| 65 | dev_dbg(&s->dev, "release_io_space for %pR\n", res); | 
|---|
| 66 |  | 
|---|
| 67 | for (i = 0; i < MAX_IO_WIN; i++) { | 
|---|
| 68 | if (!s->io[i].res) | 
|---|
| 69 | continue; | 
|---|
| 70 | if ((s->io[i].res->start <= res->start) && | 
|---|
| 71 | (s->io[i].res->end >= res->end)) { | 
|---|
| 72 | s->io[i].InUse -= num; | 
|---|
| 73 | if (res->parent) | 
|---|
| 74 | release_resource(new: res); | 
|---|
| 75 | res->start = res->end = 0; | 
|---|
| 76 | res->flags = IORESOURCE_IO; | 
|---|
| 77 | /* Free the window if no one else is using it */ | 
|---|
| 78 | if (s->io[i].InUse == 0) { | 
|---|
| 79 | release_resource(new: s->io[i].res); | 
|---|
| 80 | kfree(objp: s->io[i].res); | 
|---|
| 81 | s->io[i].res = NULL; | 
|---|
| 82 | } | 
|---|
| 83 | } | 
|---|
| 84 | } | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 |  | 
|---|
| 88 | /** | 
|---|
| 89 | * alloc_io_space() - allocate IO ports for use by a PCMCIA device | 
|---|
| 90 | * @s: pcmcia socket | 
|---|
| 91 | * @res: resource to allocate (begin: begin, end: size) | 
|---|
| 92 | * @lines: number of IO lines decoded by the PCMCIA card | 
|---|
| 93 | * | 
|---|
| 94 | * Special stuff for managing IO windows, because they are scarce | 
|---|
| 95 | */ | 
|---|
| 96 | static int alloc_io_space(struct pcmcia_socket *s, struct resource *res, | 
|---|
| 97 | unsigned int lines) | 
|---|
| 98 | { | 
|---|
| 99 | unsigned int align; | 
|---|
| 100 | unsigned int base = res->start; | 
|---|
| 101 | unsigned int num = res->end; | 
|---|
| 102 | int ret; | 
|---|
| 103 |  | 
|---|
| 104 | res->flags |= IORESOURCE_IO; | 
|---|
| 105 |  | 
|---|
| 106 | dev_dbg(&s->dev, "alloc_io_space request for %pR, %d lines\n", | 
|---|
| 107 | res, lines); | 
|---|
| 108 |  | 
|---|
| 109 | align = base ? (lines ? 1<<lines : 0) : 1; | 
|---|
| 110 | if (align && (align < num)) { | 
|---|
| 111 | if (base) { | 
|---|
| 112 | dev_dbg(&s->dev, "odd IO request\n"); | 
|---|
| 113 | align = 0; | 
|---|
| 114 | } else | 
|---|
| 115 | while (align && (align < num)) | 
|---|
| 116 | align <<= 1; | 
|---|
| 117 | } | 
|---|
| 118 | if (base & ~(align-1)) { | 
|---|
| 119 | dev_dbg(&s->dev, "odd IO request\n"); | 
|---|
| 120 | align = 0; | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | ret = s->resource_ops->find_io(s, res->flags, &base, num, align, | 
|---|
| 124 | &res->parent); | 
|---|
| 125 | if (ret) { | 
|---|
| 126 | dev_dbg(&s->dev, "alloc_io_space request failed (%d)\n", ret); | 
|---|
| 127 | return -EINVAL; | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | res->start = base; | 
|---|
| 131 | res->end = res->start + num - 1; | 
|---|
| 132 |  | 
|---|
| 133 | if (res->parent) { | 
|---|
| 134 | ret = request_resource(root: res->parent, new: res); | 
|---|
| 135 | if (ret) { | 
|---|
| 136 | dev_warn(&s->dev, | 
|---|
| 137 | "request_resource %pR failed: %d\n", res, ret); | 
|---|
| 138 | res->parent = NULL; | 
|---|
| 139 | release_io_space(s, res); | 
|---|
| 140 | } | 
|---|
| 141 | } | 
|---|
| 142 | dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res); | 
|---|
| 143 | return ret; | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 |  | 
|---|
| 147 | /* | 
|---|
| 148 | * pcmcia_access_config() - read or write card configuration registers | 
|---|
| 149 | * | 
|---|
| 150 | * pcmcia_access_config() reads and writes configuration registers in | 
|---|
| 151 | * attribute memory.  Memory window 0 is reserved for this and the tuple | 
|---|
| 152 | * reading services. Drivers must use pcmcia_read_config_byte() or | 
|---|
| 153 | * pcmcia_write_config_byte(). | 
|---|
| 154 | */ | 
|---|
| 155 | static int pcmcia_access_config(struct pcmcia_device *p_dev, | 
|---|
| 156 | off_t where, u8 *val, | 
|---|
| 157 | int (*accessf) (struct pcmcia_socket *s, | 
|---|
| 158 | int attr, unsigned int addr, | 
|---|
| 159 | unsigned int len, void *ptr)) | 
|---|
| 160 | { | 
|---|
| 161 | struct pcmcia_socket *s; | 
|---|
| 162 | config_t *c; | 
|---|
| 163 | int addr; | 
|---|
| 164 | int ret = 0; | 
|---|
| 165 |  | 
|---|
| 166 | s = p_dev->socket; | 
|---|
| 167 |  | 
|---|
| 168 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 169 | c = p_dev->function_config; | 
|---|
| 170 |  | 
|---|
| 171 | if (!(c->state & CONFIG_LOCKED)) { | 
|---|
| 172 | dev_dbg(&p_dev->dev, "Configuration isn't locked\n"); | 
|---|
| 173 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 174 | return -EACCES; | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | addr = (p_dev->config_base + where) >> 1; | 
|---|
| 178 |  | 
|---|
| 179 | ret = accessf(s, 1, addr, 1, val); | 
|---|
| 180 |  | 
|---|
| 181 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 182 |  | 
|---|
| 183 | return ret; | 
|---|
| 184 | } | 
|---|
| 185 |  | 
|---|
| 186 |  | 
|---|
| 187 | /* | 
|---|
| 188 | * pcmcia_read_config_byte() - read a byte from a card configuration register | 
|---|
| 189 | * | 
|---|
| 190 | * pcmcia_read_config_byte() reads a byte from a configuration register in | 
|---|
| 191 | * attribute memory. | 
|---|
| 192 | */ | 
|---|
| 193 | int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val) | 
|---|
| 194 | { | 
|---|
| 195 | return pcmcia_access_config(p_dev, where, val, accessf: pcmcia_read_cis_mem); | 
|---|
| 196 | } | 
|---|
| 197 | EXPORT_SYMBOL(pcmcia_read_config_byte); | 
|---|
| 198 |  | 
|---|
| 199 |  | 
|---|
| 200 | /* | 
|---|
| 201 | * pcmcia_write_config_byte() - write a byte to a card configuration register | 
|---|
| 202 | * | 
|---|
| 203 | * pcmcia_write_config_byte() writes a byte to a configuration register in | 
|---|
| 204 | * attribute memory. | 
|---|
| 205 | */ | 
|---|
| 206 | int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val) | 
|---|
| 207 | { | 
|---|
| 208 | return pcmcia_access_config(p_dev, where, val: &val, accessf: pcmcia_write_cis_mem); | 
|---|
| 209 | } | 
|---|
| 210 | EXPORT_SYMBOL(pcmcia_write_config_byte); | 
|---|
| 211 |  | 
|---|
| 212 |  | 
|---|
| 213 | /** | 
|---|
| 214 | * pcmcia_map_mem_page() - modify iomem window to point to a different offset | 
|---|
| 215 | * @p_dev: pcmcia device | 
|---|
| 216 | * @res: iomem resource already enabled by pcmcia_request_window() | 
|---|
| 217 | * @offset: card_offset to map | 
|---|
| 218 | * | 
|---|
| 219 | * pcmcia_map_mem_page() modifies what can be read and written by accessing | 
|---|
| 220 | * an iomem range previously enabled by pcmcia_request_window(), by setting | 
|---|
| 221 | * the card_offset value to @offset. | 
|---|
| 222 | */ | 
|---|
| 223 | int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res, | 
|---|
| 224 | unsigned int offset) | 
|---|
| 225 | { | 
|---|
| 226 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 227 | unsigned int w; | 
|---|
| 228 | int ret; | 
|---|
| 229 |  | 
|---|
| 230 | w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1; | 
|---|
| 231 | if (w >= MAX_WIN) | 
|---|
| 232 | return -EINVAL; | 
|---|
| 233 |  | 
|---|
| 234 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 235 | s->win[w].card_start = offset; | 
|---|
| 236 | ret = s->ops->set_mem_map(s, &s->win[w]); | 
|---|
| 237 | if (ret) | 
|---|
| 238 | dev_warn(&p_dev->dev, "failed to set_mem_map\n"); | 
|---|
| 239 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 240 | return ret; | 
|---|
| 241 | } | 
|---|
| 242 | EXPORT_SYMBOL(pcmcia_map_mem_page); | 
|---|
| 243 |  | 
|---|
| 244 |  | 
|---|
| 245 | /** | 
|---|
| 246 | * pcmcia_fixup_iowidth() - reduce io width to 8bit | 
|---|
| 247 | * @p_dev: pcmcia device | 
|---|
| 248 | * | 
|---|
| 249 | * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the | 
|---|
| 250 | * IO width to 8bit after having called pcmcia_enable_device() | 
|---|
| 251 | * previously. | 
|---|
| 252 | */ | 
|---|
| 253 | int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev) | 
|---|
| 254 | { | 
|---|
| 255 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 256 | pccard_io_map io_off = { 0, 0, 0, 0, 1 }; | 
|---|
| 257 | pccard_io_map io_on; | 
|---|
| 258 | int i, ret = 0; | 
|---|
| 259 |  | 
|---|
| 260 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 261 |  | 
|---|
| 262 | dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n"); | 
|---|
| 263 |  | 
|---|
| 264 | if (!(s->state & SOCKET_PRESENT) || | 
|---|
| 265 | !(p_dev->function_config->state & CONFIG_LOCKED)) { | 
|---|
| 266 | dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); | 
|---|
| 267 | ret = -EACCES; | 
|---|
| 268 | goto unlock; | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | io_on.speed = io_speed; | 
|---|
| 272 | for (i = 0; i < MAX_IO_WIN; i++) { | 
|---|
| 273 | if (!s->io[i].res) | 
|---|
| 274 | continue; | 
|---|
| 275 | io_off.map = i; | 
|---|
| 276 | io_on.map = i; | 
|---|
| 277 |  | 
|---|
| 278 | io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; | 
|---|
| 279 | io_on.start = s->io[i].res->start; | 
|---|
| 280 | io_on.stop = s->io[i].res->end; | 
|---|
| 281 |  | 
|---|
| 282 | s->ops->set_io_map(s, &io_off); | 
|---|
| 283 | msleep(msecs: 40); | 
|---|
| 284 | s->ops->set_io_map(s, &io_on); | 
|---|
| 285 | } | 
|---|
| 286 | unlock: | 
|---|
| 287 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 288 |  | 
|---|
| 289 | return ret; | 
|---|
| 290 | } | 
|---|
| 291 | EXPORT_SYMBOL(pcmcia_fixup_iowidth); | 
|---|
| 292 |  | 
|---|
| 293 |  | 
|---|
| 294 | /** | 
|---|
| 295 | * pcmcia_fixup_vpp() - set Vpp to a new voltage level | 
|---|
| 296 | * @p_dev: pcmcia device | 
|---|
| 297 | * @new_vpp: new Vpp voltage | 
|---|
| 298 | * | 
|---|
| 299 | * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to | 
|---|
| 300 | * a new voltage level between calls to pcmcia_enable_device() | 
|---|
| 301 | * and pcmcia_disable_device(). | 
|---|
| 302 | */ | 
|---|
| 303 | int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp) | 
|---|
| 304 | { | 
|---|
| 305 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 306 | int ret = 0; | 
|---|
| 307 |  | 
|---|
| 308 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 309 |  | 
|---|
| 310 | dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp); | 
|---|
| 311 |  | 
|---|
| 312 | if (!(s->state & SOCKET_PRESENT) || | 
|---|
| 313 | !(p_dev->function_config->state & CONFIG_LOCKED)) { | 
|---|
| 314 | dev_dbg(&p_dev->dev, "No card? Config not locked?\n"); | 
|---|
| 315 | ret = -EACCES; | 
|---|
| 316 | goto unlock; | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | s->socket.Vpp = new_vpp; | 
|---|
| 320 | if (s->ops->set_socket(s, &s->socket)) { | 
|---|
| 321 | dev_warn(&p_dev->dev, "Unable to set VPP\n"); | 
|---|
| 322 | ret = -EIO; | 
|---|
| 323 | goto unlock; | 
|---|
| 324 | } | 
|---|
| 325 | p_dev->vpp = new_vpp; | 
|---|
| 326 |  | 
|---|
| 327 | unlock: | 
|---|
| 328 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 329 |  | 
|---|
| 330 | return ret; | 
|---|
| 331 | } | 
|---|
| 332 | EXPORT_SYMBOL(pcmcia_fixup_vpp); | 
|---|
| 333 |  | 
|---|
| 334 |  | 
|---|
| 335 | /** | 
|---|
| 336 | * pcmcia_release_configuration() - physically disable a PCMCIA device | 
|---|
| 337 | * @p_dev: pcmcia device | 
|---|
| 338 | * | 
|---|
| 339 | * pcmcia_release_configuration() is the 1:1 counterpart to | 
|---|
| 340 | * pcmcia_enable_device(): If a PCMCIA device is no longer used by any | 
|---|
| 341 | * driver, the Vpp voltage is set to 0, IRQs will no longer be generated, | 
|---|
| 342 | * and I/O ranges will be disabled. As pcmcia_release_io() and | 
|---|
| 343 | * pcmcia_release_window() still need to be called, device drivers are | 
|---|
| 344 | * expected to call pcmcia_disable_device() instead. | 
|---|
| 345 | */ | 
|---|
| 346 | int pcmcia_release_configuration(struct pcmcia_device *p_dev) | 
|---|
| 347 | { | 
|---|
| 348 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | 
|---|
| 349 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 350 | config_t *c; | 
|---|
| 351 | int i; | 
|---|
| 352 |  | 
|---|
| 353 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 354 | c = p_dev->function_config; | 
|---|
| 355 | if (p_dev->_locked) { | 
|---|
| 356 | p_dev->_locked = 0; | 
|---|
| 357 | if (--(s->lock_count) == 0) { | 
|---|
| 358 | s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ | 
|---|
| 359 | s->socket.Vpp = 0; | 
|---|
| 360 | s->socket.io_irq = 0; | 
|---|
| 361 | s->ops->set_socket(s, &s->socket); | 
|---|
| 362 | } | 
|---|
| 363 | } | 
|---|
| 364 | if (c->state & CONFIG_LOCKED) { | 
|---|
| 365 | c->state &= ~CONFIG_LOCKED; | 
|---|
| 366 | if (c->state & CONFIG_IO_REQ) | 
|---|
| 367 | for (i = 0; i < MAX_IO_WIN; i++) { | 
|---|
| 368 | if (!s->io[i].res) | 
|---|
| 369 | continue; | 
|---|
| 370 | s->io[i].Config--; | 
|---|
| 371 | if (s->io[i].Config != 0) | 
|---|
| 372 | continue; | 
|---|
| 373 | io.map = i; | 
|---|
| 374 | s->ops->set_io_map(s, &io); | 
|---|
| 375 | } | 
|---|
| 376 | } | 
|---|
| 377 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 378 |  | 
|---|
| 379 | return 0; | 
|---|
| 380 | } | 
|---|
| 381 |  | 
|---|
| 382 |  | 
|---|
| 383 | /** | 
|---|
| 384 | * pcmcia_release_io() - release I/O allocated by a PCMCIA device | 
|---|
| 385 | * @p_dev: pcmcia device | 
|---|
| 386 | * | 
|---|
| 387 | * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA | 
|---|
| 388 | * device.  This may be invoked some time after a card ejection has | 
|---|
| 389 | * already dumped the actual socket configuration, so if the client is | 
|---|
| 390 | * "stale", we don't bother checking the port ranges against the | 
|---|
| 391 | * current socket values. | 
|---|
| 392 | */ | 
|---|
| 393 | static void pcmcia_release_io(struct pcmcia_device *p_dev) | 
|---|
| 394 | { | 
|---|
| 395 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 396 | config_t *c; | 
|---|
| 397 |  | 
|---|
| 398 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 399 | if (!p_dev->_io) | 
|---|
| 400 | goto out; | 
|---|
| 401 |  | 
|---|
| 402 | c = p_dev->function_config; | 
|---|
| 403 |  | 
|---|
| 404 | release_io_space(s, res: &c->io[0]); | 
|---|
| 405 |  | 
|---|
| 406 | if (c->io[1].end) | 
|---|
| 407 | release_io_space(s, res: &c->io[1]); | 
|---|
| 408 |  | 
|---|
| 409 | p_dev->_io = 0; | 
|---|
| 410 | c->state &= ~CONFIG_IO_REQ; | 
|---|
| 411 |  | 
|---|
| 412 | out: | 
|---|
| 413 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 414 | } /* pcmcia_release_io */ | 
|---|
| 415 |  | 
|---|
| 416 |  | 
|---|
| 417 | /** | 
|---|
| 418 | * pcmcia_release_window() - release reserved iomem for PCMCIA devices | 
|---|
| 419 | * @p_dev: pcmcia device | 
|---|
| 420 | * @res: iomem resource to release | 
|---|
| 421 | * | 
|---|
| 422 | * pcmcia_release_window() releases &struct resource *res which was | 
|---|
| 423 | * previously reserved by calling pcmcia_request_window(). | 
|---|
| 424 | */ | 
|---|
| 425 | int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) | 
|---|
| 426 | { | 
|---|
| 427 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 428 | pccard_mem_map *win; | 
|---|
| 429 | unsigned int w; | 
|---|
| 430 |  | 
|---|
| 431 | dev_dbg(&p_dev->dev, "releasing window %pR\n", res); | 
|---|
| 432 |  | 
|---|
| 433 | w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1; | 
|---|
| 434 | if (w >= MAX_WIN) | 
|---|
| 435 | return -EINVAL; | 
|---|
| 436 |  | 
|---|
| 437 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 438 | win = &s->win[w]; | 
|---|
| 439 |  | 
|---|
| 440 | if (!(p_dev->_win & CLIENT_WIN_REQ(w))) { | 
|---|
| 441 | dev_dbg(&p_dev->dev, "not releasing unknown window\n"); | 
|---|
| 442 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 443 | return -EINVAL; | 
|---|
| 444 | } | 
|---|
| 445 |  | 
|---|
| 446 | /* Shut down memory window */ | 
|---|
| 447 | win->flags &= ~MAP_ACTIVE; | 
|---|
| 448 | s->ops->set_mem_map(s, win); | 
|---|
| 449 | s->state &= ~SOCKET_WIN_REQ(w); | 
|---|
| 450 |  | 
|---|
| 451 | /* Release system memory */ | 
|---|
| 452 | if (win->res) { | 
|---|
| 453 | release_resource(new: res); | 
|---|
| 454 | release_resource(new: win->res); | 
|---|
| 455 | kfree(objp: win->res); | 
|---|
| 456 | win->res = NULL; | 
|---|
| 457 | } | 
|---|
| 458 | res->start = res->end = 0; | 
|---|
| 459 | res->flags = IORESOURCE_MEM; | 
|---|
| 460 | p_dev->_win &= ~CLIENT_WIN_REQ(w); | 
|---|
| 461 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 462 |  | 
|---|
| 463 | return 0; | 
|---|
| 464 | } /* pcmcia_release_window */ | 
|---|
| 465 | EXPORT_SYMBOL(pcmcia_release_window); | 
|---|
| 466 |  | 
|---|
| 467 |  | 
|---|
| 468 | /** | 
|---|
| 469 | * pcmcia_enable_device() - set up and activate a PCMCIA device | 
|---|
| 470 | * @p_dev: the associated PCMCIA device | 
|---|
| 471 | * | 
|---|
| 472 | * pcmcia_enable_device() physically enables a PCMCIA device. It parses | 
|---|
| 473 | * the flags passed to in @flags and stored in @p_dev->flags and sets up | 
|---|
| 474 | * the Vpp voltage, enables the speaker line, I/O ports and store proper | 
|---|
| 475 | * values to configuration registers. | 
|---|
| 476 | */ | 
|---|
| 477 | int pcmcia_enable_device(struct pcmcia_device *p_dev) | 
|---|
| 478 | { | 
|---|
| 479 | int i; | 
|---|
| 480 | unsigned int base; | 
|---|
| 481 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 482 | config_t *c; | 
|---|
| 483 | pccard_io_map iomap; | 
|---|
| 484 | unsigned char status = 0; | 
|---|
| 485 | unsigned char ext_status = 0; | 
|---|
| 486 | unsigned char option = 0; | 
|---|
| 487 | unsigned int flags = p_dev->config_flags; | 
|---|
| 488 |  | 
|---|
| 489 | if (!(s->state & SOCKET_PRESENT)) | 
|---|
| 490 | return -ENODEV; | 
|---|
| 491 |  | 
|---|
| 492 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 493 | c = p_dev->function_config; | 
|---|
| 494 | if (c->state & CONFIG_LOCKED) { | 
|---|
| 495 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 496 | dev_dbg(&p_dev->dev, "Configuration is locked\n"); | 
|---|
| 497 | return -EACCES; | 
|---|
| 498 | } | 
|---|
| 499 |  | 
|---|
| 500 | /* Do power control.  We don't allow changes in Vcc. */ | 
|---|
| 501 | s->socket.Vpp = p_dev->vpp; | 
|---|
| 502 | if (s->ops->set_socket(s, &s->socket)) { | 
|---|
| 503 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 504 | dev_warn(&p_dev->dev, "Unable to set socket state\n"); | 
|---|
| 505 | return -EINVAL; | 
|---|
| 506 | } | 
|---|
| 507 |  | 
|---|
| 508 | /* Pick memory or I/O card, DMA mode, interrupt */ | 
|---|
| 509 | if (p_dev->_io || flags & CONF_ENABLE_IRQ) | 
|---|
| 510 | flags |= CONF_ENABLE_IOCARD; | 
|---|
| 511 | if (flags & CONF_ENABLE_IOCARD) | 
|---|
| 512 | s->socket.flags |= SS_IOCARD; | 
|---|
| 513 | if (flags & CONF_ENABLE_ZVCARD) | 
|---|
| 514 | s->socket.flags |= SS_ZVCARD | SS_IOCARD; | 
|---|
| 515 | if (flags & CONF_ENABLE_SPKR) { | 
|---|
| 516 | s->socket.flags |= SS_SPKR_ENA; | 
|---|
| 517 | status = CCSR_AUDIO_ENA; | 
|---|
| 518 | if (!(p_dev->config_regs & PRESENT_STATUS)) | 
|---|
| 519 | dev_warn(&p_dev->dev, "speaker requested, but " | 
|---|
| 520 | "PRESENT_STATUS not set!\n"); | 
|---|
| 521 | } | 
|---|
| 522 | if (flags & CONF_ENABLE_IRQ) | 
|---|
| 523 | s->socket.io_irq = s->pcmcia_irq; | 
|---|
| 524 | else | 
|---|
| 525 | s->socket.io_irq = 0; | 
|---|
| 526 | if (flags & CONF_ENABLE_ESR) { | 
|---|
| 527 | p_dev->config_regs |= PRESENT_EXT_STATUS; | 
|---|
| 528 | ext_status = ESR_REQ_ATTN_ENA; | 
|---|
| 529 | } | 
|---|
| 530 | s->ops->set_socket(s, &s->socket); | 
|---|
| 531 | s->lock_count++; | 
|---|
| 532 |  | 
|---|
| 533 | dev_dbg(&p_dev->dev, | 
|---|
| 534 | "enable_device: V %d, flags %x, base %x, regs %x, idx %x\n", | 
|---|
| 535 | p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs, | 
|---|
| 536 | p_dev->config_index); | 
|---|
| 537 |  | 
|---|
| 538 | /* Set up CIS configuration registers */ | 
|---|
| 539 | base = p_dev->config_base; | 
|---|
| 540 | if (p_dev->config_regs & PRESENT_COPY) { | 
|---|
| 541 | u16 tmp = 0; | 
|---|
| 542 | dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n"); | 
|---|
| 543 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_SCR)>>1, len: 1, ptr: &tmp); | 
|---|
| 544 | } | 
|---|
| 545 | if (p_dev->config_regs & PRESENT_PIN_REPLACE) { | 
|---|
| 546 | u16 tmp = 0; | 
|---|
| 547 | dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n"); | 
|---|
| 548 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_PRR)>>1, len: 1, ptr: &tmp); | 
|---|
| 549 | } | 
|---|
| 550 | if (p_dev->config_regs & PRESENT_OPTION) { | 
|---|
| 551 | if (s->functions == 1) { | 
|---|
| 552 | option = p_dev->config_index & COR_CONFIG_MASK; | 
|---|
| 553 | } else { | 
|---|
| 554 | option = p_dev->config_index & COR_MFC_CONFIG_MASK; | 
|---|
| 555 | option |= COR_FUNC_ENA|COR_IREQ_ENA; | 
|---|
| 556 | if (p_dev->config_regs & PRESENT_IOBASE_0) | 
|---|
| 557 | option |= COR_ADDR_DECODE; | 
|---|
| 558 | } | 
|---|
| 559 | if ((flags & CONF_ENABLE_IRQ) && | 
|---|
| 560 | !(flags & CONF_ENABLE_PULSE_IRQ)) | 
|---|
| 561 | option |= COR_LEVEL_REQ; | 
|---|
| 562 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_COR)>>1, len: 1, ptr: &option); | 
|---|
| 563 | msleep(msecs: 40); | 
|---|
| 564 | } | 
|---|
| 565 | if (p_dev->config_regs & PRESENT_STATUS) | 
|---|
| 566 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_CCSR)>>1, len: 1, ptr: &status); | 
|---|
| 567 |  | 
|---|
| 568 | if (p_dev->config_regs & PRESENT_EXT_STATUS) | 
|---|
| 569 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_ESR)>>1, len: 1, | 
|---|
| 570 | ptr: &ext_status); | 
|---|
| 571 |  | 
|---|
| 572 | if (p_dev->config_regs & PRESENT_IOBASE_0) { | 
|---|
| 573 | u8 b = c->io[0].start & 0xff; | 
|---|
| 574 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_IOBASE_0)>>1, len: 1, ptr: &b); | 
|---|
| 575 | b = (c->io[0].start >> 8) & 0xff; | 
|---|
| 576 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_IOBASE_1)>>1, len: 1, ptr: &b); | 
|---|
| 577 | } | 
|---|
| 578 | if (p_dev->config_regs & PRESENT_IOSIZE) { | 
|---|
| 579 | u8 b = resource_size(res: &c->io[0]) + resource_size(res: &c->io[1]) - 1; | 
|---|
| 580 | pcmcia_write_cis_mem(s, attr: 1, addr: (base + CISREG_IOSIZE)>>1, len: 1, ptr: &b); | 
|---|
| 581 | } | 
|---|
| 582 |  | 
|---|
| 583 | /* Configure I/O windows */ | 
|---|
| 584 | if (c->state & CONFIG_IO_REQ) { | 
|---|
| 585 | iomap.speed = io_speed; | 
|---|
| 586 | for (i = 0; i < MAX_IO_WIN; i++) | 
|---|
| 587 | if (s->io[i].res) { | 
|---|
| 588 | iomap.map = i; | 
|---|
| 589 | iomap.flags = MAP_ACTIVE; | 
|---|
| 590 | switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) { | 
|---|
| 591 | case IO_DATA_PATH_WIDTH_16: | 
|---|
| 592 | iomap.flags |= MAP_16BIT; break; | 
|---|
| 593 | case IO_DATA_PATH_WIDTH_AUTO: | 
|---|
| 594 | iomap.flags |= MAP_AUTOSZ; break; | 
|---|
| 595 | default: | 
|---|
| 596 | break; | 
|---|
| 597 | } | 
|---|
| 598 | iomap.start = s->io[i].res->start; | 
|---|
| 599 | iomap.stop = s->io[i].res->end; | 
|---|
| 600 | s->ops->set_io_map(s, &iomap); | 
|---|
| 601 | s->io[i].Config++; | 
|---|
| 602 | } | 
|---|
| 603 | } | 
|---|
| 604 |  | 
|---|
| 605 | c->state |= CONFIG_LOCKED; | 
|---|
| 606 | p_dev->_locked = 1; | 
|---|
| 607 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 608 | return 0; | 
|---|
| 609 | } /* pcmcia_enable_device */ | 
|---|
| 610 | EXPORT_SYMBOL(pcmcia_enable_device); | 
|---|
| 611 |  | 
|---|
| 612 |  | 
|---|
| 613 | /** | 
|---|
| 614 | * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices | 
|---|
| 615 | * @p_dev: the associated PCMCIA device | 
|---|
| 616 | * | 
|---|
| 617 | * pcmcia_request_io() attempts to reserve the IO port ranges specified in | 
|---|
| 618 | * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The | 
|---|
| 619 | * "start" value is the requested start of the IO port resource; "end" | 
|---|
| 620 | * reflects the number of ports requested. The number of IO lines requested | 
|---|
| 621 | * is specified in &struct pcmcia_device @p_dev->io_lines. | 
|---|
| 622 | */ | 
|---|
| 623 | int pcmcia_request_io(struct pcmcia_device *p_dev) | 
|---|
| 624 | { | 
|---|
| 625 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 626 | config_t *c = p_dev->function_config; | 
|---|
| 627 | int ret = -EINVAL; | 
|---|
| 628 |  | 
|---|
| 629 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 630 | dev_dbg(&p_dev->dev, "pcmcia_request_io: %pR , %pR", | 
|---|
| 631 | &c->io[0], &c->io[1]); | 
|---|
| 632 |  | 
|---|
| 633 | if (!(s->state & SOCKET_PRESENT)) { | 
|---|
| 634 | dev_dbg(&p_dev->dev, "pcmcia_request_io: No card present\n"); | 
|---|
| 635 | goto out; | 
|---|
| 636 | } | 
|---|
| 637 |  | 
|---|
| 638 | if (c->state & CONFIG_LOCKED) { | 
|---|
| 639 | dev_dbg(&p_dev->dev, "Configuration is locked\n"); | 
|---|
| 640 | goto out; | 
|---|
| 641 | } | 
|---|
| 642 | if (c->state & CONFIG_IO_REQ) { | 
|---|
| 643 | dev_dbg(&p_dev->dev, "IO already configured\n"); | 
|---|
| 644 | goto out; | 
|---|
| 645 | } | 
|---|
| 646 |  | 
|---|
| 647 | ret = alloc_io_space(s, res: &c->io[0], lines: p_dev->io_lines); | 
|---|
| 648 | if (ret) | 
|---|
| 649 | goto out; | 
|---|
| 650 |  | 
|---|
| 651 | if (c->io[1].end) { | 
|---|
| 652 | ret = alloc_io_space(s, res: &c->io[1], lines: p_dev->io_lines); | 
|---|
| 653 | if (ret) { | 
|---|
| 654 | struct resource tmp = c->io[0]; | 
|---|
| 655 | /* release the previously allocated resource */ | 
|---|
| 656 | release_io_space(s, res: &c->io[0]); | 
|---|
| 657 | /* but preserve the settings, for they worked... */ | 
|---|
| 658 | c->io[0].end = resource_size(res: &tmp); | 
|---|
| 659 | c->io[0].start = tmp.start; | 
|---|
| 660 | c->io[0].flags = tmp.flags; | 
|---|
| 661 | goto out; | 
|---|
| 662 | } | 
|---|
| 663 | } else | 
|---|
| 664 | c->io[1].start = 0; | 
|---|
| 665 |  | 
|---|
| 666 | c->state |= CONFIG_IO_REQ; | 
|---|
| 667 | p_dev->_io = 1; | 
|---|
| 668 |  | 
|---|
| 669 | dev_dbg(&p_dev->dev, "pcmcia_request_io succeeded: %pR , %pR", | 
|---|
| 670 | &c->io[0], &c->io[1]); | 
|---|
| 671 | out: | 
|---|
| 672 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 673 |  | 
|---|
| 674 | return ret; | 
|---|
| 675 | } /* pcmcia_request_io */ | 
|---|
| 676 | EXPORT_SYMBOL(pcmcia_request_io); | 
|---|
| 677 |  | 
|---|
| 678 |  | 
|---|
| 679 | /** | 
|---|
| 680 | * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device | 
|---|
| 681 | * @p_dev: the associated PCMCIA device | 
|---|
| 682 | * @handler: IRQ handler to register | 
|---|
| 683 | * | 
|---|
| 684 | * pcmcia_request_irq() is a wrapper around request_irq() which allows | 
|---|
| 685 | * the PCMCIA core to clean up the registration in pcmcia_disable_device(). | 
|---|
| 686 | * Drivers are free to use request_irq() directly, but then they need to | 
|---|
| 687 | * call free_irq() themselves, too. Also, only %IRQF_SHARED capable IRQ | 
|---|
| 688 | * handlers are allowed. | 
|---|
| 689 | */ | 
|---|
| 690 | int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev, | 
|---|
| 691 | irq_handler_t handler) | 
|---|
| 692 | { | 
|---|
| 693 | int ret; | 
|---|
| 694 |  | 
|---|
| 695 | if (!p_dev->irq) | 
|---|
| 696 | return -EINVAL; | 
|---|
| 697 |  | 
|---|
| 698 | ret = request_irq(irq: p_dev->irq, handler, IRQF_SHARED, | 
|---|
| 699 | name: p_dev->devname, dev: p_dev->priv); | 
|---|
| 700 | if (!ret) | 
|---|
| 701 | p_dev->_irq = 1; | 
|---|
| 702 |  | 
|---|
| 703 | return ret; | 
|---|
| 704 | } | 
|---|
| 705 | EXPORT_SYMBOL(pcmcia_request_irq); | 
|---|
| 706 |  | 
|---|
| 707 |  | 
|---|
| 708 | #ifdef CONFIG_PCMCIA_PROBE | 
|---|
| 709 |  | 
|---|
| 710 | /* mask of IRQs already reserved by other cards, we should avoid using them */ | 
|---|
| 711 | static u8 pcmcia_used_irq[32]; | 
|---|
| 712 |  | 
|---|
| 713 | static irqreturn_t test_action(int cpl, void *dev_id) | 
|---|
| 714 | { | 
|---|
| 715 | return IRQ_NONE; | 
|---|
| 716 | } | 
|---|
| 717 |  | 
|---|
| 718 | /** | 
|---|
| 719 | * pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used | 
|---|
| 720 | * @p_dev: the associated PCMCIA device | 
|---|
| 721 | * @type:  IRQ type (flags) | 
|---|
| 722 | * | 
|---|
| 723 | * locking note: must be called with ops_mutex locked. | 
|---|
| 724 | */ | 
|---|
| 725 | static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) | 
|---|
| 726 | { | 
|---|
| 727 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 728 | unsigned int try, irq; | 
|---|
| 729 | u32 mask = s->irq_mask; | 
|---|
| 730 | int ret = -ENODEV; | 
|---|
| 731 |  | 
|---|
| 732 | for (try = 0; try < 64; try++) { | 
|---|
| 733 | irq = try % 32; | 
|---|
| 734 |  | 
|---|
| 735 | if (irq > NR_IRQS) | 
|---|
| 736 | continue; | 
|---|
| 737 |  | 
|---|
| 738 | /* marked as available by driver, not blocked by userspace? */ | 
|---|
| 739 | if (!((mask >> irq) & 1)) | 
|---|
| 740 | continue; | 
|---|
| 741 |  | 
|---|
| 742 | /* avoid an IRQ which is already used by another PCMCIA card */ | 
|---|
| 743 | if ((try < 32) && pcmcia_used_irq[irq]) | 
|---|
| 744 | continue; | 
|---|
| 745 |  | 
|---|
| 746 | /* register the correct driver, if possible, to check whether | 
|---|
| 747 | * registering a dummy handle works, i.e. if the IRQ isn't | 
|---|
| 748 | * marked as used by the kernel resource management core */ | 
|---|
| 749 | ret = request_irq(irq, test_action, type, p_dev->devname, | 
|---|
| 750 | p_dev); | 
|---|
| 751 | if (!ret) { | 
|---|
| 752 | free_irq(irq, p_dev); | 
|---|
| 753 | p_dev->irq = s->pcmcia_irq = irq; | 
|---|
| 754 | pcmcia_used_irq[irq]++; | 
|---|
| 755 | break; | 
|---|
| 756 | } | 
|---|
| 757 | } | 
|---|
| 758 |  | 
|---|
| 759 | return ret; | 
|---|
| 760 | } | 
|---|
| 761 |  | 
|---|
| 762 | void pcmcia_cleanup_irq(struct pcmcia_socket *s) | 
|---|
| 763 | { | 
|---|
| 764 | pcmcia_used_irq[s->pcmcia_irq]--; | 
|---|
| 765 | s->pcmcia_irq = 0; | 
|---|
| 766 | } | 
|---|
| 767 |  | 
|---|
| 768 | #else /* CONFIG_PCMCIA_PROBE */ | 
|---|
| 769 |  | 
|---|
| 770 | static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) | 
|---|
| 771 | { | 
|---|
| 772 | return -EINVAL; | 
|---|
| 773 | } | 
|---|
| 774 |  | 
|---|
| 775 | void pcmcia_cleanup_irq(struct pcmcia_socket *s) | 
|---|
| 776 | { | 
|---|
| 777 | s->pcmcia_irq = 0; | 
|---|
| 778 | return; | 
|---|
| 779 | } | 
|---|
| 780 |  | 
|---|
| 781 | #endif  /* CONFIG_PCMCIA_PROBE */ | 
|---|
| 782 |  | 
|---|
| 783 |  | 
|---|
| 784 | /** | 
|---|
| 785 | * pcmcia_setup_irq() - determine IRQ to be used for device | 
|---|
| 786 | * @p_dev: the associated PCMCIA device | 
|---|
| 787 | * | 
|---|
| 788 | * locking note: must be called with ops_mutex locked. | 
|---|
| 789 | */ | 
|---|
| 790 | int pcmcia_setup_irq(struct pcmcia_device *p_dev) | 
|---|
| 791 | { | 
|---|
| 792 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 793 |  | 
|---|
| 794 | if (p_dev->irq) | 
|---|
| 795 | return 0; | 
|---|
| 796 |  | 
|---|
| 797 | /* already assigned? */ | 
|---|
| 798 | if (s->pcmcia_irq) { | 
|---|
| 799 | p_dev->irq = s->pcmcia_irq; | 
|---|
| 800 | return 0; | 
|---|
| 801 | } | 
|---|
| 802 |  | 
|---|
| 803 | /* prefer an exclusive ISA irq */ | 
|---|
| 804 | if (!pcmcia_setup_isa_irq(p_dev, type: 0)) | 
|---|
| 805 | return 0; | 
|---|
| 806 |  | 
|---|
| 807 | /* but accept a shared ISA irq */ | 
|---|
| 808 | if (!pcmcia_setup_isa_irq(p_dev, IRQF_SHARED)) | 
|---|
| 809 | return 0; | 
|---|
| 810 |  | 
|---|
| 811 | /* but use the PCI irq otherwise */ | 
|---|
| 812 | if (s->pci_irq) { | 
|---|
| 813 | p_dev->irq = s->pcmcia_irq = s->pci_irq; | 
|---|
| 814 | return 0; | 
|---|
| 815 | } | 
|---|
| 816 |  | 
|---|
| 817 | return -EINVAL; | 
|---|
| 818 | } | 
|---|
| 819 |  | 
|---|
| 820 |  | 
|---|
| 821 | /** | 
|---|
| 822 | * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices | 
|---|
| 823 | * @p_dev: the associated PCMCIA device | 
|---|
| 824 | * @res: &struct resource pointing to p_dev->resource[2..5] | 
|---|
| 825 | * @speed: access speed | 
|---|
| 826 | * | 
|---|
| 827 | * pcmcia_request_window() attepts to reserve an iomem ranges specified in | 
|---|
| 828 | * &struct resource @res pointing to one of the entries in | 
|---|
| 829 | * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the | 
|---|
| 830 | * requested start of the IO mem resource; "end" reflects the size | 
|---|
| 831 | * requested. | 
|---|
| 832 | */ | 
|---|
| 833 | int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res, | 
|---|
| 834 | unsigned int speed) | 
|---|
| 835 | { | 
|---|
| 836 | struct pcmcia_socket *s = p_dev->socket; | 
|---|
| 837 | pccard_mem_map *win; | 
|---|
| 838 | u_long align; | 
|---|
| 839 | int w; | 
|---|
| 840 |  | 
|---|
| 841 | dev_dbg(&p_dev->dev, "request_window %pR %d\n", res, speed); | 
|---|
| 842 |  | 
|---|
| 843 | if (!(s->state & SOCKET_PRESENT)) { | 
|---|
| 844 | dev_dbg(&p_dev->dev, "No card present\n"); | 
|---|
| 845 | return -ENODEV; | 
|---|
| 846 | } | 
|---|
| 847 |  | 
|---|
| 848 | /* Window size defaults to smallest available */ | 
|---|
| 849 | if (res->end == 0) | 
|---|
| 850 | res->end = s->map_size; | 
|---|
| 851 | align = (s->features & SS_CAP_MEM_ALIGN) ? res->end : s->map_size; | 
|---|
| 852 | if (res->end & (s->map_size-1)) { | 
|---|
| 853 | dev_dbg(&p_dev->dev, "invalid map size\n"); | 
|---|
| 854 | return -EINVAL; | 
|---|
| 855 | } | 
|---|
| 856 | if ((res->start && (s->features & SS_CAP_STATIC_MAP)) || | 
|---|
| 857 | (res->start & (align-1))) { | 
|---|
| 858 | dev_dbg(&p_dev->dev, "invalid base address\n"); | 
|---|
| 859 | return -EINVAL; | 
|---|
| 860 | } | 
|---|
| 861 | if (res->start) | 
|---|
| 862 | align = 0; | 
|---|
| 863 |  | 
|---|
| 864 | /* Allocate system memory window */ | 
|---|
| 865 | mutex_lock(lock: &s->ops_mutex); | 
|---|
| 866 | for (w = 0; w < MAX_WIN; w++) | 
|---|
| 867 | if (!(s->state & SOCKET_WIN_REQ(w))) | 
|---|
| 868 | break; | 
|---|
| 869 | if (w == MAX_WIN) { | 
|---|
| 870 | dev_dbg(&p_dev->dev, "all windows are used already\n"); | 
|---|
| 871 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 872 | return -EINVAL; | 
|---|
| 873 | } | 
|---|
| 874 |  | 
|---|
| 875 | win = &s->win[w]; | 
|---|
| 876 |  | 
|---|
| 877 | if (!(s->features & SS_CAP_STATIC_MAP)) { | 
|---|
| 878 | win->res = pcmcia_find_mem_region(base: res->start, num: res->end, align, | 
|---|
| 879 | low: 0, s); | 
|---|
| 880 | if (!win->res) { | 
|---|
| 881 | dev_dbg(&p_dev->dev, "allocating mem region failed\n"); | 
|---|
| 882 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 883 | return -EINVAL; | 
|---|
| 884 | } | 
|---|
| 885 | } | 
|---|
| 886 | p_dev->_win |= CLIENT_WIN_REQ(w); | 
|---|
| 887 |  | 
|---|
| 888 | /* Configure the socket controller */ | 
|---|
| 889 | win->map = w+1; | 
|---|
| 890 | win->flags = res->flags & WIN_FLAGS_MAP; | 
|---|
| 891 | win->speed = speed; | 
|---|
| 892 | win->card_start = 0; | 
|---|
| 893 |  | 
|---|
| 894 | if (s->ops->set_mem_map(s, win) != 0) { | 
|---|
| 895 | dev_dbg(&p_dev->dev, "failed to set memory mapping\n"); | 
|---|
| 896 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 897 | return -EIO; | 
|---|
| 898 | } | 
|---|
| 899 | s->state |= SOCKET_WIN_REQ(w); | 
|---|
| 900 |  | 
|---|
| 901 | /* Return window handle */ | 
|---|
| 902 | if (s->features & SS_CAP_STATIC_MAP) | 
|---|
| 903 | res->start = win->static_start; | 
|---|
| 904 | else | 
|---|
| 905 | res->start = win->res->start; | 
|---|
| 906 |  | 
|---|
| 907 | /* convert to new-style resources */ | 
|---|
| 908 | res->end += res->start - 1; | 
|---|
| 909 | res->flags &= ~WIN_FLAGS_REQ; | 
|---|
| 910 | res->flags |= (win->map << 2) | IORESOURCE_MEM; | 
|---|
| 911 | res->parent = win->res; | 
|---|
| 912 | if (win->res) | 
|---|
| 913 | request_resource(root: &iomem_resource, new: res); | 
|---|
| 914 |  | 
|---|
| 915 | dev_dbg(&p_dev->dev, "request_window results in %pR\n", res); | 
|---|
| 916 |  | 
|---|
| 917 | mutex_unlock(lock: &s->ops_mutex); | 
|---|
| 918 |  | 
|---|
| 919 | return 0; | 
|---|
| 920 | } /* pcmcia_request_window */ | 
|---|
| 921 | EXPORT_SYMBOL(pcmcia_request_window); | 
|---|
| 922 |  | 
|---|
| 923 |  | 
|---|
| 924 | /** | 
|---|
| 925 | * pcmcia_disable_device() - disable and clean up a PCMCIA device | 
|---|
| 926 | * @p_dev: the associated PCMCIA device | 
|---|
| 927 | * | 
|---|
| 928 | * pcmcia_disable_device() is the driver-callable counterpart to | 
|---|
| 929 | * pcmcia_enable_device(): If a PCMCIA device is no longer used, | 
|---|
| 930 | * drivers are expected to clean up and disable the device by calling | 
|---|
| 931 | * this function. Any I/O ranges (iomem and ioports) will be released, | 
|---|
| 932 | * the Vpp voltage will be set to 0, and IRQs will no longer be | 
|---|
| 933 | * generated -- at least if there is no other card function (of | 
|---|
| 934 | * multifunction devices) being used. | 
|---|
| 935 | */ | 
|---|
| 936 | void pcmcia_disable_device(struct pcmcia_device *p_dev) | 
|---|
| 937 | { | 
|---|
| 938 | int i; | 
|---|
| 939 |  | 
|---|
| 940 | dev_dbg(&p_dev->dev, "disabling device\n"); | 
|---|
| 941 |  | 
|---|
| 942 | for (i = 0; i < MAX_WIN; i++) { | 
|---|
| 943 | struct resource *res = p_dev->resource[MAX_IO_WIN + i]; | 
|---|
| 944 | if (res->flags & WIN_FLAGS_REQ) | 
|---|
| 945 | pcmcia_release_window(p_dev, res); | 
|---|
| 946 | } | 
|---|
| 947 |  | 
|---|
| 948 | pcmcia_release_configuration(p_dev); | 
|---|
| 949 | pcmcia_release_io(p_dev); | 
|---|
| 950 | if (p_dev->_irq) { | 
|---|
| 951 | free_irq(p_dev->irq, p_dev->priv); | 
|---|
| 952 | p_dev->_irq = 0; | 
|---|
| 953 | } | 
|---|
| 954 | } | 
|---|
| 955 | EXPORT_SYMBOL(pcmcia_disable_device); | 
|---|
| 956 |  | 
|---|