Commit 60cc5147ae07b3b0f7592a611fa20169f7dd02cc

Authored by Jeff Garzik
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