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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [block/] [ataflop.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  drivers/block/ataflop.c
3
 *
4
 *  Copyright (C) 1993  Greg Harp
5
 *  Atari Support by Bjoern Brauel, Roman Hodek
6
 *
7
 *  Big cleanup Sep 11..14 1994 Roman Hodek:
8
 *   - Driver now works interrupt driven
9
 *   - Support for two drives; should work, but I cannot test that :-(
10
 *   - Reading is done in whole tracks and buffered to speed up things
11
 *   - Disk change detection and drive deselecting after motor-off
12
 *     similar to TOS
13
 *   - Autodetection of disk format (DD/HD); untested yet, because I
14
 *     don't have an HD drive :-(
15
 *
16
 *  Fixes Nov 13 1994 Martin Schaller:
17
 *   - Autodetection works now
18
 *   - Support for 5 1/4'' disks
19
 *   - Removed drive type (unknown on atari)
20
 *   - Do seeks with 8 Mhz
21
 *
22
 *  Changes by Andreas Schwab:
23
 *   - After errors in multiple read mode try again reading single sectors
24
 *  (Feb 1995):
25
 *   - Clean up error handling
26
 *   - Set blk_size for proper size checking
27
 *   - Initialize track register when testing presence of floppy
28
 *   - Implement some ioctl's
29
 *
30
 *  Changes by Torsten Lang:
31
 *   - When probing the floppies we should add the FDCCMDADD_H flag since
32
 *     the FDC will otherwise wait forever when no disk is inserted...
33
 *
34
 * ++ Freddi Aschwanden (fa) 20.9.95 fixes for medusa:
35
 *  - MFPDELAY() after each FDC access -> atari
36
 *  - more/other disk formats
37
 *  - DMA to the block buffer directly if we have a 32bit DMA
38
 *  - for medusa, the step rate is always 3ms
39
 *  - on medusa, use only cache_push()
40
 * Roman:
41
 *  - Make disk format numbering independent from minors
42
 *  - Let user set max. supported drive type (speeds up format
43
 *    detection, saves buffer space)
44
 *
45
 * Roman 10/15/95:
46
 *  - implement some more ioctls
47
 *  - disk formatting
48
 *
49
 * Andreas 95/12/12:
50
 *  - increase gap size at start of track for HD/ED disks
51
 *
52
 *  Things left to do:
53
 *   - Formatting
54
 *   - Maybe a better strategy for disk change detection (does anyone
55
 *     know one?)
56
 */
57
 
58
#include <linux/module.h>
59
 
60
#include <linux/sched.h>
61
#include <linux/string.h>
62
#include <linux/fs.h>
63
#include <linux/fcntl.h>
64
#include <linux/kernel.h>
65
#include <linux/timer.h>
66
#include <linux/fd.h>
67
#include <linux/errno.h>
68
#include <linux/types.h>
69
#include <linux/delay.h>
70
#include <linux/mm.h>
71
#include <linux/malloc.h>
72
 
73
#include <asm/system.h>
74
#include <asm/bitops.h>
75
#include <asm/irq.h>
76
#include <asm/pgtable.h>
77
 
78
#include <asm/bootinfo.h>
79
#include <asm/atafd.h>
80
#include <asm/atafdreg.h>
81
#include <asm/atarihw.h>
82
#include <asm/atariints.h>
83
#include <asm/atari_stdma.h>
84
 
85
#define MAJOR_NR FLOPPY_MAJOR
86
#include <linux/blk.h>
87
 
88
#define FD_MAX_UNITS 2
89
 
90
#undef DEBUG
91
 
92
/* Disk types: DD, HD, ED */
93
static struct atari_disk_type {
94
        const char      *name;
95
        unsigned        spt;            /* sectors per track */
96
        unsigned        blocks;         /* total number of blocks */
97
        unsigned        fdc_speed;      /* fdc_speed setting */
98
        unsigned        stretch;        /* track doubling ? */
99
} disk_type[] = {
100
        { "d360",  9, 720, 0, 0}, /*  0: 360kB diskette */
101
        { "D360",  9, 720, 0, 1},        /*  1: 360kb in 720k or 1.2MB drive */
102
        { "D720",  9,1440, 0, 0}, /*  2: 720kb in 720k or 1.2MB drive */
103
        { "D820", 10,1640, 0, 0}, /*  3: DD disk with 82 tracks/10 sectors */
104
/* formats above are probed for type DD */
105
#define MAX_TYPE_DD 3
106
        { "h1200",15,2400, 3, 0},        /*  4: 1.2MB diskette */
107
        { "H1440",18,2880, 3, 0},        /*  5: 1.4 MB diskette (HD) */
108
        { "H1640",20,3280, 3, 0},        /*  6: 1.64MB diskette (fat HD) 82 tr 20 sec */
109
/* formats above are probed for types DD and HD */
110
#define MAX_TYPE_HD 6
111
        { "E2880",36,5760, 3, 0},        /*  7: 2.8 MB diskette (ED) */
112
        { "E3280",40,6560, 3, 0},        /*  8: 3.2 MB diskette (fat ED) 82 tr 40 sec */
113
/* formats above are probed for types DD, HD and ED */
114
#define MAX_TYPE_ED 8
115
/* types below are never autoprobed */
116
        { "H1680",21,3360, 3, 0},        /*  9: 1.68MB diskette (fat HD) 80 tr 21 sec */
117
        { "h410",10,820, 0, 1},          /* 10: 410k diskette 41 tr 10 sec, stretch */
118
        { "h1476",18,2952, 3, 0},        /* 11: 1.48MB diskette 82 tr 18 sec */
119
        { "H1722",21,3444, 3, 0},        /* 12: 1.72MB diskette 82 tr 21 sec */
120
        { "h420",10,840, 0, 1},          /* 13: 420k diskette 42 tr 10 sec, stretch */
121
        { "H830",10,1660, 0, 0},  /* 14: 820k diskette 83 tr 10 sec */
122
        { "h1494",18,2952, 3, 0},        /* 15: 1.49MB diskette 83 tr 18 sec */
123
        { "H1743",21,3486, 3, 0},        /* 16: 1.74MB diskette 83 tr 21 sec */
124
        { "h880",11,1760, 0, 0},  /* 17: 880k diskette 80 tr 11 sec */
125
        { "D1040",13,2080, 0, 0}, /* 18: 1.04MB diskette 80 tr 13 sec */
126
        { "D1120",14,2240, 0, 0}, /* 19: 1.12MB diskette 80 tr 14 sec */
127
        { "h1600",20,3200, 3, 0},        /* 20: 1.60MB diskette 80 tr 20 sec */
128
        { "H1760",22,3520, 3, 0},        /* 21: 1.76MB diskette 80 tr 22 sec */
129
        { "H1920",24,3840, 3, 0},        /* 22: 1.92MB diskette 80 tr 24 sec */
130
        { "E3200",40,6400, 3, 0},        /* 23: 3.2MB diskette 80 tr 40 sec */
131
        { "E3520",44,7040, 3, 0},        /* 24: 3.52MB diskette 80 tr 44 sec */
132
        { "E3840",48,7680, 3, 0},        /* 25: 3.84MB diskette 80 tr 48 sec */
133
        { "H1840",23,3680, 3, 0},        /* 26: 1.84MB diskette 80 tr 23 sec */
134
        { "D800",10,1600, 0, 0},  /* 27: 800k diskette 80 tr 10 sec */
135
};
136
 
137
static int StartDiskType[] = {
138
        MAX_TYPE_DD,
139
        MAX_TYPE_HD,
140
        MAX_TYPE_ED
141
};
142
 
143
#define TYPE_DD         0
144
#define TYPE_HD         1
145
#define TYPE_ED         2
146
 
147
static int DriveType = TYPE_HD;
148
 
149
/* Array for translating minors into disk formats */
150
static struct {
151
        int      index;
152
        unsigned drive_types;
153
} minor2disktype[] = {
154
        {  0, TYPE_DD }, /*  1: d360 */
155
        {  4, TYPE_HD },        /*  2: h1200 */
156
        {  1, TYPE_DD },        /*  3: D360 */
157
        {  2, TYPE_DD },        /*  4: D720 */
158
        {  1, TYPE_DD },        /*  5: h360 = D360 */
159
        {  2, TYPE_DD },        /*  6: h720 = D720 */
160
        {  5, TYPE_HD },        /*  7: H1440 */
161
        {  7, TYPE_ED },        /*  8: E2880 */
162
/* some PC formats :-) */
163
        {  8, TYPE_ED },        /*  9: E3280    <- was "CompaQ" == E2880 for PC */
164
        {  5, TYPE_HD },        /* 10: h1440 = H1440 */
165
        {  9, TYPE_HD },        /* 11: H1680 */
166
        { 10, TYPE_DD },        /* 12: h410  */
167
        {  3, TYPE_DD },        /* 13: H820     <- == D820, 82x10 */
168
        { 11, TYPE_HD },        /* 14: h1476 */
169
        { 12, TYPE_HD },        /* 15: H1722 */
170
        { 13, TYPE_DD },        /* 16: h420  */
171
        { 14, TYPE_DD },        /* 17: H830  */
172
        { 15, TYPE_HD },        /* 18: h1494 */
173
        { 16, TYPE_HD },        /* 19: H1743 */
174
        { 17, TYPE_DD },        /* 20: h880  */
175
        { 18, TYPE_DD },        /* 21: D1040 */
176
        { 19, TYPE_DD },        /* 22: D1120 */
177
        { 20, TYPE_HD },        /* 23: h1600 */
178
        { 21, TYPE_HD },        /* 24: H1760 */
179
        { 22, TYPE_HD },        /* 25: H1920 */
180
        { 23, TYPE_ED },        /* 26: E3200 */
181
        { 24, TYPE_ED },        /* 27: E3520 */
182
        { 25, TYPE_ED },        /* 28: E3840 */
183
        { 26, TYPE_HD },        /* 29: H1840 */
184
        { 27, TYPE_DD },        /* 30: D800  */
185
        {  6, TYPE_HD },        /* 31: H1640    <- was H1600 == h1600 for PC */
186
};
187
 
188
#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype))
189
 
190
/*
191
 * Maximum disk size (in kilobytes). This default is used whenever the
192
 * current disk size is unknown.
193
 */
194
#define MAX_DISK_SIZE 3280
195
 
196
static int floppy_sizes[256];
197
static int floppy_blocksizes[256] = { 0, };
198
 
199
/* current info on each unit */
200
static struct atari_floppy_struct {
201
        int connected;                          /* !=0 : drive is connected */
202
        int autoprobe;                          /* !=0 : do autoprobe       */
203
 
204
        struct atari_disk_type  *disktype;      /* current type of disk */
205
 
206
        int track;              /* current head position or -1 if
207
                                   unknown */
208
        unsigned int steprate;  /* steprate setting */
209
        unsigned int wpstat;    /* current state of WP signal (for
210
                                   disk change detection) */
211
        int flags;              /* flags */
212
} unit[FD_MAX_UNITS];
213
 
214
#define UD      unit[drive]
215
#define UDT     unit[drive].disktype
216
#define SUD     unit[SelectedDrive]
217
#define SUDT    unit[SelectedDrive].disktype
218
 
219
 
220
#define FDC_READ(reg) ({                        \
221
    /* unsigned long __flags; */                \
222
    unsigned short __val;                       \
223
    /* save_flags(__flags); cli(); */           \
224
    dma_wd.dma_mode_status = 0x80 | (reg);      \
225
    udelay(25);                                 \
226
    __val = dma_wd.fdc_acces_seccount;          \
227
    MFPDELAY();                                 \
228
    /* restore_flags(__flags); */               \
229
    __val & 0xff;                               \
230
})
231
 
