⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd640.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/ide/pci/cmd640.c		Version 1.02  Sep 01, 1996 * *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below) *//* *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov) *  			mlord@pobox.com (Mark Lord) * *  See linux/MAINTAINERS for address of current maintainer. * *  This file provides support for the advanced features and bugs *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip. * *  These chips are basically fucked by design, and getting this driver *  to work on every motherboard design that uses this screwed chip seems *  bloody well impossible.  However, we're still trying. * *  Version 0.97 worked for everybody. * *  User feedback is essential.  Many thanks to the beta test team: * *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com, *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz, *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de, *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de, *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net, *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net, *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu, *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com, *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net, *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com *  liug@mama.indstate.edu, and others. * *  Version 0.01	Initial version, hacked out of ide.c, *			and #include'd rather than compiled separately. *			This will get cleaned up in a subsequent release. * *  Version 0.02	Fixes for vlb initialization code, enable prefetch *			for versions 'B' and 'C' of chip by default, *			some code cleanup. * *  Version 0.03	Added reset of secondary interface, *			and black list for devices which are not compatible *			with prefetch mode. Separate function for setting *			prefetch is added, possibly it will be called some *			day from ioctl processing code. * *  Version 0.04	Now configs/compiles separate from ide.c * *  Version 0.05	Major rewrite of interface timing code. *			Added new function cmd640_set_mode to set PIO mode *			from ioctl call. New drives added to black list. * *  Version 0.06	More code cleanup. Prefetch is enabled only for *			detected hard drives, not included in prefetch *			black list. * *  Version 0.07	Changed to more conservative drive tuning policy. *			Unknown drives, which report PIO < 4 are set to *			(reported_PIO - 1) if it is supported, or to PIO0. *			List of known drives extended by info provided by *			CMD at their ftp site. * *  Version 0.08	Added autotune/noautotune support. * *  Version 0.09	Try to be smarter about 2nd port enabling. *  Version 0.10	Be nice and don't reset 2nd port. *  Version 0.11	Try to handle more weird situations. * *  Version 0.12	Lots of bug fixes from Laszlo Peter *			irq unmasking disabled for reliability. *			try to be even smarter about the second port. *			tidy up source code formatting. *  Version 0.13	permit irq unmasking again. *  Version 0.90	massive code cleanup, some bugs fixed. *			defaults all drives to PIO mode0, prefetch off. *			autotune is OFF by default, with compile time flag. *			prefetch can be turned OFF/ON using "hdparm -p8/-p9" *			 (requires hdparm-3.1 or newer) *  Version 0.91	first release to linux-kernel list. *  Version 0.92	move initial reg dump to separate callable function *			change "readahead" to "prefetch" to avoid confusion *  Version 0.95	respect original BIOS timings unless autotuning. *			tons of code cleanup and rearrangement. *			added CONFIG_BLK_DEV_CMD640_ENHANCED option *			prevent use of unmask when prefetch is on *  Version 0.96	prevent use of io_32bit when prefetch is off *  Version 0.97	fix VLB secondary interface for sjd@slip.net *			other minor tune-ups:  0.96 was very good. *  Version 0.98	ignore PCI version when disabled by BIOS *  Version 0.99	display setup/active/recovery clocks with PIO mode *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7" *			 ("fast" is necessary for 32bit I/O in some systems) *  Version 1.02	fix bug that resulted in slow "setup times" *			 (patch courtesy of Zoltan Hidvegi) */#undef REALLY_SLOW_IO		/* most systems can safely undef this */#define CMD640_PREFETCH_MASKS 1#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/ide.h>#include <linux/init.h>#include <asm/io.h>#include "ide_modes.h"/* * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb */int cmd640_vlb = 0;/* * CMD640 specific registers definition. */#define VID		0x00#define DID		0x02#define PCMD		0x04#define   PCMD_ENA	0x01#define PSTTS		0x06#define REVID		0x08#define PROGIF		0x09#define SUBCL		0x0a#define BASCL		0x0b#define BaseA0		0x10#define BaseA1		0x14#define BaseA2		0x18#define BaseA3		0x1c#define INTLINE		0x3c#define INPINE		0x3d#define	CFR		0x50#define   CFR_DEVREV		0x03#define   CFR_IDE01INTR		0x04#define	  CFR_DEVID		0x18#define	  CFR_AT_VESA_078h	0x20#define	  CFR_DSA1		0x40#define	  CFR_DSA0		0x80#define CNTRL		0x51#define	  CNTRL_DIS_RA0		0x40#define   CNTRL_DIS_RA1		0x80#define	  CNTRL_ENA_2ND		0x08#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 DRWTIM23	0x58#define BRST		0x59/* * Registers and masks for easy access by drive index: */static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};#ifdef CONFIG_BLK_DEV_CMD640_ENHANCEDstatic u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};/* * Current cmd640 timing values for each drive. * The defaults for each are the slowest possible timings. */static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED *//* * These are initialized to point at the devices we control */static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;static ide_drive_t *cmd_drives[4];/* * Interface to access cmd640x registers */static unsigned int cmd640_key;static void (*__put_cmd640_reg)(u16 reg, u8 val);static u8 (*__get_cmd640_reg)(u16 reg);/* * This is read from the CFR reg, and is used in several places. */static unsigned int cmd640_chip_version;/* * The CMD640x chip does not support DWORD config write cycles, but some * of the BIOSes use them to implement the config services. * Therefore, we must use direct IO instead. *//* PCI method 1 access */static void put_cmd640_reg_pci1 (u16 reg, u8 val){	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);	outb_p(val, (reg & 3) | 0xcfc);}static u8 get_cmd640_reg_pci1 (u16 reg){	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);	return inb_p((reg & 3) | 0xcfc);}/* PCI method 2 access (from CMD datasheet) */static void put_cmd640_reg_pci2 (u16 reg, u8 val){	outb_p(0x10, 0xcf8);	outb_p(val, cmd640_key + reg);	outb_p(0, 0xcf8);}static u8 get_cmd640_reg_pci2 (u16 reg){	u8 b;	outb_p(0x10, 0xcf8);	b = inb_p(cmd640_key + reg);	outb_p(0, 0xcf8);	return b;}/* VLB access */static void put_cmd640_reg_vlb (u16 reg, u8 val){	outb_p(reg, cmd640_key);	outb_p(val, cmd640_key + 4);}static u8 get_cmd640_reg_vlb (u16 reg){	outb_p(reg, cmd640_key);	return inb_p(cmd640_key + 4);}static u8 get_cmd640_reg(u16 reg){	u8 b;	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	b = __get_cmd640_reg(reg);	spin_unlock_irqrestore(&ide_lock, flags);	return b;}static void put_cmd640_reg(u16 reg, u8 val){	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	__put_cmd640_reg(reg,val);	spin_unlock_irqrestore(&ide_lock, flags);}static int __init match_pci_cmd640_device (void){	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};	unsigned int i;	for (i = 0; i < 4; i++) {		if (get_cmd640_reg(i) != ven_dev[i])			return 0;	}#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {		printk("ide: cmd640 on PCI disabled by BIOS\n");		return 0;	}#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */	return 1; /* success */}/* * Probe for CMD640x -- pci method 1 */static int __init probe_for_cmd640_pci1 (void){	__get_cmd640_reg = get_cmd640_reg_pci1;	__put_cmd640_reg = put_cmd640_reg_pci1;	for (cmd640_key = 0x80000000;	     cmd640_key <= 0x8000f800;	     cmd640_key += 0x800) {		if (match_pci_cmd640_device())			return 1; /* success */	}	return 0;}/* * Probe for CMD640x -- pci method 2 */static int __init probe_for_cmd640_pci2 (void){	__get_cmd640_reg = get_cmd640_reg_pci2;	__put_cmd640_reg = put_cmd640_reg_pci2;	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {		if (match_pci_cmd640_device())			return 1; /* success */	}	return 0;}/* * Probe for CMD640x -- vlb */static int __init probe_for_cmd640_vlb (void){	u8 b;	__get_cmd640_reg = get_cmd640_reg_vlb;	__put_cmd640_reg = put_cmd640_reg_vlb;	cmd640_key = 0x178;	b = get_cmd640_reg(CFR);	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {		cmd640_key = 0x78;		b = get_cmd640_reg(CFR);		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))			return 0;	}	return 1; /* success */}/* *  Returns 1 if an IDE interface/drive exists at 0x170, *  Returns 0 otherwise. */static int __init secondary_port_responding (void){	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */	udelay(100);	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */		udelay(100);		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {			spin_unlock_irqrestore(&ide_lock, flags);			return 0; /* nothing responded */		}	}	spin_unlock_irqrestore(&ide_lock, flags);	return 1; /* success */}#ifdef CMD640_DUMP_REGS/* * Dump out all cmd640 registers.  May be called from ide.c */static void cmd640_dump_regs (void){	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;	/* Dump current state of chip registers */	printk("ide: cmd640 internal register dump:");	for (; reg <= 0x59; reg++) {		if (!(reg & 0x0f))			printk("\n%04x:", reg);		printk(" %02x", get_cmd640_reg(reg));	}	printk("\n");}#endif/* * Check whether prefetch is on for a drive, * and initialize the unmask flags for safe operation. */static void __init check_prefetch (unsigned int index){	ide_drive_t *drive = cmd_drives[index];	u8 b = get_cmd640_reg(prefetch_regs[index]);	if (b & prefetch_masks[index]) {	/* is prefetch off? */		drive->no_unmask = 0;		drive->no_io_32bit = 1;		drive->io_32bit = 0;	} else {#if CMD640_PREFETCH_MASKS		drive->no_unmask = 1;		drive->unmask = 0;#endif		drive->no_io_32bit = 0;	}}/* * Figure out which devices we control */static void __init setup_device_ptrs (void){	unsigned int i;	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */	for (i = 0; i < MAX_HWIFS; i++) {		ide_hwif_t *hwif = &ide_hwifs[i];		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)				cmd_hwif0 = hwif;			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)				cmd_hwif1 = hwif;		}	}	cmd_drives[0] = &cmd_hwif0->drives[0];	cmd_drives[1] = &cmd_hwif0->drives[1];	cmd_drives[2] = &cmd_hwif1->drives[0];	cmd_drives[3] = &cmd_hwif1->drives[1];}#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED/* * Sets prefetch mode for a drive.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -