OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [block/] [fd1772.c] - Blame information for rev 1622

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1622 jcastillo
/*
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 (gilbertd@cs.man.ac.uk)
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 seqeunce'
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
 *      4/ 9/98 - Cleaned up a few compiler warnings
119
 */
120
 
121
#include <linux/config.h>
122
#include <linux/sched.h>
123
#include <linux/fs.h>
124
#include <linux/fcntl.h>
125
#include <linux/kernel.h>
126
#include <linux/interrupt.h>
127
#include <linux/timer.h>
128
#include <linux/tqueue.h>
129
#include <linux/fd.h>
130
#include <linux/fd1772.h>
131
#include <linux/errno.h>
132
#include <linux/types.h>
133
#include <linux/delay.h>
134
#include <linux/mm.h>
135
 
136
#include <asm/arch/oldlatches.h>
137
#include <asm/system.h>
138
#include <asm/bitops.h>
139
#include <asm/dma.h>
140
#include <asm/hardware.h>
141
#include <asm/io.h>
142
#include <asm/irq.h>
143
#include <asm/pgtable.h>
144
#include <asm/segment.h>
145
 
146
#define MAJOR_NR FLOPPY_MAJOR
147
#define FLOPPY_DMA 0
148
#include "blk.h"
149
 
150
/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
151
 * little additional rework in this file). But I'm not yet sure if
152
 * some other code depends on the number of floppies... (It is defined
153
 * in a public header!)
154
 */
155
#if 0
156
#undef FD_MAX_UNITS
157
#define FD_MAX_UNITS    2
158
#endif
159
 
160
/* Ditto worries for Arc - DAG */
161
#define FD_MAX_UNITS 4
162
#define TRACKBUFFER 0
163
/*#define DEBUG*/
164
 
165
#ifdef DEBUG
166
#define DPRINT(a)       printk a
167
#else
168
#define DPRINT(a)
169
#endif
170
 
171
/* Disk types: DD */
172
static struct archy_disk_type {
173
        const char *name;
174
        unsigned spt;           /* sectors per track */
175
        unsigned blocks;        /* total number of blocks */
176
        unsigned stretch;       /* track doubling ? */
177
} disk_type[] = {
178
 
179
        { "d360", 9, 720, 0 },                   /* 360kB diskette */
180
        { "D360", 9, 720, 1 },                  /* 360kb in 720kb drive */
181
        { "D720", 9, 1440, 0 },                  /* 720kb diskette (DD) */
182
        /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors
183
                                      - DAG - can't see how type detect can distinguish this
184
                                      from 720K until it reads block 4 by which time its too late! */
185
};
186
 
187
#define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))
188
 
189
/*
190
 * Maximum disk size (in kilobytes). This default is used whenever the
191
 * current disk size is unknown.
192
 */
193
#define MAX_DISK_SIZE 720
194
 
195
static int floppy_sizes[256];
196
static int floppy_blocksizes[256] = {0,};
197
 
198
/* current info on each unit */
199
static struct archy_floppy_struct {
200
        int connected;          /* !=0 : drive is connected */
201
        int autoprobe;          /* !=0 : do autoprobe       */
202
 
203
        struct archy_disk_type *disktype;       /* current type of disk */
204
 
205
        int track;              /* current head position or -1
206
                                   * if unknown */
207
        unsigned int steprate;  /* steprate setting */
208
        unsigned int wpstat;    /* current state of WP signal
209
                                   * (for disk change detection) */
210
} unit[FD_MAX_UNITS];
211
 
212
/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which
213
   is an assembler routine */
214
extern void fdc1772_comendhandler(void);        /* Actually doens't have these parameters - see fd1772.S */
215
extern volatile int fdc1772_comendstatus;
216
extern volatile int fdc1772_fdc_int_done;
217
 
218
#define FDC1772BASE ((0x210000>>2)|0x80000000)
219
 
220
#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2))
221
 
222
/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather
223
   than the #def below - well simple - the #def won't compile - and I
224
   don't understand why (__outwc not defined) */
225
/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility
226
   with the ST version of fd1772.h */
227
/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */
228
void FDC1772_WRITE(int reg, unsigned char val)
229
{
230
        if (reg == FDC1772REG_CMD) {
231
                DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies));
232
                if (fdc1772_fdc_int_done) {
233
                        DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n"));
234
                        fdc1772_fdc_int_done = 0;
235
                };
236
        };
237
        outb(val, (reg / 2) + FDC1772BASE);
238
};
239
 
240
#define MAX_SECTORS     22
241
 
242
unsigned char *DMABuffer;       /* buffer for writes */
243
/*static unsigned long PhysDMABuffer; *//* physical address */
244
/* DAG: On Arc we just go straight for the DMA buffer */
245
#define PhysDMABuffer DMABuffer
246
 
247
#ifdef TRACKBUFFER   
248
unsigned char *TrackBuffer;       /* buffer for reads */
249
#define PhysTrackBuffer TrackBuffer /* physical address */
250
static int BufferDrive, BufferSide, BufferTrack;
251
static int read_track;    /* non-zero if we are reading whole tracks */
252
 
253
#define SECTOR_BUFFER(sec)  (TrackBuffer + ((sec)-1)*512)
254
#define IS_BUFFERED(drive,side,track) \
255
    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
256
#endif
257
 
258
/*
259
 * These are global variables, as that's the easiest way to give
260
 * information to interrupts. They are the data used for the current
261
 * request.
262
 */
263
static int SelectedDrive = 0;
264
static int ReqCmd, ReqBlock;
265
static int ReqSide, ReqTrack, ReqSector, ReqCnt;
266
static int HeadSettleFlag = 0;
267
static unsigned char *ReqData, *ReqBuffer;
268
static int MotorOn = 0, MotorOffTrys;
269
 
270
/* Synchronization of FDC1772 access. */
271
static volatile int fdc_busy = 0;
272
static struct wait_queue *fdc_wait = NULL;
273
 
274
 
275
static unsigned int changed_floppies = 0xff, fake_change = 0;
276
#define CHECK_CHANGE_DELAY      HZ/2
277
 
278
/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */
279
#define FD_MOTOR_OFF_DELAY      (10*HZ)
280
#define FD_MOTOR_OFF_MAXTRY     (10*20)
281
 
282
#define FLOPPY_TIMEOUT          (6*HZ)
283
#define RECALIBRATE_ERRORS      4       /* After this many errors the drive
284
                                         * will be recalibrated. */
