linux/drivers/isdn/hisax/elsa_cs.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    An elsa_cs PCMCIA client driver
   4
   5    This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
   6
   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 Klaus
  23    Lichtenwalder <Lichtenwalder@ACM.org>. 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/module.h>
  39#include <linux/kernel.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/cistpl.h>
  50#include <pcmcia/cisreg.h>
  51#include <pcmcia/ds.h>
  52#include "hisax_cfg.h"
  53
  54MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
  55MODULE_AUTHOR("Klaus Lichtenwalder");
  56MODULE_LICENSE("Dual MPL/GPL");
  57
  58
  59/*====================================================================*/
  60
  61/* Parameters that can be set with 'insmod' */
  62
  63static int protocol = 2;        /* EURO-ISDN Default */
  64module_param(protocol, int, 0);
  65
  66static int elsa_cs_config(struct pcmcia_device *link) __devinit ;
  67static void elsa_cs_release(struct pcmcia_device *link);
  68static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit;
  69
  70typedef struct local_info_t {
  71        struct pcmcia_device    *p_dev;
  72    int                 busy;
  73    int                 cardnr;
  74} local_info_t;
  75
  76static int __devinit elsa_cs_probe(struct pcmcia_device *link)
  77{
  78    local_info_t *local;
  79
  80    dev_dbg(&link->dev, "elsa_cs_attach()\n");
  81
  82    /* Allocate space for private device-specific data */
  83    local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
  84    if (!local) return -ENOMEM;
  85
  86    local->p_dev = link;
  87    link->priv = local;
  88
  89    local->cardnr = -1;
  90
  91    return elsa_cs_config(link);
  92} /* elsa_cs_attach */
  93
  94static void __devexit elsa_cs_detach(struct pcmcia_device *link)
  95{
  96        local_info_t *info = link->priv;
  97
  98        dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
  99
 100        info->busy = 1;
 101        elsa_cs_release(link);
 102
 103        kfree(info);
 104} /* elsa_cs_detach */
 105
 106static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 107{
 108        int j;
 109
 110        p_dev->io_lines = 3;
 111        p_dev->resource[0]->end = 8;
 112        p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
 113        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 114
 115        if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
 116                printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
 117                if (!pcmcia_request_io(p_dev))
 118                        return 0;
 119        } else {
 120                printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
 121                for (j = 0x2f0; j > 0x100; j -= 0x10) {
 122                        p_dev->resource[0]->start = j;
 123                        if (!pcmcia_request_io(p_dev))
 124                                return 0;
 125                }
 126        }
 127        return -ENODEV;
 128}
 129
 130static int __devinit elsa_cs_config(struct pcmcia_device *link)
 131{
 132    local_info_t *dev;
 133    int i;
 134    IsdnCard_t icard;
 135
 136    dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
 137    dev = link->priv;
 138
 139    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 140
 141    i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
 142    if (i != 0)
 143        goto failed;
 144
 145    if (!link->irq)
 146        goto failed;
 147
 148    i = pcmcia_enable_device(link);
 149    if (i != 0)
 150        goto failed;
 151
 152    icard.para[0] = link->irq;
 153    icard.para[1] = link->resource[0]->start;
 154    icard.protocol = protocol;
 155    icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
 156    
 157    i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
 158    if (i < 0) {
 159        printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
 160                "PCMCIA %d with %pR\n", i, link->resource[0]);
 161        elsa_cs_release(link);
 162    } else
 163        ((local_info_t*)link->priv)->cardnr = i;
 164
 165    return 0;
 166failed:
 167    elsa_cs_release(link);
 168    return -ENODEV;
 169} /* elsa_cs_config */
 170
 171static void elsa_cs_release(struct pcmcia_device *link)
 172{
 173    local_info_t *local = link->priv;
 174
 175    dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
 176
 177    if (local) {
 178        if (local->cardnr >= 0) {
 179            /* no unregister function with hisax */
 180            HiSax_closecard(local->cardnr);
 181        }
 182    }
 183
 184    pcmcia_disable_device(link);
 185} /* elsa_cs_release */
 186
 187static int elsa_suspend(struct pcmcia_device *link)
 188{
 189        local_info_t *dev = link->priv;
 190
 191        dev->busy = 1;
 192
 193        return 0;
 194}
 195
 196static int elsa_resume(struct pcmcia_device *link)
 197{
 198        local_info_t *dev = link->priv;
 199
 200        dev->busy = 0;
 201
 202        return 0;
 203}
 204
 205static struct pcmcia_device_id elsa_ids[] = {
 206        PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
 207        PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
 208        PCMCIA_DEVICE_NULL
 209};
 210MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
 211
 212static struct pcmcia_driver elsa_cs_driver = {
 213        .owner          = THIS_MODULE,
 214        .name           = "elsa_cs",
 215        .probe          = elsa_cs_probe,
 216        .remove         = __devexit_p(elsa_cs_detach),
 217        .id_table       = elsa_ids,
 218        .suspend        = elsa_suspend,
 219        .resume         = elsa_resume,
 220};
 221
 222static int __init init_elsa_cs(void)
 223{
 224        return pcmcia_register_driver(&elsa_cs_driver);
 225}
 226
 227static void __exit exit_elsa_cs(void)
 228{
 229        pcmcia_unregister_driver(&elsa_cs_driver);
 230}
 231
 232module_init(init_elsa_cs);
 233module_exit(exit_elsa_cs);
 234