root/drivers/block/ataflop.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fd_select_side
  2. fd_select_drive
  3. fd_deselect
  4. fd_motor_off_timer
  5. check_change
  6. set_head_settle_flag
  7. get_head_settle_flag
  8. floppy_irq
  9. fd_error
  10. do_format
  11. do_fd_action
  12. fd_calibrate
  13. fd_calibrate_done
  14. fd_seek
  15. fd_seek_done
  16. fd_rwsec
  17. fd_readtrack_check
  18. fd_rwsec_done
  19. fd_writetrack
  20. fd_writetrack_done
  21. fd_times_out
  22. finish_fdc
  23. finish_fdc_done
  24. floppy_off
  25. check_floppy_change
  26. floppy_revalidate
  27. copy_buffer
  28. setup_req_params
  29. redo_fd_request
  30. do_fd_request
  31. invalidate_drive
  32. fd_ioctl
  33. fd_probe
  34. fd_test_drive_present
  35. config_types
  36. floppy_open
  37. floppy_release
  38. atari_floppy_init
  39. atari_floppy_setup
  40. init_module
  41. cleanup_module

   1 /*
   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 independant 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 seperate 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       /* Atfer 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 necesary 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 dont't use seeks with verify.
 554  */
 555 
 556 static __inline__ void set_head_settle_flag( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         HeadSettleFlag = FDCCMDADD_E;
 559 }
 560 
 561 static __inline__ int get_head_settle_flag( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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( "fd%d: too many errors.\n", SelectedDrive );
 612                 end_request( 0 );
 613         }
 614         else if (CURRENT->errors == RECALIBRATE_ERRORS) {
 615                 printk( "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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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( "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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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( "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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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_maintainance( 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-existant 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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( "fd%d: DMA error\n", SelectedDrive );
1053                         goto err_end;
1054                 }
1055         }
1056         MFPDELAY();
1057 
1058         if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {
1059                 printk( "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-existant 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( "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( "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( "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( "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_maintainance( VTOP(addr), 512, 0 );
1119                         if (!ATARIHW_PRESENT( EXTD_DMA ))
1120                                 copy_buffer (addr, ReqData);
1121                 } else {
1122                         dma_cache_maintainance( 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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_maintainance( 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
1211 {
1212         DPRINT(("fd_writetrack_done()\n"));
1213 
1214         STOP_TIMEOUT();
1215 
1216         if (status & FDCSTAT_WPROT) {
1217                 printk( "fd%d: is write protected\n", SelectedDrive );
1218                 goto err_end;
1219         }       
1220         if (status & FDCSTAT_LOST) {
1221                 printk( "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 )
     /* [previous][next][first][last][top][bottom][index][help] */
1234 {
1235         atari_disable_irq( IRQ_MFP_FDC );
1236         if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but
1237                                           * before we came here... */
1238 
1239         SET_IRQ_HANDLER( NULL );
1240         /* If the timeout occured 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( "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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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 immediatly afterwards and the interrupt
1275                    may be delivered to the wrong driver. */
1276           }
1277 }
1278 
1279 
1280 static void finish_fdc_done( int dummy )
     /* [previous][next][first][last][top][bottom][index][help] */
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) {}
     /* [previous][next][first][last][top][bottom][index][help] */
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  * choosen 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)
     /* [previous][next][first][last][top][bottom][index][help] */
1344 {
1345         unsigned int drive = MINOR(dev) & 0x03;
1346 
1347         if (MAJOR(dev) != MAJOR_NR) {
1348                 printk("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)
     /* [previous][next][first][last][top][bottom][index][help] */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
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( "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( "fd%d: invalid disk format", drive );
1465                         end_request( 0 );
1466                         goto repeat;
1467                 }
1468                 if (minor2disktype[type].drive_types > DriveType)  {
1469                         printk( "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)
     /* [previous][next][first][last][top][bottom][index][help] */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
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,
     /* [previous][next][first][last][top][bottom][index][help] */
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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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("Probing floppy drive(s):\n");
1716         for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {
1717                 fd_probe( drive );
1718                 if (UD.connected) {
1719                         printk("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 )
     /* [previous][next][first][last][top][bottom][index][help] */
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   if (filp->f_flags & O_NDELAY)
1793     return 0;
1794 
1795   if (filp->f_mode & 3) {
1796           check_disk_change( inode->i_rdev );
1797           if (filp->f_mode & 2) {
1798                   if (UD.wpstat) {
1799                           floppy_release(inode, filp);
1800                           return -EROFS;
1801                   }
1802           }
1803   }
1804 
1805   return 0;
1806 }
1807 
1808 
1809 static void floppy_release( struct inode * inode, struct file * filp )
     /* [previous][next][first][last][top][bottom][index][help] */
1810 {
1811   int drive;
1812 
1813   drive = inode->i_rdev & 3;
1814 
1815   if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
1816     /* if the file is mounted OR (writable now AND writable at open
1817        time) Linus: Does this cover all cases? */
1818     block_fsync (inode, filp);
1819 
1820   if (fd_ref[drive] < 0)
1821     fd_ref[drive] = 0;
1822   else if (!fd_ref[drive]--)
1823     {
1824       printk("floppy_release with fd_ref == 0");
1825       fd_ref[drive] = 0;
1826     }
1827 }
1828 
1829 static struct file_operations floppy_fops = {
1830         NULL,                   /* lseek - default */
1831         block_read,             /* read - general block-dev read */
1832         block_write,            /* write - general block-dev write */
1833         NULL,                   /* readdir - bad */
1834         NULL,                   /* select */
1835         fd_ioctl,               /* ioctl */
1836         NULL,                   /* mmap */
1837         floppy_open,            /* open */
1838         floppy_release,         /* release */
1839         block_fsync,            /* fsync */
1840         NULL,                   /* fasync */
1841         check_floppy_change,    /* media_change */
1842         floppy_revalidate,      /* revalidate */
1843 };
1844 
1845 int atari_floppy_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1846 {
1847         int i;
1848 
1849         if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
1850                 printk("Unable to get major %d for floppy\n",MAJOR_NR);
1851                 return -EBUSY;
1852         }
1853 
1854         if (UseTrackbuffer < 0)
1855                 /* not set by user -> use default: for now, we turn
1856                    track buffering off for all Medusas, though it
1857                    could be used with ones that have a counter
1858                    card. But the test is too hard :-( */
1859                 UseTrackbuffer = !is_medusa;
1860 
1861         /* initialize variables */
1862         SelectedDrive = -1;
1863         BufferDrive = -1;
1864 
1865         /* initialize check_change timer */
1866         timer_table[FLOPPY_TIMER].fn = check_change;
1867         timer_active &= ~(1 << FLOPPY_TIMER);
1868 
1869         DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA);
1870         if (!DMABuffer) {
1871                 printk("atari_floppy_init: cannot get dma buffer\n");
1872                 unregister_blkdev(MAJOR_NR, "fd");
1873                 return -ENOMEM;
1874         }
1875         TrackBuffer = DMABuffer + 512;
1876         PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
1877         PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
1878         BufferDrive = BufferSide = BufferTrack = -1;
1879 
1880         for (i = 0; i < FD_MAX_UNITS; i++) {
1881                 unit[i].track = -1;
1882                 unit[i].flags = 0;
1883         }
1884 
1885         for (i = 0; i < 256; i++)
1886                 if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_MINORS) {
1887                         int type = minor2disktype[(i >> 2) - 1].index;
1888                         floppy_sizes[i] = disk_type[type].blocks >> 1;
1889                 } else
1890                         floppy_sizes[i] = MAX_DISK_SIZE;
1891 
1892         blk_size[MAJOR_NR] = floppy_sizes;
1893         blksize_size[MAJOR_NR] = floppy_blocksizes;
1894         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1895 
1896         printk("Atari floppy driver: max. %cD, %strack buffering\n",
1897                DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
1898                UseTrackbuffer ? "" : "no ");
1899         config_types();
1900 
1901         return 0;
1902 }
1903 
1904 
1905 void atari_floppy_setup( char *str, int *ints )
     /* [previous][next][first][last][top][bottom][index][help] */
1906 {
1907         int i;
1908         
1909         if (ints[0] < 1) {
1910                 printk( "ataflop_setup: no arguments!\n" );
1911                 return;
1912         }
1913         else if (ints[0] > 2+FD_MAX_UNITS) {
1914                 printk( "ataflop_setup: too many arguments\n" );
1915         }
1916 
1917         if (ints[1] < 0 || ints[1] > 2)
1918                 printk( "ataflop_setup: bad drive type\n" );
1919         else
1920                 DriveType = ints[1];
1921 
1922         if (ints[0] >= 2)
1923                 UseTrackbuffer = (ints[2] > 0);
1924 
1925         for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) {
1926                 if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12)
1927                         printk( "ataflop_setup: bad steprate\n" );
1928                 else
1929                         UserSteprate[i-3] = ints[i];
1930         }
1931 }
1932 
1933 #ifdef MODULE
1934 int init_module (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1935 {
1936         return atari_floppy_init ();
1937 }
1938 
1939 void cleanup_module (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1940 {
1941         unregister_blkdev(MAJOR_NR, "fd");
1942 
1943         blk_dev[MAJOR_NR].request_fn = 0;
1944         timer_active &= ~(1 << FLOPPY_TIMER);
1945         timer_table[FLOPPY_TIMER].fn = 0;
1946         kfree (DMABuffer);
1947 }
1948 #endif

/* [previous][next][first][last][top][bottom][index][help] */