while (!ft_interrupt_seen && timeout) { set_current_state(TASK_INTERRUPTIBLE); timeout = schedule_timeout(timeout); } 
while (!ft_interrupt_seen && timeout) timeout = schedule_timeout_interruptible(timeout); 
int fdc_interrupt_wait(unsigned int time){	DECLARE_WAITQUEUE(wait,current);	sigset_t old_sigmask;		static int resetting;	long timeout;	TRACE_FUN(ft_t_fdc_dma); 	if (waitqueue_active(&ftape_wait_intr)) {		TRACE_ABORT(-EIO, ft_t_err, "error: nested call");	}	/* timeout time will be up to USPT microseconds too long ! */	timeout = (1000 * time + FT_USPT - 1) / FT_USPT;	spin_lock_irq(&current->sighand->siglock);	old_sigmask = current->blocked;	sigfillset(&current->blocked);	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	set_current_state(TASK_INTERRUPTIBLE);	add_wait_queue(&ftape_wait_intr, &wait);	while (!ft_interrupt_seen && timeout) {		set_current_state(TASK_INTERRUPTIBLE);		timeout = schedule_timeout(timeout);        }	spin_lock_irq(&current->sighand->siglock);	current->blocked = old_sigmask;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);		remove_wait_queue(&ftape_wait_intr, &wait);	/*  the following IS necessary. True: as well	 *  wake_up_interruptible() as the schedule() set TASK_RUNNING	 *  when they wakeup a task, BUT: it may very well be that	 *  ft_interrupt_seen is already set to 1 when we enter here	 *  in which case schedule() gets never called, and	 *  TASK_RUNNING never set. This has the funny effect that we	 *  execute all the code until we leave kernel space, but then	 *  the task is stopped (a task CANNOT be preempted while in	 *  kernel mode. Sending a pair of SIGSTOP/SIGCONT to the	 *  tasks wakes it up again. Funny! :-)	 */	current->state = TASK_RUNNING; 	if (ft_interrupt_seen) { /* woken up by interrupt */		ft_interrupt_seen = 0;		TRACE_EXIT 0;	}	/*  Original comment:	 *  In first instance, next statement seems unnecessary since	 *  it will be cleared in fdc_command. However, a small part of	 *  the software seems to rely on this being cleared here	 *  (ftape_close might fail) so stick to it until things get fixed !	 */	/*  My deeply sought of knowledge:	 *  Behold NO! It is obvious. fdc_reset() doesn't call fdc_command()	 *  but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to	 *  be reset here.	 */	ft_interrupt_seen = 0;	/* clear for next call */	if (!resetting) {		resetting = 1;	/* break infinite recursion if reset fails */		TRACE(ft_t_any, "cleanup reset");		fdc_reset();		resetting = 0;	}	TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME;}/*      Start/stop drive motor. Enable DMA mode. */void fdc_motor(int motor){	int unit = ft_drive_sel;	int data = unit | FDC_RESET_NOT | FDC_DMA_MODE;	TRACE_FUN(ft_t_any);	ftape_motor = motor;	if (ftape_motor) {		data |= FDC_MOTOR_0 << unit;		TRACE(ft_t_noise, "turning motor %d on", unit);	} else {		TRACE(ft_t_noise, "turning motor %d off", unit);	}	if (ft_mach2) {		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) {	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;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/da4cd8dfe18ee901b880f94ca0fa79d5cc1cd0eb/fdc-io.c/clean/drivers/char/ftape/lowlevel/fdc-io.c