cmd64x.c 13.8 KB
Newer Older
1
/*
2
 * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11
 *
 * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
 *           Due to massive hardware bugs, UltraDMA is only supported
 *           on the 646U2 and not on the 646U.
 *
 * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
 * Copyright (C) 1998		David S. Miller (davem@redhat.com)
 *
 * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
12
 * Copyright (C) 2007		MontaVista Software, Inc. <source@mvista.com>
L
Linus Torvalds 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>

#include <asm/io.h>

#define CMD_DEBUG 0

#if CMD_DEBUG
#define cmdprintk(x...)	printk(x)
#else
#define cmdprintk(x...)
#endif

/*
 * CMD64x specific registers definition.
 */
#define CFR		0x50
37
#define   CFR_INTR_CH0		0x04
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

#define	CMDTIM		0x52
#define	ARTTIM0		0x53
#define	DRWTIM0		0x54
#define ARTTIM1 	0x55
#define DRWTIM1		0x56
#define ARTTIM23	0x57
#define   ARTTIM23_DIS_RA2	0x04
#define   ARTTIM23_DIS_RA3	0x08
#define   ARTTIM23_INTR_CH1	0x10
#define DRWTIM2		0x58
#define BRST		0x59
#define DRWTIM3		0x5b

#define BMIDECR0	0x70
#define MRDMODE		0x71
#define   MRDMODE_INTR_CH0	0x04
#define   MRDMODE_INTR_CH1	0x08
#define UDIDETCR0	0x73
#define DTPR0		0x74
#define BMIDECR1	0x78
#define BMIDECSR	0x79
#define UDIDETCR1	0x7B
#define DTPR1		0x7C

63 64 65 66 67
static u8 quantize_timing(int timing, int quant)
{
	return (timing + quant - 1) / quant;
}

L
Linus Torvalds 已提交
68
/*
69 70
 * This routine calculates active/recovery counts and then writes them into
 * the chipset registers.
L
Linus Torvalds 已提交
71
 */
72
static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
L
Linus Torvalds 已提交
73
{
74 75 76 77
	struct pci_dev *dev	= HWIF(drive)->pci_dev;
	int clock_time		= 1000 / system_bus_clock();
	u8  cycle_count, active_count, recovery_count, drwtim;
	static const u8 recovery_values[] =
L
Linus Torvalds 已提交
78
		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
79 80 81 82 83 84 85 86 87
	static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};

	cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
		  cycle_time, active_time);

	cycle_count	= quantize_timing( cycle_time, clock_time);
	active_count	= quantize_timing(active_time, clock_time);
	recovery_count	= cycle_count - active_count;

L
Linus Torvalds 已提交
88
	/*
89 90
	 * In case we've got too long recovery phase, try to lengthen
	 * the active phase
L
Linus Torvalds 已提交
91
	 */
92 93 94
	if (recovery_count > 16) {
		active_count += recovery_count - 16;
		recovery_count = 16;
L
Linus Torvalds 已提交
95
	}
96 97 98 99 100
	if (active_count > 16)		/* shouldn't actually happen... */
	 	active_count = 16;

	cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
		  cycle_count, active_count, recovery_count);
L
Linus Torvalds 已提交
101 102 103 104

	/*
	 * Convert values to internal chipset representation
	 */
105 106
	recovery_count = recovery_values[recovery_count];
 	active_count  &= 0x0f;
L
Linus Torvalds 已提交
107

108 109 110 111
	/* Program the active/recovery counts into the DRWTIM register */
	drwtim = (active_count << 4) | recovery_count;
	(void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
	cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
L
Linus Torvalds 已提交
112 113 114
}

/*
115 116
 * This routine writes into the chipset registers
 * PIO setup/active/recovery timings.
L
Linus Torvalds 已提交
117
 */
