cpci_hotplug_core.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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. #include <linux/config.h>
  28. #include <linux/module.h>
  29. #include <linux/kernel.h>
  30. #include <linux/slab.h>
  31. #include <linux/pci.h>
  32. #include <linux/init.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/smp_lock.h>
  35. #include <linux/delay.h>
  36. #include "pci_hotplug.h"
  37. #include "cpci_hotplug.h"
  38. #define DRIVER_VERSION "0.2"
  39. #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
  40. #define DRIVER_DESC "CompactPCI Hot Plug Core"
  41. #define MY_NAME "cpci_hotplug"
  42. #define dbg(format, arg...) \
  43. do { \
  44. if(cpci_debug) \
  45. printk (KERN_DEBUG "%s: " format "\n", \
  46. MY_NAME , ## arg); \
  47. } while(0)
  48. #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
  49. #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
  50. #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
  51. /* local variables */
  52. static spinlock_t list_lock;
  53. static LIST_HEAD(slot_list);
  54. static int slots;
  55. int cpci_debug;
  56. static struct cpci_hp_controller *controller;
  57. static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
  58. static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */
  59. static int thread_finished = 1;
  60. static int enable_slot(struct hotplug_slot *slot);
  61. static int disable_slot(struct hotplug_slot *slot);
  62. static int set_attention_status(struct hotplug_slot *slot, u8 value);
  63. static int get_power_status(struct hotplug_slot *slot, u8 * value);
  64. static int get_attention_status(struct hotplug_slot *slot, u8 * value);
  65. static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
  66. .owner = THIS_MODULE,
  67. .enable_slot = enable_slot,
  68. .disable_slot = disable_slot,
  69. .set_attention_status = set_attention_status,
  70. .get_power_status = get_power_status,
  71. .get_attention_status = get_attention_status,
  72. };
  73. static int
  74. update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
  75. {
  76. struct hotplug_slot_info info;
  77. memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
  78. info.latch_status = value;
  79. return pci_hp_change_slot_info(hotplug_slot, &info);
  80. }
  81. static int
  82. update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
  83. {
  84. struct hotplug_slot_info info;
  85. memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
  86. info.adapter_status = value;
  87. return pci_hp_change_slot_info(hotplug_slot, &info);
  88. }
  89. static int
  90. enable_slot(struct hotplug_slot *hotplug_slot)
  91. {
  92. struct slot *slot = hotplug_slot->private;
  93. int retval = 0;
  94. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  95. if(controller->ops->set_power) {
  96. retval = controller->ops->set_power(slot, 1);
  97. }
  98. return retval;
  99. }
  100. static int
  101. disable_slot(struct hotplug_slot *hotplug_slot)
  102. {
  103. struct slot *slot = hotplug_slot->private;
  104. int retval = 0;
  105. dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
  106. /* Unconfigure device */
  107. dbg("%s - unconfiguring slot %s",
  108. __FUNCTION__, slot->hotplug_slot->name);
  109. if((retval = cpci_unconfigure_slot(slot))) {
  110. err("%s - could not unconfigure slot %s",
  111. __FUNCTION__, slot->hotplug_slot->name);
  112. return retval;
  113. }
  114. dbg("%s - finished unconfiguring slot %s",
  115. __FUNCTION__, slot->hotplug_slot->name);
  116. /* Clear EXT (by setting it) */
  117. if(cpci_clear_ext(slot)) {
  118. err("%s - could not clear EXT for slot %s",
  119. __FUNCTION__, slot->hotplug_slot->name);
  120. retval = -ENODEV;
  121. }
  122. cpci_led_on(slot);
  123. if(controller->ops->set_power) {
  124. retval = controller->ops->set_power(slot, 0);
  125. }
  126. if(update_adapter_status(slot->hotplug_slot, 0)) {
  127. warn("failure to update adapter file");
  128. }
  129. slot->extracting = 0;
  130. return retval;
  131. }
  132. static u8
  133. cpci_get_power_status(struct slot *slot)
  134. {
  135. u8 power = 1;
  136. if(controller->ops->get_power) {
  137. power = controller->ops->get_power(slot);
  138. }
  139. return power;
  140. }
  141. static int
  142. get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
  143. {
  144. struct slot *slot = hotplug_slot->private;
  145. *value = cpci_get_power_status(slot);
  146. return 0;
  147. }
  148. static int
  149. get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
  150. {
  151. struct slot *slot = hotplug_slot->private;
  152. *value = cpci_get_attention_status(slot);
  153. return 0;
  154. }
  155. static int
  156. set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
  157. {
  158. return cpci_set_attention_status(hotplug_slot->private, status);
  159. }
  160. static void release_slot(struct hotplug_slot *hotplug_slot)
  161. {
  162. struct slot *slot = hotplug_slot->private;
  163. kfree(slot->hotplug_slot->info);
  164. kfree(slot->hotplug_slot->name);
  165. kfree(slot->hotplug_slot);
  166. kfree(slot);
  167. }
  168. #define SLOT_NAME_SIZE 6
  169. static void
  170. make_slot_name(struct slot *slot)
  171. {
  172. snprintf(slot->hotplug_slot->name,
  173. SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
  174. }
  175. int
  176. cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
  177. {
  178. struct slot *slot;
  179. struct hotplug_slot *hotplug_slot;
  180. struct hotplug_slot_info *info;
  181. char *name;
  182. int status = -ENOMEM;
  183. int i;
  184. if(!(controller && bus)) {
  185. return -ENODEV;
  186. }
  187. /*
  188. * Create a structure for each slot, and register that slot
  189. * with the pci_hotplug subsystem.
  190. */
  191. for (i = first; i <= last; ++i) {
  192. slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
  193. if (!slot)
  194. goto error;
  195. memset(slot, 0, sizeof (struct slot));
  196. hotplug_slot =
  197. kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
  198. if (!hotplug_slot)
  199. goto error_slot;
  200. memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
  201. slot->hotplug_slot = hotplug_slot;
  202. info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
  203. if (!info)
  204. goto error_hpslot;
  205. memset(info, 0, sizeof (struct hotplug_slot_info));
  206. hotplug_slot->info = info;
  207. name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
  208. if (!name)
  209. goto error_info;
  210. hotplug_slot->name = name;
  211. slot->bus = bus;
  212. slot->number = i;
  213. slot->devfn = PCI_DEVFN(i, 0);
  214. hotplug_slot->private = slot;
  215. hotplug_slot->release = &release_slot;
  216. make_slot_name(slot);
  217. hotplug_slot->ops = &cpci_hotplug_slot_ops;
  218. /*
  219. * Initialize the slot info structure with some known
  220. * good values.
  221. */
  222. dbg("initializing slot %s", slot->hotplug_slot->name);
  223. info->power_status = cpci_get_power_status(slot);
  224. info->attention_status = cpci_get_attention_status(slot);
  225. dbg("registering slot %s", slot->hotplug_slot->name);
  226. status = pci_hp_register(slot->hotplug_slot);
  227. if (status) {
  228. err("pci_hp_register failed with error %d", status);
  229. goto error_name;
  230. }
  231. /* Add slot to our internal list */
  232. spin_lock(&list_lock);
  233. list_add(&slot->slot_list, &slot_list);
  234. slots++;
  235. spin_unlock(&list_lock);
  236. }
  237. return 0;
  238. error_name:
  239. kfree(name);
  240. error_info:
  241. kfree(info);
  242. error_hpslot:
  243. kfree(hotplug_slot);
  244. error_slot:
  245. kfree(slot);
  246. error:
  247. return status;
  248. }
  249. int
  250. cpci_hp_unregister_bus(struct pci_bus *bus)
  251. {
  252. struct slot *slot;
  253. struct list_head *tmp;
  254. struct list_head *next;
  255. int status;
  256. spin_lock(&list_lock);
  257. if(!slots) {
  258. spin_unlock(&list_lock);
  259. return -1;
  260. }
  261. list_for_each_safe(tmp, next, &slot_list) {
  262. slot = list_entry(tmp, struct slot, slot_list);
  263. if(slot->bus == bus) {
  264. dbg("deregistering slot %s", slot->hotplug_slot->name);
  265. status = pci_hp_deregister(slot->hotplug_slot);
  266. if(status) {
  267. err("pci_hp_deregister failed with error %d",
  268. status);
  269. return status;
  270. }
  271. list_del(&slot->slot_list);
  272. slots--;
  273. }
  274. }
  275. spin_unlock(&list_lock);
  276. return 0;
  277. }
  278. /* This is the interrupt mode interrupt handler */
  279. static irqreturn_t
  280. cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
  281. {
  282. dbg("entered cpci_hp_intr");
  283. /* Check to see if it was our interrupt */
  284. if((controller->irq_flags & SA_SHIRQ) &&
  285. !controller->ops->check_irq(controller->dev_id)) {
  286. dbg("exited cpci_hp_intr, not our interrupt");
  287. return IRQ_NONE;
  288. }
  289. /* Disable ENUM interrupt */
  290. controller->ops->disable_irq();
  291. /* Trigger processing by the event thread */
  292. dbg("Signal event_semaphore");
  293. up(&event_semaphore);
  294. dbg("exited cpci_hp_intr");
  295. return IRQ_HANDLED;
  296. }
  297. /*
  298. * According to PICMG 2.12 R2.0, section 6.3.2, upon
  299. * initialization, the system driver shall clear the
  300. * INS bits of the cold-inserted devices.
  301. */
  302. static int
  303. init_slots(void)
  304. {
  305. struct slot *slot;
  306. struct list_head *tmp;
  307. struct pci_dev* dev;
  308. dbg("%s - enter", __FUNCTION__);
  309. spin_lock(&list_lock);
  310. if(!slots) {
  311. spin_unlock(&list_lock);
  312. return -1;
  313. }
  314. list_for_each(tmp, &slot_list) {
  315. slot = list_entry(tmp, struct slot, slot_list);
  316. dbg("%s - looking at slot %s",
  317. __FUNCTION__, slot->hotplug_slot->name);
  318. if(cpci_check_and_clear_ins(slot)) {
  319. dbg("%s - cleared INS for slot %s",
  320. __FUNCTION__, slot->hotplug_slot->name);
  321. dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
  322. if(dev) {
  323. if(update_adapter_status(slot->hotplug_slot, 1)) {
  324. warn("failure to update adapter file");
  325. }
  326. if(update_latch_status(slot->hotplug_slot, 1)) {
  327. warn("failure to update latch file");
  328. }
  329. slot->dev = dev;
  330. } else {
  331. err("%s - no driver attached to device in slot %s",
  332. __FUNCTION__, slot->hotplug_slot->name);
  333. }
  334. }
  335. }
  336. spin_unlock(&list_lock);
  337. dbg("%s - exit", __FUNCTION__);
  338. return 0;
  339. }
  340. static int
  341. check_slots(void)
  342. {
  343. struct slot *slot;
  344. struct list_head *tmp;
  345. int extracted;
  346. int inserted;
  347. spin_lock(&list_lock);
  348. if(!slots) {
  349. spin_unlock(&list_lock);
  350. err("no slots registered, shutting down");
  351. return -1;
  352. }
  353. extracted = inserted = 0;
  354. list_for_each(tmp, &slot_list) {
  355. slot = list_entry(tmp, struct slot, slot_list);
  356. dbg("%s - looking at slot %s",
  357. __FUNCTION__, slot->hotplug_slot->name);
  358. if(cpci_check_and_clear_ins(slot)) {
  359. u16 hs_csr;
  360. /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
  361. if(slot->dev) {
  362. warn("slot %s already inserted", slot->hotplug_slot->name);
  363. inserted++;
  364. continue;
  365. }
  366. /* Process insertion */
  367. dbg("%s - slot %s inserted",
  368. __FUNCTION__, slot->hotplug_slot->name);
  369. /* GSM, debug */
  370. hs_csr = cpci_get_hs_csr(slot);
  371. dbg("%s - slot %s HS_CSR (1) = %04x",
  372. __FUNCTION__, slot->hotplug_slot->name, hs_csr);
  373. /* Configure device */
  374. dbg("%s - configuring slot %s",
  375. __FUNCTION__, slot->hotplug_slot->name);
  376. if(cpci_configure_slot(slot)) {
  377. err("%s - could not configure slot %s",
  378. __FUNCTION__, slot->hotplug_slot->name);
  379. continue;
  380. }
  381. dbg("%s - finished configuring slot %s",
  382. __FUNCTION__, slot->hotplug_slot->name);
  383. /* GSM, debug */
  384. hs_csr = cpci_get_hs_csr(slot);
  385. dbg("%s - slot %s HS_CSR (2) = %04x",
  386. __FUNCTION__, slot->hotplug_slot->name, hs_csr);
  387. if(update_latch_status(slot->hotplug_slot, 1)) {
  388. warn("failure to update latch file");
  389. }
  390. if(update_adapter_status(slot->hotplug_slot, 1)) {
  391. warn("failure to update adapter file");
  392. }
  393. cpci_led_off(slot);
  394. /* GSM, debug */
  395. hs_csr = cpci_get_hs_csr(slot);
  396. dbg("%s - slot %s HS_CSR (3) = %04x",
  397. __FUNCTION__, slot->hotplug_slot->name, hs_csr);
  398. inserted++;
  399. } else if(cpci_check_ext(slot)) {
  400. u16 hs_csr;
  401. /* Process extraction request */
  402. dbg("%s - slot %s extracted",
  403. __FUNCTION__, slot->hotplug_slot->name);
  404. /* GSM, debug */
  405. hs_csr = cpci_get_hs_csr(slot);
  406. dbg("%s - slot %s HS_CSR = %04x",
  407. __FUNCTION__, slot->hotplug_slot->name, hs_csr);
  408. if(!slot->extracting) {
  409. if(update_latch_status(slot->hotplug_slot, 0)) {
  410. warn("failure to update latch file");
  411. }
  412. slot->extracting = 1;
  413. }
  414. extracted++;
  415. }
  416. }
  417. spin_unlock(&list_lock);
  418. if(inserted || extracted) {
  419. return extracted;
  420. }
  421. else {
  422. err("cannot find ENUM# source, shutting down");
  423. return -1;
  424. }
  425. }
  426. /* This is the interrupt mode worker thread body */
  427. static int
  428. event_thread(void *data)
  429. {
  430. int rc;
  431. struct slot *slot;
  432. struct list_head *tmp;
  433. lock_kernel();
  434. daemonize("cpci_hp_eventd");
  435. unlock_kernel();
  436. dbg("%s - event thread started", __FUNCTION__);
  437. while(1) {
  438. dbg("event thread sleeping");
  439. down_interruptible(&event_semaphore);
  440. dbg("event thread woken, thread_finished = %d",
  441. thread_finished);
  442. if(thread_finished || signal_pending(current))
  443. break;
  444. while(controller->ops->query_enum()) {
  445. rc = check_slots();
  446. if (rc > 0)
  447. /* Give userspace a chance to handle extraction */
  448. msleep(500);
  449. else if (rc < 0) {
  450. dbg("%s - error checking slots", __FUNCTION__);
  451. thread_finished = 1;
  452. break;
  453. }
  454. }
  455. /* Check for someone yanking out a board */
  456. list_for_each(tmp, &slot_list) {
  457. slot = list_entry(tmp, struct slot, slot_list);
  458. if(slot->extracting) {
  459. /*
  460. * Hmmm, we're likely hosed at this point, should we
  461. * bother trying to tell the driver or not?
  462. */
  463. err("card in slot %s was improperly removed",
  464. slot->hotplug_slot->name);
  465. if(update_adapter_status(slot->hotplug_slot, 0)) {
  466. warn("failure to update adapter file");
  467. }
  468. slot->extracting = 0;
  469. }
  470. }
  471. /* Re-enable ENUM# interrupt */
  472. dbg("%s - re-enabling irq", __FUNCTION__);
  473. controller->ops->enable_irq();
  474. }
  475. dbg("%s - event thread signals exit", __FUNCTION__);
  476. up(&thread_exit);
  477. return 0;
  478. }
  479. /* This is the polling mode worker thread body */
  480. static int
  481. poll_thread(void *data)
  482. {
  483. int rc;
  484. struct slot *slot;
  485. struct list_head *tmp;
  486. lock_kernel();
  487. daemonize("cpci_hp_polld");
  488. unlock_kernel();
  489. while(1) {
  490. if(thread_finished || signal_pending(current))
  491. break;
  492. while(controller->ops->query_enum()) {
  493. rc = check_slots();
  494. if(rc > 0)
  495. /* Give userspace a chance to handle extraction */
  496. msleep(500);
  497. else if (rc < 0) {
  498. dbg("%s - error checking slots", __FUNCTION__);
  499. thread_finished = 1;
  500. break;
  501. }
  502. }
  503. /* Check for someone yanking out a board */
  504. list_for_each(tmp, &slot_list) {
  505. slot = list_entry(tmp, struct slot, slot_list);
  506. if(slot->extracting) {
  507. /*
  508. * Hmmm, we're likely hosed at this point, should we
  509. * bother trying to tell the driver or not?
  510. */
  511. err("card in slot %s was improperly removed",
  512. slot->hotplug_slot->name);
  513. if(update_adapter_status(slot->hotplug_slot, 0)) {
  514. warn("failure to update adapter file");
  515. }
  516. slot->extracting = 0;
  517. }
  518. }
  519. msleep(100);
  520. }
  521. dbg("poll thread signals exit");
  522. up(&thread_exit);
  523. return 0;
  524. }
  525. static int
  526. cpci_start_thread(void)
  527. {
  528. int pid;
  529. /* initialize our semaphores */
  530. init_MUTEX_LOCKED(&event_semaphore);
  531. init_MUTEX_LOCKED(&thread_exit);
  532. thread_finished = 0;
  533. if(controller->irq) {
  534. pid = kernel_thread(event_thread, NULL, 0);
  535. } else {
  536. pid = kernel_thread(poll_thread, NULL, 0);
  537. }
  538. if(pid < 0) {
  539. err("Can't start up our thread");
  540. return -1;
  541. }
  542. dbg("Our thread pid = %d", pid);
  543. return 0;
  544. }
  545. static void
  546. cpci_stop_thread(void)
  547. {
  548. thread_finished = 1;
  549. dbg("thread finish command given");
  550. if(controller->irq) {
  551. up(&event_semaphore);
  552. }
  553. dbg("wait for thread to exit");
  554. down(&thread_exit);
  555. }
  556. int
  557. cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
  558. {
  559. int status = 0;
  560. if(!controller) {
  561. controller = new_controller;
  562. if(controller->irq) {
  563. if(request_irq(controller->irq,
  564. cpci_hp_intr,
  565. controller->irq_flags,
  566. MY_NAME, controller->dev_id)) {
  567. err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
  568. status = -ENODEV;
  569. }
  570. dbg("%s - acquired controller irq %d", __FUNCTION__,
  571. controller->irq);
  572. }
  573. } else {
  574. err("cPCI hotplug controller already registered");
  575. status = -1;
  576. }
  577. return status;
  578. }
  579. int
  580. cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
  581. {
  582. int status = 0;
  583. if(controller) {
  584. if(!thread_finished) {
  585. cpci_stop_thread();
  586. }
  587. if(controller->irq) {
  588. free_irq(controller->irq, controller->dev_id);
  589. }
  590. controller = NULL;
  591. } else {
  592. status = -ENODEV;
  593. }
  594. return status;
  595. }
  596. int
  597. cpci_hp_start(void)
  598. {
  599. static int first = 1;
  600. int status;
  601. dbg("%s - enter", __FUNCTION__);
  602. if(!controller) {
  603. return -ENODEV;
  604. }
  605. spin_lock(&list_lock);
  606. if(!slots) {
  607. spin_unlock(&list_lock);
  608. return -ENODEV;
  609. }
  610. spin_unlock(&list_lock);
  611. if(first) {
  612. status = init_slots();
  613. if(status) {
  614. return status;
  615. }
  616. first = 0;
  617. }
  618. status = cpci_start_thread();
  619. if(status) {
  620. return status;
  621. }
  622. dbg("%s - thread started", __FUNCTION__);
  623. if(controller->irq) {
  624. /* Start enum interrupt processing */
  625. dbg("%s - enabling irq", __FUNCTION__);
  626. controller->ops->enable_irq();
  627. }
  628. dbg("%s - exit", __FUNCTION__);
  629. return 0;
  630. }
  631. int
  632. cpci_hp_stop(void)
  633. {
  634. if(!controller) {
  635. return -ENODEV;
  636. }
  637. if(controller->irq) {
  638. /* Stop enum interrupt processing */
  639. dbg("%s - disabling irq", __FUNCTION__);
  640. controller->ops->disable_irq();
  641. }
  642. cpci_stop_thread();
  643. return 0;
  644. }
  645. static void __exit
  646. cleanup_slots(void)
  647. {
  648. struct list_head *tmp;
  649. struct slot *slot;
  650. /*
  651. * Unregister all of our slots with the pci_hotplug subsystem,
  652. * and free up all memory that we had allocated.
  653. */
  654. spin_lock(&list_lock);
  655. if(!slots) {
  656. goto null_cleanup;
  657. }
  658. list_for_each(tmp, &slot_list) {
  659. slot = list_entry(tmp, struct slot, slot_list);
  660. list_del(&slot->slot_list);
  661. pci_hp_deregister(slot->hotplug_slot);
  662. kfree(slot->hotplug_slot->info);
  663. kfree(slot->hotplug_slot->name);
  664. kfree(slot->hotplug_slot);
  665. kfree(slot);
  666. }
  667. null_cleanup:
  668. spin_unlock(&list_lock);
  669. return;
  670. }
  671. int __init
  672. cpci_hotplug_init(int debug)
  673. {
  674. spin_lock_init(&list_lock);
  675. cpci_debug = debug;
  676. info(DRIVER_DESC " version: " DRIVER_VERSION);
  677. return 0;
  678. }
  679. void __exit
  680. cpci_hotplug_exit(void)
  681. {
  682. /*
  683. * Clean everything up.
  684. */
  685. cleanup_slots();
  686. }
  687. EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
  688. EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
  689. EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
  690. EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
  691. EXPORT_SYMBOL_GPL(cpci_hp_start);
  692. EXPORT_SYMBOL_GPL(cpci_hp_stop);