232
#define FDC_WRITE(reg,val)                      \
233
    do {                                        \
234
        /* unsigned long __flags; */            \
235
        /* save_flags(__flags); cli(); */       \
236
        dma_wd.dma_mode_status = 0x80 | (reg);  \
237
        udelay(25);                             \
238
        dma_wd.fdc_acces_seccount = (val);      \
239
        MFPDELAY();                             \
240
        /* restore_flags(__flags); */           \
241
    } while(0)
242
 
243
 
244
/* Buffering variables:
245
 * First, there is a DMA buffer in ST-RAM that is used for floppy DMA
246
 * operations. Second, a track buffer is used to cache a whole track
247
 * of the disk to save read operations. These are two separate buffers
248
 * because that allows write operations without clearing the track buffer.
249
 */
250
 
251
static int MaxSectors[] = {
252
        11, 22, 44
253
};
254
static int BufferSize[] = {
255
        15*512, 30*512, 60*512
256
};
257
 
258
#define MAX_SECTORS     (MaxSectors[DriveType])
259
#define BUFFER_SIZE     (BufferSize[DriveType])
260
 
261
unsigned char *DMABuffer;                         /* buffer for writes */
262
static unsigned long PhysDMABuffer;   /* physical address */
263
 
264
static int UseTrackbuffer = -1;           /* Do track buffering? */
265
 
266
unsigned char *TrackBuffer;                       /* buffer for reads */
267
static unsigned long PhysTrackBuffer; /* physical address */
268
static int BufferDrive, BufferSide, BufferTrack;
269
static int read_track;          /* non-zero if we are reading whole tracks */
270
 
271
#define SECTOR_BUFFER(sec)      (TrackBuffer + ((sec)-1)*512)
272
#define IS_BUFFERED(drive,side,track) \
273
    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
274
 
275
/*
276
 * These are global variables, as that's the easiest way to give
277
 * information to interrupts. They are the data used for the current
278
 * request.
279
 */
280
static int SelectedDrive = 0;
281
static int ReqCmd, ReqBlock;
282
static int ReqSide, ReqTrack, ReqSector, ReqCnt;
283
static int HeadSettleFlag = 0;
284
static unsigned char *ReqData, *ReqBuffer;
285
static int MotorOn = 0, MotorOffTrys;
286
static int IsFormatting = 0, FormatError;
287
 
288
static int UserSteprate[FD_MAX_UNITS] = { -1, -1 };
289
 
290
/* Synchronization of FDC access. */
291
static volatile int fdc_busy = 0;
292
static struct wait_queue *fdc_wait = NULL;
293
static struct wait_queue *format_wait = NULL;
294
 
295
static unsigned int changed_floppies = 0xff, fake_change = 0;
296
#define CHECK_CHANGE_DELAY      HZ/2
297
 
298
#define FD_MOTOR_OFF_DELAY      (3*HZ)
299
#define FD_MOTOR_OFF_MAXTRY     (10*20)
300
 
301
#define FLOPPY_TIMEOUT          (6*HZ)
302
#define RECALIBRATE_ERRORS      4       /* After this many errors the drive
303
                                         * will be recalibrated. */
304
#define MAX_ERRORS              8       /* After this many errors the driver
305
                                         * will give up. */
306
 
307
 
308
#define START_MOTOR_OFF_TIMER(delay)                            \
309
    do {                                                        \
310
        motor_off_timer.expires = jiffies + (delay);            \
311
        add_timer( &motor_off_timer );                          \
312
        MotorOffTrys = 0;                                        \
313
        } while(0)
314
 
315
#define START_CHECK_CHANGE_TIMER(delay)                         \
316
    do {                                                        \
317
        timer_table[FLOPPY_TIMER].expires = jiffies + (delay);  \
318
        timer_active |= (1 << FLOPPY_TIMER);                    \
319
        } while(0)
320
 
321
#define START_TIMEOUT()                                         \
322
    do {                                                        \
323
        del_timer( &timeout_timer );                            \
324
        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;       \
325
        add_timer( &timeout_timer );                            \
326
        } while(0)
327
 
328
#define STOP_TIMEOUT()                                          \
329
    do {                                                        \
330
        del_timer( &timeout_timer );                            \
331
        } while(0)
332
 
333
 
334
/*
335
 * The driver is trying to determine the correct media format
336
 * while Probing is set. fd_rwsec_done() clears it after a
337
 * successful access.
338
 */
339
static int Probing = 0;
340
 
341
/* This flag is set when a dummy seek is necessary to make the WP
342
 * status bit accessible.
343
 */
344
static int NeedSeek = 0;
345
 
346
 
347
#ifdef DEBUG
348
#define DPRINT(a)       printk a
349
#else
350
#define DPRINT(a)
351
#endif
352
 
353
/***************************** Prototypes *****************************/
354
 
355
static void fd_select_side( int side );
356
static void fd_select_drive( int drive );
357
static void fd_deselect( void );
358
static void fd_motor_off_timer( unsigned long dummy );
359
static void check_change( void );
360
static __inline__ void set_head_settle_flag( void );
361
static __inline__ int get_head_settle_flag( void );
362
static void floppy_irq (int irq, struct pt_regs *fp, void *dummy);
363
static void fd_error( void );
364
static int do_format(kdev_t drive, struct atari_format_descr *desc);
365
static void do_fd_action( int drive );
366
static void fd_calibrate( void );
367
static void fd_calibrate_done( int status );
368
static void fd_seek( void );
369
static void fd_seek_done( int status );
370
static void fd_rwsec( void );
371
static void fd_readtrack_check( unsigned long dummy );
372
static void fd_rwsec_done( int status );
373
static void fd_writetrack( void );
374
static void fd_writetrack_done( int status );
375
static void fd_times_out( unsigned long dummy );
376
static void finish_fdc( void );
377
static void finish_fdc_done( int dummy );
378
static void floppy_off( unsigned int nr);
379
static __inline__ void copy_buffer( void *from, void *to);
380
static void setup_req_params( int drive );
381
static void redo_fd_request( void);
382
static int invalidate_drive(kdev_t rdev);
383
static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int
384
                     cmd, unsigned long param);
385
static void fd_probe( int drive );
386
static int fd_test_drive_present( int drive );
387
static void config_types( void );
388
static int floppy_open( struct inode *inode, struct file *filp );
389
static void floppy_release( struct inode * inode, struct file * filp );
390
 
391
/************************* End of Prototypes **************************/
392
 
