patch-1.3.92 linux/drivers/block/floppy.c

Next file: linux/drivers/block/ide.c
Previous file: linux/drivers/block/README.fd
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.91/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
@@ -157,12 +157,18 @@
 #include <linux/ioport.h>
 
 #include <asm/dma.h>
-#include <asm/floppy.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 
+static int use_virtual_dma=0; /* virtual DMA for Intel */
+static unsigned short virtual_dma_port=0x3f0;
+static void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static int set_dor(int fdc, char mask, char data);
+#include <asm/floppy.h>
+
+
 #define MAJOR_NR FLOPPY_MAJOR
 
 #include <linux/blk.h>
@@ -177,6 +183,10 @@
 #define fd_eject(x) -EINVAL
 #endif
 
+#ifndef fd_get_dma_residue
+#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
+#endif
+
 /* Dma Memory related stuff */
 
 /* Pure 2^n version of get_order */
@@ -479,7 +489,7 @@
 static void floppy_start(void);
 static void process_fd_request(void);
 static void recalibrate_floppy(void);
-static void floppy_shutdown(void);
+static void floppy_shutdown(unsigned long);
 
 static int floppy_grab_irq_and_dma(void);
 static void floppy_release_irq_and_dma(void);
@@ -517,7 +527,7 @@
 static struct floppy_fdc_state fdc_state[N_FDC];
 static int fdc; /* current fdc */
 
-static struct floppy_struct * floppy = floppy_type;
+static struct floppy_struct *_floppy = floppy_type;
 static unsigned char current_drive = 0;
 static long current_count_sectors = 0;
 static unsigned char sector_t; /* sector in track */
@@ -918,7 +928,7 @@
 
 	if (disk_change(current_drive)){
 		DPRINT("disk removed during i/o\n");
-		floppy_shutdown();
+		floppy_shutdown(1);
 	} else {
 		del_timer(&fd_timer);
 		fd_timer.function = (timeout_fn) fd_watchdog;
@@ -1019,82 +1029,103 @@
 			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();
 	sti();
 	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) {
+		DPRINT2("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 counter;
-	unsigned char status = 0;
-	unsigned char rstatus;
+	int status;
 
-	if (FDCS->reset)
+	if ((status = wait_til_ready()) < 0)
 		return -1;
-	for (counter = 0; counter < 10000 && !FDCS->reset; counter++) {
-		rstatus = fd_inb(FD_STATUS);
-		status =  rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA);
-		if (!(status & STATUS_READY))
-			continue;
-		if (status == STATUS_READY){
-			fd_outb(byte,FD_DATA);
-
+	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 = rstatus;
-			output_log[output_log_pos].jiffies = jiffies;
-			output_log_pos = (output_log_pos + 1) % OLOGSIZE;
+		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;
-		} else
-			break;
+		return 0;
 	}
 	FDCS->reset = 1;
-	if (!initialising)
+	if (!initialising) {
 		DPRINT2("Unable to send byte %x to FDC. Status=%x\n",
 			byte, status);
+		show_floppy();
+	}
 	return -1;
 }
-#define LAST_OUT(x) if (output_byte(x)){ reset_fdc();return;}
+#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
 
 /* gets the response from the fdc */
 static int result(void)
 {
-	int i = 0, counter, status = 0;
+	int i, status;
 
-	if (FDCS->reset)
-		return -1;
-	for (counter = 0; counter < 10000 && !FDCS->reset; counter++) {
-		status = fd_inb(FD_STATUS)&
-			(STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
-		if (!(status & STATUS_READY))
-			continue;
-		if (status == STATUS_READY){
+	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_DMA)
+		if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY))
+			reply_buffer[i] = fd_inb(FD_DATA);
+		else
 			break;
-		if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
-			if (i >= MAX_REPLIES) {
-				DPRINT("floppy_stat reply overrun\n");
-				break;
-			}
-			reply_buffer[i++] = fd_inb(FD_DATA);
-		}
+	}
+	if(!initialising) {
+		DPRINT2("'get result' error. Last status=%x Read bytes=%d\n",
+			status, i);
+		show_floppy();
 	}
 	FDCS->reset = 1;
