patch-1.3.4 linux/drivers/block/floppy.c
Next file: linux/drivers/block/hd.c
Previous file: linux/drivers/block/blk.h
Back to the patch index
Back to the overall index
- Lines: 879
- Date:
Mon Jun 26 11:06:50 1995
- Orig file:
v1.3.3/linux/drivers/block/floppy.c
- Orig date:
Mon Apr 3 11:31:31 1995
diff -u --recursive --new-file v1.3.3/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
@@ -81,6 +81,12 @@
* errors to allow safe writing by specialized programs.
*/
+/* 1994/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
+ * by defining bit 1 of the "stretch" parameter to mean put sectors on the
+ * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
+ * drives are "upside-down").
+ */
+
#define CONFIG_FLOPPY_SANITY
#undef CONFIG_FLOPPY_SILENT_DCL_CLEAR
@@ -94,6 +100,24 @@
/* do print messages for unexpected interrupts */
static int print_unex=1;
+#ifdef MODULE
+#define FD_MODULE
+
+#include <linux/module.h>
+/*
+ * NB. we must include the kernel idenfication string in to install the module.
+ */
+#include <linux/version.h>
+char kernel_version[] = UTS_RELEASE;
+
+int FLOPPY_IRQ=6;
+int FLOPPY_DMA=2;
+int ALLOWED_DRIVE_MASK = 0x33;
+int FDC1 = 0x3f0;
+int FDC2 = -1;
+
+#endif
+
#ifndef FD_MODULE
/* the following is the mask of allowed drives. By default units 2 and
* 3 of both floppy controllers are disabled, because switching on the
@@ -120,10 +144,12 @@
#include <linux/fd.h>
#include <linux/errno.h>
#include <linux/malloc.h>
+#include <linux/mm.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/ioport.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -134,20 +160,49 @@
#define MAJOR_NR FLOPPY_MAJOR
#include "blk.h"
+
+/* Dma Memory related stuff */
+
+/* Pure 2^n version of get_order */
+static inline int __get_order (int size)
+{
+ int order;
+
+#ifdef _ASM_IO_H2
+ __asm__ __volatile__("bsr %1,%0"
+ : "=r" (order)
+ : "r" (size / PAGE_SIZE) );
+#else
+ for (order = 0; order < NR_MEM_LISTS; ++order)
+ if (size <= (PAGE_SIZE << order))
+ return order;
+#endif
+ return NR_MEM_LISTS;
+}
+
+static unsigned long dma_mem_alloc(int size)
+{
+ int order = __get_order(size);
+
+ if (order >= NR_MEM_LISTS)
+ return(0);
+ return __get_dma_pages(GFP_KERNEL,order);
+}
+
+/* End dma memory related stuff */
+
static unsigned int fake_change = 0;
static int initialising=1;
-#define FLOPPY0_TYPE ((CMOS_READ(0x10) >> 4) & 15)
-#define FLOPPY1_TYPE (CMOS_READ(0x10) & 15)
-
/*
* Again, the CMOS information doesn't work on the alpha..
*/
#ifdef __alpha__
-#undef FLOPPY0_TYPE
-#undef FLOPPY1_TYPE
#define FLOPPY0_TYPE 6
#define FLOPPY1_TYPE 0
+#else
+#define FLOPPY0_TYPE ((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE (CMOS_READ(0x10) & 15)
#endif
#define N_FDC 2
@@ -186,6 +241,9 @@
#define DPRINT3(x,x1,x2,x3) \
printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
+#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
+#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
+
/* read/write */
#define COMMAND raw_cmd.cmd[0]
#define DR_SELECT raw_cmd.cmd[1]
@@ -213,6 +271,7 @@
#define MAX_DISK_SIZE 2 /* 3984*/
+#define K_64 0x10000 /* 64KB */
/*
* The DMA channel used by the floppy controller cannot access data at
@@ -222,8 +281,12 @@
* driver otherwise. It doesn't matter much for performance anyway, as most
* floppy accesses go through the track buffer.
*/
-#define LAST_DMA_ADDR (0x1000000)
-#define K_64 (0x10000) /* 64 k */
+#ifdef __alpha__
+# define CROSS_64KB(a,s) (0)
+#else
+# define CROSS_64KB(a,s) \
+ ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)
+#endif
/*
* globals used by 'result()'
@@ -299,9 +362,16 @@
/*
* This struct defines the different floppy types.
*
- * The 'stretch' tells if the tracks need to be doubled for some
- * types (ie 360kB diskette in 1.2MB drive etc). Others should
- * be self-explanatory.
+ * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
+ * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
+ * tells if the disk is in Commodore 1581 format, which means side 0 sectors
+ * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
+ * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
+ * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
+ * side 0 is on physical side 0 (but with the misnamed sector IDs).
+ * 'stretch' should probably be renamed to something more general, like
+ * 'options'. Other parameters should be self-explanatory (see also
+ * setfdprm(8)).
*/
static struct floppy_struct floppy_type[32] = {
{ 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
@@ -399,8 +469,8 @@
* corrupted/lost. Alignment of these is enforced in boot/head.S.
* Note that you must not change the sizes below without updating head.S.
*/
-extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
-#define max_buffer_sectors MAX_BUFFER_SECTORS
+char *floppy_track_buffer=0;
+int max_buffer_sectors=0;
int *errors;
typedef void (*done_f)(int);
@@ -410,7 +480,7 @@
void (*redo)(void); /* this is called to retry the operation */
void (*error)(void); /* this is called to tally an error */
done_f done; /* this is called to say if the operation has succeeded/failed */
-} *cont;
+} *cont=NULL;
static void floppy_ready(void);
static void floppy_start(void);
@@ -483,6 +553,65 @@
#endif
}
+typedef void (*timeout_fn)(unsigned long);
+static struct timer_list fd_timeout ={ NULL, NULL, 0, 0,
+ (timeout_fn) floppy_shutdown };
+
+static char *timeout_message;
+
+#ifdef CONFIG_FLOPPY_SANITY
+static void is_alive(char *message)
+{
+ /* this routine checks whether the floppy driver is "alive" */
+ if (fdc_busy && command_status < 2 && !fd_timeout.prev){
+ DPRINT1("timeout handler died: %s\n",message);
+ }
+}
+#endif
+
+#ifdef CONFIG_FLOPPY_SANITY
+
+#define OLOGSIZE 20
+
+void (*lasthandler)(void) = NULL;
+int interruptjiffies=0;
+int resultjiffies=0;
+int resultsize=0;
+int lastredo=0;
+
+static struct output_log {
+ unsigned char data;
+ unsigned char status;
+ unsigned long jiffies;
+} output_log[OLOGSIZE];
+
+static int output_log_pos=0;
+#endif
+
+#define CURRENTD -1
+#define MAXTIMEOUT -2
+
+
+
+static void reschedule_timeout(int drive, char *message, int marg)
+{
+ if (drive == CURRENTD )
+ drive = current_drive;
+ del_timer(&fd_timeout);
+ if (drive < 0 || drive > N_DRIVE) {
+ fd_timeout.expires = 2000;
+ drive=0;
+ } else
+ fd_timeout.expires = UDP->timeout;
+ add_timer(&fd_timeout);
+ if (UDP->flags & FD_DEBUG){
+ DPRINT("reschedule timeout ");
+ printk(message, marg);
+ printk("\n");
+ }
+ timeout_message = message;
+}
+
/*
* Bottom half floppy driver.
* ==========================
@@ -668,15 +797,13 @@
sti();
command_status = FD_COMMAND_NONE;
set_fdc(drive);
+ reschedule_timeout(drive, "lock fdc", 0);
return 0;
}
#define LOCK_FDC(drive,interruptible) \
if(lock_fdc(drive,interruptible)) return -EINTR;
-typedef void (*timeout_fn)(unsigned long);
-static struct timer_list fd_timeout ={ NULL, NULL, 0, 0,
- (timeout_fn) floppy_shutdown };
/* unlocks the driver */
static inline void unlock_fdc(void)
@@ -689,6 +816,7 @@
DEVICE_INTR);
command_status = FD_COMMAND_NONE;
del_timer(&fd_timeout);
+ cont = NULL;
fdc_busy = 0;
floppy_release_irq_and_dma();
wake_up(&fdc_wait);
@@ -878,15 +1006,13 @@
FDCS->reset=1;
return;
}
- if ( ( (long)current_addr & ~(64*1024-1) ) !=
- ((long)(current_addr + raw_cmd.length-1) & ~(64*1024-1))){
+ if (CROSS_64KB(current_addr, raw_cmd.length)) {
printk("DMA crossing 64-K boundary %p-%p\n",
current_addr, current_addr + raw_cmd.length);
cont->done(0);
FDCS->reset=1;
return;
}
-
#endif
cli();
disable_dma(FLOPPY_DMA);
@@ -894,7 +1020,7 @@
set_dma_mode(FLOPPY_DMA,
(raw_cmd.flags & FD_RAW_READ)?
DMA_MODE_READ : DMA_MODE_WRITE);
- set_dma_addr(FLOPPY_DMA, (long) current_addr);
+ set_dma_addr(FLOPPY_DMA, virt_to_bus(current_addr));
set_dma_count(FLOPPY_DMA, raw_cmd.length);
enable_dma(FLOPPY_DMA);
sti();
@@ -906,15 +1032,24 @@
{
int counter;
unsigned char status;
+ unsigned char rstatus;
if (FDCS->reset)
return -1;
for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
- status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
+ rstatus = inb_p(FD_STATUS);
+ status = rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA);
if (!(status & STATUS_READY))
continue;
if (status == STATUS_READY){
outb_p(byte,FD_DATA);
+
+#ifdef CONFIG_FLOPPY_SANITY
+ 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;
+#endif
return 0;
} else
break;
@@ -939,8 +1074,13 @@
(STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
if (!(status & STATUS_READY))
continue;
- if (status == STATUS_READY)
+ if (status == STATUS_READY){
+#ifdef CONFIG_FLOPPY_SANITY
+ resultjiffies = jiffies;
+ resultsize = i;
+#endif
return i;
+ }
if (status & STATUS_DMA )
break;
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
@@ -1112,7 +1252,7 @@
* Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
FDCS->dtr = raw_cmd.rate;
- return(wait_for_completion(jiffies+2,
+ return(wait_for_completion(jiffies+2*HZ/100,
(timeout_fn) floppy_ready));
} /* fdc_dtr */
@@ -1467,6 +1607,9 @@
{
void (*handler)(void) = DEVICE_INTR;
+ lasthandler = handler;
+ interruptjiffies = jiffies;
+
floppy_enable_hlt();
CLEAR_INTR;
if ( fdc >= N_FDC || FDCS->address == -1){
@@ -1474,11 +1617,13 @@
printk("DOR0=%x\n", fdc_state[0].dor);
printk("floppy interrupt on bizarre fdc %d\n",fdc);
printk("handler=%p\n", handler);
+ is_alive("bizarre fdc");
return;
}
inr = result();
if (!handler){
unexpected_floppy_interrupt();
+ is_alive("unexpected");
return;
}
if ( inr == 0 ){
@@ -1489,6 +1634,7 @@
}
floppy_tq.routine = (void *)(void *) handler;
queue_task_irq(&floppy_tq, &tq_timer);
+ is_alive("normal interrupt end");
}
static void recalibrate_floppy(void)
@@ -1545,6 +1691,27 @@
printk("\n");
printk("floppy driver state\n");
printk("-------------------\n");
+ printk("now=%ld last interrupt=%d last called handler=%p\n",
+ jiffies, interruptjiffies, lasthandler);
+
+
+#ifdef CONFIG_FLOPPY_SANITY
+ printk("timeout_message=%s\n", timeout_message);
+ printk("last output bytes:\n");
+ for(i=0; i < OLOGSIZE; i++)
+ printk("%2x %2x %ld\n",
+ output_log[(i+output_log_pos) % OLOGSIZE].data,
+ output_log[(i+output_log_pos) % OLOGSIZE].status,
+ output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
+ printk("last result at %d\n", resultjiffies);
+ printk("last redo_fd_request at %d\n", lastredo);
+ for(i=0; i<resultsize; i++){
+ printk("%2x ", reply_buffer[i]);
+ }
+ printk("\n");
+#endif
+
+#if 0
for(i=0; i<N_FDC; i++){
if(FDCS->address != -1){
printk("dor %d = %x\n", i, fdc_state[i].dor );
@@ -1552,6 +1719,7 @@
udelay(1000); /* maybe we'll catch an interrupt... */
}
}
+#endif
printk("status=%x\n", inb_p(FD_STATUS));
printk("fdc_busy=%d\n", fdc_busy);
if( DEVICE_INTR)
@@ -1573,6 +1741,8 @@
static void floppy_shutdown(void)
{
+ if(!initialising)
+ show_floppy();
CLEAR_INTR;
floppy_tq.routine = (void *)(void *) empty;
del_timer( &fd_timer);
@@ -1584,8 +1754,14 @@
if(!initialising)
DPRINT("floppy timeout\n");
FDCS->reset = 1;
- cont->done(0);
- cont->redo(); /* this will recall reset when needed */
+ if (cont){
+ cont->done(0);
+ cont->redo(); /* this will recall reset when needed */
+ } else {
+ printk("no cont in shutdown!\n");
+ process_fd_request();
+ }
+ is_alive("floppy shutdown");
}
/*typedef void (*timeout_fn)(unsigned long);*/
@@ -1646,9 +1822,7 @@
static void floppy_start(void)
{
- del_timer(&fd_timeout);
- fd_timeout.expires = DP->timeout;
- add_timer(&fd_timeout);
+ reschedule_timeout(CURRENTD, "floppy start", 0);
scandrives();
#ifdef DCL_DEBUG
@@ -1663,7 +1837,7 @@
/*
* ========================================================================
* here ends the bottom half. Exported routines are:
- * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
+ * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
* start_motor, reset_fdc, reset_fdc_info, interpret_errors.
* Initialisation also uses output_byte, result, set_dor, floppy_interrupt
* and set_dor.
@@ -1676,7 +1850,7 @@
static void do_wakeup(void)
{
- del_timer(&fd_timeout);
+ reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
cont = 0;
command_status += 2;
wake_up(&command_done);
@@ -1697,7 +1871,8 @@
queue_task(&floppy_tq, &tq_timer);
cli();
- while(command_status < 2 && NO_SIGNAL)
+ while(command_status < 2 && NO_SIGNAL){
+ is_alive("wait_til_done");
if (current->pid)
interruptible_sleep_on(&command_done);
else {
@@ -1705,6 +1880,7 @@
run_task_queue(&tq_timer);
cli();
}
+ }
if(command_status < 2){
sti();
floppy_shutdown();
@@ -1834,7 +2010,7 @@
raw_cmd.rate = floppy->rate & 0x3;
raw_cmd.cmd_count = NR_F;
COMMAND = FM_MODE(floppy,FD_FORMAT);
- DR_SELECT = UNIT(current_drive) + ( format_req.head << 2 );
+ 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;
@@ -1881,7 +2057,7 @@
static void redo_format(void)
{
- raw_cmd.track = format_req.track << floppy->stretch;
+ raw_cmd.track = format_req.track << STRETCH(floppy);
buffer_track = -1;
setup_format_params();
floppy_start();
@@ -1933,7 +2109,7 @@
int block;
probing = 0;
- del_timer(&fd_timeout);
+ reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
if (!CURRENT){
DPRINT("request list destroyed in floppy request done\n");
@@ -2222,13 +2398,15 @@
}
max_sector = floppy->sect * floppy->head;
+
TRACK = CURRENT->sector / max_sector;
sector_t = CURRENT->sector % max_sector;
if ( floppy->track && TRACK >= floppy->track )
return 0;
HEAD = sector_t / floppy->sect;
- if ( TESTF( FD_NEED_TWADDLE) && sector_t < 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 */
@@ -2253,8 +2431,8 @@
SIZECODE2 = 0xff;
else
SIZECODE2 = 0x80;
- raw_cmd.track = TRACK << floppy->stretch;
- DR_SELECT = UNIT(current_drive) + ( HEAD << 2 );
+ 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;
@@ -2296,18 +2474,17 @@
raw_cmd.flags &= ~FD_RAW_WRITE;
raw_cmd.flags |= FD_RAW_READ;
COMMAND = FM_MODE(floppy,FD_READ);
- } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
+ } else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS ) {
int direct, indirect;
indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
sector_t;
max_size = buffer_chain_size();
- if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
- max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
+ if ( max_size > ( MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9)
+ max_size=(MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9;
/* 64 kb boundaries */
- if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
- ((long) CURRENT->buffer ) / K_64 )
+ if (CROSS_64KB(CURRENT->buffer, max_size << 9))
max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
direct = transfer_size(ssize,max_sector,max_size) - sector_t;
/*
@@ -2443,11 +2620,16 @@
int tmp;
int error;
+
error = -1;
+ lastredo = jiffies;
if (current_drive < N_DRIVE)
floppy_off(current_drive);
- if (CURRENT && CURRENT->dev < 0) return;
+ if (CURRENT && CURRENT->dev < 0){
+ DPRINT("current dev < 0!\n");
+ return;
+ }
while(1){
if (!CURRENT) {
@@ -2470,10 +2652,7 @@
error=-1;
device = CURRENT->dev;
set_fdc( DRIVE(device));
-
- del_timer(&fd_timeout);
- fd_timeout.expires = DP->timeout;
- add_timer(&fd_timeout);
+ reschedule_timeout(CURRENTD, "redo fd request", 0);
set_floppy(device);
if(start_motor(redo_fd_request)) return;
@@ -2531,14 +2710,18 @@
static void do_fd_request(void)
{
- if (fdc_busy)
+ if (fdc_busy){
/* fdc busy, this new request will be treated when the
current one is done */
+ is_alive("do fd request, old request running");
return;
+ }
/* fdc_busy cannot be set by an interrupt or a bh */
floppy_grab_irq_and_dma();
fdc_busy=1;
+ reschedule_timeout(MAXTIMEOUT, "do fd request",0);
process_fd_request();
+ is_alive("do fd request");
}
static struct cont_t poll_cont={
@@ -2592,9 +2775,7 @@
FDCS->reset=1;
if ( FDCS->reset ){
cont = &reset_cont;
- del_timer(&fd_timeout);
- fd_timeout.expires = DP->timeout;
- add_timer(&fd_timeout);
+ reschedule_timeout(CURRENTD, "user reset fdc", 0);
WAIT(reset_fdc);
}
process_fd_request();
@@ -2757,8 +2938,7 @@
return i;
name = drive_name(type,drive);
for ( cnt=0; cnt<16; cnt++){
- put_fs_byte(name[cnt],
- ((char*)param)+cnt);
+ put_user(name[cnt], ((char*)param)+cnt);
if ( ! *name )
break;
}
@@ -2831,8 +3011,9 @@
if(newparams.sect <= 0 ||
newparams.head <= 0 ||
newparams.track <= 0 ||
- newparams.track >
- UDP->tracks>>newparams.stretch)
+ newparams.track > UDP->tracks>> STRETCH(&newparams) ||
+ /* check if reserved bits are set */
+ (newparams.stretch & ~(FD_STRETCH | FD_SWAPSIDES)) != 0)
return -EINVAL;
if ( type){
if ( !suser() )
@@ -3022,6 +3203,8 @@
{
int drive;
int old_dev;
+ int try;
+ char *tmp;
if (!filp) {
DPRINT("Weird, open called with filp=0\n");
@@ -3029,6 +3212,7 @@
}
drive = DRIVE(inode->i_rdev);
+
if (drive >= N_DRIVE ||
!( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
fdc_state[FDC(drive)].version == FDC_NONE)
@@ -3057,6 +3241,33 @@
else
UDRS->fd_ref++;
+ if (!floppy_track_buffer){
+ /* if opening an ED drive, reserve a big buffer,
+ * else reserve a small one */
+ if ((UDP->cmos == 6) || (UDP->cmos == 5))
+ try = 64; /* Only 48 actually useful */
+ else
+ try = 32; /* Only 24 actually useful */
+
+ tmp=(char *)dma_mem_alloc(1024 * try);
+ if (!tmp) {
+ try >>= 1; /* buffer only one side */
+ if (try < 16)
+ try=16;
+ tmp= (char *)dma_mem_alloc(1024*try);
+ }
+ if (!tmp) {
+ DPRINT("Unable to allocate DMA memory\n");
+ RETERR(ENXIO);
+ }
+ if (floppy_track_buffer){
+ free_pages((unsigned long)tmp,__get_order(try*1024));
+ }else {
+ floppy_track_buffer = tmp;
+ max_buffer_sectors = try;
+ }
+ }
+
UDRS->fd_device = inode->i_rdev;
if (old_dev && old_dev != inode->i_rdev) {
@@ -3353,10 +3564,7 @@
DPRINT("Read linux/drivers/block/README.fd\n");
}
-#ifdef FD_MODULE
-static
-#endif
-int new_floppy_init(void)
+int floppy_init(void)
{
int i,drive;
int have_no_fdc=0;
@@ -3377,7 +3585,7 @@
blk_size[MAJOR_NR] = floppy_sizes;
blksize_size[MAJOR_NR] = floppy_blocksizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- del_timer(&fd_timeout);
+ reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
config_types();
fdc_state[0].address = FDC1;
@@ -3407,6 +3615,8 @@
UDRS->keep_data = 0;
UDRS->fd_ref = 0;
UDRS->fd_device = 0;
+ floppy_track_buffer = NULL;
+ max_buffer_sectors = 0;
UDRWE->write_errors = 0;
UDRWE->first_error_sector = 0;
UDRWE->first_error_generation = 0;
@@ -3430,6 +3640,11 @@
FDCS->address = -1;
continue;
}
+
+ request_region(FDCS->address, 6, "floppy");
+ request_region(FDCS->address+7, 1, "floppy DIR");
+ /* address + 6 is reserved, and may be taken by IDE.
+ * Unfortunately, Adaptec doesn't know this :-(, */
have_no_fdc = 0;
/* Not all FDCs seem to be able to handle the version command
@@ -3440,6 +3655,7 @@
user_reset_fdc(-1,FD_RESET_ALWAYS,0);
}
fdc=0;
+ del_timer(&fd_timeout);
current_drive = 0;
floppy_release_irq_and_dma();
initialising=0;
@@ -3448,12 +3664,6 @@
return have_no_fdc;
}
-/* stupid compatibility hack... */
-void floppy_init(void)
-{
- new_floppy_init();
-}
-
static int floppy_grab_irq_and_dma(void)
{
int i;
@@ -3499,6 +3709,9 @@
#ifdef CONFIG_FLOPPY_SANITY
int drive;
#endif
+ long tmpsize;
+ void *tmpaddr;
+
cli();
if (--usage_count){
sti();
@@ -3518,13 +3731,22 @@
set_dor(1, ~8, 0);
#endif
floppy_enable_hlt();
+
+ if (floppy_track_buffer && max_buffer_sectors) {
+ tmpsize = max_buffer_sectors*1024;
+ tmpaddr = (void *)floppy_track_buffer;
+ floppy_track_buffer = 0;
+ max_buffer_sectors = 0;
+ free_pages((unsigned long)tmpaddr, __get_order(tmpsize));
+ }
+
#ifdef CONFIG_FLOPPY_SANITY
for(drive=0; drive < N_FDC * 4; drive++)
if( motor_off_timer[drive].next )
printk("motor off timer %d still active\n", drive);
if(fd_timeout.next)
- printk("floppy timer still active\n");
+ printk("floppy timer still active:%s\n", timeout_message);
if (fd_timer.next)
printk("auxiliary floppy timer still active\n");
if(floppy_tq.sync)
@@ -3532,3 +3754,82 @@
#endif
}
+
+#ifdef MODULE
+
+extern char *get_options(char *str, int *ints);
+
+#if 0
+/* assuming that insmod is compiled as a.out binary using a shared
+ C library ... */
+int ENVIRON = 0x60090b34;
+
+static void
+mod_setup(char *name,
+ void (*setup)(char *, int *)) {
+ char **environ,*env,*ptr,c,i;
+ char line[100];
+ int ints[11];
+
+ environ = (char **) get_fs_long( ENVIRON );
+
+ while((env = (char *)get_fs_long(environ))){
+ for(i=0; i<strlen(name); i++)
+ if ( (char) get_fs_byte(env++) != name[i] )
+ break;
+ if(i == strlen(name)){
+ ptr=line;
+ while(ptr < line+99){
+ c = (char)get_fs_byte(env++);
+ if ( c== ' ' || !c ){
+ *ptr='\0';
+ if(ptr!=line)
+ setup(get_options(line,ints),
+ ints);
+ ptr=line;
+ if (!c)
+ break;
+ } else
+ *ptr++ = c;
+ }
+ }
+ environ++;
+ }
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int init_module(void)
+{
+ int ret;
+ printk("inserting floppy driver for %s\n", kernel_version);
+
+ /*mod_setup("floppy=", floppy_setup);*/
+ /* Can't do that any more, insmod is now ELF */
+
+ ret = floppy_init();
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int fdc;
+
+ for(fdc=0; fdc<2; fdc++)
+ if (FDCS->address != -1){
+ release_region(FDCS->address, 6);
+ release_region(FDCS->address+7, 1);
+ }
+
+ unregister_blkdev(MAJOR_NR, "fd");
+
+ blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
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