Commit 60cc5147ae07b3b0f7592a611fa20169f7dd02cc
1 parent
782e3b3b38
[ISDN] hysdn: convert to PCI hotplug API
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Showing 1 changed file with 130 additions and 144 deletions Side-by-side Diff
drivers/isdn/hysdn/hysdn_init.c
... | ... | @@ -20,10 +20,15 @@ |
20 | 20 | #include "hysdn_defs.h" |
21 | 21 | |
22 | 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}, | |
24 | - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, | |
25 | - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, | |
26 | - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, | |
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 | + | |
27 | 32 | { } /* Terminating entry */ |
28 | 33 | }; |
29 | 34 | MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); |
30 | 35 | |
31 | 36 | |
... | ... | @@ -34,130 +39,9 @@ |
34 | 39 | static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; |
35 | 40 | static int cardmax; /* number of found cards */ |
36 | 41 | hysdn_card *card_root = NULL; /* pointer to first card */ |
42 | +static hysdn_card *card_last = NULL; /* pointer to first card */ | |
37 | 43 | |
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 | 44 | |
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 | - | |
160 | - | |
161 | 45 | /****************************************************************************/ |
162 | 46 | /* The module startup and shutdown code. Only compiled when used as module. */ |
163 | 47 | /* Using the driver as module is always advisable, because the booting */ |
164 | 48 | |
165 | 49 | |
166 | 50 | |
167 | 51 | |
168 | 52 | |
... | ... | @@ -191,31 +75,138 @@ |
191 | 75 | /* and the module is added to the list in /proc/modules, otherwise an error */ |
192 | 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 | 175 | static int __init |
195 | 176 | hysdn_init(void) |
196 | 177 | { |
197 | 178 | char tmp[50]; |
179 | + int rc; | |
198 | 180 | |
199 | 181 | strcpy(tmp, hysdn_init_revision); |
200 | 182 | printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); |
201 | 183 | strcpy(tmp, hysdn_net_revision); |
202 | 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 | 190 | printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); |
205 | 191 | |
206 | - if (hysdn_procconf_init()) { | |
207 | - free_resources(); /* proc file_sys not created */ | |
208 | - return (-1); | |
209 | - } | |
192 | + if (!hysdn_procconf_init()) | |
193 | + hysdn_have_procfs = 1; | |
194 | + | |
210 | 195 | #ifdef CONFIG_HYSDN_CAPI |
211 | 196 | if(cardmax > 0) { |
212 | 197 | if(hycapi_init()) { |
213 | 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 | 207 | #endif /* CONFIG_HYSDN_CAPI */ |
218 | - return (0); /* no error */ | |
208 | + | |
209 | + return 0; /* no error */ | |
219 | 210 | } /* init_module */ |
220 | 211 | |
221 | 212 | |
222 | 213 | |
223 | 214 | |
... | ... | @@ -230,20 +221,15 @@ |
230 | 221 | static void __exit |
231 | 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 | 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 | 230 | hycapi_cleanup(); |
244 | 231 | #endif /* CONFIG_HYSDN_CAPI */ |
245 | - hysdn_procconf_release(); | |
246 | - free_resources(); | |
232 | + | |
247 | 233 | printk(KERN_NOTICE "HYSDN: module unloaded\n"); |
248 | 234 | } /* cleanup_module */ |
249 | 235 |