393
static struct timer_list motor_off_timer =
394
        { NULL, NULL, 0, 0, fd_motor_off_timer };
395
static struct timer_list readtrack_timer =
396
        { NULL, NULL, 0, 0, fd_readtrack_check };
397
 
398
static struct timer_list timeout_timer =
399
        { NULL, NULL, 0, 0, fd_times_out };
400
 
401
 
402
 
403
/* Select the side to use. */
404
 
405
static void fd_select_side( int side )
406
{
407
        unsigned long flags;
408
 
409
        save_flags(flags);
410
        cli(); /* protect against various other ints mucking around with the PSG */
411
 
412
        sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
413
        sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0x01 :
414
                                         sound_ym.rd_data_reg_sel & 0xfe;
415
 
416
        restore_flags(flags);
417
}
418
 
419
 
420
/* Select a drive, update the FDC's track register and set the correct
421
 * clock speed for this disk's type.
422
 */
423
 
424
static void fd_select_drive( int drive )
425
{
426
        unsigned long flags;
427
        unsigned char tmp;
428
 
429
        if (drive == SelectedDrive)
430
          return;
431
 
432
        save_flags(flags);
433
        cli(); /* protect against various other ints mucking around with the PSG */
434
        sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
435
        tmp = sound_ym.rd_data_reg_sel;
436
        sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1);
437
        restore_flags(flags);
438
 
439
        /* restore track register to saved value */
440
        FDC_WRITE( FDCREG_TRACK, UD.track );
441
        udelay(25);
442
 
443
        /* select 8/16 MHz */
444
        if (UDT)
445
                if (ATARIHW_PRESENT(FDCSPEED))
446
                        dma_wd.fdc_speed = UDT->fdc_speed;
447
 
448
        SelectedDrive = drive;
449
}
450
 
451
 
452
/* Deselect both drives. */
453
 
454
static void fd_deselect( void )
455
{
456
        unsigned long flags;
457
 
458
        save_flags(flags);
459
        cli(); /* protect against various other ints mucking around with the PSG */
460
        sound_ym.rd_data_reg_sel=14;    /* Select PSG Port A */
461
        sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */
462
        SelectedDrive = -1;
463
        restore_flags(flags);
464
}
465
 
466
 
467
/* This timer function deselects the drives when the FDC switched the
468
 * motor off. The deselection cannot happen earlier because the FDC
469
 * counts the index signals, which arrive only if one drive is selected.
470
 */
471
 
472
static void fd_motor_off_timer( unsigned long dummy )
473
{
474
/*      unsigned long flags; */
475
        unsigned char status;
476
        int                   delay;
477
 
478
        del_timer( &motor_off_timer );
479
 
480
        if (SelectedDrive < 0)
481
                /* no drive selected, needn't deselect anyone */
482
                return;
483
 
484
/*      save_flags(flags);
485
        cli(); */
486
 
487
        if (stdma_islocked())
488
                goto retry;
489
 
490
        status = FDC_READ( FDCREG_STATUS );
491
 
492
        if (!(status & 0x80)) {
493
                /* motor already turned off by FDC -> deselect drives */
494
                MotorOn = 0;
495
                fd_deselect();
496
/*              restore_flags(flags); */
497
                return;
498
        }
499
        /* not yet off, try again */
500
 
501
  retry:
502
/*      restore_flags(flags); */
503
        /* Test again later; if tested too often, it seems there is no disk
504
         * in the drive and the FDC will leave the motor on forever (or,
505
         * at least until a disk is inserted). So we'll test only twice
506
         * per second from then on...
507
         */
508
        delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
509
                        (++MotorOffTrys, HZ/20) : HZ/2;
510
        START_MOTOR_OFF_TIMER( delay );
511
}
512
 
513
 
514
/* This function is repeatedly called to detect disk changes (as good
515
 * as possible) and keep track of the current state of the write protection.
516
 */
517
 
518
static void check_change( void )
519
{
520
        static int    drive = 0;
521
 
522
        unsigned long flags;
523
        unsigned char old_porta;
524
        int                       stat;
525
 
526
        if (++drive > 1 || !UD.connected)
527
                drive = 0;
528
 
529
        save_flags(flags);
530
        cli(); /* protect against various other ints mucking around with the PSG */
531
 
532
        if (!stdma_islocked()) {
533
                sound_ym.rd_data_reg_sel = 14;
534
                old_porta = sound_ym.rd_data_reg_sel;
535
                sound_ym.wd_data = (old_porta | DSKDRVNONE) &
536
                                       ~(drive == 0 ? DSKDRV0 : DSKDRV1);
537
                stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT);
538
                sound_ym.wd_data = old_porta;
539
 
540
                if (stat != UD.wpstat) {
541
                        DPRINT(( "wpstat[%d] = %d\n", drive, stat ));
542
                        UD.wpstat = stat;
543
                        set_bit (drive, &changed_floppies);
544
                }
545
        }
546
        restore_flags(flags);
547
 
548
        START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
549
}
550
 
551
 
552
/* Handling of the Head Settling Flag: This flag should be set after each
553
 * seek operation, because we don't use seeks with verify.
554
 */
555
 
556
static __inline__ void set_head_settle_flag( void )
557
{
558
        HeadSettleFlag = FDCCMDADD_E;
559
}
560
 
561
static __inline__ int get_head_settle_flag( void )
562
{
563
        int     tmp = HeadSettleFlag;
564
        HeadSettleFlag = 0;
565
        return( tmp );
566
}
567
 
568
 
569
 
570
 
571
/* General Interrupt Handling */
572
 
573
static void (*FloppyIRQHandler)( int status ) = NULL;
574
 
575
static void floppy_irq (int irq, struct pt_regs *fp, void *dummy)
576
{
577
        unsigned char status;
578
        void (*handler)( int );
579
 
580
        handler = FloppyIRQHandler;
581
        FloppyIRQHandler = NULL;
582
 
583
        if (handler) {
584
                nop();
585
                status = FDC_READ( FDCREG_STATUS );
586
                DPRINT(("FDC irq, status = %02x handler = %08lx\n",status,(unsigned long)handler));
587
                handler( status );
588
        }
589
        else {
590
                DPRINT(("FDC irq, no handler\n"));
591
        }
592
}
593
 
594
 
595
/* Error handling: If some error happened, retry some times, then
596
 * recalibrate, then try again, and fail after MAX_ERRORS.
597
 */
598
 
599
static void fd_error( void )
600
{
601
        if (IsFormatting) {
602
                IsFormatting = 0;
603
                FormatError = 1;
604
                wake_up( &format_wait );
605
                return;
606
        }
607
 
608
        if (!CURRENT) return;
609
        CURRENT->errors++;
610
        if (CURRENT->errors >= MAX_ERRORS) {
611
                printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
612
                end_request( 0 );
613
        }
614
        else if (CURRENT->errors == RECALIBRATE_ERRORS) {
615
                printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
616
                if (SelectedDrive != -1)
617
                        SUD.track = -1;
618
        }
619
        redo_fd_request();
620
}
621
 
622
 
623
 
624
#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
625
 
626
 
627
/* ---------- Formatting ---------- */
628
 
629
#define FILL(n,val)             \
630
    do {                        \
631
        memset( p, val, n );    \
632
        p += n;                 \
633
    } while(0)
634
 
635
static int do_format(kdev_t device, struct atari_format_descr *desc)
636
{
637
        unsigned char   *p;
638
        int sect, nsect;
639
        unsigned long   flags;
640
        int type, drive = MINOR(device) & 3;
641
 
642
        DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
643
                drive, desc->track, desc->head, desc->sect_offset ));
644
 
645
        save_flags(flags);
646
        cli();
647
        while( fdc_busy ) sleep_on( &fdc_wait );
648
        fdc_busy = 1;
649
        stdma_lock(floppy_irq, NULL);
650
        atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
651
        restore_flags(flags);
652
 
653
        type = MINOR(device) >> 2;
654
        if (type) {
655
                if (--type >= NUM_DISK_MINORS ||
656
                    minor2disktype[type].drive_types > DriveType) {
657
                        redo_fd_request();
658
                        return -EINVAL;
659
                }
660
                type = minor2disktype[type].index;
661
                UDT = &disk_type[type];
662
        }
663
 
664
        if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
665
                redo_fd_request();
666
                return -EINVAL;
667
        }
668
 
669
        nsect = UDT->spt;
670
        p = TrackBuffer;
671
        /* The track buffer is used for the raw track data, so its
672
           contents become invalid! */
673
        BufferDrive = -1;
674
        /* stop deselect timer */
675
        del_timer( &motor_off_timer );
676
 
677
        FILL( 60 * (nsect / 9), 0x4e );
678
        for( sect = 0; sect < nsect; ++sect ) {
679
                FILL( 12, 0 );
680
                FILL( 3, 0xf5 );
681
                *p++ = 0xfe;
682
                *p++ = desc->track;
683
                *p++ = desc->head;
684
                *p++ = (nsect + sect - desc->sect_offset) % nsect + 1;
685
                *p++ = 2;
686
                *p++ = 0xf7;
687
                FILL( 22, 0x4e );
688
                FILL( 12, 0 );
689
                FILL( 3, 0xf5 );
690
                *p++ = 0xfb;
691
                FILL( 512, 0xe5 );
692
                *p++ = 0xf7;
693
                FILL( 40, 0x4e );
694
        }
