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

📄 floppy.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 3 页
字号:
	clear_dma_ff(FLOPPY_DMA);	set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);	set_dma_addr(FLOPPY_DMA, addr);	set_dma_count(FLOPPY_DMA, count);	enable_dma(FLOPPY_DMA);	sti();}static void output_byte(char byte){	int counter;	unsigned char status;	if (reset)		return;	for(counter = 0 ; counter < 10000 ; counter++) {		status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);		if (status == STATUS_READY) {			outb(byte,FD_DATA);			return;		}	}	current_track = NO_TRACK;	reset = 1;	printk("Unable to send byte to FDC\n");}static int result(void){	int i = 0, counter, status;	if (reset)		return -1;	for (counter = 0 ; counter < 10000 ; counter++) {		status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);		if (status == STATUS_READY) {			return i;		}		if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {			if (i >= MAX_REPLIES) {				printk("floppy_stat reply overrun\n");				break;			}			reply_buffer[i++] = inb_p(FD_DATA);		}	}	reset = 1;	current_track = NO_TRACK;	printk("Getstatus times out\n");	return -1;}static void bad_flp_intr(void){	int errors;	current_track = NO_TRACK;	if (format_status == FORMAT_BUSY)		errors = ++format_errors;	else if (!CURRENT) {		printk(DEVICE_NAME ": no current request\n");		reset = recalibrate = 1;		return;	} else		errors = ++CURRENT->errors;	if (errors > MAX_ERRORS) {		request_done(0);	}	if (errors > MAX_ERRORS/2)		reset = 1;	else		recalibrate = 1;}	/* Set perpendicular mode as required, based on data rate, if supported. * 82077 Untested! 1Mbps data rate only possible with 82077-1. * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries. */static inline void perpendicular_mode(unsigned char rate){	if (fdc_version == FDC_TYPE_82077) {		output_byte(FD_PERPENDICULAR);		if (rate & 0x40) {			unsigned char r = rate & 0x03;			if (r == 0)				output_byte(2);	/* perpendicular, 500 kbps */			else if (r == 3)				output_byte(3);	/* perpendicular, 1Mbps */			else {				printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");				reset = 1;			}		} else			output_byte(0);		/* conventional mode */	} else {		if (rate & 0x40) {			printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");			reset = 1;		}	}} /* perpendicular_mode *//* * This has only been tested for the case fdc_version == FDC_TYPE_STD. * In case you have a 82077 and want to test it, you'll have to compile * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for * recognizing drives with vertical recording support. */static void configure_fdc_mode(void){	if (need_configure && (fdc_version == FDC_TYPE_82077)) {		/* Enhanced version with FIFO & vertical recording. */		output_byte(FD_CONFIGURE);		output_byte(0);		output_byte(0x1A);	/* FIFO on, polling off, 10 byte threshold */		output_byte(0);		/* precompensation from track 0 upwards */		need_configure = 0;		printk(DEVICE_NAME ": FIFO enabled\n");	}	if (cur_spec1 != floppy->spec1) {		cur_spec1 = floppy->spec1;		output_byte(FD_SPECIFY);		output_byte(cur_spec1);		/* hut etc */		output_byte(6);			/* Head load time =6ms, DMA */	}	if (cur_rate != floppy->rate) {		/* use bit 6 of floppy->rate to indicate perpendicular mode */		perpendicular_mode(floppy->rate);		outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR);	}} /* configure_fdc_mode */static void tell_sector(int nr){	if (nr!=7) {		printk(" -- FDC reply errror");		reset = 1;	} else		printk(": track %d, head %d, sector %d", reply_buffer[3],			reply_buffer[4], reply_buffer[5]);} /* tell_sector *//* * Ok, this interrupt is called after a DMA read/write has succeeded * or failed, so we check the results, and copy any buffers. * hhb: Added better error reporting. */static void rw_interrupt(void){	char * buffer_area;	int nr;	char bad;	nr = result();	/* check IC to find cause of interrupt */	switch ((ST0 & ST0_INTR)>>6) {		case 1:	/* error occured during command execution */			bad = 1;			if (ST1 & ST1_WP) {				printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive);				request_done(0);				bad = 0;			} else if (ST1 & ST1_OR) {				if (ftd_msg[ST0 & ST0_DS])					printk(DEVICE_NAME ": Over/Underrun - retrying\n");				/* could continue from where we stopped, but ... */				bad = 0;			} else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {				printk(DEVICE_NAME " %d: ", ST0 & ST0_DS);				if (ST0 & ST0_ECE) {					printk("Recalibrate failed!");				} else if (ST2 & ST2_CRC) {					printk("data CRC error");					tell_sector(nr);				} else if (ST1 & ST1_CRC) {					printk("CRC error");					tell_sector(nr);				} else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {					if (!probing) {						printk("sector not found");						tell_sector(nr);					} else						printk("probe failed...");				} else if (ST2 & ST2_WC) {	/* seek error */					printk("wrong cylinder");				} else if (ST2 & ST2_BC) {	/* cylinder marked as bad */					printk("bad cylinder");				} else {					printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3);				}				printk("\n");			}			if (bad)				bad_flp_intr();			redo_fd_request();			return;		case 2: /* invalid command given */			printk(DEVICE_NAME ": Invalid FDC command given!\n");			request_done(0);			return;		case 3:			printk(DEVICE_NAME ": Abnormal termination caused by polling\n");			bad_flp_intr();			redo_fd_request();			return;		default: /* (0) Normal command termination */			break;	}	if (probing) {		int drive = MINOR(CURRENT->dev);		if (ftd_msg[drive])			printk("Auto-detected floppy type %s in fd%d\n",			    floppy->name,drive);		current_type[drive] = floppy;		floppy_sizes[drive] = floppy->size >> 1;		probing = 0;	}	if (read_track) {		buffer_track = seek_track;		buffer_drive = current_drive;		buffer_area = floppy_track_buffer +			((sector-1 + head*floppy->sect)<<9);		copy_buffer(buffer_area,CURRENT->buffer);	} else if (command == FD_READ &&		(unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR)		copy_buffer(tmp_floppy_area,CURRENT->buffer);	request_done(1);	redo_fd_request();}/* * We try to read tracks, but if we get too many errors, we * go back to reading just one sector at a time. * * This means we should be able to read a sector even if there * are other bad sectors on this track. */inline void setup_rw_floppy(void){	setup_DMA();	do_floppy = rw_interrupt;	output_byte(command);	if (command != FD_FORMAT) {		if (read_track) {			output_byte(current_drive);			output_byte(track);			output_byte(0);			output_byte(1);		} else {			output_byte(head<<2 | current_drive);			output_byte(track);			output_byte(head);			output_byte(sector);		}		output_byte(2);		/* sector size = 512 */		output_byte(floppy->sect);		output_byte(floppy->gap);		output_byte(0xFF);	/* sector size (0xff when n!=0 ?) */	} else {		output_byte(head<<2 | current_drive);		output_byte(2);		output_byte(floppy->sect);		output_byte(floppy->fmt_gap);		output_byte(FD_FILL_BYTE);	}	if (reset)		redo_fd_request();}/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. Note that the "unexpected interrupt" routine * also does a recalibrate, but doesn't come here. */static void seek_interrupt(void){/* sense drive status */	output_byte(FD_SENSEI);	if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {		printk(DEVICE_NAME ": seek failed\n");		recalibrate = 1;		bad_flp_intr();		redo_fd_request();		return;	}	current_track = ST1;	setup_rw_floppy();}/* * This routine is called when everything should be correctly set up * for the transfer (ie floppy motor is on and the correct floppy is * selected). */static void transfer(void){	read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&	    (floppy->sect <= MAX_BUFFER_SECTORS);	configure_fdc_mode();	if (reset) {		redo_fd_request();		return;	}	if (!seek) {		setup_rw_floppy();		return;	}	do_floppy = seek_interrupt;	output_byte(FD_SEEK);	if (read_track)		output_byte(current_drive);	else		output_byte((head<<2) | current_drive);	output_byte(seek_track);	if (reset)		redo_fd_request();}/* * Special case - used after a unexpected interrupt (or reset) */static void recalibrate_floppy(void);static void recal_interrupt(void){	output_byte(FD_SENSEI);	current_track = NO_TRACK;	if (result()!=2 || (ST0 & 0xE0) == 0x60)		reset = 1;/* Recalibrate until track 0 is reached. Might help on some errors. */	if ((ST0 & 0x10) == 0x10)		recalibrate_floppy();	/* FIXME: should limit nr of recalibrates */	else		redo_fd_request();}static void unexpected_floppy_interrupt(void){	current_track = NO_TRACK;	output_byte(FD_SENSEI);	printk(DEVICE_NAME ": unexpected interrupt\n");	if (result()!=2 || (ST0 & 0xE0) == 0x60)		reset = 1;	else		recalibrate = 1;}static void recalibrate_floppy(void){	recalibrate = 0;	current_track = 0;	do_floppy = recal_interrupt;	output_byte(FD_RECALIBRATE);	output_byte(head<<2 | current_drive);	if (reset)		redo_fd_request();}/* * Must do 4 FD_SENSEIs after reset because of ``drive polling''. */static void reset_interrupt(void){	short i;	for (i=0; i<4; i++) {		output_byte(FD_SENSEI);		(void) result();	}	output_byte(FD_SPECIFY);	output_byte(cur_spec1);		/* hut etc */	output_byte(6);			/* Head load time =6ms, DMA */	configure_fdc_mode();		/* reprogram fdc */	if (initial_reset_flag) {		initial_reset_flag = 0;		recalibrate = 1;		reset = 0;		return;	}	if (!recover)		redo_fd_request();	else {		recalibrate_floppy();		recover = 0;	}}/* * reset is done by pulling bit 2 of DOR low for a while. */static void reset_floppy(void){	int i;	do_floppy = reset_interrupt;	reset = 0;	current_track = NO_TRACK;	cur_spec1 = -1;	cur_rate = -1;	recalibrate = 1;	need_configure = 1;	if (!initial_reset_flag)		printk("Reset-floppy called\n");	cli();	outb_p(current_DOR & ~0x04, FD_DOR);	for (i=0 ; i<1000 ; i++)		__asm__("nop");	outb(current_DOR, FD_DOR);	sti();}static void floppy_shutdown(void){	cli();	do_floppy = NULL;	request_done(0);	recover = 1;	reset_floppy();	sti();	redo_fd_request();}static void shake_done(void){	current_track = NO_TRACK;	if (inb(FD_DIR) & 0x80)		request_done(0);	redo_fd_request();}static int retry_recal(void (*proc)(void)){	output_byte(FD_SENSEI);	if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;	do_floppy = proc;	output_byte(FD_RECALIBRATE);	output_byte(head<<2 | current_drive);	return 1;}static void shake_zero(void){	if (!retry_recal(shake_zero)) shake_done();}static void shake_one(void){	if (retry_recal(shake_one)) return;	do_floppy = shake_done;	output_byte(FD_SEEK);	output_byte(head << 2 | current_drive);

⌨️ 快捷键说明

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