g_NCR5380.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. * Generic Generic NCR5380 driver
  3. *
  4. * Copyright 1993, Drew Eckhardt
  5. * Visionary Computing
  6. * (Unix and Linux consulting and custom programming)
  7. * drew@colorado.edu
  8. * +1 (303) 440-4894
  9. *
  10. * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
  11. * K.Lentin@cs.monash.edu.au
  12. *
  13. * NCR53C400A extensions (c) 1996, Ingmar Baumgart
  14. * ingmar@gonzo.schwaben.de
  15. *
  16. * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg
  17. * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl
  18. *
  19. * Added ISAPNP support for DTC436 adapters,
  20. * Thomas Sailer, sailer@ife.ee.ethz.ch
  21. *
  22. * See Documentation/scsi/g_NCR5380.txt for more info.
  23. */
  24. #include <asm/io.h>
  25. #include <linux/blkdev.h>
  26. #include <linux/module.h>
  27. #include <scsi/scsi_host.h>
  28. #include "g_NCR5380.h"
  29. #include "NCR5380.h"
  30. #include <linux/init.h>
  31. #include <linux/ioport.h>
  32. #include <linux/isa.h>
  33. #include <linux/pnp.h>
  34. #include <linux/interrupt.h>
  35. #define MAX_CARDS 8
  36. /* old-style parameters for compatibility */
  37. static int ncr_irq;
  38. static int ncr_addr;
  39. static int ncr_5380;
  40. static int ncr_53c400;
  41. static int ncr_53c400a;
  42. static int dtc_3181e;
  43. static int hp_c2502;
  44. module_param(ncr_irq, int, 0);
  45. module_param(ncr_addr, int, 0);
  46. module_param(ncr_5380, int, 0);
  47. module_param(ncr_53c400, int, 0);
  48. module_param(ncr_53c400a, int, 0);
  49. module_param(dtc_3181e, int, 0);
  50. module_param(hp_c2502, int, 0);
  51. static int irq[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  52. module_param_array(irq, int, NULL, 0);
  53. MODULE_PARM_DESC(irq, "IRQ number(s)");
  54. static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  55. module_param_array(base, int, NULL, 0);
  56. MODULE_PARM_DESC(base, "base address(es)");
  57. static int card[] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  58. module_param_array(card, int, NULL, 0);
  59. MODULE_PARM_DESC(card, "card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC3181E, 4=HP C2502)");
  60. MODULE_LICENSE("GPL");
  61. #ifndef SCSI_G_NCR5380_MEM
  62. /*
  63. * Configure I/O address of 53C400A or DTC436 by writing magic numbers
  64. * to ports 0x779 and 0x379.
  65. */
  66. static void magic_configure(int idx, u8 irq, u8 magic[])
  67. {
  68. u8 cfg = 0;
  69. outb(magic[0], 0x779);
  70. outb(magic[1], 0x379);
  71. outb(magic[2], 0x379);
  72. outb(magic[3], 0x379);
  73. outb(magic[4], 0x379);
  74. /* allowed IRQs for HP C2502 */
  75. if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
  76. irq = 0;
  77. if (idx >= 0 && idx <= 7)
  78. cfg = 0x80 | idx | (irq << 4);
  79. outb(cfg, 0x379);
  80. }
  81. #endif
  82. static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
  83. struct device *pdev, int base, int irq, int board)
  84. {
  85. unsigned int *ports;
  86. u8 *magic = NULL;
  87. #ifndef SCSI_G_NCR5380_MEM
  88. int i;
  89. int port_idx = -1;
  90. unsigned long region_size;
  91. #endif
  92. static unsigned int ncr_53c400a_ports[] = {
  93. 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
  94. };
  95. static unsigned int dtc_3181e_ports[] = {
  96. 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
  97. };
  98. static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */
  99. 0x59, 0xb9, 0xc5, 0xae, 0xa6
  100. };
  101. static u8 hp_c2502_magic[] = { /* HP C2502 */
  102. 0x0f, 0x22, 0xf0, 0x20, 0x80
  103. };
  104. int flags, ret;
  105. struct Scsi_Host *instance;
  106. struct NCR5380_hostdata *hostdata;
  107. #ifdef SCSI_G_NCR5380_MEM
  108. void __iomem *iomem;
  109. resource_size_t iomem_size;
  110. #endif
  111. ports = NULL;
  112. flags = 0;
  113. switch (board) {
  114. case BOARD_NCR5380:
  115. flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP;
  116. break;
  117. case BOARD_NCR53C400A:
  118. ports = ncr_53c400a_ports;
  119. magic = ncr_53c400a_magic;
  120. break;
  121. case BOARD_HP_C2502:
  122. ports = ncr_53c400a_ports;
  123. magic = hp_c2502_magic;
  124. break;
  125. case BOARD_DTC3181E:
  126. ports = dtc_3181e_ports;
  127. magic = ncr_53c400a_magic;
  128. break;
  129. }
  130. #ifndef SCSI_G_NCR5380_MEM
  131. if (ports && magic) {
  132. /* wakeup sequence for the NCR53C400A and DTC3181E */
  133. /* Disable the adapter and look for a free io port */
  134. magic_configure(-1, 0, magic);
  135. region_size = 16;
  136. if (base)
  137. for (i = 0; ports[i]; i++) {
  138. if (base == ports[i]) { /* index found */
  139. if (!request_region(ports[i],
  140. region_size,
  141. "ncr53c80"))
  142. return -EBUSY;
  143. break;
  144. }
  145. }
  146. else
  147. for (i = 0; ports[i]; i++) {
  148. if (!request_region(ports[i], region_size,
  149. "ncr53c80"))
  150. continue;
  151. if (inb(ports[i]) == 0xff)
  152. break;
  153. release_region(ports[i], region_size);
  154. }
  155. if (ports[i]) {
  156. /* At this point we have our region reserved */
  157. magic_configure(i, 0, magic); /* no IRQ yet */
  158. base = ports[i];
  159. outb(0xc0, base + 9);
  160. if (inb(base + 9) != 0x80) {
  161. ret = -ENODEV;
  162. goto out_release;
  163. }
  164. port_idx = i;
  165. } else
  166. return -EINVAL;
  167. }
  168. else
  169. {
  170. /* NCR5380 - no configuration, just grab */
  171. region_size = 8;
  172. if (!base || !request_region(base, region_size, "ncr5380"))
  173. return -EBUSY;
  174. }
  175. #else
  176. iomem_size = NCR53C400_region_size;
  177. if (!request_mem_region(base, iomem_size, "ncr5380"))
  178. return -EBUSY;
  179. iomem = ioremap(base, iomem_size);
  180. if (!iomem) {
  181. release_mem_region(base, iomem_size);
  182. return -ENOMEM;
  183. }
  184. #endif
  185. instance = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
  186. if (instance == NULL) {
  187. ret = -ENOMEM;
  188. goto out_release;
  189. }
  190. hostdata = shost_priv(instance);
  191. #ifndef SCSI_G_NCR5380_MEM
  192. instance->io_port = base;
  193. instance->n_io_port = region_size;
  194. hostdata->io_width = 1; /* 8-bit PDMA by default */
  195. /*
  196. * On NCR53C400 boards, NCR5380 registers are mapped 8 past
  197. * the base address.
  198. */
  199. switch (board) {
  200. case BOARD_NCR53C400:
  201. instance->io_port += 8;
  202. hostdata->c400_ctl_status = 0;
  203. hostdata->c400_blk_cnt = 1;
  204. hostdata->c400_host_buf = 4;
  205. break;
  206. case BOARD_DTC3181E:
  207. hostdata->io_width = 2; /* 16-bit PDMA */
  208. /* fall through */
  209. case BOARD_NCR53C400A:
  210. case BOARD_HP_C2502:
  211. hostdata->c400_ctl_status = 9;
  212. hostdata->c400_blk_cnt = 10;
  213. hostdata->c400_host_buf = 8;
  214. break;
  215. }
  216. #else
  217. instance->base = base;
  218. hostdata->iomem = iomem;
  219. hostdata->iomem_size = iomem_size;
  220. switch (board) {
  221. case BOARD_NCR53C400:
  222. hostdata->c400_ctl_status = 0x100;
  223. hostdata->c400_blk_cnt = 0x101;
  224. hostdata->c400_host_buf = 0x104;
  225. break;
  226. case BOARD_DTC3181E:
  227. case BOARD_NCR53C400A:
  228. case BOARD_HP_C2502:
  229. pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
  230. ret = -EINVAL;
  231. goto out_unregister;
  232. }
  233. #endif
  234. ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP);
  235. if (ret)
  236. goto out_unregister;
  237. switch (board) {
  238. case BOARD_NCR53C400:
  239. case BOARD_DTC3181E:
  240. case BOARD_NCR53C400A:
  241. case BOARD_HP_C2502:
  242. NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
  243. }
  244. NCR5380_maybe_reset_bus(instance);
  245. if (irq != IRQ_AUTO)
  246. instance->irq = irq;
  247. else
  248. instance->irq = NCR5380_probe_irq(instance, 0xffff);
  249. /* Compatibility with documented NCR5380 kernel parameters */
  250. if (instance->irq == 255)
  251. instance->irq = NO_IRQ;
  252. if (instance->irq != NO_IRQ) {
  253. #ifndef SCSI_G_NCR5380_MEM
  254. /* set IRQ for HP C2502 */
  255. if (board == BOARD_HP_C2502)
  256. magic_configure(port_idx, instance->irq, magic);
  257. #endif
  258. if (request_irq(instance->irq, generic_NCR5380_intr,
  259. 0, "NCR5380", instance)) {
  260. printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
  261. instance->irq = NO_IRQ;
  262. }
  263. }
  264. if (instance->irq == NO_IRQ) {
  265. printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
  266. printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
  267. }
  268. ret = scsi_add_host(instance, pdev);
  269. if (ret)
  270. goto out_free_irq;
  271. scsi_scan_host(instance);
  272. dev_set_drvdata(pdev, instance);
  273. return 0;
  274. out_free_irq:
  275. if (instance->irq != NO_IRQ)
  276. free_irq(instance->irq, instance);
  277. NCR5380_exit(instance);
  278. out_unregister:
  279. scsi_host_put(instance);
  280. out_release:
  281. #ifndef SCSI_G_NCR5380_MEM
  282. release_region(base, region_size);
  283. #else
  284. iounmap(iomem);
  285. release_mem_region(base, iomem_size);
  286. #endif
  287. return ret;
  288. }
  289. static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
  290. {
  291. scsi_remove_host(instance);
  292. if (instance->irq != NO_IRQ)
  293. free_irq(instance->irq, instance);
  294. NCR5380_exit(instance);
  295. #ifndef SCSI_G_NCR5380_MEM
  296. release_region(instance->io_port, instance->n_io_port);
  297. #else
  298. {
  299. struct NCR5380_hostdata *hostdata = shost_priv(instance);
  300. iounmap(hostdata->iomem);
  301. release_mem_region(instance->base, hostdata->iomem_size);
  302. }
  303. #endif
  304. scsi_host_put(instance);
  305. }
  306. /**
  307. * generic_NCR5380_pread - pseudo DMA read
  308. * @instance: adapter to read from
  309. * @dst: buffer to read into
  310. * @len: buffer length
  311. *
  312. * Perform a pseudo DMA mode read from an NCR53C400 or equivalent
  313. * controller
  314. */
  315. static inline int generic_NCR5380_pread(struct Scsi_Host *instance,
  316. unsigned char *dst, int len)
  317. {
  318. struct NCR5380_hostdata *hostdata = shost_priv(instance);
  319. int blocks = len / 128;
  320. int start = 0;
  321. NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
  322. NCR5380_write(hostdata->c400_blk_cnt, blocks);
  323. while (1) {
  324. if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
  325. break;
  326. if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
  327. printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
  328. return -1;
  329. }
  330. while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
  331. ; /* FIXME - no timeout */
  332. #ifndef SCSI_G_NCR5380_MEM
  333. if (hostdata->io_width == 2)
  334. insw(instance->io_port + hostdata->c400_host_buf,
  335. dst + start, 64);
  336. else
  337. insb(instance->io_port + hostdata->c400_host_buf,
  338. dst + start, 128);
  339. #else
  340. /* implies SCSI_G_NCR5380_MEM */
  341. memcpy_fromio(dst + start,
  342. hostdata->iomem + NCR53C400_host_buffer, 128);
  343. #endif
  344. start += 128;
  345. blocks--;
  346. }
  347. if (blocks) {
  348. while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
  349. ; /* FIXME - no timeout */
  350. #ifndef SCSI_G_NCR5380_MEM
  351. if (hostdata->io_width == 2)
  352. insw(instance->io_port + hostdata->c400_host_buf,
  353. dst + start, 64);
  354. else
  355. insb(instance->io_port + hostdata->c400_host_buf,
  356. dst + start, 128);
  357. #else
  358. /* implies SCSI_G_NCR5380_MEM */
  359. memcpy_fromio(dst + start,
  360. hostdata->iomem + NCR53C400_host_buffer, 128);
  361. #endif
  362. start += 128;
  363. blocks--;
  364. }
  365. if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
  366. printk("53C400r: no 53C80 gated irq after transfer");
  367. /* wait for 53C80 registers to be available */
  368. while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
  369. ;
  370. if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
  371. printk(KERN_ERR "53C400r: no end dma signal\n");
  372. return 0;
  373. }
  374. /**
  375. * generic_NCR5380_pwrite - pseudo DMA write
  376. * @instance: adapter to read from
  377. * @dst: buffer to read into
  378. * @len: buffer length
  379. *
  380. * Perform a pseudo DMA mode read from an NCR53C400 or equivalent
  381. * controller
  382. */
  383. static inline int generic_NCR5380_pwrite(struct Scsi_Host *instance,
  384. unsigned char *src, int len)
  385. {
  386. struct NCR5380_hostdata *hostdata = shost_priv(instance);
  387. int blocks = len / 128;
  388. int start = 0;
  389. NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
  390. NCR5380_write(hostdata->c400_blk_cnt, blocks);
  391. while (1) {
  392. if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
  393. printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
  394. return -1;
  395. }
  396. if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
  397. break;
  398. while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
  399. ; // FIXME - timeout
  400. #ifndef SCSI_G_NCR5380_MEM
  401. if (hostdata->io_width == 2)
  402. outsw(instance->io_port + hostdata->c400_host_buf,
  403. src + start, 64);
  404. else
  405. outsb(instance->io_port + hostdata->c400_host_buf,
  406. src + start, 128);
  407. #else
  408. /* implies SCSI_G_NCR5380_MEM */
  409. memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
  410. src + start, 128);
  411. #endif
  412. start += 128;
  413. blocks--;
  414. }
  415. if (blocks) {
  416. while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
  417. ; // FIXME - no timeout
  418. #ifndef SCSI_G_NCR5380_MEM
  419. if (hostdata->io_width == 2)
  420. outsw(instance->io_port + hostdata->c400_host_buf,
  421. src + start, 64);
  422. else
  423. outsb(instance->io_port + hostdata->c400_host_buf,
  424. src + start, 128);
  425. #else
  426. /* implies SCSI_G_NCR5380_MEM */
  427. memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
  428. src + start, 128);
  429. #endif
  430. start += 128;
  431. blocks--;
  432. }
  433. /* wait for 53C80 registers to be available */
  434. while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
  435. udelay(4); /* DTC436 chip hangs without this */
  436. /* FIXME - no timeout */
  437. }
  438. if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
  439. printk(KERN_ERR "53C400w: no end dma signal\n");
  440. }
  441. while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
  442. ; // TIMEOUT
  443. return 0;
  444. }
  445. static int generic_NCR5380_dma_xfer_len(struct Scsi_Host *instance,
  446. struct scsi_cmnd *cmd)
  447. {
  448. struct NCR5380_hostdata *hostdata = shost_priv(instance);
  449. int transfersize = cmd->transfersize;
  450. if (hostdata->flags & FLAG_NO_PSEUDO_DMA)
  451. return 0;
  452. /* Limit transfers to 32K, for xx400 & xx406
  453. * pseudoDMA that transfers in 128 bytes blocks.
  454. */
  455. if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
  456. !(cmd->SCp.this_residual % transfersize))
  457. transfersize = 32 * 1024;
  458. /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
  459. if (transfersize % 128)
  460. transfersize = 0;
  461. return transfersize;
  462. }
  463. /*
  464. * Include the NCR5380 core code that we build our driver around
  465. */
  466. #include "NCR5380.c"
  467. static struct scsi_host_template driver_template = {
  468. .module = THIS_MODULE,
  469. .proc_name = DRV_MODULE_NAME,
  470. .name = "Generic NCR5380/NCR53C400 SCSI",
  471. .info = generic_NCR5380_info,
  472. .queuecommand = generic_NCR5380_queue_command,
  473. .eh_abort_handler = generic_NCR5380_abort,
  474. .eh_bus_reset_handler = generic_NCR5380_bus_reset,
  475. .can_queue = 16,
  476. .this_id = 7,
  477. .sg_tablesize = SG_ALL,
  478. .cmd_per_lun = 2,
  479. .use_clustering = DISABLE_CLUSTERING,
  480. .cmd_size = NCR5380_CMD_SIZE,
  481. .max_sectors = 128,
  482. };
  483. static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev)
  484. {
  485. int ret = generic_NCR5380_init_one(&driver_template, pdev, base[ndev],
  486. irq[ndev], card[ndev]);
  487. if (ret) {
  488. if (base[ndev])
  489. printk(KERN_WARNING "Card not found at address 0x%03x\n",
  490. base[ndev]);
  491. return 0;
  492. }
  493. return 1;
  494. }
  495. static int generic_NCR5380_isa_remove(struct device *pdev,
  496. unsigned int ndev)
  497. {
  498. generic_NCR5380_release_resources(dev_get_drvdata(pdev));
  499. dev_set_drvdata(pdev, NULL);
  500. return 0;
  501. }
  502. static struct isa_driver generic_NCR5380_isa_driver = {
  503. .match = generic_NCR5380_isa_match,
  504. .remove = generic_NCR5380_isa_remove,
  505. .driver = {
  506. .name = DRV_MODULE_NAME
  507. },
  508. };
  509. #if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP)
  510. static struct pnp_device_id generic_NCR5380_pnp_ids[] = {
  511. { .id = "DTC436e", .driver_data = BOARD_DTC3181E },
  512. { .id = "" }
  513. };
  514. MODULE_DEVICE_TABLE(pnp, generic_NCR5380_pnp_ids);
  515. static int generic_NCR5380_pnp_probe(struct pnp_dev *pdev,
  516. const struct pnp_device_id *id)
  517. {
  518. int base, irq;
  519. if (pnp_activate_dev(pdev) < 0)
  520. return -EBUSY;
  521. base = pnp_port_start(pdev, 0);
  522. irq = pnp_irq(pdev, 0);
  523. return generic_NCR5380_init_one(&driver_template, &pdev->dev, base, irq,
  524. id->driver_data);
  525. }
  526. static void generic_NCR5380_pnp_remove(struct pnp_dev *pdev)
  527. {
  528. generic_NCR5380_release_resources(pnp_get_drvdata(pdev));
  529. pnp_set_drvdata(pdev, NULL);
  530. }
  531. static struct pnp_driver generic_NCR5380_pnp_driver = {
  532. .name = DRV_MODULE_NAME,
  533. .id_table = generic_NCR5380_pnp_ids,
  534. .probe = generic_NCR5380_pnp_probe,
  535. .remove = generic_NCR5380_pnp_remove,
  536. };
  537. #endif /* !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP) */
  538. static int pnp_registered, isa_registered;
  539. static int __init generic_NCR5380_init(void)
  540. {
  541. int ret = 0;
  542. /* compatibility with old-style parameters */
  543. if (irq[0] == 0 && base[0] == 0 && card[0] == -1) {
  544. irq[0] = ncr_irq;
  545. base[0] = ncr_addr;
  546. if (ncr_5380)
  547. card[0] = BOARD_NCR5380;
  548. if (ncr_53c400)
  549. card[0] = BOARD_NCR53C400;
  550. if (ncr_53c400a)
  551. card[0] = BOARD_NCR53C400A;
  552. if (dtc_3181e)
  553. card[0] = BOARD_DTC3181E;
  554. if (hp_c2502)
  555. card[0] = BOARD_HP_C2502;
  556. }
  557. #if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP)
  558. if (!pnp_register_driver(&generic_NCR5380_pnp_driver))
  559. pnp_registered = 1;
  560. #endif
  561. ret = isa_register_driver(&generic_NCR5380_isa_driver, MAX_CARDS);
  562. if (!ret)
  563. isa_registered = 1;
  564. return (pnp_registered || isa_registered) ? 0 : ret;
  565. }
  566. static void __exit generic_NCR5380_exit(void)
  567. {
  568. #if !defined(SCSI_G_NCR5380_MEM) && defined(CONFIG_PNP)
  569. if (pnp_registered)
  570. pnp_unregister_driver(&generic_NCR5380_pnp_driver);
  571. #endif
  572. if (isa_registered)
  573. isa_unregister_driver(&generic_NCR5380_isa_driver);
  574. }
  575. module_init(generic_NCR5380_init);
  576. module_exit(generic_NCR5380_exit);