695
        FILL( TrackBuffer+BUFFER_SIZE-p, 0x4e );
696
 
697
        IsFormatting = 1;
698
        FormatError = 0;
699
        ReqTrack = desc->track;
700
        ReqSide  = desc->head;
701
        do_fd_action( drive );
702
 
703
        sleep_on( &format_wait );
704
 
705
        redo_fd_request();
706
        return( FormatError ? -EIO : 0 );
707
}
708
 
709
 
710
/* do_fd_action() is the general procedure for a fd request: All
711
 * required parameter settings (drive select, side select, track
712
 * position) are checked and set if needed. For each of these
713
 * parameters and the actual reading or writing exist two functions:
714
 * one that starts the setting (or skips it if possible) and one
715
 * callback for the "done" interrupt. Each done func calls the next
716
 * set function to propagate the request down to fd_rwsec_done().
717
 */
718
 
719
static void do_fd_action( int drive )
720
{
721
        DPRINT(("do_fd_action\n"));
722
 
723
        if (UseTrackbuffer && !IsFormatting) {
724
        repeat:
725
            if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
726
                if (ReqCmd == READ) {
727
                    copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
728
                    if (++ReqCnt < CURRENT->current_nr_sectors) {
729
                        /* read next sector */
730
                        setup_req_params( drive );
731
                        goto repeat;
732
                    }
733
                    else {
734
                        /* all sectors finished */
735
                        CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
736
                        CURRENT->sector += CURRENT->current_nr_sectors;
737
                        end_request( 1 );
738
                        redo_fd_request();
739
                        return;
740
                    }
741
                }
742
                else {
743
                    /* cmd == WRITE, pay attention to track buffer
744
                     * consistency! */
745
                    copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
746
                }
747
            }
748
        }
749
 
750
        if (SelectedDrive != drive)
751
                fd_select_drive( drive );
752
 
753
        if (UD.track == -1)
754
                fd_calibrate();
755
        else if (UD.track != ReqTrack << UDT->stretch)
756
                fd_seek();
757
        else if (IsFormatting)
758
                fd_writetrack();
759
        else
760
                fd_rwsec();
761
}
762
 
763
 
764
/* Seek to track 0 if the current track is unknown */
765
 
766
static void fd_calibrate( void )
767
{
768
        if (SUD.track >= 0) {
769
                fd_calibrate_done( 0 );
770
                return;
771
        }
772
 
773
        if (ATARIHW_PRESENT(FDCSPEED))
774
                dma_wd.fdc_speed = 0;    /* always seek with 8 Mhz */;
775
        DPRINT(("fd_calibrate\n"));
776
        SET_IRQ_HANDLER( fd_calibrate_done );
777
        /* we can't verify, since the speed may be incorrect */
778
        FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | SUD.steprate );
779
 
780
        NeedSeek = 1;
781
        MotorOn = 1;
782
        START_TIMEOUT();
783
        /* wait for IRQ */
784
}
785
 
786
 
787
static void fd_calibrate_done( int status )
788
{
789
        DPRINT(("fd_calibrate_done()\n"));
790
        STOP_TIMEOUT();
791
 
792
        /* set the correct speed now */
793
        if (ATARIHW_PRESENT(FDCSPEED))
794
                dma_wd.fdc_speed = SUDT->fdc_speed;
795
        if (status & FDCSTAT_RECNF) {
796
                printk(KERN_ERR "fd%d: restore failed\n", SelectedDrive );
797
                fd_error();
798
        }
799
        else {
800
                SUD.track = 0;
801
                fd_seek();
802
        }
803
}
804
 
805
 
806
/* Seek the drive to the requested track. The drive must have been
807
 * calibrated at some point before this.
808
 */
809
 
810
static void fd_seek( void )
811
{
812
        if (SUD.track == ReqTrack << SUDT->stretch) {
813
                fd_seek_done( 0 );
814
                return;
815
        }
816
 
817
        if (ATARIHW_PRESENT(FDCSPEED)) {
818
                dma_wd.fdc_speed = 0;    /* always seek witch 8 Mhz */
819
                MFPDELAY();
820
        }
821
 
822
        DPRINT(("fd_seek() to track %d\n",ReqTrack));
823
        FDC_WRITE( FDCREG_DATA, ReqTrack << SUDT->stretch);
824
        udelay(25);
825
        SET_IRQ_HANDLER( fd_seek_done );
826
        FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK | SUD.steprate );
827
 
828
        MotorOn = 1;
829
        set_head_settle_flag();
830
        START_TIMEOUT();
831
        /* wait for IRQ */
832
}
833
 
834
 
835
static void fd_seek_done( int status )
836
{
837
        DPRINT(("fd_seek_done()\n"));
838
        STOP_TIMEOUT();
839
 
840
        /* set the correct speed */
841
        if (ATARIHW_PRESENT(FDCSPEED))
842
                dma_wd.fdc_speed = SUDT->fdc_speed;
843
        if (status & FDCSTAT_RECNF) {
844
                printk(KERN_ERR "fd%d: seek error (to track %d)\n",
845
                                SelectedDrive, ReqTrack );
846
                /* we don't know exactly which track we are on now! */
847
                SUD.track = -1;
848
                fd_error();
849
        }
850
        else {
851
                SUD.track = ReqTrack << SUDT->stretch;
852
                NeedSeek = 0;
853
                if (IsFormatting)
854
                        fd_writetrack();
855
                else
856
                        fd_rwsec();
857
        }
858
}
859
 
860
 
861
/* This does the actual reading/writing after positioning the head
862
 * over the correct track.
863
 */
864
 
865
static int MultReadInProgress = 0;
866
 
867
 
868
static void fd_rwsec( void )
869
{
870
        unsigned long paddr, flags;
871
        unsigned int  rwflag, old_motoron;
872
        unsigned int track;
873
 
874
        DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' ));
875
        if (ReqCmd == WRITE) {
876
                if (ATARIHW_PRESENT(EXTD_DMA)) {
877
                        paddr = (unsigned long)VTOP(ReqData);
878
                }
879
                else {
880
                        copy_buffer( ReqData, DMABuffer );
881
                        paddr = PhysDMABuffer;
882
                }
883
                dma_cache_maintenance( paddr, 512, 1 );
884
                rwflag = 0x100;
885
        }
886
        else {
887
                if (read_track)
888
                        paddr = PhysTrackBuffer;
889
                else
890
                        paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer;
891
                rwflag = 0;
892
        }
893
 
894
        fd_select_side( ReqSide );
895
 
896
        /* Start sector of this operation */
897
        FDC_WRITE( FDCREG_SECTOR, read_track ? 1 : ReqSector );
898
        MFPDELAY();
899
        /* Cheat for track if stretch != 0 */
900
        if (SUDT->stretch) {
901
                track = FDC_READ( FDCREG_TRACK);
902
                MFPDELAY();
903
                FDC_WRITE( FDCREG_TRACK, track >> SUDT->stretch);
904
        }
905
        udelay(25);
906
 
907
        /* Setup DMA */
908
        save_flags(flags);
909
        cli();
910
        dma_wd.dma_lo = (unsigned char)paddr;
911
        MFPDELAY();
912
        paddr >>= 8;
913
        dma_wd.dma_md = (unsigned char)paddr;
914
        MFPDELAY();
915
        paddr >>= 8;
916
        if (ATARIHW_PRESENT(EXTD_DMA))
917
                st_dma_ext_dmahi = (unsigned short)paddr;
918
        else
919
                dma_wd.dma_hi = (unsigned char)paddr;
920
        MFPDELAY();
921
        restore_flags(flags);
922
 
923
        /* Clear FIFO and switch DMA to correct mode */
924
        dma_wd.dma_mode_status = 0x90 | rwflag;
925
        MFPDELAY();
926
        dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100);
927
        MFPDELAY();
928
        dma_wd.dma_mode_status = 0x90 | rwflag;
929
        MFPDELAY();
930
 
931
        /* How many sectors for DMA */
932
        dma_wd.fdc_acces_seccount = read_track ? SUDT->spt : 1;
933
 
934
        udelay(25);
935
 
936
        /* Start operation */
937
        dma_wd.dma_mode_status = FDCSELREG_STP | rwflag;
938
        udelay(25);
939
        SET_IRQ_HANDLER( fd_rwsec_done );
940
        dma_wd.fdc_acces_seccount =
941
          (get_head_settle_flag() |
942
           (rwflag ? FDCCMD_WRSEC : (FDCCMD_RDSEC | (read_track ? FDCCMDADD_M : 0))));
943
 
944
        old_motoron = MotorOn;
945
        MotorOn = 1;
946
        NeedSeek = 1;
947
        /* wait for interrupt */
948
 