-	if (!initialising)
-		DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n",
-			status, fdc, i);
 	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.
  */
@@ -1123,7 +1154,7 @@
 
 	if (FDCS->perp_mode == perp_mode)
 		return;
-	if (FDCS->version >= FDC_82072A && FDCS->has_fifo) {
+	if (FDCS->version >= FDC_82077_ORIG) {
 		output_byte(FD_PERPENDICULAR);
 		output_byte(perp_mode);
 		FDCS->perp_mode = perp_mode;
@@ -1132,6 +1163,27 @@
 	}
 } /* perpendicular_mode */
 
+static int fifo = 0xa;
+
+static int fdc_configure(void)
+{
+	/* Turn on FIFO */
+	output_byte(FD_CONFIGURE);
+#ifdef __sparc__ 
+	output_byte(0x64);	/* Motor off timeout */
+	output_byte(fdc_cfg | 0x0A);
+#else
+	if(need_more_output() != MORE_OUTPUT)
+		return 0;
+	output_byte(0);
+	output_byte(0x10 | (fifo & 0xf)); /* FIFO on, polling off,
+					     10 byte threshold */
+#endif
+	output_byte(0);	/* precompensation from track 
+			   0 upwards */
+	return 1;
+}	
+
 #define NOMINAL_DTR 500
 
 /* Issue a "SPECIFY" command to set the step rate time, head unload time,
@@ -1163,25 +1215,7 @@
 	int hut_max_code = 0xf;
 
 	if (FDCS->need_configure && FDCS->has_fifo) {
-		if (FDCS->reset)
-			return;
-#ifdef __sparc__ 
-		output_byte(FD_CONFIGURE);
-		output_byte(0x64);	/* Motor off timeout */
-		output_byte(fdc_cfg | 0x0A);
-		output_byte(0);
-#else
-		/* Turn on FIFO for 82077-class FDC (improves performance) */
-		/* TODO: lock this in via LOCK during initialization */
-		output_byte(FD_CONFIGURE);
-		output_byte(0);
-		output_byte(0x2A);	/* FIFO on, polling off, 10 byte threshold */
-		output_byte(0);		/* precompensation from track 0 upwards */
-		if (FDCS->reset){
-			FDCS->has_fifo=0;
-			return;
-		}
-#endif
+		fdc_configure();
 		FDCS->need_configure = 0;
 		/*DPRINT("FIFO enabled\n");*/
 	}
@@ -1228,7 +1262,7 @@
 		hut = hut_max_code;
 
 	spec1 = (srt << 4) | hut;
-	spec2 = (hlt << 1);
+	spec2 = (hlt << 1) | (use_virtual_dma & 1);
 
 	/* If these parameters did not change, just return with success */
 	if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
@@ -1289,6 +1323,8 @@
 	/* 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");
@@ -1391,6 +1427,7 @@
 	debugt("rw_command: ");
 #endif
 	if (r){
+		cont->error();
 		reset_fdc();
 		return;
 	}
@@ -1754,9 +1791,9 @@
 	printk("\n");
 }
 
-static void floppy_shutdown(void)
+static void floppy_shutdown(unsigned long mode)
 {
-	if (!initialising)
+	if (!initialising && !mode)
 		show_floppy();
 	CLEAR_INTR;
 	floppy_tq.routine = (void *)(void *) empty;
@@ -1767,7 +1804,7 @@
 	fd_disable_dma();
 	/* avoid dma going to a random drive after shutdown */
 
