/*
 *  linux/drivers/ide/it8212.c	Version 0.01	January 25, 2003
 *
 *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
 *  May be copied or modified under the terms of the GNU General Public License
 *
 *  Portions Copyright (C) 2003 Integrated Technology Express , Inc.
 *  Author: Liangyao Li <liangyao.li@iteusa.com>
 *  Released under terms of General Public License
 *
 *  Jan 25, 2003 Liangyao Li
 *		initial version.
 */


#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>

#include <linux/stat.h>
#include <linux/proc_fs.h>

#include <asm/io.h>
#include <asm/irq.h>

#include "ide_modes.h"

//#define IT8212_DEBUG	// enable debug info
#include "it8212.h"


/************************************************************************
 * Global data and function prototype definitions
 ************************************************************************/

byte it8212_proc = 0;	// refered in ide-proc.c
extern int (*it8212_display_info)(char *, char **, off_t, int);	// from ide-proc.c


/************************************************************************
 * Local data and function prototype definitions
 ************************************************************************/

typedef struct
{
	u8 type;
	u8 mode;
	u8 clock;
	u8 udmaTiming;
	u8 pioDmaTiming;
} drive_config_t;


struct
{
	struct pci_dev *device;
	ide_hwif_t *hwif[NofCHANNEL];
	ide_drive_t *drive[NofCHANNEL][NofDRIVE];
	drive_config_t config[NofCHANNEL][NofDRIVE];
} it8212;


/************************************************************************
 *
 ************************************************************************/

