aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acorn
diff options
context:
space:
mode:
authorAdrian Bunk <bunk@stusta.de>2007-07-31 03:38:19 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-31 18:39:39 -0400
commit99eb8a550dbccc0e1f6c7e866fe421810e0585f6 (patch)
tree130c6e3338a0655ba74355eba83afab9261e1ed0 /drivers/acorn
parent0d0ed42e5ca2e22465c591341839c18025748fe8 (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/acorn')
-rw-r--r--drivers/acorn/README1
-rw-r--r--drivers/acorn/block/Kconfig36
-rw-r--r--drivers/acorn/block/Makefile9
-rw-r--r--drivers/acorn/block/fd1772.c1604
-rw-r--r--drivers/acorn/block/fd1772dma.S100
-rw-r--r--drivers/acorn/block/mfm.S162
-rw-r--r--drivers/acorn/block/mfmhd.c1385
7 files changed, 0 insertions, 3297 deletions
diff --git a/drivers/acorn/README b/drivers/acorn/README
deleted file mode 100644
index d399c09ca61c..000000000000
--- a/drivers/acorn/README
+++ /dev/null
@@ -1 +0,0 @@
1Drivers for the ACORN "podule" ARM specific bus.
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig
deleted file mode 100644
index a0ff25ea439f..000000000000
--- a/drivers/acorn/block/Kconfig
+++ /dev/null
@@ -1,36 +0,0 @@
1#
2# Block device driver configuration
3#
4
5menu "Acorn-specific block devices"
6 depends on ARCH_ARC || ARCH_A5K
7
8config 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
17config 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
26config 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
35endmenu
36
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
deleted file mode 100644
index 38a9afe8e03f..000000000000
--- a/drivers/acorn/block/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
1#
2# Makefile for the Acorn block device drivers.
3#
4
5fd1772_mod-objs := fd1772.o fd1772dma.o
6mfmhd_mod-objs := mfmhd.o mfm.o
7
8obj-$(CONFIG_BLK_DEV_FD1772) += fd1772_mod.o
9obj-$(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 d7e18ce8dad9..000000000000
--- 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
176static 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 */
185static 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
208static struct gendisk *disks[FD_MAX_UNIT];
209
210/* current info on each unit */
211static 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 */
226extern void fdc1772_comendhandler(void); /* Actually doens't have these parameters - see fd1772.S */
227extern volatile int fdc1772_comendstatus;
228extern 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)); */
240void 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
254unsigned 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
260unsigned char *TrackBuffer; /* buffer for reads */
261#define PhysTrackBuffer TrackBuffer /* physical address */
262static int BufferDrive, BufferSide, BufferTrack;
263static 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 */
275static int SelectedDrive = 0;
276static int ReqCmd, ReqBlock;
277static int ReqSide, ReqTrack, ReqSector, ReqCnt;
278static int HeadSettleFlag = 0;
279static unsigned char *ReqData, *ReqBuffer;
280static int MotorOn = 0, MotorOffTrys;
281
282/* Synchronization of FDC1772 access. */
283static volatile int fdc_busy = 0;
284static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
285
286
287/* long req'd for set_bit --RR */
288static 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
327static void fd1772_checkint(void);
328
329DECLARE_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 */
335static int Probing = 0;
336
337/* This flag is set when a dummy seek is necessary to make the WP
338 * status bit accessible.
339 */
340static int NeedSeek = 0;
341
342
343/***************************** Prototypes *****************************/
344
345static void fd_select_side(int side);
346static void fd_select_drive(int drive);
347static void fd_deselect(void);
348static void fd_motor_off_timer(unsigned long dummy);
349static void check_change(unsigned long dummy);
350static void floppy_irqconsequencehandler(void);
351static void fd_error(void);
352static void do_fd_action(int drive);
353static void fd_calibrate(void);
354static void fd_calibrate_done(int status);
355static void fd_seek(void);
356static void fd_seek_done(int status);
357static void fd_rwsec(void);
358#ifdef TRACKBUFFER
359static void fd_readtrack_check( unsigned long dummy );
360#endif
361static void fd_rwsec_done(int status);
362static void fd_times_out(unsigned long dummy);
363static void finish_fdc(void);
364static void finish_fdc_done(int dummy);
365static void floppy_off(unsigned int nr);
366static void setup_req_params(int drive);
367static void redo_fd_request(void);
368static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
369 cmd, unsigned long param);
370static void fd_probe(int drive);
371static int fd_test_drive_present(int drive);
372static void config_types(void);
373static int floppy_open(struct inode *inode, struct file *filp);
374static int floppy_release(struct inode *inode, struct file *filp);
375static void do_fd_request(struct request_queue *);
376
377/************************* End of Prototypes **************************/
378
379static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0);
380
381#ifdef TRACKBUFFER
382static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
383#endif
384
385static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
386
387static DEFINE_TIMER(fd_timer, check_change, 0, 0);
388
389/* DAG: Haven't got a clue what this is? */
390int stdma_islocked(void)
391{
392 return 0;
393};
394
395/* Select the side to use. */
396
397static 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
406static 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
429static 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
446static 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
481retry:
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
498static 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
537static inline void set_head_settle_flag(void)
538{
539 HeadSettleFlag = FDC1772CMDADD_E;
540}
541
542static 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
554static 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
563static void (*FloppyIRQHandler) (int status) = NULL;
564
565static 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
591static 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
623static 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
629repeat:
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
672static 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
691static 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
711static 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
739static 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
765static int MultReadInProgress = 0;
766#endif
767
768
769static 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
870static 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
922static 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
1031err_end:
1032#ifdef TRACKBUFFER
1033 BufferDrive = -1;
1034#endif
1035
1036 fd_error();
1037}
1038
1039
1040static 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
1062static 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
1085static 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. */
1117static int fd_ref[4];
1118static int fd_device[4];
1119
1120/* dummy for blk.h */
1121static 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*/
1137static 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
1159static 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
1178static 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
1197static 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
1206repeat:
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
1257the_end:
1258 finish_fdc();
1259}
1260
1261static 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
1274static 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
1295static 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
1307static 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
1327static 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
1351static 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
1412static 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
1451static 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
1486static 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
1500static 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
1509static 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
1518int 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 7964435443ec..000000000000
--- 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
8fdc1772_fiqdata:
9@ Number of bytes left to DMA
10 .global fdc1772_bytestogo
11fdc1772_bytestogo:
12 .word 0
13@ Place to put/get data from in DMA
14 .global fdc1772_dataaddr
15fdc1772_dataaddr:
16 .word 0
17
18 .global fdc1772_fdc_int_done
19fdc1772_fdc_int_done:
20 .word 0
21 .global fdc1772_comendstatus
22fdc1772_comendstatus:
23 .word 0
24
25@ We hang this off DMA channel 1
26 .global fdc1772_comendhandler
27fdc1772_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
41fdc1772_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
54fdc1772_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
59fdc1772_dma_read_end:
60
61 .global fdc1772_dma_write
62fdc1772_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
75fdc1772_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
81fdc1772_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
89fdc1772_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 c90cbd41ce21..000000000000
--- 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
7hdc63463_irqdata:
8@ Controller base address
9 .global hdc63463_baseaddress
10hdc63463_baseaddress:
11 .word 0
12
13 .global hdc63463_irqpolladdress
14hdc63463_irqpolladdress:
15 .word 0
16
17 .global hdc63463_irqpollmask
18hdc63463_irqpollmask:
19 .word 0
20
21@ where to read/write data from the kernel data space
22 .global hdc63463_dataptr
23hdc63463_dataptr:
24 .word 0
25
26@ Number of bytes left to transfer
27 .global hdc63463_dataleft
28hdc63463_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
36hdc63463_writedma:
37 stmfd sp!,{r4-r7}
38 adr r5,hdc63463_irqdata
39 ldmia r5,{r0,r1,r2,r3,r4}
40
41writedma_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
74writedma_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
95writedma_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
106hdc63463_readdma:
107 stmfd sp!,{r4-r7}
108 adr r5,hdc63463_irqdata
109 ldmia r5,{r0,r1,r2,r3,r4}
110
111readdma_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
142readdma_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
158readdma_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 74058db674db..000000000000
--- 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
123static void (*do_mfm)(void) = NULL;
124static struct request_queue *mfm_queue;
125static 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 */
156struct 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 */
176extern unsigned int hdc63463_baseaddress; /* Controller base address */
177extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */
178extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */
179extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */
180extern int hdc63463_dataleft; /* Number of bytes left to transfer */
181
182
183
184
185static int lastspecifieddrive;
186static unsigned Busy;
187
188static 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
193static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */
194static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */
195
196static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */
197static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */
198static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know
199 where to take over */
200static char *Copy_buffer;
201
202
203static void mfm_seek(void);
204static void mfm_rerequest(void);
205static void mfm_request(void);
206static void mfm_specify (void);
207static void issue_request(unsigned int block, unsigned int nsect,
208 struct request *req);
209
210static unsigned int mfm_addr; /* Controller address */
211static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */
212static unsigned int mfm_irqenable; /* Podule IRQ enable location */
213static unsigned char mfm_irq; /* Interrupt number */
214static int mfm_drives = 0; /* drives available */
215static int mfm_status = 0; /* interrupt status */
216static int *errors;
217
218static 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
229static unsigned char result[16];
230
231static 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
239static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
240#endif
241
242int 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
289static 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
311static 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
360static 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
396static void wait_for_completion(void)
397{
398 while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
399}
400
401static 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
418static 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
551static 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
559static 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
592static 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
634static 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
654static 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
667static 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
695static void mfm_initialise(void)
696{
697 DBG("init...\n");
698 mfm_seek();
699}
700
701static 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
748static 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
759static void rw_interrupt(void)
760{
761 printk("rw_interrupt\n");
762}
763
764static 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 */
776static 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 */
855static void mfm_rerequest(void)
856{
857 DBG("mfm_rerequest\n");
858 cli();
859 Busy = 0;
860 mfm_request();
861}
862
863static struct gendisk *mfm_gendisk[2];
864
865static 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
927static void do_mfm_request(struct request_queue *q)
928{
929 DBG("do_mfm_request: about to mfm_request\n");
930 mfm_request();
931}
932
933static 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 */
971static 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 */
995static 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 */
1083static 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
1134static 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 */
1148void 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 */
1158void 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
1188static 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 */
1201static 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
1228static 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
1289out4:
1290 for (i = 0; i < mfm_drives; i++)
1291 put_disk(mfm_gendisk[i]);
1292out3:
1293 blk_cleanup_queue(mfm_queue);
1294out2a:
1295 unregister_blkdev(MAJOR_NR, "mfm");
1296out2:
1297 release_region(mfm_addr, 10);
1298out1:
1299 return ret;
1300Enomem:
1301 while (i--)
1302 put_disk(mfm_gendisk[i]);
1303 goto out3;
1304}
1305
1306static 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
1321static 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
1334static 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
1340static const struct ecard_id mfm_cids[] = {
1341 { MANU_ACORN, PROD_ACORN_MFM },
1342 { 0xffff, 0xffff },
1343};
1344
1345static 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 */
1360static 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
1375static 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
1383module_init(mfm_init)
1384module_exit(mfm_exit)
1385MODULE_LICENSE("GPL");