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

📄 pc_floppy.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 2 页
字号:
	hut = (head_unload_time*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;	if (hut < 0x1)		hut = 0x1;	else if (hut > 0xf)		hut = hut_max_code;	cmd[0] = FD_SPECIFY;	cmd[1] = (srt << 4) | hut;	cmd[2] = (hlt << 1) | 1; /* Always disable DMA */	/* If these parameters did not change, just return with success */	if (!fdc_state.in_sync || fdc_state.spec1 != cmd[1] || fdc_state.spec2 != cmd[2]) {		/* Go ahead and set spec1 and spec2 */		output_command(cmd, 3);		/* FIXME how do I handle errors here... */#ifdef MDEBUG		printf("FD_SPECIFY(%hx, %hx)\n", cmd[1], cmd[2]);#endif	}} /* fdc_specify *//* * reset is done by pulling bit 2 of DOR low for a while (old FDCs), * or by setting the self clearing bit 7 of STATUS (newer FDCs) */static void reset_fdc(void){	unsigned char reply[MAX_REPLIES];	fdc_state.in_sync = 0;	/* Pseudo-DMA may intercept 'reset finished' interrupt.  */	/* Irrelevant for systems with true DMA (i386).          */	if (fdc_state.version >= FDC_82072A)		outb(0x80 | (fdc_state.dtr &3), FD_DSR);	else {		outb(fdc_state.dor & ~DOR_NO_RESET, FD_DOR);		udelay(FD_RESET_DELAY);		outb(fdc_state.dor, FD_DOR);	}	result(reply, MAX_REPLIES);}static void show_floppy(void){#ifdef MDEBUG	printf("\n");	printf("floppy driver state\n");	printf("-------------------\n");	printf("fdc_bytes: %hx %hx xx %hx %hx %hx xx %hx\n",		inb(FD_BASE + 0), inb(FD_BASE + 1),		inb(FD_BASE + 3), inb(FD_BASE + 4), inb(FD_BASE + 5), 		inb(FD_BASE + 7));	printf("status=%x\n", inb(FD_STATUS));	printf("\n");#endif}static void floppy_recalibrate(void){	unsigned char cmd[2];	unsigned char reply[MAX_REPLIES];	int nr, success;	success = 0;	do {#ifdef MDEBUG		printf("floppy_recalibrate\n");#endif		/* Send the recalibrate command to the controller.		 * We don't have interrupts or anything we can poll		 * so we have to guess when it is done.		 */		cmd[0] = FD_RECALIBRATE;		cmd[1] = 0;		if (output_command(cmd, 2) < 0)			continue;		/* Sleep for the maximum time the recalibrate command		 * can run.		 */		mdelay(80*DRIVE_H1440_SRT/1000);		/* Now call FD_SENSEI to end the command		 * and collect up the reply.		 */		if (output_byte(FD_SENSEI) < 0)			continue;		nr = result(reply, MAX_REPLIES);		/* Now see if we have succeeded in our seek */		success = 			/* We have the right size result */			(nr == 2) && 			/* The command didn't terminate in error */			((reply[0] & ST0_INTR) == ST0_INTR_OK) &&			/* We finished a seek */			(reply[0] & ST0_SE) &&			/* We are at cylinder 0 */			(reply[1] == 0);	} while(!success);	/* Remember we are at track 0 */	drive_state[FD_DRIVE].track = 0;}static int __floppy_seek(unsigned track){	unsigned char cmd[3];	unsigned char reply[MAX_REPLIES];	int nr, success;	unsigned distance, old_track;	/* Look up the old track and see if we need to	 * do anything.	 */	old_track = drive_state[FD_DRIVE].track;	if (old_track == track) {		return 1;	}	/* Compute the distance we are about to move,	 * We need to know this so we know how long to sleep... 	 */	distance = (old_track > track)?(old_track - track):(track - old_track);	distance += 1;       	/* Send the seek command to the controller.	 * We don't have interrupts or anything we can poll	 * so we have to guess when it is done.	 */	cmd[0] = FD_SEEK;	cmd[1] = FD_DRIVE;	cmd[2] = track;	if (output_command(cmd, 3) < 0)		return 0;		/* Sleep for the time it takes to step through distance tracks.	 */	mdelay(distance*DRIVE_H1440_SRT/1000);	/* Now call FD_SENSEI to end the command	 * and collect up the reply.	 */	cmd[0] = FD_SENSEI;	if (output_command(cmd, 1) < 0)		return 0;	nr = result(reply, MAX_REPLIES);	/* Now see if we have succeeded in our seek */	success = 		/* We have the right size result */		(nr == 2) && 		/* The command didn't terminate in error */		((reply[0] & ST0_INTR) == ST0_INTR_OK) &&		/* We finished a seek */		(reply[0] & ST0_SE) &&		/* We are at cylinder 0 */		(reply[1] == track);	if (success)		drive_state[FD_DRIVE].track = track;	else {#ifdef MDEBUG		printf("seek failed\n");		printf("nr = %d\n", nr);		printf("ST0 = %hx\n", reply[0]);		printf("PCN = %hx\n", reply[1]);		printf("status = %d\n", inb(FD_STATUS));#endif	}	return success;}static int floppy_seek(unsigned track){	unsigned old_track;	int result;	/* assume success */	result = 1;	/* Look up the old track and see if we need to	 * do anything.	 */	old_track = drive_state[FD_DRIVE].track;	if (old_track == track) {		return result;	}	/* For some reason seeking many tracks at once is	 * problematic so only seek a single track at a time.	 */	while(result && (old_track > track)) {		old_track--;		result = __floppy_seek(old_track);	}	while(result && (track > old_track)) {		old_track++;		result = __floppy_seek(old_track);	}	return result;}static int read_ok(unsigned head){	unsigned char results[7];	int result_ok;	int nr;	/* read back the read results */	nr = result(results, 7);	/* Now see if they say we are o.k. */	result_ok = 0;	/* Are my result bytes o.k.? */	if (nr == 7) {		/* Are we o.k. */		if ((results[0] & ST0_INTR) == ST0_INTR_OK) {			result_ok = 1;		}		/* Or did we get just an overflow error */		else if (((results[0] & ST0_INTR) == ST0_INTR_ERROR) && 			(results[1]== ST1_OR) &&			(results[2] == 0)) {			result_ok = 1;		}		/* Verify the reply had the correct head */		if (((results[0] & ST0_HA) >> 2) != head) {			result_ok = 0;		}		/* Verify the reply had the correct drive */		if (((results[0] & ST0_DS) != FD_DRIVE)) {			result_ok = 0;		}	}	if (!result_ok) {#ifdef MDEBUG		printf("result_bytes = %d\n", nr);		printf("ST0 = %hx\n", results[0]);		printf("ST1 = %hx\n", results[1]);		printf("ST2 = %hx\n", results[2]);		printf("  C = %hx\n", results[3]);		printf("  H = %hx\n", results[4]);		printf("  R = %hx\n", results[5]);		printf("  N = %hx\n", results[6]);#endif	}	return result_ok;}static int floppy_read_sectors(	char *dest, unsigned byte_offset, unsigned length,	unsigned sector, unsigned head, unsigned track){	/* MT  == Multitrack */	/* MFM == MFM or FM Mode */	/* SK  == Skip deleted data addres Mark */	/* HDS == Head number select */	/* DS0 == Disk Drive Select 0 */	/* DS1 == Disk Drive Select 1 */	/* C   == Cylinder number 0 - 255 */	/* H   == Head number */	/* R   == Record */	/* N   == The number of data bytes written in a sector */	/* EOT == End of Track */	/* GPL == Gap Length */	/* DTL == Data Length */	/* MT MFM  SK  0 1 1   0   0 */	/* 0  0    0   0 0 HDS DS1 DS0 */	/* C, H, R, N, EOT, GPL, DTL */	int i, status, result_ok;	int max_bytes, bytes_read;	int ret;	unsigned char cmd[9];	unsigned end_offset;	end_offset = byte_offset + length;	max_bytes = 512*(DISK_H1440_SECT - sector + 1);	if (byte_offset >= max_bytes) {		return 0;	}	cmd[0] = FD_READ | (((DISK_H1440_HEAD ==2)?1:0) << 6);	cmd[1] = (head << 2) | FD_DRIVE;	cmd[2] = track;	cmd[3] = head;	cmd[4] = sector;	cmd[5] = 2; /* 2^N *128 == Sector size.  Hard coded to 512 bytes */	cmd[6] = DISK_H1440_SECT;	cmd[7] = DISK_H1440_GAP;	cmd[8] = 0xff;	/* Output the command bytes */	if (output_command(cmd, 9) < 0)		return -1;	/* The execution stage begins when STATUS_READY&STATUS_NON_DMA is set */	do {#if 1		poll_interruptions();#endif		status = inb(FD_STATUS);		status &= STATUS_READY | STATUS_NON_DMA;	} while(status != (STATUS_READY|STATUS_NON_DMA));	for(i = 0; i < max_bytes; i++) {		unsigned char byte;		if ((status = wait_til_ready()) < 0) {			break;		}		status &= STATUS_READY|STATUS_DIR|STATUS_NON_DMA;		if (status != (STATUS_READY|STATUS_DIR|STATUS_NON_DMA)) {			break;		}		byte = inb(FD_DATA);		if ((i >= byte_offset) && (i < end_offset)) {			dest[i - byte_offset] = byte;		}	}	bytes_read = i;		/* The result stage begins when STATUS_NON_DMA is cleared */	while((status = inb(FD_STATUS)) & STATUS_NON_DMA) {		/* We get extra bytes in the fifo  past		 * the end of the sector and drop them on the floor.		 * Otherwise the fifo is polluted.		 */		inb(FD_DATA);	}	/* Did I get an error? */	result_ok = read_ok(head);	/* Did I read enough bytes? */	ret = -1;	if (result_ok && (bytes_read == max_bytes)) {		ret = bytes_read - byte_offset;		if (ret > length) {			ret = length;		}	}		if (ret < 0) {#ifdef MDEBUG		printf("ret = %d\n", ret);		printf("bytes_read = %d\n", bytes_read);		printf("status = %x\n", status);#endif	}	return ret;}static int floppy_read(struct disk *disk, sector_t base_sector){	unsigned head, track, sector, byte_offset;	unsigned long block;	int ret;	disk->sector = 0;	disk->bytes  = 0;	block = base_sector;	block /= disk->sectors_per_read;	/* break the offset up into sectors and bytes */	byte_offset = 0;	/* Find the disk block we are starting with... */	sector = 1;	head = block % DISK_H1440_HEAD;	track = (block / DISK_H1440_HEAD)% DISK_H1440_TRACK;	/* First seek to our start track */	if (!floppy_seek(track)) {		return -1;	}	/* Then read the data */	ret = floppy_read_sectors(		disk->buffer, byte_offset, SECTOR_SIZE*disk->sectors_per_read, sector, head, track);	if (ret >= 0) {		disk->sector = block * disk->sectors_per_read;		disk->bytes = SECTOR_SIZE * disk->sectors_per_read;		return ret;	}	/* If we failed reset the fdc... */	floppy_reset();	return -1;}/* Determine the floppy disk controller type *//* This routine was written by David C. Niemi */static char get_fdc_version(void){	int bytes, ret;	unsigned char reply_buffer[MAX_REPLIES];		ret = output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */	if (ret < 0)		return FDC_NONE;	if ((bytes = result(reply_buffer, MAX_REPLIES)) <= 0x00)		return FDC_NONE;	/* No FDC present ??? */	if ((bytes==1) && (reply_buffer[0] == 0x80)){		printf("FDC %d is an 8272A\n");		return FDC_8272A;	/* 8272a/765 don't know DUMPREGS */	}	if (bytes != 10) {#ifdef MDEBUG		printf("init: DUMPREGS: unexpected return of %d bytes.\n",			bytes);#endif		return FDC_UNKNOWN;	}	if (!fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD,		TRACK_PRECOMPENSATION)) {		printf("FDC is an 82072\n");		return FDC_82072;      	/* 82072 doesn't know CONFIGURE */	}	output_byte(FD_PERPENDICULAR);	if (need_more_output() == MORE_OUTPUT) {		output_byte(0);	} else {		printf("FDC is an 82072A\n");		return FDC_82072A;	/* 82072A as found on Sparcs. */	}	output_byte(FD_UNLOCK);	bytes = result(reply_buffer, MAX_REPLIES);	if ((bytes == 1) && (reply_buffer[0] == 0x80)){		printf("FDC is a pre-1991 82077\n");		return FDC_82077_ORIG;	/* Pre-1991 82077, doesn't know 					 * LOCK/UNLOCK */	}	if ((bytes != 1) || (reply_buffer[0] != 0x00)) {#ifdef MDEBUG		printf("FDC init: UNLOCK: unexpected return of %d bytes.\n", 			bytes);#endif		return FDC_UNKNOWN;	}	output_byte(FD_PARTID);	bytes = result(reply_buffer, MAX_REPLIES);	if (bytes != 1) {#ifdef MDEBUG		printf("FDC init: PARTID: unexpected return of %d bytes.\n",			bytes);#endif		return FDC_UNKNOWN;	}	if (reply_buffer[0] == 0x80) {		printf("FDC is a post-1991 82077\n");		return FDC_82077;	/* Revised 82077AA passes all the tests */	}	switch (reply_buffer[0] >> 5) {	case 0x0:		/* Either a 82078-1 or a 82078SL running at 5Volt */		printf("FDC is an 82078.\n");		return FDC_82078;	case 0x1:		printf("FDC is a 44pin 82078\n");		return FDC_82078;	case 0x2:		printf("FDC is a S82078B\n");		return FDC_S82078B;	case 0x3:		printf("FDC is a National Semiconductor PC87306\n");		return FDC_87306;	default:		printf("FDC init: 82078 variant with unknown PARTID=%d.\n",			reply_buffer[0] >> 5);		return FDC_82078_UNKN;	}} /* get_fdc_version */static int floppy_init(void){#ifdef MDEBUG	printf("floppy_init\n");#endif	fdc_state.in_sync = 0;	fdc_state.spec1 = -1;	fdc_state.spec2 = -1;	fdc_state.dtr = -1;	fdc_state.dor = DOR_NO_RESET;	fdc_state.version = FDC_UNKNOWN;	reset_fdc();	/* Try to determine the floppy controller type */	fdc_state.version = get_fdc_version();	if (fdc_state.version == FDC_NONE) {		return -1;	}	floppy_reset();#ifdef MDEBUG	printf("fdc_state.version = %x\n", fdc_state.version);#endif	return 0;}static void floppy_reset(void){#ifdef MDEBUG	printf("floppy_reset\n");#endif	floppy_motor_off(FD_DRIVE);	reset_fdc();	fdc_dtr(DISK_H1440_RATE);	/* program data rate via ccr */	collect_interrupt();	fdc_configure(USE_IMPLIED_SEEK, USE_FIFO, FIFO_THRESHOLD, 		TRACK_PRECOMPENSATION);	fdc_specify(DRIVE_H1440_HLT, DRIVE_H1440_HUT, DRIVE_H1440_SRT);	set_drive(FD_DRIVE);	floppy_recalibrate();	fdc_state.in_sync = 1;}static void floppy_fini(struct dev *dev __unused){	/* Disable the floppy and the floppy drive controller */	set_dor(0, 0);}static int floppy_probe(struct dev *dev, unsigned short *probe_addrs){	struct disk *disk = (struct disk *)dev;	unsigned short addr;	int index;	if (!probe_addrs || !*probe_addrs)		return 0;	index = dev->index +1;	if (dev->how_probe == PROBE_AWAKE) {		index--;	}	for(; (index >= 0) && (addr = probe_addrs[index]); index++) {		/* FIXME handle multiple drives per controller */		/* FIXME test to see if I have a drive or a disk in		 * the driver during the probe routine.		 */		/* FIXME make this work under the normal bios */		FD_BASE = addr;		if (floppy_init() != 0) {			/* nothing at this address */			continue;		}		/* O.k. I have a floppy controller */		disk->hw_sector_size   = SECTOR_SIZE;		disk->sectors_per_read = DISK_H1440_SECT;		disk->sectors          = DISK_H1440_HEAD*DISK_H1440_TRACK*DISK_H1440_SECT;		dev->index             = index;		dev->disable           = floppy_fini;		disk->read             = floppy_read;		return 1;	}	dev->index = -1;	return 0;}static unsigned short floppy_ioaddrs[] ={	0x3F0, 0x370, 0};ISA_ROM("pc_floppy", "Generic PC Floppy support")static struct isa_driver floppy_isa_driver __isa_driver = {	.type    = FLOPPY_DRIVER,	.name    = "PC flopyy",	.probe   = floppy_probe,	.ioaddrs = floppy_ioaddrs,};

⌨️ 快捷键说明

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