void it8212_showDriveTiming(int channel)
{
	u8 modeControl;
	u8 udmaTiming;
	u8 pioDmaTiming;
	int channelOffset;
	struct pci_dev *dev;

	ITE_KDBG("(channel %d)\n", channel);

	dev = it8212.device;
	channelOffset = 4 * channel;

	pci_read_config_byte(dev, IT8212_PCI_PciModeCONTROL, &modeControl);
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimPioDmaTIMING + channelOffset, &pioDmaTiming);
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimDrive0UdmaTIMING + channelOffset, &udmaTiming);

	ITE_DBG("modeControl	%02x\n", modeControl);
	ITE_DBG("udmaTiming	%02x\n", udmaTiming);
	ITE_DBG("pioDmaTiming	%02x\n", pioDmaTiming);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_showIdeRegisters(ide_hwif_t *hwif)
{
	u32 dword;
	u8 byte1, byte2;
	ide_drive_t *drive;
	unsigned long busMasterBase;

	ITE_KDBG("(%s)\n", hwif->name);

	drive = &(hwif->drives[0]);
	busMasterBase = hwif->dma_base;

	ITE_DBG("%s\n", hwif->name);
	ITE_DBG("data	%08lx  %04x\n", IDE_DATA_REG, inw(IDE_DATA_REG));
	ITE_DBG("error	%08lx  %02x\n", IDE_ERROR_REG, IN_BYTE(IDE_ERROR_REG));
	ITE_DBG("nsector	%08lx  %02x\n", IDE_NSECTOR_REG, IN_BYTE(IDE_NSECTOR_REG));
	ITE_DBG("sector	%08lx  %02x\n", IDE_SECTOR_REG, IN_BYTE(IDE_SECTOR_REG));
	ITE_DBG("lcyl	%08lx  %02x\n", IDE_LCYL_REG, IN_BYTE(IDE_LCYL_REG));
	ITE_DBG("hcyl	%08lx  %02x\n", IDE_HCYL_REG, IN_BYTE(IDE_HCYL_REG));
	ITE_DBG("select	%08lx  %02x\n", IDE_SELECT_REG, IN_BYTE(IDE_SELECT_REG));
	ITE_DBG("status	%08lx  %02x\n", IDE_STATUS_REG, IN_BYTE(IDE_STATUS_REG));
	ITE_DBG("control	%08lx  %02x\n", IDE_CONTROL_REG, IN_BYTE(IDE_CONTROL_REG));
	ITE_DBG("irq 	%08lx  %02x\n", IDE_IRQ_REG, IN_BYTE(IDE_IRQ_REG));

	ITE_DBG("BusMaster IDE IORegs\n");

	byte1 = inb(busMasterBase);
	byte2 = inb(busMasterBase + 2);
	dword = inl(busMasterBase + 4);

	ITE_DBG("command	%08lx  %02x \n", busMasterBase, byte1);
	ITE_DBG("status	%08lx  %02x\n", busMasterBase + 2, byte2);
	ITE_DBG("table	%08lx  %08x\n", busMasterBase + 4, dword);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_showPciRegisters(struct pci_dev *dev)
{
	u8 byte1, byte2, byte3, byte4;
	u16 word1, word2;
	u32 dword;

//	ITE_KDBG("(%s)\n", dev->name);

	pci_read_config_word(dev, PCI_VENDOR_ID, &word1);	
	pci_read_config_word(dev, PCI_DEVICE_ID, &word2);
	ITE_DBG("00h   %04x %04x\n", word1, word2);

	pci_read_config_word(dev, PCI_COMMAND, &word1);
	pci_read_config_word(dev, PCI_STATUS, &word2);
	ITE_DBG("04h   %04x %04x\n", word1, word2);

	pci_read_config_byte(dev, PCI_CLASS_REVISION, &byte1);	
	pci_read_config_byte(dev, PCI_CLASS_PROG, &byte2);
	pci_read_config_byte(dev, PCI_CLASS_DEVICE, &byte3);	
	pci_read_config_byte(dev, IT8212_PCI_BaseClassCode, &byte4);
	ITE_DBG("08h   %02x %02x %02x %02x\n", byte1, byte2, byte3, byte4);

	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &byte1);	
	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &byte2);
	pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte3);	
	pci_read_config_byte(dev, PCI_BIST, &byte4);
	ITE_DBG("0Ch   %02x %02x %02x %02x\n", byte1, byte2, byte3, byte4);

	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dword);
	ITE_DBG("10h   %08x\n", dword);
	
	pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &dword);
	ITE_DBG("14h   %08x\n", dword);

	pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &dword);
	ITE_DBG("18h   %08x\n", dword);
	
	pci_read_config_dword(dev, PCI_BASE_ADDRESS_3, &dword);
	ITE_DBG("1Ch   %08x\n", dword);

	pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &dword);
	ITE_DBG("20h   %08x\n", dword);

	ITE_DBG("24h   --------\n");
	ITE_DBG("28h   --------\n");
	
	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &word1);
	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &word2);
	ITE_DBG("2Ch   %04x %04x\n", word1, word2);

	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &dword);
	ITE_DBG("30h   %08x\n", dword);

	pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &byte1);
	ITE_DBG("34h   %02x -- -- --\n", byte1);

	ITE_DBG("38h   --------\n");

	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &byte1);
	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &byte2);	
	pci_read_config_byte(dev, PCI_MIN_GNT, &byte3);
	pci_read_config_byte(dev, PCI_MAX_LAT, &byte4);
	ITE_DBG("3Ch   %02x %02x %02x %02x\n", byte1, byte2, byte3, byte4);

	pci_read_config_word(dev, IT8212_PCI_IdeIoCONFIG, &word1);
	pci_read_config_byte(dev, IT8212_PCI_IdeDrivingCURRENT, &byte1);	
	pci_read_config_byte(dev, IT8212_PCI_IdeVirtualChannelEXIST, &byte2);
	ITE_DBG("40h   %04x %02x %02x\n", word1, byte1, byte2);

	pci_read_config_dword(dev, IT8212_PCI_PciBurstTHRESHOLD, &dword);
	ITE_DBG("44h   %08x\n", dword);

	pci_read_config_byte(dev, IT8212_PCI_Pll1CONTROL, &byte1);
	pci_read_config_byte(dev, IT8212_PCI_Pll2CONTROL, &byte2);
	ITE_DBG("48h   %02x %02x -- --\n", byte1, byte2);

	pci_read_config_dword(dev, IT8212_PCI_IdeBusSkewCONTROL, &dword);
	ITE_DBG("4Ch   %08x\n", dword);

	pci_read_config_byte(dev, IT8212_PCI_PciModeCONTROL, &byte1);
	pci_read_config_byte(dev, IT8212_PCI_RaidCONTROL, &byte2);
	pci_read_config_word(dev, IT8212_PCI_RaidTransferSectorCOUNT, &word1);
	ITE_DBG("50h   %02x %02x %04x\n", byte1, byte2, word1);

	pci_read_config_byte(dev, IT8212_PCI_PciModePrimPioDmaTIMING, &byte1);
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimDrive0UdmaTIMING, &byte2);	
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimDrive1UdmaTIMING, &byte3);
	ITE_DBG("54h   %02x -- %02x %02x\n", byte1, byte2, byte3);

	pci_read_config_byte(dev, IT8212_PCI_PciModeSecPioDmaTIMING, &byte1);	
	pci_read_config_byte(dev, IT8212_PCI_PciModeSecDrive0UdmaTIMING, &byte2);
	pci_read_config_byte(dev, IT8212_PCI_PciModeSecDrive1UdmaTIMING, &byte3);
	ITE_DBG("58h   %02x -- %02x %02x\n", byte1, byte2, byte3);

	pci_read_config_byte(dev, IT8212_PCI_TestMODE, &byte1);
	pci_read_config_byte(dev, IT8212_PCI_CpuNmiCONTROL, &byte2);	
	pci_read_config_byte(dev, IT8212_PCI_CpuCONTROL, &byte3);
	ITE_DBG("5Ch   %02x %02x %02x --\n", byte1, byte2, byte3);

	ITE_DBG("60h   --------\n");
	ITE_DBG("7Fh   --------\n");

	pci_read_config_byte(dev, IT8212_PCI_CapIDENTIFIER, &byte1);
	pci_read_config_byte(dev, IT8212_PCI_NextItemPOINTER, &byte2);
	pci_read_config_word(dev, IT8212_PCI_PowerManageCAP, &word1);
	ITE_DBG("80h   %02x %02x %04x\n", byte1, byte2, word1);

	pci_read_config_word(dev, IT8212_PCI_PowerManageControlSTATUS, &word1);
	pci_read_config_byte(dev, IT8212_PCI_BridgeSUPPORT, &byte2);
	pci_read_config_byte(dev, IT8212_PCI_DATA, &byte2);
	ITE_DBG("84h   %04x %02x %02x\n", word1, byte1, byte2);
}


/************************************************************************
 * Show it8212 device information
 ************************************************************************/

static char *it8212_deviceInfo(char *buffer, struct pci_dev *dev)
{
	u8 	pcicr;
	u16	iocfg;
	char *p = buffer;

//	ITE_KDBG("(%s)\n", dev->name);
 
	pci_read_config_word(dev, IT8212_PCI_IdeIoCONFIG, &iocfg);
	pci_read_config_byte(dev, IT8212_PCI_PciModeCONTROL, &pcicr);

	p += sprintf(p, "-----------------------------------  IT8212  -----------------------------------\n");
	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
	p += sprintf(p, "                %s                         %s\n",
		(iocfg&0x8000)?"enabled ":"disabled",
		(iocfg&0x4000)?"enabled ":"disabled");
	p += sprintf(p, "Clock :         %s                            %s\n",
		(pcicr&0x02)?  "50Mhz":"66Mhz",
		(pcicr&0x04)?  "50Mhz":"66Mhz");
	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
	p += sprintf(p, "Cable Report:    %s              %s             %s               %s\n",					 
		(iocfg&0x0010)?"80p":"40p",(iocfg&0x0020)?"80p":"40p",
		(iocfg&0x0040)?"80p":"40p",(iocfg&0x0080)?"80p":"40p");
	p += sprintf(p, "TransferMode:   %s       %s      %s        %s\n",					 
		(pcicr&0x08)?"MW DMA   ":"Ultra DMA",(pcicr&0x10)?"MW DMA   ":"Ultra DMA",
		(pcicr&0x20)?"MW DMA   ":"Ultra DMA",(pcicr&0x40)?"MW DMA   ":"Ultra DMA");

	return (char *)p;
}


