ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pci / hotplug / cpci_hotplug_core.c
1 /*
2  * CompactPCI Hot Plug Driver
3  *
4  * Copyright (C) 2002 SOMA Networks, Inc.
5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6  * Copyright (C) 2001 IBM Corp.
7  *
8  * All rights reserved.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or (at
13  * your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
18  * NON INFRINGEMENT.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  * Send feedback to <scottm@somanetworks.com>
26  */
27
28 #include <linux/config.h>
29 #include <linux/module.h>
30 #include <linux/kernel.h>
31 #include <linux/slab.h>
32 #include <linux/pci.h>
33 #include <linux/init.h>
34 #include <linux/interrupt.h>
35 #include <linux/smp_lock.h>
36 #include "pci_hotplug.h"
37 #include "cpci_hotplug.h"
38
39 #define DRIVER_VERSION  "0.2"
40 #define DRIVER_AUTHOR   "Scott Murray <scottm@somanetworks.com>"
41 #define DRIVER_DESC     "CompactPCI Hot Plug Core"
42
43 #if !defined(CONFIG_HOTPLUG_CPCI_MODULE)
44 #define MY_NAME "cpci_hotplug"
45 #else
46 #define MY_NAME THIS_MODULE->name
47 #endif
48
49 #define dbg(format, arg...)                                     \
50         do {                                                    \
51                 if(cpci_debug)                                  \
52                         printk (KERN_DEBUG "%s: " format "\n",  \
53                                 MY_NAME , ## arg);              \
54         } while(0)
55 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
56 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
57 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
58
59 /* local variables */
60 static spinlock_t list_lock;
61 static LIST_HEAD(slot_list);
62 static int slots;
63 int cpci_debug;
64 static struct cpci_hp_controller *controller;
65 static struct semaphore event_semaphore;        /* mutex for process loop (up if something to process) */
66 static struct semaphore thread_exit;            /* guard ensure thread has exited before calling it quits */
67 static int thread_finished = 1;
68
69 static int enable_slot(struct hotplug_slot *slot);
70 static int disable_slot(struct hotplug_slot *slot);
71 static int set_attention_status(struct hotplug_slot *slot, u8 value);
72 static int get_power_status(struct hotplug_slot *slot, u8 * value);
73 static int get_attention_status(struct hotplug_slot *slot, u8 * value);
74 static int get_latch_status(struct hotplug_slot *slot, u8 * value);
75 static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
76
77 static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
78         .owner = THIS_MODULE,
79         .enable_slot = enable_slot,
80         .disable_slot = disable_slot,
81         .set_attention_status = set_attention_status,
82         .hardware_test = NULL,
83         .get_power_status = get_power_status,
84         .get_attention_status = get_attention_status,
85         .get_latch_status = get_latch_status,
86         .get_adapter_status = get_adapter_status,
87 };
88
89 /* Inline functions to check the sanity of a pointer that is passed to us */
90 static inline int
91 slot_paranoia_check(struct slot *slot, const char *function)
92 {
93         if(!slot) {
94                 dbg("%s - slot == NULL", function);
95                 return -1;
96         }
97         if(slot->magic != SLOT_MAGIC) {
98                 dbg("%s - bad magic number for slot", function);
99                 return -1;
100         }
101         if(!slot->hotplug_slot) {
102                 dbg("%s - slot->hotplug_slot == NULL!", function);
103                 return -1;
104         }
105         return 0;
106 }
107
108 static inline struct slot *
109 get_slot(struct hotplug_slot *hotplug_slot, const char *function)
110 {
111         struct slot *slot;
112
113         if(!hotplug_slot) {
114                 dbg("%s - hotplug_slot == NULL", function);
115                 return NULL;
116         }
117
118         slot = (struct slot *) hotplug_slot->private;
119         if(slot_paranoia_check(slot, function))
120                 return NULL;
121         return slot;
122 }
123
124 static int
125 update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
126 {
127         struct hotplug_slot_info info;
128
129         if(!(hotplug_slot && hotplug_slot->info))
130                 return -EINVAL;
131         memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
132         info.latch_status = value;
133         return pci_hp_change_slot_info(hotplug_slot, &info);
134 }
135
136 static int
137 update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
138 {
139         struct hotplug_slot_info info;
140
141         if(!(hotplug_slot && hotplug_slot->info))
142                 return -EINVAL;
143         memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
144         info.adapter_status = value;
145         return pci_hp_change_slot_info(hotplug_slot, &info);
146 }
147
148 static int
149 enable_slot(struct hotplug_slot *hotplug_slot)
150 {
151         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
152         int retval = 0;
153
154         if(slot == NULL)
155                 return -ENODEV;
156
157         dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
158
159         if(controller->ops->set_power) {
160                 retval = controller->ops->set_power(slot, 1);
161         }
162
163         return retval;
164 }
165
166 static int
167 disable_slot(struct hotplug_slot *hotplug_slot)
168 {
169         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
170         int retval = 0;
171
172         if(slot == NULL)
173                 return -ENODEV;
174
175         dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
176
177         /* Unconfigure device */
178         dbg("%s - unconfiguring slot %s",
179             __FUNCTION__, slot->hotplug_slot->name);
180         if((retval = cpci_unconfigure_slot(slot))) {
181                 err("%s - could not unconfigure slot %s",
182                     __FUNCTION__, slot->hotplug_slot->name);
183                 return retval;
184         }
185         dbg("%s - finished unconfiguring slot %s",
186             __FUNCTION__, slot->hotplug_slot->name);
187
188         /* Clear EXT (by setting it) */
189         if(cpci_clear_ext(slot)) {
190                 err("%s - could not clear EXT for slot %s",
191                     __FUNCTION__, slot->hotplug_slot->name);
192                 retval = -ENODEV;
193         }
194         cpci_led_on(slot);
195
196         if(controller->ops->set_power) {
197                 retval = controller->ops->set_power(slot, 0);
198         }
199
200         if(update_adapter_status(slot->hotplug_slot, 0)) {
201                 warn("failure to update adapter file");
202         }
203
204         slot->extracting = 0;
205
206         return retval;
207 }
208
209 static u8
210 cpci_get_power_status(struct slot *slot)
211 {
212         u8 power = 1;
213
214         if(controller->ops->get_power) {
215                 power = controller->ops->get_power(slot);
216         }
217         return power;
218 }
219
220 static int
221 get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
222 {
223         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
224
225         if(slot == NULL)
226                 return -ENODEV;
227         *value = cpci_get_power_status(slot);
228         return 0;
229 }
230
231 static int
232 get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
233 {
234         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
235
236         if(slot == NULL)
237                 return -ENODEV;
238         *value = cpci_get_attention_status(slot);
239         return 0;
240 }
241
242 static int
243 set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
244 {
245         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
246
247         if(slot == NULL)
248                 return -ENODEV;
249         switch (status) {
250         case 0:
251                 cpci_set_attention_status(slot, 0);
252                 break;
253
254         case 1:
255         default:
256                 cpci_set_attention_status(slot, 1);
257                 break;
258         }
259
260         return 0;
261 }
262
263 static int
264 get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
265 {
266         if(hotplug_slot == NULL || hotplug_slot->info == NULL)
267                 return -ENODEV;
268         *value = hotplug_slot->info->latch_status;
269         return 0;
270 }
271
272 static int
273 get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
274 {
275         if(hotplug_slot == NULL || hotplug_slot->info == NULL)
276                 return -ENODEV;
277         *value = hotplug_slot->info->adapter_status;
278         return 0;
279 }
280
281 static void release_slot(struct hotplug_slot *hotplug_slot)
282 {
283         struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
284
285         if(slot == NULL)
286                 return;
287
288         kfree(slot->hotplug_slot->info);
289         kfree(slot->hotplug_slot->name);
290         kfree(slot->hotplug_slot);
291         kfree(slot);
292 }
293
294 #define SLOT_NAME_SIZE  6
295 static void
296 make_slot_name(struct slot *slot)
297 {
298         snprintf(slot->hotplug_slot->name,
299                  SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
300 }
301
302 int
303 cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
304 {
305         struct slot *slot;
306         struct hotplug_slot *hotplug_slot;
307         struct hotplug_slot_info *info;
308         char *name;
309         int status = 0;
310         int i;
311
312         if(!(controller && bus)) {
313                 return -ENODEV;
314         }
315         if(last < first) {
316                 return -EINVAL;
317         }
318
319         /*
320          * Create a structure for each slot, and register that slot
321          * with the pci_hotplug subsystem.
322          */
323         for (i = first; i <= last; ++i) {
324                 slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
325                 if(!slot)
326                         return -ENOMEM;
327                 memset(slot, 0, sizeof (struct slot));
328
329                 hotplug_slot =
330                     kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
331                 if(!hotplug_slot) {
332                         kfree(slot);
333                         return -ENOMEM;
334                 }
335                 memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
336                 slot->hotplug_slot = hotplug_slot;
337
338                 info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
339                 if(!info) {
340                         kfree(hotplug_slot);
341                         kfree(slot);
342                         return -ENOMEM;
343                 }
344                 memset(info, 0, sizeof (struct hotplug_slot_info));
345                 hotplug_slot->info = info;
346
347                 name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
348                 if(!name) {
349                         kfree(info);
350                         kfree(hotplug_slot);
351                         kfree(slot);
352                         return -ENOMEM;
353                 }
354                 hotplug_slot->name = name;
355
356                 slot->magic = SLOT_MAGIC;
357                 slot->bus = bus;
358                 slot->number = i;
359                 slot->devfn = PCI_DEVFN(i, 0);
360
361                 hotplug_slot->private = slot;
362                 hotplug_slot->release = &release_slot;
363                 make_slot_name(slot);
364                 hotplug_slot->ops = &cpci_hotplug_slot_ops;
365
366                 /*
367                  * Initialize the slot info structure with some known
368                  * good values.
369                  */
370                 dbg("initializing slot %s", slot->hotplug_slot->name);
371                 info->power_status = cpci_get_power_status(slot);
372                 info->attention_status = cpci_get_attention_status(slot);
373
374                 dbg("registering slot %s", slot->hotplug_slot->name);
375                 status = pci_hp_register(slot->hotplug_slot);
376                 if(status) {
377                         err("pci_hp_register failed with error %d", status);
378                         kfree(info);
379                         kfree(name);
380                         kfree(hotplug_slot);
381                         kfree(slot);
382                         return status;
383                 }
384
385                 /* Add slot to our internal list */
386                 spin_lock(&list_lock);
387                 list_add(&slot->slot_list, &slot_list);
388                 slots++;
389                 spin_unlock(&list_lock);
390         }
391         return status;
392 }
393
394 int
395 cpci_hp_unregister_bus(struct pci_bus *bus)
396 {
397         struct slot *slot;
398         struct list_head *tmp;
399         struct list_head *next;
400         int status;
401
402         if(!bus) {
403                 return -ENODEV;
404         }
405
406         spin_lock(&list_lock);
407         if(!slots) {
408                 spin_unlock(&list_lock);
409                 return -1;
410         }
411         list_for_each_safe(tmp, next, &slot_list) {
412                 slot = list_entry(tmp, struct slot, slot_list);
413                 if(slot->bus == bus) {
414                         dbg("deregistering slot %s", slot->hotplug_slot->name);
415                         status = pci_hp_deregister(slot->hotplug_slot);
416                         if(status) {
417                                 err("pci_hp_deregister failed with error %d",
418                                     status);
419                                 return status;
420                         }
421
422                         list_del(&slot->slot_list);
423                         slots--;
424                 }
425         }
426         spin_unlock(&list_lock);
427         return 0;
428 }
429
430 /* This is the interrupt mode interrupt handler */
431 irqreturn_t
432 cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
433 {
434         dbg("entered cpci_hp_intr");
435
436         /* Check to see if it was our interrupt */
437         if((controller->irq_flags & SA_SHIRQ) &&
438             !controller->ops->check_irq(controller->dev_id)) {
439                 dbg("exited cpci_hp_intr, not our interrupt");
440                 return IRQ_NONE;
441         }
442
443         /* Disable ENUM interrupt */
444         controller->ops->disable_irq();
445
446         /* Trigger processing by the event thread */
447         dbg("Signal event_semaphore");
448         up(&event_semaphore);
449         dbg("exited cpci_hp_intr");
450         return IRQ_HANDLED;
451 }
452
453 /*
454  * According to PICMG 2.12 R2.0, section 6.3.2, upon
455  * initialization, the system driver shall clear the
456  * INS bits of the cold-inserted devices.
457  */
458 static int
459 init_slots(void)
460 {
461         struct slot *slot;
462         struct list_head *tmp;
463         struct pci_dev* dev;
464
465         dbg("%s - enter", __FUNCTION__);
466         spin_lock(&list_lock);
467         if(!slots) {
468                 spin_unlock(&list_lock);
469                 return -1;
470         }
471         list_for_each(tmp, &slot_list) {
472                 slot = list_entry(tmp, struct slot, slot_list);
473                 dbg("%s - looking at slot %s",
474                     __FUNCTION__, slot->hotplug_slot->name);
475                 if(cpci_check_and_clear_ins(slot)) {
476                         dbg("%s - cleared INS for slot %s",
477                             __FUNCTION__, slot->hotplug_slot->name);
478                         dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
479                         if(dev) {
480                                 if(update_adapter_status(slot->hotplug_slot, 1)) {
481                                         warn("failure to update adapter file");
482                                 }
483                                 if(update_latch_status(slot->hotplug_slot, 1)) {
484                                         warn("failure to update latch file");
485                                 }
486                                 slot->dev = dev;
487                         } else {
488                                 err("%s - no driver attached to device in slot %s",
489                                     __FUNCTION__, slot->hotplug_slot->name);
490                         }
491                 }
492         }
493         spin_unlock(&list_lock);
494         dbg("%s - exit", __FUNCTION__);
495         return 0;
496 }
497
498 static int
499 check_slots(void)
500 {
501         struct slot *slot;
502         struct list_head *tmp;
503         int extracted;
504         int inserted;
505
506         spin_lock(&list_lock);
507         if(!slots) {
508                 spin_unlock(&list_lock);
509                 err("no slots registered, shutting down");
510                 return -1;
511         }
512         extracted = inserted = 0;
513         list_for_each(tmp, &slot_list) {
514                 slot = list_entry(tmp, struct slot, slot_list);
515                 dbg("%s - looking at slot %s",
516                     __FUNCTION__, slot->hotplug_slot->name);
517                 if(cpci_check_and_clear_ins(slot)) {
518                         u16 hs_csr;
519
520                         /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
521                         if(slot->dev) {
522                                 warn("slot %s already inserted", slot->hotplug_slot->name);
523                                 inserted++;
524                                 continue;
525                         }
526
527                         /* Process insertion */
528                         dbg("%s - slot %s inserted",
529                             __FUNCTION__, slot->hotplug_slot->name);
530
531                         /* GSM, debug */
532                         hs_csr = cpci_get_hs_csr(slot);
533                         dbg("%s - slot %s HS_CSR (1) = %04x",
534                             __FUNCTION__, slot->hotplug_slot->name, hs_csr);
535
536                         /* Configure device */
537                         dbg("%s - configuring slot %s",
538                             __FUNCTION__, slot->hotplug_slot->name);
539                         if(cpci_configure_slot(slot)) {
540                                 err("%s - could not configure slot %s",
541                                     __FUNCTION__, slot->hotplug_slot->name);
542                                 continue;
543                         }
544                         dbg("%s - finished configuring slot %s",
545                             __FUNCTION__, slot->hotplug_slot->name);
546
547                         /* GSM, debug */
548                         hs_csr = cpci_get_hs_csr(slot);
549                         dbg("%s - slot %s HS_CSR (2) = %04x",
550                             __FUNCTION__, slot->hotplug_slot->name, hs_csr);
551
552                         if(update_latch_status(slot->hotplug_slot, 1)) {
553                                 warn("failure to update latch file");
554                         }
555
556                         if(update_adapter_status(slot->hotplug_slot, 1)) {
557                                 warn("failure to update adapter file");
558                         }
559
560                         cpci_led_off(slot);
561
562                         /* GSM, debug */
563                         hs_csr = cpci_get_hs_csr(slot);
564                         dbg("%s - slot %s HS_CSR (3) = %04x",
565                             __FUNCTION__, slot->hotplug_slot->name, hs_csr);
566
567                         inserted++;
568                 } else if(cpci_check_ext(slot)) {
569                         u16 hs_csr;
570
571                         /* Process extraction request */
572                         dbg("%s - slot %s extracted",
573                             __FUNCTION__, slot->hotplug_slot->name);
574
575                         /* GSM, debug */
576                         hs_csr = cpci_get_hs_csr(slot);
577                         dbg("%s - slot %s HS_CSR = %04x",
578                             __FUNCTION__, slot->hotplug_slot->name, hs_csr);
579
580                         if(!slot->extracting) {
581                                 if(update_latch_status(slot->hotplug_slot, 0)) {
582                                         warn("failure to update latch file");
583                                 }
584                                 slot->extracting = 1;
585                         }
586                         extracted++;
587                 }
588         }
589         spin_unlock(&list_lock);
590         if(inserted || extracted) {
591                 return extracted;
592         }
593         else {
594                 err("cannot find ENUM# source, shutting down");
595                 return -1;
596         }
597 }
598
599 /* This is the interrupt mode worker thread body */
600 static int
601 event_thread(void *data)
602 {
603         int rc;
604         struct slot *slot;
605         struct list_head *tmp;
606
607         lock_kernel();
608         daemonize("cpci_hp_eventd");
609         unlock_kernel();
610
611         dbg("%s - event thread started", __FUNCTION__);
612         while(1) {
613                 dbg("event thread sleeping");
614                 down_interruptible(&event_semaphore);
615                 dbg("event thread woken, thread_finished = %d",
616                     thread_finished);
617                 if(thread_finished || signal_pending(current))
618                         break;
619                 while(controller->ops->query_enum()) {
620                         rc = check_slots();
621                         if(rc > 0) {
622                                 /* Give userspace a chance to handle extraction */
623                                 set_current_state(TASK_INTERRUPTIBLE);
624                                 schedule_timeout(HZ / 2);
625                         } else if(rc < 0) {
626                                 dbg("%s - error checking slots", __FUNCTION__);
627                                 thread_finished = 1;
628                                 break;
629                         }
630                 }
631                 /* Check for someone yanking out a board */
632                 list_for_each(tmp, &slot_list) {
633                         slot = list_entry(tmp, struct slot, slot_list);
634                         if(slot->extracting) {
635                                 /*
636                                  * Hmmm, we're likely hosed at this point, should we
637                                  * bother trying to tell the driver or not?
638                                  */
639                                 err("card in slot %s was improperly removed",
640                                     slot->hotplug_slot->name);
641                                 if(update_adapter_status(slot->hotplug_slot, 0)) {
642                                         warn("failure to update adapter file");
643                                 }
644                                 slot->extracting = 0;
645                         }
646                 }
647
648                 /* Re-enable ENUM# interrupt */
649                 dbg("%s - re-enabling irq", __FUNCTION__);
650                 controller->ops->enable_irq();
651         }
652
653         dbg("%s - event thread signals exit", __FUNCTION__);
654         up(&thread_exit);
655         return 0;
656 }
657
658 /* This is the polling mode worker thread body */
659 static int
660 poll_thread(void *data)
661 {
662         int rc;
663         struct slot *slot;
664         struct list_head *tmp;
665
666         lock_kernel();
667         daemonize("cpci_hp_polld");
668         unlock_kernel();
669
670         while(1) {
671                 if(thread_finished || signal_pending(current))
672                         break;
673
674                 while(controller->ops->query_enum()) {
675                         rc = check_slots();
676                         if(rc > 0) {
677                                 /* Give userspace a chance to handle extraction */
678                                 set_current_state(TASK_INTERRUPTIBLE);
679                                 schedule_timeout(HZ / 2);
680                         } else if(rc < 0) {
681                                 dbg("%s - error checking slots", __FUNCTION__);
682                                 thread_finished = 1;
683                                 break;
684                         }
685                 }
686                 /* Check for someone yanking out a board */
687                 list_for_each(tmp, &slot_list) {
688                         slot = list_entry(tmp, struct slot, slot_list);
689                         if(slot->extracting) {
690                                 /*
691                                  * Hmmm, we're likely hosed at this point, should we
692                                  * bother trying to tell the driver or not?
693                                  */
694                                 err("card in slot %s was improperly removed",
695                                     slot->hotplug_slot->name);
696                                 if(update_adapter_status(slot->hotplug_slot, 0)) {
697                                         warn("failure to update adapter file");
698                                 }
699                                 slot->extracting = 0;
700                         }
701                 }
702
703                 set_current_state(TASK_INTERRUPTIBLE);
704                 schedule_timeout(HZ / 10);
705         }
706         dbg("poll thread signals exit");
707         up(&thread_exit);
708         return 0;
709 }
710
711 static int
712 cpci_start_thread(void)
713 {
714         int pid;
715
716         /* initialize our semaphores */
717         init_MUTEX_LOCKED(&event_semaphore);
718         init_MUTEX_LOCKED(&thread_exit);
719         thread_finished = 0;
720
721         if(controller->irq) {
722                 pid = kernel_thread(event_thread, 0, 0);
723         } else {
724                 pid = kernel_thread(poll_thread, 0, 0);
725         }
726         if(pid < 0) {
727                 err("Can't start up our thread");
728                 return -1;
729         }
730         dbg("Our thread pid = %d", pid);
731         return 0;
732 }
733
734 static void
735 cpci_stop_thread(void)
736 {
737         thread_finished = 1;
738         dbg("thread finish command given");
739         if(controller->irq) {
740                 up(&event_semaphore);
741         }
742         dbg("wait for thread to exit");
743         down(&thread_exit);
744 }
745
746 int
747 cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
748 {
749         int status = 0;
750
751         if(!controller) {
752                 controller = new_controller;
753                 if(controller->irq) {
754                         if(request_irq(controller->irq,
755                                         cpci_hp_intr,
756                                         controller->irq_flags,
757                                         MY_NAME, controller->dev_id)) {
758                                 err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
759                                 status = -ENODEV;
760                         }
761                         dbg("%s - acquired controller irq %d", __FUNCTION__,
762                             controller->irq);
763                 }
764         } else {
765                 err("cPCI hotplug controller already registered");
766                 status = -1;
767         }
768         return status;
769 }
770
771 int
772 cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
773 {
774         int status = 0;
775
776         if(controller) {
777                 if(!thread_finished) {
778                         cpci_stop_thread();
779                 }
780                 if(controller->irq) {
781                         free_irq(controller->irq, controller->dev_id);
782                 }
783                 controller = NULL;
784         } else {
785                 status = -ENODEV;
786         }
787         return status;
788 }
789
790 int
791 cpci_hp_start(void)
792 {
793         static int first = 1;
794         int status;
795
796         dbg("%s - enter", __FUNCTION__);
797         if(!controller) {
798                 return -ENODEV;
799         }
800
801         spin_lock(&list_lock);
802         if(!slots) {
803                 spin_unlock(&list_lock);
804                 return -ENODEV;
805         }
806         spin_unlock(&list_lock);
807
808         if(first) {
809                 status = init_slots();
810                 if(status) {
811                         return status;
812                 }
813                 first = 0;
814         }
815
816         status = cpci_start_thread();
817         if(status) {
818                 return status;
819         }
820         dbg("%s - thread started", __FUNCTION__);
821
822         if(controller->irq) {
823                 /* Start enum interrupt processing */
824                 dbg("%s - enabling irq", __FUNCTION__);
825                 controller->ops->enable_irq();
826         }
827         dbg("%s - exit", __FUNCTION__);
828         return 0;
829 }
830
831 int
832 cpci_hp_stop(void)
833 {
834         if(!controller) {
835                 return -ENODEV;
836         }
837
838         if(controller->irq) {
839                 /* Stop enum interrupt processing */
840                 dbg("%s - disabling irq", __FUNCTION__);
841                 controller->ops->disable_irq();
842         }
843         cpci_stop_thread();
844         return 0;
845 }
846
847 static void __exit
848 cleanup_slots(void)
849 {
850         struct list_head *tmp;
851         struct slot *slot;
852
853         /*
854          * Unregister all of our slots with the pci_hotplug subsystem,
855          * and free up all memory that we had allocated.
856          */
857         spin_lock(&list_lock);
858         if(!slots) {
859                 goto null_cleanup;
860         }
861         list_for_each(tmp, &slot_list) {
862                 slot = list_entry(tmp, struct slot, slot_list);
863                 list_del(&slot->slot_list);
864                 pci_hp_deregister(slot->hotplug_slot);
865                 kfree(slot->hotplug_slot->info);
866                 kfree(slot->hotplug_slot->name);
867                 kfree(slot->hotplug_slot);
868                 kfree(slot);
869         }
870       null_cleanup:
871         spin_unlock(&list_lock);
872         return;
873 }
874
875 int __init
876 cpci_hotplug_init(int debug)
877 {
878         spin_lock_init(&list_lock);
879         cpci_debug = debug;
880
881         info(DRIVER_DESC " version: " DRIVER_VERSION);
882         return 0;
883 }
884
885 void __exit
886 cpci_hotplug_exit(void)
887 {
888         /*
889          * Clean everything up.
890          */
891         cleanup_slots();
892 }
893
894
895 EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
896 EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
897 EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
898 EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
899 EXPORT_SYMBOL_GPL(cpci_hp_start);
900 EXPORT_SYMBOL_GPL(cpci_hp_stop);