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

📄 ide.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif /* CONFIG_BLK_DEV_IDETAPE */	for (unit = 0; unit < MAX_DRIVES; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];		drive->select.all		= (unit<<4)|0xa0;		drive->hwif			= hwif;		drive->ctl			= 0x08;		drive->ready_stat		= READY_STAT;		drive->bad_wstat		= BAD_W_STAT;		drive->special.b.recalibrate	= 1;		drive->special.b.set_geometry	= 1;		drive->name[0]			= 'h';		drive->name[1]			= 'd';#ifdef MACH		drive->name[2]			= '0' + (index * MAX_DRIVES) + unit;#else		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;#endif	}}/* * init_ide_data() sets reasonable default values into all fields * of all instances of the hwifs and drives, but only on the first call. * Subsequent calls have no effect (they don't wipe out anything). * * This routine is normally called at driver initialization time, * but may also be called MUCH earlier during kernel "command-line" * parameter processing.  As such, we cannot depend on any other parts * of the kernel (such as memory allocation) to be functioning yet. * * This is too bad, as otherwise we could dynamically allocate the * ide_drive_t structs as needed, rather than always consuming memory * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */#define MAGIC_COOKIE 0x12345678static void init_ide_data (void){	unsigned int index;	static unsigned long magic_cookie = MAGIC_COOKIE;	if (magic_cookie != MAGIC_COOKIE)		return;		/* already initialized */	magic_cookie = 0;	for (index = 0; index < MAX_HWIFS; ++index)		init_hwif_data(index);	idebus_parameter = 0;	system_bus_speed = 0;}/* * ide_system_bus_speed() returns what we think is the system VESA/PCI * bus speed (in Mhz).  This is used for calculating interface PIO timings. * The default is 40 for known PCI systems, 50 otherwise. * The "idebus=xx" parameter can be used to override this value. * The actual value to be used is computed/displayed the first time through. */int ide_system_bus_speed (void){	if (!system_bus_speed) {		if (idebus_parameter)			system_bus_speed = idebus_parameter;	/* user supplied value */#ifdef CONFIG_PCI		else if (pcibios_present())			system_bus_speed = 40;	/* safe default value for PCI */#endif /* CONFIG_PCI */		else			system_bus_speed = 50;	/* safe default value for VESA and PCI */		printk("ide: Assuming %dMhz system bus speed for PIO modes; override with idebus=xx\n", system_bus_speed);	}	return system_bus_speed;}#if SUPPORT_VLB_SYNC/* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data.  We call this * the "vlb_sync" sequence, which consists of three successive reads * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */static inline void do_vlb_sync (unsigned short port) {	(void) inb (port);	(void) inb (port);	(void) inb (port);}#endif /* SUPPORT_VLB_SYNC *//* * This is used for most PIO data transfers *from* the IDE interface */void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	unsigned short io_base  = HWIF(drive)->io_base;	unsigned short data_reg = io_base+IDE_DATA_OFFSET;	byte io_32bit = drive->io_32bit;	if (io_32bit) {#if SUPPORT_VLB_SYNC		if (io_32bit & 2) {			cli();			do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);			insl(data_reg, buffer, wcount);			if (drive->unmask)				sti();		} else#endif /* SUPPORT_VLB_SYNC */			insl(data_reg, buffer, wcount);	} else {#if SUPPORT_SLOW_DATA_PORTS		if (drive->slow) {			unsigned short *ptr = (unsigned short *) buffer;			while (wcount--) {				*ptr++ = inw_p(data_reg);				*ptr++ = inw_p(data_reg);			}		} else#endif /* SUPPORT_SLOW_DATA_PORTS */			insw(data_reg, buffer, wcount<<1);	}}/* * This is used for most PIO data transfers *to* the IDE interface */void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount){	unsigned short io_base  = HWIF(drive)->io_base;	unsigned short data_reg = io_base+IDE_DATA_OFFSET;	byte io_32bit = drive->io_32bit;	if (io_32bit) {#if SUPPORT_VLB_SYNC		if (io_32bit & 2) {			cli();			do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);			outsl(data_reg, buffer, wcount);			if (drive->unmask)				sti();		} else#endif /* SUPPORT_VLB_SYNC */			outsl(data_reg, buffer, wcount);	} else {#if SUPPORT_SLOW_DATA_PORTS		if (drive->slow) {			unsigned short *ptr = (unsigned short *) buffer;			while (wcount--) {				outw_p(*ptr++, data_reg);				outw_p(*ptr++, data_reg);			}		} else#endif /* SUPPORT_SLOW_DATA_PORTS */			outsw(data_reg, buffer, wcount<<1);	}}/* * The following routines are mainly used by the ATAPI drivers. * * These routines will round up any request for an odd number of bytes, * so if an odd bytecount is specified, be sure that there's at least one * extra byte allocated for the buffer. */void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount){	++bytecount;	ide_input_data (drive, buffer, bytecount / 4);	if ((bytecount & 0x03) >= 2)		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);}void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount){	++bytecount;	ide_output_data (drive, buffer, bytecount / 4);	if ((bytecount & 0x03) >= 2)		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);}/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive.  handler() points * at the appropriate code to handle the next interrupt, and a * timer is started to prevent us from waiting forever in case * something goes wrong (see the timer_expiry() handler later on). */void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout){	ide_hwgroup_t *hwgroup = HWGROUP(drive);#ifdef DEBUG	if (hwgroup->handler != NULL) {		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",			drive->name, hwgroup->handler, handler);	}#endif	hwgroup->handler       = handler;	hwgroup->timer.expires = jiffies + timeout;	add_timer(&(hwgroup->timer));}/* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" * value for this drive (from its reported identification information). * * Returns:	1 if lba_capacity looks sensible *		0 otherwise */static int lba_capacity_is_ok (struct hd_driveid *id){	unsigned long lba_sects   = id->lba_capacity;	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;	unsigned long _10_percent = chs_sects / 10;	/* very large drives (8GB+) may lie about the number of cylinders */	if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {		return 1;	/* lba_capacity is our only option */	}	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */	if ((lba_sects - chs_sects) < _10_percent)		return 1;	/* lba_capacity is good */	/* some drives have the word order reversed */	lba_sects = (lba_sects << 16) | (lba_sects >> 16);	if ((lba_sects - chs_sects) < _10_percent) {		id->lba_capacity = lba_sects;	/* fix it */		return 1;	/* lba_capacity is (now) good */	}	return 0;	/* lba_capacity value is bad */}/* * current_capacity() returns the capacity (in sectors) of a drive * according to its current geometry/LBA settings. */static unsigned long current_capacity (ide_drive_t  *drive){	struct hd_driveid *id = drive->id;	unsigned long capacity = drive->cyl * drive->head * drive->sect;	if (!drive->present)		return 0;#ifdef CONFIG_BLK_DEV_IDEFLOPPY	if (drive->media == ide_floppy)		return idefloppy_capacity(drive);#endif /* CONFIG_BLK_DEV_IDEFLOPPY */	if (drive->media != ide_disk)		return 0x7fffffff;	/* cdrom or tape */	drive->select.b.lba = 0;	/* Determine capacity, and use LBA if the drive properly supports it */	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {		if (id->lba_capacity >= capacity) {			capacity = id->lba_capacity;			drive->select.b.lba = 1;		}	}	return (capacity - drive->sect0);}/* * ide_geninit() is called exactly *once* for each major, from genhd.c, * at the beginning of the initial partition check for the drives. */static void ide_geninit (struct gendisk *gd){	unsigned int unit;	ide_hwif_t *hwif = gd->real_devices;	for (unit = 0; unit < gd->nr_real; ++unit) {		ide_drive_t *drive = &hwif->drives[unit];#ifdef CONFIG_BLK_DEV_IDECD		if (drive->present && drive->media == ide_cdrom)			ide_cdrom_setup(drive);#endif /* CONFIG_BLK_DEV_IDECD */#ifdef CONFIG_BLK_DEV_IDETAPE		if (drive->present && drive->media == ide_tape)			idetape_setup(drive);#endif /* CONFIG_BLK_DEV_IDETAPE */#ifdef CONFIG_BLK_DEV_IDEFLOPPY		if (drive->present && drive->media == ide_floppy)			idefloppy_setup(drive);#endif /* CONFIG_BLK_DEV_IDEFLOPPY */		drive->part[0].nr_sects = current_capacity(drive);		if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) ||		    !drive->part[0].nr_sects) {			drive->part[0].start_sect = -1; /* skip partition check */		}	}}/* * init_gendisk() (as opposed to ide_geninit) is called for each major device, * after probing for drives, to allocate partition tables and other data * structures needed for the routines in genhd.c.  ide_geninit() gets called * somewhat later, during the partition check. */static void init_gendisk (ide_hwif_t *hwif){	struct gendisk *gd, **gdp;	unsigned int unit, units, minors;	int *bs;	/* figure out maximum drive number on the interface */	for (units = MAX_DRIVES; units > 0; --units) {		if (hwif->drives[units-1].present)			break;	}	minors    = units * (1<<PARTN_BITS);	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);	memset(gd->part, 0, minors * sizeof(struct hd_struct));	/* cdroms and msdos f/s are examples of non-1024 blocksizes */	blksize_size[hwif->major] = bs;	for (unit = 0; unit < minors; ++unit)		*bs++ = BLOCK_SIZE;	for (unit = 0; unit < units; ++unit)		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];	gd->major	= hwif->major;		/* our major device number */	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */	gd->max_nr	= units;		/* max num real drives */	gd->nr_real	= units;		/* current num real drives */	gd->init	= ide_geninit;		/* initialization function */	gd->real_devices= hwif;			/* ptr to internal data */	gd->next	= NULL;			/* linked list of major devs */	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ;	hwif->gd = *gdp = gd;			/* link onto tail of list */}static void do_reset1 (ide_drive_t *, int);		/* needed below */#ifdef CONFIG_BLK_DEV_IDEATAPI/* * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an atapi drive reset operation. If the drive has not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static void atapi_reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	byte stat;	OUT_BYTE (drive->select.all, IDE_SELECT_REG);	udelay (10);	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {		printk("%s: ATAPI reset complete\n", drive->name);	} else {		if (jiffies < hwgroup->poll_timeout) {			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);			return;	/* continue polling */		}		hwgroup->poll_timeout = 0;	/* end of polling */		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);		do_reset1 (drive, 1);	/* do it the old fashioned way */		return;	}	hwgroup->poll_timeout = 0;	/* done polling */}#endif /* CONFIG_BLK_DEV_IDEATAPI *//* * reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static void reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	ide_hwif_t *hwif = HWIF(drive);	byte tmp;	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {		if (jiffies < hwgroup->poll_timeout) {			ide_set_handler (drive, &reset_pollfunc, HZ/20);			return;	/* continue polling */		}		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);	} else  {		printk("%s: reset: ", hwif->name);		if ((tmp = GET_ERR()) == 1)			printk("success\n");		else {#if FANCY_STATUS_DUMPS			printk("master: ");			switch (tmp & 0x7f) {				case 1: printk("passed");

⌨️ 快捷键说明

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