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