-	if (!initialising)
+	if (!initialising && !mode)
 		DPRINT("floppy timeout\n");
 	FDCS->reset = 1;
 	if (cont){
@@ -1895,7 +1932,7 @@
 			sleep_on(&command_done);
 	}
 	if (command_status < 2){
-		floppy_shutdown();
+		floppy_shutdown(1);
 		sti();
 		process_fd_request();
 		return -EINTR;
@@ -1979,9 +2016,9 @@
 static void set_floppy(kdev_t device)
 {
 	if (TYPE(device))
-		floppy = TYPE(device) + floppy_type;
+		_floppy = TYPE(device) + floppy_type;
 	else
-		floppy = current_type[ DRIVE(device) ];
+		_floppy = current_type[ DRIVE(device) ];
 }
 
 /*
@@ -2017,13 +2054,13 @@
 
 	raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
 		/*FD_RAW_NEED_DISK |*/ FD_RAW_NEED_SEEK;
-	raw_cmd->rate = floppy->rate & 0x43;
+	raw_cmd->rate = _floppy->rate & 0x43;
 	raw_cmd->cmd_count = NR_F;
-	COMMAND = FM_MODE(floppy,FD_FORMAT);
-	DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head);
-	F_SIZECODE = FD_SIZECODE(floppy);
-	F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE;
-	F_GAP = floppy->fmt_gap;
+	COMMAND = FM_MODE(_floppy,FD_FORMAT);
+	DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,format_req.head);
+	F_SIZECODE = FD_SIZECODE(_floppy);
+	F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
+	F_GAP = _floppy->fmt_gap;
 	F_FILL = FD_FILL_BYTE;
 
 	raw_cmd->kernel_data = floppy_track_buffer;
@@ -2041,7 +2078,7 @@
 
 	/* determine interleave */
 	il = 1;