285
#define MAX_ERRORS                      8       /* After this many errors the driver
286
                                                 * will give up. */
287
 
288
 
289
#define START_MOTOR_OFF_TIMER(delay)                    \
290
    do {                                                \
291
        motor_off_timer.expires = jiffies + (delay);            \
292
        add_timer( &motor_off_timer );                  \
293
        MotorOffTrys = 0;                                \
294
        } while(0)
295
 
296
#define START_CHECK_CHANGE_TIMER(delay)                         \
297
    do {                                                        \
298
        timer_table[FLOPPY_TIMER].expires = jiffies + (delay);  \
299
        timer_active |= (1 << FLOPPY_TIMER);                    \
300
        } while(0)
301
 
302
#define START_TIMEOUT()                                 \
303
    do {                                                \
304
        del_timer( &timeout_timer );                    \
305
        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;       \
306
        add_timer( &timeout_timer );                    \
307
        } while(0)
308
 
309
#define STOP_TIMEOUT()                                  \
310
    do {                                                \
311
        del_timer( &timeout_timer );                    \
312
        } while(0)
313
 
314
#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64);
315
 
316
#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64);
317
 
318
static void fd1772_checkint(void);
319
 
320
struct tq_struct fd1772_tq =
321
{ 0,0, (void *)fd1772_checkint, 0 };
322
/*
323
 * The driver is trying to determine the correct media format
324
 * while Probing is set. fd_rwsec_done() clears it after a
325
 * successful access.
326
 */
327
static int Probing = 0;
328
 
329
/* This flag is set when a dummy seek is necesary to make the WP
330
 * status bit accessible.
331
 */
332
static int NeedSeek = 0;
333
 
334
 
335
/***************************** Prototypes *****************************/
336
 
337
static void fd_select_side(int side);
338
static void fd_select_drive(int drive);
339
static void fd_deselect(void);
340
static void fd_motor_off_timer(unsigned long dummy);
341
static void check_change(void);
342
static __inline__ void set_head_settle_flag(void);
343
static __inline__ int get_head_settle_flag(void);
344
static void floppy_irqconsequencehandler(void);
345
static void fd_error(void);
346
static void do_fd_action(int drive);
347
static void fd_calibrate(void);
348
static void fd_calibrate_done(int status);
349
static void fd_seek(void);
350
static void fd_seek_done(int status);
351
static void fd_rwsec(void);
352
#ifdef TRACKBUFFER   
353
static void fd_readtrack_check( unsigned long dummy );
354
#endif
355
static void fd_rwsec_done(int status);
356
static void fd_times_out(unsigned long dummy);
357
static void finish_fdc(void);
358
static void finish_fdc_done(int dummy);
359
static void floppy_off(unsigned int nr);
360
static __inline__ void copy_buffer(void *from, void *to);
361
static void setup_req_params(int drive);
362
static void redo_fd_request(void);
363
static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
364
                    cmd, unsigned long param);
365
static void fd_probe(int drive);
366
static int fd_test_drive_present(int drive);
367
static void config_types(void);
368
static int floppy_open(struct inode *inode, struct file *filp);
369
static void floppy_release(struct inode *inode, struct file *filp);
370
 
371
/************************* End of Prototypes **************************/
372
 
373
static struct timer_list motor_off_timer =
374
{NULL, NULL, 0, 0, fd_motor_off_timer};
375
#ifdef TRACKBUFFER
376
static struct timer_list readtrack_timer =
377
             { NULL, NULL, 0, 0, fd_readtrack_check };
378
#endif
379
static struct timer_list timeout_timer =
380
{NULL, NULL, 0, 0, fd_times_out};
381
 
382
/* DAG: Haven't got a clue what this is? */
383
int stdma_islocked(void)
384
{
385
        return 0;
386
};
387
 
388
/* Select the side to use. */
389
 
390
static void fd_select_side(int side)
391
{
392
        unsigned long flags;
393
 
394
        save_flags(flags);
395
        cli();
396
 
397
        oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);
398
        restore_flags(flags);
399
}
400
 
401
 
402
/* Select a drive, update the FDC1772's track register
403
 */
404
 
405
static void fd_select_drive(int drive)
406
{
407
        unsigned long flags;
408
 
409
#ifdef DEBUG
410
        printk("fd_select_drive:%d\n", drive);
411
#endif
412
        /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */
413
        oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);
414
 
415
        if (drive == SelectedDrive)
416
                return;
417
 
418
        save_flags(flags);
419
        cli();
420
        oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));
421
        restore_flags(flags);
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
 
433
static void fd_deselect(void)
434
{
435
        unsigned long flags;
436
 
437
        DPRINT(("fd_deselect\n"));
438
 
439
        save_flags(flags);
440
        cli();
441
        oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);
442
        restore_flags(flags);
443
 
444
        SelectedDrive = -1;
445
}
446
 
447
 
448
/* This timer function deselects the drives when the FDC1772 switched the
449
 * motor off. The deselection cannot happen earlier because the FDC1772
450
 * counts the index signals, which arrive only if one drive is selected.
451
 */
452
 
453
static void fd_motor_off_timer(unsigned long dummy)
454
{
455
        unsigned long flags;
456
        unsigned char status;
457
        int delay;
458
 
459
        del_timer(&motor_off_timer);
460
 
461
        if (SelectedDrive < 0)
462
                /* no drive selected, needn't deselect anyone */
463
                return;
464
 
465
        save_flags(flags);
466
        cli();
467
 
468
        if (fdc_busy)           /* was stdma_islocked */
469
                goto retry;
470
 
471
        status = FDC1772_READ(FDC1772REG_STATUS);
472
 
473
        if (!(status & 0x80)) {
474
                /* motor already turned off by FDC1772 -> deselect drives */
475
     /* In actual fact its this deselection which turns the motor off on the
476
        Arc, since the motor control is actually on Latch A */
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
 
485
      retry:
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
 
502
static void check_change(void)
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;                 /* lets 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 dont't use seeks with verify.
539
 */
540
 
541
static __inline__ void set_head_settle_flag(void)
542
{
543
        HeadSettleFlag = FDC1772CMDADD_E;
544
}
545
 
546
static __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
 
558
static void (*FloppyIRQHandler) (int status) = NULL;
559
 
560
static void floppy_irqconsequencehandler(void)
561
{
562
        unsigned char status;
563
        void (*handler) (int);
564
 
565
        fdc1772_fdc_int_done = 0;
566
 
567
        handler = FloppyIRQHandler;
568
        FloppyIRQHandler = NULL;
569
 
570
        if (handler) {
571
                nop();
572
                status = (unsigned char) fdc1772_comendstatus;
573
                DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));
574
                handler(status);
575
        } else {
576
                DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));