949
        if (read_track) {
950
                /* If reading a whole track, wait about one disk rotation and
951
                 * then check if all sectors are read. The FDC will even
952
                 * search for the first non-existent sector and need 1 sec to
953
                 * recognise that it isn't present :-(
954
                 */
955
                readtrack_timer.expires =
956
                  jiffies + HZ/5 + (old_motoron ? 0 : HZ);
957
                       /* 1 rot. + 5 rot.s if motor was off  */
958
                add_timer( &readtrack_timer );
959
                MultReadInProgress = 1;
960
        }
961
        START_TIMEOUT();
962
}
963
 
964
 
965
static void fd_readtrack_check( unsigned long dummy )
966
{
967
        unsigned long flags, addr, addr2;
968
 
969
        save_flags(flags);
970
        cli();
971
 
972
        del_timer( &readtrack_timer );
973
 
974
        if (!MultReadInProgress) {
975
                /* This prevents a race condition that could arise if the
976
                 * interrupt is triggered while the calling of this timer
977
                 * callback function takes place. The IRQ function then has
978
                 * already cleared 'MultReadInProgress'  when flow of control
979
                 * gets here.
980
                 */
981
                restore_flags(flags);
982
                return;
983
        }
984
 
985
        /* get the current DMA address */
986
        /* ++ f.a. read twice to avoid being fooled by switcher */
987
        addr = 0;
988
        do {
989
                addr2 = addr;
990
                addr = dma_wd.dma_lo & 0xff;
991
                MFPDELAY();
992
                addr |= (dma_wd.dma_md & 0xff) << 8;
993
                MFPDELAY();
994
                if (ATARIHW_PRESENT( EXTD_DMA ))
995
                        addr |= (st_dma_ext_dmahi & 0xffff) << 16;
996
                else
997
                        addr |= (dma_wd.dma_hi & 0xff) << 16;
998
                MFPDELAY();
999
        } while(addr != addr2);
1000
 
1001
        if (addr >= PhysTrackBuffer + SUDT->spt*512) {
1002
                /* already read enough data, force an FDC interrupt to stop
1003
                 * the read operation
1004
                 */
1005
                SET_IRQ_HANDLER( NULL );
1006
                restore_flags(flags);
1007
                DPRINT(("fd_readtrack_check(): done\n"));
1008
                FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
1009
                udelay(25);
1010
 
1011
                /* No error until now -- the FDC would have interrupted
1012
                 * otherwise!
1013
                 */
1014
                fd_rwsec_done( 0 );
1015
        }
1016
        else {
1017
                /* not yet finished, wait another tenth rotation */
1018
                restore_flags(flags);
1019
                DPRINT(("fd_readtrack_check(): not yet finished\n"));
1020
                readtrack_timer.expires = jiffies + HZ/5/10;
1021
                add_timer( &readtrack_timer );
1022
        }
1023
}
1024
 
1025
 
1026
static void fd_rwsec_done( int status )
1027
{
1028
        unsigned int track;
1029
 
1030
        DPRINT(("fd_rwsec_done()\n"));
1031
 
1032
        STOP_TIMEOUT();
1033
 
1034
        if (read_track) {
1035
                if (!MultReadInProgress)
1036
                        return;
1037
                MultReadInProgress = 0;
1038
                del_timer( &readtrack_timer );
1039
        }
1040
 
1041
        /* Correct the track if stretch != 0 */
1042
        if (SUDT->stretch) {
1043
                track = FDC_READ( FDCREG_TRACK);
1044
                MFPDELAY();
1045
                FDC_WRITE( FDCREG_TRACK, track << SUDT->stretch);
1046
        }
1047
 
1048
        if (!UseTrackbuffer) {
1049
                dma_wd.dma_mode_status = 0x90;
1050
                MFPDELAY();
1051
                if (!(dma_wd.dma_mode_status & 0x01)) {
1052
                        printk(KERN_ERR "fd%d: DMA error\n", SelectedDrive );
1053
                        goto err_end;
1054
                }
1055
        }
1056
        MFPDELAY();
1057
 
1058
        if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {
1059
                printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
1060
                goto err_end;
1061
        }
1062
        if ((status & FDCSTAT_RECNF) &&
1063
            /* RECNF is no error after a multiple read when the FDC
1064
               searched for a non-existent sector! */
1065
            !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
1066
                if (Probing) {
1067
                        if (SUDT > disk_type) {
1068
                                /* try another disk type */
1069
                                SUDT--;
1070
                                floppy_sizes[SelectedDrive] = SUDT->blocks >> 1;
1071
                        }
1072
                        else {
1073
                                if (SUD.flags & FTD_MSG)
1074
                                        printk(KERN_INFO "fd%d: Auto-detected floppy type %s\n",
1075
                                               SelectedDrive, SUDT->name );
1076
                                Probing=0;
1077
                        }
1078
                } else {
1079
/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
1080
                        if (SUD.autoprobe) {
1081
                                SUDT = disk_type + StartDiskType[DriveType];
1082
                                floppy_sizes[SelectedDrive] = SUDT->blocks >> 1;
1083
                                Probing = 1;
1084
                        }
1085
                }
1086
                if (Probing) {
1087
                        if (ATARIHW_PRESENT(FDCSPEED)) {
1088
                                dma_wd.fdc_speed = SUDT->fdc_speed;
1089
                                MFPDELAY();
1090
                        }
1091
                        setup_req_params( SelectedDrive );
1092
                        BufferDrive = -1;
1093
                        do_fd_action( SelectedDrive );
1094
                        return;
1095
                }
1096
 
1097
                printk(KERN_ERR "fd%d: sector %d not found (side %d, track %d)\n",
1098
                       SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack );
1099
                goto err_end;
1100
        }
1101
        if (status & FDCSTAT_CRC) {
1102
                printk(KERN_ERR "fd%d: CRC error (side %d, track %d, sector %d)\n",
1103
                       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
1104
                goto err_end;
1105
        }
1106
        if (status & FDCSTAT_LOST) {
1107
                printk(KERN_ERR "fd%d: lost data (side %d, track %d, sector %d)\n",
1108
                       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
1109
                goto err_end;
1110
        }
1111
 
1112
        Probing = 0;
1113
 
1114
        if (ReqCmd == READ) {
1115
                if (!read_track) {
1116
                        void *addr;
1117
                        addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
1118
                        dma_cache_maintenance( VTOP(addr), 512, 0 );
1119
                        if (!ATARIHW_PRESENT( EXTD_DMA ))
1120
                                copy_buffer (addr, ReqData);
1121
                } else {
1122
                        dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 );
1123
                        BufferDrive = SelectedDrive;
1124
                        BufferSide  = ReqSide;
1125
                        BufferTrack = ReqTrack;
1126
                        copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
1127
                }
1128
        }
1129
 
1130
        if (++ReqCnt < CURRENT->current_nr_sectors) {
1131
                /* read next sector */
1132
                setup_req_params( SelectedDrive );
1133
                do_fd_action( SelectedDrive );
1134
        }
1135
        else {
1136
                /* all sectors finished */
1137
                CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
1138
                CURRENT->sector += CURRENT->current_nr_sectors;
1139
                end_request( 1 );
1140
                redo_fd_request();
1141
        }
1142
        return;
1143
 
1144
  err_end:
1145
        BufferDrive = -1;
1146
        fd_error();
1147
}
1148
 
1149
 
1150
static void fd_writetrack( void )
1151
{
1152
        unsigned long paddr, flags;
1153
        unsigned int track;
1154
 
1155
        DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide ));
1156
 
1157
        paddr = PhysTrackBuffer;
1158
        dma_cache_maintenance( paddr, BUFFER_SIZE, 1 );
1159
 
1160
        fd_select_side( ReqSide );
1161
 
1162
        /* Cheat for track if stretch != 0 */
1163
        if (SUDT->stretch) {
1164
                track = FDC_READ( FDCREG_TRACK);
1165
                MFPDELAY();
1166
                FDC_WRITE(FDCREG_TRACK,track >> SUDT->stretch);
1167
        }
1168
        udelay(40);
1169
 
1170
        /* Setup DMA */
1171
        save_flags(flags);
1172
        cli();
1173
        dma_wd.dma_lo = (unsigned char)paddr;
1174
        MFPDELAY();
1175
        paddr >>= 8;
1176
        dma_wd.dma_md = (unsigned char)paddr;
1177
        MFPDELAY();
1178
        paddr >>= 8;
1179
        if (ATARIHW_PRESENT( EXTD_DMA ))
1180
                st_dma_ext_dmahi = (unsigned short)paddr;
1181
        else
1182
                dma_wd.dma_hi = (unsigned char)paddr;
1183
        MFPDELAY();
1184
        restore_flags(flags);
1185
 
1186
        /* Clear FIFO and switch DMA to correct mode */
1187
        dma_wd.dma_mode_status = 0x190;
1188
        MFPDELAY();
1189
        dma_wd.dma_mode_status = 0x90;
1190
        MFPDELAY();
1191
        dma_wd.dma_mode_status = 0x190;
1192
        MFPDELAY();
1193
 
1194
        /* How many sectors for DMA */
1195
        dma_wd.fdc_acces_seccount = BUFFER_SIZE/512;
1196
        udelay(40);
1197
 
1198
        /* Start operation */