118
static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
L
Linus Torvalds 已提交
119
{
120 121
	ide_hwif_t *hwif	= HWIF(drive);
	struct pci_dev *dev	= hwif->pci_dev;
122
	unsigned int cycle_time;
123 124
	u8 setup_count, arttim = 0;

125 126
	static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
	static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
127

128
	cycle_time = ide_pio_cycle_time(drive, pio);
L
Linus Torvalds 已提交
129

130
	program_cycle_times(drive, cycle_time,
131
			    ide_pio_timings[pio].active_time);
L
Linus Torvalds 已提交
132

133
	setup_count = quantize_timing(ide_pio_timings[pio].setup_time,
134 135 136 137 138 139 140 141 142 143 144 145 146
				      1000 / system_bus_clock());

	/*
	 * The primary channel has individual address setup timing registers
	 * for each drive and the hardware selects the slowest timing itself.
	 * The secondary channel has one common register and we have to select
	 * the slowest address setup timing ourselves.
	 */
	if (hwif->channel) {
		ide_drive_t *drives = hwif->drives;

		drive->drive_data = setup_count;
		setup_count = max(drives[0].drive_data, drives[1].drive_data);
L
Linus Torvalds 已提交
147 148
	}

149 150 151
	if (setup_count > 5)		/* shouldn't actually happen... */
		setup_count = 5;
	cmdprintk("Final address setup count: %d\n", setup_count);
L
Linus Torvalds 已提交
152

153 154 155 156 157 158 159 160 161 162 163
	/*
	 * Program the address setup clocks into the ARTTIM registers.
	 * Avoid clearing the secondary channel's interrupt bit.
	 */
	(void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
	if (hwif->channel)
		arttim &= ~ARTTIM23_INTR_CH1;
	arttim &= ~0xc0;
	arttim |= setup_values[setup_count];
	(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
	cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
164 165 166 167
}

/*
 * Attempts to set drive's PIO mode.
168
 * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
169
 */
170 171

static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
172 173 174 175 176 177 178 179
{
	/*
	 * Filter out the prefetch control values
	 * to prevent PIO5 from being programmed
	 */
	if (pio == 8 || pio == 9)
		return;

180
	cmd64x_tune_pio(drive, pio);
L
Linus Torvalds 已提交
181 182
}

183
static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
L
Linus Torvalds 已提交
184 185 186
{
	ide_hwif_t *hwif	= HWIF(drive);
	struct pci_dev *dev	= hwif->pci_dev;
187 188
	u8 unit			= drive->dn & 0x01;
	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
L
Linus Torvalds 已提交
189

190
	if (speed >= XFER_SW_DMA_0) {
L
Linus Torvalds 已提交
191 192 193 194 195
		(void) pci_read_config_byte(dev, pciU, &regU);
		regU &= ~(unit ? 0xCA : 0x35);
	}

	switch(speed) {
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
	case XFER_UDMA_5:
		regU |= unit ? 0x0A : 0x05;
		break;
	case XFER_UDMA_4:
		regU |= unit ? 0x4A : 0x15;
		break;
	case XFER_UDMA_3:
		regU |= unit ? 0x8A : 0x25;
		break;
	case XFER_UDMA_2:
		regU |= unit ? 0x42 : 0x11;
		break;
	case XFER_UDMA_1:
		regU |= unit ? 0x82 : 0x21;
		break;
	case XFER_UDMA_0:
		regU |= unit ? 0xC2 : 0x31;
		break;
	case XFER_MW_DMA_2:
		program_cycle_times(drive, 120, 70);
		break;
	case XFER_MW_DMA_1:
		program_cycle_times(drive, 150, 80);
		break;
	case XFER_MW_DMA_0:
		program_cycle_times(drive, 480, 215);
		break;
L
Linus Torvalds 已提交
223 224
	}

225
	if (speed >= XFER_SW_DMA_0)
L
Linus Torvalds 已提交
226 227 228
		(void) pci_write_config_byte(dev, pciU, regU);
}

229
static int cmd648_ide_dma_end (ide_drive_t *drive)
L
Linus Torvalds 已提交
230
{
231
	ide_hwif_t *hwif	= HWIF(drive);
232
	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
233 234 235
	int err			= __ide_dma_end(drive);
	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
						  MRDMODE_INTR_CH0;
236
	u8  mrdmode		= inb(base + 1);
237 238

	/* clear the interrupt bit */
239
	outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
240
	     base + 1);
241 242

	return err;
L
Linus Torvalds 已提交
243 244 245 246 247 248
}

static int cmd64x_ide_dma_end (ide_drive_t *drive)
{
	ide_hwif_t *hwif	= HWIF(drive);
	struct pci_dev *dev	= hwif->pci_dev;
249 250 251 252 253
	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
						  CFR_INTR_CH0;
	u8  irq_stat		= 0;
	int err			= __ide_dma_end(drive);
L
Linus Torvalds 已提交
254

255 256 257 258 259 260 261 262 263 264
	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
	/* clear the interrupt bit */
	(void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);

	return err;
}

static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
{
	ide_hwif_t *hwif	= HWIF(drive);
265
	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
266 267 268
	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
						  MRDMODE_INTR_CH0;
	u8 dma_stat		= inb(hwif->dma_status);
269
	u8 mrdmode		= inb(base + 1);
270 271 272 273 274 275 276 277 278 279 280 281 282

#ifdef DEBUG
	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
	       drive->name, dma_stat, mrdmode, irq_mask);
#endif
	if (!(mrdmode & irq_mask))
		return 0;

	/* return 1 if INTR asserted */
	if (dma_stat & 4)
		return 1;

	return 0;
L
Linus Torvalds 已提交
283 284 285 286
}