577
        }
578
        DPRINT(("FDC1772 irq: end of floppy_irq\n"));
579
}
580
 
581
 
582
/* Error handling: If some error happened, retry some times, then
583
 * recalibrate, then try again, and fail after MAX_ERRORS.
584
 */
585
 
586
static void fd_error(void)
587
{
588
        printk("FDC1772: fd_error\n");
589
        /*panic("fd1772: fd_error"); *//* DAG tmp */
590
        if (!CURRENT)
591
                return;
592
        CURRENT->errors++;
593
        if (CURRENT->errors >= MAX_ERRORS) {
594
                printk("fd%d: too many errors.\n", SelectedDrive);
595
                end_request(0);
596
        } else if (CURRENT->errors == RECALIBRATE_ERRORS) {
597
                printk("fd%d: recalibrating\n", SelectedDrive);
598
                if (SelectedDrive != -1)
599
                        unit[SelectedDrive].track = -1;
600
        }
601
        redo_fd_request();
602
}
603
 
604
 
605
 
606
#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
607
 
608
 
609
/* do_fd_action() is the general procedure for a fd request: All
610
 * required parameter settings (drive select, side select, track
611
 * position) are checked and set if needed. For each of these
612
 * parameters and the actual reading or writing exist two functions:
613
 * one that starts the setting (or skips it if possible) and one
614
 * callback for the "done" interrupt. Each done func calls the next
615
 * set function to propagate the request down to fd_rwsec_done().
616
 */
617
 
618
static void do_fd_action(int drive)
619
{
620
        DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));
621
 
622
#ifdef TRACKBUFFER
623
  repeat:
624
 
625
  if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
626
    if (ReqCmd == READ) {
627
      copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
628
      if (++ReqCnt < CURRENT->current_nr_sectors) {
629
        /* read next sector */
630
        setup_req_params( drive );
631
        goto repeat;
632
      }
633
      else {
634
        /* all sectors finished */
635
        CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
636
        CURRENT->sector += CURRENT->current_nr_sectors;
637
        end_request( 1 );
638
        redo_fd_request();
639
        return;
640
      }
641
    }
642
    else {
643
      /* cmd == WRITE, pay attention to track buffer
644
       * consistency! */
645
      copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
646
    }
647
  }
648
#endif
649
 
650
        if (SelectedDrive != drive) {
651
                /*unit[drive].track = -1; DAG */
652
                fd_select_drive(drive);
653
        };
654
 
655
 
656
        if (unit[drive].track == -1)
657
                fd_calibrate();
658
        else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
659
                fd_seek();
660
        else
661
                fd_rwsec();
662
}
663
 
664
 
665
/* Seek to track 0 if the current track is unknown */
666
 
667
static void fd_calibrate(void)
668
{
669
        DPRINT(("fd_calibrate\n"));
670
        if (unit[SelectedDrive].track >= 0) {
671
                fd_calibrate_done(0);
672
                return;
673
        }
674
        DPRINT(("fd_calibrate (after track compare)\n"));
675
        SET_IRQ_HANDLER(fd_calibrate_done);
676
        /* we can't verify, since the speed may be incorrect */
677
        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);
678
 
679
        NeedSeek = 1;
680
        MotorOn = 1;
681
        START_TIMEOUT();
682
        /* wait for IRQ */
683
}
684
 
685
 
686
static void fd_calibrate_done(int status)
687
{
688
        DPRINT(("fd_calibrate_done()\n"));
689
        STOP_TIMEOUT();
690
 
691
        /* set the correct speed now */
692
        if (status & FDC1772STAT_RECNF) {
693
                printk("fd%d: restore failed\n", SelectedDrive);
694
                fd_error();
695
        } else {
696
                unit[SelectedDrive].track = 0;
697
                fd_seek();
698
        }
699
}
700
 
701
 
702
/* Seek the drive to the requested track. The drive must have been
703
 * calibrated at some point before this.
704
 */
705
 
706
static void fd_seek(void)
707
{
708
  unsigned long flags;
709
        DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
710
                unit[SelectedDrive].track));
711
        if (unit[SelectedDrive].track == ReqTrack <<
712
            unit[SelectedDrive].disktype->stretch) {
713
                fd_seek_done(0);
714
                return;
715
        }
716
        FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
717
                      unit[SelectedDrive].disktype->stretch);
718
        udelay(25);
719
  save_flags(flags);
720
  cliIF();
721
        SET_IRQ_HANDLER(fd_seek_done);
722
        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |
723
                /* DAG */
724
                (MotorOn?FDC1772CMDADD_H:0));
725
 
726
  restore_flags(flags);
727
        MotorOn = 1;
728
        set_head_settle_flag();
729
        START_TIMEOUT();
730
        /* wait for IRQ */
731
}
732
 
733
 
734
static void fd_seek_done(int status)
735
{
736
        DPRINT(("fd_seek_done()\n"));
737
        STOP_TIMEOUT();
738
 
739
        /* set the correct speed */
740
        if (status & FDC1772STAT_RECNF) {
741
                printk("fd%d: seek error (to track %d)\n",
742
                       SelectedDrive, ReqTrack);
743
                /* we don't know exactly which track we are on now! */
744
                unit[SelectedDrive].track = -1;
745
                fd_error();
746
        } else {
747
                unit[SelectedDrive].track = ReqTrack <<
748
                    unit[SelectedDrive].disktype->stretch;
749
                NeedSeek = 0;
750
                fd_rwsec();
751
        }
752
}
753
 
754
 
755
/* This does the actual reading/writing after positioning the head
756
 * over the correct track.
757
 */
758
 
759
#ifdef TRACKBUFFER
760
static int MultReadInProgress = 0;
761
#endif
762
 
763
 
764
static void fd_rwsec(void)
765
{
766
        unsigned long paddr, flags;
767
        unsigned int rwflag, old_motoron;
768
        unsigned int track;
769
 
770
        DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));
