• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/isdn/hysdn/
1/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 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 char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
40static int cardmax;		/* number of found cards */
41hysdn_card *card_root = NULL;	/* pointer to first card */
42static hysdn_card *card_last = NULL;	/* pointer to first card */
43
44
45/****************************************************************************/
46/* The module startup and shutdown code. Only compiled when used as module. */
47/* Using the driver as module is always advisable, because the booting      */
48/* image becomes smaller and the driver code is only loaded when needed.    */
49/* Additionally newer versions may be activated without rebooting.          */
50/****************************************************************************/
51
52/******************************************************/
53/* extract revision number from string for log output */
54/******************************************************/
55char *
56hysdn_getrev(const char *revision)
57{
58	char *rev;
59	char *p;
60
61	if ((p = strchr(revision, ':'))) {
62		rev = p + 2;
63		p = strchr(rev, '$');
64		*--p = 0;
65	} else
66		rev = "???";
67	return rev;
68}
69
70
71/****************************************************************************/
72/* init_module is called once when the module is loaded to do all necessary */
73/* things like autodetect...                                                */
74/* If the return value of this function is 0 the init has been successful   */
75/* and the module is added to the list in /proc/modules, otherwise an error */
76/* is assumed and the module will not be kept in memory.                    */
77/****************************************************************************/
78
79static 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
125err_out_card:
126	kfree(card);
127err_out:
128	pci_disable_device(akt_pcidev);
129	return rc;
130}
131
132static 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
166static 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
173static int hysdn_have_procfs;
174
175static int __init
176hysdn_init(void)
177{
178	char tmp[50];
179	int rc;
180
181	strcpy(tmp, hysdn_init_revision);
182	printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
183	strcpy(tmp, hysdn_net_revision);
184	printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
185
186	rc = pci_register_driver(&hysdn_pci_driver);
187	if (rc)
188		return rc;
189
190	printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
191
192	if (!hysdn_procconf_init())
193		hysdn_have_procfs = 1;
194
195#ifdef CONFIG_HYSDN_CAPI
196	if(cardmax > 0) {
197		if(hycapi_init()) {
198			printk(KERN_ERR "HYCAPI: init failed\n");
199
200			if (hysdn_have_procfs)
201				hysdn_procconf_release();
202
203			pci_unregister_driver(&hysdn_pci_driver);
204			return -ESPIPE;
205		}
206	}
207#endif /* CONFIG_HYSDN_CAPI */
208
209	return 0;		/* no error */
210}				/* init_module */
211
212
213/***********************************************************************/
214/* cleanup_module is called when the module is released by the kernel. */
215/* The routine is only called if init_module has been successful and   */
216/* the module counter has a value of 0. Otherwise this function will   */
217/* not be called. This function must release all resources still allo- */
218/* cated as after the return from this function the module code will   */
219/* be removed from memory.                                             */
220/***********************************************************************/
221static void __exit
222hysdn_exit(void)
223{
224	if (hysdn_have_procfs)
225		hysdn_procconf_release();
226
227	pci_unregister_driver(&hysdn_pci_driver);
228
229#ifdef CONFIG_HYSDN_CAPI
230	hycapi_cleanup();
231#endif /* CONFIG_HYSDN_CAPI */
232
233	printk(KERN_NOTICE "HYSDN: module unloaded\n");
234}				/* cleanup_module */
235
236module_init(hysdn_init);
237module_exit(hysdn_exit);
238