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

📄 fdc-io.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		outb_p(data, fdc.dor2);	} else {		outb_p(data, fdc.dor);	}	ftape_sleep(10 * FT_MILLISECOND);	TRACE_EXIT;}static void fdc_update_dsr(void){	TRACE_FUN(ft_t_any);	TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns",	      fdc_data_rate, fdc_precomp);	if (fdc.type >= i82077) {		outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr);	} else {		outb_p(fdc_rate_code & 0x03, fdc.ccr);	}	TRACE_EXIT;}void fdc_set_write_precomp(int precomp){	TRACE_FUN(ft_t_any);	TRACE(ft_t_noise, "New precomp: %d nsec", precomp);	fdc_precomp = precomp;	/*  write precompensation can be set in multiples of 41.67 nsec.	 *  round the parameter to the nearest multiple and convert it	 *  into a fdc setting. Note that 0 means default to the fdc,	 *  7 is used instead of that.	 */	fdc_prec_code = ((fdc_precomp + 21) / 42) << 2;	if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) {		fdc_prec_code = 7 << 2;	}	fdc_update_dsr();	TRACE_EXIT;}/*  Reprogram the 82078 registers to use Data Rate Table 1 on all drives. */static void fdc_set_drive_specs(void){	__u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0};	int result;	TRACE_FUN(ft_t_any);	TRACE(ft_t_flow, "Setting of drive specs called");	if (fdc.type >= i82078_1) {		cmd[1] = (0 << 5) | (2 << 2);		cmd[2] = (1 << 5) | (2 << 2);		cmd[3] = (2 << 5) | (2 << 2);		cmd[4] = (3 << 5) | (2 << 2);		result = fdc_command(cmd, NR_ITEMS(cmd));		if (result < 0) {			TRACE(ft_t_err, "Setting of drive specs failed");		}	}	TRACE_EXIT;}/* Select clock for fdc, must correspond with tape drive setting ! * This also influences the fdc timing so we must adjust some values. */int fdc_set_data_rate(int rate){	int bad_rate = 0;	TRACE_FUN(ft_t_any);	/* Select clock for fdc, must correspond with tape drive setting !	 * This also influences the fdc timing so we must adjust some values.	 */	TRACE(ft_t_fdc_dma, "new rate = %d", rate);	switch (rate) {	case 250:		fdc_rate_code = fdc_data_rate_250;		break;	case 500:		fdc_rate_code = fdc_data_rate_500;		break;	case 1000:		if (fdc.type < i82077) {			bad_rate = 1;                } else {			fdc_rate_code = fdc_data_rate_1000;		}		break;	case 2000:		if (fdc.type < i82078_1) {			bad_rate = 1;                } else {			fdc_rate_code = fdc_data_rate_2000;		}		break;	default:		bad_rate = 1;        }	if (bad_rate) {		TRACE_ABORT(-EIO,			    ft_t_fdc_dma, "%d is not a valid data rate", rate);	}	fdc_data_rate = rate;	fdc_update_dsr();	fdc_set_seek_rate(fdc_seek_rate);  /* clock changed! */	ftape_udelay(1000);	TRACE_EXIT 0;}/*  keep the unit select if keep_select is != 0, */static void fdc_dor_reset(int keep_select){	__u8 fdc_ctl = ft_drive_sel;	if (keep_select != 0) {		fdc_ctl |= FDC_DMA_MODE;		if (ftape_motor) {			fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel;		}	}	ftape_udelay(10); /* ??? but seems to be necessary */	if (ft_mach2) {		outb_p(fdc_ctl & 0x0f, fdc.dor);		outb_p(fdc_ctl, fdc.dor2);	} else {		outb_p(fdc_ctl, fdc.dor);	}	fdc_usec_wait(10); /* delay >= 14 fdc clocks */	if (keep_select == 0) {		fdc_ctl = 0;	}	fdc_ctl |= FDC_RESET_NOT;	if (ft_mach2) {		outb_p(fdc_ctl & 0x0f, fdc.dor);		outb_p(fdc_ctl, fdc.dor2);	} else {		outb_p(fdc_ctl, fdc.dor);	}}/*      Reset the floppy disk controller. Leave the ftape_unit selected. */void fdc_reset(void){	int st0;	int i;	int dummy;	unsigned long flags;	TRACE_FUN(ft_t_any);	spin_lock_irqsave(&fdc_io_lock, flags);	fdc_dor_reset(1); /* keep unit selected */	fdc_mode = fdc_idle;	/*  maybe the cli()/sti() pair is not necessary, BUT:	 *  the following line MUST be here. Otherwise fdc_interrupt_wait()	 *  won't wait. Note that fdc_reset() is called from 	 *  ftape_dumb_stop() when the fdc is busy transferring data. In this	 *  case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries	 *  to get the result bytes from the fdc etc. CLASH.	 */	ft_interrupt_seen = 0;		/*  Program data rate	 */	fdc_update_dsr();               /* restore data rate and precomp */	spin_unlock_irqrestore(&fdc_io_lock, flags);        /*         *	Wait for first polling cycle to complete	 */	if (fdc_interrupt_wait(1 * FT_SECOND) < 0) {		TRACE(ft_t_err, "no drive polling interrupt!");	} else {	/* clear all disk-changed statuses */		for (i = 0; i < 4; ++i) {			if(fdc_sense_interrupt_status(&st0, &dummy) != 0) {				TRACE(ft_t_err, "sense failed for %d", i);			}			if (i == ft_drive_sel) {				ftape_current_cylinder = dummy;			}		}		TRACE(ft_t_noise, "drive polling completed");	}	/*         *	SPECIFY COMMAND	 */	fdc_set_seek_rate(fdc_seek_rate);	/*	 *	DRIVE SPECIFICATION COMMAND (if fdc type known)	 */	if (fdc.type >= i82078_1) {		fdc_set_drive_specs();	}	TRACE_EXIT;}#if !defined(CLK_48MHZ)# define CLK_48MHZ 1#endif/*  When we're done, put the fdc into reset mode so that the regular *  floppy disk driver will figure out that something is wrong and *  initialize the controller the way it wants. */void fdc_disable(void){	__u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00};	__u8 cmd2[] = {FDC_LOCK};	__u8 cmd3[] = {FDC_UNLOCK};	__u8 stat[1];	TRACE_FUN(ft_t_flow);	if (!fdc_fifo_locked) {		fdc_reset();		TRACE_EXIT;	}	if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) {		fdc_dor_reset(0);		TRACE_ABORT(/**/, ft_t_bug, 		"couldn't unlock fifo, configuration remains changed");	}	fdc_fifo_locked = 0;	if (CLK_48MHZ && fdc.type >= i82078) {		cmd1[0] |= FDC_CLK48_BIT;	}	cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1);	if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) {		fdc_dor_reset(0);		TRACE_ABORT(/**/, ft_t_bug,		"couldn't reconfigure fifo to old state");	}	if (fdc_lock_state &&	    fdc_issue_command(cmd2, 1, stat, 1) < 0) {		fdc_dor_reset(0);		TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again");	}	TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked",	      fdc_fifo_state ? "en" : "dis",	      fdc_fifo_thr, (fdc_lock_state) ? "" : "not ");	fdc_dor_reset(0);	TRACE_EXIT;}/*      Specify FDC seek-rate (milliseconds) */static int fdc_set_seek_rate(int seek_rate){	/* set step rate, dma mode, and minimal head load and unload times	 */	__u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; 	fdc_seek_rate = seek_rate;	in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4;	return fdc_command(in, 3);}/*      Sense drive status: get unit's drive status (ST3) */int fdc_sense_drive_status(int *st3){	__u8 out[2];	__u8 in[1];	TRACE_FUN(ft_t_any);	out[0] = FDC_SENSED;	out[1] = ft_drive_sel;	TRACE_CATCH(fdc_issue_command(out, 2, in, 1),);	*st3 = in[0];	TRACE_EXIT 0;}/*      Sense Interrupt Status command: *      should be issued at the end of each seek. *      get ST0 and current cylinder. */int fdc_sense_interrupt_status(int *st0, int *current_cylinder){	__u8 out[1];	__u8 in[2];	TRACE_FUN(ft_t_any);	out[0] = FDC_SENSEI;	TRACE_CATCH(fdc_issue_command(out, 1, in, 2),);	*st0 = in[0];	*current_cylinder = in[1];	TRACE_EXIT 0;}/*      step to track */int fdc_seek(int track){	__u8 out[3];	int st0, pcn;#ifdef TESTING	unsigned int time;#endif	TRACE_FUN(ft_t_any);	out[0] = FDC_SEEK;	out[1] = ft_drive_sel;	out[2] = track;#ifdef TESTING	time = ftape_timestamp();#endif	/*  We really need this command to work !	 */	ft_seek_completed = 0;	TRACE_CATCH(fdc_command(out, 3),		    fdc_reset();		    TRACE(ft_t_noise, "destination was: %d, resetting FDC...",			  track));	/*    Handle interrupts until ft_seek_completed or timeout.	 */	for (;;) {		TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),);		if (ft_seek_completed) {			TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),);			if ((st0 & ST0_SEEK_END) == 0) {				TRACE_ABORT(-EIO, ft_t_err,				      "no seek-end after seek completion !??");			}			break;		}	}#ifdef TESTING	time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder);	if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) {		TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)",                         time, track - ftape_current_cylinder);	}#endif	/*    Verify whether we issued the right tape command.	 */	/* Verify that we seek to the proper track. */	if (pcn != track) {		TRACE_ABORT(-EIO, ft_t_err, "bad seek..");	}	ftape_current_cylinder = track;	TRACE_EXIT 0;}static int perpend_mode; /* set if fdc is in perpendicular mode */static int perpend_off(void){ 	__u8 perpend[] = {FDC_PERPEND, 0x00};	TRACE_FUN(ft_t_any);		if (perpend_mode) {		/* Turn off perpendicular mode */		perpend[1] = 0x80;		TRACE_CATCH(fdc_command(perpend, 2),			    TRACE(ft_t_err,"Perpendicular mode exit failed!"));		perpend_mode = 0;	}	TRACE_EXIT 0;}static int handle_perpend(int segment_id){ 	__u8 perpend[] = {FDC_PERPEND, 0x00};	TRACE_FUN(ft_t_any);	/* When writing QIC-3020 tapes, turn on perpendicular mode	 * if tape is moving in forward direction (even tracks).	 */	if (ft_qic_std == QIC_TAPE_QIC3020 &&	    ((segment_id / ft_segments_per_track) & 1) == 0) {/*  FIXME: some i82077 seem to support perpendicular mode as *  well.  */#if 0		if (fdc.type < i82077AA) {}#else		if (fdc.type < i82077 && ft_data_rate < 1000) {#endif			/*  fdc does not support perpendicular mode: complain 			 */			TRACE_ABORT(-EIO, ft_t_err,				    "Your FDC does not support QIC-3020.");		}		perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ;		TRACE_CATCH(fdc_command(perpend, 2),			   TRACE(ft_t_err,"Perpendicular mode entry failed!"));		TRACE(ft_t_flow, "Perpendicular mode set");		perpend_mode = 1;		TRACE_EXIT 0;	}	TRACE_EXIT perpend_off();}static inline void fdc_setup_dma(char mode,				 volatile void *addr, unsigned int count){	/* Program the DMA controller.	 */	disable_dma(fdc.dma);	clear_dma_ff(fdc.dma);	set_dma_mode(fdc.dma, mode);	set_dma_addr(fdc.dma, virt_to_bus((void*)addr));	set_dma_count(fdc.dma, count);	enable_dma(fdc.dma);}/*  Setup fdc and dma for formatting the next segment */int fdc_setup_formatting(buffer_struct * buff){	unsigned long flags;	__u8 out[6] = {		FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b	};	TRACE_FUN(ft_t_any);		TRACE_CATCH(handle_perpend(buff->segment_id),);	/* Program the DMA controller.	 */        TRACE(ft_t_fdc_dma,	      "phys. addr. = %lx", virt_to_bus((void*) buff->ptr));	spin_lock_irqsave(&fdc_io_lock, flags);	fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4);	/* Issue FDC command to start reading/writing.	 */	out[1] = ft_drive_sel;	out[4] = buff->gap3;	TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)),		    restore_flags(flags); fdc_mode = fdc_idle);	spin_unlock_irqrestore(&fdc_io_lock, flags);	TRACE_EXIT 0;}/*      Setup Floppy Disk Controller and DMA to read or write the next cluster *      of good sectors from or to the current segment. */int fdc_setup_read_write(buffer_struct * buff, __u8 operation){	unsigned long flags;	__u8 out[9];	int dma_mode;	TRACE_FUN(ft_t_any);	switch(operation) {

⌨️ 快捷键说明

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