/************************************************************************
 *
 ************************************************************************/

void it8212_showIdeDrive(ide_drive_t *drive)
{
	struct hd_driveid *id = drive->id;

	ITE_KDBG("(%s)\n", drive->name);
	
	ITE_DBG("disk drive %s info\n", drive->name);
	ITE_DBG("  capability     %02x\n", id->capability);
	ITE_DBG("  tPIO           %02x\n", id->tPIO);
	ITE_DBG("  tDMA           %02x\n", id->tDMA);
	ITE_DBG("  field_valid    %04x\n", id->field_valid);
	ITE_DBG("  dma_1word      %04x\n", id->dma_1word);
	ITE_DBG("  dma_mword      %04x\n", id->dma_mword);
	ITE_DBG("  eide_pio_modes %04x\n", id->eide_pio_modes);
	ITE_DBG("  dma_ultra      %04x\n", id->dma_ultra);
	ITE_DBG("  hw_config      %04x\n", id->hw_config);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_showIdeHwif(ide_hwif_t *hwif)
{
	ITE_KDBG("(%s)\n", hwif->name);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_showPciDev(struct pci_dev *dev)
{
//	ITE_KDBG("(%s)\n", dev->name);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_enableDriveInterrupt(ide_drive_t *drive, byte driveDn)
{
	ITE_KDBG("(%s, %d)\n", drive->name, driveDn);

	OUT_BYTE((driveDn << 4) | 0xa0, IDE_SELECT_REG);
	OUT_BYTE(0x00, IDE_CONTROL_REG);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_disableDriveInterrupt(ide_drive_t *drive, byte driveDn)
{
	ITE_KDBG("(%s, %d)\n", drive->name, driveDn);

	OUT_BYTE((driveDn << 4) | 0xa0, IDE_SELECT_REG);
	OUT_BYTE(0x02, IDE_CONTROL_REG);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_clearDriveIntStatus(ide_drive_t *drive)
{
	u32 busMasterBase = ((ide_hwif_t *)(drive->hwif))->dma_base;

	ITE_KDBG("(%s)\n", drive->name);

	if (busMasterBase)
	{
		outb(inb(busMasterBase + 0x2) | 0x04, busMasterBase + 0x2);

		it8212_enableDriveInterrupt(drive, drive->dn);
	}
}


/************************************************************************
 *
 ************************************************************************/

int it8212_getHsbIndex(u8 value)
{
	int index = (value) ? 7 : 0;

	ITE_KDBG("(%02x)\n", value);

	if (value)
	{
		while ((value & 0x80) == 0)
		{
			value <<= 1;
			index--;
		}
	}

	ITE_DBG(" HSB index %d\n", index);

	return index;
}


/************************************************************************
 *
 ************************************************************************/

void it8212_setDriveTiming(int channel, int drive)
{
	u8 modeControl;
	u8 udmaTiming;
	u8 pioDmaTiming;
	int channelOffset;
	struct pci_dev *dev;
	drive_config_t *driveConfig;

	ITE_KDBG("(ch%d, dr%d)\n", channel, drive);

	dev = it8212.device;
	driveConfig = &(it8212.config[channel][drive]);
	channelOffset = 4 * channel;

	pci_read_config_byte(dev, IT8212_PCI_PciModeCONTROL, &modeControl);
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimPioDmaTIMING + channelOffset, &pioDmaTiming);
	pci_read_config_byte(dev, IT8212_PCI_PciModePrimDrive0UdmaTIMING + channelOffset, &udmaTiming);

	if (driveConfig->type == UDMA_MODE)
	{
		udmaTiming = driveConfig->udmaTiming;
		modeControl &= modeControlMaskVerBX[channel][drive][UdmaMaskINDEX];
	}
	else if (driveConfig->type == DMA_MODE)
	{
		pioDmaTiming = driveConfig->pioDmaTiming;
		modeControl |= modeControlMaskVerBX[channel][drive][DmaMaskINDEX];
	}
	else
	{
		pioDmaTiming = driveConfig->pioDmaTiming;
	}

	modeControl &= modeControlMaskVerBX[channel][drive][ClockMaskINDEX];
	modeControl |= driveConfig->clock << (channel + 1);

	pci_write_config_byte(dev, IT8212_PCI_PciModeCONTROL, modeControl);
	pci_write_config_byte(dev, IT8212_PCI_PciModePrimPioDmaTIMING + channelOffset, pioDmaTiming);
	pci_write_config_byte(dev, IT8212_PCI_PciModePrimDrive0UdmaTIMING + channelOffset, udmaTiming);
	pci_write_config_byte(dev, IT8212_PCI_PciModePrimDrive1UdmaTIMING + channelOffset, udmaTiming);

#ifdef IT8212_DEBUG
	it8212_showDriveTiming(channel);
#endif
}


/************************************************************************
 *
 ************************************************************************/

void it8212_dma_check(ide_drive_t *drive)
{
	int index;
	int driveNum;
	int channelNum;
	struct hd_driveid *id;
	drive_config_t *driveConfig;

	ITE_KDBG("(%s) dn%d\n", drive->name, drive->dn);

#ifdef IT8212_DEBUG
	it8212_showIdeDrive(drive);
	it8212_showIdeRegisters(drive->hwif);
#endif

	id = drive->id;
	driveNum = drive->dn % NofDRIVE;
	channelNum = drive->dn / NofDRIVE;
	driveConfig = &(it8212.config[channelNum][driveNum]);

	if (id->field_valid & 0x04)		// DMA capable
	{
		if (id->dma_ultra)			// UDMA mode
		{
			index = it8212_getHsbIndex(id->dma_ultra);

			if (udmaConfigValue[index][ModeINDEX] > XFER_UDMA_2)
			{
				index = XFER_UDMA_2_INDEX;
			}

			driveConfig->type = UDMA_MODE;
			driveConfig->mode = udmaConfigValue[index][ModeINDEX];
			driveConfig->clock = udmaConfigValue[index][ClockINDEX];
			driveConfig->udmaTiming = udmaConfigValue[index][TimingINDEX];
		}
		else						// MW DMA mode
		{
			index = it8212_getHsbIndex(id->dma_mword);

			driveConfig->type = DMA_MODE;
			driveConfig->mode = dmaConfigValue[index][ModeINDEX];
			driveConfig->clock = dmaConfigValue[index][ClockINDEX];
			driveConfig->pioDmaTiming = dmaConfigValue[index][TimingINDEX];
		}
	}
	else if (id->field_valid & 0x02)	// PIO only
	{
		if (id->eide_pio_modes)
		{
			index = it8212_getHsbIndex(id->eide_pio_modes) + XFER_PIO_3_INDEX;
		}
		else
		{
			index = XFER_PIO_2_INDEX;
		}

		driveConfig->type = PIO_MODE;
		driveConfig->mode = pioConfigValue[index][ModeINDEX];
		driveConfig->clock = pioConfigValue[index][ClockINDEX];
		driveConfig->pioDmaTiming = pioConfigValue[index][TimingINDEX];
	}

#if 0	// force to PIO4 mode for testing
	index = XFER_PIO_4_INDEX;

	driveConfig->type = PIO_MODE;
	driveConfig->mode = pioConfigValue[index][ModeINDEX];
	driveConfig->clock = pioConfigValue[index][ClockINDEX];
	driveConfig->pioDmaTiming = pioConfigValue[index][TimingINDEX];
#endif

#if 0	// force to MWDMA mode for testing
	index = XFER_MW_DMA_2_INDEX;

	driveConfig->type = DMA_MODE;
	driveConfig->mode = dmaConfigValue[index][ModeINDEX];
	driveConfig->clock = dmaConfigValue[index][ClockINDEX];
	driveConfig->pioDmaTiming = dmaConfigValue[index][TimingINDEX];
#endif

#if 0	// force to UDMA mode for testing
	index = XFER_UDMA_2_INDEX;

	driveConfig->type = UDMA_MODE;
	driveConfig->mode = udmaConfigValue[index][ModeINDEX];
	driveConfig->clock = udmaConfigValue[index][ClockINDEX];
	driveConfig->udmaTiming = udmaConfigValue[index][TimingINDEX];
#endif

	ITE_DBG("type		%02x\n", driveConfig->type);
	ITE_DBG("mode		%02x\n", driveConfig->mode);
	ITE_DBG("clock		%02x\n", driveConfig->clock);
	ITE_DBG("udmaTiming	%02x\n", driveConfig->udmaTiming);
	ITE_DBG("pioDmaTiming	%02x\n", driveConfig->pioDmaTiming);

	it8212_setDriveTiming(channelNum, driveNum);

	ide_config_drive_speed(drive, driveConfig->mode);

	it8212_clearDriveIntStatus(drive);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_initIdeRegisters(ide_hwif_t *hwif)
{
	u8 status;
	u32 busMasterBase = hwif->dma_base;

	ITE_KDBG("(%s)\n", hwif->name);

	if (busMasterBase)
	{

//		outb(0x60, busMasterBase + 0x2);
		outb(0x64, busMasterBase + 0x2);

//		outb(0x01, busMasterBase + 0x0);

		if ( (status = inb(busMasterBase + 2)) != 0x60)
		{
			ITE_DBG("Can't set Drive0/1 DMA -- 02h  %02x\n\n", status);
		}

//		it8212_disableDriveInterrupt(&(hwif->drives[1]), 1);
//		it8212_disableDriveInterrupt(&(hwif->drives[0]), 0);
	}
	else
	{
		ITE_DBG("Can't turn on DMA transfer mode\n");
	}
}


/************************************************************************
 *
 ************************************************************************/

void it8212_initPciRegisters(struct pci_dev *dev)
{
//	ITE_KDBG("(%s)\n", dev->name);

	pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
	pci_write_config_byte(dev, IT8212_PCI_CpuCONTROL, 0x01);
	pci_write_config_byte(dev, IT8212_PCI_PciModeCONTROL, 0x00);
	pci_write_config_word(dev, PCI_COMMAND, 0x0047);
	pci_write_config_word(dev, IT8212_PCI_IdeIoCONFIG, 0xA0F3);
	pci_write_config_dword(dev, IT8212_PCI_IdeBusSkewCONTROL, 0x02040204);
	pci_write_config_byte(dev, IT8212_PCI_IdeDrivingCURRENT, 0x36);
	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x00);
}


/************************************************************************
 *
 ************************************************************************/

void it8212_init8212Channel(ide_hwif_t *hwif)
{
	byte channel = hwif->channel;

	ITE_KDBG("(%s) ch%d\n", hwif->name, channel);

	it8212.hwif[channel] = hwif;
	it8212.drive[channel][0] = &(hwif->drives[0]);
	it8212.drive[channel][1] = &(hwif->drives[1]);

	it8212_initIdeRegisters(hwif);

	it8212_setDriveTiming(channel, DRIVE1);
	it8212_setDriveTiming(channel, DRIVE0);

#ifdef IT8212_DEBUG
	it8212_showIdeRegisters(hwif);
	it8212_showIdeHwif(hwif);
#endif
}


/************************************************************************
 *
 ************************************************************************/

void it8212_init8212(struct pci_dev *dev)
{
	int i, j;
	drive_config_t *drive;

//	ITE_KDBG("(%s)\n", dev->name);

	it8212.device = dev;

	for (i = 0; i < NofCHANNEL; i++)
	{
		for (j = 0; j < NofDRIVE; j++)
		{
			drive = &(it8212.config[i][j]);
		
			drive->type = UDMA_MODE;
			drive->mode = XFER_UDMA_2;
			drive->clock = CLOCK66;
			drive->udmaTiming = udmaConfigValue[XFER_UDMA_2_INDEX][TimingINDEX];
			drive->pioDmaTiming = pioConfigValue[XFER_PIO_3_INDEX][TimingINDEX];
		}
	}

	it8212_initPciRegisters(dev);

#ifdef IT8212_DEBUG
	it8212_showPciRegisters(dev);
	it8212_showPciDev(dev);
#endif
}


/************************************************************************
 * IT8212 get driver info function
 ************************************************************************/

int it8212_get_info(char *buffer, char **addr, off_t offset, int count)
{
	char *p;

	p = it8212_deviceInfo(buffer, it8212.device);

	return (p - buffer);	/* => must be less than 4k! */
}


/************************************************************************
 * 
 ************************************************************************/

int it8212_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
	ITE_KDBG("(%s, %d)\n", drive->name, func);

	switch (func) 
    {
		case ide_dma_check:
			it8212_dma_check(drive);
			break;
     
		case ide_dma_timeout:
			if (HWIF(drive)->resetproc != NULL)
			{
				HWIF(drive)->resetproc(drive);
			}
			break;

		default:
			break;
	}

	return ide_dmaproc(func, drive);	/* Use standard DMA stuff	*/
}


/************************************************************************
 * IT8212 reset drive function
 ************************************************************************/

void it8212_reset(ide_drive_t *drive)
{
	ITE_KDBG("(%s)\n", drive->name);

	it8212_initIdeRegisters(drive->hwif);
}


/************************************************************************
 * IDE init function
 ************************************************************************/

void __init ide_init_it8212(ide_hwif_t *hwif)
{
	ITE_KDBG("(%s)\n", hwif->name);

	hwif->chipset = ide_it8212;
	hwif->resetproc = &it8212_reset;

	if (hwif->dma_base) 
    {
 		hwif->dmaproc = &it8212_dmaproc;
		hwif->autodma = 1;
    }
	else 
    {
		hwif->drives[0].autotune = 1;
		hwif->drives[1].autotune = 1;
		hwif->autodma = 0;
    }

	it8212_init8212Channel(hwif);
}


/************************************************************************
 * ATA init function
 ************************************************************************/

unsigned int __init ata66_it8212(ide_hwif_t *hwif)
{
	
	u16 mask;
	u16 iocfg;;

	ITE_KDBG("(%s)\n", hwif->name);

	mask = (hwif->channel) ? (1 << 3) : (1 << 2);
	pci_read_config_word(hwif->pci_dev, 0x40, &iocfg);
	iocfg &= mask;

	ITE_DBG("CBLID signal %d\n", iocfg);
 
	return ((iocfg) ? 0 : 1);
}


/************************************************************************
 * PCI init function
 ************************************************************************/

unsigned int __init pci_init_it8212(struct pci_dev *dev, const char *name)
{
	ITE_KDBG("(%s %02x:%02x)\n", name, dev->bus->number, dev->devfn);

	it8212_proc = 1;
	it8212_display_info = &it8212_get_info;

	it8212_init8212(dev);

	return dev->irq;
}
