linux/drivers/pcmcia/pcmcia_resource.c
<<
>>
Prefs
   1/*
   2 * PCMCIA 16-bit resource management functions
   3 *
   4 * The initial developer of the original code is David A. Hinds
   5 * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
   6 * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
   7 *
   8 * Copyright (C) 1999        David A. Hinds
   9 * Copyright (C) 2004-2005   Dominik Brodowski
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 *
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/interrupt.h>
  20#include <linux/delay.h>
  21#include <linux/pci.h>
  22#include <linux/device.h>
  23
  24#include <pcmcia/cs_types.h>
  25#include <pcmcia/ss.h>
  26#include <pcmcia/cs.h>
  27#include <pcmcia/cistpl.h>
  28#include <pcmcia/cisreg.h>
  29#include <pcmcia/ds.h>
  30
  31#include "cs_internal.h"
  32#include "ds_internal.h"
  33
  34
  35/* Access speed for IO windows */
  36static int io_speed = 0;
  37module_param(io_speed, int, 0444);
  38
  39
  40#ifdef CONFIG_PCMCIA_PROBE
  41#include <asm/irq.h>
  42/* mask of IRQs already reserved by other cards, we should avoid using them */
  43static u8 pcmcia_used_irq[NR_IRQS];
  44#endif
  45
  46
  47#ifdef DEBUG
  48extern int ds_pc_debug;
  49
  50#define ds_dbg(skt, lvl, fmt, arg...) do {                      \
  51        if (ds_pc_debug >= lvl)                                 \
  52                printk(KERN_DEBUG "pcmcia_resource: %s: " fmt,  \
  53                        cs_socket_name(skt) , ## arg);          \
  54} while (0)
  55#else
  56#define ds_dbg(lvl, fmt, arg...) do { } while (0)
  57#endif
  58
  59
  60
  61/** alloc_io_space
  62 *
  63 * Special stuff for managing IO windows, because they are scarce
  64 */
  65
  66static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
  67                          unsigned int *base, unsigned int num, u_int lines)
  68{
  69        int i;
  70        unsigned int try, align;
  71
  72        align = (*base) ? (lines ? 1<<lines : 0) : 1;
  73        if (align && (align < num)) {
  74                if (*base) {
  75                        ds_dbg(s, 0, "odd IO request: num %#x align %#x\n",
  76                               num, align);
  77                        align = 0;
  78                } else
  79                        while (align && (align < num)) align <<= 1;
  80        }
  81        if (*base & ~(align-1)) {
  82                ds_dbg(s, 0, "odd IO request: base %#x align %#x\n",
  83                       *base, align);
  84                align = 0;
  85        }
  86        if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
  87                *base = s->io_offset | (*base & 0x0fff);
  88                return 0;
  89        }
  90        /* Check for an already-allocated window that must conflict with
  91         * what was asked for.  It is a hack because it does not catch all
  92         * potential conflicts, just the most obvious ones.
  93         */
  94        for (i = 0; i < MAX_IO_WIN; i++)
  95                if ((s->io[i].res) && *base &&
  96                    ((s->io[i].res->start & (align-1)) == *base))
  97                        return 1;
  98        for (i = 0; i < MAX_IO_WIN; i++) {
  99                if (!s->io[i].res) {
 100                        s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
 101                        if (s->io[i].res) {
 102                                *base = s->io[i].res->start;
 103                                s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
 104                                s->io[i].InUse = num;
 105                                break;
 106                        } else
 107                                return 1;
 108                } else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS))
 109                        continue;
 110                /* Try to extend top of window */
 111                try = s->io[i].res->end + 1;
 112                if ((*base == 0) || (*base == try))
 113                        if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
 114                                                    s->io[i].res->end + num, s) == 0) {
 115                                *base = try;
 116                                s->io[i].InUse += num;
 117                                break;
 118                        }
 119                /* Try to extend bottom of window */
 120                try = s->io[i].res->start - num;
 121                if ((*base == 0) || (*base == try))
 122                        if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
 123                                                    s->io[i].res->end, s) == 0) {
 124                                *base = try;
 125                                s->io[i].InUse += num;
 126                                break;
 127                        }
 128        }
 129        return (i == MAX_IO_WIN);
 130} /* alloc_io_space */
 131
 132
 133static void release_io_space(struct pcmcia_socket *s, unsigned int base,
 134                             unsigned int num)
 135{
 136        int i;
 137
 138        for (i = 0; i < MAX_IO_WIN; i++) {
 139                if (!s->io[i].res)
 140                        continue;
 141                if ((s->io[i].res->start <= base) &&
 142                    (s->io[i].res->end >= base+num-1)) {
 143                        s->io[i].InUse -= num;
 144                        /* Free the window if no one else is using it */
 145                        if (s->io[i].InUse == 0) {
 146                                release_resource(s->io[i].res);
 147                                kfree(s->io[i].res);
 148                                s->io[i].res = NULL;
 149                        }
 150                }
 151        }
 152} /* release_io_space */
 153
 154
 155/** pccard_access_configuration_register
 156 *
 157 * Access_configuration_register() reads and writes configuration
 158 * registers in attribute memory.  Memory window 0 is reserved for
 159 * this and the tuple reading services.
 160 */
 161
 162int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
 163                                         conf_reg_t *reg)
 164{
 165        struct pcmcia_socket *s;
 166        config_t *c;
 167        int addr;
 168        u_char val;
 169
 170        if (!p_dev || !p_dev->function_config)
 171                return CS_NO_CARD;
 172
 173        s = p_dev->socket;
 174        c = p_dev->function_config;
 175
 176        if (!(c->state & CONFIG_LOCKED))
 177                return CS_CONFIGURATION_LOCKED;
 178
 179        addr = (c->ConfigBase + reg->Offset) >> 1;
 180
 181        switch (reg->Action) {
 182        case CS_READ:
 183                pcmcia_read_cis_mem(s, 1, addr, 1, &val);
 184                reg->Value = val;
 185                break;
 186        case CS_WRITE:
 187                val = reg->Value;
 188                pcmcia_write_cis_mem(s, 1, addr, 1, &val);
 189                break;
 190        default:
 191                return CS_BAD_ARGS;
 192                break;
 193        }
 194        return CS_SUCCESS;
 195} /* pcmcia_access_configuration_register */
 196EXPORT_SYMBOL(pcmcia_access_configuration_register);
 197
 198
 199int pccard_get_configuration_info(struct pcmcia_socket *s,
 200                                  struct pcmcia_device *p_dev,
 201                                  config_info_t *config)
 202{
 203        config_t *c;
 204
 205        if (!(s->state & SOCKET_PRESENT))
 206                return CS_NO_CARD;
 207
 208
 209#ifdef CONFIG_CARDBUS
 210        if (s->state & SOCKET_CARDBUS) {
 211                memset(config, 0, sizeof(config_info_t));
 212                config->Vcc = s->socket.Vcc;
 213                config->Vpp1 = config->Vpp2 = s->socket.Vpp;
 214                config->Option = s->cb_dev->subordinate->number;
 215                if (s->state & SOCKET_CARDBUS_CONFIG) {
 216                        config->Attributes = CONF_VALID_CLIENT;
 217                        config->IntType = INT_CARDBUS;
 218                        config->AssignedIRQ = s->irq.AssignedIRQ;
 219                        if (config->AssignedIRQ)
 220                                config->Attributes |= CONF_ENABLE_IRQ;
 221                        if (s->io[0].res) {
 222                                config->BasePort1 = s->io[0].res->start;
 223                                config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
 224                        }
 225                }
 226                return CS_SUCCESS;
 227        }
 228#endif
 229
 230        if (p_dev) {
 231                c = p_dev->function_config;
 232                config->Function = p_dev->func;
 233        } else {
 234                c = NULL;
 235                config->Function = 0;
 236        }
 237
 238        if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
 239                config->Attributes = 0;
 240                config->Vcc = s->socket.Vcc;
 241                config->Vpp1 = config->Vpp2 = s->socket.Vpp;
 242                return CS_SUCCESS;
 243        }
 244
 245        config->Attributes = c->Attributes | CONF_VALID_CLIENT;
 246        config->Vcc = s->socket.Vcc;
 247        config->Vpp1 = config->Vpp2 = s->socket.Vpp;
 248        config->IntType = c->IntType;
 249        config->ConfigBase = c->ConfigBase;
 250        config->Status = c->Status;
 251        config->Pin = c->Pin;
 252        config->Copy = c->Copy;
 253        config->Option = c->Option;
 254        config->ExtStatus = c->ExtStatus;
 255        config->Present = config->CardValues = c->CardValues;
 256        config->IRQAttributes = c->irq.Attributes;
 257        config->AssignedIRQ = s->irq.AssignedIRQ;
 258        config->BasePort1 = c->io.BasePort1;
 259        config->NumPorts1 = c->io.NumPorts1;
 260        config->Attributes1 = c->io.Attributes1;
 261        config->BasePort2 = c->io.BasePort2;
 262        config->NumPorts2 = c->io.NumPorts2;
 263        config->Attributes2 = c->io.Attributes2;
 264        config->IOAddrLines = c->io.IOAddrLines;
 265
 266        return CS_SUCCESS;
 267} /* pccard_get_configuration_info */
 268
 269int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
 270                                  config_info_t *config)
 271{
 272        return pccard_get_configuration_info(p_dev->socket, p_dev,
 273                                             config);
 274}
 275EXPORT_SYMBOL(pcmcia_get_configuration_info);
 276
 277
 278/** pcmcia_get_window
 279 */
 280int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
 281                      int idx, win_req_t *req)
 282{
 283        window_t *win;
 284        int w;
 285
 286        if (!s || !(s->state & SOCKET_PRESENT))
 287                return CS_NO_CARD;
 288        for (w = idx; w < MAX_WIN; w++)
 289                if (s->state & SOCKET_WIN_REQ(w))
 290                        break;
 291        if (w == MAX_WIN)
 292                return CS_NO_MORE_ITEMS;
 293        win = &s->win[w];
 294        req->Base = win->ctl.res->start;
 295        req->Size = win->ctl.res->end - win->ctl.res->start + 1;
 296        req->AccessSpeed = win->ctl.speed;
 297        req->Attributes = 0;
 298        if (win->ctl.flags & MAP_ATTRIB)
 299                req->Attributes |= WIN_MEMORY_TYPE_AM;
 300        if (win->ctl.flags & MAP_ACTIVE)
 301                req->Attributes |= WIN_ENABLE;
 302        if (win->ctl.flags & MAP_16BIT)
 303                req->Attributes |= WIN_DATA_WIDTH_16;
 304        if (win->ctl.flags & MAP_USE_WAIT)
 305                req->Attributes |= WIN_USE_WAIT;
 306        *handle = win;
 307        return CS_SUCCESS;
 308} /* pcmcia_get_window */
 309EXPORT_SYMBOL(pcmcia_get_window);
 310
 311
 312/** pcmcia_get_mem_page
 313 *
 314 * Change the card address of an already open memory window.
 315 */
 316int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
 317{
 318        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
 319                return CS_BAD_HANDLE;
 320        req->Page = 0;
 321        req->CardOffset = win->ctl.card_start;
 322        return CS_SUCCESS;
 323} /* pcmcia_get_mem_page */
 324EXPORT_SYMBOL(pcmcia_get_mem_page);
 325
 326
 327int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
 328{
 329        struct pcmcia_socket *s;
 330        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
 331                return CS_BAD_HANDLE;
 332        if (req->Page != 0)
 333                return CS_BAD_PAGE;
 334        s = win->sock;
 335        win->ctl.card_start = req->CardOffset;
 336        if (s->ops->set_mem_map(s, &win->ctl) != 0)
 337                return CS_BAD_OFFSET;
 338        return CS_SUCCESS;
 339} /* pcmcia_map_mem_page */
 340EXPORT_SYMBOL(pcmcia_map_mem_page);
 341
 342
 343/** pcmcia_modify_configuration
 344 *
 345 * Modify a locked socket configuration
 346 */
 347int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
 348                                modconf_t *mod)
 349{
 350        struct pcmcia_socket *s;
 351        config_t *c;
 352
 353        s = p_dev->socket;
 354        c = p_dev->function_config;
 355
 356        if (!(s->state & SOCKET_PRESENT))
 357                return CS_NO_CARD;
 358        if (!(c->state & CONFIG_LOCKED))
 359                return CS_CONFIGURATION_LOCKED;
 360
 361        if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
 362                if (mod->Attributes & CONF_ENABLE_IRQ) {
 363                        c->Attributes |= CONF_ENABLE_IRQ;
 364                        s->socket.io_irq = s->irq.AssignedIRQ;
 365                } else {
 366                        c->Attributes &= ~CONF_ENABLE_IRQ;
 367                        s->socket.io_irq = 0;
 368                }
 369                s->ops->set_socket(s, &s->socket);
 370        }
 371
 372        if (mod->Attributes & CONF_VCC_CHANGE_VALID)
 373                return CS_BAD_VCC;
 374
 375        /* We only allow changing Vpp1 and Vpp2 to the same value */
 376        if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
 377            (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
 378                if (mod->Vpp1 != mod->Vpp2)
 379                        return CS_BAD_VPP;
 380                s->socket.Vpp = mod->Vpp1;
 381                if (s->ops->set_socket(s, &s->socket))
 382                        return CS_BAD_VPP;
 383        } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
 384                   (mod->Attributes & CONF_VPP2_CHANGE_VALID))
 385                return CS_BAD_VPP;
 386
 387        if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
 388                pccard_io_map io_off = { 0, 0, 0, 0, 1 };
 389                pccard_io_map io_on;
 390                int i;
 391
 392                io_on.speed = io_speed;
 393                for (i = 0; i < MAX_IO_WIN; i++) {
 394                        if (!s->io[i].res)
 395                                continue;
 396                        io_off.map = i;
 397                        io_on.map = i;
 398
 399                        io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
 400                        io_on.start = s->io[i].res->start;
 401                        io_on.stop = s->io[i].res->end;
 402
 403                        s->ops->set_io_map(s, &io_off);
 404                        mdelay(40);
 405                        s->ops->set_io_map(s, &io_on);
 406                }
 407        }
 408
 409        return CS_SUCCESS;
 410} /* modify_configuration */
 411EXPORT_SYMBOL(pcmcia_modify_configuration);
 412
 413
 414int pcmcia_release_configuration(struct pcmcia_device *p_dev)
 415{
 416        pccard_io_map io = { 0, 0, 0, 0, 1 };
 417        struct pcmcia_socket *s = p_dev->socket;
 418        config_t *c = p_dev->function_config;
 419        int i;
 420
 421        if (p_dev->_locked) {
 422                p_dev->_locked = 0;
 423                if (--(s->lock_count) == 0) {
 424                        s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
 425                        s->socket.Vpp = 0;
 426                        s->socket.io_irq = 0;
 427                        s->ops->set_socket(s, &s->socket);
 428                }
 429        }
 430        if (c->state & CONFIG_LOCKED) {
 431                c->state &= ~CONFIG_LOCKED;
 432                if (c->state & CONFIG_IO_REQ)
 433                        for (i = 0; i < MAX_IO_WIN; i++) {
 434                                if (!s->io[i].res)
 435                                        continue;
 436                                s->io[i].Config--;
 437                                if (s->io[i].Config != 0)
 438                                        continue;
 439                                io.map = i;
 440                                s->ops->set_io_map(s, &io);
 441                        }
 442        }
 443
 444        return CS_SUCCESS;
 445} /* pcmcia_release_configuration */
 446
 447
 448/** pcmcia_release_io
 449 *
 450 * Release_io() releases the I/O ranges allocated by a client.  This
 451 * may be invoked some time after a card ejection has already dumped
 452 * the actual socket configuration, so if the client is "stale", we
 453 * don't bother checking the port ranges against the current socket
 454 * values.
 455 */
 456static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
 457{
 458        struct pcmcia_socket *s = p_dev->socket;
 459        config_t *c = p_dev->function_config;
 460
 461        if (!p_dev->_io )
 462                return CS_BAD_HANDLE;
 463
 464        p_dev->_io = 0;
 465
 466        if ((c->io.BasePort1 != req->BasePort1) ||
 467            (c->io.NumPorts1 != req->NumPorts1) ||
 468            (c->io.BasePort2 != req->BasePort2) ||
 469            (c->io.NumPorts2 != req->NumPorts2))
 470                return CS_BAD_ARGS;
 471
 472        c->state &= ~CONFIG_IO_REQ;
 473
 474        release_io_space(s, req->BasePort1, req->NumPorts1);
 475        if (req->NumPorts2)
 476                release_io_space(s, req->BasePort2, req->NumPorts2);
 477
 478        return CS_SUCCESS;
 479} /* pcmcia_release_io */
 480
 481
 482static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 483{
 484        struct pcmcia_socket *s = p_dev->socket;
 485        config_t *c= p_dev->function_config;
 486
 487        if (!p_dev->_irq)
 488                return CS_BAD_HANDLE;
 489        p_dev->_irq = 0;
 490
 491        if (c->state & CONFIG_LOCKED)
 492                return CS_CONFIGURATION_LOCKED;
 493        if (c->irq.Attributes != req->Attributes)
 494                return CS_BAD_ATTRIBUTE;
 495        if (s->irq.AssignedIRQ != req->AssignedIRQ)
 496                return CS_BAD_IRQ;
 497        if (--s->irq.Config == 0) {
 498                c->state &= ~CONFIG_IRQ_REQ;
 499                s->irq.AssignedIRQ = 0;
 500        }
 501
 502        if (req->Attributes & IRQ_HANDLE_PRESENT) {
 503                free_irq(req->AssignedIRQ, req->Instance);
 504        }
 505
 506#ifdef CONFIG_PCMCIA_PROBE
 507        pcmcia_used_irq[req->AssignedIRQ]--;
 508#endif
 509
 510        return CS_SUCCESS;
 511} /* pcmcia_release_irq */
 512
 513
 514int pcmcia_release_window(window_handle_t win)
 515{
 516        struct pcmcia_socket *s;
 517
 518        if ((win == NULL) || (win->magic != WINDOW_MAGIC))
 519                return CS_BAD_HANDLE;
 520        s = win->sock;
 521        if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))
 522                return CS_BAD_HANDLE;
 523
 524        /* Shut down memory window */
 525        win->ctl.flags &= ~MAP_ACTIVE;
 526        s->ops->set_mem_map(s, &win->ctl);
 527        s->state &= ~SOCKET_WIN_REQ(win->index);
 528
 529        /* Release system memory */
 530        if (win->ctl.res) {
 531                release_resource(win->ctl.res);
 532                kfree(win->ctl.res);
 533                win->ctl.res = NULL;
 534        }
 535        win->handle->_win &= ~CLIENT_WIN_REQ(win->index);
 536
 537        win->magic = 0;
 538
 539        return CS_SUCCESS;
 540} /* pcmcia_release_window */
 541EXPORT_SYMBOL(pcmcia_release_window);
 542
 543
 544int pcmcia_request_configuration(struct pcmcia_device *p_dev,
 545                                 config_req_t *req)
 546{
 547        int i;
 548        u_int base;
 549        struct pcmcia_socket *s = p_dev->socket;
 550        config_t *c;
 551        pccard_io_map iomap;
 552
 553        if (!(s->state & SOCKET_PRESENT))
 554                return CS_NO_CARD;
 555
 556        if (req->IntType & INT_CARDBUS)
 557                return CS_UNSUPPORTED_MODE;
 558        c = p_dev->function_config;
 559        if (c->state & CONFIG_LOCKED)
 560                return CS_CONFIGURATION_LOCKED;
 561
 562        /* Do power control.  We don't allow changes in Vcc. */
 563        s->socket.Vpp = req->Vpp;
 564        if (s->ops->set_socket(s, &s->socket))
 565                return CS_BAD_VPP;
 566
 567        /* Pick memory or I/O card, DMA mode, interrupt */
 568        c->IntType = req->IntType;
 569        c->Attributes = req->Attributes;
 570        if (req->IntType & INT_MEMORY_AND_IO)
 571                s->socket.flags |= SS_IOCARD;
 572        if (req->IntType & INT_ZOOMED_VIDEO)
 573                s->socket.flags |= SS_ZVCARD | SS_IOCARD;
 574        if (req->Attributes & CONF_ENABLE_DMA)
 575                s->socket.flags |= SS_DMA_MODE;
 576        if (req->Attributes & CONF_ENABLE_SPKR)
 577                s->socket.flags |= SS_SPKR_ENA;
 578        if (req->Attributes & CONF_ENABLE_IRQ)
 579                s->socket.io_irq = s->irq.AssignedIRQ;
 580        else
 581                s->socket.io_irq = 0;
 582        s->ops->set_socket(s, &s->socket);
 583        s->lock_count++;
 584
 585        /* Set up CIS configuration registers */
 586        base = c->ConfigBase = req->ConfigBase;
 587        c->CardValues = req->Present;
 588        if (req->Present & PRESENT_COPY) {
 589                c->Copy = req->Copy;
 590                pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
 591        }
 592        if (req->Present & PRESENT_OPTION) {
 593                if (s->functions == 1) {
 594                        c->Option = req->ConfigIndex & COR_CONFIG_MASK;
 595                } else {
 596                        c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
 597                        c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
 598                        if (req->Present & PRESENT_IOBASE_0)
 599                                c->Option |= COR_ADDR_DECODE;
 600                }
 601                if (c->state & CONFIG_IRQ_REQ)
 602                        if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
 603                                c->Option |= COR_LEVEL_REQ;
 604                pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
 605                mdelay(40);
 606        }
 607        if (req->Present & PRESENT_STATUS) {
 608                c->Status = req->Status;
 609                pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
 610        }
 611        if (req->Present & PRESENT_PIN_REPLACE) {
 612                c->Pin = req->Pin;
 613                pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
 614        }
 615        if (req->Present & PRESENT_EXT_STATUS) {
 616                c->ExtStatus = req->ExtStatus;
 617                pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
 618        }
 619        if (req->Present & PRESENT_IOBASE_0) {
 620                u_char b = c->io.BasePort1 & 0xff;
 621                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
 622                b = (c->io.BasePort1 >> 8) & 0xff;
 623                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
 624        }
 625        if (req->Present & PRESENT_IOSIZE) {
 626                u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
 627                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
 628        }
 629
 630        /* Configure I/O windows */
 631        if (c->state & CONFIG_IO_REQ) {
 632                iomap.speed = io_speed;
 633                for (i = 0; i < MAX_IO_WIN; i++)
 634                        if (s->io[i].res) {
 635                                iomap.map = i;
 636                                iomap.flags = MAP_ACTIVE;
 637                                switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) {
 638                                case IO_DATA_PATH_WIDTH_16:
 639                                        iomap.flags |= MAP_16BIT; break;
 640                                case IO_DATA_PATH_WIDTH_AUTO:
 641                                        iomap.flags |= MAP_AUTOSZ; break;
 642                                default:
 643                                        break;
 644                                }
 645                                iomap.start = s->io[i].res->start;
 646                                iomap.stop = s->io[i].res->end;
 647                                s->ops->set_io_map(s, &iomap);
 648                                s->io[i].Config++;
 649                        }
 650        }
 651
 652        c->state |= CONFIG_LOCKED;
 653        p_dev->_locked = 1;
 654        return CS_SUCCESS;
 655} /* pcmcia_request_configuration */
 656EXPORT_SYMBOL(pcmcia_request_configuration);
 657
 658
 659/** pcmcia_request_io
 660 *
 661 * Request_io() reserves ranges of port addresses for a socket.
 662 * I have not implemented range sharing or alias addressing.
 663 */
 664int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
 665{
 666        struct pcmcia_socket *s = p_dev->socket;
 667        config_t *c;
 668
 669        if (!(s->state & SOCKET_PRESENT))
 670                return CS_NO_CARD;
 671
 672        if (!req)
 673                return CS_UNSUPPORTED_MODE;
 674        c = p_dev->function_config;
 675        if (c->state & CONFIG_LOCKED)
 676                return CS_CONFIGURATION_LOCKED;
 677        if (c->state & CONFIG_IO_REQ)
 678                return CS_IN_USE;
 679        if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
 680                return CS_BAD_ATTRIBUTE;
 681        if ((req->NumPorts2 > 0) &&
 682            (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
 683                return CS_BAD_ATTRIBUTE;
 684
 685        if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
 686                           req->NumPorts1, req->IOAddrLines))
 687                return CS_IN_USE;
 688
 689        if (req->NumPorts2) {
 690                if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
 691                                   req->NumPorts2, req->IOAddrLines)) {
 692                        release_io_space(s, req->BasePort1, req->NumPorts1);
 693                        return CS_IN_USE;
 694                }
 695        }
 696
 697        c->io = *req;
 698        c->state |= CONFIG_IO_REQ;
 699        p_dev->_io = 1;
 700        return CS_SUCCESS;
 701} /* pcmcia_request_io */
 702EXPORT_SYMBOL(pcmcia_request_io);
 703
 704
 705/** pcmcia_request_irq
 706 *
 707 * Request_irq() reserves an irq for this client.
 708 *
 709 * Also, since Linux only reserves irq's when they are actually
 710 * hooked, we don't guarantee that an irq will still be available
 711 * when the configuration is locked.  Now that I think about it,
 712 * there might be a way to fix this using a dummy handler.
 713 */
 714
 715#ifdef CONFIG_PCMCIA_PROBE
 716static irqreturn_t test_action(int cpl, void *dev_id)
 717{
 718        return IRQ_NONE;
 719}
 720#endif
 721
 722int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 723{
 724        struct pcmcia_socket *s = p_dev->socket;
 725        config_t *c;
 726        int ret = CS_IN_USE, irq = 0;
 727        int type;
 728
 729        if (!(s->state & SOCKET_PRESENT))
 730                return CS_NO_CARD;
 731        c = p_dev->function_config;
 732        if (c->state & CONFIG_LOCKED)
 733                return CS_CONFIGURATION_LOCKED;
 734        if (c->state & CONFIG_IRQ_REQ)
 735                return CS_IN_USE;
 736
 737        /* Decide what type of interrupt we are registering */
 738        type = 0;
 739        if (s->functions > 1)           /* All of this ought to be handled higher up */
 740                type = IRQF_SHARED;
 741        if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
 742                type = IRQF_SHARED;
 743
 744#ifdef CONFIG_PCMCIA_PROBE
 745
 746#ifdef IRQ_NOAUTOEN
 747        /* if the underlying IRQ infrastructure allows for it, only allocate
 748         * the IRQ, but do not enable it
 749         */
 750        if (!(req->Attributes & IRQ_HANDLE_PRESENT))
 751                type |= IRQ_NOAUTOEN;
 752#endif /* IRQ_NOAUTOEN */
 753
 754        if (s->irq.AssignedIRQ != 0) {
 755                /* If the interrupt is already assigned, it must be the same */
 756                irq = s->irq.AssignedIRQ;
 757        } else {
 758                int try;
 759                u32 mask = s->irq_mask;
 760                void *data = &p_dev->dev.driver; /* something unique to this device */
 761
 762                for (try = 0; try < 64; try++) {
 763                        irq = try % 32;
 764
 765                        /* marked as available by driver, and not blocked by userspace? */
 766                        if (!((mask >> irq) & 1))
 767                                continue;
 768
 769                        /* avoid an IRQ which is already used by a PCMCIA card */
 770                        if ((try < 32) && pcmcia_used_irq[irq])
 771                                continue;
 772
 773                        /* register the correct driver, if possible, of check whether
 774                         * registering a dummy handle works, i.e. if the IRQ isn't
 775                         * marked as used by the kernel resource management core */
 776                        ret = request_irq(irq,
 777                                          (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
 778                                          type,
 779                                          p_dev->devname,
 780                                          (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
 781                        if (!ret) {
 782                                if (!(req->Attributes & IRQ_HANDLE_PRESENT))
 783                                        free_irq(irq, data);
 784                                break;
 785                        }
 786                }
 787        }
 788#endif
 789        /* only assign PCI irq if no IRQ already assigned */
 790        if (ret && !s->irq.AssignedIRQ) {
 791                if (!s->pci_irq)
 792                        return ret;
 793                type = IRQF_SHARED;
 794                irq = s->pci_irq;
 795        }
 796
 797        if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {
 798                if (request_irq(irq, req->Handler, type,  p_dev->devname, req->Instance))
 799                        return CS_IN_USE;
 800        }
 801
 802        /* Make sure the fact the request type was overridden is passed back */
 803        if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
 804                req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
 805                printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");
 806                printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");
 807        }
 808        c->irq.Attributes = req->Attributes;
 809        s->irq.AssignedIRQ = req->AssignedIRQ = irq;
 810        s->irq.Config++;
 811
 812        c->state |= CONFIG_IRQ_REQ;
 813        p_dev->_irq = 1;
 814
 815#ifdef CONFIG_PCMCIA_PROBE
 816        pcmcia_used_irq[irq]++;
 817#endif
 818
 819        return CS_SUCCESS;
 820} /* pcmcia_request_irq */
 821EXPORT_SYMBOL(pcmcia_request_irq);
 822
 823
 824/** pcmcia_request_window
 825 *
 826 * Request_window() establishes a mapping between card memory space
 827 * and system memory space.
 828 */
 829int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh)
 830{
 831        struct pcmcia_socket *s = (*p_dev)->socket;
 832        window_t *win;
 833        u_long align;
 834        int w;
 835
 836        if (!(s->state & SOCKET_PRESENT))
 837                return CS_NO_CARD;
 838        if (req->Attributes & (WIN_PAGED | WIN_SHARED))
 839                return CS_BAD_ATTRIBUTE;
 840
 841        /* Window size defaults to smallest available */
 842        if (req->Size == 0)
 843                req->Size = s->map_size;
 844        align = (((s->features & SS_CAP_MEM_ALIGN) ||
 845                  (req->Attributes & WIN_STRICT_ALIGN)) ?
 846                 req->Size : s->map_size);
 847        if (req->Size & (s->map_size-1))
 848                return CS_BAD_SIZE;
 849        if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
 850            (req->Base & (align-1)))
 851                return CS_BAD_BASE;
 852        if (req->Base)
 853                align = 0;
 854
 855        /* Allocate system memory window */
 856        for (w = 0; w < MAX_WIN; w++)
 857                if (!(s->state & SOCKET_WIN_REQ(w))) break;
 858        if (w == MAX_WIN)
 859                return CS_OUT_OF_RESOURCE;
 860
 861        win = &s->win[w];
 862        win->magic = WINDOW_MAGIC;
 863        win->index = w;
 864        win->handle = *p_dev;
 865        win->sock = s;
 866
 867        if (!(s->features & SS_CAP_STATIC_MAP)) {
 868                win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
 869                                                      (req->Attributes & WIN_MAP_BELOW_1MB), s);
 870                if (!win->ctl.res)
 871                        return CS_IN_USE;
 872        }
 873        (*p_dev)->_win |= CLIENT_WIN_REQ(w);
 874
 875        /* Configure the socket controller */
 876        win->ctl.map = w+1;
 877        win->ctl.flags = 0;
 878        win->ctl.speed = req->AccessSpeed;
 879        if (req->Attributes & WIN_MEMORY_TYPE)
 880                win->ctl.flags |= MAP_ATTRIB;
 881        if (req->Attributes & WIN_ENABLE)
 882                win->ctl.flags |= MAP_ACTIVE;
 883        if (req->Attributes & WIN_DATA_WIDTH_16)
 884                win->ctl.flags |= MAP_16BIT;
 885        if (req->Attributes & WIN_USE_WAIT)
 886                win->ctl.flags |= MAP_USE_WAIT;
 887        win->ctl.card_start = 0;
 888        if (s->ops->set_mem_map(s, &win->ctl) != 0)
 889                return CS_BAD_ARGS;
 890        s->state |= SOCKET_WIN_REQ(w);
 891
 892        /* Return window handle */
 893        if (s->features & SS_CAP_STATIC_MAP) {
 894                req->Base = win->ctl.static_start;
 895        } else {
 896                req->Base = win->ctl.res->start;
 897        }
 898        *wh = win;
 899
 900        return CS_SUCCESS;
 901} /* pcmcia_request_window */
 902EXPORT_SYMBOL(pcmcia_request_window);
 903
 904void pcmcia_disable_device(struct pcmcia_device *p_dev) {
 905        pcmcia_release_configuration(p_dev);
 906        pcmcia_release_io(p_dev, &p_dev->io);
 907        pcmcia_release_irq(p_dev, &p_dev->irq);
 908        if (p_dev->win)
 909                pcmcia_release_window(p_dev->win);
 910}
 911EXPORT_SYMBOL(pcmcia_disable_device);
 912