771
        if (ReqCmd == WRITE) {
772
                /*cache_push( (unsigned long)ReqData, 512 ); */
773
                paddr = (unsigned long) ReqData;
774
                rwflag = 0x100;
775
        } else {
776
#ifdef TRACKBUFFER
777
    if (read_track)
778
      paddr = (unsigned long)PhysTrackBuffer;
779
    else
780
      paddr =(unsigned long)PhysDMABuffer;
781
#else
782
    paddr = (unsigned long)PhysDMABuffer;
783
#endif
784
                rwflag = 0;
785
        }
786
 
787
        DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,
788
                ReqSector, FDC1772_READ(FDC1772REG_TRACK)));
789
        fd_select_side(ReqSide);
790
 
791
        /*DPRINT(("fd_rwsec() before start sector \n")); */
792
        /* Start sector of this operation */
793
#ifdef TRACKBUFFER
794
  FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );
795
#else
796
  FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );
797
#endif
798
 
799
        /* Cheat for track if stretch != 0 */
800
        if (unit[SelectedDrive].disktype->stretch) {
801
                track = FDC1772_READ(FDC1772REG_TRACK);
802
                FDC1772_WRITE(FDC1772REG_TRACK, track >>
803
                              unit[SelectedDrive].disktype->stretch);
804
        }
805
        udelay(25);
806
 
807
        DPRINT(("fd_rwsec() before setup DMA \n"));
808
        /* Setup DMA - Heavily modified by DAG */
809
        save_flags(flags);
810
        cliIF();
811
        disable_dma(FLOPPY_DMA);
812
        set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);
813
        set_dma_addr(FLOPPY_DMA, (long) paddr);         /* DAG - changed from Atari specific */
814
#ifdef TRACKBUFFER
815
  set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);
816
#else
817
        set_dma_count(FLOPPY_DMA, 512);         /* Block/sector size - going to have to change */
818
#endif
819
        SET_IRQ_HANDLER(fd_rwsec_done);
820
        /* Turn on dma int */
821
        enable_dma(FLOPPY_DMA);
822
        /* Now give it something to do */
823
        FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) :
824
#ifdef TRACKBUFFER
825
              (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) |
826
              /* Hmm - the idea here is to stop the FDC spinning the disc
827
              up when we know that we already still have it spinning */
828
              (MotorOn?FDC1772CMDADD_H:0))
829
#else
830
              FDC1772CMD_RDSEC
831
#endif
832
    ));
833
 
834
        restore_flags(flags);
835
        DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));
836
        /*sti(); *//* DAG - Hmm */
837
        /* Hmm - should do something DAG */
838
        old_motoron = MotorOn;
839
        MotorOn = 1;
840
        NeedSeek = 1;
841
 
842
        /* wait for interrupt */
843
 
844
#ifdef TRACKBUFFER
845
  if (read_track) {
846
    /* If reading a whole track, wait about one disk rotation and
847
     * then check if all sectors are read. The FDC will even
848
     * search for the first non-existant sector and need 1 sec to
849
     * recognise that it isn't present :-(
850
     */
851
    del_timer( &readtrack_timer );
852
    readtrack_timer.function = fd_readtrack_check;
853
    readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ);
854
                              /* 1 rot. + 5 rot.s if motor was off  */
855
    DPRINT(("Setting readtrack_timer to %d @ %d\n",readtrack_timer.expires,jiffies));
856
    add_timer( &readtrack_timer );
857
    MultReadInProgress = 1;
858
 }
859
#endif
860
 
861
        /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */
862
        START_TIMEOUT();
863
        /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */
864
}
865
 
866
 
867
#ifdef TRACKBUFFER
868
 
869
static void fd_readtrack_check( unsigned long dummy )
870
 
871
{ unsigned long flags, addr;
872
  extern unsigned char *fdc1772_dataaddr;
873
 
874
  DPRINT(("fd_readtrack_check @ %d\n",jiffies));
875
 
876
  save_flags(flags);
877
  cliIF();
878
 
879
  del_timer( &readtrack_timer );
880
 
881
  if (!MultReadInProgress) {
882
    /* This prevents a race condition that could arise if the
883
     * interrupt is triggered while the calling of this timer
884
     * callback function takes place. The IRQ function then has
885
     * already cleared 'MultReadInProgress'  when control flow
886
     * gets here.
887
     */
888
        restore_flags(flags);
889
    return;
890
  }
891
 
892
  /* get the current DMA address */
893
  addr=fdc1772_dataaddr; /* DAG - ? */
894
  DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%p\n",addr,PhysTrackBuffer));
895
 
896
  if (addr >= (unsigned long)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
897
    /* already read enough data, force an FDC interrupt to stop
898
     * the read operation
899
     */
900
    SET_IRQ_HANDLER( NULL );
901
    restore_flags(flags);
902
    DPRINT(("fd_readtrack_check(): done\n"));
903
    FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI );
904
    udelay(25);
905
 
906
    /* No error until now -- the FDC would have interrupted
907
     * otherwise!
908
     */
909
    fd_rwsec_done( 0 );
910
  }
911
  else {
912
    /* not yet finished, wait another tenth rotation */
913
    restore_flags(flags);
914
    DPRINT(("fd_readtrack_check(): not yet finished\n"));
915
    readtrack_timer.expires = jiffies + HZ/5/10;
916
    add_timer( &readtrack_timer );
917
  }
918
}
919
 
920
#endif
921
 
922
static void fd_rwsec_done(int status)
923
{
924
        unsigned int track;
925
 
926
        DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies));
927
 
928
#ifdef TRACKBUFFER
929
  if (read_track && !MultReadInProgress) return;
930
  MultReadInProgress = 0;
931
 
932
  STOP_TIMEOUT();
933
 
934
  if (read_track)
935
    del_timer( &readtrack_timer );
936
#endif
937
 
938
 
939
        /* Correct the track if stretch != 0 */
940
        if (unit[SelectedDrive].disktype->stretch) {
941
                track = FDC1772_READ(FDC1772REG_TRACK);
942
                FDC1772_WRITE(FDC1772REG_TRACK, track <<
943
                              unit[SelectedDrive].disktype->stretch);
944
        }
945
        if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) {
946
                printk("fd%d: is write protected\n", SelectedDrive);
947
                goto err_end;
948
        }
