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

📄 fdc-io.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	case FDC_VERIFY:		if (fdc.type < i82077) {			operation = FDC_READ;		}	case FDC_READ:	case FDC_READ_DELETED:		dma_mode = DMA_MODE_READ;		TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p",		      buff->sector_count, buff->ptr);		TRACE_CATCH(perpend_off(),);		break;	case FDC_WRITE_DELETED:		TRACE(ft_t_noise, "deleting segment %d", buff->segment_id);	case FDC_WRITE:		dma_mode = DMA_MODE_WRITE;		/* When writing QIC-3020 tapes, turn on perpendicular mode		 * if tape is moving in forward direction (even tracks).		 */		TRACE_CATCH(handle_perpend(buff->segment_id),);		TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p",		      buff->sector_count, buff->ptr);		break;	default:		TRACE_ABORT(-EIO,			    ft_t_bug, "bug: invalid operation parameter");	}	TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr));	spin_lock_irqsave(&fdc_io_lock, flags);	if (operation != FDC_VERIFY) {		fdc_setup_dma(dma_mode, buff->ptr,			      FT_SECTOR_SIZE * buff->sector_count);	}	/* Issue FDC command to start reading/writing.	 */	out[0] = operation;	out[1] = ft_drive_sel;	out[2] = buff->cyl;	out[3] = buff->head;	out[4] = buff->sect + buff->sector_offset;	out[5] = 3;		/* Sector size of 1K. */	out[6] = out[4] + buff->sector_count - 1;	/* last sector */	out[7] = 109;		/* Gap length. */	out[8] = 0xff;		/* No limit to transfer size. */	TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x",		out[2], out[3], out[4], out[6] - out[4] + 1);	spin_unlock_irqrestore(&fdc_io_lock, flags);	TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle);	TRACE_EXIT 0;}int fdc_fifo_threshold(__u8 threshold,		       int *fifo_state, int *lock_state, int *fifo_thr){	const __u8 cmd0[] = {FDC_DUMPREGS};	__u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0};	const __u8 cmd2[] = {FDC_LOCK};	const __u8 cmd3[] = {FDC_UNLOCK};	__u8 reg[10];	__u8 stat;	int i;	int result;	TRACE_FUN(ft_t_any);	if (CLK_48MHZ && fdc.type >= i82078) {		cmd1[0] |= FDC_CLK48_BIT;	}	/*  Dump fdc internal registers for examination	 */	TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)),		    TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged"));	/*  Now read fdc internal registers from fifo	 */	for (i = 0; i < (int)NR_ITEMS(reg); ++i) {		fdc_read(&reg[i]);		TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]);	}	if (fifo_state && lock_state && fifo_thr) {		*fifo_state = (reg[8] & 0x20) == 0;		*lock_state = reg[7] & 0x80;		*fifo_thr = 1 + (reg[8] & 0x0f);	}	TRACE(ft_t_noise,	      "original fifo state: %sabled, threshold %d, %slocked",	      ((reg[8] & 0x20) == 0) ? "en" : "dis",	      1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not ");	/*  If fdc is already locked, unlock it first ! */	if (reg[7] & 0x80) {		fdc_ready_wait(100);		TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1),			    TRACE(ft_t_bug, "FDC unlock command failed, "				  "configuration unchanged"));	}	fdc_fifo_locked = 0;	/*  Enable fifo and set threshold at xx bytes to allow a	 *  reasonably large latency and reduce number of dma bursts.	 */	fdc_ready_wait(100);	if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) {		TRACE(ft_t_bug, "configure cmd failed, fifo unchanged");	}	/*  Now lock configuration so reset will not change it	 */        if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 ||	   stat != 0x10) {		TRACE_ABORT(-EIO, ft_t_bug,			    "FDC lock command failed, stat = 0x%02x", stat);	}	fdc_fifo_locked = 1;	TRACE_EXIT result;}static int fdc_fifo_enable(void){	TRACE_FUN(ft_t_any);	if (fdc_fifo_locked) {		TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked");	}	TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */,				       &fdc_fifo_state,				       &fdc_lock_state,				       &fdc_fifo_thr),);	TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */,				       NULL, NULL, NULL),);	TRACE_EXIT 0;}/*   Determine fd controller type  */static __u8 fdc_save_state[2];static int fdc_probe(void){	__u8 cmd[1];	__u8 stat[16]; /* must be able to hold dumpregs & save results */	int i;	TRACE_FUN(ft_t_any);	/*  Try to find out what kind of fd controller we have to deal with	 *  Scheme borrowed from floppy driver:	 *  first try if FDC_DUMPREGS command works	 *  (this indicates that we have a 82072 or better)	 *  then try the FDC_VERSION command (82072 doesn't support this)	 *  then try the FDC_UNLOCK command (some older 82077's don't support this)	 *  then try the FDC_PARTID command (82078's support this)	 */	cmd[0] = FDC_DUMPREGS;	if (fdc_issue_command(cmd, 1, stat, 1) != 0) {		TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found");	}	if (stat[0] == 0x80) {		/* invalid command: must be pre 82072 */		TRACE_ABORT(i8272,			    ft_t_warn, "Type 8272A/765A compatible FDC found");	}	fdc_result(&stat[1], 9);	fdc_save_state[0] = stat[7];	fdc_save_state[1] = stat[8];	cmd[0] = FDC_VERSION;	if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) {		TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found");	}	if (*stat != 0x90) {		TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found");	}	cmd[0] = FDC_UNLOCK;	if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) {		TRACE_ABORT(i8272, ft_t_warn,			    "Type pre-1991 82077 FDC found, "			    "treating it like a 82072");	}	if (fdc_save_state[0] & 0x80) { /* was locked */		cmd[0] = FDC_LOCK; /* restore lock */		(void)fdc_issue_command(cmd, 1, stat, 1);		TRACE(ft_t_warn, "FDC is already locked");	}	/* Test for a i82078 FDC */	cmd[0] = FDC_PARTID;	if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) {		/* invalid command: not a i82078xx type FDC */		for (i = 0; i < 4; ++i) {			outb_p(i, fdc.tdr);			if ((inb_p(fdc.tdr) & 0x03) != i) {				TRACE_ABORT(i82077,					    ft_t_warn, "Type 82077 FDC found");			}		}		TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found");	}	/* FDC_PARTID cmd succeeded */	switch (stat[0] >> 5) {	case 0x0:		/* i82078SL or i82078-1.  The SL part cannot run at		 * 2Mbps (the SL and -1 dies are identical; they are		 * speed graded after production, according to Intel).		 * Some SL's can be detected by doing a SAVE cmd and		 * look at bit 7 of the first byte (the SEL3V# bit).		 * If it is 0, the part runs off 3Volts, and hence it		 * is a SL.		 */		cmd[0] = FDC_SAVE;		if(fdc_issue_command(cmd, 1, stat, 16) < 0) {			TRACE(ft_t_err, "FDC_SAVE failed. Dunno why");			/* guess we better claim the fdc to be a i82078 */			TRACE_ABORT(i82078,				    ft_t_warn,				    "Type i82078 FDC (i suppose) found");		}		if ((stat[0] & FDC_SEL3V_BIT)) {			/* fdc running off 5Volts; Pray that it's a i82078-1			 */			TRACE_ABORT(i82078_1, ft_t_warn,				  "Type i82078-1 or 5Volt i82078SL FDC found");		}		TRACE_ABORT(i82078, ft_t_warn,			    "Type 3Volt i82078SL FDC (1Mbps) found");	case 0x1:	case 0x2: /* S82078B  */		/* The '78B  isn't '78 compatible.  Detect it as a '77AA */		TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found");	case 0x3: /* NSC PC8744 core; used in several super-IO chips */		TRACE_ABORT(i82077AA,			    ft_t_warn, "Type 82077AA compatible FDC found");	default:		TRACE(ft_t_warn, "A previously undetected FDC found");		TRACE_ABORT(i82077AA, ft_t_warn,			  "Treating it as a 82077AA. Please report partid= %d",			    stat[0]);	} /* switch(stat[ 0] >> 5) */	TRACE_EXIT no_fdc;}static int fdc_request_regions(void){	TRACE_FUN(ft_t_flow);	if (ft_mach2 || ft_probe_fc10) {		if (!request_region(fdc.sra, 8, "fdc (ft)")) {#ifndef BROKEN_FLOPPY_DRIVER			TRACE_EXIT -EBUSY;#else			TRACE(ft_t_warn,"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra);#endif		}	} else {		if (!request_region(fdc.sra, 6, "fdc (ft)")) {#ifndef BROKEN_FLOPPY_DRIVER			TRACE_EXIT -EBUSY;#else			TRACE(ft_t_warn,"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra);#endif		}		if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) {#ifndef BROKEN_FLOPPY_DRIVER			release_region(fdc.sra, 6);			TRACE_EXIT -EBUSY;#else			TRACE(ft_t_warn,"address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7);#endif		}	}	TRACE_EXIT 0;}void fdc_release_regions(void){	TRACE_FUN(ft_t_flow);	if (fdc.sra != 0) {		if (fdc.dor2 != 0) {			release_region(fdc.sra, 8);		} else {			release_region(fdc.sra, 6);			release_region(fdc.dir, 1);		}	}	TRACE_EXIT;}static int fdc_config_regs(unsigned int fdc_base, 			   unsigned int fdc_irq, 			   unsigned int fdc_dma){	TRACE_FUN(ft_t_flow);	fdc.irq = fdc_irq;	fdc.dma = fdc_dma;	fdc.sra = fdc_base;	fdc.srb = fdc_base + 1;	fdc.dor = fdc_base + 2;	fdc.tdr = fdc_base + 3;	fdc.msr = fdc.dsr = fdc_base + 4;	fdc.fifo = fdc_base + 5;	fdc.dir = fdc.ccr = fdc_base + 7;	fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0;	TRACE_CATCH(fdc_request_regions(), fdc.sra = 0);	TRACE_EXIT 0;}static int fdc_config(void){	static int already_done;	TRACE_FUN(ft_t_any);	if (already_done) {		TRACE_CATCH(fdc_request_regions(),);		*(fdc.hook) = fdc_isr;	/* hook our handler in */		TRACE_EXIT 0;	}	if (ft_probe_fc10) {		int fc_type;				TRACE_CATCH(fdc_config_regs(ft_fdc_base,					    ft_fdc_irq, ft_fdc_dma),);		fc_type = fc10_enable();		if (fc_type != 0) {			TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type);			fdc.type = fc10;			fdc.hook = &do_ftape;			*(fdc.hook) = fdc_isr;	/* hook our handler in */			already_done = 1;			TRACE_EXIT 0;		} else {			TRACE(ft_t_warn, "FC-10/20 controller not found");			fdc_release_regions();			fdc.type = no_fdc;			ft_probe_fc10 = 0;			ft_fdc_base   = 0x3f0;			ft_fdc_irq    = 6;			ft_fdc_dma    = 2;		}	}	TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", 	      ft_fdc_base, ft_fdc_irq, ft_fdc_dma);	TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),);	fdc.hook = &do_ftape;	*(fdc.hook) = fdc_isr;	/* hook our handler in */	already_done = 1;	TRACE_EXIT 0;}static irqreturn_t ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs){	void (*handler) (void) = *fdc.hook;	int handled = 0;	TRACE_FUN(ft_t_any);	*fdc.hook = NULL;	if (handler) {		handled = 1;		handler();	} else {		TRACE(ft_t_bug, "Unexpected ftape interrupt");	}	TRACE_EXIT IRQ_RETVAL(handled);}static int fdc_grab_irq_and_dma(void){	TRACE_FUN(ft_t_any);	if (fdc.hook == &do_ftape) {		/*  Get fast interrupt handler.		 */		if (request_irq(fdc.irq, ftape_interrupt,				SA_INTERRUPT, "ft", ftape_id)) {			TRACE_ABORT(-EIO, ft_t_bug,				    "Unable to grab IRQ%d for ftape driver",				    fdc.irq);		}		if (request_dma(fdc.dma, ftape_id)) {			free_irq(fdc.irq, ftape_id);			TRACE_ABORT(-EIO, ft_t_bug,			      "Unable to grab DMA%d for ftape driver",			      fdc.dma);		}	}	if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {		/* Using same dma channel or irq as standard fdc, need		 * to disable the dma-gate on the std fdc. This		 * couldn't be done in the floppy driver as some		 * laptops are using the dma-gate to enter a low power		 * or even suspended state :-(		 */		outb_p(FDC_RESET_NOT, 0x3f2);		TRACE(ft_t_noise, "DMA-gate on standard fdc disabled");	}	TRACE_EXIT 0;}int fdc_release_irq_and_dma(void){	TRACE_FUN(ft_t_any);	if (fdc.hook == &do_ftape) {		disable_dma(fdc.dma);	/* just in case... */		free_dma(fdc.dma);		free_irq(fdc.irq, ftape_id);	}	if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {		/* Using same dma channel as standard fdc, need to		 * disable the dma-gate on the std fdc. This couldn't		 * be done in the floppy driver as some laptops are		 * using the dma-gate to enter a low power or even		 * suspended state :-(		 */		outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2);		TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again");	}	TRACE_EXIT 0;}int fdc_init(void){	TRACE_FUN(ft_t_any);	/* find a FDC to use */	TRACE_CATCH(fdc_config(),);	TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions());	ftape_motor = 0;	fdc_catch_stray_interrupts(0);	/* clear number of awainted					 * stray interrupte 					 */	fdc_catch_stray_interrupts(1);	/* one always comes (?) */	TRACE(ft_t_flow, "resetting fdc");	fdc_set_seek_rate(2);		/* use nominal QIC step rate */	fdc_reset();			/* init fdc & clear track counters */	if (fdc.type == no_fdc) {	/* no FC-10 or FC-20 found */		fdc.type = fdc_probe();		fdc_reset();		/* update with new knowledge */	}	if (fdc.type == no_fdc) {		fdc_release_irq_and_dma();		fdc_release_regions();		TRACE_EXIT -ENXIO;	}	if (fdc.type >= i82077) {		if (fdc_fifo_enable() < 0) {			TRACE(ft_t_warn, "couldn't enable fdc fifo !");		} else {			TRACE(ft_t_flow, "fdc fifo enabled and locked");		}	}	TRACE_EXIT 0;}

⌨️ 快捷键说明

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