aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acorn
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/acorn
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
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.c1609
-rw-r--r--drivers/acorn/block/fd1772dma.S100
-rw-r--r--drivers/acorn/block/mfm.S162
-rw-r--r--drivers/acorn/block/mfmhd.c1416
-rw-r--r--drivers/acorn/char/Makefile6
-rw-r--r--drivers/acorn/char/defkeymap-l7200.c386
-rw-r--r--drivers/acorn/char/i2c.c369
-rw-r--r--drivers/acorn/char/pcf8583.c239
-rw-r--r--drivers/acorn/char/pcf8583.h41
12 files changed, 4374 insertions, 0 deletions
diff --git a/drivers/acorn/README b/drivers/acorn/README
new file mode 100644
index 000000000000..d399c09ca61c
--- /dev/null
+++ b/drivers/acorn/README
@@ -0,0 +1 @@
Drivers for the ACORN "podule" ARM specific bus.
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig
new file mode 100644
index 000000000000..073add35e66f
--- /dev/null
+++ b/drivers/acorn/block/Kconfig
@@ -0,0 +1,36 @@
1#
2# Block device driver configuration
3#
4
5menu "Acorn-specific block devices"
6 depends on ARCH_ACORN
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
new file mode 100644
index 000000000000..38a9afe8e03f
--- /dev/null
+++ b/drivers/acorn/block/Makefile
@@ -0,0 +1,9 @@
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
new file mode 100644
index 000000000000..3cd2e968e96c
--- /dev/null
+++ b/drivers/acorn/block/fd1772.c
@@ -0,0 +1,1609 @@
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(request_queue_t *);
376
377/************************* End of Prototypes **************************/
378
379static struct timer_list motor_off_timer =
380 TIMER_INITIALIZER(fd_motor_off_timer, 0, 0);
381
382#ifdef TRACKBUFFER
383static struct timer_list readtrack_timer =
384 TIMER_INITIALIZER(fd_readtrack_check, 0, 0);
385#endif
386
387static struct timer_list timeout_timer =
388 TIMER_INITIALIZER(fd_times_out, 0, 0);
389
390static struct timer_list fd_timer =
391 TIMER_INITIALIZER(check_change, 0, 0);
392
393/* DAG: Haven't got a clue what this is? */
394int stdma_islocked(void)
395{
396 return 0;
397};
398
399/* Select the side to use. */
400
401static void fd_select_side(int side)
402{
403 oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);
404}
405
406
407/* Select a drive, update the FDC1772's track register
408 */
409
410static void fd_select_drive(int drive)
411{
412#ifdef DEBUG
413 printk("fd_select_drive:%d\n", drive);
414#endif
415 /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */
416 oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);
417
418 if (drive == SelectedDrive)
419 return;
420
421 oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));
422
423 /* restore track register to saved value */
424 FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);
425 udelay(25);
426
427 SelectedDrive = drive;
428}
429
430
431/* Deselect both drives. */
432
433static void fd_deselect(void)
434{
435 unsigned long flags;
436
437 DPRINT(("fd_deselect\n"));
438
439 oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);
440
441 SelectedDrive = -1;
442}
443
444
445/* This timer function deselects the drives when the FDC1772 switched the
446 * motor off. The deselection cannot happen earlier because the FDC1772
447 * counts the index signals, which arrive only if one drive is selected.
448 */
449
450static void fd_motor_off_timer(unsigned long dummy)
451{
452 unsigned long flags;
453 unsigned char status;
454 int delay;
455
456 del_timer(&motor_off_timer);
457
458 if (SelectedDrive < 0)
459 /* no drive selected, needn't deselect anyone */
460 return;
461
462 save_flags(flags);
463 cli();
464
465 if (fdc_busy) /* was stdma_islocked */
466 goto retry;
467
468 status = FDC1772_READ(FDC1772REG_STATUS);
469
470 if (!(status & 0x80)) {
471 /*
472 * motor already turned off by FDC1772 -> deselect drives
473 * In actual fact its this deselection which turns the motor
474 * off on the Arc, since the motor control is actually on
475 * Latch A
476 */
477 DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));
478 fd_deselect();
479 MotorOn = 0;
480 restore_flags(flags);
481 return;
482 }
483 /* not yet off, try again */
484
485retry:
486 restore_flags(flags);
487 /* Test again later; if tested too often, it seems there is no disk
488 * in the drive and the FDC1772 will leave the motor on forever (or,
489 * at least until a disk is inserted). So we'll test only twice
490 * per second from then on...
491 */
492 delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
493 (++MotorOffTrys, HZ / 20) : HZ / 2;
494 START_MOTOR_OFF_TIMER(delay);
495}
496
497
498/* This function is repeatedly called to detect disk changes (as good
499 * as possible) and keep track of the current state of the write protection.
500 */
501
502static void check_change(unsigned long dummy)
503{
504 static int drive = 0;
505
506 unsigned long flags;
507 int stat;
508
509 if (fdc_busy)
510 return; /* Don't start poking about if the fdc is busy */
511
512 return; /* let's just forget it for the mo DAG */
513
514 if (++drive > 1 || !unit[drive].connected)
515 drive = 0;
516
517 save_flags(flags);
518 cli();
519
520 if (!stdma_islocked()) {
521 stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);
522
523 /* The idea here is that if the write protect line has changed then
524 the disc must have changed */
525 if (stat != unit[drive].wpstat) {
526 DPRINT(("wpstat[%d] = %d\n", drive, stat));
527 unit[drive].wpstat = stat;
528 set_bit(drive, &changed_floppies);
529 }
530 }
531 restore_flags(flags);
532
533 START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);
534}
535
536
537/* Handling of the Head Settling Flag: This flag should be set after each
538 * seek operation, because we don't use seeks with verify.
539 */
540
541static inline void set_head_settle_flag(void)
542{
543 HeadSettleFlag = FDC1772CMDADD_E;
544}
545
546static inline int get_head_settle_flag(void)
547{
548 int tmp = HeadSettleFlag;
549 HeadSettleFlag = 0;
550 return (tmp);
551}
552
553
554
555
556/* General Interrupt Handling */
557
558static inline void copy_buffer(void *from, void *to)
559{
560 ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
561 int cnt;
562
563 for (cnt = 512 / 4; cnt; cnt--)
564 *p2++ = *p1++;
565}
566
567static void (*FloppyIRQHandler) (int status) = NULL;
568
569static void floppy_irqconsequencehandler(void)
570{
571 unsigned char status;
572 void (*handler) (int);
573
574 fdc1772_fdc_int_done = 0;
575
576 handler = FloppyIRQHandler;
577 FloppyIRQHandler = NULL;
578
579 if (handler) {
580 nop();
581 status = (unsigned char) fdc1772_comendstatus;
582 DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));
583 handler(status);
584 } else {
585 DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));
586 }
587 DPRINT(("FDC1772 irq: end of floppy_irq\n"));
588}
589
590
591/* Error handling: If some error happened, retry some times, then
592 * recalibrate, then try again, and fail after MAX_ERRORS.
593 */
594
595static void fd_error(void)
596{
597 printk("FDC1772: fd_error\n");
598 /*panic("fd1772: fd_error"); *//* DAG tmp */
599 if (!CURRENT)
600 return;
601 CURRENT->errors++;
602 if (CURRENT->errors >= MAX_ERRORS) {
603 printk("fd%d: too many errors.\n", SelectedDrive);
604 end_request(CURRENT, 0);
605 } else if (CURRENT->errors == RECALIBRATE_ERRORS) {
606 printk("fd%d: recalibrating\n", SelectedDrive);
607 if (SelectedDrive != -1)
608 unit[SelectedDrive].track = -1;
609 }
610 redo_fd_request();
611}
612
613
614
615#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
616
617
618/* do_fd_action() is the general procedure for a fd request: All
619 * required parameter settings (drive select, side select, track
620 * position) are checked and set if needed. For each of these
621 * parameters and the actual reading or writing exist two functions:
622 * one that starts the setting (or skips it if possible) and one
623 * callback for the "done" interrupt. Each done func calls the next
624 * set function to propagate the request down to fd_rwsec_done().
625 */
626
627static void do_fd_action(int drive)
628{
629 struct request *req;
630 DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));
631
632#ifdef TRACKBUFFER
633repeat:
634
635 if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
636 req = CURRENT;
637 if (ReqCmd == READ) {
638 copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
639 if (++ReqCnt < req->current_nr_sectors) {
640 /* read next sector */
641 setup_req_params( drive );
642 goto repeat;
643 } else {
644 /* all sectors finished */
645 req->nr_sectors -= req->current_nr_sectors;
646 req->sector += req->current_nr_sectors;
647 end_request(req, 1);
648 redo_fd_request();
649 return;
650 }
651 } else {
652 /* cmd == WRITE, pay attention to track buffer
653 * consistency! */
654 copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
655 }
656 }
657#endif
658
659 if (SelectedDrive != drive) {
660 /*unit[drive].track = -1; DAG */
661 fd_select_drive(drive);
662 };
663
664
665 if (unit[drive].track == -1)
666 fd_calibrate();
667 else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
668 fd_seek();
669 else
670 fd_rwsec();
671}
672
673
674/* Seek to track 0 if the current track is unknown */
675
676static void fd_calibrate(void)
677{
678 DPRINT(("fd_calibrate\n"));
679 if (unit[SelectedDrive].track >= 0) {
680 fd_calibrate_done(0);
681 return;
682 }
683 DPRINT(("fd_calibrate (after track compare)\n"));
684 SET_IRQ_HANDLER(fd_calibrate_done);
685 /* we can't verify, since the speed may be incorrect */
686 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);
687
688 NeedSeek = 1;
689 MotorOn = 1;
690 START_TIMEOUT();
691 /* wait for IRQ */
692}
693
694
695static void fd_calibrate_done(int status)
696{
697 DPRINT(("fd_calibrate_done()\n"));
698 STOP_TIMEOUT();
699
700 /* set the correct speed now */
701 if (status & FDC1772STAT_RECNF) {
702 printk("fd%d: restore failed\n", SelectedDrive);
703 fd_error();
704 } else {
705 unit[SelectedDrive].track = 0;
706 fd_seek();
707 }
708}
709
710
711/* Seek the drive to the requested track. The drive must have been
712 * calibrated at some point before this.
713 */
714
715static void fd_seek(void)
716{
717 unsigned long flags;
718 DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
719 unit[SelectedDrive].track));
720 if (unit[SelectedDrive].track == ReqTrack <<
721 unit[SelectedDrive].disktype->stretch) {
722 fd_seek_done(0);
723 return;
724 }
725 FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
726 unit[SelectedDrive].disktype->stretch);
727 udelay(25);
728 save_flags(flags);
729 clf();
730 SET_IRQ_HANDLER(fd_seek_done);
731 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |
732 /* DAG */
733 (MotorOn?FDC1772CMDADD_H:0));
734
735 restore_flags(flags);
736 MotorOn = 1;
737 set_head_settle_flag();
738 START_TIMEOUT();
739 /* wait for IRQ */
740}
741
742
743static void fd_seek_done(int status)
744{
745 DPRINT(("fd_seek_done()\n"));
746 STOP_TIMEOUT();
747
748 /* set the correct speed */
749 if (status & FDC1772STAT_RECNF) {
750 printk("fd%d: seek error (to track %d)\n",
751 SelectedDrive, ReqTrack);
752 /* we don't know exactly which track we are on now! */
753 unit[SelectedDrive].track = -1;
754 fd_error();
755 } else {
756 unit[SelectedDrive].track = ReqTrack <<
757 unit[SelectedDrive].disktype->stretch;
758 NeedSeek = 0;
759 fd_rwsec();
760 }
761}
762
763
764/* This does the actual reading/writing after positioning the head
765 * over the correct track.
766 */
767
768#ifdef TRACKBUFFER
769static int MultReadInProgress = 0;
770#endif
771
772
773static void fd_rwsec(void)
774{
775 unsigned long paddr, flags;
776 unsigned int rwflag, old_motoron;
777 unsigned int track;
778
779 DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));
780 if (ReqCmd == WRITE) {
781 /*cache_push( (unsigned long)ReqData, 512 ); */
782 paddr = (unsigned long) ReqData;
783 rwflag = 0x100;
784 } else {
785 paddr = (unsigned long) PhysDMABuffer;
786#ifdef TRACKBUFFER
787 if (read_track)
788 paddr = (unsigned long)PhysTrackBuffer;
789#endif
790 rwflag = 0;
791 }
792
793 DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,
794 ReqSector, FDC1772_READ(FDC1772REG_TRACK)));
795 fd_select_side(ReqSide);
796
797 /*DPRINT(("fd_rwsec() before start sector \n")); */
798 /* Start sector of this operation */
799#ifdef TRACKBUFFER
800 FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );
801#else
802 FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );
803#endif
804
805 /* Cheat for track if stretch != 0 */
806 if (unit[SelectedDrive].disktype->stretch) {
807 track = FDC1772_READ(FDC1772REG_TRACK);
808 FDC1772_WRITE(FDC1772REG_TRACK, track >>
809 unit[SelectedDrive].disktype->stretch);
810 }
811 udelay(25);
812
813 DPRINT(("fd_rwsec() before setup DMA \n"));
814 /* Setup DMA - Heavily modified by DAG */
815 save_flags(flags);
816 clf();
817 disable_dma(FLOPPY_DMA);
818 set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);
819 set_dma_addr(FLOPPY_DMA, (long) paddr); /* DAG - changed from Atari specific */
820#ifdef TRACKBUFFER
821 set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);
822#else
823 set_dma_count(FLOPPY_DMA, 512); /* Block/sector size - going to have to change */
824#endif
825 SET_IRQ_HANDLER(fd_rwsec_done);
826 /* Turn on dma int */
827 enable_dma(FLOPPY_DMA);
828 /* Now give it something to do */
829 FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) :
830#ifdef TRACKBUFFER
831 (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) |
832 /* Hmm - the idea here is to stop the FDC spinning the disc
833 up when we know that we already still have it spinning */
834 (MotorOn?FDC1772CMDADD_H:0))
835#else
836 FDC1772CMD_RDSEC
837#endif
838 ));
839
840 restore_flags(flags);
841 DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));
842 /*sti(); *//* DAG - Hmm */
843 /* Hmm - should do something DAG */
844 old_motoron = MotorOn;
845 MotorOn = 1;
846 NeedSeek = 1;
847
848 /* wait for interrupt */
849
850#ifdef TRACKBUFFER
851 if (read_track) {
852 /*
853 * If reading a whole track, wait about one disk rotation and
854 * then check if all sectors are read. The FDC will even
855 * search for the first non-existant sector and need 1 sec to
856 * recognise that it isn't present :-(
857 */
858 /* 1 rot. + 5 rot.s if motor was off */
859 mod_timer(&readtrack_timer, jiffies + HZ/5 + (old_motoron ? 0 : HZ));
860 DPRINT(("Setting readtrack_timer to %d @ %d\n",
861 readtrack_timer.expires,jiffies));
862 MultReadInProgress = 1;
863 }
864#endif
865
866 /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */
867 START_TIMEOUT();
868 /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */
869}
870
871
872#ifdef TRACKBUFFER
873
874static void fd_readtrack_check(unsigned long dummy)
875{
876 unsigned long flags, addr;
877 extern unsigned char *fdc1772_dataaddr;
878
879 DPRINT(("fd_readtrack_check @ %d\n",jiffies));
880
881 save_flags(flags);
882 clf();
883
884 del_timer( &readtrack_timer );
885
886 if (!MultReadInProgress) {
887 /* This prevents a race condition that could arise if the
888 * interrupt is triggered while the calling of this timer
889 * callback function takes place. The IRQ function then has
890 * already cleared 'MultReadInProgress' when control flow
891 * gets here.
892 */
893 restore_flags(flags);
894 return;
895 }
896
897 /* get the current DMA address */
898 addr=(unsigned long)fdc1772_dataaddr; /* DAG - ? */
899 DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer));
900
901 if (addr >= (unsigned int)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
902 /* already read enough data, force an FDC interrupt to stop
903 * the read operation
904 */
905 SET_IRQ_HANDLER( NULL );
906 restore_flags(flags);
907 DPRINT(("fd_readtrack_check(): done\n"));
908 FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI );
909 udelay(25);
910
911 /* No error until now -- the FDC would have interrupted
912 * otherwise!
913 */
914 fd_rwsec_done( 0 );
915 } else {
916 /* not yet finished, wait another tenth rotation */
917 restore_flags(flags);
918 DPRINT(("fd_readtrack_check(): not yet finished\n"));
919 readtrack_timer.expires = jiffies + HZ/5/10;
920 add_timer( &readtrack_timer );
921 }
922}
923
924#endif
925
926static void fd_rwsec_done(int status)
927{
928 unsigned int track;
929
930 DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies));
931
932#ifdef TRACKBUFFER
933 if (read_track && !MultReadInProgress)
934 return;
935
936 MultReadInProgress = 0;
937
938 STOP_TIMEOUT();
939
940 if (read_track)
941 del_timer( &readtrack_timer );
942#endif
943
944
945 /* Correct the track if stretch != 0 */
946 if (unit[SelectedDrive].disktype->stretch) {
947 track = FDC1772_READ(FDC1772REG_TRACK);
948 FDC1772_WRITE(FDC1772REG_TRACK, track <<
949 unit[SelectedDrive].disktype->stretch);
950 }
951 if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) {
952 printk("fd%d: is write protected\n", SelectedDrive);
953 goto err_end;
954 }
955 if ((status & FDC1772STAT_RECNF)
956#ifdef TRACKBUFFER
957 /* RECNF is no error after a multiple read when the FDC
958 * searched for a non-existant sector!
959 */
960 && !(read_track &&
961 FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)
962#endif
963 ) {
964 if (Probing) {
965 if (unit[SelectedDrive].disktype > disk_type) {
966 /* try another disk type */
967 unit[SelectedDrive].disktype--;
968 set_capacity(disks[SelectedDrive],
969 unit[SelectedDrive].disktype->blocks);
970 } else
971 Probing = 0;
972 } else {
973 /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
974 if (unit[SelectedDrive].autoprobe) {
975 unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1;
976 set_capacity(disks[SelectedDrive],
977 unit[SelectedDrive].disktype->blocks);
978 Probing = 1;
979 }
980 }
981 if (Probing) {
982 setup_req_params(SelectedDrive);
983#ifdef TRACKBUFFER
984 BufferDrive = -1;
985#endif
986 do_fd_action(SelectedDrive);
987 return;
988 }
989 printk("fd%d: sector %d not found (side %d, track %d)\n",
990 SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack);
991 goto err_end;
992 }
993 if (status & FDC1772STAT_CRC) {
994 printk("fd%d: CRC error (side %d, track %d, sector %d)\n",
995 SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
996 goto err_end;
997 }
998 if (status & FDC1772STAT_LOST) {
999 printk("fd%d: lost data (side %d, track %d, sector %d)\n",
1000 SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
1001 goto err_end;
1002 }
1003 Probing = 0;
1004
1005 if (ReqCmd == READ) {
1006#ifdef TRACKBUFFER
1007 if (!read_track) {
1008 /*cache_clear (PhysDMABuffer, 512);*/
1009 copy_buffer (DMABuffer, ReqData);
1010 } else {
1011 /*cache_clear (PhysTrackBuffer, FD1772_MAX_SECTORS * 512);*/
1012 BufferDrive = SelectedDrive;
1013 BufferSide = ReqSide;
1014 BufferTrack = ReqTrack;
1015 copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
1016 }
1017#else
1018 /*cache_clear( PhysDMABuffer, 512 ); */
1019 copy_buffer(DMABuffer, ReqData);
1020#endif
1021 }
1022 if (++ReqCnt < CURRENT->current_nr_sectors) {
1023 /* read next sector */
1024 setup_req_params(SelectedDrive);
1025 do_fd_action(SelectedDrive);
1026 } else {
1027 /* all sectors finished */
1028 CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
1029 CURRENT->sector += CURRENT->current_nr_sectors;
1030 end_request(CURRENT, 1);
1031 redo_fd_request();
1032 }
1033 return;
1034
1035err_end:
1036#ifdef TRACKBUFFER
1037 BufferDrive = -1;
1038#endif
1039
1040 fd_error();
1041}
1042
1043
1044static void fd_times_out(unsigned long dummy)
1045{
1046 SET_IRQ_HANDLER(NULL);
1047 /* If the timeout occurred while the readtrack_check timer was
1048 * active, we need to cancel it, else bad things will happen */
1049 del_timer( &readtrack_timer );
1050 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1051 udelay(25);
1052
1053 printk("floppy timeout\n");
1054 STOP_TIMEOUT(); /* hmm - should we do this ? */
1055 fd_error();
1056}
1057
1058
1059/* The (noop) seek operation here is needed to make the WP bit in the
1060 * FDC1772 status register accessible for check_change. If the last disk
1061 * operation would have been a RDSEC, this bit would always read as 0
1062 * no matter what :-( To save time, the seek goes to the track we're
1063 * already on.
1064 */
1065
1066static void finish_fdc(void)
1067{
1068 /* DAG - just try without this dummy seek! */
1069 finish_fdc_done(0);
1070 return;
1071
1072 if (!NeedSeek) {
1073 finish_fdc_done(0);
1074 } else {
1075 DPRINT(("finish_fdc: dummy seek started\n"));
1076 FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track);
1077 SET_IRQ_HANDLER(finish_fdc_done);
1078 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
1079 MotorOn = 1;
1080 START_TIMEOUT();
1081 /* we must wait for the IRQ here, because the ST-DMA is
1082 * released immediately afterwards and the interrupt may be
1083 * delivered to the wrong driver.
1084 */
1085 }
1086}
1087
1088
1089static void finish_fdc_done(int dummy)
1090{
1091 unsigned long flags;
1092
1093 DPRINT(("finish_fdc_done entered\n"));
1094 STOP_TIMEOUT();
1095 NeedSeek = 0;
1096
1097 if (timer_pending(&fd_timer) &&
1098 time_after(jiffies + 5, fd_timer.expires))
1099 /* If the check for a disk change is done too early after this
1100 * last seek command, the WP bit still reads wrong :-((
1101 */
1102 mod_timer(&fd_timer, jiffies + 5);
1103 else {
1104 /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
1105 };
1106 del_timer(&motor_off_timer);
1107 START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
1108
1109 save_flags(flags);
1110 cli();
1111 /* stdma_release(); - not sure if I should do something DAG */
1112 fdc_busy = 0;
1113 wake_up(&fdc_wait);
1114 restore_flags(flags);
1115
1116 DPRINT(("finish_fdc() finished\n"));
1117}
1118
1119
1120/* Prevent "aliased" accesses. */
1121static int fd_ref[4];
1122static int fd_device[4];
1123
1124/* dummy for blk.h */
1125static void floppy_off(unsigned int nr)
1126{
1127}
1128
1129
1130/* On the old arcs write protect depends on the particular model
1131 of machine. On the A310, R140, and A440 there is a disc changed
1132 detect, however on the A4x0/1 range there is not. There
1133 is nothing to tell you which machine your on.
1134 At the moment I'm just marking changed always. I've
1135 left the Atari's 'change on write protect change' code in this
1136 part (but nothing sets it).
1137 RiscOS apparently checks the disc serial number etc. to detect changes
1138 - but if it sees a disc change line go high (?) it flips to using
1139 it. Well maybe I'll add that in the future (!?)
1140*/
1141static int check_floppy_change(struct gendisk *disk)
1142{
1143 struct archy_floppy_struct *p = disk->private_data;
1144 unsigned int drive = p - unit;
1145
1146 if (test_bit(drive, &fake_change)) {
1147 /* simulated change (e.g. after formatting) */
1148 return 1;
1149 }
1150 if (test_bit(drive, &changed_floppies)) {
1151 /* surely changed (the WP signal changed at least once) */
1152 return 1;
1153 }
1154 if (p->wpstat) {
1155 /* WP is on -> could be changed: to be sure, buffers should be
1156 * invalidated...
1157 */
1158 return 1;
1159 }
1160 return 1; /* DAG - was 0 */
1161}
1162
1163static int floppy_revalidate(struct gendisk *disk)
1164{
1165 struct archy_floppy_struct *p = disk->private_data;
1166 unsigned int drive = p - unit;
1167
1168 if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change)
1169 || unit[drive].disktype == 0) {
1170#ifdef TRACKBUFFER
1171 BufferDrive = -1;
1172#endif
1173 clear_bit(drive, &fake_change);
1174 clear_bit(drive, &changed_floppies);
1175 p->disktype = 0;
1176 }
1177 return 0;
1178}
1179
1180/* This sets up the global variables describing the current request. */
1181
1182static void setup_req_params(int drive)
1183{
1184 int block = ReqBlock + ReqCnt;
1185
1186 ReqTrack = block / unit[drive].disktype->spt;
1187 ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
1188 ReqSide = ReqTrack & 1;
1189 ReqTrack >>= 1;
1190 ReqData = ReqBuffer + 512 * ReqCnt;
1191
1192#ifdef TRACKBUFFER
1193 read_track = (ReqCmd == READ && CURRENT->errors == 0);
1194#endif
1195
1196 DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
1197 ReqTrack, ReqSector, (unsigned long) ReqData));
1198}
1199
1200
1201static void redo_fd_request(void)
1202{
1203 int drive, type;
1204 struct archy_floppy_struct *floppy;
1205
1206 DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",
1207 CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",
1208 CURRENT ? CURRENT->sector : 0));
1209
1210repeat:
1211
1212 if (!CURRENT)
1213 goto the_end;
1214
1215 floppy = CURRENT->rq_disk->private_data;
1216 drive = floppy - unit;
1217 type = fd_device[drive];
1218
1219 if (!floppy->connected) {
1220 /* drive not connected */
1221 printk("Unknown Device: fd%d\n", drive);
1222 end_request(CURRENT, 0);
1223 goto repeat;
1224 }
1225 if (type == 0) {
1226 if (!floppy->disktype) {
1227 Probing = 1;
1228 floppy->disktype = disk_type + NUM_DISK_TYPES - 1;
1229 set_capacity(disks[drive], floppy->disktype->blocks);
1230 floppy->autoprobe = 1;
1231 }
1232 } else {
1233 /* user supplied disk type */
1234 --type;
1235 if (type >= NUM_DISK_TYPES) {
1236 printk("fd%d: invalid disk format", drive);
1237 end_request(CURRENT, 0);
1238 goto repeat;
1239 }
1240 floppy->disktype = &disk_type[type];
1241 set_capacity(disks[drive], floppy->disktype->blocks);
1242 floppy->autoprobe = 0;
1243 }
1244
1245 if (CURRENT->sector + 1 > floppy->disktype->blocks) {
1246 end_request(CURRENT, 0);
1247 goto repeat;
1248 }
1249 /* stop deselect timer */
1250 del_timer(&motor_off_timer);
1251
1252 ReqCnt = 0;
1253 ReqCmd = CURRENT->cmd;
1254 ReqBlock = CURRENT->sector;
1255 ReqBuffer = CURRENT->buffer;
1256 setup_req_params(drive);
1257 do_fd_action(drive);
1258
1259 return;
1260
1261the_end:
1262 finish_fdc();
1263}
1264
1265static void fd1772_checkint(void)
1266{
1267 extern int fdc1772_bytestogo;
1268
1269 /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/
1270 if (fdc1772_fdc_int_done)
1271 floppy_irqconsequencehandler();
1272 if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0);
1273 if (fdc_busy) {
1274 schedule_work(&fd1772_tq);
1275 }
1276}
1277
1278static void do_fd_request(request_queue_t* q)
1279{
1280 unsigned long flags;
1281
1282 DPRINT(("do_fd_request for pid %d\n", current->pid));
1283 if (fdc_busy) return;
1284 save_flags(flags);
1285 cli();
1286 while (fdc_busy)
1287 sleep_on(&fdc_wait);
1288 fdc_busy = 1;
1289 ENABLE_IRQ();
1290 restore_flags(flags);
1291
1292 fdc1772_fdc_int_done = 0;
1293
1294 redo_fd_request();
1295
1296 schedule_work(&fd1772_tq);
1297}
1298
1299
1300static int invalidate_drive(struct block_device *bdev)
1301{
1302 struct archy_floppy_struct *p = bdev->bd_disk->private_data;
1303 /* invalidate the buffer track to force a reread */
1304#ifdef TRACKBUFFER
1305 BufferDrive = -1;
1306#endif
1307
1308 set_bit(p - unit, &fake_change);
1309 return 0;
1310}
1311
1312static int fd_ioctl(struct inode *inode, struct file *filp,
1313 unsigned int cmd, unsigned long param)
1314{
1315 struct block_device *bdev = inode->i_bdev;
1316
1317 switch (cmd) {
1318 case FDFMTEND:
1319 case FDFLUSH:
1320 invalidate_drive(bdev);
1321 check_disk_change(bdev);
1322 case FDFMTBEG:
1323 return 0;
1324 default:
1325 return -EINVAL;
1326 }
1327}
1328
1329
1330/* Initialize the 'unit' variable for drive 'drive' */
1331
1332static void fd_probe(int drive)
1333{
1334 unit[drive].connected = 0;
1335 unit[drive].disktype = NULL;
1336
1337 if (!fd_test_drive_present(drive))
1338 return;
1339
1340 unit[drive].connected = 1;
1341 unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */
1342 unit[drive].steprate = FDC1772STEP_6;
1343 MotorOn = 1; /* from probe restore operation! */
1344}
1345
1346
1347/* This function tests the physical presence of a floppy drive (not
1348 * whether a disk is inserted). This is done by issuing a restore
1349 * command, waiting max. 2 seconds (that should be enough to move the
1350 * head across the whole disk) and looking at the state of the "TR00"
1351 * signal. This should now be raised if there is a drive connected
1352 * (and there is no hardware failure :-) Otherwise, the drive is
1353 * declared absent.
1354 */
1355
1356static int fd_test_drive_present(int drive)
1357{
1358 unsigned long timeout;
1359 unsigned char status;
1360 int ok;
1361
1362 printk("fd_test_drive_present %d\n", drive);
1363 if (drive > 1)
1364 return (0);
1365 return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */
1366 fd_select_drive(drive);
1367
1368 /* disable interrupt temporarily */
1369 DISABLE_IRQ();
1370 FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */
1371 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
1372
1373 /*printk("fd_test_drive_present: Going into timeout loop\n"); */
1374 for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) {
1375 /* What does this piece of atariism do? - query for an interrupt? */
1376 /* if (!(mfp.par_dt_reg & 0x20))
1377 break; */
1378 /* Well this is my nearest guess - quit when we get an FDC interrupt */
1379 if (ioc_readb(IOC_FIQSTAT) & 2)
1380 break;
1381 }
1382
1383 /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */
1384 status = FDC1772_READ(FDC1772REG_STATUS);
1385 ok = (status & FDC1772STAT_TR00) != 0;
1386
1387 /*printk("fd_test_drive_present: ok=%d\n",ok); */
1388 /* force interrupt to abort restore operation (FDC1772 would try
1389 * about 50 seconds!) */
1390 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1391 udelay(500);
1392 status = FDC1772_READ(FDC1772REG_STATUS);
1393 udelay(20);
1394 /*printk("fd_test_drive_present: just before OK code %d\n",ok); */
1395
1396 if (ok) {
1397 /* dummy seek command to make WP bit accessible */
1398 FDC1772_WRITE(FDC1772REG_DATA, 0);
1399 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
1400 printk("fd_test_drive_present: just before wait for int\n");
1401 /* DAG: Guess means wait for interrupt */
1402 while (!(ioc_readb(IOC_FIQSTAT) & 2));
1403 printk("fd_test_drive_present: just after wait for int\n");
1404 status = FDC1772_READ(FDC1772REG_STATUS);
1405 }
1406 printk("fd_test_drive_present: just before ENABLE_IRQ\n");
1407 ENABLE_IRQ();
1408 printk("fd_test_drive_present: about to return\n");
1409 return (ok);
1410}
1411
1412
1413/* Look how many and which kind of drives are connected. If there are
1414 * floppies, additionally start the disk-change and motor-off timers.
1415 */
1416
1417static void config_types(void)
1418{
1419 int drive, cnt = 0;
1420
1421 printk("Probing floppy drive(s):\n");
1422 for (drive = 0; drive < FD_MAX_UNITS; drive++) {
1423 fd_probe(drive);
1424 if (unit[drive].connected) {
1425 printk("fd%d\n", drive);
1426 ++cnt;
1427 }
1428 }
1429
1430 if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) {
1431 /* If FDC1772 is still busy from probing, give it another FORCI
1432 * command to abort the operation. If this isn't done, the FDC1772
1433 * will interrupt later and its IRQ line stays low, because
1434 * the status register isn't read. And this will block any
1435 * interrupts on this IRQ line :-(
1436 */
1437 FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1438 udelay(500);
1439 FDC1772_READ(FDC1772REG_STATUS);
1440 udelay(20);
1441 }
1442 if (cnt > 0) {
1443 START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
1444 if (cnt == 1)
1445 fd_select_drive(0);
1446 /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
1447 }
1448}
1449
1450/*
1451 * floppy_open check for aliasing (/dev/fd0 can be the same as
1452 * /dev/PS0 etc), and disallows simultaneous access to the same
1453 * drive with different device numbers.
1454 */
1455
1456static int floppy_open(struct inode *inode, struct file *filp)
1457{
1458 int drive = iminor(inode) & 3;
1459 int type = iminor(inode) >> 2;
1460 int old_dev = fd_device[drive];
1461
1462 if (fd_ref[drive] && old_dev != type)
1463 return -EBUSY;
1464
1465 if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
1466 return -EBUSY;
1467
1468 if (filp->f_flags & O_EXCL)
1469 fd_ref[drive] = -1;
1470 else
1471 fd_ref[drive]++;
1472
1473 fd_device[drive] = type;
1474
1475 if (filp->f_flags & O_NDELAY)
1476 return 0;
1477
1478 if (filp->f_mode & 3) {
1479 check_disk_change(inode->i_bdev);
1480 if (filp->f_mode & 2) {
1481 if (unit[drive].wpstat) {
1482 floppy_release(inode, filp);
1483 return -EROFS;
1484 }
1485 }
1486 }
1487 return 0;
1488}
1489
1490
1491static int floppy_release(struct inode *inode, struct file *filp)
1492{
1493 int drive = iminor(inode) & 3;
1494
1495 if (fd_ref[drive] < 0)
1496 fd_ref[drive] = 0;
1497 else if (!fd_ref[drive]--) {
1498 printk("floppy_release with fd_ref == 0");
1499 fd_ref[drive] = 0;
1500 }
1501
1502 return 0;
1503}
1504
1505static struct block_device_operations floppy_fops =
1506{
1507 .open = floppy_open,
1508 .release = floppy_release,
1509 .ioctl = fd_ioctl,
1510 .media_changed = check_floppy_change,
1511 .revalidate_disk= floppy_revalidate,
1512};
1513
1514static struct kobject *floppy_find(dev_t dev, int *part, void *data)
1515{
1516 int drive = *part & 3;
1517 if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS)
1518 return NULL;
1519 *part = 0;
1520 return get_disk(disks[drive]);
1521}
1522
1523int fd1772_init(void)
1524{
1525 static DEFINE_SPINLOCK(lock);
1526 int i, err = -ENOMEM;
1527
1528 if (!machine_is_archimedes())
1529 return 0;
1530
1531 for (i = 0; i < FD_MAX_UNITS; i++) {
1532 disks[i] = alloc_disk(1);
1533 if (!disks[i])
1534 goto err_disk;
1535 }
1536
1537 err = register_blkdev(MAJOR_NR, "fd");
1538 if (err)
1539 goto err_disk;
1540
1541 err = -EBUSY;
1542 if (request_dma(FLOPPY_DMA, "fd1772")) {
1543 printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA);
1544 goto err_blkdev;
1545 };
1546
1547 if (request_dma(FIQ_FD1772, "fd1772 end")) {
1548 printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
1549 goto err_dma1;
1550 };
1551
1552 /* initialize variables */
1553 SelectedDrive = -1;
1554#ifdef TRACKBUFFER
1555 BufferDrive = BufferSide = BufferTrack = -1;
1556 /* Atari uses 512 - I want to eventually cope with 1K sectors */
1557 DMABuffer = (char *)kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
1558 TrackBuffer = DMABuffer + 512;
1559#else
1560 /* Allocate memory for the DMAbuffer - on the Atari this takes it
1561 out of some special memory... */
1562 DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */
1563#endif
1564 err = -ENOMEM;
1565 if (!DMAbuffer)
1566 goto err_dma2;
1567
1568 enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */
1569
1570 floppy_queue = blk_init_queue(do_fd_request, &lock);
1571 if (!floppy_queue)
1572 goto err_queue;
1573
1574 for (i = 0; i < FD_MAX_UNITS; i++) {
1575 unit[i].track = -1;
1576 disks[i]->major = MAJOR_NR;
1577 disks[i]->first_minor = 0;
1578 disks[i]->fops = &floppy_fops;
1579 sprintf(disks[i]->disk_name, "fd%d", i);
1580 disks[i]->private_data = &unit[i];
1581 disks[i]->queue = floppy_queue;
1582 set_capacity(disks[i], MAX_DISK_SIZE * 2);
1583 }
1584 blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
1585 floppy_find, NULL, NULL);
1586
1587 for (i = 0; i < FD_MAX_UNITS; i++)
1588 add_disk(disks[i]);
1589
1590 config_types();
1591
1592 return 0;
1593
1594 err_queue:
1595 kfree(DMAbuffer);
1596 err_dma2:
1597 free_dma(FIQ_FD1772);
1598
1599 err_dma1:
1600 free_dma(FLOPPY_DMA);
1601
1602 err_blkdev:
1603 unregister_blkdev(MAJOR_NR, "fd");
1604
1605 err_disk:
1606 while (i--)
1607 put_disk(disks[i]);
1608 return err;
1609}
diff --git a/drivers/acorn/block/fd1772dma.S b/drivers/acorn/block/fd1772dma.S
new file mode 100644
index 000000000000..7964435443ec
--- /dev/null
+++ b/drivers/acorn/block/fd1772dma.S
@@ -0,0 +1,100 @@
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
new file mode 100644
index 000000000000..c90cbd41ce21
--- /dev/null
+++ b/drivers/acorn/block/mfm.S
@@ -0,0 +1,162 @@
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
new file mode 100644
index 000000000000..4b65f74d66b1
--- /dev/null
+++ b/drivers/acorn/block/mfmhd.c
@@ -0,0 +1,1416 @@
1/*
2 * linux/arch/arm/drivers/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/config.h>
103#include <linux/sched.h>
104#include <linux/fs.h>
105#include <linux/interrupt.h>
106#include <linux/kernel.h>
107#include <linux/timer.h>
108#include <linux/mm.h>
109#include <linux/errno.h>
110#include <linux/genhd.h>
111#include <linux/major.h>
112#include <linux/ioport.h>
113#include <linux/delay.h>
114#include <linux/blkpg.h>
115
116#include <asm/system.h>
117#include <asm/io.h>
118#include <asm/irq.h>
119#include <asm/uaccess.h>
120#include <asm/dma.h>
121#include <asm/hardware.h>
122#include <asm/ecard.h>
123#include <asm/hardware/ioc.h>
124
125static void (*do_mfm)(void) = NULL;
126static struct request_queue *mfm_queue;
127static DEFINE_SPINLOCK(mfm_lock);
128
129#define MAJOR_NR MFM_ACORN_MAJOR
130#define QUEUE (mfm_queue)
131#define CURRENT elv_next_request(mfm_queue)
132/*
133 * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
134 */
135#ifndef HDIO_GETGEO
136#define HDIO_GETGEO 0x301
137struct hd_geometry {
138 unsigned char heads;
139 unsigned char sectors;
140 unsigned short cylinders;
141 unsigned long start;
142};
143#endif
144
145
146/*
147 * Configuration section
148 *
149 * This is the maximum number of drives that we accept
150 */
151#define MFM_MAXDRIVES 2
152/*
153 * Linux I/O address of onboard MFM controller or 0 to disable this
154 */
155#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
156/*
157 * Uncomment this to enable debugging in the MFM driver...
158 */
159#ifndef DEBUG
160/*#define DEBUG */
161#endif
162/*
163 * End of configuration
164 */
165
166
167/*
168 * This structure contains all information to do with a particular physical
169 * device.
170 */
171struct mfm_info {
172 unsigned char sectors;
173 unsigned char heads;
174 unsigned short cylinders;
175 unsigned short lowcurrent;
176 unsigned short precomp;
177#define NO_TRACK -1
178#define NEED_1_RECAL -2
179#define NEED_2_RECAL -3
180 int cylinder;
181 struct {
182 char recal;
183 char report;
184 char abort;
185 } errors;
186} mfm_info[MFM_MAXDRIVES];
187
188#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
189
190/* Stuff from the assembly routines */
191extern unsigned int hdc63463_baseaddress; /* Controller base address */
192extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */
193extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */
194extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */
195extern int hdc63463_dataleft; /* Number of bytes left to transfer */
196
197
198
199
200static int lastspecifieddrive;
201static unsigned Busy;
202
203static unsigned int PartFragRead; /* The number of sectors which have been read
204 during a partial read split over two
205 cylinders. If 0 it means a partial
206 read did not occur. */
207
208static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */
209static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */
210
211static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */
212static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */
213static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know
214 where to take over */
215static char *Copy_buffer;
216
217
218static void mfm_seek(void);
219static void mfm_rerequest(void);
220static void mfm_request(void);
221static void mfm_specify (void);
222static void issue_request(unsigned int block, unsigned int nsect,
223 struct request *req);
224
225static unsigned int mfm_addr; /* Controller address */
226static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */
227static unsigned int mfm_irqenable; /* Podule IRQ enable location */
228static unsigned char mfm_irq; /* Interrupt number */
229static int mfm_drives = 0; /* drives available */
230static int mfm_status = 0; /* interrupt status */
231static int *errors;
232
233static struct rawcmd {
234 unsigned int dev;
235 unsigned int cylinder;
236 unsigned int head;
237 unsigned int sector;
238 unsigned int cmdtype;
239 unsigned int cmdcode;
240 unsigned char cmddata[16];
241 unsigned int cmdlen;
242} raw_cmd;
243
244static unsigned char result[16];
245
246static struct cont {
247 void (*interrupt) (void); /* interrupt handler */
248 void (*error) (void); /* error handler */
249 void (*redo) (void); /* redo handler */
250 void (*done) (int st); /* done handler */
251} *cont = NULL;
252
253#if 0
254static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
255#endif
256
257int number_mfm_drives = 1;
258
259/* ------------------------------------------------------------------------------------------ */
260/*
261 * From the HD63463 data sheet from Hitachi Ltd.
262 */
263
264#define MFM_COMMAND (mfm_addr + 0)
265#define MFM_DATAOUT (mfm_addr + 1)
266#define MFM_STATUS (mfm_addr + 8)
267#define MFM_DATAIN (mfm_addr + 9)
268
269#define CMD_ABT 0xF0 /* Abort */
270#define CMD_SPC 0xE8 /* Specify */
271#define CMD_TST 0xE0 /* Test */
272#define CMD_RCLB 0xC8 /* Recalibrate */
273#define CMD_SEK 0xC0 /* Seek */
274#define CMD_WFS 0xAB /* Write Format Skew */
275#define CMD_WFM 0xA3 /* Write Format */
276#define CMD_MTB 0x90 /* Memory to buffer */
277#define CMD_CMPD 0x88 /* Compare data */
278#define CMD_WD 0x87 /* Write data */
279#define CMD_RED 0x70 /* Read erroneous data */
280#define CMD_RIS 0x68 /* Read ID skew */
281#define CMD_FID 0x61 /* Find ID */
282#define CMD_RID 0x60 /* Read ID */
283#define CMD_BTM 0x50 /* Buffer to memory */
284#define CMD_CKD 0x48 /* Check data */
285#define CMD_RD 0x40 /* Read data */
286#define CMD_OPBW 0x38 /* Open buffer write */
287#define CMD_OPBR 0x30 /* Open buffer read */
288#define CMD_CKV 0x28 /* Check drive */
289#define CMD_CKE 0x20 /* Check ECC */
290#define CMD_POD 0x18 /* Polling disable */
291#define CMD_POL 0x10 /* Polling enable */
292#define CMD_RCAL 0x08 /* Recall */
293
294#define STAT_BSY 0x8000 /* Busy */
295#define STAT_CPR 0x4000 /* Command Parameter Rejection */
296#define STAT_CED 0x2000 /* Command end */
297#define STAT_SED 0x1000 /* Seek end */
298#define STAT_DER 0x0800 /* Drive error */
299#define STAT_ABN 0x0400 /* Abnormal end */
300#define STAT_POL 0x0200 /* Polling */
301
302/* ------------------------------------------------------------------------------------------ */
303#ifdef DEBUG
304static void console_printf(const char *fmt,...)
305{
306 static char buffer[2048]; /* Arbitary! */
307 extern void console_print(const char *);
308 unsigned long flags;
309 va_list ap;
310
311 local_irq_save(flags);
312
313 va_start(ap, fmt);
314 vsprintf(buffer, fmt, ap);
315 console_print(buffer);
316 va_end(fmt);
317
318 local_irq_restore(flags);
319}; /* console_printf */
320
321#define DBG(x...) console_printf(x)
322#else
323#define DBG(x...)
324#endif
325
326static void print_status(void)
327{
328 char *error;
329 static char *errors[] = {
330 "no error",
331 "command aborted",
332 "invalid command",
333 "parameter error",
334 "not initialised",
335 "rejected TEST",
336 "no useld",
337 "write fault",
338 "not ready",
339 "no scp",
340 "in seek",
341 "invalid NCA",
342 "invalid step rate",
343 "seek error",
344 "over run",
345 "invalid PHA",
346 "data field EEC error",
347 "data field CRC error",
348 "error corrected",
349 "data field fatal error",
350 "no data am",
351 "not hit",
352 "ID field CRC error",
353 "time over",
354 "no ID am",
355 "not writable"
356 };
357 if (result[1] < 0x65)
358 error = errors[result[1] >> 2];
359 else
360 error = "unknown";
361 printk("(");
362 if (mfm_status & STAT_BSY) printk("BSY ");
363 if (mfm_status & STAT_CPR) printk("CPR ");
364 if (mfm_status & STAT_CED) printk("CED ");
365 if (mfm_status & STAT_SED) printk("SED ");
366 if (mfm_status & STAT_DER) printk("DER ");
367 if (mfm_status & STAT_ABN) printk("ABN ");
368 if (mfm_status & STAT_POL) printk("POL ");
369 printk(") SSB = %X (%s)\n", result[1], error);
370
371}
372
373/* ------------------------------------------------------------------------------------- */
374
375static void issue_command(int command, unsigned char *cmdb, int len)
376{
377 int status;
378#ifdef DEBUG
379 int i;
380 console_printf("issue_command: %02X: ", command);
381 for (i = 0; i < len; i++)
382 console_printf("%02X ", cmdb[i]);
383 console_printf("\n");
384#endif
385
386 do {
387 status = inw(MFM_STATUS);
388 } while (status & (STAT_BSY | STAT_POL));
389 DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
390
391 if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
392 outw(CMD_RCAL, MFM_COMMAND);
393 while (inw(MFM_STATUS) & STAT_BSY);
394 }
395 status = inw(MFM_STATUS);
396 DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
397
398 while (len > 0) {
399 outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
400 len -= 2;
401 cmdb += 2;
402 }
403 status = inw(MFM_STATUS);
404 DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
405
406 outw(command, MFM_COMMAND);
407 status = inw(MFM_STATUS);
408 DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8);
409}
410
411static void wait_for_completion(void)
412{
413 while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
414}
415
416static void wait_for_command_end(void)
417{
418 int i;
419
420 while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
421
422 for (i = 0; i < 16;) {
423 int in;
424 in = inw(MFM_DATAIN);
425 result[i++] = in >> 8;
426 result[i++] = in;
427 }
428 outw (CMD_RCAL, MFM_COMMAND);
429}
430
431/* ------------------------------------------------------------------------------------- */
432
433static void mfm_rw_intr(void)
434{
435 int old_status; /* Holds status on entry, we read to see if the command just finished */
436#ifdef DEBUG
437 console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
438 print_status();
439#endif
440
441 /* Now don't handle the error until BSY drops */
442 if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
443 /* Something has gone wrong - let's try that again */
444 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
445 if (cont) {
446 DBG("mfm_rw_intr: DER/ABN err\n");
447 cont->error();
448 cont->redo();
449 };
450 return;
451 };
452
453 /* OK so what ever happened it's not an error, now I reckon we are left between
454 a choice of command end or some data which is ready to be collected */
455 /* I think we have to transfer data while the interrupt line is on and its
456 not any other type of interrupt */
457 if (CURRENT->cmd == WRITE) {
458 extern void hdc63463_writedma(void);
459 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
460 printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
461 if (cont) {
462 cont->error();
463 cont->redo();
464 };
465 return;
466 };
467 hdc63463_writedma();
468 } else {
469 extern void hdc63463_readdma(void);
470 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
471 printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
472 if (cont) {
473 cont->error();
474 cont->redo();
475 };
476 return;
477 };
478 DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
479 hdc63463_readdma();
480 }; /* Read */
481
482 if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
483 /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
484 /* Ah - well looking at the status its just when we get command end; so no problem */
485 /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
486 hdc63463_dataptr,Copy_buffer+256);
487 print_status(); */
488 } else {
489 Sectors256LeftInCurrent--;
490 Copy_buffer += 256;
491 Copy_Sector++;
492
493 /* We have come to the end of this request */
494 if (!Sectors256LeftInCurrent) {
495 DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
496 CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
497
498 CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
499 CURRENT->sector += CURRENT->current_nr_sectors;
500 SectorsLeftInRequest -= CURRENT->current_nr_sectors;
501
502 end_request(CURRENT, 1);
503 if (SectorsLeftInRequest) {
504 hdc63463_dataptr = (unsigned int) CURRENT->buffer;
505 Copy_buffer = CURRENT->buffer;
506 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
507 errors = &(CURRENT->errors);
508 /* These should match the present calculations of the next logical sector
509 on the device
510 Copy_Sector=CURRENT->sector*2; */
511
512 if (Copy_Sector != CURRENT->sector * 2)
513#ifdef DEBUG
514 /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
515 Copy_Sector, CURRENT->sector * 2);
516#else
517 printk("mfm: Copy_Sector mismatch! Eek!\n");
518#endif
519 }; /* CURRENT */
520 }; /* Sectors256LeftInCurrent */
521 };
522
523 old_status = mfm_status;
524 mfm_status = inw(MFM_STATUS);
525 if (mfm_status & (STAT_DER | STAT_ABN)) {
526 /* Something has gone wrong - let's try that again */
527 if (cont) {
528 DBG("mfm_rw_intr: DER/ABN error\n");
529 cont->error();
530 cont->redo();
531 };
532 return;
533 };
534
535 /* If this code wasn't entered due to command_end but there is
536 now a command end we must read the command results out. If it was
537 entered like this then mfm_interrupt_handler would have done the
538 job. */
539 if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
540 ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
541 int len = 0;
542 while (len < 16) {
543 int in;
544 in = inw(MFM_DATAIN);
545 result[len++] = in >> 8;
546 result[len++] = in;
547 };
548 }; /* Result read */
549
550 /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
551
552 /* If end of command move on */
553 if (mfm_status & (STAT_CED)) {
554 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
555 /* End of command - trigger the next command */
556 if (cont) {
557 cont->done(1);
558 }
559 DBG("mfm_rw_intr: returned from cont->done\n");
560 } else {
561 /* Its going to generate another interrupt */
562 do_mfm = mfm_rw_intr;
563 };
564}
565
566static void mfm_setup_rw(void)
567{
568 DBG("setting up for rw...\n");
569
570 do_mfm = mfm_rw_intr;
571 issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
572}
573
574static void mfm_recal_intr(void)
575{
576#ifdef DEBUG
577 console_printf("recal intr - status = ");
578 print_status();
579#endif
580 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
581 if (mfm_status & (STAT_DER | STAT_ABN)) {
582 printk("recal failed\n");
583 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
584 if (cont) {
585 cont->error();
586 cont->redo();
587 }
588 return;
589 }
590 /* Thats seek end - we are finished */
591 if (mfm_status & STAT_SED) {
592 issue_command(CMD_POD, NULL, 0);
593 MFM_DRV_INFO.cylinder = 0;
594 mfm_seek();
595 return;
596 }
597 /* Command end without seek end (see data sheet p.20) for parallel seek
598 - we have to send a POL command to wait for the seek */
599 if (mfm_status & STAT_CED) {
600 do_mfm = mfm_recal_intr;
601 issue_command(CMD_POL, NULL, 0);
602 return;
603 }
604 printk("recal: unknown status\n");
605}
606
607static void mfm_seek_intr(void)
608{
609#ifdef DEBUG
610 console_printf("seek intr - status = ");
611 print_status();
612#endif
613 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
614 if (mfm_status & (STAT_DER | STAT_ABN)) {
615 printk("seek failed\n");
616 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
617 if (cont) {
618 cont->error();
619 cont->redo();
620 }
621 return;
622 }
623 if (mfm_status & STAT_SED) {
624 issue_command(CMD_POD, NULL, 0);
625 MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
626 mfm_seek();
627 return;
628 }
629 if (mfm_status & STAT_CED) {
630 do_mfm = mfm_seek_intr;
631 issue_command(CMD_POL, NULL, 0);
632 return;
633 }
634 printk("seek: unknown status\n");
635}
636
637/* IDEA2 seems to work better - its what RiscOS sets my
638 * disc to - on its SECOND call to specify!
639 */
640#define IDEA2
641#ifndef IDEA2
642#define SPEC_SL 0x16
643#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */
644#else
645#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */
646#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */
647#endif
648
649static void mfm_setupspecify (int drive, unsigned char *cmdb)
650{
651 cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
652 cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
653 cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */
654 cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */
655 cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
656 cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */
657 cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */
658 cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */
659 cmdb[8] = SPEC_SH;
660 cmdb[9] = 0x0a; /* gap length 1 */
661 cmdb[10] = 0x0d; /* gap length 2 */
662 cmdb[11] = 0x0c; /* gap length 3 */
663 cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */
664 cmdb[13] = mfm_info[drive].precomp - 1;
665 cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */
666 cmdb[15] = mfm_info[drive].lowcurrent - 1;
667}
668
669static void mfm_specify (void)
670{
671 unsigned char cmdb[16];
672
673 DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
674 mfm_setupspecify (raw_cmd.dev, cmdb);
675
676 issue_command (CMD_SPC, cmdb, 16);
677 /* Ensure that we will do another specify if we move to the other drive */
678 lastspecifieddrive = raw_cmd.dev;
679 wait_for_completion();
680}
681
682static void mfm_seek(void)
683{
684 unsigned char cmdb[4];
685
686 DBG("seeking...\n");
687 if (MFM_DRV_INFO.cylinder < 0) {
688 do_mfm = mfm_recal_intr;
689 DBG("mfm_seek: about to call specify\n");
690 mfm_specify (); /* DAG added this */
691
692 cmdb[0] = raw_cmd.dev + 1;
693 cmdb[1] = 0;
694
695 issue_command(CMD_RCLB, cmdb, 2);
696 return;
697 }
698 if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
699 cmdb[0] = raw_cmd.dev + 1;
700 cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */
701 cmdb[2] = raw_cmd.cylinder >> 8;
702 cmdb[3] = raw_cmd.cylinder;
703
704 do_mfm = mfm_seek_intr;
705 issue_command(CMD_SEK, cmdb, 4);
706 } else
707 mfm_setup_rw();
708}
709
710static void mfm_initialise(void)
711{
712 DBG("init...\n");
713 mfm_seek();
714}
715
716static void request_done(int uptodate)
717{
718 DBG("mfm:request_done\n");
719 if (uptodate) {
720 unsigned char block[2] = {0, 0};
721
722 /* Apparently worked - let's check bytes left to DMA */
723 if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
724 printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
725 end_request(CURRENT, 0);
726 Busy = 0;
727 };
728 /* Potentially this means that we've done; but we might be doing
729 a partial access, (over two cylinders) or we may have a number
730 of fragments in an image file. First let's deal with partial accesss
731 */
732 if (PartFragRead) {
733 /* Yep - a partial access */
734
735 /* and issue the remainder */
736 issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
737 return;
738 }
739
740 /* ah well - perhaps there is another fragment to go */
741
742 /* Increment pointers/counts to start of next fragment */
743 if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
744
745 /* No - its the end of the line */
746 /* end_request's should have happened at the end of sector DMAs */
747 /* Turns Drive LEDs off - may slow it down? */
748 if (!elv_next_request(QUEUE))
749 issue_command(CMD_CKV, block, 2);
750
751 Busy = 0;
752 DBG("request_done: About to mfm_request\n");
753 /* Next one please */
754 mfm_request(); /* Moved from mfm_rw_intr */
755 DBG("request_done: returned from mfm_request\n");
756 } else {
757 printk("mfm:request_done: update=0\n");
758 end_request(CURRENT, 0);
759 Busy = 0;
760 }
761}
762
763static void error_handler(void)
764{
765 printk("error detected... status = ");
766 print_status();
767 (*errors)++;
768 if (*errors > MFM_DRV_INFO.errors.abort)
769 cont->done(0);
770 if (*errors > MFM_DRV_INFO.errors.recal)
771 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
772}
773
774static void rw_interrupt(void)
775{
776 printk("rw_interrupt\n");
777}
778
779static struct cont rw_cont =
780{
781 rw_interrupt,
782 error_handler,
783 mfm_rerequest,
784 request_done
785};
786
787/*
788 * Actually gets round to issuing the request - note everything at this
789 * point is in 256 byte sectors not Linux 512 byte blocks
790 */
791static void issue_request(unsigned int block, unsigned int nsect,
792 struct request *req)
793{
794 struct gendisk *disk = req->rq_disk;
795 struct mfm_info *p = disk->private_data;
796 int track, start_head, start_sector;
797 int sectors_to_next_cyl;
798 dev = p - mfm_info;
799
800 track = block / p->sectors;
801 start_sector = block % p->sectors;
802 start_head = track % p->heads;
803
804 /* First get the number of whole tracks which are free before the next
805 track */
806 sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;
807 /* Then add in the number of sectors left on this track */
808 sectors_to_next_cyl += (p->sectors - start_sector);
809
810 DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);
811
812 raw_cmd.dev = dev;
813 raw_cmd.sector = start_sector;
814 raw_cmd.head = start_head;
815 raw_cmd.cylinder = track / p->heads;
816 raw_cmd.cmdtype = CURRENT->cmd;
817 raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
818 raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */
819 raw_cmd.cmddata[1] = raw_cmd.head;
820 raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
821 raw_cmd.cmddata[3] = raw_cmd.cylinder;
822 raw_cmd.cmddata[4] = raw_cmd.head;
823 raw_cmd.cmddata[5] = raw_cmd.sector;
824
825 /* Was == and worked - how the heck??? */
826 if (lastspecifieddrive != raw_cmd.dev)
827 mfm_specify ();
828
829 if (nsect <= sectors_to_next_cyl) {
830 raw_cmd.cmddata[6] = nsect >> 8;
831 raw_cmd.cmddata[7] = nsect;
832 PartFragRead = 0; /* All in one */
833 PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */
834 } else {
835 raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
836 raw_cmd.cmddata[7] = sectors_to_next_cyl;
837 PartFragRead = sectors_to_next_cyl; /* only do this many this time */
838 PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */
839 PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
840 }
841 raw_cmd.cmdlen = 8;
842
843 /* Setup DMA pointers */
844 hdc63463_dataptr = (unsigned int) Copy_buffer;
845 hdc63463_dataleft = nsect * 256; /* Better way? */
846
847 DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
848 raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
849 raw_cmd.cylinder,
850 raw_cmd.head,
851 raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
852
853 cont = &rw_cont;
854 errors = &(CURRENT->errors);
855#if 0
856 mfm_tq.routine = (void (*)(void *)) mfm_initialise;
857 queue_task(&mfm_tq, &tq_immediate);
858 mark_bh(IMMEDIATE_BH);
859#else
860 mfm_initialise();
861#endif
862} /* issue_request */
863
864/*
865 * Called when an error has just happened - need to trick mfm_request
866 * into thinking we weren't busy
867 *
868 * Turn off ints - mfm_request expects them this way
869 */
870static void mfm_rerequest(void)
871{
872 DBG("mfm_rerequest\n");
873 cli();
874 Busy = 0;
875 mfm_request();
876}
877
878static struct gendisk *mfm_gendisk[2];
879
880static void mfm_request(void)
881{
882 DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
883
884 /* If we are still processing then return; we will get called again */
885 if (Busy) {
886 /* Again seems to be common in 1.3.45 */
887 /*DBG*/printk("mfm_request: Exiting due to busy\n");
888 return;
889 }
890 Busy = 1;
891
892 while (1) {
893 unsigned int block, nsect;
894 struct gendisk *disk;
895
896 DBG("mfm_request: loop start\n");
897 sti();
898
899 DBG("mfm_request: before !CURRENT\n");
900
901 if (!CURRENT) {
902 printk("mfm_request: Exiting due to empty queue (pre)\n");
903 do_mfm = NULL;
904 Busy = 0;
905 return;
906 }
907
908 DBG("mfm_request: before arg extraction\n");
909
910 disk = CURRENT->rq_disk;
911 block = CURRENT->sector;
912 nsect = CURRENT->nr_sectors;
913 if (block >= get_capacity(disk) ||
914 block+nsect > get_capacity(disk)) {
915 printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",
916 disk->disk_name, block, nsect, get_capacity(disk));
917 printk("mfm: continue 1\n");
918 end_request(CURRENT, 0);
919 Busy = 0;
920 continue;
921 }
922
923 /* DAG: Linux doesn't cope with this - even though it has an array telling
924 it the hardware block size - silly */
925 block <<= 1; /* Now in 256 byte sectors */
926 nsect <<= 1; /* Ditto */
927
928 SectorsLeftInRequest = nsect >> 1;
929 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
930 Copy_buffer = CURRENT->buffer;
931 Copy_Sector = CURRENT->sector << 1;
932
933 DBG("mfm_request: block after offset=%d\n", block);
934
935 if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
936 printk("unknown mfm-command %d\n", CURRENT->cmd);
937 end_request(CURRENT, 0);
938 Busy = 0;
939 printk("mfm: continue 4\n");
940 continue;
941 }
942 issue_request(block, nsect, CURRENT);
943
944 break;
945 }
946 DBG("mfm_request: Dropping out bottom\n");
947}
948
949static void do_mfm_request(request_queue_t *q)
950{
951 DBG("do_mfm_request: about to mfm_request\n");
952 mfm_request();
953}
954
955static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
956{
957 void (*handler) (void) = do_mfm;
958
959 do_mfm = NULL;
960
961 DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
962
963 mfm_status = inw(MFM_STATUS);
964
965 /* If CPR (Command Parameter Reject) and not busy it means that the command
966 has some return message to give us */
967 if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
968 int len = 0;
969 while (len < 16) {
970 int in;
971 in = inw(MFM_DATAIN);
972 result[len++] = in >> 8;
973 result[len++] = in;
974 }
975 }
976 if (handler) {
977 handler();
978 return;
979 }
980 outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
981 printk ("mfm: unexpected interrupt - status = ");
982 print_status ();
983 while (1);
984}
985
986
987
988
989
990/*
991 * Tell the user about the drive if we decided it exists.
992 */
993static void mfm_geometry(int drive)
994{
995 struct mfm_info *p = mfm_info + drive;
996 struct gendisk *disk = mfm_gendisk[drive];
997 disk->private_data = p;
998 if (p->cylinders)
999 printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
1000 disk->disk_name,
1001 p->cylinders * p->heads * p->sectors / 4096,
1002 p->cylinders, p->heads, p->sectors,
1003 p->lowcurrent, p->precomp);
1004 set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);
1005}
1006
1007#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1008/*
1009 * Attempt to detect a drive and find its geometry. The drive has already been
1010 * specified...
1011 *
1012 * We first recalibrate the disk, then try to probe sectors, heads and then
1013 * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver
1014 * does something along these lines, so I assume that most drives are up to
1015 * this mistreatment...
1016 */
1017static int mfm_detectdrive (int drive)
1018{
1019 unsigned int mingeo[3], maxgeo[3];
1020 unsigned int attribute, need_recal = 1;
1021 unsigned char cmdb[8];
1022
1023 memset (mingeo, 0, sizeof (mingeo));
1024 maxgeo[0] = mfm_info[drive].sectors;
1025 maxgeo[1] = mfm_info[drive].heads;
1026 maxgeo[2] = mfm_info[drive].cylinders;
1027
1028 cmdb[0] = drive + 1;
1029 cmdb[6] = 0;
1030 cmdb[7] = 1;
1031 for (attribute = 0; attribute < 3; attribute++) {
1032 while (mingeo[attribute] != maxgeo[attribute]) {
1033 unsigned int variable;
1034
1035 variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
1036 cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
1037
1038 if (need_recal) {
1039 int tries = 5;
1040
1041 do {
1042 issue_command (CMD_RCLB, cmdb, 2);
1043 wait_for_completion ();
1044 wait_for_command_end ();
1045 if (result[1] == 0x20)
1046 break;
1047 } while (result[1] && --tries);
1048 if (result[1]) {
1049 outw (CMD_RCAL, MFM_COMMAND);
1050 return 0;
1051 }
1052 need_recal = 0;
1053 }
1054
1055 switch (attribute) {
1056 case 0:
1057 cmdb[5] = variable;
1058 issue_command (CMD_CMPD, cmdb, 8);
1059 break;
1060 case 1:
1061 cmdb[1] = variable;
1062 cmdb[4] = variable;
1063 issue_command (CMD_CMPD, cmdb, 8);
1064 break;
1065 case 2:
1066 cmdb[2] = variable >> 8;
1067 cmdb[3] = variable;
1068 issue_command (CMD_SEK, cmdb, 4);
1069 break;
1070 }
1071 wait_for_completion ();
1072 wait_for_command_end ();
1073
1074 switch (result[1]) {
1075 case 0x00:
1076 case 0x50:
1077 mingeo[attribute] = variable + 1;
1078 break;
1079
1080 case 0x20:
1081 outw (CMD_RCAL, MFM_COMMAND);
1082 return 0;
1083
1084 case 0x24:
1085 need_recal = 1;
1086 default:
1087 maxgeo[attribute] = variable;
1088 break;
1089 }
1090 }
1091 }
1092 mfm_info[drive].cylinders = mingeo[2];
1093 mfm_info[drive].lowcurrent = mingeo[2];
1094 mfm_info[drive].precomp = mingeo[2] / 2;
1095 mfm_info[drive].heads = mingeo[1];
1096 mfm_info[drive].sectors = mingeo[0];
1097 outw (CMD_RCAL, MFM_COMMAND);
1098 return 1;
1099}
1100#endif
1101
1102/*
1103 * Initialise all drive information for this controller.
1104 */
1105static int mfm_initdrives(void)
1106{
1107 int drive;
1108
1109 if (number_mfm_drives > MFM_MAXDRIVES) {
1110 number_mfm_drives = MFM_MAXDRIVES;
1111 printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
1112 }
1113
1114 for (drive = 0; drive < number_mfm_drives; drive++) {
1115 mfm_info[drive].lowcurrent = 1;
1116 mfm_info[drive].precomp = 1;
1117 mfm_info[drive].cylinder = -1;
1118 mfm_info[drive].errors.recal = 0;
1119 mfm_info[drive].errors.report = 0;
1120 mfm_info[drive].errors.abort = 4;
1121
1122#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1123 mfm_info[drive].cylinders = 1024;
1124 mfm_info[drive].heads = 8;
1125 mfm_info[drive].sectors = 64;
1126 {
1127 unsigned char cmdb[16];
1128
1129 mfm_setupspecify (drive, cmdb);
1130 cmdb[1] &= ~0x81;
1131 issue_command (CMD_SPC, cmdb, 16);
1132 wait_for_completion ();
1133 if (!mfm_detectdrive (drive)) {
1134 mfm_info[drive].cylinders = 0;
1135 mfm_info[drive].heads = 0;
1136 mfm_info[drive].sectors = 0;
1137 }
1138 cmdb[0] = cmdb[1] = 0;
1139 issue_command (CMD_CKV, cmdb, 2);
1140 }
1141#else
1142 mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */
1143 mfm_info[drive].heads = 4;
1144 mfm_info[drive].sectors = 32;
1145#endif
1146 }
1147 return number_mfm_drives;
1148}
1149
1150
1151
1152/*
1153 * The 'front' end of the mfm driver follows...
1154 */
1155
1156static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
1157{
1158 struct mfm_info *p = inode->i_bdev->bd_disk->private_data;
1159 struct hd_geometry *geo = (struct hd_geometry *) arg;
1160 if (cmd != HDIO_GETGEO)
1161 return -EINVAL;
1162 if (!arg)
1163 return -EINVAL;
1164 if (put_user (p->heads, &geo->heads))
1165 return -EFAULT;
1166 if (put_user (p->sectors, &geo->sectors))
1167 return -EFAULT;
1168 if (put_user (p->cylinders, &geo->cylinders))
1169 return -EFAULT;
1170 if (put_user (get_start_sect(inode->i_bdev), &geo->start))
1171 return -EFAULT;
1172 return 0;
1173}
1174
1175/*
1176 * This is to handle various kernel command line parameters
1177 * specific to this driver.
1178 */
1179void mfm_setup(char *str, int *ints)
1180{
1181 return;
1182}
1183
1184/*
1185 * Set the CHS from the ADFS boot block if it is present. This is not ideal
1186 * since if there are any non-ADFS partitions on the disk, this won't work!
1187 * Hence, I want to get rid of this...
1188 */
1189void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
1190 unsigned char heads, unsigned int secsize)
1191{
1192 struct mfm_info *p = bdev->bd_disk->private_data;
1193 int drive = p - mfm_info;
1194 unsigned long disksize = bdev->bd_inode->i_size;
1195
1196 if (p->cylinders == 1) {
1197 p->sectors = secsptrack;
1198 p->heads = heads;
1199 p->cylinders = discsize / (secsptrack * heads * secsize);
1200
1201 if ((heads < 1) || (p->cylinders > 1024)) {
1202 printk("%s: Insane disc shape! Setting to 512/4/32\n",
1203 bdev->bd_disk->disk_name);
1204
1205 /* These values are fairly arbitary, but are there so that if your
1206 * lucky you can pick apart your disc to find out what is going on -
1207 * I reckon these figures won't hurt MOST drives
1208 */
1209 p->sectors = 32;
1210 p->heads = 4;
1211 p->cylinders = 512;
1212 }
1213 if (raw_cmd.dev == drive)
1214 mfm_specify ();
1215 mfm_geometry (drive);
1216 }
1217}
1218
1219static struct block_device_operations mfm_fops =
1220{
1221 .owner = THIS_MODULE,
1222 .ioctl = mfm_ioctl,
1223};
1224
1225/*
1226 * See if there is a controller at the address presently at mfm_addr
1227 *
1228 * We check to see if the controller is busy - if it is, we abort it first,
1229 * and check that the chip is no longer busy after at least 180 clock cycles.
1230 * We then issue a command and check that the BSY or CPR bits are set.
1231 */
1232static int mfm_probecontroller (unsigned int mfm_addr)
1233{
1234 if (inw (MFM_STATUS) & STAT_BSY) {
1235 outw (CMD_ABT, MFM_COMMAND);
1236 udelay (50);
1237 if (inw (MFM_STATUS) & STAT_BSY)
1238 return 0;
1239 }
1240
1241 if (inw (MFM_STATUS) & STAT_CED)
1242 outw (CMD_RCAL, MFM_COMMAND);
1243
1244 outw (CMD_SEK, MFM_COMMAND);
1245
1246 if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
1247 unsigned int count = 2000;
1248 while (inw (MFM_STATUS) & STAT_BSY) {
1249 udelay (500);
1250 if (!--count)
1251 return 0;
1252 }
1253
1254 outw (CMD_RCAL, MFM_COMMAND);
1255 }
1256 return 1;
1257}
1258
1259static int mfm_do_init(unsigned char irqmask)
1260{
1261 int i, ret;
1262
1263 printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
1264
1265 ret = -EBUSY;
1266 if (!request_region (mfm_addr, 10, "mfm"))
1267 goto out1;
1268
1269 ret = register_blkdev(MAJOR_NR, "mfm");
1270 if (ret)
1271 goto out2;
1272
1273 /* Stuff for the assembler routines to get to */
1274 hdc63463_baseaddress = ioaddr(mfm_addr);
1275 hdc63463_irqpolladdress = mfm_IRQPollLoc;
1276 hdc63463_irqpollmask = irqmask;
1277
1278 mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);
1279 if (!mfm_queue)
1280 goto out2a;
1281
1282 Busy = 0;
1283 lastspecifieddrive = -1;
1284
1285 mfm_drives = mfm_initdrives();
1286 if (!mfm_drives) {
1287 ret = -ENODEV;
1288 goto out3;
1289 }
1290
1291 for (i = 0; i < mfm_drives; i++) {
1292 struct gendisk *disk = alloc_disk(64);
1293 if (!disk)
1294 goto Enomem;
1295 disk->major = MAJOR_NR;
1296 disk->first_minor = i << 6;
1297 disk->fops = &mfm_fops;
1298 sprintf(disk->disk_name, "mfm%c", 'a'+i);
1299 mfm_gendisk[i] = disk;
1300 }
1301
1302 printk("mfm: detected %d hard drive%s\n", mfm_drives,
1303 mfm_drives == 1 ? "" : "s");
1304 ret = request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL);
1305 if (ret) {
1306 printk("mfm: unable to get IRQ%d\n", mfm_irq);
1307 goto out4;
1308 }
1309
1310 if (mfm_irqenable)
1311 outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */
1312
1313 for (i = 0; i < mfm_drives; i++) {
1314 mfm_geometry(i);
1315 mfm_gendisk[i]->queue = mfm_queue;
1316 add_disk(mfm_gendisk[i]);
1317 }
1318 return 0;
1319
1320out4:
1321 for (i = 0; i < mfm_drives; i++)
1322 put_disk(mfm_gendisk[i]);
1323out3:
1324 blk_cleanup_queue(mfm_queue);
1325out2a:
1326 unregister_blkdev(MAJOR_NR, "mfm");
1327out2:
1328 release_region(mfm_addr, 10);
1329out1:
1330 return ret;
1331Enomem:
1332 while (i--)
1333 put_disk(mfm_gendisk[i]);
1334 goto out3;
1335}
1336
1337static void mfm_do_exit(void)
1338{
1339 int i;
1340
1341 free_irq(mfm_irq, NULL);
1342 for (i = 0; i < mfm_drives; i++) {
1343 del_gendisk(mfm_gendisk[i]);
1344 put_disk(mfm_gendisk[i]);
1345 }
1346 blk_cleanup_queue(mfm_queue);
1347 unregister_blkdev(MAJOR_NR, "mfm");
1348 if (mfm_addr)
1349 release_region(mfm_addr, 10);
1350}
1351
1352static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id)
1353{
1354 if (mfm_addr)
1355 return -EBUSY;
1356
1357 mfm_addr = ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;
1358 mfm_IRQPollLoc = ioaddr(mfm_addr + 0x400);
1359 mfm_irqenable = mfm_IRQPollLoc;
1360 mfm_irq = ec->irq;
1361
1362 return mfm_do_init(0x08);
1363}
1364
1365static void __devexit mfm_remove(struct expansion_card *ec)
1366{
1367 outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */
1368 mfm_do_exit();
1369}
1370
1371static const struct ecard_id mfm_cids[] = {
1372 { MANU_ACORN, PROD_ACORN_MFM },
1373 { 0xffff, 0xffff },
1374};
1375
1376static struct ecard_driver mfm_driver = {
1377 .probe = mfm_probe,
1378 .remove = __devexit(mfm_remove),
1379 .id_table = mfm_cids,
1380 .drv = {
1381 .name = "mfm",
1382 },
1383};
1384
1385/*
1386 * Look for a MFM controller - first check the motherboard, then the podules
1387 * The podules have an extra interrupt enable that needs to be played with
1388 *
1389 * The HDC is accessed at MEDIUM IOC speeds.
1390 */
1391static int __init mfm_init (void)
1392{
1393 unsigned char irqmask;
1394
1395 if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
1396 mfm_addr = ONBOARD_MFM_ADDRESS;
1397 mfm_IRQPollLoc = IOC_IRQSTATB;
1398 mfm_irqenable = 0;
1399 mfm_irq = IRQ_HARDDISK;
1400 return mfm_do_init(0x08); /* IL3 pin */
1401 } else {
1402 return ecard_register_driver(&mfm_driver);
1403 }
1404}
1405
1406static void __exit mfm_exit(void)
1407{
1408 if (mfm_addr == ONBOARD_MFM_ADDRESS)
1409 mfm_do_exit();
1410 else
1411 ecard_unregister_driver(&mfm_driver);
1412}
1413
1414module_init(mfm_init)
1415module_exit(mfm_exit)
1416MODULE_LICENSE("GPL");
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
new file mode 100644
index 000000000000..2fa9a8bf48a0
--- /dev/null
+++ b/drivers/acorn/char/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for the acorn character device drivers.
3#
4
5obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o
6obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o
diff --git a/drivers/acorn/char/defkeymap-l7200.c b/drivers/acorn/char/defkeymap-l7200.c
new file mode 100644
index 000000000000..9e18ce742e38
--- /dev/null
+++ b/drivers/acorn/char/defkeymap-l7200.c
@@ -0,0 +1,386 @@
1/*
2 * linux/drivers/acorn/char/defkeymap-l7200.c
3 *
4 * Default keyboard maps for LinkUp Systems L7200 board
5 *
6 * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
7 *
8 * Changelog:
9 * 08-04-2000 SJH Created file
10 */
11
12#include <linux/types.h>
13#include <linux/keyboard.h>
14#include <linux/kd.h>
15
16/* Normal (maps 1:1 with no processing) */
17#define KTn 0xF0
18/* Function keys */
19#define KTf 0xF1
20/* Special (Performs special house-keeping funcs) */
21#define KTs 0xF2
22#define KIGNORE K(KTs, 0) /* Ignore */
23#define KENTER K(KTs, 1) /* Enter */
24#define KREGS K(KTs, 2) /* Regs */
25#define KMEM K(KTs, 3) /* Mem */
26#define KSTAT K(KTs, 4) /* State */
27#define KINTR K(KTs, 5) /* Intr */
28#define Ksl 6 /* Last console */
29#define KCAPSLK K(KTs, 7) /* Caps lock */
30#define KNUMLK K(KTs, 8) /* Num-lock */
31#define KSCRLLK K(KTs, 9) /* Scroll-lock */
32#define KSCRLFOR K(KTs,10) /* Scroll forward */
33#define KSCRLBAK K(KTs,11) /* Scroll back */
34#define KREBOOT K(KTs,12) /* Reboot */
35#define KCAPSON K(KTs,13) /* Caps on */
36#define KCOMPOSE K(KTs,14) /* Compose */
37#define KSAK K(KTs,15) /* SAK */
38#define CONS_DEC K(KTs,16) /* Dec console */
39#define CONS_INC K(KTs,17) /* Incr console */
40#define KFLOPPY K(KTs,18) /* Floppy */
41/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
42#define KTp 0xF3
43#define KPAD_0 K(KTp, 0 )
44#define KPAD_1 K(KTp, 1 )
45#define KPAD_2 K(KTp, 2 )
46#define KPAD_3 K(KTp, 3 )
47#define KPAD_4 K(KTp, 4 )
48#define KPAD_5 K(KTp, 5 )
49#define KPAD_6 K(KTp, 6 )
50#define KPAD_7 K(KTp, 7 )
51#define KPAD_8 K(KTp, 8 )
52#define KPAD_9 K(KTp, 9 )
53#define KPAD_PL K(KTp,10 )
54#define KPAD_MI K(KTp,11 )
55#define KPAD_ML K(KTp,12 )
56#define KPAD_DV K(KTp,13 )
57#define KPAD_EN K(KTp,14 )
58#define KPAD_DT K(KTp,16 )
59#define KPAD_HS K(KTp,20 )
60/* Console switching */
61#define KCn 0xF5
62/* Cursor */
63#define KTc 0xF6
64#define Kcd 0 /* Cursor down */
65#define Kcl 1 /* Cursor left */
66#define Kcr 2 /* Cursor right */
67#define Kcu 3 /* Cursor up */
68/* Shift/alt modifiers etc */
69#define KMd 0xF7
70#define KSHIFT K(KMd, 0 )
71#define KALTGR K(KMd, 1 )
72#define KCTRL K(KMd, 2 )
73#define KALT K(KMd, 3 )
74/* Meta */
75#define KMt 0xF8
76#define KAs 0xF9
77#define KPADA_0 K(KAs, 0 )
78#define KPADA_1 K(KAs, 1 )
79#define KPADA_2 K(KAs, 2 )
80#define KPADA_3 K(KAs, 3 )
81#define KPADA_4 K(KAs, 4 )
82#define KPADA_5 K(KAs, 5 )
83#define KPADA_6 K(KAs, 6 )
84#define KPADA_7 K(KAs, 7 )
85#define KPADA_8 K(KAs, 8 )
86#define KPADA_9 K(KAs, 9 )
87#define KPADB_0 K(KAs,10 )
88#define KPADB_1 K(KAs,11 )
89#define KPADB_2 K(KAs,12 )
90#define KPADB_3 K(KAs,13 )
91#define KPADB_4 K(KAs,14 )
92#define KPADB_5 K(KAs,15 )
93#define KPADB_6 K(KAs,16 )
94#define KPADB_7 K(KAs,17 )
95#define KPADB_8 K(KAs,18 )
96#define KPADB_9 K(KAs,19 )
97/* Locking keys */
98#define KLk 0xFA
99/* Letters */
100#define KTl 0xFB
101
102/*
103 * Here is the layout of the keys for the Fujitsu QWERTY
104 * style keyboard:
105 *
106 * static char Fujitsu_Key_Table[] =
107 * {
108 * KALT, '`' , KNUL, KCTL, KFUN, KESC, '1' , '2' ,
109 * '9' , '0' , '-' , '=' , KNUL, KBSP, KNUL, KNUL,
110 * KNUL, KBSL, KSHF, KNUL, KNUL, KDEL, KNUL, 't' ,
111 * 'y' , 'u' , 'i' , KRET, KSHF, KPGD, KNUL, KNUL,
112 * KNUL, KTAB, KNUL, KNUL, KNUL, 'q' , 'w' , 'e' ,
113 * 'r' , 'o' , 'p' , '[' , KNUL, ']' , KNUL, KNUL,
114 * KNUL, 'z' , KNUL, KNUL, KNUL, KSHL, KNUL, KNUL,
115 * 'k' , 'l' , ';' , KSQT, KNUL, KPGU, KNUL, KNUL,
116 * KNUL, 'a' , KNUL, KNUL, KNUL, 's' , 'd' , 'f' ,
117 * 'g' , 'h' , 'j' , '/' , KNUL, KHME, KNUL, KNUL,
118 * KNUL, 'x' , KNUL, KNUL, KNUL, 'c' , 'v' , 'b' ,
119 * 'n' , 'm' , ',' , '.' , KNUL, ' ' , KNUL, KNUL,
120 * KNUL, KNUL, KNUL, KNUL, KNUL, '3' , '4' , '5' ,
121 * '6' , '7' , '8' , KNUL, KPRG, KNUL, KEND, KNUL,
122 * };
123 */
124
125u_short plain_map[NR_KEYS]=
126{
127 0xf703, 0xf060, 0xf200, 0xf702, 0xf200, 0xf01b, 0xf031, 0xf032,
128 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f, 0xf200, 0xf200,
129 0xf200, 0xf05c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xfb74,
130 0xfb79, 0xfb75, 0xfb69, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
131 0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xfb71, 0xfb77, 0xfb65,
132 0xfb72, 0xfb6f, 0xfb70, 0xf05b, 0xf200, 0xf05d, 0xf200, 0xf200,
133 0xf200, 0xfb7a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
134 0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf603, 0xf200, 0xf200,
135 0xf200, 0xfb61, 0xf200, 0xf200, 0xf200, 0xfb73, 0xfb64, 0xfb66,
136 0xfb67, 0xfb68, 0xfb6a, 0xf02f, 0xf200, 0xf601, 0xf200, 0xf200,
137 0xf200, 0xfb78, 0xf200, 0xf200, 0xf200, 0xfb63, 0xfb76, 0xfb62,
138 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf200, 0xf020, 0xf200, 0xf200,
139 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf033, 0xf034, 0xf035,
140 0xf036, 0xf037, 0xf038, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
141 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
142 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
143};
144
145u_short shift_map[NR_KEYS]=
146{
147 0xf703, 0xf07e, 0xf200, 0xf702, 0xf200, 0xf01b, 0xf021, 0xf040,
148 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f, 0xf200, 0xf200,
149 0xf200, 0xf07c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xfb54,
150 0xfb59, 0xfb55, 0xfb49, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
151 0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xfb51, 0xfb57, 0xfb45,
152 0xfb52, 0xfb4f, 0xfb50, 0xf07b, 0xf200, 0xf07d, 0xf200, 0xf200,
153 0xf200, 0xfb5a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
154 0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf603, 0xf200, 0xf200,
155 0xf200, 0xfb41, 0xf200, 0xf200, 0xf200, 0xfb53, 0xfb44, 0xfb46,
156 0xfb47, 0xfb48, 0xfb4a, 0xf03f, 0xf200, 0xf601, 0xf200, 0xf200,
157 0xf200, 0xfb58, 0xf200, 0xf200, 0xf200, 0xfb43, 0xfb56, 0xfb42,
158 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf200, 0xf020, 0xf200, 0xf200,
159 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf023, 0xf024, 0xf025,
160 0xf05e, 0xf026, 0xf02a, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
161 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
162 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
163};
164
165u_short altgr_map[NR_KEYS]=
166{
167 KIGNORE ,K(KCn,12 ),K(KCn,13 ),K(KCn,14 ),K(KCn,15 ),K(KCn,16 ),K(KCn,17 ),K(KCn, 18),
168 K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22 ),K(KCn,23 ),KIGNORE ,KREGS ,KINTR ,
169 KIGNORE ,KIGNORE ,K(KTn,'@'),KIGNORE ,K(KTn,'$'),KIGNORE ,KIGNORE ,K(KTn,'{'),
170 K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
171 K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTl,'q'),
172 K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
173 K(KTl,'p'),KIGNORE ,K(KTn,'~'),KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADB_7 ,
174 KPADB_8 ,KPADB_9 ,KPAD_MI ,KCTRL ,K(KAs,20 ),K(KTl,'s'),K(KAs,23 ),K(KAs,25 ),
175 K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE ,KIGNORE ,KENTER ,
176 KPADB_4 ,KPADB_5 ,KPADB_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
177 K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE ,KIGNORE ,KIGNORE ,
178 KSHIFT ,K(KTc,Kcu),KPADB_1 ,KPADB_2 ,KPADB_3 ,KCAPSLK ,KALT ,KIGNORE ,
179 KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0 ,KPAD_DT ,KPAD_EN ,
180 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
181 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
182 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
183};
184
185u_short ctrl_map[NR_KEYS]=
186{
187 0xf703, 0xf200, 0xf200, 0xf702, 0xf200, 0xf200, 0xf001, 0xf002,
188 0xf009, 0xf000, 0xf031, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf200,
189 0xf200, 0xf01c, 0xf700, 0xf200, 0xf200, 0xf116, 0xf000, 0xf020,
190 0xf019, 0xf015, 0xf009, 0xf201, 0xf700, 0xf600, 0xf200, 0xf200,
191 0xf200, 0xf009, 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005,
192 0xf012, 0xf00f, 0xf010, 0xf01b, 0xf200, 0xf01d, 0xf200, 0xf200,
193 0xf200, 0xf01a, 0xf200, 0xf200, 0xf200, 0xf207, 0xf200, 0xf200,
194 0xf00b, 0xf00c, 0xf200, 0xf007, 0xf200, 0xf603, 0xf200, 0xf200,
195 0xf200, 0xf001, 0xf200, 0xf200, 0xf200, 0xf001, 0xf013, 0xf006,
196 0xf007, 0xf008, 0xf00a, 0xf07f, 0xf200, 0xf601, 0xf200, 0xf200,
197 0xf200, 0xf018, 0xf200, 0xf200, 0xf200, 0xf003, 0xf016, 0xf002,
198 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200,
199 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b, 0xf01c, 0xf01d,
200 0xf036, 0xf037, 0xf038, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
201 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
202 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf602, 0xf200,
203};
204
205u_short shift_ctrl_map[NR_KEYS]=
206{
207 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
208 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KFLOPPY ,KINTR ,
209 KIGNORE ,KIGNORE ,K(KTn, 0 ),KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
210 KIGNORE ,KIGNORE ,KIGNORE ,K(KTn,31 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
211 K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
212 K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
213 K(KTn,16 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
214 KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
215 K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
216 KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
217 K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
218 KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
219 KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
220 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
221 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
222 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
223};
224
225u_short alt_map[NR_KEYS]=
226{
227 K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
228 K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KSCRLLK ,KINTR ,
229 K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
230 K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
231 K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KMt, 9 ),K(KMt,'q'),
232 K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
233 K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADA_7 ,
234 KPADA_8 ,KPADA_9 ,KPAD_MI ,KCTRL ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
235 K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
236 KPADA_4 ,KPADA_5 ,KPADA_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,'z' ),K(KMt,'x'),
237 K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE ,
238 KSHIFT ,K(KTc,Kcu),KPADA_1 ,KPADA_2 ,KPADA_3 ,KCAPSLK ,KALT ,K(KMt,' '),
239 KALTGR ,KCTRL ,CONS_DEC ,K(KTc,Kcd ),CONS_INC ,KPADA_0 ,KPAD_DT ,KPAD_EN ,
240 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
241 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
242 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
243};
244
245u_short ctrl_alt_map[NR_KEYS]=
246{
247 KIGNORE ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
248 K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KIGNORE ,KINTR ,
249 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
250 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
251 K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KMt,17 ),
252 K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20 ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9 ),K(KMt,15 ),
253 K(KMt,16 ),KIGNORE ,KIGNORE ,KIGNORE ,KREBOOT ,K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
254 KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4 ),K(KMt, 6 ),
255 K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11 ),K(KMt,12 ),KIGNORE ,KIGNORE ,KENTER ,
256 KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,26 ),K(KMt,24 ),
257 K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14 ),K(KMt,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
258 KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,KIGNORE ,
259 KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KREBOOT ,KPAD_EN ,
260 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
261 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
262 KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
263};
264
265ushort *key_maps[MAX_NR_KEYMAPS] = {
266 plain_map, shift_map, altgr_map, 0,
267 ctrl_map, shift_ctrl_map, 0, 0,
268 alt_map, 0, 0, 0,
269 ctrl_alt_map, 0
270};
271
272unsigned int keymap_count = 7;
273
274/*
275 * Philosophy: most people do not define more strings, but they who do
276 * often want quite a lot of string space. So, we statically allocate
277 * the default and allocate dynamically in chunks of 512 bytes.
278 */
279
280char func_buf[] = {
281 '\033', '[', '[', 'A', 0,
282 '\033', '[', '[', 'B', 0,
283 '\033', '[', '[', 'C', 0,
284 '\033', '[', '[', 'D', 0,
285 '\033', '[', '[', 'E', 0,
286 '\033', '[', '1', '7', '~', 0,
287 '\033', '[', '1', '8', '~', 0,
288 '\033', '[', '1', '9', '~', 0,
289 '\033', '[', '2', '0', '~', 0,
290 '\033', '[', '2', '1', '~', 0,
291 '\033', '[', '2', '3', '~', 0,
292 '\033', '[', '2', '4', '~', 0,
293 '\033', '[', '2', '5', '~', 0,
294 '\033', '[', '2', '6', '~', 0,
295 '\033', '[', '2', '8', '~', 0,
296 '\033', '[', '2', '9', '~', 0,
297 '\033', '[', '3', '1', '~', 0,
298 '\033', '[', '3', '2', '~', 0,
299 '\033', '[', '3', '3', '~', 0,
300 '\033', '[', '3', '4', '~', 0,
301 '\033', '[', '1', '~', 0,
302 '\033', '[', '2', '~', 0,
303 '\033', '[', '3', '~', 0,
304 '\033', '[', '4', '~', 0,
305 '\033', '[', '5', '~', 0,
306 '\033', '[', '6', '~', 0,
307 '\033', '[', 'M', 0,
308 '\033', '[', 'P', 0,
309};
310
311char *funcbufptr = func_buf;
312int funcbufsize = sizeof(func_buf);
313int funcbufleft = 0; /* space left */
314
315char *func_table[MAX_NR_FUNC] = {
316 func_buf + 0,
317 func_buf + 5,
318 func_buf + 10,
319 func_buf + 15,
320 func_buf + 20,
321 func_buf + 25,
322 func_buf + 31,
323 func_buf + 37,
324 func_buf + 43,
325 func_buf + 49,
326 func_buf + 55,
327 func_buf + 61,
328 func_buf + 67,
329 func_buf + 73,
330 func_buf + 79,
331 func_buf + 85,
332 func_buf + 91,
333 func_buf + 97,
334 func_buf + 103,
335 func_buf + 109,
336 func_buf + 115,
337 func_buf + 120,
338 func_buf + 125,
339 func_buf + 130,
340 func_buf + 135,
341 func_buf + 140,
342 func_buf + 145,
343 0,
344 0,
345 func_buf + 149,
346 0,
347};
348
349struct kbdiacr accent_table[MAX_DIACR] = {
350 {'`', 'A', '\300'}, {'`', 'a', '\340'},
351 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
352 {'^', 'A', '\302'}, {'^', 'a', '\342'},
353 {'~', 'A', '\303'}, {'~', 'a', '\343'},
354 {'"', 'A', '\304'}, {'"', 'a', '\344'},
355 {'O', 'A', '\305'}, {'o', 'a', '\345'},
356 {'0', 'A', '\305'}, {'0', 'a', '\345'},
357 {'A', 'A', '\305'}, {'a', 'a', '\345'},
358 {'A', 'E', '\306'}, {'a', 'e', '\346'},
359 {',', 'C', '\307'}, {',', 'c', '\347'},
360 {'`', 'E', '\310'}, {'`', 'e', '\350'},
361 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
362 {'^', 'E', '\312'}, {'^', 'e', '\352'},
363 {'"', 'E', '\313'}, {'"', 'e', '\353'},
364 {'`', 'I', '\314'}, {'`', 'i', '\354'},
365 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
366 {'^', 'I', '\316'}, {'^', 'i', '\356'},
367 {'"', 'I', '\317'}, {'"', 'i', '\357'},
368 {'-', 'D', '\320'}, {'-', 'd', '\360'},
369 {'~', 'N', '\321'}, {'~', 'n', '\361'},
370 {'`', 'O', '\322'}, {'`', 'o', '\362'},
371 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
372 {'^', 'O', '\324'}, {'^', 'o', '\364'},
373 {'~', 'O', '\325'}, {'~', 'o', '\365'},
374 {'"', 'O', '\326'}, {'"', 'o', '\366'},
375 {'/', 'O', '\330'}, {'/', 'o', '\370'},
376 {'`', 'U', '\331'}, {'`', 'u', '\371'},
377 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
378 {'^', 'U', '\333'}, {'^', 'u', '\373'},
379 {'"', 'U', '\334'}, {'"', 'u', '\374'},
380 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
381 {'T', 'H', '\336'}, {'t', 'h', '\376'},
382 {'s', 's', '\337'}, {'"', 'y', '\377'},
383 {'s', 'z', '\337'}, {'i', 'j', '\377'},
384};
385
386unsigned int accent_table_size = 68;
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
new file mode 100644
index 000000000000..c22bb9dca1ec
--- /dev/null
+++ b/drivers/acorn/char/i2c.c
@@ -0,0 +1,369 @@
1/*
2 * linux/drivers/acorn/char/i2c.c
3 *
4 * Copyright (C) 2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM IOC/IOMD i2c driver.
11 *
12 * On Acorn machines, the following i2c devices are on the bus:
13 * - PCF8583 real time clock & static RAM
14 */
15#include <linux/init.h>
16#include <linux/sched.h>
17#include <linux/time.h>
18#include <linux/miscdevice.h>
19#include <linux/rtc.h>
20#include <linux/i2c.h>
21#include <linux/i2c-algo-bit.h>
22#include <linux/fs.h>
23
24#include <asm/hardware.h>
25#include <asm/io.h>
26#include <asm/hardware/ioc.h>
27#include <asm/system.h>
28#include <asm/uaccess.h>
29
30#include "pcf8583.h"
31
32extern int (*set_rtc)(void);
33
34static struct i2c_client *rtc_client;
35static const unsigned char days_in_mon[] =
36 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
37
38#define CMOS_CHECKSUM (63)
39
40/*
41 * Acorn machines store the year in the static RAM at
42 * location 128.
43 */
44#define CMOS_YEAR (64 + 128)
45
46static inline int rtc_command(int cmd, void *data)
47{
48 int ret = -EIO;
49
50 if (rtc_client)
51 ret = rtc_client->driver->command(rtc_client, cmd, data);
52
53 return ret;
54}
55
56/*
57 * Update the century + year bytes in the CMOS RAM, ensuring
58 * that the check byte is correctly adjusted for the change.
59 */
60static int rtc_update_year(unsigned int new_year)
61{
62 unsigned char yr[2], chk;
63 struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr };
64 struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
65 int ret;
66
67 ret = rtc_command(MEM_READ, &cmos_check);
68 if (ret)
69 goto out;
70 ret = rtc_command(MEM_READ, &cmos_year);
71 if (ret)
72 goto out;
73
74 chk -= yr[1] + yr[0];
75
76 yr[1] = new_year / 100;
77 yr[0] = new_year % 100;
78
79 chk += yr[1] + yr[0];
80
81 ret = rtc_command(MEM_WRITE, &cmos_year);
82 if (ret == 0)
83 ret = rtc_command(MEM_WRITE, &cmos_check);
84 out:
85 return ret;
86}
87
88/*
89 * Read the current RTC time and date, and update xtime.
90 */
91static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year)
92{
93 unsigned char ctrl, yr[2];
94 struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr };
95 int real_year, year_offset;
96
97 /*
98 * Ensure that the RTC is running.
99 */
100 rtc_command(RTC_GETCTRL, &ctrl);
101 if (ctrl & 0xc0) {
102 unsigned char new_ctrl = ctrl & ~0xc0;
103
104 printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
105 ctrl, new_ctrl);
106
107 rtc_command(RTC_SETCTRL, &new_ctrl);
108 }
109
110 if (rtc_command(RTC_GETDATETIME, rtctm) ||
111 rtc_command(MEM_READ, &rtcmem))
112 return;
113
114 real_year = yr[0];
115
116 /*
117 * The RTC year holds the LSB two bits of the current
118 * year, which should reflect the LSB two bits of the
119 * CMOS copy of the year. Any difference indicates
120 * that we have to correct the CMOS version.
121 */
122 year_offset = rtctm->year_off - (real_year & 3);
123 if (year_offset < 0)
124 /*
125 * RTC year wrapped. Adjust it appropriately.
126 */
127 year_offset += 4;
128
129 *year = real_year + year_offset + yr[1] * 100;
130}
131
132static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
133{
134 unsigned char leap;
135 int ret;
136
137 leap = (!(year % 4) && (year % 100)) || !(year % 400);
138
139 if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0)
140 return -EINVAL;
141
142 if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap)))
143 return -EINVAL;
144
145 if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60)
146 return -EINVAL;
147
148 /*
149 * The RTC's own 2-bit year must reflect the least
150 * significant two bits of the CMOS year.
151 */
152 rtctm->year_off = (year % 100) & 3;
153
154 ret = rtc_command(RTC_SETDATETIME, rtctm);
155 if (ret == 0)
156 ret = rtc_update_year(year);
157
158 return ret;
159}
160
161/*
162 * Set the RTC time only. Note that
163 * we do not touch the date.
164 */
165static int k_set_rtc_time(void)
166{
167 struct rtc_tm new_rtctm, old_rtctm;
168 unsigned long nowtime = xtime.tv_sec;
169
170 if (rtc_command(RTC_GETDATETIME, &old_rtctm))
171 return 0;
172
173 new_rtctm.cs = xtime.tv_nsec / 10000000;
174 new_rtctm.secs = nowtime % 60; nowtime /= 60;
175 new_rtctm.mins = nowtime % 60; nowtime /= 60;
176 new_rtctm.hours = nowtime % 24;
177
178 /*
179 * avoid writing when we're going to change the day
180 * of the month. We will retry in the next minute.
181 * This basically means that if the RTC must not drift
182 * by more than 1 minute in 11 minutes.
183 *
184 * [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00,
185 * rtc gets set to 1/1/2000 00:01:00 ]
186 */
187 if ((old_rtctm.hours == 23 && old_rtctm.mins == 59) ||
188 (new_rtctm.hours == 23 && new_rtctm.mins == 59))
189 return 1;
190
191 return rtc_command(RTC_SETTIME, &new_rtctm);
192}
193
194static int rtc_ioctl(struct inode *inode, struct file *file,
195 unsigned int cmd, unsigned long arg)
196{
197 unsigned int year;
198 struct rtc_time rtctm;
199 struct rtc_tm rtc_raw;
200
201 switch (cmd) {
202 case RTC_ALM_READ:
203 case RTC_ALM_SET:
204 break;
205
206 case RTC_RD_TIME:
207 memset(&rtctm, 0, sizeof(struct rtc_time));
208 get_rtc_time(&rtc_raw, &year);
209 rtctm.tm_sec = rtc_raw.secs;
210 rtctm.tm_min = rtc_raw.mins;
211 rtctm.tm_hour = rtc_raw.hours;
212 rtctm.tm_mday = rtc_raw.mday;
213 rtctm.tm_mon = rtc_raw.mon - 1; /* month starts at 0 */
214 rtctm.tm_year = year - 1900; /* starts at 1900 */
215 return copy_to_user((void *)arg, &rtctm, sizeof(rtctm))
216 ? -EFAULT : 0;
217
218 case RTC_SET_TIME:
219 if (!capable(CAP_SYS_TIME))
220 return -EACCES;
221
222 if (copy_from_user(&rtctm, (void *)arg, sizeof(rtctm)))
223 return -EFAULT;
224 rtc_raw.secs = rtctm.tm_sec;
225 rtc_raw.mins = rtctm.tm_min;
226 rtc_raw.hours = rtctm.tm_hour;
227 rtc_raw.mday = rtctm.tm_mday;
228 rtc_raw.mon = rtctm.tm_mon + 1;
229 year = rtctm.tm_year + 1900;
230 return set_rtc_time(&rtc_raw, year);
231 break;
232
233 case RTC_EPOCH_READ:
234 return put_user(1900, (unsigned long *)arg);
235
236 }
237 return -EINVAL;
238}
239
240static struct file_operations rtc_fops = {
241 .ioctl = rtc_ioctl,
242};
243
244static struct miscdevice rtc_dev = {
245 .minor = RTC_MINOR,
246 .name = "rtc",
247 .fops = &rtc_fops,
248};
249
250/* IOC / IOMD i2c driver */
251
252#define FORCE_ONES 0xdc
253#define SCL 0x02
254#define SDA 0x01
255
256/*
257 * We must preserve all non-i2c output bits in IOC_CONTROL.
258 * Note also that we need to preserve the value of SCL and
259 * SDA outputs as well (which may be different from the
260 * values read back from IOC_CONTROL).
261 */
262static u_int force_ones;
263
264static void ioc_setscl(void *data, int state)
265{
266 u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
267 u_int ones = force_ones;
268
269 if (state)
270 ones |= SCL;
271 else
272 ones &= ~SCL;
273
274 force_ones = ones;
275
276 ioc_writeb(ioc_control | ones, IOC_CONTROL);
277}
278
279static void ioc_setsda(void *data, int state)
280{
281 u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
282 u_int ones = force_ones;
283
284 if (state)
285 ones |= SDA;
286 else
287 ones &= ~SDA;
288
289 force_ones = ones;
290
291 ioc_writeb(ioc_control | ones, IOC_CONTROL);
292}
293
294static int ioc_getscl(void *data)
295{
296 return (ioc_readb(IOC_CONTROL) & SCL) != 0;
297}
298
299static int ioc_getsda(void *data)
300{
301 return (ioc_readb(IOC_CONTROL) & SDA) != 0;
302}
303
304static struct i2c_algo_bit_data ioc_data = {
305 .setsda = ioc_setsda,
306 .setscl = ioc_setscl,
307 .getsda = ioc_getsda,
308 .getscl = ioc_getscl,
309 .udelay = 80,
310 .mdelay = 80,
311 .timeout = 100
312};
313
314static int ioc_client_reg(struct i2c_client *client)
315{
316 if (client->driver->id == I2C_DRIVERID_PCF8583 &&
317 client->addr == 0x50) {
318 struct rtc_tm rtctm;
319 unsigned int year;
320 struct timespec tv;
321
322 rtc_client = client;
323 get_rtc_time(&rtctm, &year);
324
325 tv.tv_nsec = rtctm.cs * 10000000;
326 tv.tv_sec = mktime(year, rtctm.mon, rtctm.mday,
327 rtctm.hours, rtctm.mins, rtctm.secs);
328 do_settimeofday(&tv);
329 set_rtc = k_set_rtc_time;
330 }
331
332 return 0;
333}
334
335static int ioc_client_unreg(struct i2c_client *client)
336{
337 if (client == rtc_client) {
338 set_rtc = NULL;
339 rtc_client = NULL;
340 }
341
342 return 0;
343}
344
345static struct i2c_adapter ioc_ops = {
346 .id = I2C_HW_B_IOC,
347 .algo_data = &ioc_data,
348 .client_register = ioc_client_reg,
349 .client_unregister = ioc_client_unreg,
350};
351
352static int __init i2c_ioc_init(void)
353{
354 int ret;
355
356 force_ones = FORCE_ONES | SCL | SDA;
357
358 ret = i2c_bit_add_bus(&ioc_ops);
359
360 if (ret >= 0){
361 ret = misc_register(&rtc_dev);
362 if(ret < 0)
363 i2c_bit_del_bus(&ioc_ops);
364 }
365
366 return ret;
367}
368
369__initcall(i2c_ioc_init);
diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c
new file mode 100644
index 000000000000..ad7ae7ab8920
--- /dev/null
+++ b/drivers/acorn/char/pcf8583.c
@@ -0,0 +1,239 @@
1/*
2 * linux/drivers/acorn/char/pcf8583.c
3 *
4 * Copyright (C) 2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Driver for PCF8583 RTC & RAM chip
11 */
12#include <linux/i2c.h>
13#include <linux/slab.h>
14#include <linux/string.h>
15#include <linux/mc146818rtc.h>
16#include <linux/init.h>
17#include <linux/errno.h>
18#include <linux/bcd.h>
19
20#include "pcf8583.h"
21
22static struct i2c_driver pcf8583_driver;
23
24static unsigned short ignore[] = { I2C_CLIENT_END };
25static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
26
27static struct i2c_client_address_data addr_data = {
28 .normal_i2c = normal_addr,
29 .normal_i2c_range = ignore,
30 .probe = ignore,
31 .probe_range = ignore,
32 .ignore = ignore,
33 .ignore_range = ignore,
34 .force = ignore,
35};
36
37#define DAT(x) ((unsigned int)(x->dev.driver_data))
38
39static int
40pcf8583_attach(struct i2c_adapter *adap, int addr, int kind)
41{
42 struct i2c_client *c;
43 unsigned char buf[1], ad[1] = { 0 };
44 struct i2c_msg msgs[2] = {
45 { addr, 0, 1, ad },
46 { addr, I2C_M_RD, 1, buf }
47 };
48
49 c = kmalloc(sizeof(*c), GFP_KERNEL);
50 if (!c)
51 return -ENOMEM;
52
53 memset(c, 0, sizeof(*c));
54 c->addr = addr;
55 c->adapter = adap;
56 c->driver = &pcf8583_driver;
57
58 if (i2c_transfer(c->adapter, msgs, 2) == 2)
59 DAT(c) = buf[0];
60
61 return i2c_attach_client(c);
62}
63
64static int
65pcf8583_probe(struct i2c_adapter *adap)
66{
67 return i2c_probe(adap, &addr_data, pcf8583_attach);
68}
69
70static int
71pcf8583_detach(struct i2c_client *client)
72{
73 i2c_detach_client(client);
74 kfree(client);
75 return 0;
76}
77
78static int
79pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
80{
81 unsigned char buf[8], addr[1] = { 1 };
82 struct i2c_msg msgs[2] = {
83 { client->addr, 0, 1, addr },
84 { client->addr, I2C_M_RD, 6, buf }
85 };
86 int ret = -EIO;
87
88 memset(buf, 0, sizeof(buf));
89
90 ret = i2c_transfer(client->adapter, msgs, 2);
91 if (ret == 2) {
92 dt->year_off = buf[4] >> 6;
93 dt->wday = buf[5] >> 5;
94
95 buf[4] &= 0x3f;
96 buf[5] &= 0x1f;
97
98 dt->cs = BCD_TO_BIN(buf[0]);
99 dt->secs = BCD_TO_BIN(buf[1]);
100 dt->mins = BCD_TO_BIN(buf[2]);
101 dt->hours = BCD_TO_BIN(buf[3]);
102 dt->mday = BCD_TO_BIN(buf[4]);
103 dt->mon = BCD_TO_BIN(buf[5]);
104
105 ret = 0;
106 }
107
108 return ret;
109}
110
111static int
112pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
113{
114 unsigned char buf[8];
115 int ret, len = 6;
116
117 buf[0] = 0;
118 buf[1] = DAT(client) | 0x80;
119 buf[2] = BIN_TO_BCD(dt->cs);
120 buf[3] = BIN_TO_BCD(dt->secs);
121 buf[4] = BIN_TO_BCD(dt->mins);
122 buf[5] = BIN_TO_BCD(dt->hours);
123
124 if (datetoo) {
125 len = 8;
126 buf[6] = BIN_TO_BCD(dt->mday) | (dt->year_off << 6);
127 buf[7] = BIN_TO_BCD(dt->mon) | (dt->wday << 5);
128 }
129
130 ret = i2c_master_send(client, (char *)buf, len);
131 if (ret == len)
132 ret = 0;
133
134 buf[1] = DAT(client);
135 i2c_master_send(client, (char *)buf, 2);
136
137 return ret;
138}
139
140static int
141pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
142{
143 *ctrl = DAT(client);
144 return 0;
145}
146
147static int
148pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
149{
150 unsigned char buf[2];
151
152 buf[0] = 0;
153 buf[1] = *ctrl;
154 DAT(client) = *ctrl;
155
156 return i2c_master_send(client, (char *)buf, 2);
157}
158
159static int
160pcf8583_read_mem(struct i2c_client *client, struct mem *mem)
161{
162 unsigned char addr[1];
163 struct i2c_msg msgs[2] = {
164 { client->addr, 0, 1, addr },
165 { client->addr, I2C_M_RD, 0, mem->data }
166 };
167
168 if (mem->loc < 8)
169 return -EINVAL;
170
171 addr[0] = mem->loc;
172 msgs[1].len = mem->nr;
173
174 return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
175}
176
177static int
178pcf8583_write_mem(struct i2c_client *client, struct mem *mem)
179{
180 unsigned char addr[1];
181 struct i2c_msg msgs[2] = {
182 { client->addr, 0, 1, addr },
183 { client->addr, 0, 0, mem->data }
184 };
185
186 if (mem->loc < 8)
187 return -EINVAL;
188
189 addr[0] = mem->loc;
190 msgs[1].len = mem->nr;
191
192 return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
193}
194
195static int
196pcf8583_command(struct i2c_client *client, unsigned int cmd, void *arg)
197{
198 switch (cmd) {
199 case RTC_GETDATETIME:
200 return pcf8583_get_datetime(client, arg);
201
202 case RTC_SETTIME:
203 return pcf8583_set_datetime(client, arg, 0);
204
205 case RTC_SETDATETIME:
206 return pcf8583_set_datetime(client, arg, 1);
207
208 case RTC_GETCTRL:
209 return pcf8583_get_ctrl(client, arg);
210
211 case RTC_SETCTRL:
212 return pcf8583_set_ctrl(client, arg);
213
214 case MEM_READ:
215 return pcf8583_read_mem(client, arg);
216
217 case MEM_WRITE:
218 return pcf8583_write_mem(client, arg);
219
220 default:
221 return -EINVAL;
222 }
223}
224
225static struct i2c_driver pcf8583_driver = {
226 .name = "PCF8583",
227 .id = I2C_DRIVERID_PCF8583,
228 .flags = I2C_DF_NOTIFY,
229 .attach_adapter = pcf8583_probe,
230 .detach_client = pcf8583_detach,
231 .command = pcf8583_command
232};
233
234static __init int pcf8583_init(void)
235{
236 return i2c_add_driver(&pcf8583_driver);
237}
238
239__initcall(pcf8583_init);
diff --git a/drivers/acorn/char/pcf8583.h b/drivers/acorn/char/pcf8583.h
new file mode 100644
index 000000000000..847f7fdb8763
--- /dev/null
+++ b/drivers/acorn/char/pcf8583.h
@@ -0,0 +1,41 @@
1/*
2 * linux/drivers/acorn/char/pcf8583.h
3 *
4 * Copyright (C) 2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10struct rtc_tm {
11 unsigned char cs;
12 unsigned char secs;
13 unsigned char mins;
14 unsigned char hours;
15 unsigned char mday;
16 unsigned char mon;
17 unsigned char year_off;
18 unsigned char wday;
19};
20
21struct mem {
22 unsigned int loc;
23 unsigned int nr;
24 unsigned char *data;
25};
26
27#define RTC_GETDATETIME 0
28#define RTC_SETTIME 1
29#define RTC_SETDATETIME 2
30#define RTC_GETCTRL 3
31#define RTC_SETCTRL 4
32#define MEM_READ 5
33#define MEM_WRITE 6
34
35#define CTRL_STOP 0x80
36#define CTRL_HOLD 0x40
37#define CTRL_32KHZ 0x00
38#define CTRL_MASK 0x08
39#define CTRL_ALARMEN 0x04
40#define CTRL_ALARM 0x02
41#define CTRL_TIMER 0x01