Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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