diff --git a/elks/arch/i86/drivers/block/directfd.c b/elks/arch/i86/drivers/block/directfd.c index eba361e9f..ce630e9bd 100644 --- a/elks/arch/i86/drivers/block/directfd.c +++ b/elks/arch/i86/drivers/block/directfd.c @@ -83,7 +83,6 @@ #include #include #include -#include /* for peek/poke */ #include #include @@ -137,11 +136,8 @@ static int seek = 0; static int nr_sectors; /* only when raw access */ #endif -/* Should use poke() for this!! No, turns out the far pointer is better. HS */ -static unsigned char __far *fl_timeout = (void __far *)0x440L; /* BIOS floppy motor timeout counter*/ - /* On some machines always active, must be - * reset to avoid random motor shutoff. - * Ihis variant takes 10 bytes */ +/* BIOS floppy motor timeout counter - FIXME leave this while BIOS driver present */ +static unsigned char __far *fl_timeout = (void __far *)0x440L; static unsigned char current_DOR = 0x0C; static unsigned char running = 0; /* keep track of motors already running */ @@ -169,14 +165,12 @@ static unsigned char running = 0; /* keep track of motors already running */ #define MAX_BUFFER_SECTORS 18 /* - * The DMA channel used by the floppy controller cannot access data at - * addresses >= 16MB - * - * Went back to the 1MB limit, as some people had problems with the floppy - * driver otherwise. It doesn't matter much for performance anyway, as most - * floppy accesses go through the track buffer. + * The 8237 DMA controller cannot access data above 1MB on the origianl PC + * (4 bit page register). The AT is different, the page reg is 8 bits while the + * 2nd DMA controller transfers words only, not bytes and thus up to 128k bytes + * in one 'swoop'. */ -#define LAST_DMA_ADDR (0x100000L - BLOCK_SIZE) +#define LAST_DMA_ADDR (0x100000L - BLOCK_SIZE) /* stick to the 1M limit */ /* * globals used by 'result()' @@ -297,7 +291,8 @@ static unsigned short min_report_error_cnt[4] = { 2, 2, 2, 2 }; * The block buffer is used for all writes, for formatting and for reads * in case track buffering doesn't work or has been turned off. */ -static char tmp_floppy_area[BLOCK_SIZE]; /* for now FIXME to be removed */ +#define WORD_ALIGNED __attribute__((aligned(2))) +static char tmp_floppy_area[BLOCK_SIZE] WORD_ALIGNED; /* for now FIXME to be removed */ #ifdef CHECK_DISK_CHANGE int check_disk_change(kdev_t); @@ -418,7 +413,7 @@ static void motor_off_callback(int nr) /* * floppy_on: turn on motor. If already running, call floppy_select - * otherwise start motor and set timer to continue (motor_on_callback). + * otherwise start motor and set timer and return. * In the latter case, motor_on_callback will call floppy_select(); * * DOR (Data Output Register) is |MOTD|MOTC|MOTB|MOTA|DMA|/RST|DR1|DR0| @@ -428,8 +423,7 @@ static void floppy_on(int nr) unsigned char mask = 0x10 << nr; /* motor on select */ DEBUG("flpON"); - *fl_timeout = 0; /* Reset BIOS motor timeout counter, neccessary on some machines */ - /* Don't ask how I found out. HS */ + *fl_timeout = 0; /* Reset BIOS motor timeout counter, neccessary on some machines */ del_timer(&motor_off_timer[nr]); if (mask & running) { @@ -542,28 +536,37 @@ int floppy_change(struct buffer_head *bh) static void setup_DMA(void) { unsigned long dma_addr; - unsigned int count; + unsigned int count, physaddr; + int use_xms; + struct request *req = CURRENT; -#ifdef CONFIG_FS_XMS_BUFFER - dma_addr = LAST_DMA_ADDR + 1; /* force use of bounce buffer */ -#else - dma_addr = _MK_LINADDR(CURRENT->rq_seg, CURRENT->rq_buffer); -#endif +#pragma GCC diagnostic ignored "-Wshift-count-overflow" + use_xms = req->rq_seg >> 16; /* will ne nonzero only if XMS configured & XMS buffer */ + physaddr = (req->rq_seg << 4) + (unsigned int)req->rq_buffer; #ifdef CONFIG_BLK_DEV_CHAR count = nr_sectors ? nr_sectors<<9 : BLOCK_SIZE; #else count = BLOCK_SIZE; #endif + if (use_xms || (physaddr + (unsigned int)count) < physaddr) + dma_addr = LAST_DMA_ADDR + 1; /* force use of bounce buffer */ + else + dma_addr = _MK_LINADDR(req->rq_seg, req->rq_buffer); + DEBUG("setupDMA "); + +#ifdef INCLUDE_FD_FORMATTING if (command == FD_FORMAT) { dma_addr = _MK_LINADDR(kernel_ds, tmp_floppy_area); count = floppy->sect * 4; } +#endif if (read_track) { /* mark buffer-track bad, in case all this fails.. */ buffer_drive = buffer_track = -1; count = floppy->sect << 9; /* sects/trk (one side) times 512 */ - if (floppy->sect & 1 && !head) count += 512; /* add one if head=0 && sector count is odd */ + if (floppy->sect & 1 && !head) + count += 512; /* add one if head=0 && sector count is odd */ dma_addr = _MK_LINADDR(DMASEG, 0); } else if (dma_addr >= LAST_DMA_ADDR) { dma_addr = _MK_LINADDR(kernel_ds, tmp_floppy_area); /* use bounce buffer */ @@ -812,12 +815,12 @@ static void rw_interrupt(void) probing = 0; } if (read_track) { - buffer_track = (seek_track << 1) + head; /* This encoding is ugly, should - * save block-start, block-end instead */ + buffer_track = (seek_track << 1) + head; /* This encoding is ugly, should + * use block-start, block-end instead */ buffer_drive = current_drive; buffer_area = (unsigned char *)(sector << 9); - DEBUG("rd:%x:%04x->%lx:%04x;", DMASEG, buffer_area, - (unsigned long)CURRENT->rq_seg, CURRENT->rq_buffer); + DEBUG("rd:%04x:%08lx->%04x:%04x;", DMASEG, buffer_area, + (unsigned long)CURRENT->rq_seg, CURRENT->rq_buffer); xms_fmemcpyw(CURRENT->rq_buffer, CURRENT->rq_seg, buffer_area, DMASEG, BLOCK_SIZE/2); } else if (command == FD_READ #ifndef CONFIG_FS_XMS_BUFFER @@ -831,7 +834,8 @@ static void rw_interrupt(void) CURRENT->rq_seg, CURRENT->rq_buffer); } request_done(1); - redo_fd_request(); + //printk("RQOK;"); + redo_fd_request(); /* Continue with the next request - if any */ } /* @@ -930,8 +934,8 @@ static void transfer(void) output_byte(FD_SEEK); output_byte((head << 2) | current_drive); output_byte(seek_track); - //if (reset) /* We already did this */ - //redo_fd_request(); + if (reset) /* If something happened in output_byte() */ + redo_fd_request(); } static void recalibrate_floppy(void) @@ -944,7 +948,7 @@ static void recalibrate_floppy(void) output_byte(current_drive); /* this may not make sense: We're waiting for recal_interrupt - * why redo_request here when recal_interrupt is doing it ??? */ + * why redo_fd_request here when recal_interrupt is doing it ??? */ /* 'reset' gets set in recal_interrupt, maybe that's it ??? */ if (reset) redo_fd_request(); @@ -1187,10 +1191,8 @@ static void redo_fd_request(void) } if (MAJOR(req->rq_dev) != MAJOR_NR) panic("%s: request list destroyed", DEVICE_NAME); - if (req->rq_bh) { - if (!EBH(req->rq_bh)->b_locked) + if (req->rq_bh && !EBH(req->rq_bh)->b_locked) panic("%s: block not locked", DEVICE_NAME); - } } seek = 0; probing = 0; @@ -1278,7 +1280,7 @@ static void redo_fd_request(void) * number of sectors (full blocks). When head=1 we read the entire track * and ignore the first sector. */ - DEBUG("bufrd tr/h/s %d/%d/%d\n", seek_track, head, sector); + DEBUG("bufrd chs %d/%d/%d\n", seek_track, head, sector); char *buf_ptr = (char *) (sector << 9); if (command == FD_READ) { /* requested data is in buffer */ xms_fmemcpyw(req->rq_buffer, req->rq_seg, buf_ptr, DMASEG, BLOCK_SIZE/2); @@ -1298,11 +1300,9 @@ void do_fd_request(void) { DEBUG("fdrq:"); if (CURRENT) CURRENT->rq_errors = 0; // EXPERIMENTAL - //clr_irq(); while (fdc_busy) sleep_on(&fdc_wait); fdc_busy = 1; - //set_irq(); redo_fd_request(); }