1199
        dma_wd.dma_mode_status = FDCSELREG_STP | 0x100;
1200
        udelay(40);
1201
        SET_IRQ_HANDLER( fd_writetrack_done );
1202
        dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag();
1203
 
1204
        MotorOn = 1;
1205
        START_TIMEOUT();
1206
        /* wait for interrupt */
1207
}
1208
 
1209
 
1210
static void fd_writetrack_done( int status )
1211
{
1212
        DPRINT(("fd_writetrack_done()\n"));
1213
 
1214
        STOP_TIMEOUT();
1215
 
1216
        if (status & FDCSTAT_WPROT) {
1217
                printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
1218
                goto err_end;
1219
        }
1220
        if (status & FDCSTAT_LOST) {
1221
                printk(KERN_ERR "fd%d: lost data (side %d, track %d)\n",
1222
                                SelectedDrive, ReqSide, ReqTrack );
1223
                goto err_end;
1224
        }
1225
 
1226
        wake_up( &format_wait );
1227
        return;
1228
 
1229
  err_end:
1230
        fd_error();
1231
}
1232
 
1233
static void fd_times_out( unsigned long dummy )
1234
{
1235
        atari_disable_irq( IRQ_MFP_FDC );
1236
        if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but
1237
                                          * before we came here... */
1238
 
1239
        SET_IRQ_HANDLER( NULL );
1240
        /* If the timeout occurred while the readtrack_check timer was
1241
         * active, we need to cancel it, else bad things will happen */
1242
        if (UseTrackbuffer)
1243
                del_timer( &readtrack_timer );
1244
        FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
1245
        udelay( 25 );
1246
 
1247
        printk(KERN_ERR "floppy timeout\n" );
1248
        fd_error();
1249
  end:
1250
        atari_enable_irq( IRQ_MFP_FDC );
1251
}
1252
 
1253
 
1254
/* The (noop) seek operation here is needed to make the WP bit in the
1255
 * FDC status register accessible for check_change. If the last disk
1256
 * operation would have been a RDSEC, this bit would always read as 0
1257
 * no matter what :-( To save time, the seek goes to the track we're
1258
 * already on.
1259
 */
1260
 
1261
static void finish_fdc( void )
1262
{
1263
        if (!NeedSeek) {
1264
                finish_fdc_done( 0 );
1265
        }
1266
        else {
1267
                DPRINT(("finish_fdc: dummy seek started\n"));
1268
                FDC_WRITE (FDCREG_DATA, SUD.track);
1269
                SET_IRQ_HANDLER( finish_fdc_done );
1270
                FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);
1271
                MotorOn = 1;
1272
                START_TIMEOUT();
1273
                /* we must wait for the IRQ here, because the ST-DMA
1274
                   is released immediately afterwards and the interrupt
1275
                   may be delivered to the wrong driver. */
1276
          }
1277
}
1278
 
1279
 
1280
static void finish_fdc_done( int dummy )
1281
{
1282
        unsigned long flags;
1283
 
1284
        DPRINT(("finish_fdc_done entered\n"));
1285
        STOP_TIMEOUT();
1286
        NeedSeek = 0;
1287
 
1288
        if ((timer_active & (1 << FLOPPY_TIMER)) &&
1289
            timer_table[FLOPPY_TIMER].expires < jiffies + 5)
1290
                /* If the check for a disk change is done too early after this
1291
                 * last seek command, the WP bit still reads wrong :-((
1292
                 */
1293
                timer_table[FLOPPY_TIMER].expires = jiffies + 5;
1294
        else
1295
                START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
1296
        del_timer( &motor_off_timer );
1297
        START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
1298
 
1299
        save_flags(flags);
1300
        cli();
1301
        stdma_release();
1302
        fdc_busy = 0;
1303
        wake_up( &fdc_wait );
1304
        restore_flags(flags);
1305
 
1306
        DPRINT(("finish_fdc() finished\n"));
1307
}
1308
 
1309
 
1310
/* Prevent "aliased" accesses. */
1311
static fd_ref[4] = { 0,0,0,0 };
1312
static fd_device[4] = { 0,0,0,0 };
1313
 
1314
/*
1315
 * Current device number. Taken either from the block header or from the
1316
 * format request descriptor.
1317
 */
1318
#define CURRENT_DEVICE (CURRENT->rq_dev)
1319
 
1320
/* Current error count. */
1321
#define CURRENT_ERRORS (CURRENT->errors)
1322
 
1323
 
1324
/* dummy for blk.h */
1325
static void floppy_off( unsigned int nr) {}
1326
 
1327
 
1328
/* The detection of disk changes is a dark chapter in Atari history :-(
1329
 * Because the "Drive ready" signal isn't present in the Atari
1330
 * hardware, one has to rely on the "Write Protect". This works fine,
1331
 * as long as no write protected disks are used. TOS solves this
1332
 * problem by introducing tri-state logic ("maybe changed") and
1333
 * looking at the serial number in block 0. This isn't possible for
1334
 * Linux, since the floppy driver can't make assumptions about the
1335
 * filesystem used on the disk and thus the contents of block 0. I've
1336
 * chosen the method to always say "The disk was changed" if it is
1337
 * unsure whether it was. This implies that every open or mount
1338
 * invalidates the disk buffers if you work with write protected
1339
 * disks. But at least this is better than working with incorrect data
1340
 * due to unrecognised disk changes.
1341
 */
1342
 
1343
static int check_floppy_change (kdev_t dev)
1344
{
1345
        unsigned int drive = MINOR(dev) & 0x03;
1346
 
1347
        if (MAJOR(dev) != MAJOR_NR) {
1348
                printk(KERN_ERR "floppy_changed: not a floppy\n");
1349
                return 0;
1350
        }
1351
 
1352
        if (test_bit (drive, &fake_change)) {
1353
                /* simulated change (e.g. after formatting) */
1354
                return 1;
1355
        }
1356
        if (test_bit (drive, &changed_floppies)) {
1357
                /* surely changed (the WP signal changed at least once) */
1358
                return 1;
1359
        }
1360
        if (UD.wpstat) {
1361
                /* WP is on -> could be changed: to be sure, buffers should be
1362
                 * invalidated...
1363
                 */
1364
                return 1;
1365
        }
1366
 
1367
        return 0;
1368
}
1369
 
1370
static int floppy_revalidate (kdev_t dev)
1371
{
1372
  int drive = MINOR(dev) & 3;
1373
 
1374
  if (test_bit (drive, &changed_floppies) || test_bit (drive, &fake_change)
1375
      || unit[drive].disktype == 0)
1376
    {
1377
      BufferDrive = -1;
1378
      clear_bit (drive, &fake_change);
1379
      clear_bit (drive, &changed_floppies);
1380
      UDT = 0;
1381
    }
1382
  return 0;
1383
}
1384
 
1385
static __inline__ void copy_buffer(void *from, void *to)
1386
{
1387
        ulong   *p1 = (ulong *)from, *p2 = (ulong *)to;
1388
        int             cnt;
1389
 
1390
        for( cnt = 512/4; cnt; cnt-- )
1391
                *p2++ = *p1++;
1392
}
1393
 
1394
 
1395
/* This sets up the global variables describing the current request. */
1396
 
1397
static void setup_req_params( int drive )
1398
{
1399
        int block = ReqBlock + ReqCnt;
1400
 
1401
        ReqTrack = block / UDT->spt;
1402
        ReqSector = block - ReqTrack * UDT->spt + 1;
1403
        ReqSide = ReqTrack & 1;
1404
        ReqTrack >>= 1;
1405
        ReqData = ReqBuffer + 512 * ReqCnt;
1406
 
1407
        if (UseTrackbuffer)
1408
                read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);
1409
        else
1410
                read_track = 0;
1411
 
1412
        DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n",ReqSide,
1413
                        ReqTrack, ReqSector, (unsigned long)ReqData ));
1414
}
1415
 
1416
 
1417
static void redo_fd_request(void)
1418
{
1419
        int device, drive, type;
1420
 
1421
        DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n",
1422
                (unsigned long)CURRENT, CURRENT ? CURRENT->rq_dev : 0,
1423
                CURRENT ? CURRENT->sector : 0 ));
1424
 
1425
        IsFormatting = 0;
1426
 
1427
        if (CURRENT && CURRENT->rq_status == RQ_INACTIVE){
1428
                return;
1429
        }
1430
 
1431
repeat:
1432
 
1433
        if (!CURRENT)
1434
                goto the_end;
1435
 
1436
        if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
1437
                panic(DEVICE_NAME ": request list destroyed");
1438
 
1439
        if (CURRENT->bh && !buffer_locked(CURRENT->bh))
1440
                panic(DEVICE_NAME ": block not locked");
1441
 
1442
        device = MINOR(CURRENT_DEVICE);
1443
        drive = device & 3;
1444
        type = device >> 2;
1445
 
1446
        if (!UD.connected) {
1447
                /* drive not connected */
1448
                printk(KERN_ERR "Unknown Device: fd%d\n", drive );
1449
                end_request(0);
1450
                goto repeat;
1451
        }
1452
 
