diff options
| -rw-r--r-- | drivers/isdn/hysdn/hysdn_init.c | 274 |
1 files changed, 130 insertions, 144 deletions
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 9e01748a176e..b7cc5c2f08c6 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c | |||
| @@ -20,10 +20,15 @@ | |||
| 20 | #include "hysdn_defs.h" | 20 | #include "hysdn_defs.h" |
| 21 | 21 | ||
| 22 | static struct pci_device_id hysdn_pci_tbl[] = { | 22 | static struct pci_device_id hysdn_pci_tbl[] = { |
| 23 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, | 23 | { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, |
| 24 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, | 24 | PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, |
| 25 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, | 25 | { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, |
| 26 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, | 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 | |||
| 27 | { } /* Terminating entry */ | 32 | { } /* Terminating entry */ |
| 28 | }; | 33 | }; |
| 29 | MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); | 34 | MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); |
| @@ -34,128 +39,7 @@ MODULE_LICENSE("GPL"); | |||
| 34 | static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; | 39 | static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; |
| 35 | static int cardmax; /* number of found cards */ | 40 | static int cardmax; /* number of found cards */ |
| 36 | hysdn_card *card_root = NULL; /* pointer to first card */ | 41 | hysdn_card *card_root = NULL; /* pointer to first card */ |
| 37 | 42 | static hysdn_card *card_last = NULL; /* pointer to first card */ | |
| 38 | /**********************************************/ | ||
| 39 | /* table assigning PCI-sub ids to board types */ | ||
| 40 | /* the last entry contains all 0 */ | ||
| 41 | /**********************************************/ | ||
| 42 | static struct { | ||
| 43 | unsigned short subid; /* PCI sub id */ | ||
| 44 | unsigned char cardtyp; /* card type assigned */ | ||
| 45 | } pci_subid_map[] = { | ||
| 46 | |||
| 47 | { | ||
| 48 | PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO | ||
| 49 | }, | ||
| 50 | { | ||
| 51 | PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 | ||
| 52 | }, | ||
| 53 | { | ||
| 54 | PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO | ||
| 55 | }, | ||
| 56 | { | ||
| 57 | PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO | ||
| 58 | }, | ||
| 59 | { | ||
| 60 | 0, 0 | ||
| 61 | } /* terminating entry */ | ||
| 62 | }; | ||
| 63 | |||
| 64 | |||
| 65 | /*********************************************************************/ | ||
| 66 | /* search_cards searches for available cards in the pci config data. */ | ||
| 67 | /* If a card is found, the card structure is allocated and the cards */ | ||
| 68 | /* ressources are reserved. cardmax is incremented. */ | ||
| 69 | /*********************************************************************/ | ||
| 70 | static void | ||
| 71 | search_cards(void) | ||
| 72 | { | ||
| 73 | struct pci_dev *akt_pcidev = NULL; | ||
| 74 | hysdn_card *card, *card_last; | ||
| 75 | int i; | ||
| 76 | |||
| 77 | card_root = NULL; | ||
| 78 | card_last = NULL; | ||
| 79 | while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, | ||
| 80 | akt_pcidev)) != NULL) { | ||
| 81 | if (pci_enable_device(akt_pcidev)) | ||
| 82 | continue; | ||
| 83 | |||
| 84 | if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { | ||
| 85 | printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | card->myid = cardmax; /* set own id */ | ||
| 89 | card->bus = akt_pcidev->bus->number; | ||
| 90 | card->devfn = akt_pcidev->devfn; /* slot + function */ | ||
| 91 | card->subsysid = akt_pcidev->subsystem_device; | ||
| 92 | card->irq = akt_pcidev->irq; | ||
| 93 | card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); | ||
| 94 | card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); | ||
| 95 | card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); | ||
| 96 | card->brdtype = BD_NONE; /* unknown */ | ||
| 97 | card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ | ||
| 98 | card->faxchans = 0; /* default no fax channels */ | ||
| 99 | card->bchans = 2; /* and 2 b-channels */ | ||
| 100 | for (i = 0; pci_subid_map[i].subid; i++) | ||
| 101 | if (pci_subid_map[i].subid == card->subsysid) { | ||
| 102 | card->brdtype = pci_subid_map[i].cardtyp; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | if (card->brdtype != BD_NONE) { | ||
| 106 | if (ergo_inithardware(card)) { | ||
| 107 | printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); | ||
| 108 | kfree(card); | ||
| 109 | continue; | ||
| 110 | } | ||
| 111 | } else { | ||
| 112 | printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); | ||
| 113 | kfree(card); /* release mem */ | ||
| 114 | continue; | ||
| 115 | } | ||
| 116 | cardmax++; | ||
| 117 | card->next = NULL; /*end of chain */ | ||
| 118 | if (card_last) | ||
| 119 | card_last->next = card; /* pointer to next card */ | ||
| 120 | else | ||
| 121 | card_root = card; | ||
| 122 | card_last = card; /* new chain end */ | ||
| 123 | } /* device found */ | ||
| 124 | } /* search_cards */ | ||
| 125 | |||
| 126 | /************************************************************************************/ | ||
| 127 | /* free_resources frees the acquired PCI resources and returns the allocated memory */ | ||
| 128 | /************************************************************************************/ | ||
| 129 | static void | ||
| 130 | free_resources(void) | ||
| 131 | { | ||
| 132 | hysdn_card *card; | ||
| 133 | |||
| 134 | while (card_root) { | ||
| 135 | card = card_root; | ||
| 136 | if (card->releasehardware) | ||
| 137 | card->releasehardware(card); /* free all hardware resources */ | ||
| 138 | card_root = card_root->next; /* remove card from chain */ | ||
| 139 | kfree(card); /* return mem */ | ||
| 140 | |||
| 141 | } /* while card_root */ | ||
| 142 | } /* free_resources */ | ||
| 143 | |||
| 144 | /**************************************************************************/ | ||
| 145 | /* stop_cards disables (hardware resets) all cards and disables interrupt */ | ||
| 146 | /**************************************************************************/ | ||
| 147 | static void | ||
| 148 | stop_cards(void) | ||
| 149 | { | ||
| 150 | hysdn_card *card; | ||
| 151 | |||
| 152 | card = card_root; /* first in chain */ | ||
| 153 | while (card) { | ||
| 154 | if (card->stopcard) | ||
| 155 | card->stopcard(card); | ||
| 156 | card = card->next; /* remove card from chain */ | ||
| 157 | } /* while card */ | ||
| 158 | } /* stop_cards */ | ||
| 159 | 43 | ||
| 160 | 44 | ||
| 161 | /****************************************************************************/ | 45 | /****************************************************************************/ |
| @@ -191,31 +75,138 @@ hysdn_getrev(const char *revision) | |||
| 191 | /* and the module is added to the list in /proc/modules, otherwise an error */ | 75 | /* and the module is added to the list in /proc/modules, otherwise an error */ |
| 192 | /* is assumed and the module will not be kept in memory. */ | 76 | /* is assumed and the module will not be kept in memory. */ |
| 193 | /****************************************************************************/ | 77 | /****************************************************************************/ |
| 78 | |||
| 79 | static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev, | ||
| 80 | const struct pci_device_id *ent) | ||
| 81 | { | ||
| 82 | hysdn_card *card; | ||
| 83 | int rc; | ||
| 84 | |||
| 85 | rc = pci_enable_device(akt_pcidev); | ||
| 86 | if (rc) | ||
| 87 | return rc; | ||
| 88 | |||
| 89 | if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { | ||
| 90 | printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); | ||
| 91 | rc = -ENOMEM; | ||
| 92 | goto err_out; | ||
| 93 | } | ||
| 94 | card->myid = cardmax; /* set own id */ | ||
| 95 | card->bus = akt_pcidev->bus->number; | ||
| 96 | card->devfn = akt_pcidev->devfn; /* slot + function */ | ||
| 97 | card->subsysid = akt_pcidev->subsystem_device; | ||
| 98 | card->irq = akt_pcidev->irq; | ||
| 99 | card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); | ||
| 100 | card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); | ||
| 101 | card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); | ||
| 102 | card->brdtype = BD_NONE; /* unknown */ | ||
| 103 | card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ | ||
| 104 | card->faxchans = 0; /* default no fax channels */ | ||
| 105 | card->bchans = 2; /* and 2 b-channels */ | ||
| 106 | card->brdtype = ent->driver_data; | ||
| 107 | |||
| 108 | if (ergo_inithardware(card)) { | ||
| 109 | printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); | ||
| 110 | rc = -EBUSY; | ||
| 111 | goto err_out_card; | ||
| 112 | } | ||
| 113 | |||
| 114 | cardmax++; | ||
| 115 | card->next = NULL; /*end of chain */ | ||
| 116 | if (card_last) | ||
| 117 | card_last->next = card; /* pointer to next card */ | ||
| 118 | else | ||
| 119 | card_root = card; | ||
| 120 | card_last = card; /* new chain end */ | ||
| 121 | |||
| 122 | pci_set_drvdata(akt_pcidev, card); | ||
| 123 | return 0; | ||
| 124 | |||
| 125 | err_out_card: | ||
| 126 | kfree(card); | ||
| 127 | err_out: | ||
| 128 | pci_disable_device(akt_pcidev); | ||
| 129 | return rc; | ||
| 130 | } | ||
| 131 | |||
| 132 | static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev) | ||
| 133 | { | ||
| 134 | hysdn_card *card = pci_get_drvdata(akt_pcidev); | ||
| 135 | |||
| 136 | pci_set_drvdata(akt_pcidev, NULL); | ||
| 137 | |||
| 138 | if (card->stopcard) | ||
| 139 | card->stopcard(card); | ||
| 140 | |||
| 141 | #ifdef CONFIG_HYSDN_CAPI | ||
| 142 | hycapi_capi_release(card); | ||
| 143 | #endif | ||
| 144 | |||
| 145 | if (card->releasehardware) | ||
| 146 | card->releasehardware(card); /* free all hardware resources */ | ||
| 147 | |||
| 148 | if (card == card_root) { | ||
| 149 | card_root = card_root->next; | ||
| 150 | if (!card_root) | ||
| 151 | card_last = NULL; | ||
| 152 | } else { | ||
| 153 | hysdn_card *tmp = card_root; | ||
| 154 | while (tmp) { | ||
| 155 | if (tmp->next == card) | ||
| 156 | tmp->next = card->next; | ||
| 157 | card_last = tmp; | ||
| 158 | tmp = tmp->next; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | kfree(card); | ||
| 163 | pci_disable_device(akt_pcidev); | ||
| 164 | } | ||
| 165 | |||
| 166 | static struct pci_driver hysdn_pci_driver = { | ||
| 167 | .name = "hysdn", | ||
| 168 | .id_table = hysdn_pci_tbl, | ||
| 169 | .probe = hysdn_pci_init_one, | ||
| 170 | .remove = __devexit_p(hysdn_pci_remove_one), | ||
| 171 | }; | ||
| 172 | |||
| 173 | static int hysdn_have_procfs; | ||
| 174 | |||
| 194 | static int __init | 175 | static int __init |
| 195 | hysdn_init(void) | 176 | hysdn_init(void) |
| 196 | { | 177 | { |
| 197 | char tmp[50]; | 178 | char tmp[50]; |
| 179 | int rc; | ||
| 198 | 180 | ||
| 199 | strcpy(tmp, hysdn_init_revision); | 181 | strcpy(tmp, hysdn_init_revision); |
| 200 | printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); | 182 | printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); |
| 201 | strcpy(tmp, hysdn_net_revision); | 183 | strcpy(tmp, hysdn_net_revision); |
| 202 | printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); | 184 | printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); |
| 203 | search_cards(); | 185 | |
| 186 | rc = pci_register_driver(&hysdn_pci_driver); | ||
| 187 | if (rc) | ||
| 188 | return rc; | ||
| 189 | |||
| 204 | printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); | 190 | printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); |
| 205 | 191 | ||
| 206 | if (hysdn_procconf_init()) { | 192 | if (!hysdn_procconf_init()) |
| 207 | free_resources(); /* proc file_sys not created */ | 193 | hysdn_have_procfs = 1; |
| 208 | return (-1); | 194 | |
| 209 | } | ||
| 210 | #ifdef CONFIG_HYSDN_CAPI | 195 | #ifdef CONFIG_HYSDN_CAPI |
| 211 | if(cardmax > 0) { | 196 | if(cardmax > 0) { |
| 212 | if(hycapi_init()) { | 197 | if(hycapi_init()) { |
| 213 | printk(KERN_ERR "HYCAPI: init failed\n"); | 198 | printk(KERN_ERR "HYCAPI: init failed\n"); |
| 214 | return(-1); | 199 | |
| 200 | if (hysdn_have_procfs) | ||
| 201 | hysdn_procconf_release(); | ||
| 202 | |||
| 203 | pci_unregister_driver(&hysdn_pci_driver); | ||
| 204 | return -ESPIPE; | ||
| 215 | } | 205 | } |
| 216 | } | 206 | } |
| 217 | #endif /* CONFIG_HYSDN_CAPI */ | 207 | #endif /* CONFIG_HYSDN_CAPI */ |
| 218 | return (0); /* no error */ | 208 | |
| 209 | return 0; /* no error */ | ||
| 219 | } /* init_module */ | 210 | } /* init_module */ |
| 220 | 211 | ||
| 221 | 212 | ||
| @@ -230,20 +221,15 @@ hysdn_init(void) | |||
| 230 | static void __exit | 221 | static void __exit |
| 231 | hysdn_exit(void) | 222 | hysdn_exit(void) |
| 232 | { | 223 | { |
| 224 | if (hysdn_have_procfs) | ||
| 225 | hysdn_procconf_release(); | ||
| 226 | |||
| 227 | pci_unregister_driver(&hysdn_pci_driver); | ||
| 228 | |||
| 233 | #ifdef CONFIG_HYSDN_CAPI | 229 | #ifdef CONFIG_HYSDN_CAPI |
| 234 | hysdn_card *card; | ||
| 235 | #endif /* CONFIG_HYSDN_CAPI */ | ||
| 236 | stop_cards(); | ||
| 237 | #ifdef CONFIG_HYSDN_CAPI | ||
| 238 | card = card_root; /* first in chain */ | ||
| 239 | while (card) { | ||
| 240 | hycapi_capi_release(card); | ||
| 241 | card = card->next; /* remove card from chain */ | ||
| 242 | } /* while card */ | ||
| 243 | hycapi_cleanup(); | 230 | hycapi_cleanup(); |
| 244 | #endif /* CONFIG_HYSDN_CAPI */ | 231 | #endif /* CONFIG_HYSDN_CAPI */ |
| 245 | hysdn_procconf_release(); | 232 | |
| 246 | free_resources(); | ||
| 247 | printk(KERN_NOTICE "HYSDN: module unloaded\n"); | 233 | printk(KERN_NOTICE "HYSDN: module unloaded\n"); |
| 248 | } /* cleanup_module */ | 234 | } /* cleanup_module */ |
| 249 | 235 | ||