static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
{
287 288
	ide_hwif_t *hwif	= HWIF(drive);
	struct pci_dev *dev	= hwif->pci_dev;
289 290 291 292 293
	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
						  CFR_INTR_CH0;
	u8  dma_stat		= inb(hwif->dma_status);
	u8  irq_stat		= 0;
294 295

	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
L
Linus Torvalds 已提交
296 297

#ifdef DEBUG
298 299
	printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n",
	       drive->name, dma_stat, irq_stat, irq_mask);
L
Linus Torvalds 已提交
300
#endif
301
	if (!(irq_stat & irq_mask))
L
Linus Torvalds 已提交
302 303 304
		return 0;

	/* return 1 if INTR asserted */
305
	if (dma_stat & 4)
L
Linus Torvalds 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
		return 1;

	return 0;
}

/*
 * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
 * event order for DMA transfers.
 */

static int cmd646_1_ide_dma_end (ide_drive_t *drive)
{
	ide_hwif_t *hwif = HWIF(drive);
	u8 dma_stat = 0, dma_cmd = 0;

	drive->waiting_for_dma = 0;
	/* get DMA status */
323
	dma_stat = inb(hwif->dma_status);
L
Linus Torvalds 已提交
324
	/* read DMA command state */
325
	dma_cmd = inb(hwif->dma_command);
L
Linus Torvalds 已提交
326
	/* stop DMA */
327
	outb(dma_cmd & ~1, hwif->dma_command);
L
Linus Torvalds 已提交
328
	/* clear the INTR & ERROR bits */
329
	outb(dma_stat | 6, hwif->dma_status);
L
Linus Torvalds 已提交
330 331 332 333 334 335 336 337 338 339
	/* and free any DMA resources */
	ide_destroy_dmatable(drive);
	/* verify good DMA status */
	return (dma_stat & 7) != 4;
}

