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-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Driver for SWIM (Sander Woz Integrated Machine) floppy controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * based on Alastair Bridgewater SWIM analysis, 2001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * based on SWIM3 driver (c) Paul Mackerras, 1996
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * 2004-08-21 (lv) - Initial implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * 2008-10-30 (lv) - Port to 2.6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/fd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/blk-mq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/hdreg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <asm/mac_via.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define CARDNAME "swim"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) struct sector_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	unsigned char side;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	unsigned char track;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	unsigned char sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	unsigned char size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	unsigned char crc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	unsigned char crc1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) } __attribute__((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define DRIVER_VERSION "Version 0.2 (2008-10-30)"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #define REG(x)	unsigned char x, x ## _pad[0x200 - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) struct swim {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	REG(write_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	REG(write_mark)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	REG(write_CRC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	REG(write_parameter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	REG(write_phase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	REG(write_setup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	REG(write_mode0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	REG(write_mode1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	REG(read_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	REG(read_mark)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	REG(read_error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	REG(read_parameter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	REG(read_phase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	REG(read_setup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	REG(read_status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	REG(read_handshake)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) } __attribute__((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #define swim_write(base, reg, v) 	out_8(&(base)->write_##reg, (v))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) #define swim_read(base, reg)		in_8(&(base)->read_##reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) /* IWM registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) struct iwm {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	REG(ph0L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	REG(ph0H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	REG(ph1L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	REG(ph1H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	REG(ph2L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	REG(ph2H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	REG(ph3L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	REG(ph3H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	REG(mtrOff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	REG(mtrOn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	REG(intDrive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	REG(extDrive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	REG(q6L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	REG(q6H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	REG(q7L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	REG(q7H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) } __attribute__((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) #define iwm_write(base, reg, v) 	out_8(&(base)->reg, (v))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) #define iwm_read(base, reg)		in_8(&(base)->reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) /* bits in phase register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) #define SEEK_POSITIVE	0x070
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) #define SEEK_NEGATIVE	0x074
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) #define STEP		0x071
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) #define MOTOR_ON	0x072
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) #define MOTOR_OFF	0x076
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) #define INDEX		0x073
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) #define EJECT		0x077
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) #define SETMFM		0x171
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) #define SETGCR		0x175
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define RELAX		0x033
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define LSTRB		0x008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define CA_MASK		0x077
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Select values for swim_select and swim_readbit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define READ_DATA_0	0x074
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define ONEMEG_DRIVE	0x075
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define SINGLE_SIDED	0x076
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define DRIVE_PRESENT	0x077
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define DISK_IN		0x170
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define WRITE_PROT	0x171
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define TRACK_ZERO	0x172
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define TACHO		0x173
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define READ_DATA_1	0x174
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define GCR_MODE	0x175
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define SEEK_COMPLETE	0x176
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define TWOMEG_MEDIA	0x177
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* Bits in handshake register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define MARK_BYTE	0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define CRC_ZERO	0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #define RDDATA		0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define SENSE		0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define MOTEN		0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #define ERROR		0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define DAT2BYTE	0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define DAT1BYTE	0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /* bits in setup register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define S_INV_WDATA	0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define S_3_5_SELECT	0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define S_GCR		0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define S_FCLK_DIV2	0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define S_ERROR_CORR	0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define S_IBM_DRIVE	0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define S_GCR_WRITE	0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define S_TIMEOUT	0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* bits in mode register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define CLFIFO		0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define ENBL1		0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define ENBL2		0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define ACTION		0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define WRITE_MODE	0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define HEDSEL		0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define MOTON		0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /*----------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) enum drive_location {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	INTERNAL_DRIVE = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	EXTERNAL_DRIVE = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) enum media_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	DD_MEDIA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	HD_MEDIA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct floppy_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	/* physical properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	enum drive_location location;	/* internal or external drive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	int		 head_number;	/* single- or double-sided drive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	/* media */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	int		 disk_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	int		 ejected;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	enum media_type	 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	int		 write_protected;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	int		 total_secs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	int		 secpercyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	int		 secpertrack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	/* in-use information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	int		track;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	int		ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	struct gendisk *disk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	struct blk_mq_tag_set tag_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	/* parent controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	struct swim_priv *swd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) enum motor_action {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) enum head {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	LOWER_HEAD = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	UPPER_HEAD = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #define FD_MAX_UNIT	2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct swim_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	struct swim __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	int floppy_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	struct floppy_state unit[FD_MAX_UNIT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) extern int swim_read_sector_header(struct swim __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 				   struct sector_header *header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) extern int swim_read_sector_data(struct swim __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 				 unsigned char *data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static DEFINE_MUTEX(swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static inline void set_swim_mode(struct swim __iomem *base, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	struct iwm __iomem *iwm_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	if (!enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 		swim_write(base, mode0, 0xf8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	iwm_base = (struct iwm __iomem *)base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	iwm_read(iwm_base, q7L);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	iwm_read(iwm_base, mtrOff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	iwm_read(iwm_base, q6H);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	iwm_write(iwm_base, q7H, 0x57);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	iwm_write(iwm_base, q7H, 0x17);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	iwm_write(iwm_base, q7H, 0x57);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	iwm_write(iwm_base, q7H, 0x57);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static inline int get_swim_mode(struct swim __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	swim_write(base, phase, 0xf5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	if (swim_read(base, phase) != 0xf5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		goto is_iwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	swim_write(base, phase, 0xf6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	if (swim_read(base, phase) != 0xf6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		goto is_iwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	swim_write(base, phase, 0xf7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	if (swim_read(base, phase) != 0xf7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		goto is_iwm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) is_iwm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	return 0;
^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) static inline void swim_select(struct swim __iomem *base, int sel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	swim_write(base, phase, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	via1_set_head(sel & 0x100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	swim_write(base, phase, sel & CA_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static inline void swim_action(struct swim __iomem *base, int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	swim_select(base, action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	swim_write(base, phase, (LSTRB<<4) | LSTRB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	swim_write(base, phase, (LSTRB<<4) | ((~LSTRB) & 0x0F));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static inline int swim_readbit(struct swim __iomem *base, int bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	int stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	swim_select(base, bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	stat = swim_read(base, handshake);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	return (stat & SENSE) == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static inline void swim_drive(struct swim __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 			      enum drive_location location)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	if (location == INTERNAL_DRIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		swim_write(base, mode0, EXTERNAL_DRIVE); /* clear drive 1 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		swim_write(base, mode1, INTERNAL_DRIVE); /* set drive 0 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	} else if (location == EXTERNAL_DRIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		swim_write(base, mode0, INTERNAL_DRIVE); /* clear drive 0 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		swim_write(base, mode1, EXTERNAL_DRIVE); /* set drive 1 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static inline void swim_motor(struct swim __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			      enum motor_action action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	if (action == ON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		swim_action(base, MOTOR_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		for (i = 0; i < 2*HZ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 			swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 			if (swim_readbit(base, MOTOR_ON))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 			schedule_timeout(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	} else if (action == OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		swim_action(base, MOTOR_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static inline void swim_eject(struct swim __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	swim_action(base, EJECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	for (i = 0; i < 2*HZ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 		swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 		if (!swim_readbit(base, DISK_IN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 		schedule_timeout(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static inline void swim_head(struct swim __iomem *base, enum head head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	/* wait drive is ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	if (head == UPPER_HEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		swim_select(base, READ_DATA_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	else if (head == LOWER_HEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		swim_select(base, READ_DATA_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static inline int swim_step(struct swim __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	int wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 	swim_action(base, STEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	for (wait = 0; wait < HZ; wait++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		schedule_timeout(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		if (!swim_readbit(base, STEP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static inline int swim_track00(struct swim __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	int try;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	swim_action(base, SEEK_NEGATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	for (try = 0; try < 100; try++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 		swim_select(base, RELAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		if (swim_readbit(base, TRACK_ZERO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		if (swim_step(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 			return -1;
^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) 	if (swim_readbit(base, TRACK_ZERO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static inline int swim_seek(struct swim __iomem *base, int step)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	if (step == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	if (step < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		swim_action(base, SEEK_NEGATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		step = -step;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 		swim_action(base, SEEK_POSITIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	for ( ; step > 0; step--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		if (swim_step(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 			return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) static inline int swim_track(struct floppy_state *fs,  int track)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	ret = swim_seek(base, track - fs->track);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 		fs->track = track;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 		swim_track00(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 		fs->track = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static int floppy_eject(struct floppy_state *fs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	swim_drive(base, fs->location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	swim_motor(base, OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	swim_eject(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	fs->disk_in = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	fs->ejected = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static inline int swim_read_sector(struct floppy_state *fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 				   int side, int track,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 				   int sector, unsigned char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	struct sector_header header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	int ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	short i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	swim_track(fs, track);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	swim_write(base, mode1, MOTON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	swim_head(base, side);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	swim_write(base, mode0, side);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	for (i = 0; i < 36; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		ret = swim_read_sector_header(base, &header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		if (!ret && (header.sector == sector)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			/* found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 			ret = swim_read_sector_data(base, buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	swim_write(base, mode0, MOTON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	if ((header.side != side)  || (header.track != track) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	     (header.sector != sector))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) static blk_status_t floppy_read_sectors(struct floppy_state *fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 			       int req_sector, int sectors_nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 			       unsigned char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	int side, track, sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	int i, try;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	swim_drive(base, fs->location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	for (i = req_sector; i < req_sector + sectors_nb; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 		int x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 		track = i / fs->secpercyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		x = i % fs->secpercyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 		side = x / fs->secpertrack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 		sector = x % fs->secpertrack + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 		try = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 		do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 			ret = swim_read_sector(fs, side, track, sector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 						buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 			if (try-- == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 				return BLK_STS_IOERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 		} while (ret != 512);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 		buffer += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 				  const struct blk_mq_queue_data *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	struct floppy_state *fs = hctx->queue->queuedata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	struct swim_priv *swd = fs->swd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	struct request *req = bd->rq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	blk_status_t err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	if (!spin_trylock_irq(&swd->lock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		return BLK_STS_DEV_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	blk_mq_start_request(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	if (!fs->disk_in || rq_data_dir(req) == WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 		err = BLK_STS_IOERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 		err = floppy_read_sectors(fs, blk_rq_pos(req),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 					  blk_rq_cur_sectors(req),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 					  bio_data(req->bio));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	} while (blk_update_request(req, err, blk_rq_cur_bytes(req)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	__blk_mq_end_request(req, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	err = BLK_STS_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	spin_unlock_irq(&swd->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	return err;
^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) static struct floppy_struct floppy_type[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 	{    0,  0, 0,  0, 0, 0x00, 0x00, 0x00, 0x00, NULL }, /* no testing   */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	{  720,  9, 1, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 360KB SS 3.5"*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	{ 1440,  9, 2, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 720KB 3.5"   */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	{ 2880, 18, 2, 80, 0, 0x1B, 0x00, 0xCF, 0x6C, NULL }, /* 1.44MB 3.5"  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int get_floppy_geometry(struct floppy_state *fs, int type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 			       struct floppy_struct **g)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	if (type >= ARRAY_SIZE(floppy_type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	if (type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		*g = &floppy_type[type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	else if (fs->type == HD_MEDIA) /* High-Density media */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 		*g = &floppy_type[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 	else if (fs->head_number == 2) /* double-sided */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 		*g = &floppy_type[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 		*g = &floppy_type[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static void setup_medium(struct floppy_state *fs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 	if (swim_readbit(base, DISK_IN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 		struct floppy_struct *g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 		fs->disk_in = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 		fs->write_protected = swim_readbit(base, WRITE_PROT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 		if (swim_track00(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 			printk(KERN_ERR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 				"SWIM: cannot move floppy head to track 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 		swim_track00(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 		fs->type = swim_readbit(base, TWOMEG_MEDIA) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 			HD_MEDIA : DD_MEDIA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 		fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 		get_floppy_geometry(fs, 0, &g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 		fs->total_secs = g->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 		fs->secpercyl = g->head * g->sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 		fs->secpertrack = g->sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 		fs->track = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 		fs->disk_in = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) static int floppy_open(struct block_device *bdev, fmode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	struct floppy_state *fs = bdev->bd_disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	if (fs->ref_count == -1 || (fs->ref_count && mode & FMODE_EXCL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 	if (mode & FMODE_EXCL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 		fs->ref_count = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 		fs->ref_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	swim_write(base, setup, S_IBM_DRIVE  | S_FCLK_DIV2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	swim_drive(base, fs->location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	swim_motor(base, ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	swim_action(base, SETMFM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 	if (fs->ejected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 		setup_medium(fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	if (!fs->disk_in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 		err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 		goto out;
^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) 	set_capacity(fs->disk, fs->total_secs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 	if (mode & FMODE_NDELAY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 	if (mode & (FMODE_READ|FMODE_WRITE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 		if (bdev_check_media_change(bdev) && fs->disk_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 			fs->ejected = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 		if ((mode & FMODE_WRITE) && fs->write_protected) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 			err = -EROFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	if (fs->ref_count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 		fs->ref_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	else if (fs->ref_count > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 		--fs->ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 	if (fs->ref_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 		swim_motor(base, OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	mutex_lock(&swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 	ret = floppy_open(bdev, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	mutex_unlock(&swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) static void floppy_release(struct gendisk *disk, fmode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	struct floppy_state *fs = disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 	struct swim __iomem *base = fs->swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 	mutex_lock(&swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 	if (fs->ref_count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 		fs->ref_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 	else if (fs->ref_count > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		--fs->ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	if (fs->ref_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 		swim_motor(base, OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 	mutex_unlock(&swim_mutex);
^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 int floppy_ioctl(struct block_device *bdev, fmode_t mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 			unsigned int cmd, unsigned long param)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 	struct floppy_state *fs = bdev->bd_disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 			return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	case FDEJECT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 		if (fs->ref_count != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 			return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 		mutex_lock(&swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 		err = floppy_eject(fs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 		mutex_unlock(&swim_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 	case FDGETPRM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 		if (copy_to_user((void __user *) param, (void *) &floppy_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 				 sizeof(struct floppy_struct)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 			return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 	return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 	struct floppy_state *fs = bdev->bd_disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 	struct floppy_struct *g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	ret = get_floppy_geometry(fs, 0, &g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	geo->heads = g->head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	geo->sectors = g->sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 	geo->cylinders = g->track;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) static unsigned int floppy_check_events(struct gendisk *disk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 					unsigned int clearing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 	struct floppy_state *fs = disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) static const struct block_device_operations floppy_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 	.owner		 = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	.open		 = floppy_unlocked_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 	.release	 = floppy_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 	.ioctl		 = floppy_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 	.getgeo		 = floppy_getgeo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	.check_events	 = floppy_check_events,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) static struct kobject *floppy_find(dev_t dev, int *part, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 	struct swim_priv *swd = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 	int drive = (*part & 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 	if (drive >= swd->floppy_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 	*part = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 	return get_disk_and_module(swd->unit[drive].disk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 	struct floppy_state *fs = &swd->unit[swd->floppy_count];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 	struct swim __iomem *base = swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 	fs->location = location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 	swim_drive(base, location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 	swim_motor(base, OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	fs->type = HD_MEDIA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 	fs->head_number = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 	fs->ref_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 	fs->ejected = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 	swd->floppy_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static const struct blk_mq_ops swim_mq_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 	.queue_rq = swim_queue_rq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) static int swim_floppy_init(struct swim_priv *swd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 	int drive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	struct swim __iomem *base = swd->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 	/* scan floppy drives */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 	swim_drive(base, INTERNAL_DRIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) 	if (swim_readbit(base, DRIVE_PRESENT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 	    !swim_readbit(base, ONEMEG_DRIVE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 		swim_add_floppy(swd, INTERNAL_DRIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 	swim_drive(base, EXTERNAL_DRIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) 	if (swim_readbit(base, DRIVE_PRESENT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) 	    !swim_readbit(base, ONEMEG_DRIVE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) 		swim_add_floppy(swd, EXTERNAL_DRIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) 	/* register floppy drives */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) 	err = register_blkdev(FLOPPY_MAJOR, "fd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) 		printk(KERN_ERR "Unable to get major %d for SWIM floppy\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) 		       FLOPPY_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) 	spin_lock_init(&swd->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 	for (drive = 0; drive < swd->floppy_count; drive++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) 		struct request_queue *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) 		swd->unit[drive].disk = alloc_disk(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) 		if (swd->unit[drive].disk == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) 			err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) 			goto exit_put_disks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) 		q = blk_mq_init_sq_queue(&swd->unit[drive].tag_set, &swim_mq_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) 						2, BLK_MQ_F_SHOULD_MERGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) 		if (IS_ERR(q)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) 			err = PTR_ERR(q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) 			goto exit_put_disks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) 		swd->unit[drive].disk->queue = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) 		blk_queue_bounce_limit(swd->unit[drive].disk->queue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) 				BLK_BOUNCE_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) 		swd->unit[drive].disk->queue->queuedata = &swd->unit[drive];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) 		swd->unit[drive].swd = swd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) 	for (drive = 0; drive < swd->floppy_count; drive++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) 		swd->unit[drive].disk->flags = GENHD_FL_REMOVABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) 		swd->unit[drive].disk->major = FLOPPY_MAJOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) 		swd->unit[drive].disk->first_minor = drive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) 		sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) 		swd->unit[drive].disk->fops = &floppy_fops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) 		swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) 		swd->unit[drive].disk->private_data = &swd->unit[drive];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) 		set_capacity(swd->unit[drive].disk, 2880);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) 		add_disk(swd->unit[drive].disk);
^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) 	blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) 			    floppy_find, NULL, swd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) exit_put_disks:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) 	unregister_blkdev(FLOPPY_MAJOR, "fd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) 		struct gendisk *disk = swd->unit[drive].disk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) 		if (disk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) 			if (disk->queue) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) 				blk_cleanup_queue(disk->queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) 				disk->queue = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) 			blk_mq_free_tag_set(&swd->unit[drive].tag_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) 			put_disk(disk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) 	} while (drive--);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) static int swim_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) 	struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) 	struct swim __iomem *swim_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) 	struct swim_priv *swd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) 	if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) 		ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) 	if (!request_mem_region(res->start, resource_size(res), CARDNAME)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) 		ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) 	swim_base = (struct swim __iomem *)res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) 	if (!swim_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) 		goto out_release_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) 	/* probe device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) 	set_swim_mode(swim_base, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) 	if (!get_swim_mode(swim_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) 		printk(KERN_INFO "SWIM device not found !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) 		ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) 		goto out_release_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) 	/* set platform driver data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) 	swd = kzalloc(sizeof(struct swim_priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) 	if (!swd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) 		goto out_release_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) 	platform_set_drvdata(dev, swd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) 	swd->base = swim_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) 	ret = swim_floppy_init(swd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) 		goto out_kfree;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) out_kfree:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) 	kfree(swd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) out_release_io:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) 	release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) static int swim_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) 	struct swim_priv *swd = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) 	int drive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) 	struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) 	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) 	for (drive = 0; drive < swd->floppy_count; drive++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) 		del_gendisk(swd->unit[drive].disk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) 		blk_cleanup_queue(swd->unit[drive].disk->queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) 		blk_mq_free_tag_set(&swd->unit[drive].tag_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) 		put_disk(swd->unit[drive].disk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) 	unregister_blkdev(FLOPPY_MAJOR, "fd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) 	/* eject floppies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) 	for (drive = 0; drive < swd->floppy_count; drive++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) 		floppy_eject(&swd->unit[drive]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) 	if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) 		release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) 	kfree(swd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) static struct platform_driver swim_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) 	.probe  = swim_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) 	.remove = swim_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) 	.driver   = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) 		.name	= CARDNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) static int __init swim_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) 	printk(KERN_INFO "SWIM floppy driver %s\n", DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) 	return platform_driver_register(&swim_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) module_init(swim_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static void __exit swim_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) 	platform_driver_unregister(&swim_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) module_exit(swim_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) MODULE_DESCRIPTION("Driver for SWIM floppy controller");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) MODULE_AUTHOR("Laurent Vivier <laurent@lvivier.info>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);