949
        if ((status & FDC1772STAT_RECNF)
950
#ifdef TRACKBUFFER
951
    /* RECNF is no error after a multiple read when the FDC
952
     * searched for a non-existant sector!
953
     */
954
    && !(read_track &&
955
       FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)
956
#endif
957
    ) {
958
                if (Probing) {
959
                        if (unit[SelectedDrive].disktype > disk_type) {
960
                                /* try another disk type */
961
                                unit[SelectedDrive].disktype--;
962
                                floppy_sizes[SelectedDrive]
963
                                    = unit[SelectedDrive].disktype->blocks >> 1;
964
                        } else
965
                                Probing = 0;
966
                } else {
967
                        /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
968
                        if (unit[SelectedDrive].autoprobe) {
969
                                unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1;
970
                                floppy_sizes[SelectedDrive]
971
                                    = unit[SelectedDrive].disktype->blocks >> 1;
972
                                Probing = 1;
973
                        }
974
                }
975
                if (Probing) {
976
                        setup_req_params(SelectedDrive);
977
#ifdef TRACKBUFFER
978
      BufferDrive = -1;
979
#endif
980
                        do_fd_action(SelectedDrive);
981
                        return;
982
                }
983
                printk("fd%d: sector %d not found (side %d, track %d)\n",
984
                       SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack);
985
                goto err_end;
986
        }
987
        if (status & FDC1772STAT_CRC) {
988
                printk("fd%d: CRC error (side %d, track %d, sector %d)\n",
989
                       SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
990
                goto err_end;
991
        }
992
        if (status & FDC1772STAT_LOST) {
993
                printk("fd%d: lost data (side %d, track %d, sector %d)\n",
994
                       SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
995
                goto err_end;
996
        }
997
        Probing = 0;
998
 
999
        if (ReqCmd == READ) {
1000
#ifdef TRACKBUFFER
1001
    if (!read_track)
1002
      {
1003
        /*cache_clear (PhysDMABuffer, 512);*/
1004
        copy_buffer (DMABuffer, ReqData);
1005
      }
1006
    else
1007
      {
1008
        /*cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);*/
1009
        BufferDrive = SelectedDrive;
1010
        BufferSide  = ReqSide;
1011
        BufferTrack = ReqTrack;
1012
        copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
1013
      }
1014
#else
1015
                /*cache_clear( PhysDMABuffer, 512 ); */
1016
                copy_buffer(DMABuffer, ReqData);
1017
#endif
1018
        }
1019
        if (++ReqCnt < CURRENT->current_nr_sectors) {
1020
                /* read next sector */
1021
                setup_req_params(SelectedDrive);
1022
                do_fd_action(SelectedDrive);
1023
        } else {
1024
                /* all sectors finished */
1025
                CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
1026
                CURRENT->sector += CURRENT->current_nr_sectors;
1027
                end_request(1);
1028
                redo_fd_request();
1029
        }
1030
        return;
1031
 
1032
  err_end:
1033
#ifdef TRACKBUFFER
1034
  BufferDrive = -1;
1035
#endif
1036
 
1037
        fd_error();
1038
}
1039
 
1040
 
1041
static void fd_times_out(unsigned long dummy)
1042
{
1043
        SET_IRQ_HANDLER(NULL);
1044
        /* If the timeout occured while the readtrack_check timer was
1045
         * active, we need to cancel it, else bad things will happen */
1046
        del_timer( &readtrack_timer );
1047
        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1048
        udelay(25);
1049
 
1050
        printk("floppy timeout\n");
1051
        STOP_TIMEOUT();         /* hmm - should we do this ? */
1052
        fd_error();
1053
}
1054
 
1055
 
1056
/* The (noop) seek operation here is needed to make the WP bit in the
1057
 * FDC1772 status register accessible for check_change. If the last disk
1058
 * operation would have been a RDSEC, this bit would always read as 0
1059
 * no matter what :-( To save time, the seek goes to the track we're
1060
 * already on.
1061
 */
1062
 
1063
static void finish_fdc(void)
1064
{
1065
        /* DAG - just try without this dummy seek! */
1066
        finish_fdc_done(0);
1067
        return;
1068
 
1069
        if (!NeedSeek) {
1070
                finish_fdc_done(0);
1071
        } else {
1072
                DPRINT(("finish_fdc: dummy seek started\n"));
1073
                FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track);
1074
                SET_IRQ_HANDLER(finish_fdc_done);
1075
                FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
1076
                MotorOn = 1;
1077
                START_TIMEOUT();
1078
                /* we must wait for the IRQ here, because the ST-DMA is
1079
                 * released immediatly afterwards and the interrupt may be
1080
                 * delivered to the wrong driver.
1081
                 */
1082
        }
1083
}
1084
 
1085
 
