linux/drivers/staging/comedi/drivers/das08_cs.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/das08_cs.c
   3    DAS08 driver
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
   7    Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net>
   8
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 2 of the License, or
  12    (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18
  19    You should have received a copy of the GNU General Public License
  20    along with this program; if not, write to the Free Software
  21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22
  23*****************************************************************
  24
  25*/
  26/*
  27Driver: das08_cs
  28Description: DAS-08 PCMCIA boards
  29Author: Warren Jasper, ds, Frank Hess
  30Devices: [ComputerBoards] PCM-DAS08 (pcm-das08)
  31Status: works
  32
  33This is the PCMCIA-specific support split off from the
  34das08 driver.
  35
  36Options (for pcm-das08):
  37        NONE
  38
  39Command support does not exist, but could be added for this board.
  40*/
  41
  42#include "../comedidev.h"
  43
  44#include <linux/delay.h>
  45#include <linux/pci.h>
  46
  47#include "das08.h"
  48
  49/* pcmcia includes */
  50#include <pcmcia/cs_types.h>
  51#include <pcmcia/cs.h>
  52#include <pcmcia/cistpl.h>
  53#include <pcmcia/ds.h>
  54
  55static struct pcmcia_device *cur_dev = NULL;
  56
  57#define thisboard ((const struct das08_board_struct *)dev->board_ptr)
  58
  59static int das08_cs_attach(struct comedi_device *dev,
  60                           struct comedi_devconfig *it);
  61
  62static struct comedi_driver driver_das08_cs = {
  63        .driver_name = "das08_cs",
  64        .module = THIS_MODULE,
  65        .attach = das08_cs_attach,
  66        .detach = das08_common_detach,
  67        .board_name = &das08_cs_boards[0].name,
  68        .num_names = ARRAY_SIZE(das08_cs_boards),
  69        .offset = sizeof(struct das08_board_struct),
  70};
  71
  72static int das08_cs_attach(struct comedi_device *dev,
  73                           struct comedi_devconfig *it)
  74{
  75        int ret;
  76        unsigned long iobase;
  77        struct pcmcia_device *link = cur_dev;   /*  XXX hack */
  78
  79        ret = alloc_private(dev, sizeof(struct das08_private_struct));
  80        if (ret < 0)
  81                return ret;
  82
  83        printk("comedi%d: das08_cs: ", dev->minor);
  84        /*  deal with a pci board */
  85
  86        if (thisboard->bustype == pcmcia) {
  87                if (link == NULL) {
  88                        printk(" no pcmcia cards found\n");
  89                        return -EIO;
  90                }
  91                iobase = link->io.BasePort1;
  92        } else {
  93                printk(" bug! board does not have PCMCIA bustype\n");
  94                return -EINVAL;
  95        }
  96
  97        printk("\n");
  98
  99        return das08_common_attach(dev, iobase);
 100}
 101
 102/*======================================================================
 103
 104    The following pcmcia code for the pcm-das08 is adapted from the
 105    dummy_cs.c driver of the Linux PCMCIA Card Services package.
 106
 107    The initial developer of the original code is David A. Hinds
 108    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 109    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 110
 111======================================================================*/
 112
 113/*
 114   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
 115   you do not define PCMCIA_DEBUG at all, all the debug code will be
 116   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
 117   be present but disabled -- but it can then be enabled for specific
 118   modules at load time with a 'pc_debug=#' option to insmod.
 119*/
 120
 121#ifdef PCMCIA_DEBUG
 122static int pc_debug = PCMCIA_DEBUG;
 123module_param(pc_debug, int, 0644);
 124#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 125static const char *version =
 126    "das08.c pcmcia code (Frank Hess), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)";
 127#else
 128#define DEBUG(n, args...)
 129#endif
 130
 131/*====================================================================*/
 132static void das08_pcmcia_config(struct pcmcia_device *link);
 133static void das08_pcmcia_release(struct pcmcia_device *link);
 134static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
 135static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
 136
 137/*
 138   The attach() and detach() entry points are used to create and destroy
 139   "instances" of the driver, where each instance represents everything
 140   needed to manage one actual PCMCIA card.
 141*/
 142
 143static int das08_pcmcia_attach(struct pcmcia_device *);
 144static void das08_pcmcia_detach(struct pcmcia_device *);
 145
 146/*
 147   You'll also need to prototype all the functions that will actually
 148   be used to talk to your device.  See 'memory_cs' for a good example
 149   of a fully self-sufficient driver; the other drivers rely more or
 150   less on other parts of the kernel.
 151*/
 152
 153/*
 154   The dev_info variable is the "key" that is used to match up this
 155   device driver with appropriate cards, through the card configuration
 156   database.
 157*/
 158
 159static const dev_info_t dev_info = "pcm-das08";
 160
 161struct local_info_t {
 162        struct pcmcia_device *link;
 163        dev_node_t node;
 164        int stop;
 165        struct bus_operations *bus;
 166};
 167
 168/*======================================================================
 169
 170    das08_pcmcia_attach() creates an "instance" of the driver, allocating
 171    local data structures for one device.  The device is registered
 172    with Card Services.
 173
 174    The dev_link structure is initialized, but we don't actually
 175    configure the card at this point -- we wait until we receive a
 176    card insertion event.
 177
 178======================================================================*/
 179
 180static int das08_pcmcia_attach(struct pcmcia_device *link)
 181{
 182        struct local_info_t *local;
 183
 184        DEBUG(0, "das08_pcmcia_attach()\n");
 185
 186        /* Allocate space for private device-specific data */
 187        local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
 188        if (!local)
 189                return -ENOMEM;
 190        local->link = link;
 191        link->priv = local;
 192
 193        /* Interrupt setup */
 194        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 195        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 196        link->irq.Handler = NULL;
 197
 198        /*
 199           General socket configuration defaults can go here.  In this
 200           client, we assume very little, and rely on the CIS for almost
 201           everything.  In most clients, many details (i.e., number, sizes,
 202           and attributes of IO windows) are fixed by the nature of the
 203           device, and can be hard-wired here.
 204         */
 205        link->conf.Attributes = 0;
 206        link->conf.IntType = INT_MEMORY_AND_IO;
 207
 208        cur_dev = link;
 209
 210        das08_pcmcia_config(link);
 211
 212        return 0;
 213}                               /* das08_pcmcia_attach */
 214
 215/*======================================================================
 216
 217    This deletes a driver "instance".  The device is de-registered
 218    with Card Services.  If it has been released, all local data
 219    structures are freed.  Otherwise, the structures will be freed
 220    when the device is released.
 221
 222======================================================================*/
 223
 224static void das08_pcmcia_detach(struct pcmcia_device *link)
 225{
 226
 227        DEBUG(0, "das08_pcmcia_detach(0x%p)\n", link);
 228
 229        if (link->dev_node) {
 230                ((struct local_info_t *)link->priv)->stop = 1;
 231                das08_pcmcia_release(link);
 232        }
 233
 234        /* This points to the parent struct local_info_t struct */
 235        if (link->priv)
 236                kfree(link->priv);
 237
 238}                               /* das08_pcmcia_detach */
 239
 240/*======================================================================
 241
 242    das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
 243    is received, to configure the PCMCIA socket, and to make the
 244    device available to the system.
 245
 246======================================================================*/
 247
 248static void das08_pcmcia_config(struct pcmcia_device *link)
 249{
 250        struct local_info_t *dev = link->priv;
 251        tuple_t tuple;
 252        cisparse_t parse;
 253        int last_fn, last_ret;
 254        u_char buf[64];
 255        cistpl_cftable_entry_t dflt = { 0 };
 256
 257        DEBUG(0, "das08_pcmcia_config(0x%p)\n", link);
 258
 259        /*
 260           This reads the card's CONFIG tuple to find its configuration
 261           registers.
 262         */
 263        tuple.DesiredTuple = CISTPL_CONFIG;
 264        tuple.Attributes = 0;
 265        tuple.TupleData = buf;
 266        tuple.TupleDataMax = sizeof(buf);
 267        tuple.TupleOffset = 0;
 268        last_fn = GetFirstTuple;
 269
 270        last_ret = pcmcia_get_first_tuple(link, &tuple);
 271        if (last_ret)
 272                goto cs_failed;
 273
 274        last_fn = GetTupleData;
 275
 276        last_ret = pcmcia_get_tuple_data(link, &tuple);
 277        if (last_ret)
 278                goto cs_failed;
 279
 280        last_fn = ParseTuple;
 281
 282        last_ret = pcmcia_parse_tuple(&tuple, &parse);
 283        if (last_ret)
 284                goto cs_failed;
 285
 286        link->conf.ConfigBase = parse.config.base;
 287        link->conf.Present = parse.config.rmask[0];
 288
 289        /*
 290           In this loop, we scan the CIS for configuration table entries,
 291           each of which describes a valid card configuration, including
 292           voltage, IO window, memory window, and interrupt settings.
 293
 294           We make no assumptions about the card to be configured: we use
 295           just the information available in the CIS.  In an ideal world,
 296           this would work for any PCMCIA card, but it requires a complete
 297           and accurate CIS.  In practice, a driver usually "knows" most of
 298           these things without consulting the CIS, and most client drivers
 299           will only use the CIS to fill in implementation-defined details.
 300         */
 301        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 302        last_fn = GetFirstTuple;
 303
 304        last_ret = pcmcia_get_first_tuple(link, &tuple);
 305        if (last_ret)
 306                goto cs_failed;
 307
 308        while (1) {
 309                cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 310
 311                last_ret = pcmcia_get_tuple_data(link, &tuple);
 312                if (last_ret)
 313                        goto next_entry;
 314
 315                last_ret = pcmcia_parse_tuple(&tuple, &parse);
 316                if (last_ret)
 317                        goto next_entry;
 318
 319                if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 320                        dflt = *cfg;
 321                if (cfg->index == 0)
 322                        goto next_entry;
 323                link->conf.ConfigIndex = cfg->index;
 324
 325                /* Does this card need audio output? */
 326/*      if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
 327                link->conf.Attributes |= CONF_ENABLE_SPKR;
 328                link->conf.Status = CCSR_AUDIO_ENA;
 329        }
 330*/
 331                /* Do we need to allocate an interrupt? */
 332                if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
 333                        link->conf.Attributes |= CONF_ENABLE_IRQ;
 334
 335                /* IO window settings */
 336                link->io.NumPorts1 = link->io.NumPorts2 = 0;
 337                if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
 338                        cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
 339                        link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 340                        if (!(io->flags & CISTPL_IO_8BIT))
 341                                link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 342                        if (!(io->flags & CISTPL_IO_16BIT))
 343                                link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 344                        link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 345                        link->io.BasePort1 = io->win[0].base;
 346                        link->io.NumPorts1 = io->win[0].len;
 347                        if (io->nwin > 1) {
 348                                link->io.Attributes2 = link->io.Attributes1;
 349                                link->io.BasePort2 = io->win[1].base;
 350                                link->io.NumPorts2 = io->win[1].len;
 351                        }
 352                        /* This reserves IO space but doesn't actually enable it */
 353                        if (pcmcia_request_io(link, &link->io) != 0)
 354                                goto next_entry;
 355                }
 356
 357                /* If we got this far, we're cool! */
 358                break;
 359
 360next_entry:
 361                last_fn = GetNextTuple;
 362
 363                last_ret = pcmcia_get_next_tuple(link, &tuple);
 364                if (last_ret)
 365                        goto cs_failed;
 366        }
 367
 368        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
 369                last_fn = RequestIRQ;
 370                last_ret = pcmcia_request_irq(link, &link->irq);
 371                if (last_ret)
 372                        goto cs_failed;
 373        }
 374
 375        /*
 376           This actually configures the PCMCIA socket -- setting up
 377           the I/O windows and the interrupt mapping, and putting the
 378           card and host interface into "Memory and IO" mode.
 379         */
 380        last_fn = RequestConfiguration;
 381        last_ret = pcmcia_request_configuration(link, &link->conf);
 382        if (last_ret)
 383                goto cs_failed;
 384
 385        /*
 386           At this point, the dev_node_t structure(s) need to be
 387           initialized and arranged in a linked list at link->dev.
 388         */
 389        sprintf(dev->node.dev_name, "pcm-das08");
 390        dev->node.major = dev->node.minor = 0;
 391        link->dev_node = &dev->node;
 392
 393        /* Finally, report what we've done */
 394        printk(KERN_INFO "%s: index 0x%02x",
 395               dev->node.dev_name, link->conf.ConfigIndex);
 396        if (link->conf.Attributes & CONF_ENABLE_IRQ)
 397                printk(", irq %u", link->irq.AssignedIRQ);
 398        if (link->io.NumPorts1)
 399                printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 400                       link->io.BasePort1 + link->io.NumPorts1 - 1);
 401        if (link->io.NumPorts2)
 402                printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 403                       link->io.BasePort2 + link->io.NumPorts2 - 1);
 404        printk("\n");
 405
 406        return;
 407
 408cs_failed:
 409        cs_error(link, last_fn, last_ret);
 410        das08_pcmcia_release(link);
 411
 412}                               /* das08_pcmcia_config */
 413
 414/*======================================================================
 415
 416    After a card is removed, das08_pcmcia_release() will unregister the
 417    device, and release the PCMCIA configuration.  If the device is
 418    still open, this will be postponed until it is closed.
 419
 420======================================================================*/
 421
 422static void das08_pcmcia_release(struct pcmcia_device *link)
 423{
 424        DEBUG(0, "das08_pcmcia_release(0x%p)\n", link);
 425        pcmcia_disable_device(link);
 426}                               /* das08_pcmcia_release */
 427
 428/*======================================================================
 429
 430    The card status event handler.  Mostly, this schedules other
 431    stuff to run after an event is received.
 432
 433    When a CARD_REMOVAL event is received, we immediately set a
 434    private flag to block future accesses to this device.  All the
 435    functions that actually access the device should check this flag
 436    to make sure the card is still present.
 437
 438======================================================================*/
 439
 440static int das08_pcmcia_suspend(struct pcmcia_device *link)
 441{
 442        struct local_info_t *local = link->priv;
 443        /* Mark the device as stopped, to block IO until later */
 444        local->stop = 1;
 445
 446        return 0;
 447}                               /* das08_pcmcia_suspend */
 448
 449static int das08_pcmcia_resume(struct pcmcia_device *link)
 450{
 451        struct local_info_t *local = link->priv;
 452
 453        local->stop = 0;
 454        return 0;
 455}                               /* das08_pcmcia_resume */
 456
 457/*====================================================================*/
 458
 459static struct pcmcia_device_id das08_cs_id_table[] = {
 460        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
 461        PCMCIA_DEVICE_NULL
 462};
 463
 464MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table);
 465
 466struct pcmcia_driver das08_cs_driver = {
 467        .probe = das08_pcmcia_attach,
 468        .remove = das08_pcmcia_detach,
 469        .suspend = das08_pcmcia_suspend,
 470        .resume = das08_pcmcia_resume,
 471        .id_table = das08_cs_id_table,
 472        .owner = THIS_MODULE,
 473        .drv = {
 474                .name = dev_info,
 475                },
 476};
 477
 478static int __init init_das08_pcmcia_cs(void)
 479{
 480        DEBUG(0, "%s\n", version);
 481        pcmcia_register_driver(&das08_cs_driver);
 482        return 0;
 483}
 484
 485static void __exit exit_das08_pcmcia_cs(void)
 486{
 487        DEBUG(0, "das08_pcmcia_cs: unloading\n");
 488        pcmcia_unregister_driver(&das08_cs_driver);
 489}
 490
 491static int __init das08_cs_init_module(void)
 492{
 493        int ret;
 494
 495        ret = init_das08_pcmcia_cs();
 496        if (ret < 0)
 497                return ret;
 498
 499        return comedi_driver_register(&driver_das08_cs);
 500}
 501
 502static void __exit das08_cs_exit_module(void)
 503{
 504        exit_das08_pcmcia_cs();
 505        comedi_driver_unregister(&driver_das08_cs);
 506}
 507
 508MODULE_LICENSE("GPL");
 509module_init(das08_cs_init_module);
 510module_exit(das08_cs_exit_module);
 511