^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);