1086
static void finish_fdc_done(int dummy)
1087
{
1088
        unsigned long flags;
1089
 
1090
        DPRINT(("finish_fdc_done entered\n"));
1091
        STOP_TIMEOUT();
1092
        NeedSeek = 0;
1093
 
1094
        if ((timer_active & (1 << FLOPPY_TIMER)) &&
1095
            timer_table[FLOPPY_TIMER].expires < jiffies + 5)
1096
                /* If the check for a disk change is done too early after this
1097
                 * last seek command, the WP bit still reads wrong :-((
1098
                 */
1099
                timer_table[FLOPPY_TIMER].expires = jiffies + 5;
1100
        else {
1101
                /*      START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
1102
        };
1103
        del_timer(&motor_off_timer);
1104
        START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
1105
 
1106
        save_flags(flags);
1107
        cli();
1108
        /* stdma_release(); - not sure if I should do something DAG  */
1109
        fdc_busy = 0;
1110
        wake_up(&fdc_wait);
1111
        restore_flags(flags);
1112
 
1113
        DPRINT(("finish_fdc() finished\n"));
1114
}
1115
 
1116
 
1117
/* Prevent "aliased" accesses. */
1118
static fd_ref[4] =
1119
{0, 0, 0, 0};
1120
static fd_device[4] =
1121
{0, 0, 0, 0};
1122
 
1123
/*
1124
 * Current device number. Taken either from the block header or from the
1125
 * format request descriptor.
1126
 */
1127
#define CURRENT_DEVICE (CURRENT->rq_dev)
1128
 
1129
/* Current error count. */
1130
#define CURRENT_ERRORS (CURRENT->errors)
1131
 
1132
 
1133
/* dummy for blk.h */
1134
static void floppy_off(unsigned int nr)
1135
{
1136
}
1137
 
1138
 
1139
/* On the old arcs write protect depends on the particular model
1140
   of machine.  On the A310, R140, and A440 there is a disc changed
1141
   detect, however on the A4x0/1 range there is not.  There
1142
   is nothing to tell you which machine your on.
1143
   At the moment I'm just marking changed always. I've
1144
   left the Atari's 'change on write protect change' code in this
1145
   part (but nothing sets it).
1146
   RiscOS apparently checks the disc serial number etc. to detect changes
1147
   - but if it sees a disc change line go high (?) it flips to using
1148
   it. Well  maybe I'll add that in the future (!?)
1149
*/
1150
static int check_floppy_change(dev_t dev)
1151
{
1152
        unsigned int drive = (dev & 0x03);
1153
 
1154
        if (MAJOR(dev) != MAJOR_NR) {
1155
                printk("floppy_changed: not a floppy\n");
1156
                return 0;
1157
        }
1158
        if (test_bit(drive, &fake_change)) {
1159
                /* simulated change (e.g. after formatting) */
1160
                return 1;
1161
        }
1162
        if (test_bit(drive, &changed_floppies)) {
1163
                /* surely changed (the WP signal changed at least once) */
1164
                return 1;
1165
        }
1166
        if (unit[drive].wpstat) {
1167
                /* WP is on -> could be changed: to be sure, buffers should be
1168
                   * invalidated...
1169
                 */
1170
                return 1;
1171
        }
1172
        return 1; /* DAG - was 0 */
1173
}
1174
 
1175
static int floppy_revalidate(dev_t dev)
1176
{
1177
        int drive = dev & 3;
1178
 
1179
        if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change)
1180
            || unit[drive].disktype == 0) {
1181
#ifdef TRACKBUFFER
1182
      BufferDrive = -1;
1183
#endif
1184
                clear_bit(drive, &fake_change);
1185
                clear_bit(drive, &changed_floppies);
1186
                unit[drive].disktype = 0;
1187
        }
1188
        return 0;
1189
}
1190
 
1191
static __inline__ void copy_buffer(void *from, void *to)
1192
{
1193
        ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
1194
        int cnt;
1195
 
1196
        for (cnt = 512 / 4; cnt; cnt--)
1197
                *p2++ = *p1++;
1198
}
1199
 
1200
 
1201
/* This sets up the global variables describing the current request. */
1202
 
1203
static void setup_req_params(int drive)
1204
{
1205
        int block = ReqBlock + ReqCnt;
1206
 
1207
        ReqTrack = block / unit[drive].disktype->spt;
1208
        ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
1209
        ReqSide = ReqTrack & 1;
1210
        ReqTrack >>= 1;
1211
        ReqData = ReqBuffer + 512 * ReqCnt;
1212
 
1213
#ifdef TRACKBUFFER
1214
  read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
1215
#endif
1216
 
1217
        DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
1218
                ReqTrack, ReqSector, (unsigned long) ReqData));
1219
}
1220
 
1221
 
1222
static void redo_fd_request(void)
1223
{
1224
        int device, drive, type;
1225
        struct archy_floppy_struct *floppy;
1226
 
1227
        DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n",
1228
                (unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0,
1229
                CURRENT ? CURRENT->sector : 0));
1230
 
1231
        if (CURRENT && CURRENT->rq_status == RQ_INACTIVE)
1232
                goto the_end;
1233
 
1234
      repeat:
1235
 
1236
        if (!CURRENT)
1237
                goto the_end;
1238
 
1239
        if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
1240
                panic(DEVICE_NAME ": request list destroyed");
1241
 
1242
        if (CURRENT->bh) {
1243
                if (!buffer_locked(CURRENT->bh))
1244
                        panic(DEVICE_NAME ": block not locked");
1245
        }
1246
        device = MINOR(CURRENT_DEVICE);
1247
        drive = device & 3;
1248
        type = device >> 2;
1249
        floppy = &unit[drive];
1250
 
1251
        if (!floppy->connected) {
1252
                /* drive not connected */
1253
                printk("Unknown Device: fd%d\n", drive);
1254
                end_request(0);
1255
                goto repeat;
1256
        }
1257
        if (type == 0) {
1258
                if (!floppy->disktype) {
1259
                        Probing = 1;
1260
                        floppy->disktype = disk_type + NUM_DISK_TYPES - 1;
1261
                        floppy_sizes[drive] = floppy->disktype->blocks >> 1;
1262
                        floppy->autoprobe = 1;
1263
                }
1264
        } else {
1265
                /* user supplied disk type */
1266
                --type;
1267
                if (type >= NUM_DISK_TYPES) {
1268
                        printk("fd%d: invalid disk format", drive);
1269
                        end_request(0);
1270
                        goto repeat;
1271
                }
1272
                floppy->disktype = &disk_type[type];
1273
                floppy_sizes[drive] = disk_type[type].blocks >> 1;
1274
                floppy->autoprobe = 0;
1275
        }
1276
 
1277
        if (CURRENT->sector + 1 > floppy->disktype->blocks) {
1278
                end_request(0);
1279
                goto repeat;
1280
        }
1281
        /* stop deselect timer */
1282
        del_timer(&motor_off_timer);
1283
 
1284
        ReqCnt = 0;
1285
        ReqCmd = CURRENT->cmd;
1286
        ReqBlock = CURRENT->sector;
1287
        ReqBuffer = CURRENT->buffer;
1288
        setup_req_params(drive);
1289
        do_fd_action(drive);
1290
 
1291
        return;
1292
 
1293
      the_end:
1294
        finish_fdc();
1295
}
1296
 
1297
static void fd1772_checkint(void)
1298
{
1299
  extern int fdc1772_bytestogo;
1300
 
1301
  /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/
1302
  if (fdc1772_fdc_int_done)
1303
    floppy_irqconsequencehandler();
1304
  if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0);
1305
  if (fdc_busy) {
1306
    queue_task(&fd1772_tq,&tq_immediate);
1307
    mark_bh(IMMEDIATE_BH);
1308
  };
1309
};
1310
 
1311
void do_fd_request(void)
1312
{
1313
        unsigned long flags;
1314
 
1315
        DPRINT(("do_fd_request for pid %d\n", current->pid));
1316
        if (fdc_busy) return;
1317
        save_flags(flags);
1318
        cli();
1319
        while (fdc_busy)
1320
                sleep_on(&fdc_wait);
1321
        fdc_busy = 1;
1322
        ENABLE_IRQ();
1323
        restore_flags(flags);
1324
 
1325
        fdc1772_fdc_int_done = 0;
1326
 
1327
        redo_fd_request();
1328
 
1329
  queue_task(&fd1772_tq,&tq_immediate);
1330
  mark_bh(IMMEDIATE_BH);
1331
}
1332
 
