g_NCR5380.c 16.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Generic Generic NCR5380 driver
 *	
 * Copyright 1993, Drew Eckhardt
 *	Visionary Computing
 *	(Unix and Linux consulting and custom programming)
 *	drew@colorado.edu
 *      +1 (303) 440-4894
 *
 * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
 *    K.Lentin@cs.monash.edu.au
 *
 * NCR53C400A extensions (c) 1996, Ingmar Baumgart
 *    ingmar@gonzo.schwaben.de
 *
 * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg
 * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl
 *
 * Added ISAPNP support for DTC436 adapters,
 * Thomas Sailer, sailer@ife.ee.ethz.ch
 *
F
Finn Thain 已提交
22
 * See Documentation/scsi/g_NCR5380.txt for more info.
L
Linus Torvalds 已提交
23 24 25 26
 */

#include <asm/io.h>
#include <linux/blkdev.h>
27
#include <linux/module.h>
L
Linus Torvalds 已提交
28 29 30 31 32
#include <scsi/scsi_host.h>
#include "g_NCR5380.h"
#include "NCR5380.h"
#include <linux/init.h>
#include <linux/ioport.h>
33 34
#include <linux/isa.h>
#include <linux/pnp.h>
L
Linus Torvalds 已提交
35 36
#include <linux/interrupt.h>

37 38 39
#define MAX_CARDS 8

/* old-style parameters for compatibility */
40 41 42 43 44 45
static int ncr_irq;
static int ncr_addr;
static int ncr_5380;
static int ncr_53c400;
static int ncr_53c400a;
static int dtc_3181e;
O
Ondrej Zary 已提交
46
static int hp_c2502;
47 48 49 50 51 52 53 54 55 56 57
module_param(ncr_irq, int, 0);
module_param(ncr_addr, int, 0);
module_param(ncr_5380, int, 0);
module_param(ncr_53c400, int, 0);
module_param(ncr_53c400a, int, 0);
module_param(dtc_3181e, int, 0);
module_param(hp_c2502, int, 0);

static int irq[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
module_param_array(irq, int, NULL, 0);
MODULE_PARM_DESC(irq, "IRQ number(s)");
L
Linus Torvalds 已提交
58

59 60 61 62 63 64 65 66
static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
module_param_array(base, int, NULL, 0);
MODULE_PARM_DESC(base, "base address(es)");

static int card[] = { -1, -1, -1, -1, -1, -1, -1, -1 };
module_param_array(card, int, NULL, 0);
MODULE_PARM_DESC(card, "card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC3181E, 4=HP C2502)");

67
MODULE_ALIAS("g_NCR5380_mmio");
68
MODULE_LICENSE("GPL");
L
Linus Torvalds 已提交
69

O
Ondrej Zary 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
/*
 * Configure I/O address of 53C400A or DTC436 by writing magic numbers
 * to ports 0x779 and 0x379.
 */
static void magic_configure(int idx, u8 irq, u8 magic[])
{
	u8 cfg = 0;

	outb(magic[0], 0x779);
	outb(magic[1], 0x379);
	outb(magic[2], 0x379);
	outb(magic[3], 0x379);
	outb(magic[4], 0x379);

	/* allowed IRQs for HP C2502 */
	if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
		irq = 0;
	if (idx >= 0 && idx <= 7)
		cfg = 0x80 | idx | (irq << 4);
	outb(cfg, 0x379);
}
91 92 93 94 95 96 97 98 99 100 101 102 103

static unsigned int ncr_53c400a_ports[] = {
	0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
};
static unsigned int dtc_3181e_ports[] = {
	0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
};
static u8 ncr_53c400a_magic[] = {	/* 53C400A & DTC436 */
	0x59, 0xb9, 0xc5, 0xae, 0xa6
};
static u8 hp_c2502_magic[] = {	/* HP C2502 */
	0x0f, 0x22, 0xf0, 0x20, 0x80
};
O
Ondrej Zary 已提交
104

105 106
static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
			struct device *pdev, int base, int irq, int board)
