diff options
| author | Adrian Bunk <bunk@stusta.de> | 2007-07-31 03:38:19 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 18:39:39 -0400 |
| commit | 99eb8a550dbccc0e1f6c7e866fe421810e0585f6 (patch) | |
| tree | 130c6e3338a0655ba74355eba83afab9261e1ed0 /drivers | |
| parent | 0d0ed42e5ca2e22465c591341839c18025748fe8 (diff) | |
Remove the arm26 port
The arm26 port has been in a state where it was far from even compiling
for quite some time.
Ian Molton agreed with the removal.
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Cc: Ian Molton <spyro@f2s.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acorn/README | 1 | ||||
| -rw-r--r-- | drivers/acorn/block/Kconfig | 36 | ||||
| -rw-r--r-- | drivers/acorn/block/Makefile | 9 | ||||
| -rw-r--r-- | drivers/acorn/block/fd1772.c | 1604 | ||||
| -rw-r--r-- | drivers/acorn/block/fd1772dma.S | 100 | ||||
| -rw-r--r-- | drivers/acorn/block/mfm.S | 162 | ||||
| -rw-r--r-- | drivers/acorn/block/mfmhd.c | 1385 | ||||
| -rw-r--r-- | drivers/ide/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/ide/arm/ide_arm.c | 20 | ||||
| -rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/scsi/arm/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/scsi/arm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/scsi/arm/ecoscsi.c | 166 | ||||
| -rw-r--r-- | drivers/video/acornfb.c | 20 |
14 files changed, 8 insertions, 3509 deletions
diff --git a/drivers/acorn/README b/drivers/acorn/README deleted file mode 100644 index d399c09ca6..0000000000 --- a/drivers/acorn/README +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | Drivers for the ACORN "podule" ARM specific bus. | ||
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig deleted file mode 100644 index a0ff25ea43..0000000000 --- a/drivers/acorn/block/Kconfig +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Block device driver configuration | ||
| 3 | # | ||
| 4 | |||
| 5 | menu "Acorn-specific block devices" | ||
| 6 | depends on ARCH_ARC || ARCH_A5K | ||
| 7 | |||
| 8 | config BLK_DEV_FD1772 | ||
| 9 | tristate "Old Archimedes floppy (1772) support" | ||
| 10 | depends on ARCH_ARC || ARCH_A5K | ||
| 11 | help | ||
| 12 | Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540, | ||
| 13 | R140 and R260) series of computers; it supports only 720K floppies | ||
| 14 | at the moment. If you don't have one of these machines just answer | ||
| 15 | N. | ||
| 16 | |||
| 17 | config BLK_DEV_MFM | ||
| 18 | tristate "MFM harddisk support" | ||
| 19 | depends on ARCH_ARC || ARCH_A5K | ||
| 20 | help | ||
| 21 | Support the MFM hard drives on the Acorn Archimedes both | ||
| 22 | on-board the A4x0 motherboards and via the Acorn MFM podules. | ||
| 23 | Drives up to 64MB are supported. If you haven't got one of these | ||
| 24 | machines or drives just say N. | ||
| 25 | |||
| 26 | config BLK_DEV_MFM_AUTODETECT | ||
| 27 | bool "Autodetect hard drive geometry" | ||
| 28 | depends on BLK_DEV_MFM | ||
| 29 | help | ||
| 30 | If you answer Y, the MFM code will attempt to automatically detect | ||
| 31 | the cylinders/heads/sectors count on your hard drive. WARNING: This | ||
| 32 | sometimes doesn't work and it also does some dodgy stuff which | ||
| 33 | potentially might damage your drive. | ||
| 34 | |||
| 35 | endmenu | ||
| 36 | |||
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile deleted file mode 100644 index 38a9afe8e0..0000000000 --- a/drivers/acorn/block/Makefile +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Acorn block device drivers. | ||
| 3 | # | ||
| 4 | |||
| 5 | fd1772_mod-objs := fd1772.o fd1772dma.o | ||
| 6 | mfmhd_mod-objs := mfmhd.o mfm.o | ||
| 7 | |||
| 8 | obj-$(CONFIG_BLK_DEV_FD1772) += fd1772_mod.o | ||
| 9 | obj-$(CONFIG_BLK_DEV_MFM) += mfmhd_mod.o | ||
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c deleted file mode 100644 index d7e18ce8da..0000000000 --- a/drivers/acorn/block/fd1772.c +++ /dev/null | |||
| @@ -1,1604 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/kernel/arch/arm/drivers/block/fd1772.c | ||
| 3 | * Based on ataflop.c in the m68k Linux | ||
| 4 | * Copyright (C) 1993 Greg Harp | ||
| 5 | * Atari Support by Bjoern Brauel, Roman Hodek | ||
| 6 | * Archimedes Support by Dave Gilbert (linux@treblig.org) | ||
| 7 | * | ||
| 8 | * Big cleanup Sep 11..14 1994 Roman Hodek: | ||
| 9 | * - Driver now works interrupt driven | ||
| 10 | * - Support for two drives; should work, but I cannot test that :-( | ||
| 11 | * - Reading is done in whole tracks and buffered to speed up things | ||
| 12 | * - Disk change detection and drive deselecting after motor-off | ||
| 13 | * similar to TOS | ||
| 14 | * - Autodetection of disk format (DD/HD); untested yet, because I | ||
| 15 | * don't have an HD drive :-( | ||
| 16 | * | ||
| 17 | * Fixes Nov 13 1994 Martin Schaller: | ||
| 18 | * - Autodetection works now | ||
| 19 | * - Support for 5 1/4" disks | ||
| 20 | * - Removed drive type (unknown on atari) | ||
| 21 | * - Do seeks with 8 Mhz | ||
| 22 | * | ||
| 23 | * Changes by Andreas Schwab: | ||
| 24 | * - After errors in multiple read mode try again reading single sectors | ||
| 25 | * (Feb 1995): | ||
| 26 | * - Clean up error handling | ||
| 27 | * - Set blk_size for proper size checking | ||
| 28 | * - Initialize track register when testing presence of floppy | ||
| 29 | * - Implement some ioctl's | ||
| 30 | * | ||
| 31 | * Changes by Torsten Lang: | ||
| 32 | * - When probing the floppies we should add the FDC1772CMDADD_H flag since | ||
| 33 | * the FDC1772 will otherwise wait forever when no disk is inserted... | ||
| 34 | * | ||
| 35 | * Things left to do: | ||
| 36 | * - Formatting | ||
| 37 | * - Maybe a better strategy for disk change detection (does anyone | ||
| 38 | * know one?) | ||
| 39 | * - There are some strange problems left: The strangest one is | ||
| 40 | * that, at least on my TT (4+4MB), the first 2 Bytes of the last | ||
| 41 | * page of the TT-Ram (!) change their contents (some bits get | ||
| 42 | * set) while a floppy DMA is going on. But there are no accesses | ||
| 43 | * to these memory locations from the kernel... (I tested that by | ||
| 44 | * making the page read-only). I cannot explain what's going on... | ||
| 45 | * - Sometimes the drive-change-detection stops to work. The | ||
| 46 | * function is still called, but the WP bit always reads as 0... | ||
| 47 | * Maybe a problem with the status reg mode or a timing problem. | ||
| 48 | * Note 10/12/94: The change detection now seems to work reliably. | ||
| 49 | * There is no proof, but I've seen no hang for a long time... | ||
| 50 | * | ||
| 51 | * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk) | ||
| 52 | * 26/12/95 - Changed all names starting with FDC to FDC1772 | ||
| 53 | * Removed all references to clock speed of FDC - we're stuck with 8MHz | ||
| 54 | * Modified disk_type structure to remove HD formats | ||
| 55 | * | ||
| 56 | * 7/ 1/96 - Wrote FIQ code, removed most remaining atariisms | ||
| 57 | * | ||
| 58 | * 13/ 1/96 - Well I think its read a single sector; but there is a problem | ||
| 59 | * fd_rwsec_done which is called in FIQ mode starts another transfer | ||
| 60 | * off (in fd_rwsec) while still in FIQ mode. Because its still in | ||
| 61 | * FIQ mode it can't service the DMA and loses data. So need to | ||
| 62 | * heavily restructure. | ||
| 63 | * 14/ 1/96 - Found that the definitions of the register numbers of the | ||
| 64 | * FDC were multiplied by 2 in the header for the 16bit words | ||
| 65 | * of the atari so half the writes were going in the wrong place. | ||
| 66 | * Also realised that the FIQ entry didn't make any attempt to | ||
| 67 | * preserve registers or return correctly; now in assembler. | ||
| 68 | * | ||
| 69 | * 11/ 2/96 - Hmm - doesn't work on real machine. Auto detect doesn't | ||
| 70 | * and hacking that past seems to wait forever - check motor | ||
| 71 | * being turned on. | ||
| 72 | * | ||
| 73 | * 17/ 2/96 - still having problems - forcing track to -1 when selecting | ||
| 74 | * new drives seems to allow it to read first few sectors | ||
| 75 | * but then we get solid hangs at apparently random places | ||
| 76 | * which change depending what is happening. | ||
| 77 | * | ||
| 78 | * 9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35 | ||
| 79 | * A lot of fiddling in DMA stuff. Having problems with it | ||
| 80 | * constnatly thinking its timeing out. Ah - its timeout | ||
| 81 | * was set to (6*HZ) rather than jiffies+(6*HZ). Now giving | ||
| 82 | * duff data! | ||
| 83 | * | ||
| 84 | * 5/ 4/96 - Made it use the new IOC_ macros rather than *ioc | ||
| 85 | * Hmm - giving unexpected FIQ and then timeouts | ||
| 86 | * 18/ 8/96 - Ran through indent -kr -i8 | ||
| 87 | * Some changes to disc change detect; don't know how well it | ||
| 88 | * works. | ||
| 89 | * 24/ 8/96 - Put all the track buffering code back in from the atari | ||
| 90 | * code - I wonder if it will still work... No :-) | ||
| 91 | * Still works if I turn off track buffering. | ||
| 92 | * 25/ 8/96 - Changed the timer expires that I'd added back to be | ||
| 93 | * jiffies + ....; and it all sprang to life! Got 2.8K/sec | ||
| 94 | * off a cp -r of a 679K disc (showed 94% cpu usage!) | ||
| 95 | * (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt! | ||
| 96 | * Also perhaps that compile was with cache off. | ||
| 97 | * changed cli in fd_readtrack_check to cliIF | ||
| 98 | * changed vmallocs to kmalloc (whats the difference!!) | ||
| 99 | * Removed the busy wait loop in do_fd_request and replaced | ||
| 100 | * by a routine on tq_immediate; only 11% cpu on a dd off the | ||
| 101 | * raw disc - but the speed is the same. | ||
| 102 | * 1/ 9/96 - Idea (failed!) - set the 'disable spin-up sequence' | ||
| 103 | * when we read the track if we know the motor is on; didn't | ||
| 104 | * help - perhaps we have to do it in stepping as well. | ||
| 105 | * Nope. Still doesn't help. | ||
| 106 | * Hmm - what seems to be happening is that fd_readtrack_check | ||
| 107 | * is never getting called. Its job is to terminate the read | ||
| 108 | * just after we think we should have got the data; otherwise | ||
| 109 | * the fdc takes 1 second to timeout; which is what's happening | ||
| 110 | * Now I can see 'readtrack_timer' being set (which should do the | ||
| 111 | * call); but it never seems to be called - hmm! | ||
| 112 | * OK - I've moved the check to my tq_immediate code - | ||
| 113 | * and it WORKS! 13.95K/second at 19% CPU. | ||
| 114 | * I wish I knew why that timer didn't work..... | ||
| 115 | * | ||
| 116 | * 16/11/96 - Fiddled and frigged for 2.0.18 | ||
| 117 | * | ||
| 118 | * DAG 30/01/99 - Started frobbing for 2.2.1 | ||
| 119 | * DAG 20/06/99 - A little more frobbing: | ||
| 120 | * Included include/asm/uaccess.h for get_user/put_user | ||
| 121 | * | ||
| 122 | * DAG 1/09/00 - Dusted off for 2.4.0-test7 | ||
| 123 | * MAX_SECTORS was name clashing so it is now FD1772_... | ||
| 124 | * Minor parameter, name layouts for 2.4.x differences | ||
| 125 | */ | ||
| 126 | |||
| 127 | #include <linux/sched.h> | ||
| 128 | #include <linux/fs.h> | ||
| 129 | #include <linux/fcntl.h> | ||
| 130 | #include <linux/slab.h> | ||
| 131 | #include <linux/kernel.h> | ||
| 132 | #include <linux/interrupt.h> | ||
| 133 | #include <linux/timer.h> | ||
| 134 | #include <linux/workqueue.h> | ||
| 135 | #include <linux/fd.h> | ||
| 136 | #include <linux/fd1772.h> | ||
| 137 | #include <linux/errno.h> | ||
| 138 | #include <linux/types.h> | ||
| 139 | #include <linux/delay.h> | ||
| 140 | #include <linux/mm.h> | ||
| 141 | #include <linux/bitops.h> | ||
| 142 | |||
| 143 | #include <asm/arch/oldlatches.h> | ||
| 144 | #include <asm/dma.h> | ||
| 145 | #include <asm/hardware.h> | ||
| 146 | #include <asm/hardware/ioc.h> | ||
| 147 | #include <asm/io.h> | ||
| 148 | #include <asm/irq.h> | ||
| 149 | #include <asm/mach-types.h> | ||
| 150 | #include <asm/pgtable.h> | ||
| 151 | #include <asm/system.h> | ||
| 152 | #include <asm/uaccess.h> | ||
| 153 | |||
| 154 | |||
| 155 | /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with | ||
| 156 | * little additional rework in this file). But I'm not yet sure if | ||
| 157 | * some other code depends on the number of floppies... (It is defined | ||
| 158 | * in a public header!) | ||
| 159 | */ | ||
| 160 | #if 0 | ||
| 161 | #undef FD_MAX_UNITS | ||
| 162 | #define FD_MAX_UNITS 2 | ||
| 163 | #endif | ||
| 164 | |||
| 165 | /* Ditto worries for Arc - DAG */ | ||
| 166 | #define FD_MAX_UNITS 4 | ||
| 167 | #define TRACKBUFFER 0 | ||
| 168 | /*#define DEBUG*/ | ||
| 169 | |||
| 170 | #ifdef DEBUG | ||
| 171 | #define DPRINT(a) printk a | ||
| 172 | #else | ||
| 173 | #define DPRINT(a) | ||
| 174 | #endif | ||
| 175 | |||
| 176 | static struct request_queue *floppy_queue; | ||
| 177 | |||
| 178 | #define MAJOR_NR FLOPPY_MAJOR | ||
| 179 | #define FLOPPY_DMA 0 | ||
| 180 | #define DEVICE_NAME "floppy" | ||
| 181 | #define QUEUE (floppy_queue) | ||
| 182 | #define CURRENT elv_next_request(floppy_queue) | ||
| 183 | |||
| 184 | /* Disk types: DD */ | ||
| 185 | static struct archy_disk_type { | ||
| 186 | const char *name; | ||
| 187 | unsigned spt; /* sectors per track */ | ||
| 188 | unsigned blocks; /* total number of blocks */ | ||
| 189 | unsigned stretch; /* track doubling ? */ | ||
| 190 | } disk_type[] = { | ||
| 191 | |||
| 192 | { "d360", 9, 720, 0 }, /* 360kB diskette */ | ||
| 193 | { "D360", 9, 720, 1 }, /* 360kb in 720kb drive */ | ||
| 194 | { "D720", 9, 1440, 0 }, /* 720kb diskette (DD) */ | ||
| 195 | /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors | ||
| 196 | - DAG - can't see how type detect can distinguish this | ||
| 197 | from 720K until it reads block 4 by which time its too late! */ | ||
| 198 | }; | ||
| 199 | |||
| 200 | #define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type)) | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Maximum disk size (in kilobytes). This default is used whenever the | ||
| 204 | * current disk size is unknown. | ||
| 205 | */ | ||
| 206 | #define MAX_DISK_SIZE 720 | ||
| 207 | |||
| 208 | static struct gendisk *disks[FD_MAX_UNIT]; | ||
| 209 | |||
| 210 | /* current info on each unit */ | ||
| 211 | static struct archy_floppy_struct { | ||
| 212 | int connected; /* !=0 : drive is connected */ | ||
| 213 | int autoprobe; /* !=0 : do autoprobe */ | ||
| 214 | |||
| 215 | struct archy_disk_type *disktype; /* current type of disk */ | ||
| 216 | |||
| 217 | int track; /* current head position or -1 | ||
| 218 | * if unknown */ | ||
| 219 | unsigned int steprate; /* steprate setting */ | ||
| 220 | unsigned int wpstat; /* current state of WP signal | ||
| 221 | * (for disk change detection) */ | ||
| 222 | } unit[FD_MAX_UNITS]; | ||
| 223 | |||
| 224 | /* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which | ||
| 225 | is an assembler routine */ | ||
| 226 | extern void fdc1772_comendhandler(void); /* Actually doens't have these parameters - see fd1772.S */ | ||
| 227 | extern volatile int fdc1772_comendstatus; | ||
| 228 | extern volatile int fdc1772_fdc_int_done; | ||
| 229 | |||
| 230 | #define FDC1772BASE ((0x210000>>2)|0x80000000) | ||
| 231 | |||
| 232 | #define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2)) | ||
| 233 | |||
| 234 | /* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather | ||
| 235 | than the #def below - well simple - the #def won't compile - and I | ||
| 236 | don't understand why (__outwc not defined) */ | ||
| 237 | /* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility | ||
| 238 | with the ST version of fd1772.h */ | ||
| 239 | /*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */ | ||
| 240 | void FDC1772_WRITE(int reg, unsigned char val) | ||
| 241 | { | ||
| 242 | if (reg == FDC1772REG_CMD) { | ||
| 243 | DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies)); | ||
| 244 | if (fdc1772_fdc_int_done) { | ||
| 245 | DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n")); | ||
| 246 | fdc1772_fdc_int_done = 0; | ||
| 247 | }; | ||
| 248 | }; | ||
| 249 | outb(val, (reg / 2) + FDC1772BASE); | ||
| 250 | }; | ||
| 251 | |||
| 252 | #define FD1772_MAX_SECTORS 22 | ||
| 253 | |||
| 254 | unsigned char *DMABuffer; /* buffer for writes */ | ||
| 255 | /*static unsigned long PhysDMABuffer; *//* physical address */ | ||
| 256 | /* DAG: On Arc we just go straight for the DMA buffer */ | ||
| 257 | #define PhysDMABuffer DMABuffer | ||
| 258 | |||
| 259 | #ifdef TRACKBUFFER | ||
| 260 | unsigned char *TrackBuffer; /* buffer for reads */ | ||
| 261 | #define PhysTrackBuffer TrackBuffer /* physical address */ | ||
| 262 | static int BufferDrive, BufferSide, BufferTrack; | ||
| 263 | static int read_track; /* non-zero if we are reading whole tracks */ | ||
| 264 | |||
| 265 | #define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512) | ||
| 266 | #define IS_BUFFERED(drive,side,track) \ | ||
| 267 | (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track)) | ||
| 268 | #endif | ||
| 269 | |||
| 270 | /* | ||
| 271 | * These are global variables, as that's the easiest way to give | ||
| 272 | * information to interrupts. They are the data used for the current | ||
| 273 | * request. | ||
| 274 | */ | ||
| 275 | static int SelectedDrive = 0; | ||
| 276 | static int ReqCmd, ReqBlock; | ||
| 277 | static int ReqSide, ReqTrack, ReqSector, ReqCnt; | ||
| 278 | static int HeadSettleFlag = 0; | ||
| 279 | static unsigned char *ReqData, *ReqBuffer; | ||
| 280 | static int MotorOn = 0, MotorOffTrys; | ||
| 281 | |||
| 282 | /* Synchronization of FDC1772 access. */ | ||
| 283 | static volatile int fdc_busy = 0; | ||
| 284 | static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); | ||
| 285 | |||
| 286 | |||
| 287 | /* long req'd for set_bit --RR */ | ||
| 288 | static unsigned long changed_floppies = 0xff, fake_change = 0; | ||
| 289 | #define CHECK_CHANGE_DELAY HZ/2 | ||
| 290 | |||
| 291 | /* DAG - increased to 30*HZ - not sure if this is the correct thing to do */ | ||
| 292 | #define FD_MOTOR_OFF_DELAY (10*HZ) | ||
| 293 | #define FD_MOTOR_OFF_MAXTRY (10*20) | ||
| 294 | |||
| 295 | #define FLOPPY_TIMEOUT (6*HZ) | ||
| 296 | #define RECALIBRATE_ERRORS 4 /* After this many errors the drive | ||
| 297 | * will be recalibrated. */ | ||
| 298 | #define MAX_ERRORS 8 /* After this many errors the driver | ||
| 299 | * will give up. */ | ||
| 300 | |||
| 301 | #define START_MOTOR_OFF_TIMER(delay) \ | ||
| 302 | do { \ | ||
| 303 | motor_off_timer.expires = jiffies + (delay); \ | ||
| 304 | add_timer( &motor_off_timer ); \ | ||
| 305 | MotorOffTrys = 0; \ | ||
| 306 | } while(0) | ||
| 307 | |||
| 308 | #define START_CHECK_CHANGE_TIMER(delay) \ | ||
| 309 | do { \ | ||
| 310 | mod_timer(&fd_timer, jiffies + (delay)); \ | ||
| 311 | } while(0) | ||
| 312 | |||
| 313 | #define START_TIMEOUT() \ | ||
| 314 | do { \ | ||
| 315 | mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \ | ||
| 316 | } while(0) | ||
| 317 | |||
| 318 | #define STOP_TIMEOUT() \ | ||
| 319 | do { \ | ||
| 320 | del_timer( &timeout_timer ); \ | ||
| 321 | } while(0) | ||
| 322 | |||
| 323 | #define ENABLE_IRQ() enable_irq(FIQ_FD1772+64); | ||
| 324 | |||
| 325 | #define DISABLE_IRQ() disable_irq(FIQ_FD1772+64); | ||
| 326 | |||
| 327 | static void fd1772_checkint(void); | ||
| 328 | |||
| 329 | DECLARE_WORK(fd1772_tq, (void *)fd1772_checkint, NULL); | ||
| 330 | /* | ||
| 331 | * The driver is trying to determine the correct media format | ||
| 332 | * while Probing is set. fd_rwsec_done() clears it after a | ||
| 333 | * successful access. | ||
| 334 | */ | ||
| 335 | static int Probing = 0; | ||
| 336 | |||
| 337 | /* This flag is set when a dummy seek is necessary to make the WP | ||
| 338 | * status bit accessible. | ||
| 339 | */ | ||
| 340 | static int NeedSeek = 0; | ||
| 341 | |||
| 342 | |||
| 343 | /***************************** Prototypes *****************************/ | ||
| 344 | |||
| 345 | static void fd_select_side(int side); | ||
| 346 | static void fd_select_drive(int drive); | ||
| 347 | static void fd_deselect(void); | ||
| 348 | static void fd_motor_off_timer(unsigned long dummy); | ||
| 349 | static void check_change(unsigned long dummy); | ||
| 350 | static void floppy_irqconsequencehandler(void); | ||
| 351 | static void fd_error(void); | ||
| 352 | static void do_fd_action(int drive); | ||
| 353 | static void fd_calibrate(void); | ||
| 354 | static void fd_calibrate_done(int status); | ||
| 355 | static void fd_seek(void); | ||
| 356 | static void fd_seek_done(int status); | ||
| 357 | static void fd_rwsec(void); | ||
| 358 | #ifdef TRACKBUFFER | ||
| 359 | static void fd_readtrack_check( unsigned long dummy ); | ||
| 360 | #endif | ||
| 361 | static void fd_rwsec_done(int status); | ||
| 362 | static void fd_times_out(unsigned long dummy); | ||
| 363 | static void finish_fdc(void); | ||
| 364 | static void finish_fdc_done(int dummy); | ||
| 365 | static void floppy_off(unsigned int nr); | ||
| 366 | static void setup_req_params(int drive); | ||
| 367 | static void redo_fd_request(void); | ||
| 368 | static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int | ||
| 369 | cmd, unsigned long param); | ||
| 370 | static void fd_probe(int drive); | ||
| 371 | static int fd_test_drive_present(int drive); | ||
| 372 | static void config_types(void); | ||
| 373 | static int floppy_open(struct inode *inode, struct file *filp); | ||
| 374 | static int floppy_release(struct inode *inode, struct file *filp); | ||
| 375 | static void do_fd_request(struct request_queue *); | ||
| 376 | |||
| 377 | /************************* End of Prototypes **************************/ | ||
| 378 | |||
| 379 | static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0); | ||
| 380 | |||
| 381 | #ifdef TRACKBUFFER | ||
| 382 | static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0); | ||
| 383 | #endif | ||
| 384 | |||
| 385 | static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0); | ||
| 386 | |||
| 387 | static DEFINE_TIMER(fd_timer, check_change, 0, 0); | ||
| 388 | |||
| 389 | /* DAG: Haven't got a clue what this is? */ | ||
| 390 | int stdma_islocked(void) | ||
| 391 | { | ||
| 392 | return 0; | ||
| 393 | }; | ||
| 394 | |||
| 395 | /* Select the side to use. */ | ||
| 396 | |||
| 397 | static void fd_select_side(int side) | ||
| 398 | { | ||
| 399 | oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL); | ||
| 400 | } | ||
| 401 | |||
| 402 | |||
| 403 | /* Select a drive, update the FDC1772's track register | ||
| 404 | */ | ||
| 405 | |||
| 406 | static void fd_select_drive(int drive) | ||
| 407 | { | ||
| 408 | #ifdef DEBUG | ||
| 409 | printk("fd_select_drive:%d\n", drive); | ||
| 410 | #endif | ||
| 411 | /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */ | ||
| 412 | oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0); | ||
| 413 | |||
| 414 | if (drive == SelectedDrive) | ||
| 415 | return; | ||
| 416 | |||
| 417 | oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive)); | ||
| 418 | |||
| 419 | /* restore track register to saved value */ | ||
| 420 | FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track); | ||
| 421 | udelay(25); | ||
| 422 | |||
| 423 | SelectedDrive = drive; | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | /* Deselect both drives. */ | ||
| 428 | |||
| 429 | static void fd_deselect(void) | ||
| 430 | { | ||
| 431 | unsigned long flags; | ||
| 432 | |||
| 433 | DPRINT(("fd_deselect\n")); | ||
| 434 | |||
| 435 | oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE); | ||
| 436 | |||
| 437 | SelectedDrive = -1; | ||
| 438 | } | ||
| 439 | |||
| 440 | |||
| 441 | /* This timer function deselects the drives when the FDC1772 switched the | ||
| 442 | * motor off. The deselection cannot happen earlier because the FDC1772 | ||
| 443 | * counts the index signals, which arrive only if one drive is selected. | ||
| 444 | */ | ||
| 445 | |||
| 446 | static void fd_motor_off_timer(unsigned long dummy) | ||
| 447 | { | ||
| 448 | unsigned long flags; | ||
| 449 | unsigned char status; | ||
| 450 | int delay; | ||
| 451 | |||
| 452 | del_timer(&motor_off_timer); | ||
| 453 | |||
| 454 | if (SelectedDrive < 0) | ||
| 455 | /* no drive selected, needn't deselect anyone */ | ||
| 456 | return; | ||
| 457 | |||
| 458 | save_flags(flags); | ||
| 459 | cli(); | ||
| 460 | |||
| 461 | if (fdc_busy) /* was stdma_islocked */ | ||
| 462 | goto retry; | ||
| 463 | |||
| 464 | status = FDC1772_READ(FDC1772REG_STATUS); | ||
| 465 | |||
| 466 | if (!(status & 0x80)) { | ||
| 467 | /* | ||
| 468 | * motor already turned off by FDC1772 -> deselect drives | ||
| 469 | * In actual fact its this deselection which turns the motor | ||
| 470 | * off on the Arc, since the motor control is actually on | ||
| 471 | * Latch A | ||
| 472 | */ | ||
| 473 | DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n")); | ||
| 474 | fd_deselect(); | ||
| 475 | MotorOn = 0; | ||
| 476 | restore_flags(flags); | ||
| 477 | return; | ||
| 478 | } | ||
| 479 | /* not yet off, try again */ | ||
| 480 | |||
| 481 | retry: | ||
| 482 | restore_flags(flags); | ||
| 483 | /* Test again later; if tested too often, it seems there is no disk | ||
| 484 | * in the drive and the FDC1772 will leave the motor on forever (or, | ||
| 485 | * at least until a disk is inserted). So we'll test only twice | ||
| 486 | * per second from then on... | ||
| 487 | */ | ||
| 488 | delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ? | ||
| 489 | (++MotorOffTrys, HZ / 20) : HZ / 2; | ||
| 490 | START_MOTOR_OFF_TIMER(delay); | ||
| 491 | } | ||
| 492 | |||
| 493 | |||
| 494 | /* This function is repeatedly called to detect disk changes (as good | ||
| 495 | * as possible) and keep track of the current state of the write protection. | ||
| 496 | */ | ||
| 497 | |||
| 498 | static void check_change(unsigned long dummy) | ||
| 499 | { | ||
| 500 | static int drive = 0; | ||
| 501 | |||
| 502 | unsigned long flags; | ||
| 503 | int stat; | ||
| 504 | |||
| 505 | if (fdc_busy) | ||
| 506 | return; /* Don't start poking about if the fdc is busy */ | ||
| 507 | |||
| 508 | return; /* let's just forget it for the mo DAG */ | ||
| 509 | |||
| 510 | if (++drive > 1 || !unit[drive].connected) | ||
| 511 | drive = 0; | ||
| 512 | |||
| 513 | save_flags(flags); | ||
| 514 | cli(); | ||
| 515 | |||
| 516 | if (!stdma_islocked()) { | ||
| 517 | stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT); | ||
| 518 | |||
| 519 | /* The idea here is that if the write protect line has changed then | ||
| 520 | the disc must have changed */ | ||
| 521 | if (stat != unit[drive].wpstat) { | ||
| 522 | DPRINT(("wpstat[%d] = %d\n", drive, stat)); | ||
| 523 | unit[drive].wpstat = stat; | ||
| 524 | set_bit(drive, &changed_floppies); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | restore_flags(flags); | ||
| 528 | |||
| 529 | START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY); | ||
| 530 | } | ||
| 531 | |||
| 532 | |||
| 533 | /* Handling of the Head Settling Flag: This flag should be set after each | ||
| 534 | * seek operation, because we don't use seeks with verify. | ||
| 535 | */ | ||
| 536 | |||
| 537 | static inline void set_head_settle_flag(void) | ||
| 538 | { | ||
| 539 | HeadSettleFlag = FDC1772CMDADD_E; | ||
| 540 | } | ||
| 541 | |||
| 542 | static inline int get_head_settle_flag(void) | ||
| 543 | { | ||
| 544 | int tmp = HeadSettleFlag; | ||
| 545 | HeadSettleFlag = 0; | ||
| 546 | return (tmp); | ||
| 547 | } | ||
| 548 | |||
| 549 | |||
| 550 | |||
| 551 | |||
| 552 | /* General Interrupt Handling */ | ||
| 553 | |||
| 554 | static inline void copy_buffer(void *from, void *to) | ||
| 555 | { | ||
| 556 | ulong *p1 = (ulong *) from, *p2 = (ulong *) to; | ||
| 557 | int cnt; | ||
| 558 | |||
| 559 | for (cnt = 512 / 4; cnt; cnt--) | ||
| 560 | *p2++ = *p1++; | ||
| 561 | } | ||
| 562 | |||
| 563 | static void (*FloppyIRQHandler) (int status) = NULL; | ||
| 564 | |||
| 565 | static void floppy_irqconsequencehandler(void) | ||
| 566 | { | ||
| 567 | unsigned char status; | ||
| 568 | void (*handler) (int); | ||
| 569 | |||
| 570 | fdc1772_fdc_int_done = 0; | ||
| 571 | |||
| 572 | handler = FloppyIRQHandler; | ||
| 573 | FloppyIRQHandler = NULL; | ||
| 574 | |||
| 575 | if (handler) { | ||
| 576 | nop(); | ||
| 577 | status = (unsigned char) fdc1772_comendstatus; | ||
| 578 | DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler)); | ||
| 579 | handler(status); | ||
| 580 | } else { | ||
| 581 | DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus)); | ||
| 582 | } | ||
| 583 | DPRINT(("FDC1772 irq: end of floppy_irq\n")); | ||
| 584 | } | ||
| 585 | |||
| 586 | |||
| 587 | /* Error handling: If some error happened, retry some times, then | ||
| 588 | * recalibrate, then try again, and fail after MAX_ERRORS. | ||
| 589 | */ | ||
| 590 | |||
| 591 | static void fd_error(void) | ||
| 592 | { | ||
| 593 | printk("FDC1772: fd_error\n"); | ||
| 594 | /*panic("fd1772: fd_error"); *//* DAG tmp */ | ||
| 595 | if (!CURRENT) | ||
| 596 | return; | ||
| 597 | CURRENT->errors++; | ||
| 598 | if (CURRENT->errors >= MAX_ERRORS) { | ||
| 599 | printk("fd%d: too many errors.\n", SelectedDrive); | ||
| 600 | end_request(CURRENT, 0); | ||
| 601 | } else if (CURRENT->errors == RECALIBRATE_ERRORS) { | ||
| 602 | printk("fd%d: recalibrating\n", SelectedDrive); | ||
| 603 | if (SelectedDrive != -1) | ||
| 604 | unit[SelectedDrive].track = -1; | ||
| 605 | } | ||
| 606 | redo_fd_request(); | ||
| 607 | } | ||
| 608 | |||
| 609 | |||
| 610 | |||
| 611 | #define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0) | ||
| 612 | |||
| 613 | |||
| 614 | /* do_fd_action() is the general procedure for a fd request: All | ||
| 615 | * required parameter settings (drive select, side select, track | ||
| 616 | * position) are checked and set if needed. For each of these | ||
| 617 | * parameters and the actual reading or writing exist two functions: | ||
| 618 | * one that starts the setting (or skips it if possible) and one | ||
| 619 | * callback for the "done" interrupt. Each done func calls the next | ||
| 620 | * set function to propagate the request down to fd_rwsec_done(). | ||
| 621 | */ | ||
| 622 | |||
| 623 | static void do_fd_action(int drive) | ||
| 624 | { | ||
| 625 | struct request *req; | ||
| 626 | DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track)); | ||
| 627 | |||
| 628 | #ifdef TRACKBUFFER | ||
| 629 | repeat: | ||
| 630 | |||
| 631 | if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { | ||
| 632 | req = CURRENT; | ||
| 633 | if (ReqCmd == READ) { | ||
| 634 | copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); | ||
| 635 | if (++ReqCnt < req->current_nr_sectors) { | ||
| 636 | /* read next sector */ | ||
| 637 | setup_req_params( drive ); | ||
| 638 | goto repeat; | ||
| 639 | } else { | ||
| 640 | /* all sectors finished */ | ||
| 641 | req->nr_sectors -= req->current_nr_sectors; | ||
| 642 | req->sector += req->current_nr_sectors; | ||
| 643 | end_request(req, 1); | ||
| 644 | redo_fd_request(); | ||
| 645 | return; | ||
| 646 | } | ||
| 647 | } else { | ||
| 648 | /* cmd == WRITE, pay attention to track buffer | ||
| 649 | * consistency! */ | ||
| 650 | copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) ); | ||
| 651 | } | ||
| 652 | } | ||
| 653 | #endif | ||
| 654 | |||
| 655 | if (SelectedDrive != drive) { | ||
| 656 | /*unit[drive].track = -1; DAG */ | ||
| 657 | fd_select_drive(drive); | ||
| 658 | }; | ||
| 659 | |||
| 660 | |||
| 661 | if (unit[drive].track == -1) | ||
| 662 | fd_calibrate(); | ||
| 663 | else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch) | ||
| 664 | fd_seek(); | ||
| 665 | else | ||
| 666 | fd_rwsec(); | ||
| 667 | } | ||
| 668 | |||
| 669 | |||
| 670 | /* Seek to track 0 if the current track is unknown */ | ||
| 671 | |||
| 672 | static void fd_calibrate(void) | ||
| 673 | { | ||
| 674 | DPRINT(("fd_calibrate\n")); | ||
| 675 | if (unit[SelectedDrive].track >= 0) { | ||
| 676 | fd_calibrate_done(0); | ||
| 677 | return; | ||
| 678 | } | ||
| 679 | DPRINT(("fd_calibrate (after track compare)\n")); | ||
| 680 | SET_IRQ_HANDLER(fd_calibrate_done); | ||
| 681 | /* we can't verify, since the speed may be incorrect */ | ||
| 682 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate); | ||
| 683 | |||
| 684 | NeedSeek = 1; | ||
| 685 | MotorOn = 1; | ||
| 686 | START_TIMEOUT(); | ||
| 687 | /* wait for IRQ */ | ||
| 688 | } | ||
| 689 | |||
| 690 | |||
| 691 | static void fd_calibrate_done(int status) | ||
| 692 | { | ||
| 693 | DPRINT(("fd_calibrate_done()\n")); | ||
| 694 | STOP_TIMEOUT(); | ||
| 695 | |||
| 696 | /* set the correct speed now */ | ||
| 697 | if (status & FDC1772STAT_RECNF) { | ||
| 698 | printk("fd%d: restore failed\n", SelectedDrive); | ||
| 699 | fd_error(); | ||
| 700 | } else { | ||
| 701 | unit[SelectedDrive].track = 0; | ||
| 702 | fd_seek(); | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | |||
| 707 | /* Seek the drive to the requested track. The drive must have been | ||
| 708 | * calibrated at some point before this. | ||
| 709 | */ | ||
| 710 | |||
| 711 | static void fd_seek(void) | ||
| 712 | { | ||
| 713 | unsigned long flags; | ||
| 714 | DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack, | ||
| 715 | unit[SelectedDrive].track)); | ||
| 716 | if (unit[SelectedDrive].track == ReqTrack << | ||
| 717 | unit[SelectedDrive].disktype->stretch) { | ||
| 718 | fd_seek_done(0); | ||
| 719 | return; | ||
| 720 | } | ||
| 721 | FDC1772_WRITE(FDC1772REG_DATA, ReqTrack << | ||
| 722 | unit[SelectedDrive].disktype->stretch); | ||
| 723 | udelay(25); | ||
| 724 | save_flags(flags); | ||
| 725 | clf(); | ||
| 726 | SET_IRQ_HANDLER(fd_seek_done); | ||
| 727 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate | | ||
| 728 | /* DAG */ | ||
| 729 | (MotorOn?FDC1772CMDADD_H:0)); | ||
| 730 | |||
| 731 | restore_flags(flags); | ||
| 732 | MotorOn = 1; | ||
| 733 | set_head_settle_flag(); | ||
| 734 | START_TIMEOUT(); | ||
| 735 | /* wait for IRQ */ | ||
| 736 | } | ||
| 737 | |||
| 738 | |||
| 739 | static void fd_seek_done(int status) | ||
| 740 | { | ||
| 741 | DPRINT(("fd_seek_done()\n")); | ||
| 742 | STOP_TIMEOUT(); | ||
| 743 | |||
| 744 | /* set the correct speed */ | ||
| 745 | if (status & FDC1772STAT_RECNF) { | ||
| 746 | printk("fd%d: seek error (to track %d)\n", | ||
| 747 | SelectedDrive, ReqTrack); | ||
| 748 | /* we don't know exactly which track we are on now! */ | ||
| 749 | unit[SelectedDrive].track = -1; | ||
| 750 | fd_error(); | ||
| 751 | } else { | ||
| 752 | unit[SelectedDrive].track = ReqTrack << | ||
| 753 | unit[SelectedDrive].disktype->stretch; | ||
| 754 | NeedSeek = 0; | ||
| 755 | fd_rwsec(); | ||
| 756 | } | ||
| 757 | } | ||
| 758 | |||
| 759 | |||
| 760 | /* This does the actual reading/writing after positioning the head | ||
| 761 | * over the correct track. | ||
| 762 | */ | ||
| 763 | |||
| 764 | #ifdef TRACKBUFFER | ||
| 765 | static int MultReadInProgress = 0; | ||
| 766 | #endif | ||
| 767 | |||
| 768 | |||
| 769 | static void fd_rwsec(void) | ||
| 770 | { | ||
| 771 | unsigned long paddr, flags; | ||
| 772 | unsigned int rwflag, old_motoron; | ||
| 773 | unsigned int track; | ||
| 774 | |||
| 775 | DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r')); | ||
| 776 | if (ReqCmd == WRITE) { | ||
| 777 | /*cache_push( (unsigned long)ReqData, 512 ); */ | ||
| 778 | paddr = (unsigned long) ReqData; | ||
| 779 | rwflag = 0x100; | ||
| 780 | } else { | ||
| 781 | paddr = (unsigned long) PhysDMABuffer; | ||
| 782 | #ifdef TRACKBUFFER | ||
| 783 | if (read_track) | ||
| 784 | paddr = (unsigned long)PhysTrackBuffer; | ||
| 785 | #endif | ||
| 786 | rwflag = 0; | ||
| 787 | } | ||
| 788 | |||
| 789 | DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag, | ||
| 790 | ReqSector, FDC1772_READ(FDC1772REG_TRACK))); | ||
| 791 | fd_select_side(ReqSide); | ||
| 792 | |||
| 793 | /*DPRINT(("fd_rwsec() before start sector \n")); */ | ||
| 794 | /* Start sector of this operation */ | ||
| 795 | #ifdef TRACKBUFFER | ||
| 796 | FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 ); | ||
| 797 | #else | ||
| 798 | FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector ); | ||
| 799 | #endif | ||
| 800 | |||
| 801 | /* Cheat for track if stretch != 0 */ | ||
| 802 | if (unit[SelectedDrive].disktype->stretch) { | ||
| 803 | track = FDC1772_READ(FDC1772REG_TRACK); | ||
| 804 | FDC1772_WRITE(FDC1772REG_TRACK, track >> | ||
| 805 | unit[SelectedDrive].disktype->stretch); | ||
| 806 | } | ||
| 807 | udelay(25); | ||
| 808 | |||
| 809 | DPRINT(("fd_rwsec() before setup DMA \n")); | ||
| 810 | /* Setup DMA - Heavily modified by DAG */ | ||
| 811 | save_flags(flags); | ||
| 812 | clf(); | ||
| 813 | disable_dma(FLOPPY_DMA); | ||
| 814 | set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ); | ||
| 815 | set_dma_addr(FLOPPY_DMA, (long) paddr); /* DAG - changed from Atari specific */ | ||
| 816 | #ifdef TRACKBUFFER | ||
| 817 | set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512); | ||
| 818 | #else | ||
| 819 | set_dma_count(FLOPPY_DMA, 512); /* Block/sector size - going to have to change */ | ||
| 820 | #endif | ||
| 821 | SET_IRQ_HANDLER(fd_rwsec_done); | ||
| 822 | /* Turn on dma int */ | ||
| 823 | enable_dma(FLOPPY_DMA); | ||
| 824 | /* Now give it something to do */ | ||
| 825 | FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : | ||
| 826 | #ifdef TRACKBUFFER | ||
| 827 | (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) | | ||
| 828 | /* Hmm - the idea here is to stop the FDC spinning the disc | ||
| 829 | up when we know that we already still have it spinning */ | ||
| 830 | (MotorOn?FDC1772CMDADD_H:0)) | ||
| 831 | #else | ||
| 832 | FDC1772CMD_RDSEC | ||
| 833 | #endif | ||
| 834 | )); | ||
| 835 | |||
| 836 | restore_flags(flags); | ||
| 837 | DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags)); | ||
| 838 | /*sti(); *//* DAG - Hmm */ | ||
| 839 | /* Hmm - should do something DAG */ | ||
| 840 | old_motoron = MotorOn; | ||
| 841 | MotorOn = 1; | ||
| 842 | NeedSeek = 1; | ||
| 843 | |||
| 844 | /* wait for interrupt */ | ||
| 845 | |||
| 846 | #ifdef TRACKBUFFER | ||
| 847 | if (read_track) { | ||
| 848 | /* | ||
| 849 | * If reading a whole track, wait about one disk rotation and | ||
| 850 | * then check if all sectors are read. The FDC will even | ||
| 851 | * search for the first non-existant sector and need 1 sec to | ||
| 852 | * recognise that it isn't present :-( | ||
| 853 | */ | ||
| 854 | /* 1 rot. + 5 rot.s if motor was off */ | ||
| 855 | mod_timer(&readtrack_timer, jiffies + HZ/5 + (old_motoron ? 0 : HZ)); | ||
| 856 | DPRINT(("Setting readtrack_timer to %d @ %d\n", | ||
| 857 | readtrack_timer.expires,jiffies)); | ||
| 858 | MultReadInProgress = 1; | ||
| 859 | } | ||
| 860 | #endif | ||
| 861 | |||
| 862 | /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */ | ||
| 863 | START_TIMEOUT(); | ||
| 864 | /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */ | ||
| 865 | } | ||
| 866 | |||
| 867 | |||
| 868 | #ifdef TRACKBUFFER | ||
| 869 | |||
| 870 | static void fd_readtrack_check(unsigned long dummy) | ||
| 871 | { | ||
| 872 | unsigned long flags, addr; | ||
| 873 | extern unsigned char *fdc1772_dataaddr; | ||
| 874 | |||
| 875 | DPRINT(("fd_readtrack_check @ %d\n",jiffies)); | ||
| 876 | |||
| 877 | save_flags(flags); | ||
| 878 | clf(); | ||
| 879 | |||
| 880 | del_timer( &readtrack_timer ); | ||
| 881 | |||
| 882 | if (!MultReadInProgress) { | ||
| 883 | /* This prevents a race condition that could arise if the | ||
| 884 | * interrupt is triggered while the calling of this timer | ||
| 885 | * callback function takes place. The IRQ function then has | ||
| 886 | * already cleared 'MultReadInProgress' when control flow | ||
| 887 | * gets here. | ||
| 888 | */ | ||
| 889 | restore_flags(flags); | ||
| 890 | return; | ||
| 891 | } | ||
| 892 | |||
| 893 | /* get the current DMA address */ | ||
| 894 | addr=(unsigned long)fdc1772_dataaddr; /* DAG - ? */ | ||
| 895 | DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer)); | ||
| 896 | |||
| 897 | if (addr >= (unsigned int)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) { | ||
| 898 | /* already read enough data, force an FDC interrupt to stop | ||
| 899 | * the read operation | ||
| 900 | */ | ||
| 901 | SET_IRQ_HANDLER( NULL ); | ||
| 902 | restore_flags(flags); | ||
| 903 | DPRINT(("fd_readtrack_check(): done\n")); | ||
| 904 | FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI ); | ||
| 905 | udelay(25); | ||
| 906 | |||
| 907 | /* No error until now -- the FDC would have interrupted | ||
| 908 | * otherwise! | ||
| 909 | */ | ||
| 910 | fd_rwsec_done( 0 ); | ||
| 911 | } else { | ||
| 912 | /* not yet finished, wait another tenth rotation */ | ||
| 913 | restore_flags(flags); | ||
| 914 | DPRINT(("fd_readtrack_check(): not yet finished\n")); | ||
| 915 | readtrack_timer.expires = jiffies + HZ/5/10; | ||
| 916 | add_timer( &readtrack_timer ); | ||
| 917 | } | ||
| 918 | } | ||
| 919 | |||
| 920 | #endif | ||
| 921 | |||
| 922 | static void fd_rwsec_done(int status) | ||
| 923 | { | ||
| 924 | unsigned int track; | ||
| 925 | |||
| 926 | DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies)); | ||
| 927 | |||
| 928 | #ifdef TRACKBUFFER | ||
| 929 | if (read_track && !MultReadInProgress) | ||
| 930 | return; | ||
| 931 | |||
| 932 | MultReadInProgress = 0; | ||
| 933 | |||
| 934 | STOP_TIMEOUT(); | ||
| 935 | |||
| 936 | if (read_track) | ||
| 937 | del_timer( &readtrack_timer ); | ||
| 938 | #endif | ||
| 939 | |||
| 940 | |||
| 941 | /* Correct the track if stretch != 0 */ | ||
| 942 | if (unit[SelectedDrive].disktype->stretch) { | ||
| 943 | track = FDC1772_READ(FDC1772REG_TRACK); | ||
| 944 | FDC1772_WRITE(FDC1772REG_TRACK, track << | ||
| 945 | unit[SelectedDrive].disktype->stretch); | ||
| 946 | } | ||
| 947 | if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) { | ||
| 948 | printk("fd%d: is write protected\n", SelectedDrive); | ||
| 949 | goto err_end; | ||
| 950 | } | ||
| 951 | if ((status & FDC1772STAT_RECNF) | ||
| 952 | #ifdef TRACKBUFFER | ||
| 953 | /* RECNF is no error after a multiple read when the FDC | ||
| 954 | * searched for a non-existant sector! | ||
| 955 | */ | ||
| 956 | && !(read_track && | ||
| 957 | FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt) | ||
| 958 | #endif | ||
| 959 | ) { | ||
| 960 | if (Probing) { | ||
| 961 | if (unit[SelectedDrive].disktype > disk_type) { | ||
| 962 | /* try another disk type */ | ||
| 963 | unit[SelectedDrive].disktype--; | ||
| 964 | set_capacity(disks[SelectedDrive], | ||
| 965 | unit[SelectedDrive].disktype->blocks); | ||
| 966 | } else | ||
| 967 | Probing = 0; | ||
| 968 | } else { | ||
| 969 | /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ | ||
| 970 | if (unit[SelectedDrive].autoprobe) { | ||
| 971 | unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1; | ||
| 972 | set_capacity(disks[SelectedDrive], | ||
| 973 | unit[SelectedDrive].disktype->blocks); | ||
| 974 | Probing = 1; | ||
| 975 | } | ||
| 976 | } | ||
| 977 | if (Probing) { | ||
| 978 | setup_req_params(SelectedDrive); | ||
| 979 | #ifdef TRACKBUFFER | ||
| 980 | BufferDrive = -1; | ||
| 981 | #endif | ||
| 982 | do_fd_action(SelectedDrive); | ||
| 983 | return; | ||
| 984 | } | ||
| 985 | printk("fd%d: sector %d not found (side %d, track %d)\n", | ||
| 986 | SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack); | ||
| 987 | goto err_end; | ||
| 988 | } | ||
| 989 | if (status & FDC1772STAT_CRC) { | ||
| 990 | printk("fd%d: CRC error (side %d, track %d, sector %d)\n", | ||
| 991 | SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); | ||
| 992 | goto err_end; | ||
| 993 | } | ||
| 994 | if (status & FDC1772STAT_LOST) { | ||
| 995 | printk("fd%d: lost data (side %d, track %d, sector %d)\n", | ||
| 996 | SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); | ||
| 997 | goto err_end; | ||
| 998 | } | ||
| 999 | Probing = 0; | ||
| 1000 | |||
| 1001 | if (ReqCmd == READ) { | ||
| 1002 | #ifdef TRACKBUFFER | ||
| 1003 | if (!read_track) { | ||
| 1004 | /*cache_clear (PhysDMABuffer, 512);*/ | ||
| 1005 | copy_buffer (DMABuffer, ReqData); | ||
| 1006 | } else { | ||
| 1007 | /*cache_clear (PhysTrackBuffer, FD1772_MAX_SECTORS * 512);*/ | ||
| 1008 | BufferDrive = SelectedDrive; | ||
| 1009 | BufferSide = ReqSide; | ||
| 1010 | BufferTrack = ReqTrack; | ||
| 1011 | copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); | ||
| 1012 | } | ||
| 1013 | #else | ||
| 1014 | /*cache_clear( PhysDMABuffer, 512 ); */ | ||
| 1015 | copy_buffer(DMABuffer, ReqData); | ||
| 1016 | #endif | ||
| 1017 | } | ||
| 1018 | if (++ReqCnt < CURRENT->current_nr_sectors) { | ||
| 1019 | /* read next sector */ | ||
| 1020 | setup_req_params(SelectedDrive); | ||
| 1021 | do_fd_action(SelectedDrive); | ||
| 1022 | } else { | ||
| 1023 | /* all sectors finished */ | ||
| 1024 | CURRENT->nr_sectors -= CURRENT->current_nr_sectors; | ||
| 1025 | CURRENT->sector += CURRENT->current_nr_sectors; | ||
| 1026 | end_request(CURRENT, 1); | ||
| 1027 | redo_fd_request(); | ||
| 1028 | } | ||
| 1029 | return; | ||
| 1030 | |||
| 1031 | err_end: | ||
| 1032 | #ifdef TRACKBUFFER | ||
| 1033 | BufferDrive = -1; | ||
| 1034 | #endif | ||
| 1035 | |||
| 1036 | fd_error(); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | |||
| 1040 | static void fd_times_out(unsigned long dummy) | ||
| 1041 | { | ||
| 1042 | SET_IRQ_HANDLER(NULL); | ||
| 1043 | /* If the timeout occurred while the readtrack_check timer was | ||
| 1044 | * active, we need to cancel it, else bad things will happen */ | ||
| 1045 | del_timer( &readtrack_timer ); | ||
| 1046 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); | ||
| 1047 | udelay(25); | ||
| 1048 | |||
| 1049 | printk("floppy timeout\n"); | ||
| 1050 | STOP_TIMEOUT(); /* hmm - should we do this ? */ | ||
| 1051 | fd_error(); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | |||
| 1055 | /* The (noop) seek operation here is needed to make the WP bit in the | ||
| 1056 | * FDC1772 status register accessible for check_change. If the last disk | ||
| 1057 | * operation would have been a RDSEC, this bit would always read as 0 | ||
| 1058 | * no matter what :-( To save time, the seek goes to the track we're | ||
| 1059 | * already on. | ||
| 1060 | */ | ||
| 1061 | |||
| 1062 | static void finish_fdc(void) | ||
| 1063 | { | ||
| 1064 | /* DAG - just try without this dummy seek! */ | ||
| 1065 | finish_fdc_done(0); | ||
| 1066 | return; | ||
| 1067 | |||
| 1068 | if (!NeedSeek) { | ||
| 1069 | finish_fdc_done(0); | ||
| 1070 | } else { | ||
| 1071 | DPRINT(("finish_fdc: dummy seek started\n")); | ||
| 1072 | FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track); | ||
| 1073 | SET_IRQ_HANDLER(finish_fdc_done); | ||
| 1074 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); | ||
| 1075 | MotorOn = 1; | ||
| 1076 | START_TIMEOUT(); | ||
| 1077 | /* we must wait for the IRQ here, because the ST-DMA is | ||
| 1078 | * released immediately afterwards and the interrupt may be | ||
| 1079 | * delivered to the wrong driver. | ||
| 1080 | */ | ||
| 1081 | } | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | |||
| 1085 | static void finish_fdc_done(int dummy) | ||
| 1086 | { | ||
| 1087 | unsigned long flags; | ||
| 1088 | |||
| 1089 | DPRINT(("finish_fdc_done entered\n")); | ||
| 1090 | STOP_TIMEOUT(); | ||
| 1091 | NeedSeek = 0; | ||
| 1092 | |||
| 1093 | if (timer_pending(&fd_timer) && | ||
| 1094 | time_after(jiffies + 5, fd_timer.expires)) | ||
| 1095 | /* If the check for a disk change is done too early after this | ||
| 1096 | * last seek command, the WP bit still reads wrong :-(( | ||
| 1097 | */ | ||
| 1098 | mod_timer(&fd_timer, jiffies + 5); | ||
| 1099 | else { | ||
| 1100 | /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ | ||
| 1101 | }; | ||
| 1102 | del_timer(&motor_off_timer); | ||
| 1103 | START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); | ||
| 1104 | |||
| 1105 | save_flags(flags); | ||
| 1106 | cli(); | ||
| 1107 | /* stdma_release(); - not sure if I should do something DAG */ | ||
| 1108 | fdc_busy = 0; | ||
| 1109 | wake_up(&fdc_wait); | ||
| 1110 | restore_flags(flags); | ||
| 1111 | |||
| 1112 | DPRINT(("finish_fdc() finished\n")); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | |||
| 1116 | /* Prevent "aliased" accesses. */ | ||
| 1117 | static int fd_ref[4]; | ||
| 1118 | static int fd_device[4]; | ||
| 1119 | |||
| 1120 | /* dummy for blk.h */ | ||
| 1121 | static void floppy_off(unsigned int nr) | ||
| 1122 | { | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | |||
| 1126 | /* On the old arcs write protect depends on the particular model | ||
| 1127 | of machine. On the A310, R140, and A440 there is a disc changed | ||
| 1128 | detect, however on the A4x0/1 range there is not. There | ||
| 1129 | is nothing to tell you which machine your on. | ||
| 1130 | At the moment I'm just marking changed always. I've | ||
| 1131 | left the Atari's 'change on write protect change' code in this | ||
| 1132 | part (but nothing sets it). | ||
| 1133 | RiscOS apparently checks the disc serial number etc. to detect changes | ||
| 1134 | - but if it sees a disc change line go high (?) it flips to using | ||
| 1135 | it. Well maybe I'll add that in the future (!?) | ||
| 1136 | */ | ||
| 1137 | static int check_floppy_change(struct gendisk *disk) | ||
| 1138 | { | ||
| 1139 | struct archy_floppy_struct *p = disk->private_data; | ||
| 1140 | unsigned int drive = p - unit; | ||
| 1141 | |||
| 1142 | if (test_bit(drive, &fake_change)) { | ||
| 1143 | /* simulated change (e.g. after formatting) */ | ||
| 1144 | return 1; | ||
| 1145 | } | ||
| 1146 | if (test_bit(drive, &changed_floppies)) { | ||
| 1147 | /* surely changed (the WP signal changed at least once) */ | ||
| 1148 | return 1; | ||
| 1149 | } | ||
| 1150 | if (p->wpstat) { | ||
| 1151 | /* WP is on -> could be changed: to be sure, buffers should be | ||
| 1152 | * invalidated... | ||
| 1153 | */ | ||
| 1154 | return 1; | ||
| 1155 | } | ||
| 1156 | return 1; /* DAG - was 0 */ | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | static int floppy_revalidate(struct gendisk *disk) | ||
| 1160 | { | ||
| 1161 | struct archy_floppy_struct *p = disk->private_data; | ||
| 1162 | unsigned int drive = p - unit; | ||
| 1163 | |||
| 1164 | if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) | ||
| 1165 | || unit[drive].disktype == 0) { | ||
| 1166 | #ifdef TRACKBUFFER | ||
| 1167 | BufferDrive = -1; | ||
| 1168 | #endif | ||
| 1169 | clear_bit(drive, &fake_change); | ||
| 1170 | clear_bit(drive, &changed_floppies); | ||
| 1171 | p->disktype = 0; | ||
| 1172 | } | ||
| 1173 | return 0; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | /* This sets up the global variables describing the current request. */ | ||
| 1177 | |||
| 1178 | static void setup_req_params(int drive) | ||
| 1179 | { | ||
| 1180 | int block = ReqBlock + ReqCnt; | ||
| 1181 | |||
| 1182 | ReqTrack = block / unit[drive].disktype->spt; | ||
| 1183 | ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1; | ||
| 1184 | ReqSide = ReqTrack & 1; | ||
| 1185 | ReqTrack >>= 1; | ||
| 1186 | ReqData = ReqBuffer + 512 * ReqCnt; | ||
| 1187 | |||
| 1188 | #ifdef TRACKBUFFER | ||
| 1189 | read_track = (ReqCmd == READ && CURRENT->errors == 0); | ||
| 1190 | #endif | ||
| 1191 | |||
| 1192 | DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide, | ||
| 1193 | ReqTrack, ReqSector, (unsigned long) ReqData)); | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | |||
| 1197 | static void redo_fd_request(void) | ||
| 1198 | { | ||
| 1199 | int drive, type; | ||
| 1200 | struct archy_floppy_struct *floppy; | ||
| 1201 | |||
| 1202 | DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", | ||
| 1203 | CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", | ||
| 1204 | CURRENT ? CURRENT->sector : 0)); | ||
| 1205 | |||
| 1206 | repeat: | ||
| 1207 | |||
| 1208 | if (!CURRENT) | ||
| 1209 | goto the_end; | ||
| 1210 | |||
| 1211 | floppy = CURRENT->rq_disk->private_data; | ||
| 1212 | drive = floppy - unit; | ||
| 1213 | type = fd_device[drive]; | ||
| 1214 | |||
| 1215 | if (!floppy->connected) { | ||
| 1216 | /* drive not connected */ | ||
| 1217 | printk("Unknown Device: fd%d\n", drive); | ||
| 1218 | end_request(CURRENT, 0); | ||
| 1219 | goto repeat; | ||
| 1220 | } | ||
| 1221 | if (type == 0) { | ||
| 1222 | if (!floppy->disktype) { | ||
| 1223 | Probing = 1; | ||
| 1224 | floppy->disktype = disk_type + NUM_DISK_TYPES - 1; | ||
| 1225 | set_capacity(disks[drive], floppy->disktype->blocks); | ||
| 1226 | floppy->autoprobe = 1; | ||
| 1227 | } | ||
| 1228 | } else { | ||
| 1229 | /* user supplied disk type */ | ||
| 1230 | --type; | ||
| 1231 | if (type >= NUM_DISK_TYPES) { | ||
| 1232 | printk("fd%d: invalid disk format", drive); | ||
| 1233 | end_request(CURRENT, 0); | ||
| 1234 | goto repeat; | ||
| 1235 | } | ||
| 1236 | floppy->disktype = &disk_type[type]; | ||
| 1237 | set_capacity(disks[drive], floppy->disktype->blocks); | ||
| 1238 | floppy->autoprobe = 0; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | if (CURRENT->sector + 1 > floppy->disktype->blocks) { | ||
| 1242 | end_request(CURRENT, 0); | ||
| 1243 | goto repeat; | ||
| 1244 | } | ||
| 1245 | /* stop deselect timer */ | ||
| 1246 | del_timer(&motor_off_timer); | ||
| 1247 | |||
| 1248 | ReqCnt = 0; | ||
| 1249 | ReqCmd = rq_data_dir(CURRENT); | ||
| 1250 | ReqBlock = CURRENT->sector; | ||
| 1251 | ReqBuffer = CURRENT->buffer; | ||
| 1252 | setup_req_params(drive); | ||
| 1253 | do_fd_action(drive); | ||
| 1254 | |||
| 1255 | return; | ||
| 1256 | |||
| 1257 | the_end: | ||
| 1258 | finish_fdc(); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | static void fd1772_checkint(void) | ||
| 1262 | { | ||
| 1263 | extern int fdc1772_bytestogo; | ||
| 1264 | |||
| 1265 | /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/ | ||
| 1266 | if (fdc1772_fdc_int_done) | ||
| 1267 | floppy_irqconsequencehandler(); | ||
| 1268 | if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0); | ||
| 1269 | if (fdc_busy) { | ||
| 1270 | schedule_work(&fd1772_tq); | ||
| 1271 | } | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | static void do_fd_request(struct request_queue* q) | ||
| 1275 | { | ||
| 1276 | unsigned long flags; | ||
| 1277 | |||
| 1278 | DPRINT(("do_fd_request for pid %d\n", current->pid)); | ||
| 1279 | if (fdc_busy) return; | ||
| 1280 | save_flags(flags); | ||
| 1281 | cli(); | ||
| 1282 | wait_event(fdc_wait, !fdc_busy); | ||
| 1283 | fdc_busy = 1; | ||
| 1284 | ENABLE_IRQ(); | ||
| 1285 | restore_flags(flags); | ||
| 1286 | |||
| 1287 | fdc1772_fdc_int_done = 0; | ||
| 1288 | |||
| 1289 | redo_fd_request(); | ||
| 1290 | |||
| 1291 | schedule_work(&fd1772_tq); | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | |||
| 1295 | static int invalidate_drive(struct block_device *bdev) | ||
| 1296 | { | ||
| 1297 | struct archy_floppy_struct *p = bdev->bd_disk->private_data; | ||
| 1298 | /* invalidate the buffer track to force a reread */ | ||
| 1299 | #ifdef TRACKBUFFER | ||
| 1300 | BufferDrive = -1; | ||
| 1301 | #endif | ||
| 1302 | |||
| 1303 | set_bit(p - unit, &fake_change); | ||
| 1304 | return 0; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | static int fd_ioctl(struct inode *inode, struct file *filp, | ||
| 1308 | unsigned int cmd, unsigned long param) | ||
| 1309 | { | ||
| 1310 | struct block_device *bdev = inode->i_bdev; | ||
| 1311 | |||
| 1312 | switch (cmd) { | ||
| 1313 | case FDFMTEND: | ||
| 1314 | case FDFLUSH: | ||
| 1315 | invalidate_drive(bdev); | ||
| 1316 | check_disk_change(bdev); | ||
| 1317 | case FDFMTBEG: | ||
| 1318 | return 0; | ||
| 1319 | default: | ||
| 1320 | return -EINVAL; | ||
| 1321 | } | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | |||
| 1325 | /* Initialize the 'unit' variable for drive 'drive' */ | ||
| 1326 | |||
| 1327 | static void fd_probe(int drive) | ||
| 1328 | { | ||
| 1329 | unit[drive].connected = 0; | ||
| 1330 | unit[drive].disktype = NULL; | ||
| 1331 | |||
| 1332 | if (!fd_test_drive_present(drive)) | ||
| 1333 | return; | ||
| 1334 | |||
| 1335 | unit[drive].connected = 1; | ||
| 1336 | unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */ | ||
| 1337 | unit[drive].steprate = FDC1772STEP_6; | ||
| 1338 | MotorOn = 1; /* from probe restore operation! */ | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | |||
| 1342 | /* This function tests the physical presence of a floppy drive (not | ||
| 1343 | * whether a disk is inserted). This is done by issuing a restore | ||
| 1344 | * command, waiting max. 2 seconds (that should be enough to move the | ||
| 1345 | * head across the whole disk) and looking at the state of the "TR00" | ||
| 1346 | * signal. This should now be raised if there is a drive connected | ||
| 1347 | * (and there is no hardware failure :-) Otherwise, the drive is | ||
| 1348 | * declared absent. | ||
| 1349 | */ | ||
| 1350 | |||
| 1351 | static int fd_test_drive_present(int drive) | ||
| 1352 | { | ||
| 1353 | unsigned long timeout; | ||
| 1354 | unsigned char status; | ||
| 1355 | int ok; | ||
| 1356 | |||
| 1357 | printk("fd_test_drive_present %d\n", drive); | ||
| 1358 | if (drive > 1) | ||
| 1359 | return (0); | ||
| 1360 | return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */ | ||
| 1361 | fd_select_drive(drive); | ||
| 1362 | |||
| 1363 | /* disable interrupt temporarily */ | ||
| 1364 | DISABLE_IRQ(); | ||
| 1365 | FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */ | ||
| 1366 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6); | ||
| 1367 | |||
| 1368 | /*printk("fd_test_drive_present: Going into timeout loop\n"); */ | ||
| 1369 | for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) { | ||
| 1370 | /* What does this piece of atariism do? - query for an interrupt? */ | ||
| 1371 | /* if (!(mfp.par_dt_reg & 0x20)) | ||
| 1372 | break; */ | ||
| 1373 | /* Well this is my nearest guess - quit when we get an FDC interrupt */ | ||
| 1374 | if (ioc_readb(IOC_FIQSTAT) & 2) | ||
| 1375 | break; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */ | ||
| 1379 | status = FDC1772_READ(FDC1772REG_STATUS); | ||
| 1380 | ok = (status & FDC1772STAT_TR00) != 0; | ||
| 1381 | |||
| 1382 | /*printk("fd_test_drive_present: ok=%d\n",ok); */ | ||
| 1383 | /* force interrupt to abort restore operation (FDC1772 would try | ||
| 1384 | * about 50 seconds!) */ | ||
| 1385 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); | ||
| 1386 | udelay(500); | ||
| 1387 | status = FDC1772_READ(FDC1772REG_STATUS); | ||
| 1388 | udelay(20); | ||
| 1389 | /*printk("fd_test_drive_present: just before OK code %d\n",ok); */ | ||
| 1390 | |||
| 1391 | if (ok) { | ||
| 1392 | /* dummy seek command to make WP bit accessible */ | ||
| 1393 | FDC1772_WRITE(FDC1772REG_DATA, 0); | ||
| 1394 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); | ||
| 1395 | printk("fd_test_drive_present: just before wait for int\n"); | ||
| 1396 | /* DAG: Guess means wait for interrupt */ | ||
| 1397 | while (!(ioc_readb(IOC_FIQSTAT) & 2)); | ||
| 1398 | printk("fd_test_drive_present: just after wait for int\n"); | ||
| 1399 | status = FDC1772_READ(FDC1772REG_STATUS); | ||
| 1400 | } | ||
| 1401 | printk("fd_test_drive_present: just before ENABLE_IRQ\n"); | ||
| 1402 | ENABLE_IRQ(); | ||
| 1403 | printk("fd_test_drive_present: about to return\n"); | ||
| 1404 | return (ok); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | |||
| 1408 | /* Look how many and which kind of drives are connected. If there are | ||
| 1409 | * floppies, additionally start the disk-change and motor-off timers. | ||
| 1410 | */ | ||
| 1411 | |||
| 1412 | static void config_types(void) | ||
| 1413 | { | ||
| 1414 | int drive, cnt = 0; | ||
| 1415 | |||
| 1416 | printk("Probing floppy drive(s):\n"); | ||
| 1417 | for (drive = 0; drive < FD_MAX_UNITS; drive++) { | ||
| 1418 | fd_probe(drive); | ||
| 1419 | if (unit[drive].connected) { | ||
| 1420 | printk("fd%d\n", drive); | ||
| 1421 | ++cnt; | ||
| 1422 | } | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) { | ||
| 1426 | /* If FDC1772 is still busy from probing, give it another FORCI | ||
| 1427 | * command to abort the operation. If this isn't done, the FDC1772 | ||
| 1428 | * will interrupt later and its IRQ line stays low, because | ||
| 1429 | * the status register isn't read. And this will block any | ||
| 1430 | * interrupts on this IRQ line :-( | ||
| 1431 | */ | ||
| 1432 | FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); | ||
| 1433 | udelay(500); | ||
| 1434 | FDC1772_READ(FDC1772REG_STATUS); | ||
| 1435 | udelay(20); | ||
| 1436 | } | ||
| 1437 | if (cnt > 0) { | ||
| 1438 | START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); | ||
| 1439 | if (cnt == 1) | ||
| 1440 | fd_select_drive(0); | ||
| 1441 | /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ | ||
| 1442 | } | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | /* | ||
| 1446 | * floppy_open check for aliasing (/dev/fd0 can be the same as | ||
| 1447 | * /dev/PS0 etc), and disallows simultaneous access to the same | ||
| 1448 | * drive with different device numbers. | ||
| 1449 | */ | ||
| 1450 | |||
| 1451 | static int floppy_open(struct inode *inode, struct file *filp) | ||
| 1452 | { | ||
| 1453 | int drive = iminor(inode) & 3; | ||
| 1454 | int type = iminor(inode) >> 2; | ||
| 1455 | int old_dev = fd_device[drive]; | ||
| 1456 | |||
| 1457 | if (fd_ref[drive] && old_dev != type) | ||
| 1458 | return -EBUSY; | ||
| 1459 | |||
| 1460 | if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) | ||
| 1461 | return -EBUSY; | ||
| 1462 | |||
| 1463 | if (filp->f_flags & O_EXCL) | ||
| 1464 | fd_ref[drive] = -1; | ||
| 1465 | else | ||
| 1466 | fd_ref[drive]++; | ||
| 1467 | |||
| 1468 | fd_device[drive] = type; | ||
| 1469 | |||
| 1470 | if (filp->f_flags & O_NDELAY) | ||
| 1471 | return 0; | ||
| 1472 | |||
| 1473 | if (filp->f_mode & 3) { | ||
| 1474 | check_disk_change(inode->i_bdev); | ||
| 1475 | if (filp->f_mode & 2) { | ||
| 1476 | if (unit[drive].wpstat) { | ||
| 1477 | floppy_release(inode, filp); | ||
| 1478 | return -EROFS; | ||
| 1479 | } | ||
| 1480 | } | ||
| 1481 | } | ||
| 1482 | return 0; | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | |||
| 1486 | static int floppy_release(struct inode *inode, struct file *filp) | ||
| 1487 | { | ||
| 1488 | int drive = iminor(inode) & 3; | ||
| 1489 | |||
| 1490 | if (fd_ref[drive] < 0) | ||
| 1491 | fd_ref[drive] = 0; | ||
| 1492 | else if (!fd_ref[drive]--) { | ||
| 1493 | printk("floppy_release with fd_ref == 0"); | ||
| 1494 | fd_ref[drive] = 0; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | return 0; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | static struct block_device_operations floppy_fops = | ||
| 1501 | { | ||
| 1502 | .open = floppy_open, | ||
| 1503 | .release = floppy_release, | ||
| 1504 | .ioctl = fd_ioctl, | ||
| 1505 | .media_changed = check_floppy_change, | ||
| 1506 | .revalidate_disk= floppy_revalidate, | ||
| 1507 | }; | ||
| 1508 | |||
| 1509 | static struct kobject *floppy_find(dev_t dev, int *part, void *data) | ||
| 1510 | { | ||
| 1511 | int drive = *part & 3; | ||
| 1512 | if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS) | ||
| 1513 | return NULL; | ||
| 1514 | *part = 0; | ||
| 1515 | return get_disk(disks[drive]); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | int fd1772_init(void) | ||
| 1519 | { | ||
| 1520 | static DEFINE_SPINLOCK(lock); | ||
| 1521 | int i, err = -ENOMEM; | ||
| 1522 | |||
| 1523 | if (!machine_is_archimedes()) | ||
| 1524 | return 0; | ||
| 1525 | |||
| 1526 | for (i = 0; i < FD_MAX_UNITS; i++) { | ||
| 1527 | disks[i] = alloc_disk(1); | ||
| 1528 | if (!disks[i]) | ||
| 1529 | goto err_disk; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | err = register_blkdev(MAJOR_NR, "fd"); | ||
| 1533 | if (err) | ||
| 1534 | goto err_disk; | ||
| 1535 | |||
| 1536 | err = -EBUSY; | ||
| 1537 | if (request_dma(FLOPPY_DMA, "fd1772")) { | ||
| 1538 | printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA); | ||
| 1539 | goto err_blkdev; | ||
| 1540 | }; | ||
| 1541 | |||
| 1542 | if (request_dma(FIQ_FD1772, "fd1772 end")) { | ||
| 1543 | printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772); | ||
| 1544 | goto err_dma1; | ||
| 1545 | }; | ||
| 1546 | |||
| 1547 | /* initialize variables */ | ||
| 1548 | SelectedDrive = -1; | ||
| 1549 | #ifdef TRACKBUFFER | ||
| 1550 | BufferDrive = BufferSide = BufferTrack = -1; | ||
| 1551 | /* Atari uses 512 - I want to eventually cope with 1K sectors */ | ||
| 1552 | DMABuffer = kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL); | ||
| 1553 | TrackBuffer = DMABuffer + 512; | ||
| 1554 | #else | ||
| 1555 | /* Allocate memory for the DMAbuffer - on the Atari this takes it | ||
| 1556 | out of some special memory... */ | ||
| 1557 | DMABuffer = kmalloc(2048); /* Copes with pretty large sectors */ | ||
| 1558 | #endif | ||
| 1559 | err = -ENOMEM; | ||
| 1560 | if (!DMAbuffer) | ||
| 1561 | goto err_dma2; | ||
| 1562 | |||
| 1563 | enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */ | ||
| 1564 | |||
| 1565 | floppy_queue = blk_init_queue(do_fd_request, &lock); | ||
| 1566 | if (!floppy_queue) | ||
| 1567 | goto err_queue; | ||
| 1568 | |||
| 1569 | for (i = 0; i < FD_MAX_UNITS; i++) { | ||
| 1570 | unit[i].track = -1; | ||
| 1571 | disks[i]->major = MAJOR_NR; | ||
| 1572 | disks[i]->first_minor = 0; | ||
| 1573 | disks[i]->fops = &floppy_fops; | ||
| 1574 | sprintf(disks[i]->disk_name, "fd%d", i); | ||
| 1575 | disks[i]->private_data = &unit[i]; | ||
| 1576 | disks[i]->queue = floppy_queue; | ||
| 1577 | set_capacity(disks[i], MAX_DISK_SIZE * 2); | ||
| 1578 | } | ||
| 1579 | blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, | ||
| 1580 | floppy_find, NULL, NULL); | ||
| 1581 | |||
| 1582 | for (i = 0; i < FD_MAX_UNITS; i++) | ||
| 1583 | add_disk(disks[i]); | ||
| 1584 | |||
| 1585 | config_types(); | ||
| 1586 | |||
| 1587 | return 0; | ||
| 1588 | |||
| 1589 | err_queue: | ||
| 1590 | kfree(DMAbuffer); | ||
| 1591 | err_dma2: | ||
| 1592 | free_dma(FIQ_FD1772); | ||
| 1593 | |||
| 1594 | err_dma1: | ||
| 1595 | free_dma(FLOPPY_DMA); | ||
| 1596 | |||
| 1597 | err_blkdev: | ||
| 1598 | unregister_blkdev(MAJOR_NR, "fd"); | ||
| 1599 | |||
| 1600 | err_disk: | ||
| 1601 | while (i--) | ||
| 1602 | put_disk(disks[i]); | ||
| 1603 | return err; | ||
| 1604 | } | ||
diff --git a/drivers/acorn/block/fd1772dma.S b/drivers/acorn/block/fd1772dma.S deleted file mode 100644 index 7964435443..0000000000 --- a/drivers/acorn/block/fd1772dma.S +++ /dev/null | |||
| @@ -1,100 +0,0 @@ | |||
| 1 | #include <asm/hardware.h> | ||
| 2 | |||
| 3 | @ Code for DMA with the 1772 fdc | ||
| 4 | .text | ||
| 5 | |||
| 6 | |||
| 7 | .global fdc1772_dataaddr | ||
| 8 | fdc1772_fiqdata: | ||
| 9 | @ Number of bytes left to DMA | ||
| 10 | .global fdc1772_bytestogo | ||
| 11 | fdc1772_bytestogo: | ||
| 12 | .word 0 | ||
| 13 | @ Place to put/get data from in DMA | ||
| 14 | .global fdc1772_dataaddr | ||
| 15 | fdc1772_dataaddr: | ||
| 16 | .word 0 | ||
| 17 | |||
| 18 | .global fdc1772_fdc_int_done | ||
| 19 | fdc1772_fdc_int_done: | ||
| 20 | .word 0 | ||
| 21 | .global fdc1772_comendstatus | ||
| 22 | fdc1772_comendstatus: | ||
| 23 | .word 0 | ||
| 24 | |||
| 25 | @ We hang this off DMA channel 1 | ||
| 26 | .global fdc1772_comendhandler | ||
| 27 | fdc1772_comendhandler: | ||
| 28 | mov r8,#IOC_BASE | ||
| 29 | ldrb r9,[r8,#0x34] @ IOC FIQ status | ||
| 30 | tst r9,#2 | ||
| 31 | subeqs pc,r14,#4 @ should I leave a space here | ||
| 32 | orr r9,r8,#0x10000 @ FDC base | ||
| 33 | adr r8,fdc1772_fdc_int_done | ||
| 34 | ldrb r10,[r9,#0] @ FDC status | ||
| 35 | mov r9,#1 @ Got a FIQ flag | ||
| 36 | stmia r8,{r9,r10} | ||
| 37 | subs pc,r14,#4 | ||
| 38 | |||
| 39 | |||
| 40 | .global fdc1772_dma_read | ||
| 41 | fdc1772_dma_read: | ||
| 42 | mov r8,#IOC_BASE | ||
| 43 | ldrb r9,[r8,#0x34] @ IOC FIQ status | ||
| 44 | tst r9,#1 | ||
| 45 | beq fdc1772_dma_read_notours | ||
| 46 | orr r8,r8,#0x10000 @ FDC base | ||
| 47 | ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt) | ||
| 48 | ldmia r11,{r8,r9} | ||
| 49 | subs r8,r8,#1 @ One less byte to go | ||
| 50 | @ If there was somewhere for this data to go then store it and update pointers | ||
| 51 | strplb r10,[r9],#1 @ Store the data and increment the pointer | ||
| 52 | stmplia r11,{r8,r9} @ Update count/pointers | ||
| 53 | @ Handle any other interrupts if there are any | ||
| 54 | fdc1772_dma_read_notours: | ||
| 55 | @ Cant branch because this code has been copied down to the FIQ vector | ||
| 56 | ldr pc,[pc,#-4] | ||
| 57 | .word fdc1772_comendhandler | ||
| 58 | .global fdc1772_dma_read_end | ||
| 59 | fdc1772_dma_read_end: | ||
| 60 | |||
| 61 | .global fdc1772_dma_write | ||
| 62 | fdc1772_dma_write: | ||
| 63 | mov r8,#IOC_BASE | ||
| 64 | ldrb r9,[r8,#0x34] @ IOC FIQ status | ||
| 65 | tst r9,#1 | ||
| 66 | beq fdc1772_dma_write_notours | ||
| 67 | orr r8,r8,#0x10000 @ FDC base | ||
| 68 | ldmia r11,{r9,r10} | ||
| 69 | subs r9,r9,#1 @ One less byte to go | ||
| 70 | @ If there really is some data then get it, store it and update count | ||
| 71 | ldrplb r12,[r10],#1 | ||
| 72 | strplb r12,[r8,#0xc] @ write it to FDC data reg | ||
| 73 | stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt | ||
| 74 | @ Handle any other interrupts | ||
| 75 | fdc1772_dma_write_notours: | ||
| 76 | @ Cant branch because this code has been copied down to the FIQ vector | ||
| 77 | ldr pc,[pc,#-4] | ||
| 78 | .word fdc1772_comendhandler | ||
| 79 | |||
| 80 | .global fdc1772_dma_write_end | ||
| 81 | fdc1772_dma_write_end: | ||
| 82 | |||
| 83 | |||
| 84 | @ Setup the FIQ R11 to point to the data and store the count, address | ||
| 85 | @ for this dma | ||
| 86 | @ R0=count | ||
| 87 | @ R1=address | ||
| 88 | .global fdc1772_setupdma | ||
| 89 | fdc1772_setupdma: | ||
| 90 | @ The big job is flipping in and out of FIQ mode | ||
| 91 | adr r2,fdc1772_fiqdata @ This is what we really came here for | ||
| 92 | stmia r2,{r0,r1} | ||
| 93 | mov r3, pc | ||
| 94 | teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode | ||
| 95 | mov r0,r0 @ NOP | ||
| 96 | mov r11,r2 | ||
| 97 | teqp r3,#0 @ Normal mode | ||
| 98 | mov r0,r0 @ NOP | ||
| 99 | mov pc,r14 | ||
| 100 | |||
diff --git a/drivers/acorn/block/mfm.S b/drivers/acorn/block/mfm.S deleted file mode 100644 index c90cbd41ce..0000000000 --- a/drivers/acorn/block/mfm.S +++ /dev/null | |||
| @@ -1,162 +0,0 @@ | |||
| 1 | @ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes | ||
| 2 | @ motherboard and on ST506 expansion podules. | ||
| 3 | @ (c) David Alan Gilbert (linux@treblig.org) 1996-1999 | ||
| 4 | |||
| 5 | #include <asm/assembler.h> | ||
| 6 | |||
| 7 | hdc63463_irqdata: | ||
| 8 | @ Controller base address | ||
| 9 | .global hdc63463_baseaddress | ||
| 10 | hdc63463_baseaddress: | ||
| 11 | .word 0 | ||
| 12 | |||
| 13 | .global hdc63463_irqpolladdress | ||
| 14 | hdc63463_irqpolladdress: | ||
| 15 | .word 0 | ||
| 16 | |||
| 17 | .global hdc63463_irqpollmask | ||
| 18 | hdc63463_irqpollmask: | ||
| 19 | .word 0 | ||
| 20 | |||
| 21 | @ where to read/write data from the kernel data space | ||
| 22 | .global hdc63463_dataptr | ||
| 23 | hdc63463_dataptr: | ||
| 24 | .word 0 | ||
| 25 | |||
| 26 | @ Number of bytes left to transfer | ||
| 27 | .global hdc63463_dataleft | ||
| 28 | hdc63463_dataleft: | ||
| 29 | .word 0 | ||
| 30 | |||
| 31 | @ ------------------------------------------------------------------------- | ||
| 32 | @ hdc63463_writedma: DMA from host to controller | ||
| 33 | @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask | ||
| 34 | @ r3=data ptr, r4=data left, r5,r6=temporary | ||
| 35 | .global hdc63463_writedma | ||
| 36 | hdc63463_writedma: | ||
| 37 | stmfd sp!,{r4-r7} | ||
| 38 | adr r5,hdc63463_irqdata | ||
| 39 | ldmia r5,{r0,r1,r2,r3,r4} | ||
| 40 | |||
| 41 | writedma_again: | ||
| 42 | |||
| 43 | @ test number of remaining bytes to transfer | ||
| 44 | cmp r4,#0 | ||
| 45 | beq writedma_end | ||
| 46 | bmi writedma_end | ||
| 47 | |||
| 48 | @ Check the hdc is interrupting | ||
| 49 | ldrb r5,[r1,#0] | ||
| 50 | tst r5,r2 | ||
| 51 | beq writedma_end | ||
| 52 | |||
| 53 | @ Transfer a block of upto 256 bytes | ||
| 54 | cmp r4,#256 | ||
| 55 | movlt r7,r4 | ||
| 56 | movge r7,#256 | ||
| 57 | |||
| 58 | @ Check the hdc is still busy and command has not ended and no errors | ||
| 59 | ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status | ||
| 60 | @ think we should continue DMA until it drops busy - perhaps this was | ||
| 61 | @ the main problem with corrected errors causing a hang | ||
| 62 | @tst r5,#0x3c00 @ Test for things which should be off | ||
| 63 | @bne writedma_end | ||
| 64 | and r5,r5,#0x8000 @ This is test for things which should be on: Busy | ||
| 65 | cmp r5,#0x8000 | ||
| 66 | bne writedma_end | ||
| 67 | |||
| 68 | @ Bytes remaining at end | ||
| 69 | sub r4,r4,r7 | ||
| 70 | |||
| 71 | @ HDC Write register location | ||
| 72 | add r0,r0,#32+8 | ||
| 73 | |||
| 74 | writedma_loop: | ||
| 75 | @ OK - pretty sure we should be doing this | ||
| 76 | |||
| 77 | ldr r5,[r3],#4 @ Get a word to be written | ||
| 78 | @ get bottom half to be sent first | ||
| 79 | mov r6,r5,lsl#16 @ Separate the first 2 bytes | ||
| 80 | orr r2,r6,r6,lsr #16 @ Duplicate them in the bottom half of the word | ||
| 81 | @ now the top half | ||
| 82 | mov r6,r5,lsr#16 @ Get 2nd 2 bytes | ||
| 83 | orr r6,r6,r6,lsl#16 @ Duplicate | ||
| 84 | @str r6,[r0] @ to hdc | ||
| 85 | stmia r0,{r2,r6} | ||
| 86 | subs r7,r7,#4 @ Dec. number of bytes left | ||
| 87 | bne writedma_loop | ||
| 88 | |||
| 89 | @ If we were too slow we had better go through again - DAG - took out with new interrupt routine | ||
| 90 | @ sub r0,r0,#32+8 | ||
| 91 | @ adr r2,hdc63463_irqdata | ||
| 92 | @ ldr r2,[r2,#8] | ||
| 93 | @ b writedma_again | ||
| 94 | |||
| 95 | writedma_end: | ||
| 96 | adr r5,hdc63463_irqdata+12 | ||
| 97 | stmia r5,{r3,r4} | ||
| 98 | ldmfd sp!,{r4-r7} | ||
| 99 | RETINSTR(mov,pc,lr) | ||
| 100 | |||
| 101 | @ ------------------------------------------------------------------------- | ||
| 102 | @ hdc63463_readdma: DMA from controller to host | ||
| 103 | @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask | ||
| 104 | @ r3=data ptr, r4=data left, r5,r6=temporary | ||
| 105 | .global hdc63463_readdma | ||
| 106 | hdc63463_readdma: | ||
| 107 | stmfd sp!,{r4-r7} | ||
| 108 | adr r5,hdc63463_irqdata | ||
| 109 | ldmia r5,{r0,r1,r2,r3,r4} | ||
| 110 | |||
| 111 | readdma_again: | ||
| 112 | @ test number of remaining bytes to transfer | ||
| 113 | cmp r4,#0 | ||
| 114 | beq readdma_end | ||
| 115 | bmi readdma_end | ||
| 116 | |||
| 117 | @ Check the hdc is interrupting | ||
| 118 | ldrb r5,[r1,#0] | ||
| 119 | tst r5,r2 | ||
| 120 | beq readdma_end | ||
| 121 | |||
| 122 | @ Check the hdc is still busy and command has not ended and no errors | ||
| 123 | ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status | ||
| 124 | @ think we should continue DMA until it drops busy - perhaps this was | ||
| 125 | @ the main problem with corrected errors causing a hang | ||
| 126 | @tst r5,#0x3c00 @ Test for things which should be off | ||
| 127 | @bne readdma_end | ||
| 128 | and r5,r5,#0x8000 @ This is test for things which should be on: Busy | ||
| 129 | cmp r5,#0x8000 | ||
| 130 | bne readdma_end | ||
| 131 | |||
| 132 | @ Transfer a block of upto 256 bytes | ||
| 133 | cmp r4,#256 | ||
| 134 | movlt r7,r4 | ||
| 135 | movge r7,#256 | ||
| 136 | |||
| 137 | @ Bytes remaining at end | ||
| 138 | sub r4,r4,r7 | ||
| 139 | |||
| 140 | @ Set a pointer to the data register in the HDC | ||
| 141 | add r0,r0,#8 | ||
| 142 | readdma_loop: | ||
| 143 | @ OK - pretty sure we should be doing this | ||
| 144 | ldmia r0,{r5,r6} | ||
| 145 | mov r5,r5,lsl#16 | ||
| 146 | mov r6,r6,lsl#16 | ||
| 147 | orr r6,r6,r5,lsr #16 | ||
| 148 | str r6,[r3],#4 | ||
| 149 | subs r7,r7,#4 @ Decrement bytes to go | ||
| 150 | bne readdma_loop | ||
| 151 | |||
| 152 | @ Try reading multiple blocks - if this was fast enough then I do not think | ||
| 153 | @ this should help - NO taken out DAG - new interrupt handler has | ||
| 154 | @ non-consecutive memory blocks | ||
| 155 | @ sub r0,r0,#8 | ||
| 156 | @ b readdma_again | ||
| 157 | |||
| 158 | readdma_end: | ||
| 159 | adr r5,hdc63463_irqdata+12 | ||
| 160 | stmia r5,{r3,r4} | ||
| 161 | ldmfd sp!,{r4-r7} | ||
| 162 | RETINSTR(mov,pc,lr) | ||
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c deleted file mode 100644 index 74058db674..0000000000 --- a/drivers/acorn/block/mfmhd.c +++ /dev/null | |||
| @@ -1,1385 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/acorn/block/mfmhd.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk) | ||
| 5 | * | ||
| 6 | * MFM hard drive code [experimental] | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * Change list: | ||
| 11 | * | ||
| 12 | * 3/2/96:DAG: Started a change list :-) | ||
| 13 | * Set the hardsect_size pointers up since we are running 256 byte | ||
| 14 | * sectors | ||
| 15 | * Added DMA code, put it into the rw_intr | ||
| 16 | * Moved RCAL out of generic interrupt code - don't want to do it | ||
| 17 | * while DMA'ing - its now in individual handlers. | ||
| 18 | * Took interrupt handlers off task queue lists and called | ||
| 19 | * directly - not sure of implications. | ||
| 20 | * | ||
| 21 | * 18/2/96:DAG: Well its reading OK I think, well enough for image file code | ||
| 22 | * to find the image file; but now I've discovered that I actually | ||
| 23 | * have to put some code in for image files. | ||
| 24 | * | ||
| 25 | * Added stuff for image files; seems to work, but I've not | ||
| 26 | * got a multisegment image file (I don't think!). | ||
| 27 | * Put in a hack (yep a real hack) for multiple cylinder reads. | ||
| 28 | * Not convinced its working. | ||
| 29 | * | ||
| 30 | * 5/4/96:DAG: Added asm/hardware.h and use IOC_ macros | ||
| 31 | * Rewrote dma code in mfm.S (again!) - now takes a word at a time | ||
| 32 | * from main RAM for speed; still doesn't feel speedy! | ||
| 33 | * | ||
| 34 | * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding | ||
| 35 | * things up, I've finally figured out why its so damn slow. | ||
| 36 | * Linux is only reading a block at a time, and so you never | ||
| 37 | * get more than 1K per disc revoloution ~=60K/second. | ||
| 38 | * | ||
| 39 | * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to | ||
| 40 | * join adjacent blocks together. Everything falls flat on its | ||
| 41 | * face. | ||
| 42 | * Four hours of debugging later; I hadn't realised that | ||
| 43 | * ll_rw_blk would be so generous as to join blocks whose | ||
| 44 | * results aren't going into consecutive buffers. | ||
| 45 | * | ||
| 46 | * OK; severe rehacking of mfm_rw_interrupt; now end_request's | ||
| 47 | * as soon as its DMA'd each request. Odd thing is that | ||
| 48 | * we are sometimes getting interrupts where we are not transferring | ||
| 49 | * any data; why? Is that what happens when you miss? I doubt | ||
| 50 | * it; are we too fast? No - its just at command ends. Got 240K/s | ||
| 51 | * better than before, but RiscOS hits 480K/s | ||
| 52 | * | ||
| 53 | * 25/6/96:RMK: Fixed init code to allow the MFM podule to work. Increased the | ||
| 54 | * number of errors for my Miniscribe drive (8425). | ||
| 55 | * | ||
| 56 | * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off | ||
| 57 | * - so in request_done just before it clears Busy it sends a | ||
| 58 | * check drive 0 - and the LEDs go off!!!! | ||
| 59 | * | ||
| 60 | * Added test for mainboard controller. - Removes need for separate | ||
| 61 | * define. | ||
| 62 | * | ||
| 63 | * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make | ||
| 64 | * IM drivers work. | ||
| 65 | * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO | ||
| 66 | * error.) | ||
| 67 | * | ||
| 68 | * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents | ||
| 69 | * gone :-( Hand modified afterwards. | ||
| 70 | * Took out last remains of the older image map system. | ||
| 71 | * | ||
| 72 | * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped | ||
| 73 | * Changed mfm_rw_intr so that it doesn't follow the error | ||
| 74 | * code until BSY is dropped. Nope - still broke. Problem | ||
| 75 | * may revolve around when it reads the results for the error | ||
| 76 | * number? | ||
| 77 | * | ||
| 78 | *16/11/96:DAG: Modified for 2.0.18; request_irq changed | ||
| 79 | * | ||
| 80 | *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system. | ||
| 81 | * Improved probe for onboard MFM chip - it was hanging on my A5k. | ||
| 82 | * Added autodetect CHS code such that we don't rely on the presence | ||
| 83 | * of an ADFS boot block. Added ioport resource manager calls so | ||
| 84 | * that we don't clash with already-running hardware (eg. RiscPC Ether | ||
| 85 | * card slots if someone tries this)! | ||
| 86 | * | ||
| 87 | * 17/1/97:RMK: Upgraded to 2.1 kernels. | ||
| 88 | * | ||
| 89 | * 4/3/98:RMK: Changed major number to 21. | ||
| 90 | * | ||
| 91 | * 27/6/98:RMK: Changed asm/delay.h to linux/delay.h for mdelay(). | ||
| 92 | */ | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Possible enhancements: | ||
| 96 | * Multi-thread the code so that it is possible that while one drive | ||
| 97 | * is seeking, the other one can be reading data/seeking as well. | ||
| 98 | * This would be a performance boost with dual drive systems. | ||
| 99 | */ | ||
| 100 | |||
| 101 | #include <linux/module.h> | ||
| 102 | #include <linux/fs.h> | ||
| 103 | #include <linux/interrupt.h> | ||
| 104 | #include <linux/kernel.h> | ||
| 105 | #include <linux/timer.h> | ||
| 106 | #include <linux/mm.h> | ||
| 107 | #include <linux/errno.h> | ||
| 108 | #include <linux/genhd.h> | ||
| 109 | #include <linux/major.h> | ||
| 110 | #include <linux/ioport.h> | ||
| 111 | #include <linux/delay.h> | ||
| 112 | #include <linux/blkpg.h> | ||
| 113 | |||
| 114 | #include <asm/system.h> | ||
| 115 | #include <asm/io.h> | ||
| 116 | #include <asm/irq.h> | ||
| 117 | #include <asm/uaccess.h> | ||
| 118 | #include <asm/dma.h> | ||
| 119 | #include <asm/hardware.h> | ||
| 120 | #include <asm/ecard.h> | ||
| 121 | #include <asm/hardware/ioc.h> | ||
| 122 | |||
| 123 | static void (*do_mfm)(void) = NULL; | ||
| 124 | static struct request_queue *mfm_queue; | ||
| 125 | static DEFINE_SPINLOCK(mfm_lock); | ||
| 126 | |||
| 127 | #define MAJOR_NR MFM_ACORN_MAJOR | ||
| 128 | #define QUEUE (mfm_queue) | ||
| 129 | #define CURRENT elv_next_request(mfm_queue) | ||
| 130 | |||
| 131 | /* | ||
| 132 | * Configuration section | ||
| 133 | * | ||
| 134 | * This is the maximum number of drives that we accept | ||
| 135 | */ | ||
| 136 | #define MFM_MAXDRIVES 2 | ||
| 137 | /* | ||
| 138 | * Linux I/O address of onboard MFM controller or 0 to disable this | ||
| 139 | */ | ||
| 140 | #define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000) | ||
| 141 | /* | ||
| 142 | * Uncomment this to enable debugging in the MFM driver... | ||
| 143 | */ | ||
| 144 | #ifndef DEBUG | ||
| 145 | /*#define DEBUG */ | ||
| 146 | #endif | ||
| 147 | /* | ||
| 148 | * End of configuration | ||
| 149 | */ | ||
| 150 | |||
| 151 | |||
| 152 | /* | ||
| 153 | * This structure contains all information to do with a particular physical | ||
| 154 | * device. | ||
| 155 | */ | ||
| 156 | struct mfm_info { | ||
| 157 | unsigned char sectors; | ||
| 158 | unsigned char heads; | ||
| 159 | unsigned short cylinders; | ||
| 160 | unsigned short lowcurrent; | ||
| 161 | unsigned short precomp; | ||
| 162 | #define NO_TRACK -1 | ||
| 163 | #define NEED_1_RECAL -2 | ||
| 164 | #define NEED_2_RECAL -3 | ||
| 165 | int cylinder; | ||
| 166 | struct { | ||
| 167 | char recal; | ||
| 168 | char report; | ||
| 169 | char abort; | ||
| 170 | } errors; | ||
| 171 | } mfm_info[MFM_MAXDRIVES]; | ||
| 172 | |||
| 173 | #define MFM_DRV_INFO mfm_info[raw_cmd.dev] | ||
| 174 | |||
| 175 | /* Stuff from the assembly routines */ | ||
| 176 | extern unsigned int hdc63463_baseaddress; /* Controller base address */ | ||
| 177 | extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */ | ||
| 178 | extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */ | ||
| 179 | extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */ | ||
| 180 | extern int hdc63463_dataleft; /* Number of bytes left to transfer */ | ||
| 181 | |||
| 182 | |||
| 183 | |||
| 184 | |||
| 185 | static int lastspecifieddrive; | ||
| 186 | static unsigned Busy; | ||
| 187 | |||
| 188 | static unsigned int PartFragRead; /* The number of sectors which have been read | ||
| 189 | during a partial read split over two | ||
| 190 | cylinders. If 0 it means a partial | ||
| 191 | read did not occur. */ | ||
| 192 | |||
| 193 | static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */ | ||
| 194 | static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */ | ||
| 195 | |||
| 196 | static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */ | ||
| 197 | static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */ | ||
| 198 | static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know | ||
| 199 | where to take over */ | ||
| 200 | static char *Copy_buffer; | ||
| 201 | |||
| 202 | |||
| 203 | static void mfm_seek(void); | ||
| 204 | static void mfm_rerequest(void); | ||
| 205 | static void mfm_request(void); | ||
| 206 | static void mfm_specify (void); | ||
| 207 | static void issue_request(unsigned int block, unsigned int nsect, | ||
| 208 | struct request *req); | ||
| 209 | |||
| 210 | static unsigned int mfm_addr; /* Controller address */ | ||
| 211 | static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */ | ||
| 212 | static unsigned int mfm_irqenable; /* Podule IRQ enable location */ | ||
| 213 | static unsigned char mfm_irq; /* Interrupt number */ | ||
| 214 | static int mfm_drives = 0; /* drives available */ | ||
| 215 | static int mfm_status = 0; /* interrupt status */ | ||
| 216 | static int *errors; | ||
| 217 | |||
| 218 | static struct rawcmd { | ||
| 219 | unsigned int dev; | ||
| 220 | unsigned int cylinder; | ||
| 221 | unsigned int head; | ||
| 222 | unsigned int sector; | ||
| 223 | unsigned int cmdtype; | ||
| 224 | unsigned int cmdcode; | ||
| 225 | unsigned char cmddata[16]; | ||
| 226 | unsigned int cmdlen; | ||
| 227 | } raw_cmd; | ||
| 228 | |||
| 229 | static unsigned char result[16]; | ||
| 230 | |||
| 231 | static struct cont { | ||
| 232 | void (*interrupt) (void); /* interrupt handler */ | ||
| 233 | void (*error) (void); /* error handler */ | ||
| 234 | void (*redo) (void); /* redo handler */ | ||
| 235 | void (*done) (int st); /* done handler */ | ||
| 236 | } *cont = NULL; | ||
| 237 | |||
| 238 | #if 0 | ||
| 239 | static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0}; | ||
| 240 | #endif | ||
| 241 | |||
| 242 | int number_mfm_drives = 1; | ||
| 243 | |||
| 244 | /* ------------------------------------------------------------------------------------------ */ | ||
| 245 | /* | ||
| 246 | * From the HD63463 data sheet from Hitachi Ltd. | ||
| 247 | */ | ||
| 248 | |||
| 249 | #define MFM_COMMAND (mfm_addr + 0) | ||
| 250 | #define MFM_DATAOUT (mfm_addr + 1) | ||
| 251 | #define MFM_STATUS (mfm_addr + 8) | ||
| 252 | #define MFM_DATAIN (mfm_addr + 9) | ||
| 253 | |||
| 254 | #define CMD_ABT 0xF0 /* Abort */ | ||
| 255 | #define CMD_SPC 0xE8 /* Specify */ | ||
| 256 | #define CMD_TST 0xE0 /* Test */ | ||
| 257 | #define CMD_RCLB 0xC8 /* Recalibrate */ | ||
| 258 | #define CMD_SEK 0xC0 /* Seek */ | ||
| 259 | #define CMD_WFS 0xAB /* Write Format Skew */ | ||
| 260 | #define CMD_WFM 0xA3 /* Write Format */ | ||
| 261 | #define CMD_MTB 0x90 /* Memory to buffer */ | ||
| 262 | #define CMD_CMPD 0x88 /* Compare data */ | ||
| 263 | #define CMD_WD 0x87 /* Write data */ | ||
| 264 | #define CMD_RED 0x70 /* Read erroneous data */ | ||
| 265 | #define CMD_RIS 0x68 /* Read ID skew */ | ||
| 266 | #define CMD_FID 0x61 /* Find ID */ | ||
| 267 | #define CMD_RID 0x60 /* Read ID */ | ||
| 268 | #define CMD_BTM 0x50 /* Buffer to memory */ | ||
| 269 | #define CMD_CKD 0x48 /* Check data */ | ||
| 270 | #define CMD_RD 0x40 /* Read data */ | ||
| 271 | #define CMD_OPBW 0x38 /* Open buffer write */ | ||
| 272 | #define CMD_OPBR 0x30 /* Open buffer read */ | ||
| 273 | #define CMD_CKV 0x28 /* Check drive */ | ||
| 274 | #define CMD_CKE 0x20 /* Check ECC */ | ||
| 275 | #define CMD_POD 0x18 /* Polling disable */ | ||
| 276 | #define CMD_POL 0x10 /* Polling enable */ | ||
| 277 | #define CMD_RCAL 0x08 /* Recall */ | ||
| 278 | |||
| 279 | #define STAT_BSY 0x8000 /* Busy */ | ||
| 280 | #define STAT_CPR 0x4000 /* Command Parameter Rejection */ | ||
| 281 | #define STAT_CED 0x2000 /* Command end */ | ||
| 282 | #define STAT_SED 0x1000 /* Seek end */ | ||
| 283 | #define STAT_DER 0x0800 /* Drive error */ | ||
| 284 | #define STAT_ABN 0x0400 /* Abnormal end */ | ||
| 285 | #define STAT_POL 0x0200 /* Polling */ | ||
| 286 | |||
| 287 | /* ------------------------------------------------------------------------------------------ */ | ||
| 288 | #ifdef DEBUG | ||
| 289 | static void console_printf(const char *fmt,...) | ||
| 290 | { | ||
| 291 | static char buffer[2048]; /* Arbitary! */ | ||
| 292 | extern void console_print(const char *); | ||
| 293 | unsigned long flags; | ||
| 294 | va_list ap; | ||
| 295 | |||
| 296 | local_irq_save(flags); | ||
| 297 | |||
| 298 | va_start(ap, fmt); | ||
| 299 | vsprintf(buffer, fmt, ap); | ||
| 300 | console_print(buffer); | ||
| 301 | va_end(fmt); | ||
| 302 | |||
| 303 | local_irq_restore(flags); | ||
| 304 | }; /* console_printf */ | ||
| 305 | |||
| 306 | #define DBG(x...) console_printf(x) | ||
| 307 | #else | ||
| 308 | #define DBG(x...) | ||
| 309 | #endif | ||
| 310 | |||
| 311 | static void print_status(void) | ||
| 312 | { | ||
| 313 | char *error; | ||
| 314 | static char *errors[] = { | ||
| 315 | "no error", | ||
| 316 | "command aborted", | ||
| 317 | "invalid command", | ||
| 318 | "parameter error", | ||
| 319 | "not initialised", | ||
| 320 | "rejected TEST", | ||
| 321 | "no useld", | ||
| 322 | "write fault", | ||
| 323 | "not ready", | ||
| 324 | "no scp", | ||
| 325 | "in seek", | ||
| 326 | "invalid NCA", | ||
| 327 | "invalid step rate", | ||
| 328 | "seek error", | ||
| 329 | "over run", | ||
| 330 | "invalid PHA", | ||
| 331 | "data field EEC error", | ||
| 332 | "data field CRC error", | ||
| 333 | "error corrected", | ||
| 334 | "data field fatal error", | ||
| 335 | "no data am", | ||
| 336 | "not hit", | ||
| 337 | "ID field CRC error", | ||
| 338 | "time over", | ||
| 339 | "no ID am", | ||
| 340 | "not writable" | ||
| 341 | }; | ||
| 342 | if (result[1] < 0x65) | ||
| 343 | error = errors[result[1] >> 2]; | ||
| 344 | else | ||
| 345 | error = "unknown"; | ||
| 346 | printk("("); | ||
| 347 | if (mfm_status & STAT_BSY) printk("BSY "); | ||
| 348 | if (mfm_status & STAT_CPR) printk("CPR "); | ||
| 349 | if (mfm_status & STAT_CED) printk("CED "); | ||
| 350 | if (mfm_status & STAT_SED) printk("SED "); | ||
| 351 | if (mfm_status & STAT_DER) printk("DER "); | ||
| 352 | if (mfm_status & STAT_ABN) printk("ABN "); | ||
| 353 | if (mfm_status & STAT_POL) printk("POL "); | ||
| 354 | printk(") SSB = %X (%s)\n", result[1], error); | ||
| 355 | |||
| 356 | } | ||
| 357 | |||
| 358 | /* ------------------------------------------------------------------------------------- */ | ||
| 359 | |||
| 360 | static void issue_command(int command, unsigned char *cmdb, int len) | ||
| 361 | { | ||
| 362 | int status; | ||
| 363 | #ifdef DEBUG | ||
| 364 | int i; | ||
| 365 | console_printf("issue_command: %02X: ", command); | ||
| 366 | for (i = 0; i < len; i++) | ||
| 367 | console_printf("%02X ", cmdb[i]); | ||
| 368 | console_printf("\n"); | ||
| 369 | #endif | ||
| 370 | |||
| 371 | do { | ||
| 372 | status = inw(MFM_STATUS); | ||
| 373 | } while (status & (STAT_BSY | STAT_POL)); | ||
| 374 | DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8); | ||
| 375 | |||
| 376 | if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) { | ||
| 377 | outw(CMD_RCAL, MFM_COMMAND); | ||
| 378 | while (inw(MFM_STATUS) & STAT_BSY); | ||
| 379 | } | ||
| 380 | status = inw(MFM_STATUS); | ||
| 381 | DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8); | ||
| 382 | |||
| 383 | while (len > 0) { | ||
| 384 | outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT); | ||
| 385 | len -= 2; | ||
| 386 | cmdb += 2; | ||
| 387 | } | ||
| 388 | status = inw(MFM_STATUS); | ||
| 389 | DBG("issue_command: status before command issue: %02X:\n ", status >> 8); | ||
| 390 | |||
| 391 | outw(command, MFM_COMMAND); | ||
| 392 | status = inw(MFM_STATUS); | ||
| 393 | DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8); | ||
| 394 | } | ||
| 395 | |||
| 396 | static void wait_for_completion(void) | ||
| 397 | { | ||
| 398 | while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY); | ||
| 399 | } | ||
| 400 | |||
| 401 | static void wait_for_command_end(void) | ||
| 402 | { | ||
| 403 | int i; | ||
| 404 | |||
| 405 | while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED)); | ||
| 406 | |||
| 407 | for (i = 0; i < 16;) { | ||
| 408 | int in; | ||
| 409 | in = inw(MFM_DATAIN); | ||
| 410 | result[i++] = in >> 8; | ||
| 411 | result[i++] = in; | ||
| 412 | } | ||
| 413 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 414 | } | ||
| 415 | |||
| 416 | /* ------------------------------------------------------------------------------------- */ | ||
| 417 | |||
| 418 | static void mfm_rw_intr(void) | ||
| 419 | { | ||
| 420 | int old_status; /* Holds status on entry, we read to see if the command just finished */ | ||
| 421 | #ifdef DEBUG | ||
| 422 | console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft); | ||
| 423 | print_status(); | ||
| 424 | #endif | ||
| 425 | |||
| 426 | /* Now don't handle the error until BSY drops */ | ||
| 427 | if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) { | ||
| 428 | /* Something has gone wrong - let's try that again */ | ||
| 429 | outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ | ||
| 430 | if (cont) { | ||
| 431 | DBG("mfm_rw_intr: DER/ABN err\n"); | ||
| 432 | cont->error(); | ||
| 433 | cont->redo(); | ||
| 434 | }; | ||
| 435 | return; | ||
| 436 | }; | ||
| 437 | |||
| 438 | /* OK so what ever happened it's not an error, now I reckon we are left between | ||
| 439 | a choice of command end or some data which is ready to be collected */ | ||
| 440 | /* I think we have to transfer data while the interrupt line is on and its | ||
| 441 | not any other type of interrupt */ | ||
| 442 | if (rq_data_dir(CURRENT) == WRITE) { | ||
| 443 | extern void hdc63463_writedma(void); | ||
| 444 | if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { | ||
| 445 | printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); | ||
| 446 | if (cont) { | ||
| 447 | cont->error(); | ||
| 448 | cont->redo(); | ||
| 449 | }; | ||
| 450 | return; | ||
| 451 | }; | ||
| 452 | hdc63463_writedma(); | ||
| 453 | } else { | ||
| 454 | extern void hdc63463_readdma(void); | ||
| 455 | if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { | ||
| 456 | printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n"); | ||
| 457 | if (cont) { | ||
| 458 | cont->error(); | ||
| 459 | cont->redo(); | ||
| 460 | }; | ||
| 461 | return; | ||
| 462 | }; | ||
| 463 | DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr); | ||
| 464 | hdc63463_readdma(); | ||
| 465 | }; /* Read */ | ||
| 466 | |||
| 467 | if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) { | ||
| 468 | /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */ | ||
| 469 | /* Ah - well looking at the status its just when we get command end; so no problem */ | ||
| 470 | /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n", | ||
| 471 | hdc63463_dataptr,Copy_buffer+256); | ||
| 472 | print_status(); */ | ||
| 473 | } else { | ||
| 474 | Sectors256LeftInCurrent--; | ||
| 475 | Copy_buffer += 256; | ||
| 476 | Copy_Sector++; | ||
| 477 | |||
| 478 | /* We have come to the end of this request */ | ||
| 479 | if (!Sectors256LeftInCurrent) { | ||
| 480 | DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n", | ||
| 481 | CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors); | ||
| 482 | |||
| 483 | CURRENT->nr_sectors -= CURRENT->current_nr_sectors; | ||
| 484 | CURRENT->sector += CURRENT->current_nr_sectors; | ||
| 485 | SectorsLeftInRequest -= CURRENT->current_nr_sectors; | ||
| 486 | |||
| 487 | end_request(CURRENT, 1); | ||
| 488 | if (SectorsLeftInRequest) { | ||
| 489 | hdc63463_dataptr = (unsigned int) CURRENT->buffer; | ||
| 490 | Copy_buffer = CURRENT->buffer; | ||
| 491 | Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; | ||
| 492 | errors = &(CURRENT->errors); | ||
| 493 | /* These should match the present calculations of the next logical sector | ||
| 494 | on the device | ||
| 495 | Copy_Sector=CURRENT->sector*2; */ | ||
| 496 | |||
| 497 | if (Copy_Sector != CURRENT->sector * 2) | ||
| 498 | #ifdef DEBUG | ||
| 499 | /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n", | ||
| 500 | Copy_Sector, CURRENT->sector * 2); | ||
| 501 | #else | ||
| 502 | printk("mfm: Copy_Sector mismatch! Eek!\n"); | ||
| 503 | #endif | ||
| 504 | }; /* CURRENT */ | ||
| 505 | }; /* Sectors256LeftInCurrent */ | ||
| 506 | }; | ||
| 507 | |||
| 508 | old_status = mfm_status; | ||
| 509 | mfm_status = inw(MFM_STATUS); | ||
| 510 | if (mfm_status & (STAT_DER | STAT_ABN)) { | ||
| 511 | /* Something has gone wrong - let's try that again */ | ||
| 512 | if (cont) { | ||
| 513 | DBG("mfm_rw_intr: DER/ABN error\n"); | ||
| 514 | cont->error(); | ||
| 515 | cont->redo(); | ||
| 516 | }; | ||
| 517 | return; | ||
| 518 | }; | ||
| 519 | |||
| 520 | /* If this code wasn't entered due to command_end but there is | ||
| 521 | now a command end we must read the command results out. If it was | ||
| 522 | entered like this then mfm_interrupt_handler would have done the | ||
| 523 | job. */ | ||
| 524 | if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) && | ||
| 525 | ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) { | ||
| 526 | int len = 0; | ||
| 527 | while (len < 16) { | ||
| 528 | int in; | ||
| 529 | in = inw(MFM_DATAIN); | ||
| 530 | result[len++] = in >> 8; | ||
| 531 | result[len++] = in; | ||
| 532 | }; | ||
| 533 | }; /* Result read */ | ||
| 534 | |||
| 535 | /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */ | ||
| 536 | |||
| 537 | /* If end of command move on */ | ||
| 538 | if (mfm_status & (STAT_CED)) { | ||
| 539 | outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ | ||
| 540 | /* End of command - trigger the next command */ | ||
| 541 | if (cont) { | ||
| 542 | cont->done(1); | ||
| 543 | } | ||
| 544 | DBG("mfm_rw_intr: returned from cont->done\n"); | ||
| 545 | } else { | ||
| 546 | /* Its going to generate another interrupt */ | ||
| 547 | do_mfm = mfm_rw_intr; | ||
| 548 | }; | ||
| 549 | } | ||
| 550 | |||
| 551 | static void mfm_setup_rw(void) | ||
| 552 | { | ||
| 553 | DBG("setting up for rw...\n"); | ||
| 554 | |||
| 555 | do_mfm = mfm_rw_intr; | ||
| 556 | issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen); | ||
| 557 | } | ||
| 558 | |||
| 559 | static void mfm_recal_intr(void) | ||
| 560 | { | ||
| 561 | #ifdef DEBUG | ||
| 562 | console_printf("recal intr - status = "); | ||
| 563 | print_status(); | ||
| 564 | #endif | ||
| 565 | outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ | ||
| 566 | if (mfm_status & (STAT_DER | STAT_ABN)) { | ||
| 567 | printk("recal failed\n"); | ||
| 568 | MFM_DRV_INFO.cylinder = NEED_2_RECAL; | ||
| 569 | if (cont) { | ||
| 570 | cont->error(); | ||
| 571 | cont->redo(); | ||
| 572 | } | ||
| 573 | return; | ||
| 574 | } | ||
| 575 | /* Thats seek end - we are finished */ | ||
| 576 | if (mfm_status & STAT_SED) { | ||
| 577 | issue_command(CMD_POD, NULL, 0); | ||
| 578 | MFM_DRV_INFO.cylinder = 0; | ||
| 579 | mfm_seek(); | ||
| 580 | return; | ||
| 581 | } | ||
| 582 | /* Command end without seek end (see data sheet p.20) for parallel seek | ||
| 583 | - we have to send a POL command to wait for the seek */ | ||
| 584 | if (mfm_status & STAT_CED) { | ||
| 585 | do_mfm = mfm_recal_intr; | ||
| 586 | issue_command(CMD_POL, NULL, 0); | ||
| 587 | return; | ||
| 588 | } | ||
| 589 | printk("recal: unknown status\n"); | ||
| 590 | } | ||
| 591 | |||
| 592 | static void mfm_seek_intr(void) | ||
| 593 | { | ||
| 594 | #ifdef DEBUG | ||
| 595 | console_printf("seek intr - status = "); | ||
| 596 | print_status(); | ||
| 597 | #endif | ||
| 598 | outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ | ||
| 599 | if (mfm_status & (STAT_DER | STAT_ABN)) { | ||
| 600 | printk("seek failed\n"); | ||
| 601 | MFM_DRV_INFO.cylinder = NEED_2_RECAL; | ||
| 602 | if (cont) { | ||
| 603 | cont->error(); | ||
| 604 | cont->redo(); | ||
| 605 | } | ||
| 606 | return; | ||
| 607 | } | ||
| 608 | if (mfm_status & STAT_SED) { | ||
| 609 | issue_command(CMD_POD, NULL, 0); | ||
| 610 | MFM_DRV_INFO.cylinder = raw_cmd.cylinder; | ||
| 611 | mfm_seek(); | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | if (mfm_status & STAT_CED) { | ||
| 615 | do_mfm = mfm_seek_intr; | ||
| 616 | issue_command(CMD_POL, NULL, 0); | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | printk("seek: unknown status\n"); | ||
| 620 | } | ||
| 621 | |||
| 622 | /* IDEA2 seems to work better - its what RiscOS sets my | ||
| 623 | * disc to - on its SECOND call to specify! | ||
| 624 | */ | ||
| 625 | #define IDEA2 | ||
| 626 | #ifndef IDEA2 | ||
| 627 | #define SPEC_SL 0x16 | ||
| 628 | #define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */ | ||
| 629 | #else | ||
| 630 | #define SPEC_SL 0x00 /* OM2 - SL - step pulse low */ | ||
| 631 | #define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */ | ||
| 632 | #endif | ||
| 633 | |||
| 634 | static void mfm_setupspecify (int drive, unsigned char *cmdb) | ||
| 635 | { | ||
| 636 | cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */ | ||
| 637 | cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */ | ||
| 638 | cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */ | ||
| 639 | cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */ | ||
| 640 | cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */ | ||
| 641 | cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */ | ||
| 642 | cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */ | ||
| 643 | cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */ | ||
| 644 | cmdb[8] = SPEC_SH; | ||
| 645 | cmdb[9] = 0x0a; /* gap length 1 */ | ||
| 646 | cmdb[10] = 0x0d; /* gap length 2 */ | ||
| 647 | cmdb[11] = 0x0c; /* gap length 3 */ | ||
| 648 | cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */ | ||
| 649 | cmdb[13] = mfm_info[drive].precomp - 1; | ||
| 650 | cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */ | ||
| 651 | cmdb[15] = mfm_info[drive].lowcurrent - 1; | ||
| 652 | } | ||
| 653 | |||
| 654 | static void mfm_specify (void) | ||
| 655 | { | ||
| 656 | unsigned char cmdb[16]; | ||
| 657 | |||
| 658 | DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive); | ||
| 659 | mfm_setupspecify (raw_cmd.dev, cmdb); | ||
| 660 | |||
| 661 | issue_command (CMD_SPC, cmdb, 16); | ||
| 662 | /* Ensure that we will do another specify if we move to the other drive */ | ||
| 663 | lastspecifieddrive = raw_cmd.dev; | ||
| 664 | wait_for_completion(); | ||
| 665 | } | ||
| 666 | |||
| 667 | static void mfm_seek(void) | ||
| 668 | { | ||
| 669 | unsigned char cmdb[4]; | ||
| 670 | |||
| 671 | DBG("seeking...\n"); | ||
| 672 | if (MFM_DRV_INFO.cylinder < 0) { | ||
| 673 | do_mfm = mfm_recal_intr; | ||
| 674 | DBG("mfm_seek: about to call specify\n"); | ||
| 675 | mfm_specify (); /* DAG added this */ | ||
| 676 | |||
| 677 | cmdb[0] = raw_cmd.dev + 1; | ||
| 678 | cmdb[1] = 0; | ||
| 679 | |||
| 680 | issue_command(CMD_RCLB, cmdb, 2); | ||
| 681 | return; | ||
| 682 | } | ||
| 683 | if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) { | ||
| 684 | cmdb[0] = raw_cmd.dev + 1; | ||
| 685 | cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */ | ||
| 686 | cmdb[2] = raw_cmd.cylinder >> 8; | ||
| 687 | cmdb[3] = raw_cmd.cylinder; | ||
| 688 | |||
| 689 | do_mfm = mfm_seek_intr; | ||
| 690 | issue_command(CMD_SEK, cmdb, 4); | ||
| 691 | } else | ||
| 692 | mfm_setup_rw(); | ||
| 693 | } | ||
| 694 | |||
| 695 | static void mfm_initialise(void) | ||
| 696 | { | ||
| 697 | DBG("init...\n"); | ||
| 698 | mfm_seek(); | ||
| 699 | } | ||
| 700 | |||
| 701 | static void request_done(int uptodate) | ||
| 702 | { | ||
| 703 | DBG("mfm:request_done\n"); | ||
| 704 | if (uptodate) { | ||
| 705 | unsigned char block[2] = {0, 0}; | ||
| 706 | |||
| 707 | /* Apparently worked - let's check bytes left to DMA */ | ||
| 708 | if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) { | ||
| 709 | printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256); | ||
| 710 | end_request(CURRENT, 0); | ||
| 711 | Busy = 0; | ||
| 712 | }; | ||
| 713 | /* Potentially this means that we've done; but we might be doing | ||
| 714 | a partial access, (over two cylinders) or we may have a number | ||
| 715 | of fragments in an image file. First let's deal with partial accesss | ||
| 716 | */ | ||
| 717 | if (PartFragRead) { | ||
| 718 | /* Yep - a partial access */ | ||
| 719 | |||
| 720 | /* and issue the remainder */ | ||
| 721 | issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); | ||
| 722 | return; | ||
| 723 | } | ||
| 724 | |||
| 725 | /* ah well - perhaps there is another fragment to go */ | ||
| 726 | |||
| 727 | /* Increment pointers/counts to start of next fragment */ | ||
| 728 | if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n"); | ||
| 729 | |||
| 730 | /* No - its the end of the line */ | ||
| 731 | /* end_request's should have happened at the end of sector DMAs */ | ||
| 732 | /* Turns Drive LEDs off - may slow it down? */ | ||
| 733 | if (!elv_next_request(QUEUE)) | ||
| 734 | issue_command(CMD_CKV, block, 2); | ||
| 735 | |||
| 736 | Busy = 0; | ||
| 737 | DBG("request_done: About to mfm_request\n"); | ||
| 738 | /* Next one please */ | ||
| 739 | mfm_request(); /* Moved from mfm_rw_intr */ | ||
| 740 | DBG("request_done: returned from mfm_request\n"); | ||
| 741 | } else { | ||
| 742 | printk("mfm:request_done: update=0\n"); | ||
| 743 | end_request(CURRENT, 0); | ||
| 744 | Busy = 0; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | static void error_handler(void) | ||
| 749 | { | ||
| 750 | printk("error detected... status = "); | ||
| 751 | print_status(); | ||
| 752 | (*errors)++; | ||
| 753 | if (*errors > MFM_DRV_INFO.errors.abort) | ||
| 754 | cont->done(0); | ||
| 755 | if (*errors > MFM_DRV_INFO.errors.recal) | ||
| 756 | MFM_DRV_INFO.cylinder = NEED_2_RECAL; | ||
| 757 | } | ||
| 758 | |||
| 759 | static void rw_interrupt(void) | ||
| 760 | { | ||
| 761 | printk("rw_interrupt\n"); | ||
| 762 | } | ||
| 763 | |||
| 764 | static struct cont rw_cont = | ||
| 765 | { | ||
| 766 | rw_interrupt, | ||
| 767 | error_handler, | ||
| 768 | mfm_rerequest, | ||
| 769 | request_done | ||
| 770 | }; | ||
| 771 | |||
| 772 | /* | ||
| 773 | * Actually gets round to issuing the request - note everything at this | ||
| 774 | * point is in 256 byte sectors not Linux 512 byte blocks | ||
| 775 | */ | ||
| 776 | static void issue_request(unsigned int block, unsigned int nsect, | ||
| 777 | struct request *req) | ||
| 778 | { | ||
| 779 | struct gendisk *disk = req->rq_disk; | ||
| 780 | struct mfm_info *p = disk->private_data; | ||
| 781 | int track, start_head, start_sector; | ||
| 782 | int sectors_to_next_cyl; | ||
| 783 | dev = p - mfm_info; | ||
| 784 | |||
| 785 | track = block / p->sectors; | ||
| 786 | start_sector = block % p->sectors; | ||
| 787 | start_head = track % p->heads; | ||
| 788 | |||
| 789 | /* First get the number of whole tracks which are free before the next | ||
| 790 | track */ | ||
| 791 | sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors; | ||
| 792 | /* Then add in the number of sectors left on this track */ | ||
| 793 | sectors_to_next_cyl += (p->sectors - start_sector); | ||
| 794 | |||
| 795 | DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track); | ||
| 796 | |||
| 797 | raw_cmd.dev = dev; | ||
| 798 | raw_cmd.sector = start_sector; | ||
| 799 | raw_cmd.head = start_head; | ||
| 800 | raw_cmd.cylinder = track / p->heads; | ||
| 801 | raw_cmd.cmdtype = CURRENT->cmd; | ||
| 802 | raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD; | ||
| 803 | raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ | ||
| 804 | raw_cmd.cmddata[1] = raw_cmd.head; | ||
| 805 | raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; | ||
| 806 | raw_cmd.cmddata[3] = raw_cmd.cylinder; | ||
| 807 | raw_cmd.cmddata[4] = raw_cmd.head; | ||
| 808 | raw_cmd.cmddata[5] = raw_cmd.sector; | ||
| 809 | |||
| 810 | /* Was == and worked - how the heck??? */ | ||
| 811 | if (lastspecifieddrive != raw_cmd.dev) | ||
| 812 | mfm_specify (); | ||
| 813 | |||
| 814 | if (nsect <= sectors_to_next_cyl) { | ||
| 815 | raw_cmd.cmddata[6] = nsect >> 8; | ||
| 816 | raw_cmd.cmddata[7] = nsect; | ||
| 817 | PartFragRead = 0; /* All in one */ | ||
| 818 | PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */ | ||
| 819 | } else { | ||
| 820 | raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8; | ||
| 821 | raw_cmd.cmddata[7] = sectors_to_next_cyl; | ||
| 822 | PartFragRead = sectors_to_next_cyl; /* only do this many this time */ | ||
| 823 | PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */ | ||
| 824 | PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl; | ||
| 825 | } | ||
| 826 | raw_cmd.cmdlen = 8; | ||
| 827 | |||
| 828 | /* Setup DMA pointers */ | ||
| 829 | hdc63463_dataptr = (unsigned int) Copy_buffer; | ||
| 830 | hdc63463_dataleft = nsect * 256; /* Better way? */ | ||
| 831 | |||
| 832 | DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", | ||
| 833 | raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ", | ||
| 834 | raw_cmd.cylinder, | ||
| 835 | raw_cmd.head, | ||
| 836 | raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); | ||
| 837 | |||
| 838 | cont = &rw_cont; | ||
| 839 | errors = &(CURRENT->errors); | ||
| 840 | #if 0 | ||
| 841 | mfm_tq.routine = (void (*)(void *)) mfm_initialise; | ||
| 842 | queue_task(&mfm_tq, &tq_immediate); | ||
| 843 | mark_bh(IMMEDIATE_BH); | ||
| 844 | #else | ||
| 845 | mfm_initialise(); | ||
| 846 | #endif | ||
| 847 | } /* issue_request */ | ||
| 848 | |||
| 849 | /* | ||
| 850 | * Called when an error has just happened - need to trick mfm_request | ||
| 851 | * into thinking we weren't busy | ||
| 852 | * | ||
| 853 | * Turn off ints - mfm_request expects them this way | ||
| 854 | */ | ||
| 855 | static void mfm_rerequest(void) | ||
| 856 | { | ||
| 857 | DBG("mfm_rerequest\n"); | ||
| 858 | cli(); | ||
| 859 | Busy = 0; | ||
| 860 | mfm_request(); | ||
| 861 | } | ||
| 862 | |||
| 863 | static struct gendisk *mfm_gendisk[2]; | ||
| 864 | |||
| 865 | static void mfm_request(void) | ||
| 866 | { | ||
| 867 | DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy); | ||
| 868 | |||
| 869 | /* If we are still processing then return; we will get called again */ | ||
| 870 | if (Busy) { | ||
| 871 | /* Again seems to be common in 1.3.45 */ | ||
| 872 | /*DBG*/printk("mfm_request: Exiting due to busy\n"); | ||
| 873 | return; | ||
| 874 | } | ||
| 875 | Busy = 1; | ||
| 876 | |||
| 877 | while (1) { | ||
| 878 | unsigned int block, nsect; | ||
| 879 | struct gendisk *disk; | ||
| 880 | |||
| 881 | DBG("mfm_request: loop start\n"); | ||
| 882 | sti(); | ||
| 883 | |||
| 884 | DBG("mfm_request: before !CURRENT\n"); | ||
| 885 | |||
| 886 | if (!CURRENT) { | ||
| 887 | printk("mfm_request: Exiting due to empty queue (pre)\n"); | ||
| 888 | do_mfm = NULL; | ||
| 889 | Busy = 0; | ||
| 890 | return; | ||
| 891 | } | ||
| 892 | |||
| 893 | DBG("mfm_request: before arg extraction\n"); | ||
| 894 | |||
| 895 | disk = CURRENT->rq_disk; | ||
| 896 | block = CURRENT->sector; | ||
| 897 | nsect = CURRENT->nr_sectors; | ||
| 898 | if (block >= get_capacity(disk) || | ||
| 899 | block+nsect > get_capacity(disk)) { | ||
| 900 | printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n", | ||
| 901 | disk->disk_name, block, nsect, get_capacity(disk)); | ||
| 902 | printk("mfm: continue 1\n"); | ||
| 903 | end_request(CURRENT, 0); | ||
| 904 | Busy = 0; | ||
| 905 | continue; | ||
| 906 | } | ||
| 907 | |||
| 908 | /* DAG: Linux doesn't cope with this - even though it has an array telling | ||
| 909 | it the hardware block size - silly */ | ||
| 910 | block <<= 1; /* Now in 256 byte sectors */ | ||
| 911 | nsect <<= 1; /* Ditto */ | ||
| 912 | |||
| 913 | SectorsLeftInRequest = nsect >> 1; | ||
| 914 | Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; | ||
| 915 | Copy_buffer = CURRENT->buffer; | ||
| 916 | Copy_Sector = CURRENT->sector << 1; | ||
| 917 | |||
| 918 | DBG("mfm_request: block after offset=%d\n", block); | ||
| 919 | |||
| 920 | issue_request(block, nsect, CURRENT); | ||
| 921 | |||
| 922 | break; | ||
| 923 | } | ||
| 924 | DBG("mfm_request: Dropping out bottom\n"); | ||
| 925 | } | ||
| 926 | |||
| 927 | static void do_mfm_request(struct request_queue *q) | ||
| 928 | { | ||
| 929 | DBG("do_mfm_request: about to mfm_request\n"); | ||
| 930 | mfm_request(); | ||
| 931 | } | ||
| 932 | |||
| 933 | static void mfm_interrupt_handler(int unused, void *dev_id) | ||
| 934 | { | ||
| 935 | void (*handler) (void) = do_mfm; | ||
| 936 | |||
| 937 | do_mfm = NULL; | ||
| 938 | |||
| 939 | DBG("mfm_interrupt_handler (handler=0x%p)\n", handler); | ||
| 940 | |||
| 941 | mfm_status = inw(MFM_STATUS); | ||
| 942 | |||
| 943 | /* If CPR (Command Parameter Reject) and not busy it means that the command | ||
| 944 | has some return message to give us */ | ||
| 945 | if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) { | ||
| 946 | int len = 0; | ||
| 947 | while (len < 16) { | ||
| 948 | int in; | ||
| 949 | in = inw(MFM_DATAIN); | ||
| 950 | result[len++] = in >> 8; | ||
| 951 | result[len++] = in; | ||
| 952 | } | ||
| 953 | } | ||
| 954 | if (handler) { | ||
| 955 | handler(); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ | ||
| 959 | printk ("mfm: unexpected interrupt - status = "); | ||
| 960 | print_status (); | ||
| 961 | while (1); | ||
| 962 | } | ||
| 963 | |||
| 964 | |||
| 965 | |||
| 966 | |||
| 967 | |||
| 968 | /* | ||
| 969 | * Tell the user about the drive if we decided it exists. | ||
| 970 | */ | ||
| 971 | static void mfm_geometry(int drive) | ||
| 972 | { | ||
| 973 | struct mfm_info *p = mfm_info + drive; | ||
| 974 | struct gendisk *disk = mfm_gendisk[drive]; | ||
| 975 | disk->private_data = p; | ||
| 976 | if (p->cylinders) | ||
| 977 | printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", | ||
| 978 | disk->disk_name, | ||
| 979 | p->cylinders * p->heads * p->sectors / 4096, | ||
| 980 | p->cylinders, p->heads, p->sectors, | ||
| 981 | p->lowcurrent, p->precomp); | ||
| 982 | set_capacity(disk, p->cylinders * p->heads * p->sectors / 2); | ||
| 983 | } | ||
| 984 | |||
| 985 | #ifdef CONFIG_BLK_DEV_MFM_AUTODETECT | ||
| 986 | /* | ||
| 987 | * Attempt to detect a drive and find its geometry. The drive has already been | ||
| 988 | * specified... | ||
| 989 | * | ||
| 990 | * We first recalibrate the disk, then try to probe sectors, heads and then | ||
| 991 | * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver | ||
| 992 | * does something along these lines, so I assume that most drives are up to | ||
| 993 | * this mistreatment... | ||
| 994 | */ | ||
| 995 | static int mfm_detectdrive (int drive) | ||
| 996 | { | ||
| 997 | unsigned int mingeo[3], maxgeo[3]; | ||
| 998 | unsigned int attribute, need_recal = 1; | ||
| 999 | unsigned char cmdb[8]; | ||
| 1000 | |||
| 1001 | memset (mingeo, 0, sizeof (mingeo)); | ||
| 1002 | maxgeo[0] = mfm_info[drive].sectors; | ||
| 1003 | maxgeo[1] = mfm_info[drive].heads; | ||
| 1004 | maxgeo[2] = mfm_info[drive].cylinders; | ||
| 1005 | |||
| 1006 | cmdb[0] = drive + 1; | ||
| 1007 | cmdb[6] = 0; | ||
| 1008 | cmdb[7] = 1; | ||
| 1009 | for (attribute = 0; attribute < 3; attribute++) { | ||
| 1010 | while (mingeo[attribute] != maxgeo[attribute]) { | ||
| 1011 | unsigned int variable; | ||
| 1012 | |||
| 1013 | variable = (maxgeo[attribute] + mingeo[attribute]) >> 1; | ||
| 1014 | cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0; | ||
| 1015 | |||
| 1016 | if (need_recal) { | ||
| 1017 | int tries = 5; | ||
| 1018 | |||
| 1019 | do { | ||
| 1020 | issue_command (CMD_RCLB, cmdb, 2); | ||
| 1021 | wait_for_completion (); | ||
| 1022 | wait_for_command_end (); | ||
| 1023 | if (result[1] == 0x20) | ||
| 1024 | break; | ||
| 1025 | } while (result[1] && --tries); | ||
| 1026 | if (result[1]) { | ||
| 1027 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 1028 | return 0; | ||
| 1029 | } | ||
| 1030 | need_recal = 0; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | switch (attribute) { | ||
| 1034 | case 0: | ||
| 1035 | cmdb[5] = variable; | ||
| 1036 | issue_command (CMD_CMPD, cmdb, 8); | ||
| 1037 | break; | ||
| 1038 | case 1: | ||
| 1039 | cmdb[1] = variable; | ||
| 1040 | cmdb[4] = variable; | ||
| 1041 | issue_command (CMD_CMPD, cmdb, 8); | ||
| 1042 | break; | ||
| 1043 | case 2: | ||
| 1044 | cmdb[2] = variable >> 8; | ||
| 1045 | cmdb[3] = variable; | ||
| 1046 | issue_command (CMD_SEK, cmdb, 4); | ||
| 1047 | break; | ||
| 1048 | } | ||
| 1049 | wait_for_completion (); | ||
| 1050 | wait_for_command_end (); | ||
| 1051 | |||
| 1052 | switch (result[1]) { | ||
| 1053 | case 0x00: | ||
| 1054 | case 0x50: | ||
| 1055 | mingeo[attribute] = variable + 1; | ||
| 1056 | break; | ||
| 1057 | |||
| 1058 | case 0x20: | ||
| 1059 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 1060 | return 0; | ||
| 1061 | |||
| 1062 | case 0x24: | ||
| 1063 | need_recal = 1; | ||
| 1064 | default: | ||
| 1065 | maxgeo[attribute] = variable; | ||
| 1066 | break; | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | mfm_info[drive].cylinders = mingeo[2]; | ||
| 1071 | mfm_info[drive].lowcurrent = mingeo[2]; | ||
| 1072 | mfm_info[drive].precomp = mingeo[2] / 2; | ||
| 1073 | mfm_info[drive].heads = mingeo[1]; | ||
| 1074 | mfm_info[drive].sectors = mingeo[0]; | ||
| 1075 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 1076 | return 1; | ||
| 1077 | } | ||
| 1078 | #endif | ||
| 1079 | |||
| 1080 | /* | ||
| 1081 | * Initialise all drive information for this controller. | ||
| 1082 | */ | ||
| 1083 | static int mfm_initdrives(void) | ||
| 1084 | { | ||
| 1085 | int drive; | ||
| 1086 | |||
| 1087 | if (number_mfm_drives > MFM_MAXDRIVES) { | ||
| 1088 | number_mfm_drives = MFM_MAXDRIVES; | ||
| 1089 | printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n"); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | for (drive = 0; drive < number_mfm_drives; drive++) { | ||
| 1093 | mfm_info[drive].lowcurrent = 1; | ||
| 1094 | mfm_info[drive].precomp = 1; | ||
| 1095 | mfm_info[drive].cylinder = -1; | ||
| 1096 | mfm_info[drive].errors.recal = 0; | ||
| 1097 | mfm_info[drive].errors.report = 0; | ||
| 1098 | mfm_info[drive].errors.abort = 4; | ||
| 1099 | |||
| 1100 | #ifdef CONFIG_BLK_DEV_MFM_AUTODETECT | ||
| 1101 | mfm_info[drive].cylinders = 1024; | ||
| 1102 | mfm_info[drive].heads = 8; | ||
| 1103 | mfm_info[drive].sectors = 64; | ||
| 1104 | { | ||
| 1105 | unsigned char cmdb[16]; | ||
| 1106 | |||
| 1107 | mfm_setupspecify (drive, cmdb); | ||
| 1108 | cmdb[1] &= ~0x81; | ||
| 1109 | issue_command (CMD_SPC, cmdb, 16); | ||
| 1110 | wait_for_completion (); | ||
| 1111 | if (!mfm_detectdrive (drive)) { | ||
| 1112 | mfm_info[drive].cylinders = 0; | ||
| 1113 | mfm_info[drive].heads = 0; | ||
| 1114 | mfm_info[drive].sectors = 0; | ||
| 1115 | } | ||
| 1116 | cmdb[0] = cmdb[1] = 0; | ||
| 1117 | issue_command (CMD_CKV, cmdb, 2); | ||
| 1118 | } | ||
| 1119 | #else | ||
| 1120 | mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */ | ||
| 1121 | mfm_info[drive].heads = 4; | ||
| 1122 | mfm_info[drive].sectors = 32; | ||
| 1123 | #endif | ||
| 1124 | } | ||
| 1125 | return number_mfm_drives; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | |||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * The 'front' end of the mfm driver follows... | ||
| 1132 | */ | ||
| 1133 | |||
| 1134 | static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
| 1135 | { | ||
| 1136 | struct mfm_info *p = bdev->bd_disk->private_data; | ||
| 1137 | |||
| 1138 | geo->heads = p->heads; | ||
| 1139 | geo->sectors = p->sectors; | ||
| 1140 | geo->cylinders = p->cylinders; | ||
| 1141 | return 0; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | /* | ||
| 1145 | * This is to handle various kernel command line parameters | ||
| 1146 | * specific to this driver. | ||
| 1147 | */ | ||
| 1148 | void mfm_setup(char *str, int *ints) | ||
| 1149 | { | ||
| 1150 | return; | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | /* | ||
| 1154 | * Set the CHS from the ADFS boot block if it is present. This is not ideal | ||
| 1155 | * since if there are any non-ADFS partitions on the disk, this won't work! | ||
| 1156 | * Hence, I want to get rid of this... | ||
| 1157 | */ | ||
| 1158 | void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack, | ||
| 1159 | unsigned char heads, unsigned int secsize) | ||
| 1160 | { | ||
| 1161 | struct mfm_info *p = bdev->bd_disk->private_data; | ||
| 1162 | int drive = p - mfm_info; | ||
| 1163 | unsigned long disksize = bdev->bd_inode->i_size; | ||
| 1164 | |||
| 1165 | if (p->cylinders == 1) { | ||
| 1166 | p->sectors = secsptrack; | ||
| 1167 | p->heads = heads; | ||
| 1168 | p->cylinders = discsize / (secsptrack * heads * secsize); | ||
| 1169 | |||
| 1170 | if ((heads < 1) || (p->cylinders > 1024)) { | ||
| 1171 | printk("%s: Insane disc shape! Setting to 512/4/32\n", | ||
| 1172 | bdev->bd_disk->disk_name); | ||
| 1173 | |||
| 1174 | /* These values are fairly arbitary, but are there so that if your | ||
| 1175 | * lucky you can pick apart your disc to find out what is going on - | ||
| 1176 | * I reckon these figures won't hurt MOST drives | ||
| 1177 | */ | ||
| 1178 | p->sectors = 32; | ||
| 1179 | p->heads = 4; | ||
| 1180 | p->cylinders = 512; | ||
| 1181 | } | ||
| 1182 | if (raw_cmd.dev == drive) | ||
| 1183 | mfm_specify (); | ||
| 1184 | mfm_geometry (drive); | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | static struct block_device_operations mfm_fops = | ||
| 1189 | { | ||
| 1190 | .owner = THIS_MODULE, | ||
| 1191 | .getgeo = mfm_getgeo, | ||
| 1192 | }; | ||
| 1193 | |||
| 1194 | /* | ||
| 1195 | * See if there is a controller at the address presently at mfm_addr | ||
| 1196 | * | ||
| 1197 | * We check to see if the controller is busy - if it is, we abort it first, | ||
| 1198 | * and check that the chip is no longer busy after at least 180 clock cycles. | ||
| 1199 | * We then issue a command and check that the BSY or CPR bits are set. | ||
| 1200 | */ | ||
| 1201 | static int mfm_probecontroller (unsigned int mfm_addr) | ||
| 1202 | { | ||
| 1203 | if (inw (MFM_STATUS) & STAT_BSY) { | ||
| 1204 | outw (CMD_ABT, MFM_COMMAND); | ||
| 1205 | udelay (50); | ||
| 1206 | if (inw (MFM_STATUS) & STAT_BSY) | ||
| 1207 | return 0; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | if (inw (MFM_STATUS) & STAT_CED) | ||
| 1211 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 1212 | |||
| 1213 | outw (CMD_SEK, MFM_COMMAND); | ||
| 1214 | |||
| 1215 | if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) { | ||
| 1216 | unsigned int count = 2000; | ||
| 1217 | while (inw (MFM_STATUS) & STAT_BSY) { | ||
| 1218 | udelay (500); | ||
| 1219 | if (!--count) | ||
| 1220 | return 0; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | outw (CMD_RCAL, MFM_COMMAND); | ||
| 1224 | } | ||
| 1225 | return 1; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | static int mfm_do_init(unsigned char irqmask) | ||
| 1229 | { | ||
| 1230 | int i, ret; | ||
| 1231 | |||
| 1232 | printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); | ||
| 1233 | |||
| 1234 | ret = -EBUSY; | ||
| 1235 | if (!request_region (mfm_addr, 10, "mfm")) | ||
| 1236 | goto out1; | ||
| 1237 | |||
| 1238 | ret = register_blkdev(MAJOR_NR, "mfm"); | ||
| 1239 | if (ret) | ||
| 1240 | goto out2; | ||
| 1241 | |||
| 1242 | /* Stuff for the assembler routines to get to */ | ||
| 1243 | hdc63463_baseaddress = ioaddr(mfm_addr); | ||
| 1244 | hdc63463_irqpolladdress = mfm_IRQPollLoc; | ||
| 1245 | hdc63463_irqpollmask = irqmask; | ||
| 1246 | |||
| 1247 | mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock); | ||
| 1248 | if (!mfm_queue) | ||
| 1249 | goto out2a; | ||
| 1250 | |||
| 1251 | Busy = 0; | ||
| 1252 | lastspecifieddrive = -1; | ||
| 1253 | |||
| 1254 | mfm_drives = mfm_initdrives(); | ||
| 1255 | if (!mfm_drives) { | ||
| 1256 | ret = -ENODEV; | ||
| 1257 | goto out3; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | for (i = 0; i < mfm_drives; i++) { | ||
| 1261 | struct gendisk *disk = alloc_disk(64); | ||
| 1262 | if (!disk) | ||
| 1263 | goto Enomem; | ||
| 1264 | disk->major = MAJOR_NR; | ||
| 1265 | disk->first_minor = i << 6; | ||
| 1266 | disk->fops = &mfm_fops; | ||
| 1267 | sprintf(disk->disk_name, "mfm%c", 'a'+i); | ||
| 1268 | mfm_gendisk[i] = disk; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | printk("mfm: detected %d hard drive%s\n", mfm_drives, | ||
| 1272 | mfm_drives == 1 ? "" : "s"); | ||
| 1273 | ret = request_irq(mfm_irq, mfm_interrupt_handler, IRQF_DISABLED, "MFM harddisk", NULL); | ||
| 1274 | if (ret) { | ||
| 1275 | printk("mfm: unable to get IRQ%d\n", mfm_irq); | ||
| 1276 | goto out4; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | if (mfm_irqenable) | ||
| 1280 | outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */ | ||
| 1281 | |||
| 1282 | for (i = 0; i < mfm_drives; i++) { | ||
| 1283 | mfm_geometry(i); | ||
| 1284 | mfm_gendisk[i]->queue = mfm_queue; | ||
| 1285 | add_disk(mfm_gendisk[i]); | ||
| 1286 | } | ||
| 1287 | return 0; | ||
| 1288 | |||
| 1289 | out4: | ||
| 1290 | for (i = 0; i < mfm_drives; i++) | ||
| 1291 | put_disk(mfm_gendisk[i]); | ||
| 1292 | out3: | ||
| 1293 | blk_cleanup_queue(mfm_queue); | ||
| 1294 | out2a: | ||
| 1295 | unregister_blkdev(MAJOR_NR, "mfm"); | ||
| 1296 | out2: | ||
| 1297 | release_region(mfm_addr, 10); | ||
| 1298 | out1: | ||
| 1299 | return ret; | ||
| 1300 | Enomem: | ||
| 1301 | while (i--) | ||
| 1302 | put_disk(mfm_gendisk[i]); | ||
| 1303 | goto out3; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | static void mfm_do_exit(void) | ||
| 1307 | { | ||
| 1308 | int i; | ||
| 1309 | |||
| 1310 | free_irq(mfm_irq, NULL); | ||
| 1311 | for (i = 0; i < mfm_drives; i++) { | ||
| 1312 | del_gendisk(mfm_gendisk[i]); | ||
| 1313 | put_disk(mfm_gendisk[i]); | ||
| 1314 | } | ||
| 1315 | blk_cleanup_queue(mfm_queue); | ||
| 1316 | unregister_blkdev(MAJOR_NR, "mfm"); | ||
| 1317 | if (mfm_addr) | ||
| 1318 | release_region(mfm_addr, 10); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id) | ||
| 1322 | { | ||
| 1323 | if (mfm_addr) | ||
| 1324 | return -EBUSY; | ||
| 1325 | |||
| 1326 | mfm_addr = ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800; | ||
| 1327 | mfm_IRQPollLoc = ioaddr(mfm_addr + 0x400); | ||
| 1328 | mfm_irqenable = mfm_IRQPollLoc; | ||
| 1329 | mfm_irq = ec->irq; | ||
| 1330 | |||
| 1331 | return mfm_do_init(0x08); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | static void __devexit mfm_remove(struct expansion_card *ec) | ||
| 1335 | { | ||
| 1336 | outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */ | ||
| 1337 | mfm_do_exit(); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | static const struct ecard_id mfm_cids[] = { | ||
| 1341 | { MANU_ACORN, PROD_ACORN_MFM }, | ||
| 1342 | { 0xffff, 0xffff }, | ||
| 1343 | }; | ||
| 1344 | |||
| 1345 | static struct ecard_driver mfm_driver = { | ||
| 1346 | .probe = mfm_probe, | ||
| 1347 | .remove = __devexit(mfm_remove), | ||
| 1348 | .id_table = mfm_cids, | ||
| 1349 | .drv = { | ||
| 1350 | .name = "mfm", | ||
| 1351 | }, | ||
| 1352 | }; | ||
| 1353 | |||
| 1354 | /* | ||
| 1355 | * Look for a MFM controller - first check the motherboard, then the podules | ||
| 1356 | * The podules have an extra interrupt enable that needs to be played with | ||
| 1357 | * | ||
| 1358 | * The HDC is accessed at MEDIUM IOC speeds. | ||
| 1359 | */ | ||
| 1360 | static int __init mfm_init (void) | ||
| 1361 | { | ||
| 1362 | unsigned char irqmask; | ||
| 1363 | |||
| 1364 | if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) { | ||
| 1365 | mfm_addr = ONBOARD_MFM_ADDRESS; | ||
| 1366 | mfm_IRQPollLoc = IOC_IRQSTATB; | ||
| 1367 | mfm_irqenable = 0; | ||
| 1368 | mfm_irq = IRQ_HARDDISK; | ||
| 1369 | return mfm_do_init(0x08); /* IL3 pin */ | ||
| 1370 | } else { | ||
| 1371 | return ecard_register_driver(&mfm_driver); | ||
| 1372 | } | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | static void __exit mfm_exit(void) | ||
| 1376 | { | ||
| 1377 | if (mfm_addr == ONBOARD_MFM_ADDRESS) | ||
| 1378 | mfm_do_exit(); | ||
| 1379 | else | ||
| 1380 | ecard_unregister_driver(&mfm_driver); | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | module_init(mfm_init) | ||
| 1384 | module_exit(mfm_exit) | ||
| 1385 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index b1a9b81c21..e049f65bc3 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig | |||
| @@ -833,7 +833,7 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ | |||
| 833 | depends on BLK_DEV_IDE_AU1XXX | 833 | depends on BLK_DEV_IDE_AU1XXX |
| 834 | 834 | ||
| 835 | config IDE_ARM | 835 | config IDE_ARM |
| 836 | def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) | 836 | def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) |
| 837 | 837 | ||
| 838 | config BLK_DEV_IDE_ICSIDE | 838 | config BLK_DEV_IDE_ICSIDE |
| 839 | tristate "ICS IDE interface support" | 839 | tristate "ICS IDE interface support" |
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c index a3d6744e87..bce2bec814 100644 --- a/drivers/ide/arm/ide_arm.c +++ b/drivers/ide/arm/ide_arm.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * ARM/ARM26 default IDE host driver | 2 | * ARM default IDE host driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Bartlomiej Zolnierkiewicz | 4 | * Copyright (C) 2004 Bartlomiej Zolnierkiewicz |
| 5 | * Based on code by: Russell King, Ian Molton and Alexander Schulz. | 5 | * Based on code by: Russell King, Ian Molton and Alexander Schulz. |
| @@ -14,12 +14,6 @@ | |||
| 14 | #include <asm/mach-types.h> | 14 | #include <asm/mach-types.h> |
| 15 | #include <asm/irq.h> | 15 | #include <asm/irq.h> |
| 16 | 16 | ||
| 17 | #ifdef CONFIG_ARM26 | ||
| 18 | # define IDE_ARM_HOST (machine_is_a5k()) | ||
| 19 | #else | ||
| 20 | # define IDE_ARM_HOST (1) | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifdef CONFIG_ARCH_CLPS7500 | 17 | #ifdef CONFIG_ARCH_CLPS7500 |
| 24 | # include <asm/arch/hardware.h> | 18 | # include <asm/arch/hardware.h> |
| 25 | # | 19 | # |
| @@ -32,12 +26,10 @@ | |||
| 32 | 26 | ||
| 33 | void __init ide_arm_init(void) | 27 | void __init ide_arm_init(void) |
| 34 | { | 28 | { |
| 35 | if (IDE_ARM_HOST) { | 29 | hw_regs_t hw; |
| 36 | hw_regs_t hw; | ||
| 37 | 30 | ||
| 38 | memset(&hw, 0, sizeof(hw)); | 31 | memset(&hw, 0, sizeof(hw)); |
| 39 | ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206); | 32 | ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206); |
| 40 | hw.irq = IDE_ARM_IRQ; | 33 | hw.irq = IDE_ARM_IRQ; |
| 41 | ide_register_hw(&hw, 1, NULL); | 34 | ide_register_hw(&hw, 1, NULL); |
| 42 | } | ||
| 43 | } | 35 | } |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9d8d40d5c8..9ed0a98bf5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -275,7 +275,7 @@ comment "Platform RTC drivers" | |||
| 275 | 275 | ||
| 276 | config RTC_DRV_CMOS | 276 | config RTC_DRV_CMOS |
| 277 | tristate "PC-style 'CMOS'" | 277 | tristate "PC-style 'CMOS'" |
| 278 | depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ | 278 | depends on RTC_CLASS && (X86 || ALPHA || ARM \ |
| 279 | || M32R || ATARI || PPC || MIPS) | 279 | || M32R || ATARI || PPC || MIPS) |
| 280 | help | 280 | help |
| 281 | Say "yes" here to get direct support for the real time clock | 281 | Say "yes" here to get direct support for the real time clock |
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig index d006a8cb4a..7236143941 100644 --- a/drivers/scsi/arm/Kconfig +++ b/drivers/scsi/arm/Kconfig | |||
| @@ -74,15 +74,6 @@ config SCSI_CUMANA_1 | |||
| 74 | This enables support for the Cumana SCSI I card. If you have an | 74 | This enables support for the Cumana SCSI I card. If you have an |
| 75 | Acorn system with one of these, say Y. If unsure, say N. | 75 | Acorn system with one of these, say Y. If unsure, say N. |
| 76 | 76 | ||
| 77 | config SCSI_ECOSCSI | ||
| 78 | tristate "EcoScsi support (EXPERIMENTAL)" | ||
| 79 | depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI | ||
| 80 | select SCSI_SPI_ATTRS | ||
| 81 | help | ||
| 82 | This enables support for the EcoSCSI card -- a small card that sits | ||
| 83 | in the Econet socket. If you have an Acorn system with one of these, | ||
| 84 | say Y. If unsure, say N. | ||
| 85 | |||
| 86 | config SCSI_OAK1 | 77 | config SCSI_OAK1 |
| 87 | tristate "Oak SCSI support (EXPERIMENTAL)" | 78 | tristate "Oak SCSI support (EXPERIMENTAL)" |
| 88 | depends on ARCH_ACORN && EXPERIMENTAL && SCSI | 79 | depends on ARCH_ACORN && EXPERIMENTAL && SCSI |
diff --git a/drivers/scsi/arm/Makefile b/drivers/scsi/arm/Makefile index e8db17924c..16c3e86a6b 100644 --- a/drivers/scsi/arm/Makefile +++ b/drivers/scsi/arm/Makefile | |||
| @@ -8,7 +8,6 @@ obj-$(CONFIG_SCSI_ACORNSCSI_3) += acornscsi_mod.o queue.o msgqueue.o | |||
| 8 | obj-$(CONFIG_SCSI_ARXESCSI) += arxescsi.o fas216.o queue.o msgqueue.o | 8 | obj-$(CONFIG_SCSI_ARXESCSI) += arxescsi.o fas216.o queue.o msgqueue.o |
| 9 | obj-$(CONFIG_SCSI_CUMANA_1) += cumana_1.o | 9 | obj-$(CONFIG_SCSI_CUMANA_1) += cumana_1.o |
| 10 | obj-$(CONFIG_SCSI_CUMANA_2) += cumana_2.o fas216.o queue.o msgqueue.o | 10 | obj-$(CONFIG_SCSI_CUMANA_2) += cumana_2.o fas216.o queue.o msgqueue.o |
| 11 | obj-$(CONFIG_SCSI_ECOSCSI) += ecoscsi.o | ||
| 12 | obj-$(CONFIG_SCSI_OAK1) += oak.o | 11 | obj-$(CONFIG_SCSI_OAK1) += oak.o |
| 13 | obj-$(CONFIG_SCSI_POWERTECSCSI) += powertec.o fas216.o queue.o msgqueue.o | 12 | obj-$(CONFIG_SCSI_POWERTECSCSI) += powertec.o fas216.o queue.o msgqueue.o |
| 14 | obj-$(CONFIG_SCSI_EESOXSCSI) += eesox.o fas216.o queue.o msgqueue.o | 13 | obj-$(CONFIG_SCSI_EESOXSCSI) += eesox.o fas216.o queue.o msgqueue.o |
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c deleted file mode 100644 index 5265a98843..0000000000 --- a/drivers/scsi/arm/ecoscsi.c +++ /dev/null | |||
| @@ -1,166 +0,0 @@ | |||
| 1 | #define AUTOSENSE | ||
| 2 | /* #define PSEUDO_DMA */ | ||
| 3 | |||
| 4 | /* | ||
| 5 | * EcoSCSI Generic NCR5380 driver | ||
| 6 | * | ||
| 7 | * Copyright 1995, Russell King | ||
| 8 | * | ||
| 9 | * ALPHA RELEASE 1. | ||
| 10 | * | ||
| 11 | * For more information, please consult | ||
| 12 | * | ||
| 13 | * NCR 5380 Family | ||
| 14 | * SCSI Protocol Controller | ||
| 15 | * Databook | ||
| 16 | * | ||
| 17 | * NCR Microelectronics | ||
| 18 | * 1635 Aeroplaza Drive | ||
| 19 | * Colorado Springs, CO 80916 | ||
| 20 | * 1+ (719) 578-3400 | ||
| 21 | * 1+ (800) 334-5454 | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/signal.h> | ||
| 26 | #include <linux/ioport.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/blkdev.h> | ||
| 30 | |||
| 31 | #include <asm/io.h> | ||
| 32 | #include <asm/system.h> | ||
| 33 | |||
| 34 | #include "../scsi.h" | ||
| 35 | #include <scsi/scsi_host.h> | ||
| 36 | |||
| 37 | #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) | ||
| 38 | |||
| 39 | #define NCR5380_local_declare() void __iomem *_base | ||
| 40 | #define NCR5380_setup(host) _base = priv(host)->base | ||
| 41 | |||
| 42 | #define NCR5380_read(reg) ({ writeb(reg | 8, _base); readb(_base + 4); }) | ||
| 43 | #define NCR5380_write(reg, value) ({ writeb(reg | 8, _base); writeb(value, _base + 4); }) | ||
| 44 | |||
| 45 | #define NCR5380_intr ecoscsi_intr | ||
| 46 | #define NCR5380_queue_command ecoscsi_queue_command | ||
| 47 | #define NCR5380_proc_info ecoscsi_proc_info | ||
| 48 | |||
| 49 | #define NCR5380_implementation_fields \ | ||
| 50 | void __iomem *base | ||
| 51 | |||
| 52 | #include "../NCR5380.h" | ||
| 53 | |||
| 54 | #define ECOSCSI_PUBLIC_RELEASE 1 | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Function : ecoscsi_setup(char *str, int *ints) | ||
| 58 | * | ||
| 59 | * Purpose : LILO command line initialization of the overrides array, | ||
| 60 | * | ||
| 61 | * Inputs : str - unused, ints - array of integer parameters with ints[0] | ||
| 62 | * equal to the number of ints. | ||
| 63 | * | ||
| 64 | */ | ||
| 65 | |||
| 66 | void ecoscsi_setup(char *str, int *ints) | ||
| 67 | { | ||
| 68 | } | ||
| 69 | |||
| 70 | const char * ecoscsi_info (struct Scsi_Host *spnt) | ||
| 71 | { | ||
| 72 | return ""; | ||
| 73 | } | ||
| 74 | |||
| 75 | #define BOARD_NORMAL 0 | ||
| 76 | #define BOARD_NCR53C400 1 | ||
| 77 | |||
| 78 | #include "../NCR5380.c" | ||
| 79 | |||
| 80 | static struct scsi_host_template ecoscsi_template = { | ||
| 81 | .module = THIS_MODULE, | ||
| 82 | .name = "Serial Port EcoSCSI NCR5380", | ||
| 83 | .proc_name = "ecoscsi", | ||
| 84 | .info = ecoscsi_info, | ||
| 85 | .queuecommand = ecoscsi_queue_command, | ||
| 86 | .eh_abort_handler = NCR5380_abort, | ||
| 87 | .eh_bus_reset_handler = NCR5380_bus_reset, | ||
| 88 | .can_queue = 16, | ||
| 89 | .this_id = 7, | ||
| 90 | .sg_tablesize = SG_ALL, | ||
| 91 | .cmd_per_lun = 2, | ||
| 92 | .use_clustering = DISABLE_CLUSTERING | ||
| 93 | }; | ||
| 94 | |||
| 95 | static struct Scsi_Host *host; | ||
| 96 | |||
| 97 | static int __init ecoscsi_init(void) | ||
| 98 | { | ||
| 99 | void __iomem *_base; | ||
| 100 | int ret; | ||
| 101 | |||
| 102 | if (!request_mem_region(0x33a0000, 4096, "ecoscsi")) { | ||
| 103 | ret = -EBUSY; | ||
| 104 | goto out; | ||
| 105 | } | ||
| 106 | |||
| 107 | _base = ioremap(0x33a0000, 4096); | ||
| 108 | if (!_base) { | ||
| 109 | ret = -ENOMEM; | ||
| 110 | goto out_release; | ||
| 111 | } | ||
| 112 | |||
| 113 | NCR5380_write(MODE_REG, 0x20); /* Is it really SCSI? */ | ||
| 114 | if (NCR5380_read(MODE_REG) != 0x20) /* Write to a reg. */ | ||
| 115 | goto out_unmap; | ||
| 116 | |||
| 117 | NCR5380_write(MODE_REG, 0x00); /* it back. */ | ||
| 118 | if (NCR5380_read(MODE_REG) != 0x00) | ||
| 119 | goto out_unmap; | ||
| 120 | |||
| 121 | host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata)); | ||
| 122 | if (!host) { | ||
| 123 | ret = -ENOMEM; | ||
| 124 | goto out_unmap; | ||
| 125 | } | ||
| 126 | |||
| 127 | priv(host)->base = _base; | ||
| 128 | host->irq = IRQ_NONE; | ||
| 129 | |||
| 130 | NCR5380_init(host, 0); | ||
| 131 | |||
| 132 | printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port); | ||
| 133 | printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", | ||
| 134 | host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE); | ||
| 135 | printk("\nscsi%d:", host->host_no); | ||
| 136 | NCR5380_print_options(host); | ||
| 137 | printk("\n"); | ||
| 138 | |||
| 139 | scsi_add_host(host, NULL); /* XXX handle failure */ | ||
| 140 | scsi_scan_host(host); | ||
| 141 | return 0; | ||
| 142 | |||
| 143 | out_unmap: | ||
| 144 | iounmap(_base); | ||
| 145 | out_release: | ||
| 146 | release_mem_region(0x33a0000, 4096); | ||
| 147 | out: | ||
| 148 | return ret; | ||
| 149 | } | ||
| 150 | |||
| 151 | static void __exit ecoscsi_exit(void) | ||
| 152 | { | ||
| 153 | scsi_remove_host(host); | ||
| 154 | NCR5380_exit(host); | ||
| 155 | scsi_host_put(host); | ||
| 156 | release_mem_region(0x33a0000, 4096); | ||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | module_init(ecoscsi_init); | ||
| 161 | module_exit(ecoscsi_exit); | ||
| 162 | |||
| 163 | MODULE_AUTHOR("Russell King"); | ||
| 164 | MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines"); | ||
| 165 | MODULE_LICENSE("GPL"); | ||
| 166 | |||
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 61a8bf159c..eedb8285e3 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c | |||
| @@ -138,17 +138,6 @@ static struct pixclock arc_clocks[] = { | |||
| 138 | { 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */ | 138 | { 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */ |
| 139 | }; | 139 | }; |
| 140 | 140 | ||
| 141 | #ifdef CONFIG_ARCH_A5K | ||
| 142 | static struct pixclock a5k_clocks[] = { | ||
| 143 | { 117974, 120357, VIDC_CTRL_DIV3, VID_CTL_25MHz }, /* 8.392MHz */ | ||
| 144 | { 78649, 80238, VIDC_CTRL_DIV2, VID_CTL_25MHz }, /* 12.588MHz */ | ||
| 145 | { 58987, 60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz }, /* 16.588MHz */ | ||
| 146 | { 55000, 56111, VIDC_CTRL_DIV2, VID_CTL_36MHz }, /* 18.000MHz */ | ||
| 147 | { 39325, 40119, VIDC_CTRL_DIV1, VID_CTL_25MHz }, /* 25.175MHz */ | ||
| 148 | { 27500, 28055, VIDC_CTRL_DIV1, VID_CTL_36MHz }, /* 36.000MHz */ | ||
| 149 | }; | ||
| 150 | #endif | ||
| 151 | |||
| 152 | static struct pixclock * | 141 | static struct pixclock * |
| 153 | acornfb_valid_pixrate(struct fb_var_screeninfo *var) | 142 | acornfb_valid_pixrate(struct fb_var_screeninfo *var) |
| 154 | { | 143 | { |
| @@ -163,15 +152,6 @@ acornfb_valid_pixrate(struct fb_var_screeninfo *var) | |||
| 163 | pixclock < arc_clocks[i].max_clock) | 152 | pixclock < arc_clocks[i].max_clock) |
| 164 | return arc_clocks + i; | 153 | return arc_clocks + i; |
| 165 | 154 | ||
| 166 | #ifdef CONFIG_ARCH_A5K | ||
| 167 | if (machine_is_a5k()) { | ||
| 168 | for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++) | ||
| 169 | if (pixclock > a5k_clocks[i].min_clock && | ||
| 170 | pixclock < a5k_clocks[i].max_clock) | ||
| 171 | return a5k_clocks + i; | ||
| 172 | } | ||
| 173 | #endif | ||
| 174 | |||
| 175 | return NULL; | 155 | return NULL; |
| 176 | } | 156 | } |
| 177 | 157 | ||