-	if (floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
+	if (_floppy->sect > DP->interleave_sect && F_SIZECODE == 2)
 		il++;
 
 	/* initialize field */
@@ -2068,7 +2105,7 @@
 static void redo_format(void)
 {
 	buffer_track = -1;
-	setup_format_params(format_req.track << STRETCH(floppy));
+	setup_format_params(format_req.track << STRETCH(_floppy));
 	floppy_start();
 #ifdef DEBUGT
 	debugt("queue format request");
@@ -2088,12 +2125,12 @@
 
 	LOCK_FDC(drive,1);
 	set_floppy(device);
-	if (!floppy ||
-	    floppy->track > DP->tracks ||
-	    tmp_format_req->track >= floppy->track ||
-	    tmp_format_req->head >= floppy->head ||
-	    (floppy->sect << 2) % (1 <<  FD_SIZECODE(floppy)) ||
-	    !floppy->fmt_gap) {
+	if (!_floppy ||
+	    _floppy->track > DP->tracks ||
+	    tmp_format_req->track >= _floppy->track ||
+	    tmp_format_req->head >= _floppy->head ||
+	    (_floppy->sect << 2) % (1 <<  FD_SIZECODE(_floppy)) ||
+	    !_floppy->fmt_gap) {
 		process_fd_request();
 		return -EINVAL;
 	}
@@ -2130,7 +2167,7 @@
 		 * change */
 		block = current_count_sectors + CURRENT->sector;
 		INFBOUND(DRS->maxblock, block);
-		if (block > floppy->sect)
+		if (block > _floppy->sect)
 			DRS->maxtrack = 1;
 
 		/* unlock chained buffers */
@@ -2171,16 +2208,21 @@
 /* Interrupt handler evaluating the result of the r/w operation */
 static void rw_interrupt(void)
 {
-	int nr_sectors, ssize;
+	int nr_sectors, ssize, eoc;
 
 	if (!DRS->first_read_date)
 		DRS->first_read_date = jiffies;
 
 	nr_sectors = 0;
 	CODE2SIZE;
-	nr_sectors = ((R_TRACK-TRACK)*floppy->head+R_HEAD-HEAD) *
-		floppy->sect + ((R_SECTOR-SECTOR) <<  SIZECODE >> 2) -
-		(sector_t % floppy->sect) % ssize;
+
+	if(ST1 & ST1_EOC)
+		eoc = 1;
+	else
+		eoc = 0;
+	nr_sectors = ((R_TRACK-TRACK)*_floppy->head+R_HEAD-HEAD) *
+		_floppy->sect + ((R_SECTOR-SECTOR+eoc) <<  SIZECODE >> 2) -
+		(sector_t % _floppy->sect) % ssize;
 
 #ifdef FLOPPY_SANITY_CHECK
 	if (nr_sectors > current_count_sectors + ssize -
@@ -2214,17 +2256,17 @@
 				cont->redo();
 				return;
 			}
-			current_type[current_drive] = floppy;
-			floppy_sizes[TOMINOR(current_drive) ]= floppy->size>>1;
+			current_type[current_drive] = _floppy;
+			floppy_sizes[TOMINOR(current_drive) ]= _floppy->size>>1;
 			break;
 	}
 
 	if (probing) {
 		if (DP->flags & FTD_MSG)
 			DPRINT2("Auto-detected floppy type %s in fd%d\n",
-				floppy->name,current_drive);
-		current_type[current_drive] = floppy;
-		floppy_sizes[TOMINOR(current_drive)] = floppy->size >> 1;
+				_floppy->name,current_drive);
+		current_type[current_drive] = _floppy;
+		floppy_sizes[TOMINOR(current_drive)] = _floppy->size >> 1;
 		probing = 0;
 	}
 
@@ -2267,7 +2309,7 @@
 	SUPBOUND(max_sector, sector_t + max_size);
 
 	/* alignment */
-	max_sector -= (max_sector % floppy->sect) % ssize;
+	max_sector -= (max_sector % _floppy->sect) % ssize;
 
 	/* transfer size, beginning not aligned */
 	current_count_sectors = max_sector - sector_t ;
@@ -2392,40 +2434,40 @@
 	raw_cmd->cmd_count = NR_RW;
 	if (CURRENT->cmd == READ){
 		raw_cmd->flags |= FD_RAW_READ;
-		COMMAND = FM_MODE(floppy,FD_READ);
+		COMMAND = FM_MODE(_floppy,FD_READ);
 	} else if (CURRENT->cmd == WRITE){
 		raw_cmd->flags |= FD_RAW_WRITE;
-		COMMAND = FM_MODE(floppy,FD_WRITE);
+		COMMAND = FM_MODE(_floppy,FD_WRITE);
 	} else {
 		DPRINT("make_raw_rw_request: unknown command\n");
 		return 0;
 	}
 
-	max_sector = floppy->sect * floppy->head;
+	max_sector = _floppy->sect * _floppy->head;
 
 	TRACK = CURRENT->sector / max_sector;
 	sector_t = CURRENT->sector % max_sector;
-	if (floppy->track && TRACK >= floppy->track)
+	if (_floppy->track && TRACK >= _floppy->track)
 		return 0;
-	HEAD = sector_t / floppy->sect;
+	HEAD = sector_t / _floppy->sect;
 
-	if (((floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) &&
-	    sector_t < floppy->sect)
-		max_sector = floppy->sect;
+	if (((_floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) &&
+	    sector_t < _floppy->sect)
+		max_sector = _floppy->sect;
 
 	/* 2M disks have phantom sectors on the first track */
-	if ((floppy->rate & FD_2M) && (!TRACK) && (!HEAD)){
-		max_sector = 2 * floppy->sect / 3;
+	if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)){
+		max_sector = 2 * _floppy->sect / 3;
 		if (sector_t >= max_sector){
-			current_count_sectors = minimum(floppy->sect - sector_t,
+			current_count_sectors = minimum(_floppy->sect - sector_t,
 							CURRENT->nr_sectors);
 			return 1;
 		}
 		SIZECODE = 2;
 	} else
-		SIZECODE = FD_SIZECODE(floppy);
-	raw_cmd->rate = floppy->rate & 0x43;
-	if ((floppy->rate & FD_2M) &&
+		SIZECODE = FD_SIZECODE(_floppy);
+	raw_cmd->rate = _floppy->rate & 0x43;
+	if ((_floppy->rate & FD_2M) &&
 	    (TRACK || HEAD) &&
 	    raw_cmd->rate == 2)
 		raw_cmd->rate = 1;
@@ -2434,30 +2476,30 @@
 		SIZECODE2 = 0xff;
 	else
 		SIZECODE2 = 0x80;
-	raw_cmd->track = TRACK << STRETCH(floppy);
-	DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,HEAD);
-	GAP = floppy->gap;
+	raw_cmd->track = TRACK << STRETCH(_floppy);
+	DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,HEAD);
+	GAP = _floppy->gap;
 	CODE2SIZE;
-	SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE;
-	SECTOR = ((sector_t % floppy->sect) << 2 >> SIZECODE) + 1;
-	tracksize = floppy->sect - floppy->sect % ssize;
-	if (tracksize < floppy->sect){
+	SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
+	SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1;
+	tracksize = _floppy->sect - _floppy->sect % ssize;
+	if (tracksize < _floppy->sect){
 		SECT_PER_TRACK ++;
-		if (tracksize <= sector_t % floppy->sect)
+		if (tracksize <= sector_t % _floppy->sect)
 			SECTOR--;
-		while (tracksize <= sector_t % floppy->sect){
-			while(tracksize + ssize > floppy->sect){
+		while (tracksize <= sector_t % _floppy->sect){
+			while(tracksize + ssize > _floppy->sect){
 				SIZECODE--;
 				ssize >>= 1;
 			}
 			SECTOR++; SECT_PER_TRACK ++;
 			tracksize += ssize;
 		}
-		max_sector = HEAD * floppy->sect + tracksize;
-	} else if (!TRACK && !HEAD && !(floppy->rate & FD_2M) && probing)
-		max_sector = floppy->sect;
+		max_sector = HEAD * _floppy->sect + tracksize;
+	} else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing)
+		max_sector = _floppy->sect;
 
-	aligned_sector_t = sector_t - (sector_t % floppy->sect) % ssize;
+	aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize;
 	max_size = CURRENT->nr_sectors;
 	if ((raw_cmd->track == buffer_track) && 
 	    (current_drive == buffer_drive) &&
@@ -2477,7 +2519,7 @@
 		}
 		raw_cmd->flags &= ~FD_RAW_WRITE;
 		raw_cmd->flags |= FD_RAW_READ;
-		COMMAND = FM_MODE(floppy,FD_READ);
+		COMMAND = FM_MODE(_floppy,FD_READ);
 	} else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS) {
 		unsigned long dma_limit;
 		int direct, indirect;
@@ -2666,17 +2708,17 @@
 			DPRINT("disk absent or changed during operation\n");
 			REPEAT;
 		}
-		if (!floppy) { /* Autodetection */
+		if (!_floppy) { /* Autodetection */
 			if (!probing){
 				DRS->probed_format = 0;
 				if (next_valid_format()){
 					DPRINT("no autodetectable formats\n");
-					floppy = NULL;
+					_floppy = NULL;
 					REPEAT;
 				}
 			}
 			probing = 1;
-			floppy = floppy_type+DP->autodetect[DRS->probed_format];
+			_floppy = floppy_type+DP->autodetect[DRS->probed_format];
 		} else
 			probing = 0;
 		errors = & (CURRENT->errors);
@@ -2844,7 +2886,7 @@
 			raw_cmd->reply[i] = reply_buffer[i];
 
 		if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE))
-			raw_cmd->length = get_dma_residue(FLOPPY_DMA);
+			raw_cmd->length = fd_get_dma_residue();
 		
 		if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
 		    (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
@@ -3692,13 +3734,14 @@
 {
 	int r;
 
+	FDCS->has_fifo = 0;
 	output_byte(FD_DUMPREGS);	/* 82072 and better know DUMPREGS */
 	if (FDCS->reset)
 		return FDC_NONE;
 	if ((r = result()) <= 0x00)
 		return FDC_NONE;	/* No FDC present ??? */
 	if ((r==1) && (reply_buffer[0] == 0x80)){
-		printk(KERN_INFO "FDC %d is a 8272A\n",fdc);
+		printk(KERN_INFO "FDC %d is an 8272A\n",fdc);
 		return FDC_8272A;	/* 8272a/765 don't know DUMPREGS */
 	}
 	if (r != 10) {
@@ -3709,7 +3752,7 @@
 	output_byte(FD_VERSION);
 	r = result();
 	if ((r == 1) && (reply_buffer[0] == 0x80)){
-		printk(KERN_INFO "FDC %d is a 82072\n",fdc);
+		printk(KERN_INFO "FDC %d is an 82072\n",fdc);
 		return FDC_82072;		/* 82072 doesn't know VERSION */
 	}
 	if ((r != 1) || (reply_buffer[0] != 0x90)) {
@@ -3717,12 +3760,20 @@
 		       fdc, r);
 		return FDC_UNKNOWN;
 	}
+	FDCS->has_fifo = fdc_configure();
+	output_byte(FD_PERPENDICULAR);
+	if(need_more_output() == MORE_OUTPUT) {
+		output_byte(0);
+	} else {
+		printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
+		return FDC_82072A;	/* 82072A as found on Sparcs. */
+	}
+
 	output_byte(FD_UNLOCK);
 	r = result();
 	if ((r == 1) && (reply_buffer[0] == 0x80)){
-		printk(KERN_INFO "FDC %d is a 82072A\n", fdc);
-		return FDC_82072A;	/* Pre-1991 82077 or 82072A as found
-					 * on Sparcs. These doesn't know 
+		printk(KERN_INFO "FDC %d is a pre-1991 82077\n", fdc);
+		return FDC_82077_ORIG;	/* Pre-1991 82077, doesn't know 
 					 * LOCK/UNLOCK */
 	}
 	if ((r != 1) || (reply_buffer[0] != 0x00)) {
@@ -3754,7 +3805,7 @@
 				return FDC_82078;
 			}
 			/* Either a 82078-1 or a 82078SL running at 5Volt */
-			printk(KERN_INFO "FDC %d is a 82078-1.\n",fdc);
+			printk(KERN_INFO "FDC %d is an 82078-1.\n",fdc);
 			return FDC_82078_1;
 		case 0x1:
 			printk(KERN_INFO "FDC %d is a 44pin 82078\n",fdc);
@@ -3806,28 +3857,6 @@
 	DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-static void allow_drives(int *ints, int param)
-{
-	allowed_drive_mask=param;
-	DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
-}
-
-static void fdc2_adr(int *ints, int param)
-{
-	FDC2 = param;
-	if (param)
-		DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
-	else
-		DPRINT("disabling second fdc\n");
-}
-
-static void unex(int *ints,int param)
-{
-	print_unex = param;
-	DPRINT1("%sprinting messages for unexpected interrupts\n",
-		param ? "" : "not ");
-}
-
 static void set_cmos(int *ints, int dummy)
 {
 	int current_drive=0;
@@ -3842,7 +3871,7 @@
 		return;
 	}
 	if (current_drive >= 4 && !FDC2)
-		fdc2_adr(0, 0x370);
+		FDC2 = 0x370;
 	if (ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
 		DPRINT1("bad cmos code %d\n", ints[2]);
 		return;
@@ -3854,24 +3883,31 @@
 static struct param_table {
 	const char *name;
 	void (*fn)(int *ints, int param);
+	int *var;
 	int def_param;
 } config_params[]={
-	{ "allowed_drive_mask", allow_drives, 0xff },
-	{ "all_drives", allow_drives, 0xff },
-	{ "asus_pci", allow_drives, 0x33 },
+	{ "allowed_drive_mask", 0, &allowed_drive_mask, 0xff },
+	{ "all_drives", 0, &allowed_drive_mask, 0xff },
+	{ "asus_pci", 0, &allowed_drive_mask, 0x33 },
+
+	{ "daring", daring, 0, 1},
+
+	{ "two_fdc",  0, &FDC2, 0x370 },
+	{ "one_fdc", 0, &FDC2, 0 },
 
-	{ "daring", daring, 1},
+	{ "thinkpad", floppy_invert_dcl, 0, 1 },
 
-	{ "two_fdc", fdc2_adr, 0x370 },
-	{ "one_fdc", fdc2_adr, 0 },
+	{ "nodma", 0, &use_virtual_dma, 1 },
+	{ "omnibook", 0, &use_virtual_dma, 1 },
+	{ "dma", 0, &use_virtual_dma, 0 },
 
-	{ "thinkpad", floppy_invert_dcl, 1 },
+	{ "fifo", 0, &fifo, 0xa },
 
-	{ "cmos", set_cmos, 0 },
+	{ "cmos", set_cmos, 0, 0 },
 
-	{ "unexpected_interrupts", unex, 1 },
-	{ "no_unexpected_interrupts", unex, 0 },
-	{ "L40SX", unex, 0 } };
+	{ "unexpected_interrupts", 0, &print_unex, 1 },
+	{ "no_unexpected_interrupts", 0, &print_unex, 0 },
+	{ "L40SX", 0, &print_unex, 0 } };
 
 #define FLOPPY_SETUP
 void floppy_setup(char *str, int *ints)
@@ -3885,7 +3921,12 @@
 					param = ints[1];
 				else
 					param = config_params[i].def_param;
-				config_params[i].fn(ints,param);
+				if(config_params[i].fn)
+					config_params[i].fn(ints,param);
+				if(config_params[i].var) {
+					DPRINT2("%s=%d\n", str, param);
+					*config_params[i].var = param;
+				}
 				return;
 			}
 		}
@@ -3986,7 +4027,6 @@
 		 * properly, so force a reset for the standard FDC clones,
 		 * to avoid interrupt garbage.
 		 */
-		FDCS->has_fifo = FDCS->version >= FDC_82072A;
 		user_reset_fdc(-1,FD_RESET_ALWAYS,0);
 	}
 	fdc=0;
