11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Version 0.03	Cleaned auto-tune, added probe
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Version 0.04	Added second channel tuning
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Version 0.05	Enhanced tuning ; added qd6500 support
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Version 0.06	Added dos driver's list
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Version 0.07	Second channel bug fix
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * QDI QD6500/QD6580 EIDE controller fast support
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To activate controller support, use "ide0=qd65xx"
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
195193535517825f9a07967e4868a1103013d0a99dSamuel Thibault * Samuel Thibault <samuel.thibault@ens-lyon.org>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ide.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35d92f1a2829dbe29c644569a3b64a021e4d90005dBartlomiej Zolnierkiewicz#define DRV_NAME "qd65xx"
36d92f1a2829dbe29c644569a3b64a021e4d90005dBartlomiej Zolnierkiewicz
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "qd65xx.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	-- qd6500 is a single IDE interface
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	-- qd6580 is a dual IDE interface
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * More research on qd6580 being done by willmore@cig.mot.com (David)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * More Information given by Petr Soucek (petr@ryston.cz)
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * http://www.ryston.cz/petr/vlb
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base: Timer1
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base+0x01: Config (R/O)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 3: qd6500: 1 = disabled, 0 = enabled
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        qd6580: 1
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * upper nibble:
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        qd6500: 1100
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        qd6580: either 1010 or 0101
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base+0x02: Timer2 (qd6580 only)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base+0x03: Control (qd6580 only)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits 0-3 must always be set 1
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                                                   channel 1 for hdc & hdd
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 1 : 1 = only disks on primary port
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         0 = disks & ATAPI devices on primary port
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 2-4 : always 0
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 5 : status, but of what ?
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 6 : always set 1 by dos driver
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 7 : set 1 for non-ATAPI devices on primary port
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(maybe read-ahead and post-write buffer ?)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
88d07616f19336b514eef06e6a361988c4073e6ecbBartlomiej Zolnierkiewicz * qd65xx_select:
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
90d07616f19336b514eef06e6a361988c4073e6ecbBartlomiej Zolnierkiewicz * This routine is invoked to prepare for access to a given drive.
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
93abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyovstatic void qd65xx_dev_select(ide_drive_t *drive)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(QD_TIMREG(drive) & 0x02);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timings[index] != QD_TIMING(drive))
99c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz		outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
100abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov
101abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd6500_compute_timing
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * computes the timing value where
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	lower nibble represents active time,   in count of VLB clocks
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	upper nibble represents recovery time, in count of VLB clocks
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11430e5ee4d1a651a0c66e86c6612c003034bd20ba2Bartlomiej Zolnierkiewicz	int clk = ide_vlb_clk ? ide_vlb_clk : 50;
115ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	u8 act_cyc, rec_cyc;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	if (clk <= 33) {
118ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz		act_cyc =  9 - IDE_IN(active_time   * clk / 1000 + 1, 2,  9);
119ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz		rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
121ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz		act_cyc =  8 - IDE_IN(active_time   * clk / 1000 + 1, 1,  8);
122ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz		rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	return (rec_cyc << 4) | 0x08 | act_cyc;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd6580_compute_timing
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * idem for qd6580
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 qd6580_compute_timing (int active_time, int recovery_time)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13630e5ee4d1a651a0c66e86c6612c003034bd20ba2Bartlomiej Zolnierkiewicz	int clk = ide_vlb_clk ? ide_vlb_clk : 50;
137ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	u8 act_cyc, rec_cyc;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
139ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	act_cyc = 17 - IDE_IN(active_time   * clk / 1000 + 1, 2, 17);
140ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
141ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz
142ebae41a5a0583fb732c41445df4ac2c41016df74Bartlomiej Zolnierkiewicz	return (rec_cyc << 4) | act_cyc;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd_find_disk_type
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tries to find timing from dos driver's table
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int qd_find_disk_type (ide_drive_t *drive,
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int *active_time, int *recovery_time)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct qd65xx_timing_s *p;
1554dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	char *m = (char *)&drive->id[ATA_ID_PROD];
1564dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	char model[ATA_ID_PROD_LEN];
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1584dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	if (*m == 0)
1594dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz		return 0;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1614dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	strncpy(model, m, ATA_ID_PROD_LEN);
1624dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(p->model, model+p->offset, 4)) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_DEBUG "%s: listed !\n", drive->name);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*active_time = p->active;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*recovery_time = p->recovery;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd_set_timing:
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
178d07616f19336b514eef06e6a361988c4073e6ecbBartlomiej Zolnierkiewicz * records the timing
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void qd_set_timing (ide_drive_t *drive, u8 timing)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1835bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	unsigned long data = (unsigned long)ide_get_drivedata(drive);
1845bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos
1855bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	data &= 0xff00;
1865bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	data |= timing;
1875bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	ide_set_drivedata(drive, (void *)data);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192e085b3cae85af47eb0a3eda3186bd898310fb322Bartlomiej Zolnierkiewiczstatic void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1944dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	u16 *id = drive->id;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int active_time   = 175;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int recovery_time = 415; /* worst case values from the dos driver */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198e085b3cae85af47eb0a3eda3186bd898310fb322Bartlomiej Zolnierkiewicz	/* FIXME: use drive->pio_mode value */
1994dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
20048fb2688aa67baba373531cc4ed2d9e695983c3fBartlomiej Zolnierkiewicz	    (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
2014dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz	    id[ATA_ID_EIDE_PIO] >= 240) {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
20348fb2688aa67baba373531cc4ed2d9e695983c3fBartlomiej Zolnierkiewicz			id[ATA_ID_OLD_PIO_MODES] & 0xff);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		active_time = 110;
2054dde4492d850a4c9bcaa92e5bd7f4eebe3e2f5abBartlomiej Zolnierkiewicz		recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208898ec223fea2a2df88035e58dbf50f493577e225Bartlomiej Zolnierkiewicz	qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
209898ec223fea2a2df88035e58dbf50f493577e225Bartlomiej Zolnierkiewicz				active_time, recovery_time));
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212e085b3cae85af47eb0a3eda3186bd898310fb322Bartlomiej Zolnierkiewiczstatic void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
214e085b3cae85af47eb0a3eda3186bd898310fb322Bartlomiej Zolnierkiewicz	const u8 pio = drive->pio_mode - XFER_PIO_0;
2152feecface7fd62be75bd4961324dc279a04bef22Bartlomiej Zolnierkiewicz	struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
2167dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz	unsigned int cycle_time;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int active_time   = 175;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int recovery_time = 415; /* worst case values from the dos driver */
21979472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	u8 base = (hwif->config_data & 0xff00) >> 8;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
2227dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz		cycle_time = ide_pio_cycle_time(drive, pio);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (pio) {
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 0: break;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 3:
2277dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz				if (cycle_time >= 110) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					active_time = 86;
2297dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz					recovery_time = cycle_time - 102;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 4:
2347dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz				if (cycle_time >= 69) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					active_time = 70;
2367dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz					recovery_time = cycle_time - 61;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
2417dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz				if (cycle_time >= 180) {
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					active_time = 110;
2437dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz					recovery_time = cycle_time - 120;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
2452feecface7fd62be75bd4961324dc279a04bef22Bartlomiej Zolnierkiewicz					active_time = t->active;
2467dd00083b1160b560fa2a0a486799b57baa5d035Bartlomiej Zolnierkiewicz					recovery_time = cycle_time - active_time;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252898ec223fea2a2df88035e58dbf50f493577e225Bartlomiej Zolnierkiewicz	if (!hwif->channel && drive->media != ide_disk) {
253c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz		outb(0x5f, QD_CONTROL_PORT);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"and post-write buffer on %s.\n",
256898ec223fea2a2df88035e58dbf50f493577e225Bartlomiej Zolnierkiewicz			drive->name, hwif->name);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd_testreg
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tests if the given port is a register
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init qd_testreg(int port)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
271f949820de30b6fd0eb958f7eea87dac190de1cecBartlomiej Zolnierkiewicz	u8 savereg, readreg;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
273c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz	local_irq_save(flags);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	savereg = inb_p(port);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(QD_TESTVAL, port);	/* safe value */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	readreg = inb_p(port);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(savereg, port);
278c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz	local_irq_restore(flags);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savereg == QD_TESTVAL) {
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Assuming qd65xx is not present.\n");
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (readreg != QD_TESTVAL);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
290e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewiczstatic void __init qd6500_init_dev(ide_drive_t *drive)
2911f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz{
292e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewicz	ide_hwif_t *hwif = drive->hwif;
29379472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	u8 base = (hwif->config_data & 0xff00) >> 8;
29479472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	u8 config = QD_CONFIG(hwif);
2951f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz
2965bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
2971f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz}
2981f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz
299e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewiczstatic void __init qd6580_init_dev(ide_drive_t *drive)
3001f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz{
301e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewicz	ide_hwif_t *hwif = drive->hwif;
3021f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz	u16 t1, t2;
30379472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	u8 base = (hwif->config_data & 0xff00) >> 8;
30479472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	u8 config = QD_CONFIG(hwif);
3051f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz
30679472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz	if (hwif->host_flags & IDE_HFLAG_SINGLE) {
3071f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz		t1 = QD6580_DEF_DATA;
3081f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz		t2 = QD6580_DEF_DATA2;
3091f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz	} else
3101f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz		t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
3111f2cf8b0014fdfa3141449b508aca25e78c078a7Bartlomiej Zolnierkiewicz
3125bfb151f1f565e6082304a30e8c81dfb6ed0b0c8Joao Ramos	ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
315abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyovstatic const struct ide_tp_ops qd65xx_tp_ops = {
316abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.exec_command		= ide_exec_command,
317abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.read_status		= ide_read_status,
318abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.read_altstatus		= ide_read_altstatus,
319abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.write_devctl		= ide_write_devctl,
320abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov
321abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.dev_select		= qd65xx_dev_select,
322abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.tf_load		= ide_tf_load,
323abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.tf_read		= ide_tf_read,
324abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov
325abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.input_data		= ide_input_data,
326abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.output_data		= ide_output_data,
327abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov};
328abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov
329ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewiczstatic const struct ide_port_ops qd6500_port_ops = {
330e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewicz	.init_dev		= qd6500_init_dev,
331ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz	.set_pio_mode		= qd6500_set_pio_mode,
332ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz};
333ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz
334ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewiczstatic const struct ide_port_ops qd6580_port_ops = {
335e6d95bd14928926d6658b5e4ace905e8b83ed27aBartlomiej Zolnierkiewicz	.init_dev		= qd6580_init_dev,
336ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz	.set_pio_mode		= qd6580_set_pio_mode,
337ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz};
338ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz
339c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewiczstatic const struct ide_port_info qd65xx_port_info __initdata = {
340d92f1a2829dbe29c644569a3b64a021e4d90005dBartlomiej Zolnierkiewicz	.name			= DRV_NAME,
341abb596b25edac1ec1acc4ef53df190771661c3d2Sergei Shtylyov	.tp_ops 		= &qd65xx_tp_ops,
342c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewicz	.chipset		= ide_qd65xx,
343c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewicz	.host_flags		= IDE_HFLAG_IO_32BIT |
3440d28ec7f213eee37855741410a95ec559f9fa87aBartlomiej Zolnierkiewicz				  IDE_HFLAG_NO_DMA,
345c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewicz	.pio_mask		= ATA_PIO4,
346c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewicz};
347c413b9b94d9a8e7548cc4b2e04b7df0439ce76fdBartlomiej Zolnierkiewicz
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * qd_probe:
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * looks at the specified baseport, and if qd found, registers & initialises it
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return 1 if another qd may be probed
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init qd_probe(int base)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3570bfeee7d4190938291a76536c7f6cd8f4e2dc30cBartlomiej Zolnierkiewicz	int rc;
3587a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	u8 config, unit, control;
359e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz	struct ide_port_info d = qd65xx_port_info;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz	config = inb(QD_CONFIG_PORT);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
3647daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz		return -ENODEV;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
368e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz	if (unit)
369e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz		d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
370e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz
3717a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	switch (config & 0xf0) {
3727a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	case QD_CONFIG_QD6500:
3737daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz		if (qd_testreg(base))
3747daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz			 return -ENODEV;	/* bad register */
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (config & QD_CONFIG_DISABLED) {
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "qd6500 is disabled !\n");
3787daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz			return -ENODEV;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz		printk(KERN_NOTICE "qd6500 at %#x\n", base);
382e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
383e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz			config, QD_ID3);
384e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz
385ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz		d.port_ops = &qd6500_port_ops;
38679472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz		d.host_flags |= IDE_HFLAG_SINGLE;
3877a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		break;
3887a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	case QD_CONFIG_QD6580_A:
3897a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	case QD_CONFIG_QD6580_B:
3907daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz		if (qd_testreg(base) || qd_testreg(base + 0x02))
3917daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz			return -ENODEV;	/* bad registers */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
393c196567a81af6988d1a71b43dd21c47e1ff46f6eBartlomiej Zolnierkiewicz		control = inb(QD_CONTROL_PORT);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE "qd6580 at %#x\n", base);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			config, control, QD_ID3);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
399788d669736dd3d15195fea07bf97ec5a2e9f15e7Bartlomiej Zolnierkiewicz		outb(QD_DEF_CONTR, QD_CONTROL_PORT);
400788d669736dd3d15195fea07bf97ec5a2e9f15e7Bartlomiej Zolnierkiewicz
401ac95beedf8bc97b24f9540d4da9952f07221c023Bartlomiej Zolnierkiewicz		d.port_ops = &qd6580_port_ops;
4027a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		if (control & QD_CONTR_SEC_DISABLED)
40379472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz			d.host_flags |= IDE_HFLAG_SINGLE;
40479472b6ea9e74ee4400ba57ba84cad86426e2d6dBartlomiej Zolnierkiewicz
4057a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		printk(KERN_INFO "qd6580: %s IDE board\n",
4067a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz			(control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
4077a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		break;
4087a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	default:
4097a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		return -ENODEV;
4107a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	}
41126bcb879c03254545a19c6700fe5bcef6f21e7b1Bartlomiej Zolnierkiewicz
4127a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	rc = ide_legacy_device_add(&d, (base << 8) | config);
413e277f91fef8a0ff7726ad33eb79c6f0d0c6229a8Bartlomiej Zolnierkiewicz
4147a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	if (d.host_flags & IDE_HFLAG_SINGLE)
4157a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz		return (rc == 0) ? 1 : rc;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4177a2199f341edb2515021ccd6fe122c0d15b08fc7Bartlomiej Zolnierkiewicz	return rc;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42090ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool probe_qd65xx;
421849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewicz
422849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewiczmodule_param_named(probe, probe_qd65xx, bool, 0);
423849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej ZolnierkiewiczMODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
424849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewicz
425ade2daf9c6e57845fe83a24e0a9fa1c03c6e91b1Bartlomiej Zolnierkiewiczstatic int __init qd65xx_init(void)
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4277daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz	int rc1, rc2 = -ENODEV;
4287daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz
429849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewicz	if (probe_qd65xx == 0)
430849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewicz		return -ENODEV;
431849138827c962589ac50496fa7feeb2a2d51b467Bartlomiej Zolnierkiewicz
4327daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz	rc1 = qd_probe(0x30);
4337daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz	if (rc1)
4347daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz		rc2 = qd_probe(0xb0);
4357daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz
4367daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz	if (rc1 < 0 && rc2 < 0)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4387daf66dd142b1978bf8670d9d959d835de37476fBartlomiej Zolnierkiewicz
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(qd65xx_init);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Samuel Thibault");
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
447