L
Linus Torvalds 已提交
107
{
108 109 110 111
	bool is_pmio = base <= 0xffff;
	int ret;
	int flags = 0;
	unsigned int *ports = NULL;
O
Ondrej Zary 已提交
112
	u8 *magic = NULL;
113
	int i;
O
Ondrej Zary 已提交
114
	int port_idx = -1;
115
	unsigned long region_size;
L
Linus Torvalds 已提交
116
	struct Scsi_Host *instance;
117
	struct NCR5380_hostdata *hostdata;
118
	u8 __iomem *iomem;
L
Linus Torvalds 已提交
119

120
	switch (board) {
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	case BOARD_NCR5380:
		flags = FLAG_NO_PSEUDO_DMA | FLAG_DMA_FIXUP;
		break;
	case BOARD_NCR53C400A:
		ports = ncr_53c400a_ports;
		magic = ncr_53c400a_magic;
		break;
	case BOARD_HP_C2502:
		ports = ncr_53c400a_ports;
		magic = hp_c2502_magic;
		break;
	case BOARD_DTC3181E:
		ports = dtc_3181e_ports;
		magic = ncr_53c400a_magic;
		break;
	}
L
Linus Torvalds 已提交
137

138
	if (is_pmio && ports && magic) {
139
		/* wakeup sequence for the NCR53C400A and DTC3181E */
L
Linus Torvalds 已提交
140

141 142
		/* Disable the adapter and look for a free io port */
		magic_configure(-1, 0, magic);
L
Linus Torvalds 已提交
143

144
		region_size = 16;
145
		if (base)
146
			for (i = 0; ports[i]; i++) {
147 148 149 150 151
				if (base == ports[i]) {	/* index found */
					if (!request_region(ports[i],
							    region_size,
							    "ncr53c80"))
						return -EBUSY;
152
					break;
153 154 155
				}
			}
		else
156
			for (i = 0; ports[i]; i++) {
157 158
				if (!request_region(ports[i], region_size,
						    "ncr53c80"))
159 160 161 162 163 164 165 166 167
					continue;
				if (inb(ports[i]) == 0xff)
					break;
				release_region(ports[i], region_size);
			}
		if (ports[i]) {
			/* At this point we have our region reserved */
			magic_configure(i, 0, magic); /* no IRQ yet */
			outb(0xc0, ports[i] + 9);
168 169 170 171 172
			if (inb(ports[i] + 9) != 0x80) {
				ret = -ENODEV;
				goto out_release;
			}
			base = ports[i];
173 174
			port_idx = i;
		} else
175
			return -EINVAL;
176
	} else if (is_pmio) {
177
		/* NCR5380 - no configuration, just grab */
178
		region_size = 8;
179 180
		if (!base || !request_region(base, region_size, "ncr5380"))
			return -EBUSY;
181 182 183 184
	} else {	/* MMIO */
		region_size = NCR53C400_region_size;
		if (!request_mem_region(base, region_size, "ncr5380"))
			return -EBUSY;
185
	}
186 187 188 189 190 191

	if (is_pmio)
		iomem = ioport_map(base, region_size);
	else
		iomem = ioremap(base, region_size);

192
	if (!iomem) {
193 194
		ret = -ENOMEM;
		goto out_release;
195
	}
196

197 198 199
	instance = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
	if (instance == NULL) {
		ret = -ENOMEM;
200
		goto out_unmap;
201
	}
202
	hostdata = shost_priv(instance);
L
Linus Torvalds 已提交
203

204 205
	hostdata->io = iomem;
	hostdata->region_size = region_size;
206 207

	if (is_pmio) {
208
		hostdata->io_port = base;
209 210 211 212 213 214 215 216 217
		hostdata->io_width = 1; /* 8-bit PDMA by default */
		hostdata->offset = 0;

		/*
		 * On NCR53C400 boards, NCR5380 registers are mapped 8 past
		 * the base address.
		 */
		switch (board) {
		case BOARD_NCR53C400:
218
			hostdata->io_port += 8;
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
			hostdata->c400_ctl_status = 0;
			hostdata->c400_blk_cnt = 1;
			hostdata->c400_host_buf = 4;
			break;
		case BOARD_DTC3181E:
			hostdata->io_width = 2;	/* 16-bit PDMA */
			/* fall through */
		case BOARD_NCR53C400A:
		case BOARD_HP_C2502:
			hostdata->c400_ctl_status = 9;
			hostdata->c400_blk_cnt = 10;
			hostdata->c400_host_buf = 8;
			break;
		}
	} else {
234
		hostdata->base = base;
235 236 237 238 239 240 241 242 243 244 245 246 247 248
		hostdata->offset = NCR53C400_mem_base;
		switch (board) {
		case BOARD_NCR53C400:
			hostdata->c400_ctl_status = 0x100;
			hostdata->c400_blk_cnt = 0x101;
			hostdata->c400_host_buf = 0x104;
			break;
		case BOARD_DTC3181E:
		case BOARD_NCR53C400A:
		case BOARD_HP_C2502:
			pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
			ret = -EINVAL;
			goto out_unregister;
		}
249
	}
L
Linus Torvalds 已提交
250

251 252
	ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP);
	if (ret)