1453
        if (type == 0) {
1454
                if (!UDT) {
1455
                        Probing = 1;
1456
                        UDT = disk_type + StartDiskType[DriveType];
1457
                        floppy_sizes[drive] = UDT->blocks >> 1;
1458
                        UD.autoprobe = 1;
1459
                }
1460
        }
1461
        else {
1462
                /* user supplied disk type */
1463
                if (--type >= NUM_DISK_MINORS) {
1464
                        printk(KERN_WARNING "fd%d: invalid disk format", drive );
1465
                        end_request( 0 );
1466
                        goto repeat;
1467
                }
1468
                if (minor2disktype[type].drive_types > DriveType)  {
1469
                        printk(KERN_WARNING "fd%d: unsupported disk format", drive );
1470
                        end_request( 0 );
1471
                        goto repeat;
1472
                }
1473
                type = minor2disktype[type].index;
1474
                UDT = &disk_type[type];
1475
                floppy_sizes[drive] = UDT->blocks >> 1;
1476
                UD.autoprobe = 0;
1477
        }
1478
 
1479
        if (CURRENT->sector + 1 > UDT->blocks) {
1480
                end_request(0);
1481
                goto repeat;
1482
        }
1483
 
1484
        /* stop deselect timer */
1485
        del_timer( &motor_off_timer );
1486
 
1487
        ReqCnt = 0;
1488
        ReqCmd = CURRENT->cmd;
1489
        ReqBlock = CURRENT->sector;
1490
        ReqBuffer = CURRENT->buffer;
1491
        setup_req_params( drive );
1492
        do_fd_action( drive );
1493
 
1494
        return;
1495
 
1496
  the_end:
1497
        finish_fdc();
1498
}
1499
 
1500
 
1501
void do_fd_request(void)
1502
{
1503
        unsigned long flags;
1504
 
1505
        DPRINT(("do_fd_request for pid %d\n",current->pid));
1506
        while( fdc_busy ) sleep_on( &fdc_wait );
1507
        fdc_busy = 1;
1508
        stdma_lock(floppy_irq, NULL);
1509
 
1510
        atari_disable_irq( IRQ_MFP_FDC );
1511
        save_flags(flags);      /* The request function is called with ints
1512
        sti();                           * disabled... so must save the IPL for later */
1513
        redo_fd_request();
1514
        restore_flags(flags);
1515
        atari_enable_irq( IRQ_MFP_FDC );
1516
}
1517
 
1518
 
1519
static int
1520
invalidate_drive (kdev_t rdev)
1521
{
1522
  /* invalidate the buffer track to force a reread */
1523
  BufferDrive = -1;
1524
  set_bit (MINOR(rdev) & 3, &fake_change);
1525
  check_disk_change (rdev);
1526
  return 0;
1527
}
1528
 
1529
static int fd_ioctl(struct inode *inode, struct file *filp,
1530
                    unsigned int cmd, unsigned long param)
1531
{
1532
#define IOCTL_MODE_BIT 8
1533
#define OPEN_WRITE_BIT 16
1534
#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
1535
#define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x)))
1536
 
1537
        int drive, type, error;
1538
        kdev_t device;
1539
        struct atari_format_descr fmt_desc;
1540
        struct atari_disk_type *dtp;
1541
        struct floppy_struct getprm;
1542
 
1543
        device = inode->i_rdev;
1544
        switch (cmd) {
1545
                RO_IOCTLS (device, param);
1546
        }
1547
        drive = MINOR (device);
1548
        type  = drive >> 2;
1549
        drive &= 3;
1550
        switch (cmd) {
1551
        case FDGETPRM:
1552
                if (type) {
1553
                        if (--type >= NUM_DISK_MINORS)
1554
                                return -ENODEV;
1555
                        if (minor2disktype[type].drive_types > DriveType)
1556
                                return -ENODEV;
1557
                        type = minor2disktype[type].index;
1558
                        dtp = &disk_type[type];
1559
                }
1560
                else {
1561
                        if (!UDT)
1562
                                return -ENXIO;
1563
                        else
1564
                                dtp = UDT;
1565
                }
1566
                error = verify_area(VERIFY_WRITE, (void *)param,
1567
                                    sizeof(struct floppy_struct));
1568
                if (error)
1569
                        return( error );
1570
                memset((void *)&getprm, 0, sizeof(getprm));
1571
                getprm.size = dtp->blocks;
1572
                getprm.sect = dtp->spt;
1573
                getprm.head = 2;
1574
                getprm.track = dtp->blocks/dtp->spt/2;
1575
                getprm.stretch = dtp->stretch;
1576
                memcpy_tofs((void *)param, &getprm, sizeof(struct floppy_struct));
1577
                return 0;
1578
        }
1579
        if (!IOCTL_ALLOWED)
1580
                return -EPERM;
1581
        switch (cmd) {
1582
        case FDSETPRM:
1583
        case FDDEFPRM:
1584
                return -EINVAL;
1585
        case FDMSGON:
1586
                UD.flags |= FTD_MSG;
1587
                return 0;
1588
        case FDMSGOFF:
1589
                UD.flags &= ~FTD_MSG;
1590
                return 0;
1591
        case FDSETEMSGTRESH:
1592
                return -EINVAL;
1593
        case FDFMTBEG:
1594
                return 0;
1595
        case FDFMTTRK:
1596
                if (fd_ref[drive] != 1 && fd_ref[drive] != -1)
1597
                        return -EBUSY;
1598
                if ((error = verify_area(VERIFY_READ, (void *)param,
1599
                                         sizeof(struct atari_format_descr) )))
1600
                        return( error );
1601
                COPYIN( fmt_desc );
1602
                return do_format(device, &fmt_desc);
1603
        case FDCLRPRM:
1604
                UDT = NULL;
1605
                floppy_sizes[drive] = MAX_DISK_SIZE;
1606
                return invalidate_drive (device);
1607
        case FDFMTEND:
1608
        case FDFLUSH:
1609
                return invalidate_drive (drive);
1610
        }
1611
        return -EINVAL;
1612
}
1613
 
1614
 
1615
/* Initialize the 'unit' variable for drive 'drive' */
1616
 
1617
static void fd_probe( int drive )
1618
{
1619
        UD.connected = 0;
1620
        UDT  = NULL;
1621
 
1622
        if (!fd_test_drive_present( drive ))
1623
                return;
1624
 
1625
        UD.connected = 1;
1626
        UD.track     = 0;
1627
        switch( UserSteprate[drive] ) {
1628
        case 2:
1629
                UD.steprate = FDCSTEP_2;
1630
                break;
1631
        case 3:
1632
                UD.steprate = FDCSTEP_3;
1633
                break;
1634
        case 6:
1635
                UD.steprate = FDCSTEP_6;
1636
                break;
1637
        case 12:
1638
                UD.steprate = FDCSTEP_12;
1639
                break;
1640
        default: /* should be -1 for "not set by user" */
1641
                if (ATARIHW_PRESENT( FDCSPEED ) || is_medusa)
1642
                        UD.steprate = FDCSTEP_3;
1643
                else
1644
                        UD.steprate = FDCSTEP_6;
1645
                break;
1646
        }
1647
        MotorOn = 1;    /* from probe restore operation! */
1648
}
1649
 
1650
 
1651
/* This function tests the physical presence of a floppy drive (not
1652
 * whether a disk is inserted). This is done by issuing a restore
1653
 * command, waiting max. 2 seconds (that should be enough to move the
1654
 * head across the whole disk) and looking at the state of the "TR00"
1655
 * signal. This should now be raised if there is a drive connected
1656
 * (and there is no hardware failure :-) Otherwise, the drive is
1657
 * declared absent.
1658
 */
1659
 
1660
static int fd_test_drive_present( int drive )
1661
{
1662
        unsigned long timeout;
1663
        unsigned char status;
1664
        int ok;
1665
 
1666
        if (drive > 1) return( 0 );
1667
        fd_select_drive( drive );
1668
 
1669
        /* disable interrupt temporarily */
1670
        atari_turnoff_irq( IRQ_MFP_FDC );
1671
        FDC_WRITE (FDCREG_TRACK, 0xff00);
1672
        FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );
1673
 
1674
        for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; jiffies < timeout; ) {
1675
                if (!(mfp.par_dt_reg & 0x20))
1676
                        break;
1677
        }
1678
 
1679
        status = FDC_READ( FDCREG_STATUS );
1680
        ok = (status & FDCSTAT_TR00) != 0;
1681
 
1682
        /* force interrupt to abort restore operation (FDC would try
1683
         * about 50 seconds!) */
1684
        FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
1685
        udelay(500);
1686
        status = FDC_READ( FDCREG_STATUS );
1687
        udelay(20);
1688
 
1689
        if (ok) {
1690
                /* dummy seek command to make WP bit accessible */
1691
                FDC_WRITE( FDCREG_DATA, 0 );
1692
                FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
1693
                while( mfp.par_dt_reg & 0x20 )
1694
                        ;
1695
                status = FDC_READ( FDCREG_STATUS );
1696
        }
1697
 
1698
        atari_turnon_irq( IRQ_MFP_FDC );
1699
        return( ok );
