g_NCR5380.c 16.1 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
	void __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
	hostdata->iomem = iomem;
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

	if (is_pmio) {
		instance->io_port = base;
		instance->n_io_port = region_size;
		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:
			instance->io_port += 8;
			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 {
		instance->base = base;
		hostdata->iomem_size = region_size;
		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;
		}
250
	}
L
Linus Torvalds 已提交
251

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

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

264
	NCR5380_maybe_reset_bus(instance);
265

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

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

275 276
	if (instance->irq != NO_IRQ) {
		/* set IRQ for HP C2502 */
277
		if (board == BOARD_HP_C2502)
278 279 280 281 282
			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 已提交
283
		}
284
	}
L
Linus Torvalds 已提交
285

286 287 288
	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 已提交
289
	}
290

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

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

314
static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
L
Linus Torvalds 已提交
315
{
316 317
	struct NCR5380_hostdata *hostdata = shost_priv(instance);

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

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

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

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

L
Linus Torvalds 已提交
369 370 371 372 373
		start += 128;
		blocks--;
	}

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

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

L
Linus Torvalds 已提交
387 388 389 390
		start += 128;
		blocks--;
	}

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

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

L
Linus Torvalds 已提交
398 399 400 401 402 403 404
	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 已提交
405
 *	generic_NCR5380_pwrite - pseudo DMA write
L
Linus Torvalds 已提交
406 407 408 409
 *	@instance: adapter to read from
 *	@dst: buffer to read into
 *	@len: buffer length
 *
L
Lucas De Marchi 已提交
410
 *	Perform a pseudo DMA mode read from an NCR53C400 or equivalent
L
Linus Torvalds 已提交
411 412 413
 *	controller
 */

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

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

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

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

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

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

L
Linus Torvalds 已提交
461 462 463 464
		start += 128;
		blocks--;
	}

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

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

L
Linus Torvalds 已提交
475 476 477 478
	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
		; 	// TIMEOUT
	return 0;
}
479

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

486 487 488
	if (hostdata->flags & FLAG_NO_PSEUDO_DMA)
		return 0;

489 490 491 492 493 494 495
	/* 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;

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

500 501 502
	return transfersize;
}

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

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

L
Linus Torvalds 已提交
526

527 528 529 530 531 532 533 534 535 536
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 已提交
537

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
	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
	},
};

557
#ifdef CONFIG_PNP
558 559 560 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
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 已提交
590
};
591
#endif /* defined(CONFIG_PNP) */
L
Linus Torvalds 已提交
592

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
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;
	}

615
#ifdef CONFIG_PNP
616 617
	if (!pnp_register_driver(&generic_NCR5380_pnp_driver))
		pnp_registered = 1;
618
#endif
619 620 621 622 623 624 625 626 627
	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)
{
628
#ifdef CONFIG_PNP
629 630 631 632 633 634 635 636 637
	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);