static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const char *name)
{
	u8 mrdmode = 0;

S
Sergei Shtylyov 已提交
340
	if (dev->device == PCI_DEVICE_ID_CMD_646) {
L
Linus Torvalds 已提交
341

A
Auke Kok 已提交
342
		switch (dev->revision) {
S
Sergei Shtylyov 已提交
343 344
		case 0x07:
		case 0x05:
345
			printk("%s: UltraDMA capable\n", name);
L
Linus Torvalds 已提交
346
			break;
S
Sergei Shtylyov 已提交
347
		case 0x03:
L
Linus Torvalds 已提交
348
		default:
349
			printk("%s: MultiWord DMA force limited\n", name);
S
Sergei Shtylyov 已提交
350 351 352 353
			break;
		case 0x01:
			printk("%s: MultiWord DMA limited, "
			       "IRQ workaround enabled\n", name);
L
Linus Torvalds 已提交
354
			break;
S
Sergei Shtylyov 已提交
355
		}
L
Linus Torvalds 已提交
356 357 358 359 360 361
	}

	/* Set a good latency timer and cache line size value. */
	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
	/* FIXME: pci_set_master() to ensure a good latency timer value */

S
Sergei Shtylyov 已提交
362 363 364 365 366 367
	/*
	 * Enable interrupts, select MEMORY READ LINE for reads.
	 *
	 * NOTE: although not mentioned in the PCI0646U specs,
	 * bits 0-1 are write only and won't be read back as
	 * set or not -- PCI0646U2 specs clarify this point.
L
Linus Torvalds 已提交
368
	 */
S
Sergei Shtylyov 已提交
369 370 371
	(void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
	mrdmode &= ~0x30;
	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
L
Linus Torvalds 已提交
372 373 374 375

	return 0;
}

376
static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
L
Linus Torvalds 已提交
377
{
S
Sergei Shtylyov 已提交
378 379
	struct pci_dev  *dev	= hwif->pci_dev;
	u8 bmidecsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
L
Linus Torvalds 已提交
380

S
Sergei Shtylyov 已提交
381 382 383 384
	switch (dev->device) {
	case PCI_DEVICE_ID_CMD_648:
	case PCI_DEVICE_ID_CMD_649:
 		pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
385
		return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
S
Sergei Shtylyov 已提交
386
	default:
387
		return ATA_CBL_PATA40;
L
Linus Torvalds 已提交
388 389 390 391 392 393 394
	}
}

static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
{
	struct pci_dev *dev	= hwif->pci_dev;

395
	hwif->set_pio_mode = &cmd64x_set_pio_mode;
396
	hwif->set_dma_mode = &cmd64x_set_dma_mode;
L
Linus Torvalds 已提交
397

398
	if (!hwif->dma_base)
L
Linus Torvalds 已提交
399 400
		return;

401 402 403 404 405 406 407 408 409 410 411 412
	/*
	 * UltraDMA only supported on PCI646U and PCI646U2, which
	 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
	 * Actually, although the CMD tech support people won't
	 * tell me the details, the 0x03 revision cannot support
	 * UDMA correctly without hardware modifications, and even
	 * then it only works with Quantum disks due to some
	 * hold time assumptions in the 646U part which are fixed
	 * in the 646U2.
	 *
	 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
	 */
A
Auke Kok 已提交
413
	if (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 5)
414
		hwif->ultra_mask = 0x00;
L
Linus Torvalds 已提交
415

416 417
	if (hwif->cbl != ATA_CBL_PATA40_SHORT)
		hwif->cbl = ata66_cmd64x(hwif);
L
Linus Torvalds 已提交
418

S
Sergei Shtylyov 已提交
419
	switch (dev->device) {
420 421 422 423 424 425 426
	case PCI_DEVICE_ID_CMD_648:
	case PCI_DEVICE_ID_CMD_649:
	alt_irq_bits:
		hwif->ide_dma_end	= &cmd648_ide_dma_end;
		hwif->ide_dma_test_irq	= &cmd648_ide_dma_test_irq;
		break;
	case PCI_DEVICE_ID_CMD_646:
A
Auke Kok 已提交
427
		if (dev->revision == 0x01) {
L
Linus Torvalds 已提交
428
			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
429
			break;
A
Auke Kok 已提交
430
		} else if (dev->revision >= 0x03)
431 432 433 434 435 436
			goto alt_irq_bits;
		/* fall thru */
	default:
		hwif->ide_dma_end	= &cmd64x_ide_dma_end;
		hwif->ide_dma_test_irq	= &cmd64x_ide_dma_test_irq;
		break;
L
Linus Torvalds 已提交
437 438 439
	}
}

440
static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
L
Linus Torvalds 已提交
441 442 443 444
	{	/* 0 */
		.name		= "CMD643",
		.init_chipset	= init_chipset_cmd64x,
		.init_hwif	= init_hwif_cmd64x,
445
		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
446
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
B
Bartlomiej Zolnierkiewicz 已提交
447
		.pio_mask	= ATA_PIO5,
448
		.mwdma_mask	= ATA_MWDMA2,
449
		.udma_mask	= 0x00, /* no udma */
L
Linus Torvalds 已提交
450 451 452 453
	},{	/* 1 */
		.name		= "CMD646",
		.init_chipset	= init_chipset_cmd64x,
		.init_hwif	= init_hwif_cmd64x,
454
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
455
		.chipset	= ide_cmd646,
456
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
B
Bartlomiej Zolnierkiewicz 已提交
457
		.pio_mask	= ATA_PIO5,
458 459
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA2,
L
Linus Torvalds 已提交
460 461 462 463
	},{	/* 2 */
		.name		= "CMD648",
		.init_chipset	= init_chipset_cmd64x,
		.init_hwif	= init_hwif_cmd64x,
464
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
465
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
B
Bartlomiej Zolnierkiewicz 已提交
466
		.pio_mask	= ATA_PIO5,
467 468
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA4,
L
Linus Torvalds 已提交
469 470 471 472
	},{	/* 3 */
		.name		= "CMD649",
		.init_chipset	= init_chipset_cmd64x,
		.init_hwif	= init_hwif_cmd64x,
473
		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
474
		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
B
Bartlomiej Zolnierkiewicz 已提交
475
		.pio_mask	= ATA_PIO5,
476 477
		.mwdma_mask	= ATA_MWDMA2,
		.udma_mask	= ATA_UDMA5,
L
Linus Torvalds 已提交
478 479 480 481 482
	}
};

static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
483
	struct ide_port_info d;
484 485 486 487 488 489 490 491 492 493
	u8 idx = id->driver_data;

	d = cmd64x_chipsets[idx];

	/*
	 * The original PCI0646 didn't have the primary channel enable bit,
	 * it appeared starting with PCI0646U (i.e. revision ID 3).
	 */
	if (idx == 1 && dev->revision < 3)
		d.enablebits[0].reg = 0;
494

495
	return ide_setup_pci_device(dev, &d);
L
Linus Torvalds 已提交
496 497
}

498 499 500 501 502
static const struct pci_device_id cmd64x_pci_tbl[] = {
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
L
Linus Torvalds 已提交
503 504 505 506 507 508 509 510 511 512
	{ 0, },
};
MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);

static struct pci_driver driver = {
	.name		= "CMD64x_IDE",
	.id_table	= cmd64x_pci_tbl,
	.probe		= cmd64x_init_one,
};

513
static int __init cmd64x_ide_init(void)
L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521 522
{
	return ide_pci_register_driver(&driver);
}

module_init(cmd64x_ide_init);

MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
MODULE_LICENSE("GPL");