diff -uprN -X dontdiff linux-2.2.27-pre2.orig/arch/m68k/mac/config.c linux-2.2.27-pre2/arch/m68k/mac/config.c --- linux-2.2.27-pre2.orig/arch/m68k/mac/config.c 2004-09-02 10:27:55.000000000 +0200 +++ linux-2.2.27-pre2/arch/m68k/mac/config.c 2004-09-02 11:47:16.000000000 +0200 @@ -86,6 +86,7 @@ extern void via_init_clock(void (*func)( extern void via_flush_cache(void); extern void oss_init(void); extern void psc_init(void); +extern void swim_init(void); extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); @@ -709,6 +710,7 @@ void mac_identify(void) via_init(); oss_init(); psc_init(); + swim_init(); } void mac_report_hardware(void) diff -uprN -X dontdiff linux-2.2.27-pre2.orig/arch/m68k/mac/mac_ksyms.c linux-2.2.27-pre2/arch/m68k/mac/mac_ksyms.c --- linux-2.2.27-pre2.orig/arch/m68k/mac/mac_ksyms.c 2001-03-25 18:31:52.000000000 +0200 +++ linux-2.2.27-pre2/arch/m68k/mac/mac_ksyms.c 2004-09-02 20:24:41.000000000 +0200 @@ -7,8 +7,10 @@ extern void (*adb_mouse_interrupt_hook) /* Says whether we're using A/UX interrupts or not */ extern int via_alt_mapping; +extern unsigned char *SWIMBase; #ifndef CONFIG_ADB_NEW EXPORT_SYMBOL(adb_mouse_interrupt_hook); #endif EXPORT_SYMBOL(via_alt_mapping); +EXPORT_SYMBOL(SWIMBase); diff -uprN -X dontdiff linux-2.2.27-pre2.orig/arch/m68k/mac/Makefile linux-2.2.27-pre2/arch/m68k/mac/Makefile --- linux-2.2.27-pre2.orig/arch/m68k/mac/Makefile 2001-03-25 18:31:52.000000000 +0200 +++ linux-2.2.27-pre2/arch/m68k/mac/Makefile 2004-09-02 11:17:30.000000000 +0200 @@ -9,7 +9,7 @@ O_TARGET := mac.o O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ - mackeyb.o adb-bus.o macboing.o debug.o adb-misc.o + mackeyb.o adb-bus.o macboing.o debug.o adb-misc.o swim.o OX_OBJS := mac_ksyms.o include $(TOPDIR)/Rules.make diff -uprN -X dontdiff linux-2.2.27-pre2.orig/arch/m68k/mac/swim.c linux-2.2.27-pre2/arch/m68k/mac/swim.c --- linux-2.2.27-pre2.orig/arch/m68k/mac/swim.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.2.27-pre2/arch/m68k/mac/swim.c 2004-09-15 16:35:42.000000000 +0200 @@ -0,0 +1,111 @@ +/* + * Driver for SWIM (Sander. Woz Integrated Machine) floppy controller + * + * Copyright (C) 2004 Laurent Vivier + * + * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. + * based on Alastair Bridgewater SWIM analysis, 2001 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 2004-09-02 (lv) - Initial implementation + */ + +#include +#include +#include +#include +#include + +#include +#include + +volatile __u8 *SWIMBase; + +#define writePhase *(SWIMBase + 0x0800) +#define readPhase *(SWIMBase + 0x1800) + +/* + * According to IWM netBSD driver, there are four kinds of SWIM: + * + * - QUADRA, QUADRA2, P580 -> SWIM base address is VIA1 + 0X1E000; + * - II, PB, LC -> SWIM base address is VIA1 + 0x16000; + * - IIfx, Q900, Q950 -> managed by IOP driver + * - AV -> not managed + * + */ + +__initfunc(void swim_init(void)) +{ + int valid; + + switch(macintosh_config->ident) + { + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q650: + case MAC_MODEL_Q605: + case MAC_MODEL_Q605_ACC: + case MAC_MODEL_Q610: + case MAC_MODEL_Q630: + case MAC_MODEL_P475: + case MAC_MODEL_P475F: + case MAC_MODEL_P575: + case MAC_MODEL_P588: + SWIMBase = (__u8*)(VIA1_BASE + 0x1E000); + break; + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + case MAC_MODEL_PB140: + case MAC_MODEL_PB145: + case MAC_MODEL_PB160: + case MAC_MODEL_PB165: + case MAC_MODEL_PB165C: + case MAC_MODEL_PB170: + case MAC_MODEL_PB180: + case MAC_MODEL_PB180C: + case MAC_MODEL_PB190: + case MAC_MODEL_PB520: + case MAC_MODEL_PB150: + case MAC_MODEL_PB210: + case MAC_MODEL_PB230: + case MAC_MODEL_PB250: + case MAC_MODEL_PB270C: + case MAC_MODEL_PB280: + case MAC_MODEL_PB280C: + case MAC_MODEL_IICI: + case MAC_MODEL_IISI: + case MAC_MODEL_IIVI: + case MAC_MODEL_IIVX: + case MAC_MODEL_P600: + case MAC_MODEL_P460: + case MAC_MODEL_P550: + case MAC_MODEL_TV: + case MAC_MODEL_LCII: + case MAC_MODEL_LCIII: + case MAC_MODEL_P520: + case MAC_MODEL_CLII: + case MAC_MODEL_CCL: + SWIMBase = (__u8*)(VIA1_BASE + 0x16000); + break; + case MAC_MODEL_IIFX: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + SWIMBase = NULL; + break; + default: + SWIMBase = NULL; + printk("SWIM: unknown Macintosh: report to maintainer !\n"); + break; + } + + if (SWIMBase == NULL) + return; + + printk("SWIM floppy controller base at 0x%p\n", SWIMBase); +} diff -uprN -X dontdiff linux-2.2.27-pre2.orig/Documentation/Configure.help linux-2.2.27-pre2/Documentation/Configure.help --- linux-2.2.27-pre2.orig/Documentation/Configure.help 2004-09-02 10:28:26.000000000 +0200 +++ linux-2.2.27-pre2/Documentation/Configure.help 2004-09-02 12:15:11.000000000 +0200 @@ -180,6 +180,27 @@ CONFIG_BLK_DEV_FD The module will be called floppy.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Support for Macintosh floppy +CONFIG_BLK_DEV_SWIM + You should select this option, if you want floppy support and + you have one of following macintoshes: + + II, IIci, IIsi, IIvx, IIx, IIcx, SE/30, + PowerBook 100, PowerBook 140, PowerBook 145, PowerBook 160, + PowerBook 165, PowerBook 165c, PowerBook 170, PowerBook 180, + PowerBook 180c, PowerBook 190, PowerBook 190cs, PowerBook 500, + Performa 460, Performa 550, LC II, LC III, LC 520, Color Classic, + Color Classic II, ClassicII, + Quadra 700, Quadra 800, Quadra 650, Quadra 605, Quadra 610, + Centris 610, Quadra 630, Performa 580, LC 475, LC 575, + +Support for Macintosh floppy IOP-based +CONFIG_BLK_DEV_SWIM_IOP + You should select this option, if you want floppy support and + you have a one of following macintoshes: + + Macintosh IIfx, Quadra 900, Quadra 950 + Support for PowerMac floppy CONFIG_MAC_FLOPPY If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/Config.in linux-2.2.27-pre2/drivers/block/Config.in --- linux-2.2.27-pre2.orig/drivers/block/Config.in 2004-09-02 10:27:55.000000000 +0200 +++ linux-2.2.27-pre2/drivers/block/Config.in 2004-09-02 12:15:44.000000000 +0200 @@ -13,6 +13,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support' CONFIG_BLK_DEV_SWIM_IOP + tristate 'Other Macintosh II/Quadra/Centris/LC/Classic floppy support' CONFIG_BLK_DEV_SWIM fi tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/ll_rw_blk.c linux-2.2.27-pre2/drivers/block/ll_rw_blk.c --- linux-2.2.27-pre2.orig/drivers/block/ll_rw_blk.c 2004-09-02 10:27:55.000000000 +0200 +++ linux-2.2.27-pre2/drivers/block/ll_rw_blk.c 2004-09-02 12:37:22.000000000 +0200 @@ -1007,6 +1007,9 @@ __initfunc(int blk_dev_init(void)) #ifdef CONFIG_MAC_FLOPPY swim3_init(); #endif +#ifdef CONFIG_BLK_DEV_SWIM + swim_floppy_init(); +#endif #ifdef CONFIG_BLK_DEV_SWIM_IOP swimiop_init(); #endif diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/Makefile linux-2.2.27-pre2/drivers/block/Makefile --- linux-2.2.27-pre2.orig/drivers/block/Makefile 2004-09-02 10:27:56.000000000 +0200 +++ linux-2.2.27-pre2/drivers/block/Makefile 2004-09-02 12:50:24.000000000 +0200 @@ -116,6 +116,14 @@ else endif endif +ifeq ($(CONFIG_BLK_DEV_SWIM),y) + L_OBJS += swim_driver.o swim_asm.o +else + ifeq ($(CONFIG_BLK_DEV_SWIM),m) + M_OBJS += swim.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_SWIM_IOP),y) L_OBJS += swim_iop.o endif @@ -414,3 +422,6 @@ include $(TOPDIR)/Rules.make ide-mod.o: ide.o $(IDE_OBJS) $(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS) + +swim.o: swim_driver.o swim_asm.o + $(LD) $(LD_RFLAG) -r -o $@ swim_driver.o swim_asm.o diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/rd.c linux-2.2.27-pre2/drivers/block/rd.c --- linux-2.2.27-pre2.orig/drivers/block/rd.c 2004-09-02 10:27:56.000000000 +0200 +++ linux-2.2.27-pre2/drivers/block/rd.c 2004-09-14 21:11:54.000000000 +0200 @@ -590,13 +590,18 @@ done: #ifdef CONFIG_MAC_FLOPPY int swim3_fd_eject(int devnum); #endif +#ifdef CONFIG_BLK_DEV_SWIM +int swim_fd_eject(int devnum); +#endif +#ifdef CONFIG_BLK_DEV_SWIM_IOP +int swimiop_fd_eject(int devnum); +#endif __initfunc(static void rd_load_disk(int n)) { #ifdef CONFIG_BLK_DEV_INITRD extern kdev_t real_root_dev; #endif - if (rd_doload == 0) return; @@ -639,6 +644,22 @@ __initfunc(static void rd_load_disk(int swim3_fd_eject(MINOR(real_root_dev)); #endif #endif +#if CONFIG_BLK_DEV_SWIM + if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) + swim_fd_eject(MINOR(ROOT_DEV)); +#ifdef CONFIG_BLK_DEV_INITRD + else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) + swim_fd_eject(MINOR(real_root_dev)); +#endif +#endif +#if CONFIG_BLK_DEV_SWIM_IOP + if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) + swimiop_fd_eject(MINOR(ROOT_DEV)); +#ifdef CONFIG_BLK_DEV_INITRD + else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) + swimiop_fd_eject(MINOR(real_root_dev)); +#endif +#endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); wait_for_keypress(); diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/swim_asm.S linux-2.2.27-pre2/drivers/block/swim_asm.S --- linux-2.2.27-pre2.orig/drivers/block/swim_asm.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.2.27-pre2/drivers/block/swim_asm.S 2004-09-15 16:21:52.000000000 +0200 @@ -0,0 +1,295 @@ +/* + * low-level functions for the SWIM floppy controller + * + * needs assembly language because is very timing dependent + * this controller exists only on macintosh 680x0 based + * + * Copyright (C) 2004 Laurent Vivier + * + * based on Alastair Bridgewater SWIM analysis, 2001 + * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 2004-08-21 (lv) - Initial implementation + */ + + .equ ph0L, 0x0000 + .equ ph0H, 0x0200 + .equ ph1L, 0x0400 + .equ ph1H, 0x0600 + .equ ph2L, 0x0800 + .equ ph2H, 0x0a00 + .equ ph3L, 0x0c00 + .equ ph3H, 0x0e00 + .equ mtrOff, 0x1000 + .equ mtrOn, 0x1200 + .equ intDrive, 0x1400 + .equ extDrive, 0x1600 + .equ q6L, 0x1800 + .equ q6H, 0x1a00 + .equ q7L, 0x1c00 + .equ q7H, 0x1e00 + + .equ write_data, 0x0000 + .equ write_mark, 0x0200 + .equ write_CRC, 0x0400 + .equ write_parameter,0x0600 + .equ write_phase, 0x0800 + .equ write_setup, 0x0a00 + .equ write_mode0, 0x0c00 + .equ write_mode1, 0x0e00 + .equ read_data, 0x1000 + .equ read_mark, 0x1200 + .equ read_error, 0x1400 + .equ read_parameter, 0x1600 + .equ read_phase, 0x1800 + .equ read_setup, 0x1a00 + .equ read_status, 0x1c00 + .equ read_handshake, 0x1e00 + + .equ o_side, 0 + .equ o_track, 1 + .equ o_sector, 2 + .equ o_size, 3 + .equ o_crc0, 4 + .equ o_crc1, 5 + + .equ seek_time, 30000 + .equ max_retry, 40 + .equ sector_size, 512 + + .global swim_mode +swim_mode: + link %a6, #0 + moveml %a0/%d2, %sp@- + + movel SWIMBase, %a0 + + tstl %a6@(0x08) + beq iwm_mode + + /* switch to SWIM mode */ + + tstb %a0@(q7L) + tstb %a0@(mtrOff) + tstb %a0@(q6H) + moveb #0x57, %d2 + moveb %d2, %a0@(q7H) + moveb #0x17, %a0@(q7H) + moveb %d2, %a0@(q7H) + moveb %d2, %a0@(q7H) + moveml %sp@+, %a0/%d2 + unlk %a6 + rts +iwm_mode: + /* switch to IWM mode */ + + moveb #0xf8, %a0@(write_mode0) + moveml %sp@+, %a0/%d2 + unlk %a6 + rts + + + .global swim_read_sector_header +swim_read_sector_header: + link %a6, #0 + moveml %d1-%d5/%a0-%a4,%sp@- + movel %a6@(0x08), %a4 + bsr mfm_read_addrmark + moveml %sp@+, %d1-%d5/%a0-%a4 + unlk %a6 + rts + +sector_address_mark: + .byte 0xa1, 0xa1, 0xa1, 0xfe +sector_data_mark: + .byte 0xa1, 0xa1, 0xa1, 0xfb + +mfm_read_addrmark: + movel SWIMBase, %a3 + lea %a3@(read_handshake), %a2 + lea %a3@(read_mark), %a3 + moveq #-1, %d0 + movew #seek_time, %d2 + +wait_header_init: + tstb %a3@(read_error - read_mark) + moveb #0x18, %a3@(write_mode0 - read_mark) + moveb #0x01, %a3@(write_mode1 - read_mark) + moveb #0x01, %a3@(write_mode0 - read_mark) + tstb %a3@(read_error - read_mark) + moveb #0x08, %a3@(write_mode1 - read_mark) + + lea sector_address_mark, %a0 + moveq #3, %d1 + +wait_addr_mark_byte: + + tstb %a2@ + dbmi %d2, wait_addr_mark_byte + bpl header_exit + + moveb %a3@, %d3 + cmpb %a0@+, %d3 + dbne %d1, wait_addr_mark_byte + bne wait_header_init + + moveq #max_retry, %d2 + +amark0: tstb %a2@ + dbmi %d2, amark0 + bpl signal_nonyb + + moveb %a3@, %a4@(o_track) + + moveq #max_retry, %d2 + +amark1: tstb %a2@ + dbmi %d2, amark1 + bpl signal_nonyb + + moveb %a3@, %a4@(o_side) + + moveq #max_retry, %d2 + +amark2: tstb %a2@ + dbmi %d2, amark2 + bpl signal_nonyb + + moveb %a3@, %a4@(o_sector) + + moveq #max_retry, %d2 + +amark3: tstb %a2@ + dbmi %d2, amark3 + bpl signal_nonyb + + moveb %a3@, %a4@(o_size) + + moveq #max_retry, %d2 + +crc0: tstb %a2@ + dbmi %d2, crc0 + bpl signal_nonyb + + moveb %a3@, %a4@(o_crc0) + + moveq #max_retry, %d2 + +crc1: tstb %a2@ + dbmi %d2, crc1 + bpl signal_nonyb + + moveb %a3@, %a4@(o_crc1) + + tstb %a3@(read_error - read_mark) + +header_exit: + moveq #0, %d0 + moveb #0x18, %a3@(write_mode0 - read_mark) + rts +signal_nonyb: + moveq #-1, %d0 + moveb #0x18, %a3@(write_mode0 - read_mark) + rts + + .global swim_read_sector_data +swim_read_sector_data: + link %a6, #0 + moveml %d1-%d5/%a0-%a5,%sp@- + movel %a6@(0x08), %a4 + bsr mfm_read_data + moveml %sp@+, %d1-%d5/%a0-%a5 + unlk %a6 + rts + +mfm_read_data: + movel SWIMBase, %a3 + lea %a3@(read_handshake), %a2 + lea %a3@(read_data), %a5 + lea %a3@(read_mark), %a3 + movew #seek_time, %d2 + +wait_data_init: + tstb %a3@(read_error - read_mark) + moveb #0x18, %a3@(write_mode0 - read_mark) + moveb #0x01, %a3@(write_mode1 - read_mark) + moveb #0x01, %a3@(write_mode0 - read_mark) + tstb %a3@(read_error - read_mark) + moveb #0x08, %a3@(write_mode1 - read_mark) + + lea sector_data_mark, %a0 + moveq #3, %d1 + + /* wait data address mark */ + +wait_data_mark_byte: + + tstb %a2@ + dbmi %d2, wait_data_mark_byte + bpl data_exit + + moveb %a3@, %d3 + cmpb %a0@+, %d3 + dbne %d1, wait_data_mark_byte + bne wait_data_init + + /* read data */ + + tstb %a3@(read_error - read_mark) + + movel #sector_size-1, %d4 /* sector size */ +read_new_data: + movew #max_retry, %d2 +read_data_loop: + moveb %a2@, %d5 + andb #0xc0, %d5 + dbne %d2, read_data_loop + beq data_exit + moveb %a5@, %a4@+ + andb #0x40, %d5 + dbne %d4, read_new_data + beq exit_loop + moveb %a5@, %a4@+ + dbra %d4, read_new_data +exit_loop: + + /* read CRC */ + + movew #max_retry, %d2 +data_crc0: + + tstb %a2@ + dbmi %d2, data_crc0 + bpl data_exit + + moveb %a3@, %d5 + + moveq #max_retry, %d2 + +data_crc1: + + tstb %a2@ + dbmi %d2, data_crc1 + bpl data_exit + + moveb %a3@, %d5 + + tstb %a3@(read_error - read_mark) + + moveb #0x18, %a3@(write_mode0 - read_mark) + + /* return number of bytes read */ + + movel #sector_size, %d0 + addw #1, %d4 + subl %d4, %d0 + rts +data_exit: + moveb #0x18, %a3@(write_mode0 - read_mark) + moveq #-1, %d0 + rts diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/swim_driver.c linux-2.2.27-pre2/drivers/block/swim_driver.c --- linux-2.2.27-pre2.orig/drivers/block/swim_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.2.27-pre2/drivers/block/swim_driver.c 2004-09-15 16:24:08.000000000 +0200 @@ -0,0 +1,891 @@ +/* + * Driver for SWIM (Sander. Woz Integrated Machine) floppy controller + * + * Copyright (C) 2004 Laurent Vivier + * + * based on Alastair Bridgewater SWIM analysis, 2001 + * based on SWIM3 driver (c) Paul Mackerras, 1996 + * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. + * + * Supported Macintoshes: + * + * II, IIci, IIsi, IIvx, IIx, IIcx, SE/30, + * PowerBook 100, PowerBook 140, PowerBook 145, PowerBook 160, + * PowerBook 165, PowerBook 165c, PowerBook 170, PowerBook 180, + * PowerBook 180c, PowerBook 190, PowerBook 190cs, PowerBook 500, + * Performa 460, Performa 550, LC II, LC III, LC 520, Color Classic, + * Color Classic II, ClassicII, + * Quadra 700, Quadra 800, Quadra 650, Quadra 605, Quadra 610, + * Centris 610, Quadra 630, Performa 580, LC 475, LC 575, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 2004-08-21 (lv) - Initial implementation + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR + +#include /* configured by MAJOR_NR */ + +#include +#include +#include +#include + +struct sector_header { + unsigned char side; + unsigned char track; + unsigned char sector; + unsigned char size; + unsigned char crc0; + unsigned char crc1; +} __attribute__((packed)); + +extern int swim_mode(int enable); +extern int swim_read_sector_header(struct sector_header* header); +extern int swim_read_sector_data(unsigned char *data); + +#define INT_OFF save_flags(flags); cli() +#define INT_ON restore_flags(flags) + +#define DRIVER_VERSION "Version 0.1 (2004-08-21)" + +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 + +#define REG(x) volatile unsigned char x, x ## _pad[0x200 - 1]; + +struct swim { + REG(write_data) + REG(write_mark) + REG(write_CRC) + REG(write_parameter) + REG(write_phase) + REG(write_setup) + REG(write_mode0) + REG(write_mode1) + + REG(read_data) + REG(read_mark) + REG(read_error) + REG(read_parameter) + REG(read_phase) + REG(read_setup) + REG(read_status) + REG(read_handshake) +} __attribute__((packed)); + +extern struct swim *SWIMBase; + +#define swim_write(reg, v) SWIMBase->write_##reg = v +#define swim_read(reg) SWIMBase->read_##reg + +/* bits in phase register */ + +#define SEEK_POSITIVE 0x070 +#define SEEK_NEGATIVE 0x074 +#define STEP 0x071 +#define MOTOR_ON 0x072 +#define MOTOR_OFF 0x076 +#define INDEX 0x073 +#define EJECT 0x077 +#define SETMFM 0x171 +#define SETGCR 0x175 + +#define RELAX 0x033 +#define LSTRB 0x008 + +#define CA_MASK 0x077 + +/* Select values for swim_select and swim_readbit */ + +#define STEP_DIR 0x070 +#define STEPPING 0x071 +#define MOTOR_ON 0x072 +#define ELAX 0x073 /* also eject in progress */ +#define READ_DATA_0 0x074 +#define TWOMEG_DRIVE 0x075 +#define SINGLE_SIDED 0x076 +#define DRIVE_PRESENT 0x077 +#define DISK_IN 0x170 +#define WRITE_PROT 0x171 +#define TRACK_ZERO 0x172 +#define TACHO 0x173 +#define READ_DATA_1 0x174 +#define MFM_MODE 0x175 +#define SEEK_COMPLETE 0x176 +#define ONEMEG_MEDIA 0x177 + +/* Bits in handshake register */ + +#define MARK_BYTE 0x01 +#define CRC_ZERO 0x02 +#define RDDATA 0x04 +#define SENSE 0x08 +#define MOTEN 0x10 +#define ERROR 0x20 +#define DAT2BYTE 0x40 +#define DAT1BYTE 0x80 + +/* bits in setup register */ + +#define S_INV_WDATA 0x01 +#define S_3_5_SELECT 0x02 +#define S_GCR 0x04 +#define S_FCLK_DIV2 0x08 +#define S_ERROR_CORR 0x10 +#define S_IBM_DRIVE 0x20 +#define S_GCR_WRITE 0x40 +#define S_TIMEOUT 0x80 + +/* bits in mode register */ + +#define CLFIFO 0x01 +#define ENBL1 0x02 +#define ENBL2 0x04 +#define ACTION 0x08 +#define WRITE_MODE 0x10 +#define HEDSEL 0x20 +#define MOTON 0x80 + + +/*----------------------------------------------------------------------------*/ + +typedef enum { + INTERNAL_DRIVE = 0x02, + EXTERNAL_DRIVE = 0x04, +} drive_location_t; + +typedef enum { + DD_MEDIA, + HD_MEDIA, +} media_type_t; + +struct floppy_state { + + /* physical properties */ + + drive_location_t location; /* internal or external drive */ + int head_number; /* single- or double-sided drive */ + + /* media */ + + int disk_in; + int ejected; + media_type_t type; + int write_protected; + + int total_secs; + int secpercyl; + int secpertrack; + + /* in-use information */ + + int track; +#if 0 + struct timer_list timeout; + int timeout_done; +#endif + + int ref_count; +}; + +typedef enum { + OFF, + ON, +} motor_action_t; + +typedef enum { + LOWER_HEAD = 0, + UPPER_HEAD = 1, +} head_t; + +#define MAX_FLOPPIES 2 + +static int floppy_blocksizes[MAX_FLOPPIES] = {512,512}; +static int floppy_sizes[MAX_FLOPPIES] = {2880,2880}; + +static struct floppy_state floppy_states[MAX_FLOPPIES]; +static int floppy_count = 0; + +static inline void swim_select(int sel) +{ + swim_write(phase, RELAX); + + if (sel & 0x100) + via_write((char*)VIA1_BASE, vBufA, + via_read((char*)VIA1_BASE, vBufA) | VIA1A_vHeadSel); + else + via_write((char*)VIA1_BASE, vBufA, + via_read((char*)VIA1_BASE, vBufA) & ~VIA1A_vHeadSel); + + swim_write(phase, sel & CA_MASK); +} + +static inline void swim_action(int action) +{ + swim_select(action); + udelay(1); + swim_write(phase, (LSTRB<<4) | LSTRB); + udelay(1); + swim_write(phase, (LSTRB<<4) | ((~LSTRB) & 0x0F)); + udelay(1); + swim_write(phase, RELAX); +} + +static inline int swim_readbit(int bit) +{ + int stat; + + swim_select(bit); + + udelay(10); + + stat = swim_read(handshake); + + swim_write(phase, RELAX); + + return (stat & SENSE) == 0; +} + +static inline void swim_drive(drive_location_t location) +{ + if (location == INTERNAL_DRIVE) { + swim_write(mode0, EXTERNAL_DRIVE); /* clear drive 1 bit */ + swim_write(mode1, INTERNAL_DRIVE); /* set drive 0 bit */ + } else if (location == EXTERNAL_DRIVE) { + swim_write(mode0, INTERNAL_DRIVE); /* clear drive 0 bit */ + swim_write(mode1, EXTERNAL_DRIVE); /* set drive 1 bit */ + } +} + +static inline void swim_motor(motor_action_t action) +{ + if (action == ON) { + int i; + + swim_action(MOTOR_ON); + + for (i = 0; i < 2*HZ; i++) { + if (swim_readbit(MOTOR_ON)) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + } else if (action == OFF) + swim_action(MOTOR_OFF); +} + +static inline void swim_eject(void) +{ + int i; + + swim_action(EJECT); + + for (i = 0; i < 2*HZ; i++) { + if (swim_readbit(RELAX)) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +} + +static inline void swim_head(head_t head) +{ + /* FIXME: IWM reads bits SEL, CA2, CA1 to wait drive ready... */ + + /* wait drive is ready */ + + if (head == UPPER_HEAD) + swim_select(READ_DATA_1); + else if (head == LOWER_HEAD) + swim_select(READ_DATA_0); +} + +static inline int swim_step(void) +{ + int wait; + + swim_action(STEP); + + for (wait = 0; wait < 80; wait++) { + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + + if (!swim_readbit(STEPPING)) + return 0; + } + + return -1; +} + +static inline int swim_track00(void) +{ + int try; + + swim_motor(ON); + + swim_action(SEEK_NEGATIVE); + + for (try = 0; try < 100; try++) { + + if (swim_readbit(TRACK_ZERO)) + break; + + if (swim_step()) + return -1; + } + + if (swim_readbit(TRACK_ZERO)) + return 0; + + return -1; +} + +static inline int swim_seek(int step) +{ + if (step == 0) + return 0; + + swim_motor(ON); + + if (step < 0) { + swim_action(SEEK_NEGATIVE); + step = -step; + } else + swim_action(SEEK_POSITIVE); + + for ( ; step > 0; step--) { + if (swim_step()) + return -1; + } + + return 0; +} + +static inline int swim_track(struct floppy_state *fs, int track) +{ + int ret; + + ret = swim_seek(track - fs->track); + + if (ret == 0) + fs->track = track; + else { + swim_track00(); + fs->track = 0; + } + + return ret; +} + +static void setup_medium(struct floppy_state *fs) +{ + if (swim_readbit(DISK_IN)) { + fs->disk_in = 1; + fs->write_protected = swim_readbit(WRITE_PROT); + fs->type = swim_readbit(ONEMEG_MEDIA); + + if (swim_track00()) + printk(KERN_ERR + "SWIM: cannot move floppy head to track 0\n"); + + swim_track00(); + + fs->total_secs = 2880; + fs->secpercyl = 36; + fs->secpertrack = 18; + fs->track = 0; + } else { + fs->disk_in = 0; + } +} + +static int fd_eject(struct floppy_state *fs) +{ + swim_drive(fs->location); + swim_motor(OFF); + swim_eject(); + + fs->disk_in = 0; + fs->ejected = 1; + + return 0; +} + +int swim_fd_eject(int devnum) +{ + if (devnum >= floppy_count) + return -ENODEV; + return fd_eject(&floppy_states[devnum]); +} + + +static struct floppy_struct floppy_type = + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ + +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || + ((cmd & 0x80) && !suser())) + return -EPERM; + + fs = &floppy_states[devnum]; + + switch (cmd) { + case FDEJECT: + if (fs->ref_count != 1) + return -EBUSY; + err = fd_eject(fs); + return err; + + case FDGETPRM: + err = copy_to_user((void *) param, (void *) &floppy_type, + sizeof(struct floppy_struct)); + return err; + } + return -ENOIOCTLCMD; +} + +static int floppy_open(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + int err; + + if (devnum >= floppy_count) + return -ENODEV; + if (filp == 0) + return -EIO; + + fs = &floppy_states[devnum]; + + err = 0; + if (fs->ref_count == 0) { + swim_write(setup, S_IBM_DRIVE | S_FCLK_DIV2); + udelay(10); + swim_drive(INTERNAL_DRIVE); + swim_motor(ON); + swim_action(SETMFM); + if (fs->ejected) + setup_medium(fs); + if (!fs->disk_in) + err = -ENXIO; + } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL) + return -EBUSY; + + if (err == 0 && (filp->f_flags & O_NDELAY) == 0 + && (filp->f_mode & 3)) { + check_disk_change(inode->i_rdev); + if (!fs->disk_in) + err = -ENXIO; + } + + if (err == 0 && (filp->f_mode & 2)) { + fs->write_protected = swim_readbit(WRITE_PROT); + if (fs->write_protected) + err = -EROFS; + } + + if (err) { + if (fs->ref_count == 0) { + swim_motor(OFF); + } + return err; + } + + if (filp->f_flags & O_EXCL) + fs->ref_count = -1; + else + ++fs->ref_count; + + /* Allow ioctls if we have write-permissions even if read-only open */ + + if ((filp->f_mode & 2) || (permission(inode, 2) == 0)) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + return 0; +} + +static int floppy_release(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT))) + block_fsync (filp, filp->f_dentry); + + fs = &floppy_states[devnum]; + if (fs->ref_count > 0 && --fs->ref_count == 0) { + swim_motor(OFF); + } + + return 0; +} + +static int floppy_check_change(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + + return fs->ejected; +} + +static int floppy_revalidate(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + + swim_drive(fs->location); + + if (fs->ejected) + setup_medium(fs); + + if (!fs->disk_in) { + swim_motor(OFF); + } else { + fs->ejected = 0; + } + + return !fs->disk_in; +} + +#if defined(DUMP_MEM) +static void dump_mem(unsigned char* data, int size) +{ + int i,j; + + i = 0; + while (i < size) { + printk("%08x ", (unsigned int)(data + i)); + for (j = 0; (j < 16) && (i + j) < size; j++) { + printk("%02x ", data[i+j]); + } + for (j = 0; (j < 16) && (i + j) < size; j++) { + printk("%c", data[i+j]); + } + printk("\n"); + i += j; + } +} +#endif + +static inline int swim_read_sector(struct floppy_state *fs, + int side, int track, + int sector, unsigned char *buffer) +{ + unsigned long flags; + struct sector_header header; + int ret = -1; + short i; + + swim_track(fs, track); + + swim_write(mode1, MOTON); + swim_head(side); + swim_write(mode0, side); + + INT_OFF; + for (i = 0; i < 20000; i++) { + ret = swim_read_sector_header(&header); + if ( !ret && (header.sector == sector) ) { + + /* found */ + + ret = swim_read_sector_data(buffer); + break; + } + } + swim_write(mode0, MOTON); + INT_ON; + + if ( (header.side != side) || (header.track != track) || + (header.sector != sector) ) + return 0; + + return ret; +} + +static int floppy_read_sectors(struct floppy_state *fs, + int req_sector, int sectors_nb, + unsigned char* buffer) +{ + int ret; + int side; + int track; + int sector; + int i; + int try; + + swim_drive(fs->location); + for (i = req_sector; i < req_sector + sectors_nb; i++) { + int x; + + track = i / fs->secpercyl; + x = i % fs->secpercyl; + side = x / fs->secpertrack; + sector = x % fs->secpertrack + 1; + + try = 5; + do { + ret = swim_read_sector(fs, side, track, sector, + buffer); + if (try-- == 0) + return -1; + } while(ret != 512); + + buffer += ret; + } + + return 0; +} + +static void start_request(struct floppy_state *fs) +{ + while(CURRENT) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); + if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { + end_request(0); + continue; + } + if (CURRENT->current_nr_sectors == 0) { + end_request(1); + continue; + } + if (!fs->disk_in) { + end_request(0); + continue; + } + switch(CURRENT->cmd) { + case WRITE: + if (fs->write_protected) { + end_request(0); + continue; + } + /* NOT IMPLEMENTED */ + end_request(0); + break; + case READ: + if (floppy_read_sectors(fs, CURRENT->sector, + CURRENT->current_nr_sectors, + CURRENT->buffer)) { + end_request(0); + continue; + } + CURRENT->sector += CURRENT->current_nr_sectors; + CURRENT->buffer += CURRENT->current_nr_sectors * 512; + CURRENT->current_nr_sectors = 0; + end_request(1); + break; + default: + end_request(0); + } + } +} + +static void do_fd_request(void) +{ + int i; + for(i=0;if_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + fs = &floppy_states[devnum]; + if (!fs->disk_in) + return -ENXIO; + return block_read(filp, buf, count, ppos); +} + +static ssize_t floppy_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + check_disk_change(inode->i_rdev); + fs = &floppy_states[devnum]; + if (!fs->disk_in) + return -ENXIO; + if (fs->write_protected) + return -EROFS; + return block_write(filp, buf, count, ppos); +} + +static void floppy_off(unsigned int nr) +{ +} + +static struct file_operations floppy_fops = { + NULL, /* lseek */ + floppy_read, /* read */ + floppy_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + floppy_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + NULL, /* flush */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + floppy_check_change, /* check_media_change */ + floppy_revalidate, /* revalidate */ +}; + +static int swim_add_floppy(drive_location_t location) +{ + struct floppy_state *fs = &floppy_states[floppy_count]; + + fs->location = location; + + swim_drive(location); + + swim_motor(OFF); + + if (swim_readbit(SINGLE_SIDED)) { + printk(KERN_INFO "SWIM: drive is single sided\n"); + fs->head_number = 1; + } else + fs->head_number = 2; + + fs->ref_count = 0; + fs->ejected = 1; + + do_floppy = NULL; + + floppy_count++; + + return 0; +} + +int swim_floppy_init(void) +{ + if (SWIMBase == NULL) + return 0; + + printk(KERN_INFO "SWIM: %s by Laurent Vivier \n" + , DRIVER_VERSION); + + /* scan floppy drives */ + + swim_mode(1); + + swim_drive(INTERNAL_DRIVE); + if (swim_readbit(DRIVE_PRESENT)) { + printk("SWIM: internal floppy drive detected\n"); + swim_add_floppy(INTERNAL_DRIVE); + } + swim_drive(EXTERNAL_DRIVE); + if (swim_readbit(DRIVE_PRESENT)) { + printk("SWIM: external floppy drive detected\n"); + swim_add_floppy(EXTERNAL_DRIVE); + } + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk(KERN_ERR "Unable to get major %d for floppy\n", + MAJOR_NR); + return -EBUSY; + } + + /* by default, set size to HD floppy, we need a media to really know */ + + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + return 0; +} + +#ifdef MODULE +static void *base = NULL; + +int init_module(void) +{ + printk(KERN_INFO "Inserting SWIM floppy driver " UTS_RELEASE "\n"); + + if (base != NULL) { + printk(KERN_INFO "SWIM: Setting SWIMBase to 0x%p\n", base); + SWIMBase = base; + } + + return swim_floppy_init(); +} + +void cleanup_module(void) +{ + int i; + + printk(KERN_INFO "Removing SWIM floppy driver\n"); + + /* switch off motor(s) */ + + for (i = 0; i < floppy_count; i++) { + swim_drive(floppy_states[i].location); + swim_motor(OFF); + } + + /* unregister driver */ + + unregister_blkdev(MAJOR_NR, "fd"); + + blk_dev[MAJOR_NR].request_fn = 0; +} +MODULE_AUTHOR("Laurent Vivier"); +MODULE_SUPPORTED_DEVICE("fd"); +MODULE_PARM(base, "l"); +MODULE_PARM_DESC(base, "Base address of SWIM chip."); +MODULE_DESCRIPTION("Driver for SWIM (Sander. Woz Integrated Machine) floppy controller"); +#endif /* MODULE */ diff -uprN -X dontdiff linux-2.2.27-pre2.orig/drivers/block/swim_iop.c linux-2.2.27-pre2/drivers/block/swim_iop.c --- linux-2.2.27-pre2.orig/drivers/block/swim_iop.c 2004-09-02 10:27:56.000000000 +0200 +++ linux-2.2.27-pre2/drivers/block/swim_iop.c 2004-09-14 21:09:06.000000000 +0200 @@ -401,6 +401,14 @@ static int swimiop_eject(struct floppy_s return cmd->error ? -ENXIO : 0; } +int swimiop_fd_eject(int devnum) +{ + if (devnum >= floppy_count) + return -ENODEV; + + return swimiop_eject(&floppy_states[devnum]); +} + static ssize_t floppy_read(struct file *filp, char *buf, size_t count, loff_t *ppos) {