linux/drivers/isdn/hisax/sedlbauer_cs.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A Sedlbauer PCMCIA client driver
   4
   5    This driver is for the Sedlbauer Speed Star and Speed Star II, 
   6    which are ISDN PCMCIA Cards.
   7    
   8    The contents of this file are subject to the Mozilla Public
   9    License Version 1.1 (the "License"); you may not use this file
  10    except in compliance with the License. You may obtain a copy of
  11    the License at http://www.mozilla.org/MPL/
  12
  13    Software distributed under the License is distributed on an "AS
  14    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  15    implied. See the License for the specific language governing
  16    rights and limitations under the License.
  17
  18    The initial developer of the original code is David A. Hinds
  19    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  20    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  21
  22    Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
  23    <maniemann@users.sourceforge.net>. All Rights Reserved.
  24
  25    Alternatively, the contents of this file may be used under the
  26    terms of the GNU General Public License version 2 (the "GPL"), in
  27    which case the provisions of the GPL are applicable instead of the
  28    above.  If you wish to allow the use of your version of this file
  29    only under the terms of the GPL and not to allow others to use
  30    your version of this file under the MPL, indicate your decision
  31    by deleting the provisions above and replace them with the notice
  32    and other provisions required by the GPL.  If you do not delete
  33    the provisions above, a recipient may use your version of this
  34    file under either the MPL or the GPL.
  35    
  36======================================================================*/
  37
  38#include <linux/kernel.h>
  39#include <linux/module.h>
  40#include <linux/init.h>
  41#include <linux/ptrace.h>
  42#include <linux/slab.h>
  43#include <linux/string.h>
  44#include <linux/timer.h>
  45#include <linux/ioport.h>
  46#include <asm/io.h>
  47#include <asm/system.h>
  48
  49#include <pcmcia/cs_types.h>
  50#include <pcmcia/cs.h>
  51#include <pcmcia/cistpl.h>
  52#include <pcmcia/cisreg.h>
  53#include <pcmcia/ds.h>
  54#include "hisax_cfg.h"
  55
  56MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
  57MODULE_AUTHOR("Marcus Niemann");
  58MODULE_LICENSE("Dual MPL/GPL");
  59
  60/*
  61   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
  62   you do not define PCMCIA_DEBUG at all, all the debug code will be
  63   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
  64   be present but disabled -- but it can then be enabled for specific
  65   modules at load time with a 'pc_debug=#' option to insmod.
  66*/
  67
  68#ifdef PCMCIA_DEBUG
  69static int pc_debug = PCMCIA_DEBUG;
  70module_param(pc_debug, int, 0);
  71#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); 
  72static char *version =
  73"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)";
  74#else
  75#define DEBUG(n, args...)
  76#endif
  77
  78
  79/*====================================================================*/
  80
  81/* Parameters that can be set with 'insmod' */
  82
  83static int protocol = 2;        /* EURO-ISDN Default */
  84module_param(protocol, int, 0);
  85
  86/*====================================================================*/
  87
  88/*
  89   The event() function is this driver's Card Services event handler.
  90   It will be called by Card Services when an appropriate card status
  91   event is received.  The config() and release() entry points are
  92   used to configure or release a socket, in response to card
  93   insertion and ejection events.  They are invoked from the sedlbauer
  94   event handler. 
  95*/
  96
  97static int sedlbauer_config(struct pcmcia_device *link);
  98static void sedlbauer_release(struct pcmcia_device *link);
  99
 100/*
 101   The attach() and detach() entry points are used to create and destroy
 102   "instances" of the driver, where each instance represents everything
 103   needed to manage one actual PCMCIA card.
 104*/
 105
 106static void sedlbauer_detach(struct pcmcia_device *p_dev);
 107
 108/*
 109   You'll also need to prototype all the functions that will actually
 110   be used to talk to your device.  See 'memory_cs' for a good example
 111   of a fully self-sufficient driver; the other drivers rely more or
 112   less on other parts of the kernel.
 113*/
 114
 115/*
 116   A driver needs to provide a dev_node_t structure for each device
 117   on a card.  In some cases, there is only one device per card (for
 118   example, ethernet cards, modems).  In other cases, there may be
 119   many actual or logical devices (SCSI adapters, memory cards with
 120   multiple partitions).  The dev_node_t structures need to be kept
 121   in a linked list starting at the 'dev' field of a struct pcmcia_device
 122   structure.  We allocate them in the card's private data structure,
 123   because they generally shouldn't be allocated dynamically.
 124
 125   In this case, we also provide a flag to indicate if a device is
 126   "stopped" due to a power management event, or card ejection.  The
 127   device IO routines can use a flag like this to throttle IO to a
 128   card that is not ready to accept it.
 129*/
 130   
 131typedef struct local_info_t {
 132        struct pcmcia_device    *p_dev;
 133    dev_node_t          node;
 134    int                 stop;
 135    int                 cardnr;
 136} local_info_t;
 137
 138/*======================================================================
 139
 140    sedlbauer_attach() creates an "instance" of the driver, allocating
 141    local data structures for one device.  The device is registered
 142    with Card Services.
 143
 144    The dev_link structure is initialized, but we don't actually
 145    configure the card at this point -- we wait until we receive a
 146    card insertion event.
 147    
 148======================================================================*/
 149
 150static int sedlbauer_probe(struct pcmcia_device *link)
 151{
 152    local_info_t *local;
 153
 154    DEBUG(0, "sedlbauer_attach()\n");
 155
 156    /* Allocate space for private device-specific data */
 157    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 158    if (!local) return -ENOMEM;
 159    local->cardnr = -1;
 160
 161    local->p_dev = link;
 162    link->priv = local;
 163
 164    /* Interrupt setup */
 165    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
 166    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 167    link->irq.Handler = NULL;
 168
 169    /*
 170      General socket configuration defaults can go here.  In this
 171      client, we assume very little, and rely on the CIS for almost
 172      everything.  In most clients, many details (i.e., number, sizes,
 173      and attributes of IO windows) are fixed by the nature of the
 174      device, and can be hard-wired here.
 175    */
 176
 177    /* from old sedl_cs 
 178    */
 179    /* The io structure describes IO port mapping */
 180    link->io.NumPorts1 = 8;
 181    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 182    link->io.IOAddrLines = 3;
 183
 184    link->conf.Attributes = 0;
 185    link->conf.IntType = INT_MEMORY_AND_IO;
 186
 187    return sedlbauer_config(link);
 188} /* sedlbauer_attach */
 189
 190/*======================================================================
 191
 192    This deletes a driver "instance".  The device is de-registered
 193    with Card Services.  If it has been released, all local data
 194    structures are freed.  Otherwise, the structures will be freed
 195    when the device is released.
 196
 197======================================================================*/
 198
 199static void sedlbauer_detach(struct pcmcia_device *link)
 200{
 201        DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
 202
 203        ((local_info_t *)link->priv)->stop = 1;
 204        sedlbauer_release(link);
 205
 206        /* This points to the parent local_info_t struct */
 207        kfree(link->priv);
 208} /* sedlbauer_detach */
 209
 210/*======================================================================
 211
 212    sedlbauer_config() is scheduled to run after a CARD_INSERTION event
 213    is received, to configure the PCMCIA socket, and to make the
 214    device available to the system.
 215    
 216======================================================================*/
 217#define CS_CHECK(fn, ret) \
 218do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 219
 220static int sedlbauer_config_check(struct pcmcia_device *p_dev,
 221                                  cistpl_cftable_entry_t *cfg,
 222                                  cistpl_cftable_entry_t *dflt,
 223                                  unsigned int vcc,
 224                                  void *priv_data)
 225{
 226        win_req_t *req = priv_data;
 227
 228        if (cfg->index == 0)
 229                return -ENODEV;
 230
 231        /* Does this card need audio output? */
 232        if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
 233                p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
 234                p_dev->conf.Status = CCSR_AUDIO_ENA;
 235        }
 236
 237        /* Use power settings for Vcc and Vpp if present */
 238        /*  Note that the CIS values need to be rescaled */
 239        if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
 240                if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
 241                        return -ENODEV;
 242        } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
 243                if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
 244                        return -ENODEV;
 245        }
 246
 247        if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
 248                p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
 249        else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
 250                p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
 251
 252        /* Do we need to allocate an interrupt? */
 253        if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
 254                p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
 255
 256        /* IO window settings */
 257        p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
 258        if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
 259                cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
 260                p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
 261                if (!(io->flags & CISTPL_IO_8BIT))
 262                        p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
 263                if (!(io->flags & CISTPL_IO_16BIT))
 264                        p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 265                p_dev->io.BasePort1 = io->win[0].base;
 266                p_dev->io.NumPorts1 = io->win[0].len;
 267                if (io->nwin > 1) {
 268                        p_dev->io.Attributes2 = p_dev->io.Attributes1;
 269                        p_dev->io.BasePort2 = io->win[1].base;
 270                        p_dev->io.NumPorts2 = io->win[1].len;
 271                }
 272                /* This reserves IO space but doesn't actually enable it */
 273                if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
 274                        return -ENODEV;
 275        }
 276
 277        /*
 278          Now set up a common memory window, if needed.  There is room
 279          in the struct pcmcia_device structure for one memory window handle,
 280          but if the base addresses need to be saved, or if multiple
 281          windows are needed, the info should go in the private data
 282          structure for this device.
 283
 284          Note that the memory window base is a physical address, and
 285          needs to be mapped to virtual space with ioremap() before it
 286          is used.
 287        */
 288        if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
 289                cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
 290                memreq_t map;
 291                req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
 292                req->Attributes |= WIN_ENABLE;
 293                req->Base = mem->win[0].host_addr;
 294                req->Size = mem->win[0].len;
 295                req->AccessSpeed = 0;
 296                if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0)
 297                        return -ENODEV;
 298                map.Page = 0;
 299                map.CardOffset = mem->win[0].card_addr;
 300                if (pcmcia_map_mem_page(p_dev->win, &map) != 0)
 301                        return -ENODEV;
 302        }
 303        return 0;
 304}
 305
 306
 307
 308static int sedlbauer_config(struct pcmcia_device *link)
 309{
 310    local_info_t *dev = link->priv;
 311    win_req_t *req;
 312    int last_fn, last_ret;
 313    IsdnCard_t  icard;
 314
 315    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
 316
 317    req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
 318    if (!req)
 319            return -ENOMEM;
 320
 321    /*
 322      In this loop, we scan the CIS for configuration table entries,
 323      each of which describes a valid card configuration, including
 324      voltage, IO window, memory window, and interrupt settings.
 325
 326      We make no assumptions about the card to be configured: we use
 327      just the information available in the CIS.  In an ideal world,
 328      this would work for any PCMCIA card, but it requires a complete
 329      and accurate CIS.  In practice, a driver usually "knows" most of
 330      these things without consulting the CIS, and most client drivers
 331      will only use the CIS to fill in implementation-defined details.
 332    */
 333    last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
 334    if (last_ret)
 335            goto failed;
 336
 337    /*
 338       Allocate an interrupt line.  Note that this does not assign a
 339       handler to the interrupt, unless the 'Handler' member of the
 340       irq structure is initialized.
 341    */
 342    if (link->conf.Attributes & CONF_ENABLE_IRQ)
 343        CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 344        
 345    /*
 346       This actually configures the PCMCIA socket -- setting up
 347       the I/O windows and the interrupt mapping, and putting the
 348       card and host interface into "Memory and IO" mode.
 349    */
 350    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 351
 352    /*
 353      At this point, the dev_node_t structure(s) need to be
 354      initialized and arranged in a linked list at link->dev.
 355    */
 356    sprintf(dev->node.dev_name, "sedlbauer");
 357    dev->node.major = dev->node.minor = 0;
 358    link->dev_node = &dev->node;
 359
 360    /* Finally, report what we've done */
 361    printk(KERN_INFO "%s: index 0x%02x:",
 362           dev->node.dev_name, link->conf.ConfigIndex);
 363    if (link->conf.Vpp)
 364        printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
 365    if (link->conf.Attributes & CONF_ENABLE_IRQ)
 366        printk(", irq %d", link->irq.AssignedIRQ);
 367    if (link->io.NumPorts1)
 368        printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 369               link->io.BasePort1+link->io.NumPorts1-1);
 370    if (link->io.NumPorts2)
 371        printk(" & 0x%04x-0x%04x", link->io.BasePort2,
 372               link->io.BasePort2+link->io.NumPorts2-1);
 373    if (link->win)
 374        printk(", mem 0x%06lx-0x%06lx", req->Base,
 375               req->Base+req->Size-1);
 376    printk("\n");
 377
 378    icard.para[0] = link->irq.AssignedIRQ;
 379    icard.para[1] = link->io.BasePort1;
 380    icard.protocol = protocol;
 381    icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
 382    
 383    last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
 384    if (last_ret < 0) {
 385        printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
 386                last_ret, link->io.BasePort1);
 387        sedlbauer_release(link);
 388        return -ENODEV;
 389    } else
 390        ((local_info_t*)link->priv)->cardnr = last_ret;
 391
 392    return 0;
 393
 394cs_failed:
 395    cs_error(link, last_fn, last_ret);
 396failed:
 397    sedlbauer_release(link);
 398    return -ENODEV;
 399
 400} /* sedlbauer_config */
 401
 402/*======================================================================
 403
 404    After a card is removed, sedlbauer_release() will unregister the
 405    device, and release the PCMCIA configuration.  If the device is
 406    still open, this will be postponed until it is closed.
 407    
 408======================================================================*/
 409
 410static void sedlbauer_release(struct pcmcia_device *link)
 411{
 412    local_info_t *local = link->priv;
 413    DEBUG(0, "sedlbauer_release(0x%p)\n", link);
 414
 415    if (local) {
 416        if (local->cardnr >= 0) {
 417            /* no unregister function with hisax */
 418            HiSax_closecard(local->cardnr);
 419        }
 420    }
 421
 422    pcmcia_disable_device(link);
 423} /* sedlbauer_release */
 424
 425static int sedlbauer_suspend(struct pcmcia_device *link)
 426{
 427        local_info_t *dev = link->priv;
 428
 429        dev->stop = 1;
 430
 431        return 0;
 432}
 433
 434static int sedlbauer_resume(struct pcmcia_device *link)
 435{
 436        local_info_t *dev = link->priv;
 437
 438        dev->stop = 0;
 439
 440        return 0;
 441}
 442
 443
 444static struct pcmcia_device_id sedlbauer_ids[] = {
 445        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
 446        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
 447        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
 448        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
 449        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
 450        PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
 451/*      PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
 452        PCMCIA_DEVICE_NULL
 453};
 454MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
 455
 456static struct pcmcia_driver sedlbauer_driver = {
 457        .owner          = THIS_MODULE,
 458        .drv            = {
 459                .name   = "sedlbauer_cs",
 460        },
 461        .probe          = sedlbauer_probe,
 462        .remove         = sedlbauer_detach,
 463        .id_table       = sedlbauer_ids,
 464        .suspend        = sedlbauer_suspend,
 465        .resume         = sedlbauer_resume,
 466};
 467
 468static int __init init_sedlbauer_cs(void)
 469{
 470        return pcmcia_register_driver(&sedlbauer_driver);
 471}
 472
 473static void __exit exit_sedlbauer_cs(void)
 474{
 475        pcmcia_unregister_driver(&sedlbauer_driver);
 476}
 477
 478module_init(init_sedlbauer_cs);
 479module_exit(exit_sedlbauer_cs);
 480
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.