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

📄 ide-probe.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/block/ide-probe.c	Version 1.04  March 10, 1999 * *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below) *//* *  Mostly written by Mark Lord <mlord@pobox.com> *                and Gadi Oxman <gadio@netvision.net.il> * *  See linux/MAINTAINERS for address of current maintainer. * * This is the IDE probe module, as evolved from hd.c and ide.c. * * Version 1.00		move drive probing code from ide.c to ide-probe.c * Version 1.01		fix compilation problem for m68k * Version 1.02		increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot *			 by Andrea Arcangeli * Version 1.03		fix for (hwif->chipset == ide_4drives) * Version 1.04		fixed buggy treatments of known flash memory cards */#undef REALLY_SLOW_IO		/* most systems can safely undef this */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/malloc.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>#include "ide.h"#ifdef OSKIT/* This proto needs to be someplace else */int	oskit_linux_ofw_probe_ide(ide_hwif_t *hwif);#endifstatic inline void do_identify (ide_drive_t *drive, byte cmd){	int bswap = 1;	struct hd_driveid *id;	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */	ide__sti();	/* local CPU only */	ide_fix_driveid(id);#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)	/*	 * EATA SCSI controllers do a hardware ATA emulation:	 * Ignore them if there is a driver for them available.	 */	if ((id->model[0] == 'P' && id->model[1] == 'M')	 || (id->model[0] == 'S' && id->model[1] == 'K')) {		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);		drive->present = 0;		return;	}#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */	/*	 *  WIN_IDENTIFY returns little-endian info,	 *  WIN_PIDENTIFY *usually* returns little-endian info.	 */	if (cmd == WIN_PIDENTIFY) {		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */			bswap ^= 1;	/* Vertos drives may still be weird */	}	ide_fixstring (id->model,     sizeof(id->model),     bswap);	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */	printk("%s: %s, ", drive->name, id->model);	drive->present = 1;	/*	 * Check for an ATAPI device	 */	if (cmd == WIN_PIDENTIFY) {		byte type = (id->config >> 8) & 0x1f;		printk("ATAPI ");#ifdef CONFIG_BLK_DEV_PDC4030		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {			printk(" -- not supported on 2nd Promise port\n");			drive->present = 0;			return;		}#endif /* CONFIG_BLK_DEV_PDC4030 */		switch (type) {			case ide_floppy:				if (!strstr(id->model, "CD-ROM")) {					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))						printk("cdrom or floppy?, assuming ");					if (drive->media != ide_cdrom) {						printk ("FLOPPY");						break;					}				}				type = ide_cdrom;	/* Early cdrom models used zero */			case ide_cdrom:				printk ("CDROM");				drive->removable = 1;				break;			case ide_tape:				printk ("TAPE");				break;			case ide_optical:				printk ("OPTICAL");				drive->removable = 1;				break;			default:				printk("UNKNOWN (type %d)", type);				break;		}		printk (" drive\n");		drive->media = type;		return;	}	/*	 * Not an ATAPI device: looks like a "regular" hard disk	 */	if (id->config & (1<<7))		drive->removable = 1;	/*	 * Prevent long system lockup probing later for non-existant	 * slave drive if the hwif is actually a flash memory card of some variety:	 */	if (drive_is_flashcard(drive)) {		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];		mate->present = 0;		mate->noprobe = 1;	}	drive->media = ide_disk;	printk("ATA DISK drive\n");	return;}/* * Delay for *at least* 50ms.  As we don't know how much time is left * until the next tick occurs, we wait an extra tick to be safe. * This is used only during the probing/polling for drives at boot time. */static void delay_50ms (void){	unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;	while (0 < (signed long)(timeout - jiffies));}/* * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive * and waits for a response.  It also monitors irqs while this is * happening, in hope of automatically determining which one is * being used by the interface. * * Returns:	0  device was identified *		1  device timed-out (no response to identify request) *		2  device aborted the command (refused to identify itself) */static int try_to_identify (ide_drive_t *drive, byte cmd){	int rc;	ide_ioreg_t hd_status;	unsigned long timeout;	unsigned long irqs = 0;	byte s, a;	if (!HWIF(drive)->irq) {		/* already got an IRQ? */		probe_irq_off(probe_irq_on());	/* clear dangling irqs */		irqs = probe_irq_on();		/* start monitoring irqs */		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */	}	delay_50ms();				/* take a deep breath */	a = IN_BYTE(IDE_ALTSTATUS_REG);	s = IN_BYTE(IDE_STATUS_REG);	if ((a ^ s) & ~INDEX_STAT) {		printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);		hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */	} else		hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */#if CONFIG_BLK_DEV_PDC4030	if (IS_PDC4030_DRIVE) {		extern int pdc4030_cmd(ide_drive_t *, byte);		if (pdc4030_cmd(drive,PROMISE_IDENTIFY)) {			if (irqs)				(void) probe_irq_off(irqs);			return 1;		}	} else#endif /* CONFIG_BLK_DEV_PDC4030 */		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;	timeout += jiffies;	do {		if (0 < (signed long)(jiffies - timeout)) {			if (irqs)				(void) probe_irq_off(irqs);			return 1;	/* drive timed-out */		}		delay_50ms();		/* give drive a breather */	} while (IN_BYTE(hd_status) & BUSY_STAT);	delay_50ms();		/* wait for IRQ and DRQ_STAT */	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {		unsigned long flags;		__save_flags(flags);	/* local CPU only */		__cli();		/* local CPU only; some systems need this */		do_identify(drive, cmd); /* drive returned ID */		rc = 0;			/* drive responded with ID */		(void) GET_STAT();	/* clear drive IRQ */		__restore_flags(flags);	/* local CPU only */	} else		rc = 2;			/* drive refused ID */	if (!HWIF(drive)->irq) {		irqs = probe_irq_off(irqs);	/* get our irq number */		if (irqs > 0) {			HWIF(drive)->irq = irqs; /* save it for later */			irqs = probe_irq_on();			OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */			udelay(5);			(void) probe_irq_off(irqs);			(void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */			(void) GET_STAT();	/* clear drive IRQ */		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */			printk("%s: IRQ probe failed (%ld)\n", drive->name, irqs);#ifdef CONFIG_BLK_DEV_CMD640#ifdef CMD640_DUMP_REGS			if (HWIF(drive)->chipset == ide_cmd640) {				printk("%s: Hmmm.. probably a driver problem.\n", drive->name);				CMD640_DUMP_REGS;			}#endif /* CMD640_DUMP_REGS */#endif /* CONFIG_BLK_DEV_CMD640 */		}	}	return rc;}/* * do_probe() has the difficult job of finding a drive if it exists, * without getting hung up if it doesn't exist, without trampling on * ethernet cards, and without leaving any IRQs dangling to haunt us later. * * If a drive is "known" to exist (from CMOS or kernel parameters), * but does not respond right away, the probe will "hang in there" * for the maximum wait time (about 30 seconds), otherwise it will * exit much more quickly. * * Returns:	0  device was identified *		1  device timed-out (no response to identify request) *		2  device aborted the command (refused to identify itself) *		3  bad status from device (possible for ATAPI drives) *		4  probe was not attempted because failure was obvious */static int do_probe (ide_drive_t *drive, byte cmd){	int rc;	ide_hwif_t *hwif = HWIF(drive);	if (drive->present) {	/* avoid waiting for inappropriate probes */		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))			return 4;	}#ifdef DEBUG	printk("probing for %s: present=%d, media=%d, probetype=%s\n",		drive->name, drive->present, drive->media,		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");#endif	SELECT_DRIVE(hwif,drive);	delay_50ms();	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {		if (drive->select.b.unit != 0) {			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */			delay_50ms();		/* allow BUSY_STAT to assert & clear */		}		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */	}	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)	 || drive->present || cmd == WIN_PIDENTIFY)	{		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */			rc = try_to_identify(drive,cmd); /* failed: try again */		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {			unsigned long timeout;			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());			delay_50ms();			OUT_BYTE (drive->select.all, IDE_SELECT_REG);			delay_50ms();			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);			timeout = jiffies;			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))				delay_50ms();			rc = try_to_identify(drive, cmd);		}		if (rc == 1)			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());		(void) GET_STAT();		/* ensure drive irq is clear */	} else {		rc = 3;				/* not present or maybe ATAPI */	}	if (drive->select.b.unit != 0) {		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */		delay_50ms();		(void) GET_STAT();		/* ensure drive irq is clear */	}	return rc;}/* * probe_for_drive() tests for existence of a given drive using do_probe(). * * Returns:	0  no device was found *		1  device was found (note: drive->present might still be 0) */static inline byte probe_for_drive (ide_drive_t *drive){	if (drive->noprobe)			/* skip probing? */		return drive->present;	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */	}	if (!drive->present)		return 0;			/* drive not found */	if (drive->id == NULL) {		/* identification failed? */		if (drive->media == ide_disk) {			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",			 drive->name, drive->cyl, drive->head, drive->sect);		} else if (drive->media == ide_cdrom) {			printk("%s: ATAPI cdrom (?)\n", drive->name);		} else {			drive->present = 0;	/* nuke it */		}	}	return 1;	/* drive was found */}/* * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc * controller that is BIOS compatible with ST-506, and thus showing up in our * BIOS table, but not register compatible, and therefore not present in CMOS. * * Furthermore, we will assume that our ST-506 drives <if any> are the primary * drives in the system -- the ones reflected as drive 1 or 2.  The first * drive is stored in the high nibble of CMOS byte 0x12, the second in the low * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value * means we have an AT controller hard disk for that drive. * * Of course, there is no guarantee that either drive is actually on the * "primary" IDE interface, but we don't bother trying to sort that out here. * If a drive is not actually on the primary interface, then these parameters * will be ignored.  This results in the user having to supply the logical * drive geometry as a boot parameter for each drive not on the primary i/f. * * The only "perfect" way to handle this would be to modify the setup.[cS] code * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info * for us during initialization.  I have the necessary docs -- any takers?  -ml */static void probe_cmos_for_drives (ide_hwif_t *hwif){#ifdef __i386__	extern struct drive_info_struct drive_info;	byte cmos_disks, *BIOS = (byte *) &drive_info;	int unit;#ifdef CONFIG_BLK_DEV_PDC4030	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)		return;#endif /* CONFIG_BLK_DEV_PDC4030 */	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */	/* Extract drive geometry from CMOS+BIOS if not already setup */	for (unit = 0; unit < MAX_DRIVES; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];		if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;			drive->head  = drive->bios_head = *(BIOS+2);			drive->sect  = drive->bios_sect = *(BIOS+14);			drive->ctl   = *(BIOS+8);			drive->present = 1;		}		BIOS += 16;	}#endif}/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */static void probe_hwif (ide_hwif_t *hwif){	unsigned int unit;	unsigned long flags;#ifdef OSKIT_ARM32_SHARK

⌨️ 快捷键说明

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