253
		goto out_unregister;
L
Linus Torvalds 已提交
254

255
	switch (board) {
256 257 258 259 260 261
	case BOARD_NCR53C400:
	case BOARD_DTC3181E:
	case BOARD_NCR53C400A:
	case BOARD_HP_C2502:
		NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
	}
262

263
	NCR5380_maybe_reset_bus(instance);
264

265 266
	if (irq != IRQ_AUTO)
		instance->irq = irq;
267 268
	else
		instance->irq = NCR5380_probe_irq(instance, 0xffff);
L
Linus Torvalds 已提交
269

270 271 272
	/* Compatibility with documented NCR5380 kernel parameters */
	if (instance->irq == 255)
		instance->irq = NO_IRQ;
F
Finn Thain 已提交
273

274 275
	if (instance->irq != NO_IRQ) {
		/* set IRQ for HP C2502 */
276
		if (board == BOARD_HP_C2502)
277 278 279 280 281
			magic_configure(port_idx, instance->irq, magic);
		if (request_irq(instance->irq, generic_NCR5380_intr,
				0, "NCR5380", instance)) {
			printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
			instance->irq = NO_IRQ;
L
Linus Torvalds 已提交
282
		}
283
	}
L
Linus Torvalds 已提交
284

285 286 287
	if (instance->irq == NO_IRQ) {
		printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
		printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
L
Linus Torvalds 已提交
288
	}
289

290 291 292 293 294 295
	ret = scsi_add_host(instance, pdev);
	if (ret)
		goto out_free_irq;
	scsi_scan_host(instance);
	dev_set_drvdata(pdev, instance);
	return 0;
296

297 298 299 300
out_free_irq:
	if (instance->irq != NO_IRQ)
		free_irq(instance->irq, instance);
	NCR5380_exit(instance);
301
out_unregister:
302
	scsi_host_put(instance);
303
out_unmap:
304
	iounmap(iomem);
305 306 307 308 309
out_release:
	if (is_pmio)
		release_region(base, region_size);
	else
		release_mem_region(base, region_size);
310
	return ret;
L
Linus Torvalds 已提交
311 312
}

313
static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
L
Linus Torvalds 已提交
314
{
315
	struct NCR5380_hostdata *hostdata = shost_priv(instance);
316 317 318 319
	void __iomem *iomem = hostdata->io;
	unsigned long io_port = hostdata->io_port;
	unsigned long base = hostdata->base;
	unsigned long region_size = hostdata->region_size;
320

321
	scsi_remove_host(instance);
F
Finn Thain 已提交
322
	if (instance->irq != NO_IRQ)
323
		free_irq(instance->irq, instance);
L
Linus Torvalds 已提交
324
	NCR5380_exit(instance);
325
	scsi_host_put(instance);
326 327 328 329 330
	iounmap(iomem);
	if (io_port)
		release_region(io_port, region_size);
	else
		release_mem_region(base, region_size);
L
Linus Torvalds 已提交
331 332 333
}

