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

📄 floppy.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
static void floppy_enable_hlt(void){	unsigned long flags;	INT_OFF;	if (hlt_disabled){		hlt_disabled=0;#ifdef HAVE_DISABLE_HLT		enable_hlt();#endif	}	INT_ON;}static void setup_DMA(void){	unsigned long flags;#ifdef FLOPPY_SANITY_CHECK	if (raw_cmd->length == 0){		int i;		printk("zero dma transfer size:");		for (i=0; i < raw_cmd->cmd_count; i++)			printk("%x,", raw_cmd->cmd[i]);		printk("\n");		cont->done(0);		FDCS->reset = 1;		return;	}	if ((long) raw_cmd->kernel_data % 512){		printk("non aligned address: %p\n", raw_cmd->kernel_data);		cont->done(0);		FDCS->reset=1;		return;	}	if (CROSS_64KB(raw_cmd->kernel_data, raw_cmd->length)) {		printk("DMA crossing 64-K boundary %p-%p\n",		       raw_cmd->kernel_data,		       raw_cmd->kernel_data + raw_cmd->length);		cont->done(0);		FDCS->reset=1;		return;	}#endif	INT_OFF;	fd_disable_dma();	fd_clear_dma_ff();	fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);	fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?			DMA_MODE_READ : DMA_MODE_WRITE);	fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data));	fd_set_dma_count(raw_cmd->length);	virtual_dma_port = FDCS->address;	fd_enable_dma();	INT_ON;	floppy_disable_hlt();}void show_floppy(void);/* waits until the fdc becomes ready */static int wait_til_ready(void){	int counter, status;	if(FDCS->reset)		return -1;	for (counter = 0; counter < 10000; counter++) {		status = fd_inb(FD_STATUS);				if (status & STATUS_READY)			return status;	}	if (!initialising) {		DPRINT("Getstatus times out (%x) on fdc %d\n",			status, fdc);		show_floppy();	}	FDCS->reset = 1;	return -1;}/* sends a command byte to the fdc */static int output_byte(char byte){	int status;	if ((status = wait_til_ready()) < 0)		return -1;	if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY){		fd_outb(byte,FD_DATA);#ifdef FLOPPY_SANITY_CHECK		output_log[output_log_pos].data = byte;		output_log[output_log_pos].status = status;		output_log[output_log_pos].jiffies = jiffies;		output_log_pos = (output_log_pos + 1) % OLOGSIZE;#endif		return 0;	}	FDCS->reset = 1;	if (!initialising) {		DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",		       byte, fdc, status);		show_floppy();	}	return -1;}#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}/* gets the response from the fdc */static int result(void){	int i, status;	for(i=0; i < MAX_REPLIES; i++) {		if ((status = wait_til_ready()) < 0)			break;		status &= STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA;		if ((status & ~STATUS_BUSY) == STATUS_READY){#ifdef FLOPPY_SANITY_CHECK			resultjiffies = jiffies;			resultsize = i;#endif			return i;		}		if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))			reply_buffer[i] = fd_inb(FD_DATA);		else			break;	}	if(!initialising) {		DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",		       fdc, status, i);		show_floppy();	}	FDCS->reset = 1;	return -1;}#define MORE_OUTPUT -2/* does the fdc need more output? */static int need_more_output(void){	int status;	if( (status = wait_til_ready()) < 0)		return -1;	if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY)		return MORE_OUTPUT;	return result();}/* Set perpendicular mode as required, based on data rate, if supported. * 82077 Now tested. 1Mbps data rate only possible with 82077-1. */static inline void perpendicular_mode(void){	unsigned char perp_mode;	if (raw_cmd->rate & 0x40){		switch(raw_cmd->rate & 3){			case 0:				perp_mode=2;				break;			case 3:				perp_mode=3;				break;			default:				DPRINT("Invalid data rate for perpendicular mode!\n");				cont->done(0);				FDCS->reset = 1; /* convenient way to return to						  * redo without to much hassle (deep						  * stack et al. */				return;		}	} else		perp_mode = 0;	if (FDCS->perp_mode == perp_mode)		return;	if (FDCS->version >= FDC_82077_ORIG) {		output_byte(FD_PERPENDICULAR);		output_byte(perp_mode);		FDCS->perp_mode = perp_mode;	} else if (perp_mode) {		DPRINT("perpendicular mode not supported by this FDC.\n");	}} /* perpendicular_mode */static int fifo_depth = 0xa;static int no_fifo = 0;static int fdc_configure(void){	/* Turn on FIFO */	output_byte(FD_CONFIGURE);	if(need_more_output() != MORE_OUTPUT)		return 0;	output_byte(0);	output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));	output_byte(0);	/* pre-compensation from track 			   0 upwards */	return 1;}	#define NOMINAL_DTR 500/* Issue a "SPECIFY" command to set the step rate time, head unload time, * head load time, and DMA disable flag to values needed by floppy. * * The value "dtr" is the data transfer rate in Kbps.  It is needed * to account for the data rate-based scaling done by the 82072 and 82077 * FDC types.  This parameter is ignored for other types of FDCs (i.e. * 8272a). * * Note that changing the data transfer rate has a (probably deleterious) * effect on the parameters subject to scaling for 82072/82077 FDCs, so * fdc_specify is called again after each data transfer rate * change. * * srt: 1000 to 16000 in microseconds * hut: 16 to 240 milliseconds * hlt: 2 to 254 milliseconds * * These values are rounded up to the next highest available delay time. */static void fdc_specify(void){	unsigned char spec1, spec2;	int srt, hlt, hut;	unsigned long dtr = NOMINAL_DTR;	unsigned long scale_dtr = NOMINAL_DTR;	int hlt_max_code = 0x7f;	int hut_max_code = 0xf;	if (FDCS->need_configure && FDCS->version >= FDC_82072A) {		fdc_configure();		FDCS->need_configure = 0;		/*DPRINT("FIFO enabled\n");*/	}	switch (raw_cmd->rate & 0x03) {		case 3:			dtr = 1000;			break;		case 1:			dtr = 300;			if (FDCS->version >= FDC_82078) {				/* chose the default rate table, not the one				 * where 1 = 2 Mbps */				output_byte(FD_DRIVESPEC);				if(need_more_output() == MORE_OUTPUT) {					output_byte(UNIT(current_drive));					output_byte(0xc0);				}			}			break;		case 2:			dtr = 250;			break;	}	if (FDCS->version >= FDC_82072) {		scale_dtr = dtr;		hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */		hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */	}	/* Convert step rate from microseconds to milliseconds and 4 bits */	srt = 16 - (DP->srt*scale_dtr/1000 + NOMINAL_DTR - 1)/NOMINAL_DTR;	SUPBOUND(srt, 0xf);	INFBOUND(srt, 0);	hlt = (DP->hlt*scale_dtr/2 + NOMINAL_DTR - 1)/NOMINAL_DTR;	if (hlt < 0x01)		hlt = 0x01;	else if (hlt > 0x7f)		hlt = hlt_max_code;	hut = (DP->hut*scale_dtr/16 + NOMINAL_DTR - 1)/NOMINAL_DTR;	if (hut < 0x1)		hut = 0x1;	else if (hut > 0xf)		hut = hut_max_code;	spec1 = (srt << 4) | hut;	spec2 = (hlt << 1) | (use_virtual_dma & 1);	/* If these parameters did not change, just return with success */	if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {		/* Go ahead and set spec1 and spec2 */		output_byte(FD_SPECIFY);		output_byte(FDCS->spec1 = spec1);		output_byte(FDCS->spec2 = spec2);	}} /* fdc_specify *//* Set the FDC's data transfer rate on behalf of the specified drive. * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue * of the specify command (i.e. using the fdc_specify function). */static int fdc_dtr(void){	/* If data rate not already set to desired value, set it. */	if ((raw_cmd->rate & 3) == FDCS->dtr)		return 0;	/* Set dtr */	fd_outb(raw_cmd->rate & 3, FD_DCR);	/* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)	 * need a stabilization period of several milliseconds to be	 * enforced after data rate changes before R/W operations.	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)	 */	FDCS->dtr = raw_cmd->rate & 3;	return(wait_for_completion(jiffies+2*HZ/100,				   (timeout_fn) floppy_ready));} /* fdc_dtr */static void tell_sector(void){	printk(": track %d, head %d, sector %d, size %d",	       R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);} /* tell_sector *//* * OK, this error interpreting routine 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. * ak: Made this into a separate routine. */static int interpret_errors(void){	char bad;	if (inr!=7) {		DPRINT("-- FDC reply error");		FDCS->reset = 1;		return 1;	}	/* check IC to find cause of interrupt */	switch (ST0 & ST0_INTR) {		case 0x40:	/* error occurred during command execution */			if (ST1 & ST1_EOC)				return 0; /* occurs with pseudo-DMA */			bad = 1;			if (ST1 & ST1_WP) {				DPRINT("Drive is write protected\n");				CLEARF(FD_DISK_WRITABLE);				cont->done(0);				bad = 2;			} else if (ST1 & ST1_ND) {				SETF(FD_NEED_TWADDLE);			} else if (ST1 & ST1_OR) {				if (DP->flags & FTD_MSG)					DPRINT("Over/Underrun - retrying\n");				bad = 0;			}else if (*errors >= DP->max_errors.reporting){				DPRINT("");				if (ST0 & ST0_ECE) {					printk("Recalibrate failed!");				} else if (ST2 & ST2_CRC) {					printk("data CRC error");					tell_sector();				} else if (ST1 & ST1_CRC) {					printk("CRC error");					tell_sector();				} else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {					if (!probing) {						printk("sector not found");						tell_sector();					} 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..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2);					tell_sector();				}				printk("\n");			}			if (ST2 & ST2_WC || ST2 & ST2_BC)				/* wrong cylinder => recal */				DRS->track = NEED_2_RECAL;			return bad;		case 0x80: /* invalid command given */			DPRINT("Invalid FDC command given!\n");			cont->done(0);			return 2;		case 0xc0:			DPRINT("Abnormal termination caused by polling\n");			cont->error();			return 2;		default: /* (0) Normal command termination */			return 0;	}}/* * This routine is called when everything should be correctly set up * for the transfer (i.e. floppy motor is on, the correct floppy is * selected, and the head is sitting on the right track). */static void setup_rw_floppy(void){	int i,ready_date,r, flags,dflags;	timeout_fn function;	flags = raw_cmd->flags;	if (flags & (FD_RAW_READ | FD_RAW_WRITE))		flags |= FD_RAW_INTR;	if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){		ready_date = DRS->spinup_date + DP->spinup;		/* If spinup will take a long time, rerun scandrives		 * again just before spinup completion. Beware that		 * after scandrives, we must again wait for selection.		 */		if ((signed) (ready_date - jiffies) > DP->select_delay){			ready_date -= DP->select_delay;			function = (timeout_fn) floppy_start;		} else			function = (timeout_fn) setup_rw_floppy;		/* wait until the floppy is spinning fast enough */		if (wait_for_completion(ready_date,function))			return;	}	dflags = DRS->flags;	if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))		setup_DMA();	if (flags & FD_RAW_INTR)		SET_INTR(main_command_interrupt);	r=0;	for (i=0; i< raw_cmd->cmd_count; i++)		r|=output_byte(raw_cmd->cmd[i]);#ifdef DEBUGT	debugt("rw_command: ");#endif	if (r){		cont->error();		reset_fdc();		return;	}	if (!(flags & FD_RAW_INTR)){		inr = result();		cont->interrupt();	} else if (flags & FD_RAW_NEED_DISK)		fd_watchdog();}static int blind_seek;/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. */static void seek_interrupt(void){#ifdef DEBUGT	debugt("seek interrupt:");#endif	if (inr != 2 || (ST0 & 0xF8) != 0x20) {		DPRINT("seek failed\n");		DRS->track = NEED_2_RECAL;		cont->error();		cont->redo();		return;	}	if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){#ifdef DCL_DEBUG		if (DP->flags & FD_DEBUG){			DPRINT("clearing NEWCHANGE flag because of effective seek\n");			DPRINT("jiffies=%ld\n", jiffies);		}#endif		CLEARF(FD_DISK_NEWCHANGE); /* effective seek */		DRS->select_date = jiffies;	}	DRS->track = ST1;	floppy_ready();}static void check_wp(void){	if (TESTF(FD_VERIFY)) {		/* check write protection */		output_byte(FD_GETSTATUS);		output_byte(UNIT(current_drive));

⌨️ 快捷键说明

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