1333
 
1334
static int invalidate_drive(int rdev)
1335
{
1336
        /* invalidate the buffer track to force a reread */
1337
#ifdef TRACKBUFFER
1338
  BufferDrive = -1;
1339
#endif
1340
 
1341
        set_bit(rdev & 3, &fake_change);
1342
        check_disk_change(rdev);
1343
        return 0;
1344
}
1345
 
1346
static int fd_ioctl(struct inode *inode, struct file *filp,
1347
                    unsigned int cmd, unsigned long param)
1348
{
1349
#define IOCTL_MODE_BIT 8
1350
#define OPEN_WRITE_BIT 16
1351
#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
1352
 
1353
        int drive, device;
1354
 
1355
        device = inode->i_rdev;
1356
        switch (cmd) {
1357
                RO_IOCTLS(inode->i_rdev, param);
1358
        }
1359
        drive = MINOR(device);
1360
        if (!IOCTL_ALLOWED)
1361
                return -EPERM;
1362
        switch (cmd) {
1363
        case FDFMTBEG:
1364
                return 0;
1365
                /* case FDC1772LRPRM:  ??? DAG what does this do??
1366
                   unit[drive].disktype = NULL;
1367
                   floppy_sizes[drive] = MAX_DISK_SIZE;
1368
                   return invalidate_drive (device); */
1369
        case FDFMTEND:
1370
        case FDFLUSH:
1371
                return invalidate_drive(drive);
1372
        }
1373
        if (!suser())
1374
                return -EPERM;
1375
        if (drive < 0 || drive > 3)
1376
                return -EINVAL;
1377
        switch (cmd) {
1378
        default:
1379
                return -EINVAL;
1380
        }
1381
        return 0;
1382
}
1383
 
1384
 
1385
/* Initialize the 'unit' variable for drive 'drive' */
1386
 
1387
static void fd_probe(int drive)
1388
{
1389
        unit[drive].connected = 0;
1390
        unit[drive].disktype = NULL;
1391
 
1392
        if (!fd_test_drive_present(drive))
1393
                return;
1394
 
1395
        unit[drive].connected = 1;
1396
        unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */
1397
        unit[drive].steprate = FDC1772STEP_6;
1398
        MotorOn = 1;            /* from probe restore operation! */
1399
}
1400
 
1401
 
1402
/* This function tests the physical presence of a floppy drive (not
1403
 * whether a disk is inserted). This is done by issuing a restore
1404
 * command, waiting max. 2 seconds (that should be enough to move the
1405
 * head across the whole disk) and looking at the state of the "TR00"
1406
 * signal. This should now be raised if there is a drive connected
1407
 * (and there is no hardware failure :-) Otherwise, the drive is
1408
 * declared absent.
1409
 */
1410
 
1411
static int fd_test_drive_present(int drive)
1412
{
1413
        unsigned long timeout;
1414
        unsigned char status;
1415
        int ok;
1416
 
1417
        printk("fd_test_drive_present %d\n", drive);
1418
        if (drive > 1)
1419
                return (0);
1420
        return (1);             /* Simple hack for the moment - the autodetect doesn't seem to work on arc */
1421
        fd_select_drive(drive);
1422
 
1423
        /* disable interrupt temporarily */
1424
        DISABLE_IRQ();
1425
        FDC1772_WRITE(FDC1772REG_TRACK, 0x00);  /* was ff00 why? */
1426
        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
1427
 
1428
        /*printk("fd_test_drive_present: Going into timeout loop\n"); */
1429
        for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; jiffies < timeout;) {
1430
                /*  What does this piece of atariism do? - query for an interrupt? */
1431
                /*  if (!(mfp.par_dt_reg & 0x20))
1432
                   break; */
1433
                /* Well this is my nearest guess - quit when we get an FDC interrupt */
1434
                if (IOC_FIQSTAT & 2)
1435
                        break;
1436
        }
1437
 
1438
        /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */
1439
        status = FDC1772_READ(FDC1772REG_STATUS);
1440
        ok = (status & FDC1772STAT_TR00) != 0;
1441
 
1442
        /*printk("fd_test_drive_present: ok=%d\n",ok); */
1443
        /* force interrupt to abort restore operation (FDC1772 would try
1444
         * about 50 seconds!) */
1445
        FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1446
        udelay(500);
1447
        status = FDC1772_READ(FDC1772REG_STATUS);
1448
        udelay(20);
1449
        /*printk("fd_test_drive_present: just before OK code %d\n",ok); */
1450
 
1451
        if (ok) {
1452
                /* dummy seek command to make WP bit accessible */
1453
                FDC1772_WRITE(FDC1772REG_DATA, 0);
1454
                FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
1455
                printk("fd_test_drive_present: just before wait for int\n");
1456
                /* DAG: Guess means wait for interrupt */
1457
                while (!(IOC_FIQSTAT & 2));
1458
                printk("fd_test_drive_present: just after wait for int\n");
1459
                status = FDC1772_READ(FDC1772REG_STATUS);
1460
        }
1461
        printk("fd_test_drive_present: just before ENABLE_IRQ\n");
1462
        ENABLE_IRQ();
1463
        printk("fd_test_drive_present: about to return\n");
1464
        return (ok);
1465
}
1466
 
1467
 
1468
/* Look how many and which kind of drives are connected. If there are
1469
 * floppies, additionally start the disk-change and motor-off timers.
1470
 */
1471
 
1472
static void config_types(void)
1473
{
1474
        int drive, cnt = 0;
1475
 
1476
        printk("Probing floppy drive(s):\n");
1477
        for (drive = 0; drive < FD_MAX_UNITS; drive++) {
1478
                fd_probe(drive);
1479
                if (unit[drive].connected) {
1480
                        printk("fd%d\n", drive);
1481
                        ++cnt;
1482
                }
1483
        }
1484
 
1485
        if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) {
1486
                /* If FDC1772 is still busy from probing, give it another FORCI
1487
                 * command to abort the operation. If this isn't done, the FDC1772
1488
                 * will interrupt later and its IRQ line stays low, because
1489
                 * the status register isn't read. And this will block any
1490
                 * interrupts on this IRQ line :-(
1491
                 */
1492
                FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
1493
                udelay(500);
1494
                FDC1772_READ(FDC1772REG_STATUS);
1495
                udelay(20);
1496
        }
