linux/drivers/isdn/hysdn/hysdn_init.c
<<
>>
Prefs
   1/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $
   2 *
   3 * Linux driver for HYSDN cards, init functions.
   4 *
   5 * Author    Werner Cornelius (werner@titro.de) for Hypercope GmbH
   6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/poll.h>
  16#include <linux/vmalloc.h>
  17#include <linux/slab.h>
  18#include <linux/pci.h>
  19
  20#include "hysdn_defs.h"
  21
  22static struct pci_device_id hysdn_pci_tbl[] = {
  23        { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
  24          PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
  25        { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
  26          PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
  27        { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
  28          PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
  29        { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
  30          PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
  31
  32        { }                             /* Terminating entry */
  33};
  34MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
  35MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards");
  36MODULE_AUTHOR("Werner Cornelius");
  37MODULE_LICENSE("GPL");
  38
  39static int cardmax;             /* number of found cards */
  40hysdn_card *card_root = NULL;   /* pointer to first card */
  41static hysdn_card *card_last = NULL;    /* pointer to first card */
  42
  43
  44/****************************************************************************/
  45/* The module startup and shutdown code. Only compiled when used as module. */
  46/* Using the driver as module is always advisable, because the booting      */
  47/* image becomes smaller and the driver code is only loaded when needed.    */
  48/* Additionally newer versions may be activated without rebooting.          */
  49/****************************************************************************/
  50
  51/****************************************************************************/
  52/* init_module is called once when the module is loaded to do all necessary */
  53/* things like autodetect...                                                */
  54/* If the return value of this function is 0 the init has been successful   */
  55/* and the module is added to the list in /proc/modules, otherwise an error */
  56/* is assumed and the module will not be kept in memory.                    */
  57/****************************************************************************/
  58
  59static int hysdn_pci_init_one(struct pci_dev *akt_pcidev,
  60                              const struct pci_device_id *ent)
  61{
  62        hysdn_card *card;
  63        int rc;
  64
  65        rc = pci_enable_device(akt_pcidev);
  66        if (rc)
  67                return rc;
  68
  69        if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
  70                printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
  71                rc = -ENOMEM;
  72                goto err_out;
  73        }
  74        card->myid = cardmax;   /* set own id */
  75        card->bus = akt_pcidev->bus->number;
  76        card->devfn = akt_pcidev->devfn;        /* slot + function */
  77        card->subsysid = akt_pcidev->subsystem_device;
  78        card->irq = akt_pcidev->irq;
  79        card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
  80        card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
  81        card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
  82        card->brdtype = BD_NONE;        /* unknown */
  83        card->debug_flags = DEF_DEB_FLAGS;      /* set default debug */
  84        card->faxchans = 0;     /* default no fax channels */
  85        card->bchans = 2;       /* and 2 b-channels */
  86        card->brdtype = ent->driver_data;
  87
  88        if (ergo_inithardware(card)) {
  89                printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
  90                rc = -EBUSY;
  91                goto err_out_card;
  92        }
  93
  94        cardmax++;
  95        card->next = NULL;      /*end of chain */
  96        if (card_last)
  97                card_last->next = card;         /* pointer to next card */
  98        else
  99                card_root = card;
 100        card_last = card;       /* new chain end */
 101
 102        pci_set_drvdata(akt_pcidev, card);
 103        return 0;
 104
 105err_out_card:
 106        kfree(card);
 107err_out:
 108        pci_disable_device(akt_pcidev);
 109        return rc;
 110}
 111
 112static void hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
 113{
 114        hysdn_card *card = pci_get_drvdata(akt_pcidev);
 115
 116        pci_set_drvdata(akt_pcidev, NULL);
 117
 118        if (card->stopcard)
 119                card->stopcard(card);
 120
 121#ifdef CONFIG_HYSDN_CAPI
 122        hycapi_capi_release(card);
 123#endif
 124
 125        if (card->releasehardware)
 126                card->releasehardware(card);   /* free all hardware resources */
 127
 128        if (card == card_root) {
 129                card_root = card_root->next;
 130                if (!card_root)
 131                        card_last = NULL;
 132        } else {
 133                hysdn_card *tmp = card_root;
 134                while (tmp) {
 135                        if (tmp->next == card)
 136                                tmp->next = card->next;
 137                        card_last = tmp;
 138                        tmp = tmp->next;
 139                }
 140        }
 141
 142        kfree(card);
 143        pci_disable_device(akt_pcidev);
 144}
 145
 146static struct pci_driver hysdn_pci_driver = {
 147        .name           = "hysdn",
 148        .id_table       = hysdn_pci_tbl,
 149        .probe          = hysdn_pci_init_one,
 150        .remove         = hysdn_pci_remove_one,
 151};
 152
 153static int hysdn_have_procfs;
 154
 155static int __init
 156hysdn_init(void)
 157{
 158        int rc;
 159
 160        printk(KERN_NOTICE "HYSDN: module loaded\n");
 161
 162        rc = pci_register_driver(&hysdn_pci_driver);
 163        if (rc)
 164                return rc;
 165
 166        printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
 167
 168        if (!hysdn_procconf_init())
 169                hysdn_have_procfs = 1;
 170
 171#ifdef CONFIG_HYSDN_CAPI
 172        if (cardmax > 0) {
 173                if (hycapi_init()) {
 174                        printk(KERN_ERR "HYCAPI: init failed\n");
 175
 176                        if (hysdn_have_procfs)
 177                                hysdn_procconf_release();
 178
 179                        pci_unregister_driver(&hysdn_pci_driver);
 180                        return -ESPIPE;
 181                }
 182        }
 183#endif /* CONFIG_HYSDN_CAPI */
 184
 185        return 0;               /* no error */
 186}                               /* init_module */
 187
 188
 189/***********************************************************************/
 190/* cleanup_module is called when the module is released by the kernel. */
 191/* The routine is only called if init_module has been successful and   */
 192/* the module counter has a value of 0. Otherwise this function will   */
 193/* not be called. This function must release all resources still allo- */
 194/* cated as after the return from this function the module code will   */
 195/* be removed from memory.                                             */
 196/***********************************************************************/
 197static void __exit
 198hysdn_exit(void)
 199{
 200        if (hysdn_have_procfs)
 201                hysdn_procconf_release();
 202
 203        pci_unregister_driver(&hysdn_pci_driver);
 204
 205#ifdef CONFIG_HYSDN_CAPI
 206        hycapi_cleanup();
 207#endif /* CONFIG_HYSDN_CAPI */
 208
 209        printk(KERN_NOTICE "HYSDN: module unloaded\n");
 210}                               /* cleanup_module */
 211
 212module_init(hysdn_init);
 213module_exit(hysdn_exit);
 214