/**
F
Finn Thain 已提交
334
 *	generic_NCR5380_pread - pseudo DMA read
L
Linus Torvalds 已提交
335 336 337 338
 *	@instance: adapter to read from
 *	@dst: buffer to read into
 *	@len: buffer length
 *
L
Lucas De Marchi 已提交
339
 *	Perform a pseudo DMA mode read from an NCR53C400 or equivalent
L
Linus Torvalds 已提交
340 341 342
 *	controller
 */
 
F
Finn Thain 已提交
343 344
static inline int generic_NCR5380_pread(struct Scsi_Host *instance,
                                        unsigned char *dst, int len)
L
Linus Torvalds 已提交
345
{
346
	struct NCR5380_hostdata *hostdata = shost_priv(instance);
L
Linus Torvalds 已提交
347 348 349
	int blocks = len / 128;
	int start = 0;

350 351
	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
	NCR5380_write(hostdata->c400_blk_cnt, blocks);
L
Linus Torvalds 已提交
352
	while (1) {
353
		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
L
Linus Torvalds 已提交
354
			break;
355
		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
L
Linus Torvalds 已提交
356 357 358
			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
			return -1;
		}
359 360
		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
			; /* FIXME - no timeout */
L
Linus Torvalds 已提交
361

362 363
		if (hostdata->io_port && hostdata->io_width == 2)
			insw(hostdata->io_port + hostdata->c400_host_buf,
O
Ondrej Zary 已提交
364
							dst + start, 64);
365 366
		else if (hostdata->io_port)
			insb(hostdata->io_port + hostdata->c400_host_buf,
367
							dst + start, 128);
368 369
		else
			memcpy_fromio(dst + start,
370
				hostdata->io + NCR53C400_host_buffer, 128);
371

L
Linus Torvalds 已提交
372 373 374 375 376
		start += 128;
		blocks--;
	}

	if (blocks) {
377 378
		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
			; /* FIXME - no timeout */
L
Linus Torvalds 已提交
379

380 381
		if (hostdata->io_port && hostdata->io_width == 2)
			insw(hostdata->io_port + hostdata->c400_host_buf,
O
Ondrej Zary 已提交
382
							dst + start, 64);
383 384
		else if (hostdata->io_port)
			insb(hostdata->io_port + hostdata->c400_host_buf,
385
							dst + start, 128);
386 387
		else
			memcpy_fromio(dst + start,
388
				hostdata->io + NCR53C400_host_buffer, 128);
389

L
Linus Torvalds 已提交
390 391 392 393
		start += 128;
		blocks--;
	}

394
	if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
L
Linus Torvalds 已提交
395 396
		printk("53C400r: no 53C80 gated irq after transfer");

397 398
	/* wait for 53C80 registers to be available */
	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
L
Linus Torvalds 已提交
399
		;
400

L
Linus Torvalds 已提交
401 402 403 404 405 406 407
	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
		printk(KERN_ERR "53C400r: no end dma signal\n");
		
	return 0;
}

/**
F
Finn Thain 已提交
408
 *	generic_NCR5380_pwrite - pseudo DMA write
L
Linus Torvalds 已提交
409 410 411 412
 *	@instance: adapter to read from
 *	@dst: buffer to read into
 *	@len: buffer length
 *
L
Lucas De Marchi 已提交
413
 *	Perform a pseudo DMA mode read from an NCR53C400 or equivalent
L
Linus Torvalds 已提交
414 415 416
 *	controller
 */

F
Finn Thain 已提交
417 418
static inline int generic_NCR5380_pwrite(struct Scsi_Host *instance,
                                         unsigned char *src, int len)
L
Linus Torvalds 已提交
419
{
420
	struct NCR5380_hostdata *hostdata = shost_priv(instance);
L
Linus Torvalds 已提交
421 422 423
	int blocks = len / 128;
	int start = 0;

424 425
	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
	NCR5380_write(hostdata->c400_blk_cnt, blocks);
L
Linus Torvalds 已提交
426
	while (1) {
427
		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
L
Linus Torvalds 已提交
428 429 430 431
			printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
			return -1;
		}

432
		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
L
Linus Torvalds 已提交
433
			break;
434
		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
L
Linus Torvalds 已提交
435
			; // FIXME - timeout
436

437 438
		if (hostdata->io_port && hostdata->io_width == 2)
			outsw(hostdata->io_port + hostdata->c400_host_buf,
O
Ondrej Zary 已提交
439
							src + start, 64);
440 441
		else if (hostdata->io_port)
			outsb(hostdata->io_port + hostdata->c400_host_buf,
442
							src + start, 128);
443
		else
444
			memcpy_toio(hostdata->io + NCR53C400_host_buffer,
445 446
			            src + start, 128);

L
Linus Torvalds 已提交
447 448 449 450
		start += 128;
		blocks--;
	}
	if (blocks) {
451
		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
L
Linus Torvalds 已提交
452 453
			; // FIXME - no timeout

454 455
		if (hostdata->io_port && hostdata->io_width == 2)
			outsw(hostdata->io_port + hostdata->c400_host_buf,
O
Ondrej Zary 已提交
456
							src + start, 64);
457 458
		else if (hostdata->io_port)
			outsb(hostdata->io_port + hostdata->c400_host_buf,
459
							src + start, 128);
460
		else
461
			memcpy_toio(hostdata->io + NCR53C400_host_buffer,
462 463
			            src + start, 128);

L
Linus Torvalds 已提交
464 465 466 467
		start += 128;
		blocks--;
	}

468 469
	/* wait for 53C80 registers to be available */
	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
O
Ondrej Zary 已提交
470 471 472
		udelay(4); /* DTC436 chip hangs without this */
		/* FIXME - no timeout */
	}
L
Linus Torvalds 已提交
473 474 475 476

	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
		printk(KERN_ERR "53C400w: no end dma signal\n");
	}
477

L
Linus Torvalds 已提交
478 479 480 481
	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
		; 	// TIMEOUT
	return 0;
}
482

483 484
static int generic_NCR5380_dma_xfer_len(struct Scsi_Host *instance,
                                        struct scsi_cmnd *cmd)
485
{
486
	struct NCR5380_hostdata *hostdata = shost_priv(instance);
487 488
	int transfersize = cmd->transfersize;

489 490 491
	if (hostdata->flags & FLAG_NO_PSEUDO_DMA)
		return 0;

492 493 494 495 496 497 498
	/* Limit transfers to 32K, for xx400 & xx406
	 * pseudoDMA that transfers in 128 bytes blocks.
	 */
	if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
	    !(cmd->SCp.this_residual % transfersize))
		transfersize = 32 * 1024;

499 500 501 502
	/* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
	if (transfersize % 128)
		transfersize = 0;

503 504 505
	return transfersize;
}

L
Linus Torvalds 已提交
506 507 508 509 510 511
/*
 *	Include the NCR5380 core code that we build our driver around	
 */
 
#include "NCR5380.c"

512
static struct scsi_host_template driver_template = {
513
	.module			= THIS_MODULE,
514 515 516 517
	.proc_name		= DRV_MODULE_NAME,
	.name			= "Generic NCR5380/NCR53C400 SCSI",
	.info			= generic_NCR5380_info,
	.queuecommand		= generic_NCR5380_queue_command,
L
Linus Torvalds 已提交
518 519
	.eh_abort_handler	= generic_NCR5380_abort,
	.eh_bus_reset_handler	= generic_NCR5380_bus_reset,
520 521 522 523 524
	.can_queue		= 16,
	.this_id		= 7,
	.sg_tablesize		= SG_ALL,
	.cmd_per_lun		= 2,
	.use_clustering		= DISABLE_CLUSTERING,
525
	.cmd_size		= NCR5380_CMD_SIZE,
F
Finn Thain 已提交
526
	.max_sectors		= 128,
L
Linus Torvalds 已提交
527
};
528

