linux-old/drivers/scsi/pcmcia/fdomain_stub.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A driver for Future Domain-compatible PCMCIA SCSI cards
   4
   5    fdomain_cs.c 1.47 2001/10/13 00:08:52
   6
   7    The contents of this file are subject to the Mozilla Public
   8    License Version 1.1 (the "License"); you may not use this file
   9    except in compliance with the License. You may obtain a copy of
  10    the License at http://www.mozilla.org/MPL/
  11
  12    Software distributed under the License is distributed on an "AS
  13    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14    implied. See the License for the specific language governing
  15    rights and limitations under the License.
  16
  17    The initial developer of the original code is David A. Hinds
  18    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  19    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  20
  21    Alternatively, the contents of this file may be used under the
  22    terms of the GNU General Public License version 2 (the "GPL"), in
  23    which case the provisions of the GPL are applicable instead of the
  24    above.  If you wish to allow the use of your version of this file
  25    only under the terms of the GPL and not to allow others to use
  26    your version of this file under the MPL, indicate your decision
  27    by deleting the provisions above and replace them with the notice
  28    and other provisions required by the GPL.  If you do not delete
  29    the provisions above, a recipient may use your version of this
  30    file under either the MPL or the GPL.
  31    
  32======================================================================*/
  33
  34#include <linux/module.h>
  35#include <linux/init.h>
  36#include <linux/kernel.h>
  37#include <linux/sched.h>
  38#include <linux/slab.h>
  39#include <linux/string.h>
  40#include <linux/ioport.h>
  41#include <scsi/scsi.h>
  42#include <linux/major.h>
  43#include <linux/blk.h>
  44
  45#include <../drivers/scsi/scsi.h>
  46#include <../drivers/scsi/hosts.h>
  47#include <scsi/scsi_ioctl.h>
  48#include <../drivers/scsi/fdomain.h>
  49
  50#include <pcmcia/version.h>
  51#include <pcmcia/cs_types.h>
  52#include <pcmcia/cs.h>
  53#include <pcmcia/cistpl.h>
  54#include <pcmcia/ds.h>
  55
  56/*====================================================================*/
  57
  58/* Module parameters */
  59
  60MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
  61MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
  62MODULE_LICENSE("Dual MPL/GPL");
  63
  64#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
  65
  66/* Bit map of interrupts to choose from */
  67INT_MODULE_PARM(irq_mask, 0xdeb8);
  68static int irq_list[4] = { -1 };
  69MODULE_PARM(irq_list, "1-4i");
  70
  71#ifdef PCMCIA_DEBUG
  72INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
  73#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
  74static char *version =
  75"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
  76#else
  77#define DEBUG(n, args...)
  78#endif
  79
  80/*====================================================================*/
  81
  82typedef struct scsi_info_t {
  83    dev_link_t          link;
  84    int                 ndev;
  85    dev_node_t          node[8];
  86} scsi_info_t;
  87
  88extern void fdomain_setup(char *str, int *ints);
  89
  90static void fdomain_release(u_long arg);
  91static int fdomain_event(event_t event, int priority,
  92                        event_callback_args_t *args);
  93
  94static dev_link_t *fdomain_attach(void);
  95static void fdomain_detach(dev_link_t *);
  96
  97static Scsi_Host_Template driver_template = FDOMAIN_16X0;
  98
  99static dev_link_t *dev_list = NULL;
 100
 101static dev_info_t dev_info = "fdomain_cs";
 102
 103/*====================================================================*/
 104
 105static void cs_error(client_handle_t handle, int func, int ret)
 106{
 107    error_info_t err = { func, ret };
 108    CardServices(ReportError, handle, &err);
 109}
 110
 111/*====================================================================*/
 112
 113static dev_link_t *fdomain_attach(void)
 114{
 115    scsi_info_t *info;
 116    client_reg_t client_reg;
 117    dev_link_t *link;
 118    int i, ret;
 119    
 120    DEBUG(0, "fdomain_attach()\n");
 121
 122    /* Create new SCSI device */
 123    info = kmalloc(sizeof(*info), GFP_KERNEL);
 124    if (!info) return NULL;
 125    memset(info, 0, sizeof(*info));
 126    link = &info->link; link->priv = info;
 127
 128    link->io.NumPorts1 = 0x10;
 129    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 130    link->io.IOAddrLines = 10;
 131    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 132    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
 133    if (irq_list[0] == -1)
 134        link->irq.IRQInfo2 = irq_mask;
 135    else
 136        for (i = 0; i < 4; i++)
 137            link->irq.IRQInfo2 |= 1 << irq_list[i];
 138    link->conf.Attributes = CONF_ENABLE_IRQ;
 139    link->conf.Vcc = 50;
 140    link->conf.IntType = INT_MEMORY_AND_IO;
 141    link->conf.Present = PRESENT_OPTION;
 142
 143    /* Register with Card Services */
 144    link->next = dev_list;
 145    dev_list = link;
 146    client_reg.dev_info = &dev_info;
 147    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
 148    client_reg.event_handler = &fdomain_event;
 149    client_reg.EventMask =
 150        CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
 151        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 152        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
 153    client_reg.Version = 0x0210;
 154    client_reg.event_callback_args.client_data = link;
 155    ret = CardServices(RegisterClient, &link->handle, &client_reg);
 156    if (ret != 0) {
 157        cs_error(link->handle, RegisterClient, ret);
 158        fdomain_detach(link);
 159        return NULL;
 160    }
 161    
 162    return link;
 163} /* fdomain_attach */
 164
 165/*====================================================================*/
 166
 167static void fdomain_detach(dev_link_t *link)
 168{
 169    dev_link_t **linkp;
 170
 171    DEBUG(0, "fdomain_detach(0x%p)\n", link);
 172    
 173    /* Locate device structure */
 174    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 175        if (*linkp == link) break;
 176    if (*linkp == NULL)
 177        return;
 178
 179    if (link->state & DEV_CONFIG) {
 180        fdomain_release((u_long)link);
 181        if (link->state & DEV_STALE_CONFIG) {
 182            link->state |= DEV_STALE_LINK;
 183            return;
 184        }
 185    }
 186
 187    if (link->handle)
 188        CardServices(DeregisterClient, link->handle);
 189    
 190    /* Unlink device structure, free bits */
 191    *linkp = link->next;
 192    kfree(link->priv);
 193    
 194} /* fdomain_detach */
 195
 196/*====================================================================*/
 197
 198#define CS_CHECK(fn, args...) \
 199while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
 200
 201#define CFG_CHECK(fn, args...) \
 202if (CardServices(fn, args) != 0) goto next_entry
 203
 204static void fdomain_config(dev_link_t *link)
 205{
 206    client_handle_t handle = link->handle;
 207    scsi_info_t *info = link->priv;
 208    tuple_t tuple;
 209    cisparse_t parse;
 210    int i, last_ret, last_fn, ints[3];
 211    u_char tuple_data[64];
 212    Scsi_Device *dev;
 213    dev_node_t *node, **tail;
 214    char str[16];
 215    struct Scsi_Host *host;
 216
 217    DEBUG(0, "fdomain_config(0x%p)\n", link);
 218
 219    tuple.DesiredTuple = CISTPL_CONFIG;
 220    tuple.TupleData = tuple_data;
 221    tuple.TupleDataMax = 64;
 222    tuple.TupleOffset = 0;
 223    CS_CHECK(GetFirstTuple, handle, &tuple);
 224    CS_CHECK(GetTupleData, handle, &tuple);
 225    CS_CHECK(ParseTuple, handle, &tuple, &parse);
 226    link->conf.ConfigBase = parse.config.base;
 227
 228    /* Configure card */
 229    driver_template.module = &__this_module;
 230    link->state |= DEV_CONFIG;
 231    
 232    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 233    CS_CHECK(GetFirstTuple, handle, &tuple);
 234    while (1) {
 235        CFG_CHECK(GetTupleData, handle, &tuple);
 236        CFG_CHECK(ParseTuple, handle, &tuple, &parse);
 237        link->conf.ConfigIndex = parse.cftable_entry.index;
 238        link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
 239        i = CardServices(RequestIO, handle, &link->io);
 240        if (i == CS_SUCCESS) break;
 241    next_entry:
 242        CS_CHECK(GetNextTuple, handle, &tuple);
 243    }
 244
 245    CS_CHECK(RequestIRQ, handle, &link->irq);
 246    CS_CHECK(RequestConfiguration, handle, &link->conf);
 247    
 248    /* A bad hack... */
 249    release_region(link->io.BasePort1, link->io.NumPorts1);
 250
 251    /* Set configuration options for the fdomain driver */
 252    ints[0] = 2;
 253    ints[1] = link->io.BasePort1;
 254    ints[2] = link->irq.AssignedIRQ;
 255    sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
 256    fdomain_setup(str, ints);
 257    
 258    scsi_register_module(MODULE_SCSI_HA, &driver_template);
 259
 260    tail = &link->dev;
 261    info->ndev = 0;
 262    for (host = scsi_hostlist; host; host = host->next)
 263        if (host->hostt == &driver_template)
 264            for (dev = host->host_queue; dev; dev = dev->next) {
 265            u_long arg[2], id;
 266            kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
 267            id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
 268                ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
 269            node = &info->node[info->ndev];
 270            node->minor = 0;
 271            switch (dev->type) {
 272            case TYPE_TAPE:
 273                node->major = SCSI_TAPE_MAJOR;
 274                sprintf(node->dev_name, "st#%04lx", id);
 275                break;
 276            case TYPE_DISK:
 277            case TYPE_MOD:
 278                node->major = SCSI_DISK0_MAJOR;
 279                sprintf(node->dev_name, "sd#%04lx", id);
 280                break;
 281            case TYPE_ROM:
 282            case TYPE_WORM:
 283                node->major = SCSI_CDROM_MAJOR;
 284                sprintf(node->dev_name, "sr#%04lx", id);
 285                break;
 286            default:
 287                node->major = SCSI_GENERIC_MAJOR;
 288                sprintf(node->dev_name, "sg#%04lx", id);
 289                break;
 290            }
 291            *tail = node; tail = &node->next;
 292            info->ndev++;
 293        }
 294    *tail = NULL;
 295    if (info->ndev == 0)
 296        printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
 297    
 298    link->state &= ~DEV_CONFIG_PENDING;
 299    return;
 300    
 301cs_failed:
 302    cs_error(link->handle, last_fn, last_ret);
 303    fdomain_release((u_long)link);
 304    return;
 305    
 306} /* fdomain_config */
 307
 308/*====================================================================*/
 309
 310static void fdomain_release(u_long arg)
 311{
 312    dev_link_t *link = (dev_link_t *)arg;
 313
 314    DEBUG(0, "fdomain_release(0x%p)\n", link);
 315
 316    if (GET_USE_COUNT(&__this_module) != 0) {
 317        DEBUG(1, "fdomain_cs: release postponed, "
 318              "device still open\n");
 319        link->state |= DEV_STALE_CONFIG;
 320        return;
 321    }
 322
 323    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
 324    link->dev = NULL;
 325    
 326    CardServices(ReleaseConfiguration, link->handle);
 327    CardServices(ReleaseIO, link->handle, &link->io);
 328    CardServices(ReleaseIRQ, link->handle, &link->irq);
 329    
 330    link->state &= ~DEV_CONFIG;
 331    if (link->state & DEV_STALE_LINK)
 332        fdomain_detach(link);
 333    
 334} /* fdomain_release */
 335
 336/*====================================================================*/
 337
 338static int fdomain_event(event_t event, int priority,
 339                        event_callback_args_t *args)
 340{
 341    dev_link_t *link = args->client_data;
 342
 343    DEBUG(1, "fdomain_event(0x%06x)\n", event);
 344    
 345    switch (event) {
 346    case CS_EVENT_CARD_REMOVAL:
 347        link->state &= ~DEV_PRESENT;
 348        if (link->state & DEV_CONFIG)
 349            fdomain_release((u_long)link);
 350        break;
 351    case CS_EVENT_CARD_INSERTION:
 352        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 353        fdomain_config(link);
 354        break;
 355    case CS_EVENT_PM_SUSPEND:
 356        link->state |= DEV_SUSPEND;
 357        /* Fall through... */
 358    case CS_EVENT_RESET_PHYSICAL:
 359        if (link->state & DEV_CONFIG)
 360            CardServices(ReleaseConfiguration, link->handle);
 361        break;
 362    case CS_EVENT_PM_RESUME:
 363        link->state &= ~DEV_SUSPEND;
 364        /* Fall through... */
 365    case CS_EVENT_CARD_RESET:
 366        if (link->state & DEV_CONFIG) {
 367            CardServices(RequestConfiguration, link->handle, &link->conf);
 368            fdomain_16x0_reset(NULL, 0);
 369        }
 370        break;
 371    }
 372    return 0;
 373} /* fdomain_event */
 374
 375/*====================================================================*/
 376
 377static int __init init_fdomain_cs(void) {
 378    servinfo_t serv;
 379    DEBUG(0, "%s\n", version);
 380    CardServices(GetCardServicesInfo, &serv);
 381    if (serv.Revision != CS_RELEASE_CODE) {
 382        printk(KERN_NOTICE "fdomain_cs: Card Services release "
 383               "does not match!\n");
 384        return -1;
 385    }
 386    register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach);
 387    return 0;
 388}
 389
 390static void __exit exit_fdomain_cs(void) {
 391    DEBUG(0, "fdomain_cs: unloading\n");
 392    unregister_pccard_driver(&dev_info);
 393    while (dev_list != NULL)
 394        fdomain_detach(dev_list);
 395}
 396
 397module_init(init_fdomain_cs);
 398module_exit(exit_fdomain_cs);
 399
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.