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 __devinit 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 __devexit 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 = __devexit_p(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