@@ -4094,6 +4134,24 @@
 
 extern char *get_options(char *str, int *ints);
 
+char *floppy=NULL;
+
+static void parse_floppy_cfg_string(char *cfg)
+{
+	char *ptr;
+	int ints[11];
+
+	while(*cfg) {
+		for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++);
+		if(*cfg) {
+			*cfg = '\0';
+			cfg++;
+		}
+		if(*ptr)
+			floppy_setup(get_options(ptr,ints),ints);
+	}
+}
+
 static void mod_setup(char *pattern, void (*setup)(char *, int *))
 {
 	unsigned long i;
@@ -4144,14 +4202,17 @@
 {
 	printk(KERN_INFO "inserting floppy driver for %s\n", kernel_version);
 		
-	mod_setup("floppy=", floppy_setup);
+	if(floppy)
+		parse_floppy_cfg_string(floppy);
+	else
+		mod_setup("floppy=", floppy_setup);
 		
 	return floppy_init();
 }
 
 void cleanup_module(void)
 {
-	int fdc;
+	int fdc, dummy;
 		
 	for (fdc=0; fdc<2; fdc++)
 		if (FDCS->address != -1){
@@ -4163,7 +4224,7 @@
 
 	blk_dev[MAJOR_NR].request_fn = 0;
 	/* eject disk, if any */
-	fd_eject(0);
+	dummy = fd_eject(0);
 }
 
 #ifdef __cplusplus

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this