diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hysdn/hysdn_init.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hysdn/hysdn_init.c')
-rw-r--r-- | drivers/isdn/hysdn/hysdn_init.c | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c new file mode 100644 index 000000000000..5cac2bf5f4b0 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_init.c | |||
@@ -0,0 +1,254 @@ | |||
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/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/poll.h> | ||
18 | #include <linux/vmalloc.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/pci.h> | ||
21 | |||
22 | #include "hysdn_defs.h" | ||
23 | |||
24 | static struct pci_device_id hysdn_pci_tbl[] = { | ||
25 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, | ||
26 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, | ||
27 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, | ||
28 | {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, | ||
29 | { } /* Terminating entry */ | ||
30 | }; | ||
31 | MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); | ||
32 | MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards"); | ||
33 | MODULE_AUTHOR("Werner Cornelius"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; | ||
37 | int cardmax; /* number of found cards */ | ||
38 | hysdn_card *card_root = NULL; /* pointer to first card */ | ||
39 | |||
40 | /**********************************************/ | ||
41 | /* table assigning PCI-sub ids to board types */ | ||
42 | /* the last entry contains all 0 */ | ||
43 | /**********************************************/ | ||
44 | static struct { | ||
45 | word subid; /* PCI sub id */ | ||
46 | uchar cardtyp; /* card type assigned */ | ||
47 | } pci_subid_map[] = { | ||
48 | |||
49 | { | ||
50 | PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO | ||
51 | }, | ||
52 | { | ||
53 | PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 | ||
54 | }, | ||
55 | { | ||
56 | PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO | ||
57 | }, | ||
58 | { | ||
59 | PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO | ||
60 | }, | ||
61 | { | ||
62 | 0, 0 | ||
63 | } /* terminating entry */ | ||
64 | }; | ||
65 | |||
66 | |||
67 | /*********************************************************************/ | ||
68 | /* search_cards searches for available cards in the pci config data. */ | ||
69 | /* If a card is found, the card structure is allocated and the cards */ | ||
70 | /* ressources are reserved. cardmax is incremented. */ | ||
71 | /*********************************************************************/ | ||
72 | static void | ||
73 | search_cards(void) | ||
74 | { | ||
75 | struct pci_dev *akt_pcidev = NULL; | ||
76 | hysdn_card *card, *card_last; | ||
77 | int i; | ||
78 | |||
79 | card_root = NULL; | ||
80 | card_last = NULL; | ||
81 | while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, | ||
82 | akt_pcidev)) != NULL) { | ||
83 | if (pci_enable_device(akt_pcidev)) | ||
84 | continue; | ||
85 | |||
86 | if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { | ||
87 | printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); | ||
88 | return; | ||
89 | } | ||
90 | memset(card, 0, sizeof(hysdn_card)); | ||
91 | card->myid = cardmax; /* set own id */ | ||
92 | card->bus = akt_pcidev->bus->number; | ||
93 | card->devfn = akt_pcidev->devfn; /* slot + function */ | ||
94 | card->subsysid = akt_pcidev->subsystem_device; | ||
95 | card->irq = akt_pcidev->irq; | ||
96 | card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); | ||
97 | card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); | ||
98 | card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); | ||
99 | card->brdtype = BD_NONE; /* unknown */ | ||
100 | card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ | ||
101 | card->faxchans = 0; /* default no fax channels */ | ||
102 | card->bchans = 2; /* and 2 b-channels */ | ||
103 | for (i = 0; pci_subid_map[i].subid; i++) | ||
104 | if (pci_subid_map[i].subid == card->subsysid) { | ||
105 | card->brdtype = pci_subid_map[i].cardtyp; | ||
106 | break; | ||
107 | } | ||
108 | if (card->brdtype != BD_NONE) { | ||
109 | if (ergo_inithardware(card)) { | ||
110 | printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); | ||
111 | kfree(card); | ||
112 | continue; | ||
113 | } | ||
114 | } else { | ||
115 | printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); | ||
116 | kfree(card); /* release mem */ | ||
117 | continue; | ||
118 | } | ||
119 | cardmax++; | ||
120 | card->next = NULL; /*end of chain */ | ||
121 | if (card_last) | ||
122 | card_last->next = card; /* pointer to next card */ | ||
123 | else | ||
124 | card_root = card; | ||
125 | card_last = card; /* new chain end */ | ||
126 | } /* device found */ | ||
127 | } /* search_cards */ | ||
128 | |||
129 | /************************************************************************************/ | ||
130 | /* free_resources frees the acquired PCI resources and returns the allocated memory */ | ||
131 | /************************************************************************************/ | ||
132 | static void | ||
133 | free_resources(void) | ||
134 | { | ||
135 | hysdn_card *card; | ||
136 | |||
137 | while (card_root) { | ||
138 | card = card_root; | ||
139 | if (card->releasehardware) | ||
140 | card->releasehardware(card); /* free all hardware resources */ | ||
141 | card_root = card_root->next; /* remove card from chain */ | ||
142 | kfree(card); /* return mem */ | ||
143 | |||
144 | } /* while card_root */ | ||
145 | } /* free_resources */ | ||
146 | |||
147 | /**************************************************************************/ | ||
148 | /* stop_cards disables (hardware resets) all cards and disables interrupt */ | ||
149 | /**************************************************************************/ | ||
150 | static void | ||
151 | stop_cards(void) | ||
152 | { | ||
153 | hysdn_card *card; | ||
154 | |||
155 | card = card_root; /* first in chain */ | ||
156 | while (card) { | ||
157 | if (card->stopcard) | ||
158 | card->stopcard(card); | ||
159 | card = card->next; /* remove card from chain */ | ||
160 | } /* while card */ | ||
161 | } /* stop_cards */ | ||
162 | |||
163 | |||
164 | /****************************************************************************/ | ||
165 | /* The module startup and shutdown code. Only compiled when used as module. */ | ||
166 | /* Using the driver as module is always advisable, because the booting */ | ||
167 | /* image becomes smaller and the driver code is only loaded when needed. */ | ||
168 | /* Additionally newer versions may be activated without rebooting. */ | ||
169 | /****************************************************************************/ | ||
170 | |||
171 | /******************************************************/ | ||
172 | /* extract revision number from string for log output */ | ||
173 | /******************************************************/ | ||
174 | char * | ||
175 | hysdn_getrev(const char *revision) | ||
176 | { | ||
177 | char *rev; | ||
178 | char *p; | ||
179 | |||
180 | if ((p = strchr(revision, ':'))) { | ||
181 | rev = p + 2; | ||
182 | p = strchr(rev, '$'); | ||
183 | *--p = 0; | ||
184 | } else | ||
185 | rev = "???"; | ||
186 | return rev; | ||
187 | } | ||
188 | |||
189 | |||
190 | /****************************************************************************/ | ||
191 | /* init_module is called once when the module is loaded to do all necessary */ | ||
192 | /* things like autodetect... */ | ||
193 | /* If the return value of this function is 0 the init has been successful */ | ||
194 | /* and the module is added to the list in /proc/modules, otherwise an error */ | ||
195 | /* is assumed and the module will not be kept in memory. */ | ||
196 | /****************************************************************************/ | ||
197 | static int __init | ||
198 | hysdn_init(void) | ||
199 | { | ||
200 | char tmp[50]; | ||
201 | |||
202 | strcpy(tmp, hysdn_init_revision); | ||
203 | printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); | ||
204 | strcpy(tmp, hysdn_net_revision); | ||
205 | printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); | ||
206 | search_cards(); | ||
207 | printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); | ||
208 | |||
209 | if (hysdn_procconf_init()) { | ||
210 | free_resources(); /* proc file_sys not created */ | ||
211 | return (-1); | ||
212 | } | ||
213 | #ifdef CONFIG_HYSDN_CAPI | ||
214 | if(cardmax > 0) { | ||
215 | if(hycapi_init()) { | ||
216 | printk(KERN_ERR "HYCAPI: init failed\n"); | ||
217 | return(-1); | ||
218 | } | ||
219 | } | ||
220 | #endif /* CONFIG_HYSDN_CAPI */ | ||
221 | return (0); /* no error */ | ||
222 | } /* init_module */ | ||
223 | |||
224 | |||
225 | /***********************************************************************/ | ||
226 | /* cleanup_module is called when the module is released by the kernel. */ | ||
227 | /* The routine is only called if init_module has been successful and */ | ||
228 | /* the module counter has a value of 0. Otherwise this function will */ | ||
229 | /* not be called. This function must release all resources still allo- */ | ||
230 | /* cated as after the return from this function the module code will */ | ||
231 | /* be removed from memory. */ | ||
232 | /***********************************************************************/ | ||
233 | static void __exit | ||
234 | hysdn_exit(void) | ||
235 | { | ||
236 | #ifdef CONFIG_HYSDN_CAPI | ||
237 | hysdn_card *card; | ||
238 | #endif /* CONFIG_HYSDN_CAPI */ | ||
239 | stop_cards(); | ||
240 | #ifdef CONFIG_HYSDN_CAPI | ||
241 | card = card_root; /* first in chain */ | ||
242 | while (card) { | ||
243 | hycapi_capi_release(card); | ||
244 | card = card->next; /* remove card from chain */ | ||
245 | } /* while card */ | ||
246 | hycapi_cleanup(); | ||
247 | #endif /* CONFIG_HYSDN_CAPI */ | ||
248 | hysdn_procconf_release(); | ||
249 | free_resources(); | ||
250 | printk(KERN_NOTICE "HYSDN: module unloaded\n"); | ||
251 | } /* cleanup_module */ | ||
252 | |||
253 | module_init(hysdn_init); | ||
254 | module_exit(hysdn_exit); | ||