1700
}
1701
 
1702
 
1703
/* Look how many and which kind of drives are connected. If there are
1704
 * floppies, additionally start the disk-change and motor-off timers.
1705
 */
1706
 
1707
static void config_types( void )
1708
{
1709
        int drive, cnt = 0;
1710
 
1711
        /* for probing drives, set the FDC speed to 8 MHz */
1712
        if (ATARIHW_PRESENT(FDCSPEED))
1713
                dma_wd.fdc_speed = 0;
1714
 
1715
        printk(KERN_INFO "Probing floppy drive(s):\n");
1716
        for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {
1717
                fd_probe( drive );
1718
                if (UD.connected) {
1719
                        printk(KERN_INFO "fd%d\n", drive);
1720
                        ++cnt;
1721
                }
1722
        }
1723
 
1724
        if (FDC_READ( FDCREG_STATUS ) & FDCSTAT_BUSY) {
1725
                /* If FDC is still busy from probing, give it another FORCI
1726
                 * command to abort the operation. If this isn't done, the FDC
1727
                 * will interrupt later and its IRQ line stays low, because
1728
                 * the status register isn't read. And this will block any
1729
                 * interrupts on this IRQ line :-(
1730
                 */
1731
                FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
1732
                udelay(500);
1733
                FDC_READ( FDCREG_STATUS );
1734
                udelay(20);
1735
        }
1736
 
1737
        if (cnt > 0) {
1738
                START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
1739
                if (cnt == 1) fd_select_drive( 0 );
1740
                START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
1741
        }
1742
}
1743
 
1744
/*
1745
 * floppy_open check for aliasing (/dev/fd0 can be the same as
1746
 * /dev/PS0 etc), and disallows simultaneous access to the same
1747
 * drive with different device numbers.
1748
 */
1749
 
1750
static int floppy_open( struct inode *inode, struct file *filp )
1751
{
1752
  int drive, type;
1753
  int old_dev;
1754
 
1755
  if (!filp)
1756
    {
1757
      DPRINT (("Weird, open called with filp=0\n"));
1758
      return -EIO;
1759
    }
1760
 
1761
  drive = MINOR (inode->i_rdev) & 3;
1762
  type  = MINOR(inode->i_rdev) >> 2;
1763
  DPRINT(("fd_open: type=%d\n",type));
1764
  if (type > NUM_DISK_MINORS)
1765
        return -ENXIO;
1766
 
1767
  old_dev = fd_device[drive];
1768
 
1769
  if (fd_ref[drive])
1770
    if (old_dev != inode->i_rdev)
1771
      return -EBUSY;
1772
 
1773
  if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
1774
    return -EBUSY;
1775
 
1776
  if (filp->f_flags & O_EXCL)
1777
    fd_ref[drive] = -1;
1778
  else
1779
    fd_ref[drive]++;
1780
 
1781
  fd_device[drive] = inode->i_rdev;
1782
 
1783
  if (old_dev && old_dev != inode->i_rdev)
1784
    invalidate_buffers(old_dev);
1785
 
1786
  /* Allow ioctls if we have write-permissions even if read-only open */
1787
  if (filp->f_mode & 2 || permission (inode, 2) == 0)
1788
    filp->f_mode |= IOCTL_MODE_BIT;
1789
  if (filp->f_mode & 2)
1790
    filp->f_mode |= OPEN_WRITE_BIT;
1791
 
1792
  MOD_INC_USE_COUNT;
1793
 
1794
  if (filp->f_flags & O_NDELAY)
1795
    return 0;
1796
 
1797
  if (filp->f_mode & 3) {
1798
          check_disk_change( inode->i_rdev );
1799
          if (filp->f_mode & 2) {
1800
                  if (UD.wpstat) {
1801
                          floppy_release(inode, filp);
1802
                          return -EROFS;
1803
                  }
1804
          }
1805
  }
1806
 
1807
  return 0;
1808
}
1809
 
1810
 
1811
static void floppy_release( struct inode * inode, struct file * filp )
1812
{
1813
  int drive;
1814
 
1815
  drive = inode->i_rdev & 3;
1816
 
1817
  if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
1818
    /* if the file is mounted OR (writable now AND writable at open
1819
       time) Linus: Does this cover all cases? */
1820
    block_fsync (inode, filp);
1821
 
1822
  if (fd_ref[drive] < 0)
1823
    fd_ref[drive] = 0;
1824
  else if (!fd_ref[drive]--)
1825
    {
1826
      printk(KERN_ERR "floppy_release with fd_ref == 0");
1827
      fd_ref[drive] = 0;
1828
    }
1829
 
1830
  MOD_DEC_USE_COUNT;
1831
}
1832
 
1833
static struct file_operations floppy_fops = {
1834
        NULL,                   /* lseek - default */
1835
        block_read,             /* read - general block-dev read */
1836
        block_write,            /* write - general block-dev write */
1837
        NULL,                   /* readdir - bad */
1838
        NULL,                   /* select */
1839
        fd_ioctl,               /* ioctl */
1840
        NULL,                   /* mmap */
1841
        floppy_open,            /* open */
1842
        floppy_release,         /* release */
1843
        block_fsync,            /* fsync */
1844
        NULL,                   /* fasync */
1845
        check_floppy_change,    /* media_change */
1846
        floppy_revalidate,      /* revalidate */
1847
};
1848
 
1849
int atari_floppy_init (void)
1850
{
1851
        int i;
1852
 
1853
        if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
1854
                printk(KERN_ERR "Unable to get major %d for floppy\n",MAJOR_NR);
1855
                return -EBUSY;
1856
        }
1857
 
1858
        if (UseTrackbuffer < 0)
1859
                /* not set by user -> use default: for now, we turn
1860
                   track buffering off for all Medusas, though it
1861
                   could be used with ones that have a counter
1862
                   card. But the test is too hard :-( */
1863
                UseTrackbuffer = !is_medusa;
1864
 
1865
        /* initialize variables */
1866
        SelectedDrive = -1;
1867
        BufferDrive = -1;
1868
 
1869
        /* initialize check_change timer */
1870
        timer_table[FLOPPY_TIMER].fn = check_change;
1871
        timer_active &= ~(1 << FLOPPY_TIMER);
1872
 
1873
        DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA);
1874
        if (!DMABuffer) {
1875
                printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");
1876
                unregister_blkdev(MAJOR_NR, "fd");
1877
                return -ENOMEM;
1878
        }
1879
        TrackBuffer = DMABuffer + 512;
1880
        PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
1881
        PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
1882
        BufferDrive = BufferSide = BufferTrack = -1;
1883
 
1884
        for (i = 0; i < FD_MAX_UNITS; i++) {
1885
                unit[i].track = -1;
1886
                unit[i].flags = 0;
1887
        }
1888
 
1889
        for (i = 0; i < 256; i++)
1890
                if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_MINORS) {
1891
                        int type = minor2disktype[(i >> 2) - 1].index;
1892
                        floppy_sizes[i] = disk_type[type].blocks >> 1;
1893
                } else
1894
                        floppy_sizes[i] = MAX_DISK_SIZE;
1895
 
1896
        blk_size[MAJOR_NR] = floppy_sizes;
1897
        blksize_size[MAJOR_NR] = floppy_blocksizes;
1898
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1899
 
1900
        printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
1901
               DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
1902
               UseTrackbuffer ? "" : "no ");
1903
        config_types();
1904
 
1905
        return 0;
1906
}
1907
 
1908
 
1909
void atari_floppy_setup( char *str, int *ints )
1910
{
1911
        int i;
1912
 
1913
        if (ints[0] < 1) {
1914
                printk(KERN_ERR "ataflop_setup: no arguments!\n" );
1915
                return;
1916
        }
1917
        else if (ints[0] > 2+FD_MAX_UNITS) {
1918
                printk(KERN_ERR "ataflop_setup: too many arguments\n" );
1919
        }
1920
 
1921
        if (ints[1] < 0 || ints[1] > 2)
1922
                printk(KERN_ERR "ataflop_setup: bad drive type\n" );
1923
        else
1924
                DriveType = ints[1];
1925
 
1926
        if (ints[0] >= 2)
1927
                UseTrackbuffer = (ints[2] > 0);
1928
 
1929
        for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) {
1930
                if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12)
1931
                        printk(KERN_ERR "ataflop_setup: bad steprate\n" );
1932
                else
1933
                        UserSteprate[i-3] = ints[i];
1934
        }
1935
}
1936
 
1937
#ifdef MODULE
1938
int init_module (void)
1939
{
1940
        if (!MACH_IS_ATARI)
1941
                return -ENXIO;
1942
        return atari_floppy_init ();
1943
}
1944
 
1945
void cleanup_module (void)
1946
{
1947
        unregister_blkdev(MAJOR_NR, "fd");
1948
 
1949
        blk_dev[MAJOR_NR].request_fn = 0;
1950
        timer_active &= ~(1 << FLOPPY_TIMER);
1951
        timer_table[FLOPPY_TIMER].fn = 0;
1952
        kfree (DMABuffer);
1953
}
1954
#endif
1955
 

powered by: WebSVN 2.1.0

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