1497
        if (cnt > 0) {
1498
                START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
1499
                if (cnt == 1)
1500
                        fd_select_drive(0);
1501
                /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
1502
        }
1503
}
1504
 
1505
/*
1506
 * floppy_open check for aliasing (/dev/fd0 can be the same as
1507
 * /dev/PS0 etc), and disallows simultaneous access to the same
1508
 * drive with different device numbers.
1509
 */
1510
 
1511
static int floppy_open(struct inode *inode, struct file *filp)
1512
{
1513
        int drive;
1514
        int old_dev;
1515
 
1516
        if (!filp) {
1517
                DPRINT(("Weird, open called with filp=0\n"));
1518
                return -EIO;
1519
        }
1520
        drive = MINOR(inode->i_rdev) & 3;
1521
        if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
1522
                return -ENXIO;
1523
 
1524
        old_dev = fd_device[drive];
1525
 
1526
        if (fd_ref[drive])
1527
                if (old_dev != inode->i_rdev)
1528
                        return -EBUSY;
1529
 
1530
        if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
1531
                return -EBUSY;
1532
 
1533
        if (filp->f_flags & O_EXCL)
1534
                fd_ref[drive] = -1;
1535
        else
1536
                fd_ref[drive]++;
1537
 
1538
        fd_device[drive] = inode->i_rdev;
1539
 
1540
        if (old_dev && old_dev != inode->i_rdev)
1541
                invalidate_buffers(old_dev);
1542
 
1543
        /* Allow ioctls if we have write-permissions even if read-only open */
1544
        if (filp->f_mode & 2 || permission(inode, 2) == 0)
1545
                filp->f_mode |= IOCTL_MODE_BIT;
1546
        if (filp->f_mode & 2)
1547
                filp->f_mode |= OPEN_WRITE_BIT;
1548
 
1549
        if (filp->f_flags & O_NDELAY)
1550
                return 0;
1551
 
1552
        if (filp->f_mode & 3) {
1553
                check_disk_change(inode->i_rdev);
1554
                if (filp->f_mode & 2) {
1555
                        if (unit[drive].wpstat) {
1556
                                floppy_release(inode, filp);
1557
                                return -EROFS;
1558
                        }
1559
                }
1560
        }
1561
        return 0;
1562
}
1563
 
1564
 
1565
static void floppy_release(struct inode *inode, struct file *filp)
1566
{
1567
        int drive;
1568
 
1569
        drive = inode->i_rdev & 3;
1570
 
1571
        if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
1572
                /* if the file is mounted OR (writable now AND writable at open
1573
                   time) Linus: Does this cover all cases? */
1574
                block_fsync(inode, filp);
1575
 
1576
        if (fd_ref[drive] < 0)
1577
                fd_ref[drive] = 0;
1578
        else if (!fd_ref[drive]--) {
1579
                printk("floppy_release with fd_ref == 0");
1580
                fd_ref[drive] = 0;
1581
        }
1582
}
1583
 
1584
static struct file_operations floppy_fops =
1585
{
1586
        NULL,                   /* lseek - default */
1587
        block_read,             /* read - general block-dev read */
1588
        block_write,            /* write - general block-dev write */
1589
        NULL,                   /* readdir - bad */
1590
        NULL,                   /* select */
1591
        fd_ioctl,               /* ioctl */
1592
        NULL,                   /* mmap */
1593
        floppy_open,            /* open */
1594
        floppy_release,         /* release */
1595
        block_fsync,            /* fsync */
1596
        NULL,                   /* fasync */
1597
        check_floppy_change,    /* media_change */
1598
        floppy_revalidate,      /* revalidate */
1599
};
1600
 
1601
 
1602
int floppy_init(void)
1603
{
1604
        int i;
1605
 
1606
        if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
1607
                printk("Unable to get major %d for floppy\n", MAJOR_NR);
1608
                return 1;
1609
        }
1610
 
1611
        if (request_dma(FLOPPY_DMA, "fd1772")) {
1612
                printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA);
1613
                return 1;
1614
        };
1615
 
1616
        if (request_dma(FIQ_FD1772, "fd1772 end")) {
1617
                printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
1618
                free_dma(FLOPPY_DMA);
1619
                return 1;
1620
        };
1621
        enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */
1622
 
1623
        /* initialize variables */
1624
        SelectedDrive = -1;
1625
#ifdef TRACKBUFFER
1626
  BufferDrive = -1;
1627
#endif
1628
 
1629
        /* initialize check_change timer */
1630
        timer_table[FLOPPY_TIMER].fn = check_change;
1631
        timer_active &= ~(1 << FLOPPY_TIMER);
1632
 
1633
 
1634
#ifdef TRACKBUFFER
1635
  DMABuffer = (char *)kmalloc((MAX_SECTORS+1)*512,GFP_KERNEL); /* Atari uses 512 - I want to eventually cope with 1K sectors */
1636
  TrackBuffer = DMABuffer + 512;
1637
#else
1638
        /* Allocate memory for the DMAbuffer - on the Atari this takes it
1639
           out of some special memory... */
1640
        DMABuffer = (char *) kmalloc(2048);     /* Copes with pretty large sectors */
1641
#endif
1642
#ifdef TRACKBUFFER  
1643
  BufferDrive = BufferSide = BufferTrack = -1;
1644
#endif
1645
 
1646
        for (i = 0; i < FD_MAX_UNITS; i++) {
1647
                unit[i].track = -1;
1648
        }
1649
 
1650
        for (i = 0; i < 256; i++)
1651
                if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_TYPES)
1652
                        floppy_sizes[i] = disk_type[(i >> 2) - 1].blocks >> 1;
1653
                else
1654
                        floppy_sizes[i] = MAX_DISK_SIZE;
1655
 
1656
        blk_size[MAJOR_NR] = floppy_sizes;
1657
        blksize_size[MAJOR_NR] = floppy_blocksizes;
1658
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1659
 
1660
        config_types();
1661
 
1662
        return 0;
1663
}
1664
 
1665
/* Just a dummy at the moment */
1666
void floppy_setup(char *str, int *ints)
1667
{
1668
}
1669
 
1670
void floppy_eject(void) {
1671
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.