L
Linus Torvalds 已提交
529

530 531 532 533 534 535 536 537 538 539
static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev)
{
	int ret = generic_NCR5380_init_one(&driver_template, pdev, base[ndev],
					  irq[ndev], card[ndev]);
	if (ret) {
		if (base[ndev])
			printk(KERN_WARNING "Card not found at address 0x%03x\n",
			       base[ndev]);
		return 0;
	}
L
Linus Torvalds 已提交
540

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	return 1;
}

static int generic_NCR5380_isa_remove(struct device *pdev,
				   unsigned int ndev)
{
	generic_NCR5380_release_resources(dev_get_drvdata(pdev));
	dev_set_drvdata(pdev, NULL);
	return 0;
}

static struct isa_driver generic_NCR5380_isa_driver = {
	.match		= generic_NCR5380_isa_match,
	.remove		= generic_NCR5380_isa_remove,
	.driver		= {
		.name	= DRV_MODULE_NAME
	},
};

560
#ifdef CONFIG_PNP
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
static struct pnp_device_id generic_NCR5380_pnp_ids[] = {
	{ .id = "DTC436e", .driver_data = BOARD_DTC3181E },
	{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, generic_NCR5380_pnp_ids);

static int generic_NCR5380_pnp_probe(struct pnp_dev *pdev,
			       const struct pnp_device_id *id)
{
	int base, irq;

	if (pnp_activate_dev(pdev) < 0)
		return -EBUSY;

	base = pnp_port_start(pdev, 0);
	irq = pnp_irq(pdev, 0);

	return generic_NCR5380_init_one(&driver_template, &pdev->dev, base, irq,
				       id->driver_data);
}

static void generic_NCR5380_pnp_remove(struct pnp_dev *pdev)
{
	generic_NCR5380_release_resources(pnp_get_drvdata(pdev));
	pnp_set_drvdata(pdev, NULL);
}

static struct pnp_driver generic_NCR5380_pnp_driver = {
	.name		= DRV_MODULE_NAME,
	.id_table	= generic_NCR5380_pnp_ids,
	.probe		= generic_NCR5380_pnp_probe,
	.remove		= generic_NCR5380_pnp_remove,
L
Linus Torvalds 已提交
593
};
594
#endif /* defined(CONFIG_PNP) */
L
Linus Torvalds 已提交
595

596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
static int pnp_registered, isa_registered;

static int __init generic_NCR5380_init(void)
{
	int ret = 0;

	/* compatibility with old-style parameters */
	if (irq[0] == 0 && base[0] == 0 && card[0] == -1) {
		irq[0] = ncr_irq;
		base[0] = ncr_addr;
		if (ncr_5380)
			card[0] = BOARD_NCR5380;
		if (ncr_53c400)
			card[0] = BOARD_NCR53C400;
		if (ncr_53c400a)
			card[0] = BOARD_NCR53C400A;
		if (dtc_3181e)
			card[0] = BOARD_DTC3181E;
		if (hp_c2502)
			card[0] = BOARD_HP_C2502;
	}

618
#ifdef CONFIG_PNP
619 620
	if (!pnp_register_driver(&generic_NCR5380_pnp_driver))
		pnp_registered = 1;
621
#endif
622 623 624 625 626 627 628 629 630
	ret = isa_register_driver(&generic_NCR5380_isa_driver, MAX_CARDS);
	if (!ret)
		isa_registered = 1;

	return (pnp_registered || isa_registered) ? 0 : ret;
}

static void __exit generic_NCR5380_exit(void)
{
631
#ifdef CONFIG_PNP
632 633 634 635 636 637 638 639 640
	if (pnp_registered)
		pnp_unregister_driver(&generic_NCR5380_pnp_driver);
#endif
	if (isa_registered)
		isa_unregister_driver(&generic_NCR5380_isa_driver);
}

module_init(generic_NCR5380_init);
module_exit(generic_NCR5380_exit);