Пример #1
0
/*
 * 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();
}
Пример #2
0
/*
 * 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);
	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);
	}
	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();
}
Пример #3
0
/**
 * 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.
 *
 * @see rw_interrupt 
 */
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();
}
Пример #4
0
static void shake_done(void)
{
    current_track = NO_TRACK;
    if (inb(FD_DIR) & 0x80)
        request_done(0);
    redo_fd_request();
}
Пример #5
0
/*
 * 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;
    }
}
Пример #6
0
static void floppy_shutdown(void) {

	cli();
	do_floppy = NULL;
	request_done(0);
	recover = 1;
	reset_floppy();
	sti();
	redo_fd_request();
}
Пример #7
0
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();
}
Пример #8
0
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();
	else redo_fd_request();
}
Пример #9
0
/*
 * 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();
}
Пример #10
0
static void fd_error(void)
{
	printk("FDC1772: fd_error\n");
	/*panic("fd1772: fd_error"); *//* DAG tmp */
	if (!CURRENT)
		return;
	CURRENT->errors++;
	if (CURRENT->errors >= MAX_ERRORS) {
		printk("fd%d: too many errors.\n", SelectedDrive);
		end_request(CURRENT, 0);
	} else if (CURRENT->errors == RECALIBRATE_ERRORS) {
		printk("fd%d: recalibrating\n", SelectedDrive);
		if (SelectedDrive != -1)
			unit[SelectedDrive].track = -1;
	}
	redo_fd_request();
}
Пример #11
0
static void do_fd_action(int drive)
{
	struct request *req;
	DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));

#ifdef TRACKBUFFER
repeat:

	if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
		req = CURRENT;
		if (ReqCmd == READ) {
			copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
			if (++ReqCnt < req->current_nr_sectors) {
				/* read next sector */
				setup_req_params( drive );
				goto repeat;
			} else {
				/* all sectors finished */
				req->nr_sectors -= req->current_nr_sectors;
				req->sector += req->current_nr_sectors;
				end_request(req, 1);
				redo_fd_request();
				return;
			}
		} else {
			/* cmd == WRITE, pay attention to track buffer
			 * consistency! */
			copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
		}
	}
#endif

	if (SelectedDrive != drive) {
		/*unit[drive].track = -1; DAG */
		fd_select_drive(drive);
	};


	if (unit[drive].track == -1)
		fd_calibrate();
	else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
		fd_seek();
	else
		fd_rwsec();
}
Пример #12
0
/**
 * 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();
}