diff options
Diffstat (limited to 'arch/m68k/atari')
-rw-r--r-- | arch/m68k/atari/Makefile | 4 | ||||
-rw-r--r-- | arch/m68k/atari/ataints.c | 36 | ||||
-rw-r--r-- | arch/m68k/atari/atakeyb.c | 68 | ||||
-rw-r--r-- | arch/m68k/atari/atari_ksyms.c | 13 | ||||
-rw-r--r-- | arch/m68k/atari/atasound.c | 25 | ||||
-rw-r--r-- | arch/m68k/atari/config.c | 784 | ||||
-rw-r--r-- | arch/m68k/atari/debug.c | 359 | ||||
-rw-r--r-- | arch/m68k/atari/joystick.c | 13 | ||||
-rw-r--r-- | arch/m68k/atari/stdma.c | 4 | ||||
-rw-r--r-- | arch/m68k/atari/stram.c | 1577 | ||||
-rw-r--r-- | arch/m68k/atari/time.c | 415 |
11 files changed, 2438 insertions, 860 deletions
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 77d5c7c2b..dcd6170c6 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := atari.o -O_OBJS := config.o atakeyb.o ataints.o \ - stdma.o atasound.o joystick.o stram.o atafb.o +O_OBJS := config.o time.o debug.o atakeyb.o ataints.o stdma.o atasound.o \ + joystick.o stram.o OX_OBJS := atari_ksyms.o include $(TOPDIR)/Rules.make diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 189095cfc..61afbb50b 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -166,7 +166,7 @@ static int free_vme_vec_bitmap = 0; asmlinkage void IRQ_NAME(n); \ /* Dummy function to allow asm with operands. */ \ void atari_slow_irq_##n##_dummy (void) { \ -__asm__ (ALIGN_STR "\n" \ +__asm__ (__ALIGN_STR "\n" \ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ " addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \ SAVE_ALL_INT "\n" \ @@ -190,7 +190,7 @@ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ " jbra "SYMBOL_NAME_STR(ret_from_interrupt)"\n" \ - : : "i" (&kstat.interrupts[n+8]), "i" (&irq_handler[n+8]), \ + : : "i" (&kstat.irqs[0][n+8]), "i" (&irq_handler[n+8]), \ "n" (PT_OFF_SR), "n" (n), \ "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)) \ @@ -270,7 +270,7 @@ asmlinkage void atari_prio_irq_handler( void ); /* Dummy function to allow asm with operands. */ void atari_fast_prio_irq_dummy (void) { -__asm__ (ALIGN_STR "\n" +__asm__ (__ALIGN_STR "\n" SYMBOL_NAME_STR(atari_fast_irq_handler) ": orw #0x700,%%sr /* disable all interrupts */ "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t @@ -294,7 +294,7 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": addql #8,%%sp addql #4,%%sp jbra "SYMBOL_NAME_STR(ret_from_interrupt) - : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC) + : : "i" (&kstat.irqs), "n" (PT_OFF_FORMATVEC) ); } @@ -304,7 +304,7 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": */ asmlinkage void falcon_hblhandler(void); asm(".text\n" -ALIGN_STR "\n" +__ALIGN_STR "\n" SYMBOL_NAME_STR(falcon_hblhandler) ": orw #0x200,%sp@ /* set saved ipl to 2 */ rte"); @@ -314,6 +314,8 @@ asmlinkage void bad_interrupt(void); extern void atari_microwire_cmd( int cmd ); +extern int atari_SCC_reset_done; + /* * void atari_init_IRQ (void) * @@ -358,7 +360,7 @@ __initfunc(void atari_init_IRQ(void)) tt_mfp.int_mk_b = 0xff; } - if (ATARIHW_PRESENT(SCC)) { + if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { scc.cha_a_ctrl = 9; MFPDELAY(); scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ @@ -374,10 +376,13 @@ __initfunc(void atari_init_IRQ(void)) tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ } else { - /* If no SCU, the HSYNC interrupt needs to be disabled this - * way. (Else _inthandler in kernel/sys_call.S gets overruns) + /* If no SCU and no Hades, the HSYNC interrupt needs to be + * disabled this way. (Else _inthandler in kernel/sys_call.S + * gets overruns) */ - vectors[VEC_INT2] = falcon_hblhandler; + + if (!MACH_IS_HADES) + vectors[VEC_INT2] = falcon_hblhandler; } if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { @@ -414,7 +419,14 @@ int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r unsigned long flags, const char *devname, void *dev_id) { int vector; - + + /* + * The following is a hack to make some PCI card drivers work, + * which set the SA_SHIRQ flag. + */ + + flags &= ~SA_SHIRQ; + if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { printk ("%s: Bad irq type %ld requested from %s\n", __FUNCTION__, flags, devname); @@ -600,11 +612,11 @@ int atari_get_irq_list(char *buf) continue; if (i < STMFP_SOURCE_BASE) len += sprintf(buf+len, "auto %2d: %10u ", - i, kstat.interrupts[i]); + i, kstat.irqs[0][i]); else len += sprintf(buf+len, "vec $%02x: %10u ", IRQ_SOURCE_TO_VECTOR(i), - kstat.interrupts[i]); + kstat.irqs[0][i]); if (irq_handler[i].handler != atari_call_irq_list) { len += sprintf(buf+len, "%s\n", irq_param[i].devname); diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index e09743e79..bf792da5c 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -32,7 +32,6 @@ #include <asm/atari_joystick.h> #include <asm/irq.h> -extern int ovsc_switchmode; extern unsigned char mach_keyboard_type; static void atakeyb_rep( unsigned long ignore ); extern unsigned int keymap_count; @@ -504,23 +503,6 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) } } -#ifdef KEYB_WRITE_INTERRUPT - if (acia_stat & ACIA_TDRE) /* transmit of character is finished */ - { - if (kb_state.buf) - { - acia.key_data = *kb_state.buf++; - kb_state.len--; - if (kb_state.len == 0) - { - kb_state.buf = NULL; - if (!kb_state.kernel_mode) - /* unblock something */; - } - } - } -#endif - #if 0 if (acia_stat & ACIA_CTS) /* cannot happen */; @@ -537,26 +519,6 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) goto repeat; } -#ifdef KEYB_WRITE_INTERRUPT -void ikbd_write(const char *str, int len) -{ - u_char acia_stat; - - if (kb_stat.buf) - /* wait */; - acia_stat = acia.key_ctrl; - if (acia_stat & ACIA_TDRE) - { - if (len != 1) - { - kb_stat.buf = str + 1; - kb_stat.len = len - 1; - } - acia.key_data = *str; - /* poll */ - } -} -#else /* * I write to the keyboard without using interrupts, I poll instead. * This takes for the maximum length string allowed (7) at 7812.5 baud @@ -581,7 +543,6 @@ void ikbd_write(const char *str, int len) } } } -#endif /* Reset (without touching the clock) */ void ikbd_reset(void) @@ -828,33 +789,28 @@ __initfunc(int atari_keyb_init(void)) atari_turnoff_irq(IRQ_MFP_ACIA); do { - acia.key_ctrl = ACIA_RESET; /* reset ACIA */ + /* reset IKBD ACIA */ + acia.key_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; (void)acia.key_ctrl; (void)acia.key_data; - acia.mid_ctrl = ACIA_RESET; /* reset other ACIA */ + /* reset MIDI ACIA */ + acia.mid_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; (void)acia.mid_ctrl; (void)acia.mid_data; /* divide 500kHz by 64 gives 7812.5 baud */ /* 8 data no parity 1 start 1 stop bit */ /* receive interrupt enabled */ -#ifdef KEYB_WRITE_INTERRUPT - /* RTS low, transmit interrupt enabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTIE|ACIA_RIE); - /* switch on OverScan via keyboard ACIA */ - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTIE|ACIA_RIE); -#else - /* RTS low, transmit interrupt disabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTID|ACIA_RIE); -#endif + /* RTS low (except if switch selected), transmit interrupt disabled */ + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | + ((atari_switches & ATARI_SWITCH_IKBD) ? + ACIA_RHTID : ACIA_RLTID); - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S; + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; } /* make sure the interrupt line is up */ while ((mfp.par_dt_reg & 0x10) == 0); diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c index c2a9da86e..0eb19e4a0 100644 --- a/arch/m68k/atari/atari_ksyms.c +++ b/arch/m68k/atari/atari_ksyms.c @@ -1,4 +1,3 @@ -#include <linux/config.h> #include <linux/module.h> #include <asm/ptrace.h> #include <asm/traps.h> @@ -7,24 +6,32 @@ #include <asm/atarikb.h> #include <asm/atari_joystick.h> #include <asm/atari_stdma.h> +#include <asm/atari_stram.h> extern void atari_microwire_cmd( int cmd ); +extern int atari_MFP_init_done; +extern int atari_SCC_init_done; extern int atari_SCC_reset_done; EXPORT_SYMBOL(atari_mch_cookie); +EXPORT_SYMBOL(atari_mch_type); EXPORT_SYMBOL(atari_hw_present); -EXPORT_SYMBOL(is_medusa); -EXPORT_SYMBOL(is_hades); +EXPORT_SYMBOL(atari_switches); +EXPORT_SYMBOL(atari_dont_touch_floppy_select); EXPORT_SYMBOL(atari_register_vme_int); EXPORT_SYMBOL(atari_unregister_vme_int); EXPORT_SYMBOL(stdma_lock); EXPORT_SYMBOL(stdma_release); EXPORT_SYMBOL(stdma_others_waiting); EXPORT_SYMBOL(stdma_islocked); +EXPORT_SYMBOL(atari_stram_alloc); +EXPORT_SYMBOL(atari_stram_free); EXPORT_SYMBOL(atari_mouse_buttons); EXPORT_SYMBOL(atari_mouse_interrupt_hook); EXPORT_SYMBOL(atari_MIDI_interrupt_hook); +EXPORT_SYMBOL(atari_MFP_init_done); +EXPORT_SYMBOL(atari_SCC_init_done); EXPORT_SYMBOL(atari_SCC_reset_done); EXPORT_SYMBOL(ikbd_write); EXPORT_SYMBOL(ikbd_mouse_y0_top); diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c index 51f8b6823..6b03b96fd 100644 --- a/arch/m68k/atari/atasound.c +++ b/arch/m68k/atari/atasound.c @@ -1,17 +1,16 @@ /* -linux/arch/m68k/atari/atasound.c - -++Geert: Moved almost all stuff to linux/drivers/sound/ - -The author of atari_nosound, atari_mksound and atari_microwire_cmd is -unknown. -(++roman: That's me... :-) - -This file is subject to the terms and conditions of the GNU General Public -License. See the file COPYING in the main directory of this archive -for more details. - -*/ + * linux/arch/m68k/atari/atasound.c + * + * ++Geert: Moved almost all stuff to linux/drivers/sound/ + * + * The author of atari_nosound, atari_mksound and atari_microwire_cmd is + * unknown. (++roman: That's me... :-) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ #include <linux/sched.h> diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 3cc2a840a..9ea8a4fab 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -27,35 +27,33 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/mm.h> -#include <linux/mc146818rtc.h> -#include <linux/kd.h> -#include <linux/tty.h> #include <linux/console.h> -#include <linux/interrupt.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/atarihw.h> -#include <asm/atarihdreg.h> #include <asm/atariints.h> - +#include <asm/atari_stram.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/pgtable.h> #include <asm/machdep.h> -#ifdef CONFIG_KGDB -#include <asm/kgdb.h> -#endif - u_long atari_mch_cookie; +u_long atari_mch_type = 0; struct atari_hw_present atari_hw_present; +u_long atari_switches = 0; +int atari_dont_touch_floppy_select = 0; +int atari_rtc_year_offset; -extern char m68k_debug_device[]; +/* local function prototypes */ +static void atari_reset( void ); +#ifdef CONFIG_ATARI_FLOPPY +extern void atari_floppy_setup(char *, int *); +#endif +static void atari_get_model(char *model); +static int atari_get_hardware_list(char *buffer); -static void atari_sched_init(void (*)(int, void *, struct pt_regs *)); /* atari specific keyboard functions */ extern int atari_keyb_init(void); extern int atari_kbdrate (struct kbd_repeat *); @@ -68,33 +66,36 @@ extern void atari_free_irq (unsigned int irq, void *dev_id); extern void atari_enable_irq (unsigned int); extern void atari_disable_irq (unsigned int); extern int atari_get_irq_list (char *buf); -static void atari_get_model(char *model); -static int atari_get_hardware_list(char *buffer); -/* atari specific timer functions */ -static unsigned long atari_gettimeoffset (void); -static void atari_mste_gettod (int *, int *, int *, int *, int *, int *); -static void atari_gettod (int *, int *, int *, int *, int *, int *); -static int atari_mste_hwclk (int, struct hwclk_time *); -static int atari_hwclk (int, struct hwclk_time *); -static int atari_mste_set_clock_mmss (unsigned long); -static int atari_set_clock_mmss (unsigned long); extern void atari_mksound( unsigned int count, unsigned int ticks ); -static void atari_reset( void ); -#ifdef CONFIG_BLK_DEV_FD -extern int atari_floppy_init (void); -extern void atari_floppy_setup(char *, int *); +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ); #endif extern struct consw fb_con; -extern struct fb_info *atari_fb_init(long *); -static void atari_debug_init(void); -extern void atari_video_setup(char *, int *); - -static struct console atari_console_driver; - -/* Can be set somewhere, if a SCC master reset has already be done and should - * not be repeated; used by kgdb */ -int atari_SCC_reset_done = 0; +/* atari specific timer functions (in time.c) */ +extern void atari_sched_init(void (*)(int, void *, struct pt_regs *)); +extern unsigned long atari_gettimeoffset (void); +extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *); +extern void atari_tt_gettod (int *, int *, int *, int *, int *, int *); +extern int atari_mste_hwclk (int, struct hwclk_time *); +extern int atari_tt_hwclk (int, struct hwclk_time *); +extern int atari_mste_set_clock_mmss (unsigned long); +extern int atari_tt_set_clock_mmss (unsigned long); + +/* atari specific debug functions (in debug.c) */ +extern void atari_debug_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static char atari_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ + "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000()/*789456123" /* 0x60 - 0x6f */ + "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif extern void (*kd_mksound)(unsigned int, unsigned int); @@ -237,18 +238,62 @@ __initfunc(int atari_parse_bootinfo(const struct bi_record *record)) case BI_ATARI_MCH_COOKIE: atari_mch_cookie = *data; break; + case BI_ATARI_MCH_TYPE: + atari_mch_type = *data; + break; default: unknown = 1; } return(unknown); } + +/* Parse the Atari-specific switches= option. */ +__initfunc(void atari_switches_setup( const char *str, unsigned len )) +{ + char switches[len+1]; + char *p; + int ovsc_shift; + + /* copy string to local array, strtok works destructively... */ + strncpy( switches, str, len ); + switches[len] = 0; + atari_switches = 0; + + /* parse the options */ + for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) { + ovsc_shift = 0; + if (strncmp( p, "ov_", 3 ) == 0) { + p += 3; + ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; + } + + if (strcmp( p, "ikbd" ) == 0) { + /* RTS line of IKBD ACIA */ + atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; + } + else if (strcmp( p, "midi" ) == 0) { + /* RTS line of MIDI ACIA */ + atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + } + else if (strcmp( p, "snd6" ) == 0) { + atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; + } + else if (strcmp( p, "snd7" ) == 0) { + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } + } +} + + /* * Setup the Atari configuration info */ __initfunc(void config_atari(void)) { + unsigned short tos_version; + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); atari_debug_init(); @@ -267,22 +312,40 @@ __initfunc(void config_atari(void)) mach_get_irq_list = atari_get_irq_list; mach_gettimeoffset = atari_gettimeoffset; mach_reset = atari_reset; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = atari_floppy_init; +#ifdef CONFIG_ATARI_FLOPPY mach_floppy_setup = atari_floppy_setup; #endif conswitchp = &fb_con; - mach_fb_init = atari_fb_init; mach_max_dma_address = 0xffffff; - mach_video_setup = atari_video_setup; kd_mksound = atari_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 98; /* HELP */ + mach_sysrq_shift_state = 8; /* Alt */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = atari_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = atari_heartbeat; +#endif + /* Set switches as requested by the user */ + if (atari_switches & ATARI_SWITCH_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & ATARI_SWITCH_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | + ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); + } + /* ++bjoern: * Determine hardware present */ printk( "Atari hardware found: " ); - if (is_medusa || is_hades) { + if (MACH_IS_MEDUSA || MACH_IS_HADES) { /* There's no Atari video hardware on the Medusa, but all the * addresses below generate a DTACK so no bus error occurs! */ } @@ -324,12 +387,12 @@ __initfunc(void config_atari(void)) ATARIHW_SET(SCSI_DMA); printk( "TT_SCSI_DMA " ); } - if (!is_hades && hwreg_present( &st_dma.dma_hi )) { + if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { ATARIHW_SET(STND_DMA); printk( "STND_DMA " ); } - if (is_medusa || /* The ST-DMA address registers aren't readable - * on all Medusas, so the test below may fail */ + if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail */ (hwreg_present( &st_dma.dma_vhi ) && (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && @@ -346,11 +409,12 @@ __initfunc(void config_atari(void)) ATARIHW_SET(YM_2149); printk( "YM2149 " ); } - if (!is_medusa && !is_hades && hwreg_present( &tt_dmasnd.ctrl )) { + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &tt_dmasnd.ctrl )) { ATARIHW_SET(PCM_8BIT); printk( "PCM " ); } - if (!is_hades && hwreg_present( &codec.unused5 )) { + if (!MACH_IS_HADES && hwreg_present( &codec.unused5 )) { ATARIHW_SET(CODEC); printk( "CODEC " ); } @@ -364,7 +428,7 @@ __initfunc(void config_atari(void)) (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) #else - !is_medusa && !is_hades + !MACH_IS_MEDUSA && !MACH_IS_HADES #endif ) { ATARIHW_SET(SCC_DMA); @@ -378,7 +442,7 @@ __initfunc(void config_atari(void)) ATARIHW_SET( ST_ESCC ); printk( "ST_ESCC " ); } - if (is_hades) + if (MACH_IS_HADES) { ATARIHW_SET( VME ); printk( "VME " ); @@ -393,20 +457,22 @@ __initfunc(void config_atari(void)) ATARIHW_SET(ANALOG_JOY); printk( "ANALOG_JOY " ); } - if (!is_hades && hwreg_present( blitter.halftone )) { + if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { ATARIHW_SET(BLITTER); printk( "BLITTER " ); } - if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) { + if (hwreg_present((void *)0xfff00039)) { ATARIHW_SET(IDE); printk( "IDE " ); } #if 1 /* This maybe wrong */ - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &tt_microwire.data ) && hwreg_present( &tt_microwire.mask ) && (tt_microwire.mask = 0x7ff, + udelay(1), tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + udelay(1), tt_microwire.data != 0)) { ATARIHW_SET(MICROWIRE); while (tt_microwire.mask != 0x7ff) ; @@ -416,24 +482,24 @@ __initfunc(void config_atari(void)) if (hwreg_present( &tt_rtc.regsel )) { ATARIHW_SET(TT_CLK); printk( "TT_CLK " ); - mach_gettod = atari_gettod; - mach_hwclk = atari_hwclk; - mach_set_clock_mmss = atari_set_clock_mmss; + mach_gettod = atari_tt_gettod; + mach_hwclk = atari_tt_hwclk; + mach_set_clock_mmss = atari_tt_set_clock_mmss; } - if (!is_hades && hwreg_present( &mste_rtc.sec_ones)) { + if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { ATARIHW_SET(MSTE_CLK); printk( "MSTE_CLK "); mach_gettod = atari_mste_gettod; mach_hwclk = atari_mste_hwclk; mach_set_clock_mmss = atari_mste_set_clock_mmss; } - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &dma_wd.fdc_speed ) && hwreg_write( &dma_wd.fdc_speed, 0 )) { ATARIHW_SET(FDCSPEED); printk( "FDC_SPEED "); } - if (!is_hades && !ATARIHW_PRESENT(ST_SCSI)) { + if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { ATARIHW_SET(ACSI); printk( "ACSI " ); } @@ -491,153 +557,24 @@ __initfunc(void config_atari(void)) : "d0" ); } -} - -__initfunc(static void -atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) -{ - /* set Timer C data Register */ - mfp.tim_dt_c = INT_TICKS; - /* start timer C, div = 1:100 */ - mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; - /* install interrupt service routine for MFP Timer C */ - request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, - "timer", timer_routine); -} - -/* ++andreas: gettimeoffset fixed to check for pending interrupt */ -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ -static unsigned long atari_gettimeoffset (void) -{ - unsigned long ticks, offset = 0; - - /* read MFP timer C current value */ - ticks = mfp.tim_dt_c; - /* The probability of underflow is less than 2% */ - if (ticks > INT_TICKS - INT_TICKS / 50) - /* Check for pending timer interrupt */ - if (mfp.int_pn_b & (1 << 5)) - offset = TICK_SIZE; - - ticks = INT_TICKS - ticks; - ticks = ticks * 10000L / INT_TICKS; - - return ticks + offset; -} - - -static void -mste_read(struct MSTE_RTC *val) -{ -#define COPY(v) val->v=(mste_rtc.v & 0xf) - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from reading the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -static void -mste_write(struct MSTE_RTC *val) -{ -#define COPY(v) mste_rtc.v=val->v - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from writing the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -#define RTC_READ(reg) \ - ({ unsigned char __val; \ - outb(reg,&tt_rtc.regsel); \ - __val = tt_rtc.data; \ - __val; \ - }) - -#define RTC_WRITE(reg,val) \ - do { \ - outb(reg,&tt_rtc.regsel); \ - tt_rtc.data = (val); \ - } while(0) - - -static void atari_mste_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - int hr24=0, hour; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - mste_read(&val); - *secp = val.sec_ones + val.sec_tens * 10; - *minp = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - *hourp = hour; - *dayp = val.day_ones + val.day_tens * 10; - *monp = val.mon_ones + val.mon_tens * 10; - *yearp = val.year_ones + val.year_tens * 10 + 80; -} - - -static void atari_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - unsigned char ctrl; - unsigned short tos_version; - int hour, pm; - - while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; - while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; - - *secp = RTC_READ(RTC_SECONDS); - *minp = RTC_READ(RTC_MINUTES); - hour = RTC_READ(RTC_HOURS); - *dayp = RTC_READ(RTC_DAY_OF_MONTH); - *monp = RTC_READ(RTC_MONTH); - *yearp = RTC_READ(RTC_YEAR); - pm = hour & 0x80; - hour &= ~0x80; - - ctrl = RTC_READ(RTC_CONTROL); + /* + * On the Hades map the PCI memory, I/O and configuration areas + * (0x80000000 - 0xbfffffff). + * + * Settings: supervisor only, non-cacheable, serialized, read and write. + */ - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(*secp); - BCD_TO_BIN(*minp); - BCD_TO_BIN(hour); - BCD_TO_BIN(*dayp); - BCD_TO_BIN(*monp); - BCD_TO_BIN(*yearp); - } - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; + if (MACH_IS_HADES) { + __asm__ __volatile__ ("movel %0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" + : /* no outputs */ + : "g" (0x803fa040) + : "d0"); } - *hourp = hour; - - /* Adjust values (let the setup valid) */ /* Fetch tos version at Physical 2 */ /* We my not be able to access this address if the kernel is @@ -647,403 +584,29 @@ static void atari_gettod (int *yearp, int *monp, int *dayp, we use the fact that in head.S we have set up a mapping 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible in the last 16MB of the address space. */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xFF000002; - *yearp += (tos_version < 0x306) ? 70 : 68; -} - -#define HWCLK_POLL_INTERVAL 5 - -static int atari_mste_hwclk( int op, struct hwclk_time *t ) -{ - int hour, year; - int hr24=0; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - if (op) { - /* write: prepare values */ - - val.sec_ones = t->sec % 10; - val.sec_tens = t->sec / 10; - val.min_ones = t->min % 10; - val.min_tens = t->min / 10; - hour = t->hour; - if (!hr24) { - if (hour > 11) - hour += 20 - 12; - if (hour == 0 || hour == 20) - hour += 12; - } - val.hr_ones = hour % 10; - val.hr_tens = hour / 10; - val.day_ones = t->day % 10; - val.day_tens = t->day / 10; - val.mon_ones = (t->mon+1) % 10; - val.mon_tens = (t->mon+1) / 10; - year = t->year - 80; - val.year_ones = year % 10; - val.year_tens = year / 10; - val.weekday = t->wday; - mste_write(&val); - mste_rtc.mode=(mste_rtc.mode | 1); - val.year_ones = (year % 4); /* leap year register */ - mste_rtc.mode=(mste_rtc.mode & ~1); - } - else { - mste_read(&val); - t->sec = val.sec_ones + val.sec_tens * 10; - t->min = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - t->hour = hour; - t->day = val.day_ones + val.day_tens * 10; - t->mon = val.mon_ones + val.mon_tens * 10 - 1; - t->year = val.year_ones + val.year_tens * 10 + 80; - t->wday = val.weekday; - } - return 0; + tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? + 0xfff : *(unsigned short *)0xff000002; + atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; } -static int atari_hwclk( int op, struct hwclk_time *t ) +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ) { - int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; - unsigned long flags; - unsigned short tos_version; - unsigned char ctrl; - int pm = 0; - - /* Tos version at Physical 2. See above for explanation why we - cannot use PTOV(2). */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xff000002; - - ctrl = RTC_READ(RTC_CONTROL); /* control registers are - * independent from the UIP */ + unsigned char tmp; + unsigned long flags; - if (op) { - /* write: prepare values */ - - sec = t->sec; - min = t->min; - hour = t->hour; - day = t->day; - mon = t->mon + 1; - year = t->year - ((tos_version < 0x306) ? 70 : 68); - wday = t->wday + (t->wday >= 0); - - if (!(ctrl & RTC_24H)) { - if (hour > 11) { - pm = 0x80; - if (hour != 12) - hour -= 12; - } - else if (hour == 0) - hour = 12; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hour); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(year); - if (wday >= 0) BIN_TO_BCD(wday); - } - } + if (atari_dont_touch_floppy_select) + return; - /* Reading/writing the clock registers is a bit critical due to - * the regular update cycle of the RTC. While an update is in - * progress, registers 0..9 shouldn't be touched. - * The problem is solved like that: If an update is currently in - * progress (the UIP bit is set), the process sleeps for a while - * (50ms). This really should be enough, since the update cycle - * normally needs 2 ms. - * If the UIP bit reads as 0, we have at least 244 usecs until the - * update starts. This should be enough... But to be sure, - * additionally the RTC_SET bit is set to prevent an update cycle. - */ - - while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HWCLK_POLL_INTERVAL; - schedule(); - } - save_flags(flags); cli(); - RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); - if (!op) { - sec = RTC_READ( RTC_SECONDS ); - min = RTC_READ( RTC_MINUTES ); - hour = RTC_READ( RTC_HOURS ); - day = RTC_READ( RTC_DAY_OF_MONTH ); - mon = RTC_READ( RTC_MONTH ); - year = RTC_READ( RTC_YEAR ); - wday = RTC_READ( RTC_DAY_OF_WEEK ); - } - else { - RTC_WRITE( RTC_SECONDS, sec ); - RTC_WRITE( RTC_MINUTES, min ); - RTC_WRITE( RTC_HOURS, hour + pm); - RTC_WRITE( RTC_DAY_OF_MONTH, day ); - RTC_WRITE( RTC_MONTH, mon ); - RTC_WRITE( RTC_YEAR, year ); - if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); - } - RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); - restore_flags(flags); - - if (!op) { - /* read: adjust values */ - - if (hour & 0x80) { - hour &= ~0x80; - pm = 1; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - BCD_TO_BIN(wday); - } - - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; - } - - t->sec = sec; - t->min = min; - t->hour = hour; - t->day = day; - t->mon = mon - 1; - t->year = year + ((tos_version < 0x306) ? 70 : 68); - t->wday = wday - 1; - } - - return( 0 ); -} - - -static int atari_mste_set_clock_mmss (unsigned long nowtime) -{ - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - struct MSTE_RTC val; - unsigned char rtc_minutes; - - mste_read(&val); - rtc_minutes= val.min_ones + val.min_tens * 10; - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - val.sec_ones = real_seconds % 10; - val.sec_tens = real_seconds / 10; - val.min_ones = real_minutes % 10; - val.min_tens = real_minutes / 10; - mste_write(&val); - } - else - return -1; - return 0; -} - -static int atari_set_clock_mmss (unsigned long nowtime) -{ - int retval = 0; - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - unsigned char save_control, save_freq_select, rtc_minutes; - - save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ - RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); - - save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); - - rtc_minutes = RTC_READ (RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY)) - BCD_TO_BIN (rtc_minutes); - - /* Since we're only adjusting minutes and seconds, don't interfere - with hour overflow. This avoids messing with unknown time zones - but requires your RTC not to be off by more than 30 minutes. */ - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - if (!(save_control & RTC_DM_BINARY)) - { - BIN_TO_BCD (real_seconds); - BIN_TO_BCD (real_minutes); - } - RTC_WRITE (RTC_SECONDS, real_seconds); - RTC_WRITE (RTC_MINUTES, real_minutes); - } - else - retval = -1; - - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); - RTC_WRITE (RTC_CONTROL, save_control); - return retval; -} - -static inline void ata_mfp_out (char c) -{ - while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ - barrier (); - mfp.usart_dta = c; -} - -static void atari_mfp_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_mfp_out( '\r' ); - ata_mfp_out( *str++ ); - } -} - -static inline void ata_scc_out (char c) -{ - do { - MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - MFPDELAY(); - scc.cha_b_data = c; -} - -static void atari_scc_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_scc_out( '\r' ); - ata_scc_out( *str++ ); - } -} - -static int ata_par_out (char c) -{ - extern unsigned long loops_per_sec; - unsigned char tmp; - /* This a some-seconds timeout in case no printer is connected */ - unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; - - while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ - ; - if (!i) return( 0 ); - - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = c; /* put char onto port */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ - MFPDELAY(); /* wait a bit */ - sound_ym.wd_data = tmp | 0x20; /* set strobe H */ - return( 1 ); -} - -static void atari_par_console_write (const char *str, unsigned int count) -{ - static int printer_present = 1; - - if (!printer_present) - return; - - while (count--) { - if (*str == '\n') - if (!ata_par_out( '\r' )) { - printer_present = 0; - return; - } - if (!ata_par_out( *str++ )) { - printer_present = 0; - return; - } - } + sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); + restore_flags(flags); } - - -__initfunc(static void atari_debug_init(void)) -{ -#ifdef CONFIG_KGDB - /* if the m68k_debug_device is used by the GDB stub, do nothing here */ - if (kgdb_initialized) - return(NULL); #endif - if (!strcmp( m68k_debug_device, "ser" )) { - /* defaults to ser2 for a Falcon and ser1 otherwise */ - strcpy( m68k_debug_device, - ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON) ? - "ser2" : "ser1" ); - - } - - if (!strcmp( m68k_debug_device, "ser1" )) { - /* ST-MFP Modem1 serial port */ - mfp.trn_stat &= ~0x01; /* disable TX */ - mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */ - mfp.tim_ct_cd &= 0x70; /* stop timer D */ - mfp.tim_dt_d = 2; /* 9600 bps */ - mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ - mfp.trn_stat |= 0x01; /* enable TX */ - atari_console_driver.write = atari_mfp_console_write; - } - else if (!strcmp( m68k_debug_device, "ser2" )) { - /* SCC Modem2 serial port */ - static unsigned char *p, scc_table[] = { - 9, 12, /* Reset */ - 4, 0x44, /* x16, 1 stopbit, no parity */ - 3, 0xc0, /* receiver: 8 bpc */ - 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */ - 9, 0, /* no interrupts */ - 10, 0, /* NRZ */ - 11, 0x50, /* use baud rate generator */ - 12, 24, 13, 0, /* 9600 baud */ - 14, 2, 14, 3, /* use master clock for BRG, enable */ - 3, 0xc1, /* enable receiver */ - 5, 0xea, /* enable transmitter */ - 0 - }; - - (void)scc.cha_b_ctrl; /* reset reg pointer */ - for( p = scc_table; *p != 0; ) { - scc.cha_b_ctrl = *p++; - MFPDELAY(); - scc.cha_b_ctrl = *p++; - MFPDELAY(); - } - atari_console_driver.write = atari_scc_console_write; - } - else if (!strcmp( m68k_debug_device, "par" )) { - /* parallel printer */ - atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ - sound_ym.rd_data_reg_sel = 7; /* select mixer control */ - sound_ym.wd_data = 0xff; /* sound off, ports are output */ - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = 0; /* no char */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ - atari_console_driver.write = atari_par_console_write; - } - if (atari_console_driver.write) - register_console(&atari_console_driver); -} - /* ++roman: * * This function does a reset on machines that lack the ability to @@ -1082,11 +645,16 @@ static void atari_reset (void) /* On the Medusa, phys. 0x4 may contain garbage because it's no ROM. See above for explanation why we cannot use PTOV(4). */ - reset_addr = is_hades ? 0x7fe00030 : - (is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004); - - acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */ - + reset_addr = MACH_IS_HADES ? 0x7fe00030 : + MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : + *(unsigned long *) 0xff000004; + + /* reset ACIA for switch off OverScan, if it's active */ + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_RESET; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_RESET; + /* processor independent: turn off interrupts and reset the VBR; * the caches must be left enabled, else prefetching the final jump * instruction doesn't work. */ @@ -1126,8 +694,21 @@ static void atari_reset (void) "nop\n\t" ".chip 68040\n\t" "cinva %%bc\n\t" + "nop\n\t" "pflusha\n\t" + "nop\n\t" "movec %%d0,%%tc\n\t" + "nop\n\t" + /* the following setup of transparent translations is needed on the + * Afterburner040 to successfully reboot. Other machines shouldn't + * care about a different tt regs setup, they also didn't care in + * the past that the regs weren't turned off. */ + "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%itt1\n\t" + "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ + "movec %%d0,%%dtt0\n\t" + "movec %%d0,%%dtt1\n\t" ".chip 68k\n\t" "jmp %0@" : /* no outputs */ @@ -1154,22 +735,24 @@ static void atari_get_model(char *model) strcat (model, "ST"); break; case ATARI_MCH_STE: - if ((atari_mch_cookie & 0xffff) == 0x10) + if (MACH_IS_MSTE) strcat (model, "Mega STE"); else strcat (model, "STE"); break; case ATARI_MCH_TT: - if (is_medusa) + if (MACH_IS_MEDUSA) /* Medusa has TT _MCH cookie */ strcat (model, "Medusa"); - else if (is_hades) + else if (MACH_IS_HADES) strcat(model, "Hades"); else strcat (model, "TT"); break; case ATARI_MCH_FALCON: strcat (model, "Falcon"); + if (MACH_IS_AB40) + strcat (model, " (with Afterburner040)"); break; default: sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", @@ -1225,3 +808,10 @@ static int atari_get_hardware_list(char *buffer) return(len); } + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c new file mode 100644 index 000000000..249e8208b --- /dev/null +++ b/arch/m68k/atari/debug.c @@ -0,0 +1,359 @@ +/* + * linux/arch/m68k/atari/debug.c + * + * Atari debugging and serial console stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/delay.h> + +#include <asm/atarihw.h> +#include <asm/atariints.h> + +extern char m68k_debug_device[]; + +/* Flag that Modem1 port is already initialized and used */ +int atari_MFP_init_done = 0; +/* Flag that Modem1 port is already initialized and used */ +int atari_SCC_init_done = 0; +/* Can be set somewhere, if a SCC master reset has already be done and should + * not be repeated; used by kgdb */ +int atari_SCC_reset_done = 0; + +static struct console atari_console_driver = { + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + NULL, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +static inline void ata_mfp_out (char c) +{ + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier (); + mfp.usart_dta = c; +} + +void atari_mfp_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_mfp_out( '\r' ); + ata_mfp_out( *str++ ); + } +} + +static inline void ata_scc_out (char c) +{ + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); + scc.cha_b_data = c; +} + +void atari_scc_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_scc_out( '\r' ); + ata_scc_out( *str++ ); + } +} + +static inline void ata_midi_out (char c) +{ + while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ + barrier (); + acia.mid_data = c; +} + +void atari_midi_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_midi_out( '\r' ); + ata_midi_out( *str++ ); + } +} + +static int ata_par_out (char c) +{ + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; + + while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ + ; + if (!i) return( 0 ); + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return( 1 ); +} + +static void atari_par_console_write (struct console *co, const char *str, + unsigned int count) +{ + static int printer_present = 1; + + if (!printer_present) + return; + + while (count--) { + if (*str == '\n') + if (!ata_par_out( '\r' )) { + printer_present = 0; + return; + } + if (!ata_par_out( *str++ )) { + printer_present = 0; + return; + } + } +} + +#ifdef CONFIG_SERIAL_CONSOLE +int atari_mfp_console_wait_key(struct console *co) +{ + while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ + barrier(); + return( mfp.usart_dta ); +} + +int atari_scc_console_wait_key(struct console *co) +{ + do { + MFPDELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + MFPDELAY(); + return( scc.cha_b_data ); +} + +int atari_midi_console_wait_key(struct console *co) +{ + while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ + barrier(); + return( acia.mid_data ); +} +#endif + +/* The following two functions do a quick'n'dirty initialization of the MFP or + * SCC serial ports. They're used by the debugging interface, kgdb, and the + * serial console code. */ +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_mfp_port( int cflag )) +#else +void atari_init_mfp_port( int cflag ) +#endif +{ + /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 + * bps, resp., and work only correct if there's a RSVE or RSSPEED */ + static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; + int baud = cflag & CBAUD; + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; + int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* baud_table[] starts at 1200bps */ + + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = baud_table[baud]; + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + + atari_MFP_init_done = 1; +} + +#define SCC_WRITE(reg,val) \ + do { \ + scc.cha_b_ctrl = (reg); \ + MFPDELAY(); \ + scc.cha_b_ctrl = (val); \ + MFPDELAY(); \ + } while(0) + +/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a + * delay of ~ 60us. */ +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 100; i > 0; --i ) \ + MFPDELAY(); \ + } while(0) + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_scc_port( int cflag )) +#else +void atari_init_scc_port( int cflag ) +#endif +{ + extern int atari_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { + /* special treatment for TT, where rates >= 38400 are done via TRxC */ + clksrc = 0x28; /* TRxC */ + clkmode = baud == 6 ? 0xc0 : + baud == 7 ? 0x80 : /* really 76800bps */ + 0x40; /* really 153600bps */ + div = 0; + } + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + atari_SCC_reset_done = 1; + atari_SCC_init_done = 1; +} + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_midi_port( int cflag )) +#else +void atari_init_midi_port( int cflag ) +#endif +{ + int baud = cflag & CBAUD; + int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; + /* warning 7N1 isn't possible! (instead 7O2 is used...) */ + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; + int div; + + /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as + * default) the standard MIDI speed 31250. */ + if (cflag & CBAUDEX) + baud += B38400; + if (baud == B4800) + div = ACIA_DIV64; /* really 7812.5 bps */ + else if (baud == B38400+2 /* 115200 */) + div = ACIA_DIV1; /* really 500 kbps (does that work??) */ + else + div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + + /* RTS low, ints disabled */ + acia.mid_ctrl = div | csize | parity | + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : ACIA_RLTID); +} + +__initfunc(void atari_debug_init(void)) +{ +#ifdef CONFIG_KGDB + /* the m68k_debug_device is used by the GDB stub, do nothing here */ + return; +#endif + if (!strcmp( m68k_debug_device, "ser" )) { + /* defaults to ser2 for a Falcon and ser1 otherwise */ + strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); + + } + + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port( B9600|CS8 ); + atari_console_driver.write = atari_mfp_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + atari_init_scc_port( B9600|CS8 ); + atari_console_driver.write = atari_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "midi" )) { + /* MIDI port */ + atari_init_midi_port( B9600|CS8 ); + atari_console_driver.write = atari_midi_console_write; + } + else if (!strcmp( m68k_debug_device, "par" )) { + /* parallel printer */ + atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + atari_console_driver.write = atari_par_console_write; + } + if (atari_console_driver.write) + register_console(&atari_console_driver); +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c index 2e33b151f..82eb85288 100644 --- a/arch/m68k/atari/joystick.c +++ b/arch/m68k/atari/joystick.c @@ -82,15 +82,16 @@ static int open_joystick(struct inode *inode, struct file *file) return 0; } -static long write_joystick(struct inode *inode, struct file *file, - const char *buffer, unsigned long count) +static ssize_t write_joystick(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; } -static long read_joystick(struct inode *inode, struct file *file, - char *buffer, unsigned long count) +static ssize_t read_joystick(struct file *file, char *buffer, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int minor = DEVICE_NR(inode->i_rdev); if (count < 2) @@ -109,9 +110,9 @@ static long read_joystick(struct inode *inode, struct file *file, static unsigned int joystick_poll(struct file *file, poll_table *wait) { - int minor = DEVICE_NR(file->f_inode->i_rdev); + int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev); - poll_wait(&joystick[minor].wait, wait); + poll_wait(file, &joystick[minor].wait, wait); if (joystick[minor].ready) return POLLIN | POLLRDNORM; return 0; diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 9dc82de18..5e2090f8f 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -1,6 +1,5 @@ - /* - * linux/atari/stmda.c + * linux/arch/m68k/atari/stmda.c * * Copyright (C) 1994 Roman Hodek * @@ -37,7 +36,6 @@ #include <asm/atari_stdma.h> #include <asm/atariints.h> #include <asm/atarihw.h> -#include <asm/atarihdreg.h> #include <asm/io.h> #include <asm/irq.h> diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index 4e5f57bc9..de9a96d03 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -1,157 +1,56 @@ +/* + * arch/m68k/atari/stram.c: Functions for ST-RAM allocations + * + * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/init.h> +#include <linux/swap.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/pagemap.h> #include <asm/setup.h> -#include <asm/atarihw.h> +#include <asm/machdep.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/atarihw.h> +#include <asm/atari_stram.h> -#if 0 - -struct stram_desc - { - unsigned first:1; - unsigned last:1; - unsigned alloced:1; - unsigned length:24; - }; - -#define DP(ptr) ((struct stram_desc *) (ptr)) - -static unsigned long stramsize; -static unsigned long stramaddr; - -void -atari_stram_init (void) -{ - struct stram_desc *dp; - stramaddr = atari_stram_start; - stramsize = atari_stram_size; - - /* initialize start boundary */ - dp = DP (stramaddr); - dp->first = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); - - /* initialize end boundary */ - dp = DP (stramaddr + stramsize) - 1; - dp->last = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); -#ifdef DEBUG - printk ("stram end boundary is %p, length is %d\n", dp, - dp->length); +#ifdef CONFIG_STRAM_SWAP +#define MAJOR_NR Z2RAM_MAJOR +#include <linux/blk.h> +#undef DEVICE_NAME +#define DEVICE_NAME "stram" #endif -} -void * -atari_stram_alloc (long size) -{ - /* last chunk */ - struct stram_desc *dp; - void *ptr; - - /* round off */ - size = (size + 3) & ~3; +#undef DEBUG #ifdef DEBUG - printk ("stram_alloc: allocate %ld bytes\n", size); -#endif - - /* - * get pointer to descriptor for last chunk by - * going backwards from end chunk - */ - dp = DP (stramaddr + stramsize) - 1; - dp = DP ((unsigned long) dp - dp->length) - 1; - - while ((dp->alloced || dp->length < size) && !dp->first) - dp = DP ((unsigned long) dp - dp[-1].length) - 2; - - if (dp->alloced || dp->length < size) - { - printk ("no stram available for %ld allocation\n", size); - return NULL; - } - - if (dp->length < size + 2 * sizeof (*dp)) - { - /* length too small to split; allocate the whole thing */ - dp->alloced = 1; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + dp->length); - dp->alloced = 1; -#ifdef DEBUG - printk ("stram_alloc: no split\n"); +#define DPRINTK(fmt,args...) printk( fmt, ##args ) +#else +#define DPRINTK(fmt,args...) #endif - } - else - { - /* split the extent; use the end part */ - long newsize = dp->length - (2 * sizeof (*dp) + size); - -#ifdef DEBUG - printk ("stram_alloc: splitting %d to %ld\n", dp->length, - newsize); -#endif - dp->length = newsize; - dp = DP ((unsigned long) (dp + 1) + newsize); - dp->first = dp->last = 0; - dp->alloced = 0; - dp->length = newsize; - dp++; - dp->first = dp->last = 0; - dp->alloced = 1; - dp->length = size; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + size); - dp->alloced = 1; - dp->length = size; - } -#ifdef DEBUG - printk ("stram_alloc: returning %p\n", ptr); +#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC) +/* abbrev for the && above... */ +#define DO_PROC +#include <linux/proc_fs.h> #endif - return ptr; -} - -void -atari_stram_free (void *ptr) -{ - struct stram_desc *sdp = DP (ptr) - 1, *dp2; - struct stram_desc *edp = DP ((unsigned long) ptr + sdp->length); - - /* deallocate the chunk */ - sdp->alloced = edp->alloced = 0; - /* check if we should merge with the previous chunk */ - if (!sdp->first && !sdp[-1].alloced) - { - dp2 = DP ((unsigned long) sdp - sdp[-1].length) - 2; - dp2->length += sdp->length + 2 * sizeof (*sdp); - edp->length = dp2->length; - sdp = dp2; - } - - /* check if we should merge with the following chunk */ - if (!edp->last && !edp[1].alloced) - { - dp2 = DP ((unsigned long) edp + edp[1].length) + 2; - dp2->length += edp->length + 2 * sizeof (*sdp); - sdp->length = dp2->length; - edp = dp2; - } -} - -#else - -#include <linux/mm.h> -#include <linux/init.h> - -/* ++roman: +/* Pre-swapping comments: + * + * ++roman: * * New version of ST-Ram buffer allocation. Instead of using the * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000 @@ -173,72 +72,1414 @@ atari_stram_free (void *ptr) * no provision now for freeing ST-Ram buffers. It seems that isn't * really needed. * - * ToDo: - * Check the high level scsi code what is done when the - * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr - * < 16 Mega. There should be call to atari_stram_alloc() instead. + */ + +/* + * New Nov 1997: Use ST-RAM as swap space! + * + * In the past, there were often problems with modules that require ST-RAM + * buffers. Such drivers have to use __get_dma_pages(), which unfortunately + * often isn't very successful in allocating more than 1 page :-( [1] The net + * result was that most of the time you couldn't insmod such modules (ataflop, + * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm, + * which needs a 1 MB buffer... :-). * - * Also ToDo: - * Go through head.S and delete parts no longer needed (transparent - * mapping of ST-Ram etc.) + * To overcome this limitation, ST-RAM can now be turned into a very + * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel + * now tries to unswap some pages on that swap device to make some free (and + * contiguous) space. This works much better in comparison to + * __get_dma_pages(), since used swap pages can be selectively freed by either + * moving them to somewhere else in swap space, or by reading them back into + * system memory. Ok, there operation of unswapping isn't really cheap (for + * each page, one has to go through the page tables of all processes), but it + * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a + * module that needs ST-RAM). But it at least makes it possible to load such + * modules! + * + * It could also be that overall system performance increases a bit due to + * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or + * executing code in. It's then just a (very fast, compared to disk) back + * storage for not-so-often needed data. (But this effect must be compared + * with the loss of total memory...) Don't know if the effect is already + * visible on a TT, where the speed difference between ST- and TT-RAM isn't + * that dramatic, but it should on machines where TT-RAM is really much faster + * (e.g. Afterburner). * + * [1]: __get_free_pages() does a fine job if you only want one page, but if + * you want more (contiguous) pages, it can give you such a block only if + * there's already a free one. The algorithm can't try to free buffers or swap + * out something in order to make more free space, since all that page-freeing + * mechanisms work "target-less", i.e. they just free something, but not in a + * specific place. I.e., __get_free_pages() can't do anything to free + * *adjacent* pages :-( This situation becomes even worse for DMA memory, + * since the freeing algorithms are also blind to DMA capability of pages. + */ + +#ifdef CONFIG_STRAM_SWAP +#define ALIGN_IF_SWAP(x) PAGE_ALIGN(x) +#else +#define ALIGN_IF_SWAP(x) (x) +#endif + +/* map entry for reserved swap page (used as buffer) */ +#define SWP_RSVD 0x80 + +/* get index of swap page at address 'addr' */ +#define SWAP_NR(addr) (((unsigned long)(addr)-swap_start) >> PAGE_SHIFT) + +/* get address of swap page #'nr' */ +#define SWAP_ADDR(nr) ((void *)(swap_start + ((nr)<<PAGE_SHIFT))) + +/* get number of pages for 'n' bytes (already page-aligned) */ +#define N_PAGES(n) ((n) >> PAGE_SHIFT) + +/* The following two numbers define the maximum fraction of ST-RAM in total + * memory, below that the kernel would automatically use ST-RAM as swap + * space. This decision can be overriden with stram_swap= */ +#define MAX_STRAM_FRACTION_NOM 1 +#define MAX_STRAM_FRACTION_DENOM 3 + +/* Start and end of the (pre-mem_init) reserved ST-RAM region */ +static unsigned long rsvd_stram_beg, rsvd_stram_end; + +/* Start and end (virtual) of ST-RAM */ +static unsigned long stram_start, stram_end; + +/* set after memory_init() executed and allocations via start_mem aren't + * possible anymore */ +static int mem_init_done = 0; + +/* set if kernel is in ST-RAM */ +static int kernel_in_stram; + +typedef struct stram_block { + struct stram_block *next; + unsigned long start; + unsigned long size; + unsigned flags; + const char *owner; +} BLOCK; + +/* values for flags field */ +#define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ +#define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ +#define BLOCK_STATIC 0x04 /* pre-mem_init() allocated block */ +#define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ +#define BLOCK_INSWAP 0x10 /* block allocated in swap space */ + +/* list of allocated blocks */ +static BLOCK *alloc_list = NULL; + +/* We can't always use kmalloc() to allocate BLOCK structures, since + * stram_alloc() can be called rather early. So we need some pool of + * statically allocated structures. 20 of them is more than enough, so in most + * cases we never should need to call kmalloc(). */ +#define N_STATIC_BLOCKS 20 +static BLOCK static_blocks[N_STATIC_BLOCKS]; + +#ifdef CONFIG_STRAM_SWAP +/* max. number of bytes to use for swapping + * 0 = no ST-RAM swapping + * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of + * total memory */ - +static int max_swap_size = -1; -unsigned long rsvd_stram_beg, rsvd_stram_end; - /* Start and end of the reserved ST-Ram region */ -static unsigned long stram_end; - /* Overall end of ST-Ram */ +/* start and end of swapping area */ +static unsigned long swap_start, swap_end; +/* The ST-RAM's swap info structure */ +static struct swap_info_struct *stram_swap_info; +/* The ST-RAM's swap type */ +static int stram_swap_type; + +/* major and minor device number of the ST-RAM device; for the major, we use + * the same as Amiga z2ram, which is really similar and impossible on Atari, + * and for the minor a relatively odd number to avoid the user creating and + * using that device. */ +#define STRAM_MAJOR Z2RAM_MAJOR +#define STRAM_MINOR 13 + +/* Some impossible pointer value */ +#define MAGIC_FILE_P (struct file *)0xffffdead + +#ifdef DO_PROC +static unsigned stat_swap_read = 0; +static unsigned stat_swap_write = 0; +static unsigned stat_swap_move = 0; +static unsigned stat_swap_force = 0; +#endif /* DO_PROC */ + +#endif /* CONFIG_STRAM_SWAP */ + +/***************************** Prototypes *****************************/ + +#ifdef CONFIG_STRAM_SWAP +static int swap_init( unsigned long start_mem, unsigned long swap_data ); +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, int + isswap ); +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, unsigned + long entry, unsigned long page, int isswap ); +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ); +static int unswap_by_move( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static int unswap_by_read( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static void *get_stram_region( unsigned long n_pages ); +static void free_stram_region( unsigned long offset, unsigned long n_pages + ); +static int in_some_region( unsigned long addr ); +static unsigned long find_free_region( unsigned long n_pages, unsigned long + *total_free, unsigned long + *region_free ); +static void do_stram_request( void ); +static int stram_open( struct inode *inode, struct file *filp ); +static int stram_release( struct inode *inode, struct file *filp ); +static void do_z2_request( void ); +#endif +static int get_gfp_order( unsigned long size ); +static void reserve_region( unsigned long addr, unsigned long end ); +static BLOCK *add_region( void *addr, unsigned long size ); +static BLOCK *find_region( void *addr ); +static int remove_region( BLOCK *block ); + +/************************* End of Prototypes **************************/ + + +/* ------------------------------------------------------------------------ */ +/* Public Interface */ +/* ------------------------------------------------------------------------ */ + +/* + * This init function is called very early by atari/config.c + * It initializes some internal variables needed for stram_alloc() + */ __initfunc(void atari_stram_init( void )) +{ + int i; + + /* initialize static blocks */ + for( i = 0; i < N_STATIC_BLOCKS; ++i ) + static_blocks[i].flags = BLOCK_FREE; -{ int i; + /* determine whether kernel code resides in ST-RAM (then ST-RAM is the + * first memory block at virtual 0x0) */ + stram_start = PTOV( 0 ); + kernel_in_stram = (stram_start == 0); for( i = 0; i < m68k_num_memory; ++i ) { if (m68k_memory[i].addr == 0) { - rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */ + /* skip first 2kB or page (supervisor-only!) */ + rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800); rsvd_stram_end = rsvd_stram_beg; - stram_end = rsvd_stram_beg - 0x800 + m68k_memory[i].size; + stram_end = stram_start + m68k_memory[i].size; return; } } /* Should never come here! (There is always ST-Ram!) */ + panic( "atari_stram_init: no ST-RAM found!" ); +} + + +/* + * This function is called from mem_init() to reserve the pages needed for + * ST-RAM management. + */ +__initfunc(void atari_stram_reserve_pages( unsigned long start_mem )) +{ +#ifdef CONFIG_STRAM_SWAP + /* if max_swap_size is negative (i.e. no stram_swap= option given), + * determine at run time whether to use ST-RAM swapping */ + if (max_swap_size < 0) + /* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION + * of total memory. In that case, the max. size is set to 16 MB, + * because ST-RAM can never be bigger than that. + * Also, never use swapping on a Hades, there's no separate ST-RAM in + * that machine. */ + max_swap_size = + (!MACH_IS_HADES && + (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= + max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; + DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); +#endif + + /* always reserve first page of ST-RAM, the first 2 kB are + * supervisor-only! */ + set_bit( PG_reserved, &mem_map[MAP_NR(stram_start)].flags ); + +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { + fallback: +#endif + DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" ); + if (!kernel_in_stram) { + /* Reserve all pages that have been marked by pre-mem_init + * stram_alloc() (e.g. for the screen memory). */ + reserve_region( rsvd_stram_beg, rsvd_stram_end ); + DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n", + rsvd_stram_beg, rsvd_stram_end ); + } + /* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are + * kernel data */ +#ifdef CONFIG_STRAM_SWAP + } + else { + unsigned long swap_data; + BLOCK *p; + + /* determine first page to use as swap: + * if the kernel is in TT-RAM, this is the first page of (usable) + * ST-RAM; else if there were already some allocations (probable...), + * use the lowest address of these (the list is sorted by address!); + * otherwise just use the end of kernel data (= start_mem) */ + swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : + alloc_list ? alloc_list->start : + start_mem; + /* decrement by one page, rest of kernel assumes that first swap page + * is always reserved and maybe doesn't handle SWP_ENTRY == 0 + * correctly */ + swap_start -= PAGE_SIZE; + swap_end = stram_end; + if (swap_end-swap_start > max_swap_size) + swap_end = swap_start + max_swap_size; + DPRINTK( "atari_stram_reserve_pages: swapping enabled; " + "swap=%08lx-%08lx\n", swap_start, swap_end ); + + /* reserve some amount of memory for maintainance of swapping itself: + * 1 page for the lockmap, and one page for each 4096 (PAGE_SIZE) swap + * pages. (1 byte for each page) */ + swap_data = start_mem; + start_mem += PAGE_ALIGN(SWAP_NR(swap_end)) + PAGE_SIZE; + /* correct swap_start if necessary */ + if (swap_start == swap_data) + swap_start = start_mem; + + if (!swap_init( start_mem, swap_data )) { + printk( KERN_ERR "ST-RAM swap space initialization failed\n" ); + max_swap_size = 0; + goto fallback; + } + /* reserve region for swapping meta-data */ + reserve_region( swap_data, start_mem ); + /* reserve swapping area itself */ + reserve_region( swap_start+PAGE_SIZE, swap_end ); + + /* Formerly static areas have been included in the swap area. */ + for( p = alloc_list; p; p = p->next ) { + if (p->flags & BLOCK_STATIC) + p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP; + } + + /* + * If the whole ST-RAM is used for swapping, there are no allocatable + * dma pages left. But unfortunately, some shared parts of the kernel + * (particularily the SCSI mid-level) call __get_dma_pages() + * unconditionally :-( These calls then fail, and scsi.c even doesn't + * check for NULL return values and just crashes. The quick fix for + * this (instead of doing much clean up work in the SCSI code) is to + * pretend all pages are DMA-able by setting mach_max_dma_address to + * ULONG_MAX. This doesn't change any functionality so far, since + * get_dma_pages() shouldn't be used on Atari anyway anymore (better + * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA + * memory. But unfortunately there's now no kind of warning (even not + * a NULL return value) if you use get_dma_pages() nevertheless :-( + * You just will get non-DMA-able memory... + */ + mach_max_dma_address = 0xffffffff; + + /* + * Ok, num_physpages needs not be really exact, but it's better to + * subtract the pages set aside for swapping. + */ + num_physpages -= SWAP_NR(swap_end)-1; + } +#endif + + mem_init_done = 1; } -void *atari_stram_alloc( long size, unsigned long *start_mem ) +/* + * This is main public interface: somehow allocate a ST-RAM block + * There are three strategies: + * + * - If we're before mem_init(), we have to make a static allocation. The + * region is taken in the kernel data area (if the kernel is in ST-RAM) or + * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the + * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel + * address space in the latter case. + * + * - If mem_init() already has been called and ST-RAM swapping is enabled, + * try to get the memory from the (pseudo) swap-space, either free already + * or by moving some other pages out of the swap. + * + * - If mem_init() already has been called, and ST-RAM swapping is not + * enabled, the only possibility is to try with __get_dma_pages(). This has + * the disadvantage that it's very hard to get more than 1 page, and it is + * likely to fail :-( + * + */ +void *atari_stram_alloc( long size, unsigned long *start_mem, + const char *owner ) +{ + void *addr = NULL; + BLOCK *block; + int flags; + + DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n", + size, start_mem ? *start_mem : 0xffffffff, owner ); + + if (start_mem && mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL " + "after mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + if (!start_mem && !mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL " + "before mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + + size = ALIGN_IF_SWAP(size); + DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size ); + if (!mem_init_done) { + /* before mem_init(): allocate "statically", i.e. either in the kernel + * data space (current end in *start_mem), or at the end of currently + * reserved ST-RAM. */ + if (kernel_in_stram) { + /* Get memory from kernel data space */ + *start_mem = ALIGN_IF_SWAP(*start_mem); + addr = (void *)*start_mem; + *start_mem += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: " + "shifted start_mem to %08lx, addr=%p\n", + *start_mem, addr ); + } + else { + /* Get memory from rsvd_stram_beg */ + if (rsvd_stram_end + size < stram_end) { + addr = (void *) rsvd_stram_end; + rsvd_stram_end += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: " + "shifted rsvd_stram_end to %08lx, addr=%p\n", + rsvd_stram_end, addr ); + } + } + flags = BLOCK_STATIC; + } +#ifdef CONFIG_STRAM_SWAP + else if (max_swap_size) { + /* If swapping is active (can only be the case after mem_init()!): + * make some free space in the swap "device". */ + DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, " + "calling get_region\n" ); + addr = get_stram_region( N_PAGES(size) ); + flags = BLOCK_INSWAP; + } +#endif + else { + /* After mem_init() and no swapping: can only resort to + * __get_dma_pages() */ + addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size)); + flags = BLOCK_GFP; + DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " + "get_pages=%p\n", addr ); + } + + if (addr) { + if (!(block = add_region( addr, size ))) { + /* out of memory for BLOCK structure :-( */ + DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " + "freeing again\n" ); + if (flags == BLOCK_STATIC) + rsvd_stram_end -= size; +#ifdef CONFIG_STRAM_SWAP + else if (flags == BLOCK_INSWAP) + free_stram_region( SWAP_NR(addr), N_PAGES(size) ); +#endif + else + free_pages( (unsigned long)addr, get_gfp_order(size)); + return( NULL ); + } + block->owner = owner; + block->flags |= flags; + } + return( addr ); +} + +void atari_stram_free( void *addr ) { - static int kernel_in_stram = -1; + BLOCK *block; + + DPRINTK( "atari_stram_free(addr=%p)\n", addr ); + + if (!(block = find_region( addr ))) { + printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " + "from %p\n", addr, __builtin_return_address(0) ); + return; + } + DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " + "flags=%02x\n", block, block->size, block->owner, block->flags ); - void *adr = 0; +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { +#endif + if (block->flags & BLOCK_GFP) { + DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n", + get_gfp_order(block->size) ); + free_pages( (unsigned long)addr, get_gfp_order(block->size) ); + } + else + goto fail; +#ifdef CONFIG_STRAM_SWAP + } + else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) { + DPRINTK( "atari_stram_free: is swap-alloced\n" ); + free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); + } + else + goto fail; +#endif + remove_region( block ); + return; + + fail: + printk( KERN_ERR "atari_stram_free: cannot free block at %p " + "(called from %p)\n", addr, __builtin_return_address(0) ); +} + + +#ifdef CONFIG_STRAM_SWAP + + +/* ------------------------------------------------------------------------ */ +/* Main Swapping Functions */ +/* ------------------------------------------------------------------------ */ + + +/* + * Initialize ST-RAM swap device + * (lots copied and modified from sys_swapon() in mm/swapfile.c) + */ +__initfunc(static int swap_init( unsigned long start_mem, + unsigned long swap_data )) +{ + static struct dentry fake_dentry[3]; + struct swap_info_struct *p; + struct inode swap_inode; + unsigned int type; + unsigned long addr; + int i, j, k, prev; + + DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n", + start_mem, swap_data ); + + /* need at least one page for swapping to (and this also isn't very + * much... :-) */ + if (swap_end - swap_start < 2*PAGE_SIZE) { + printk( KERN_WARNING "stram_swap_init: swap space too small\n" ); + return( 0 ); + } - if (kernel_in_stram < 0) - kernel_in_stram = (PTOV( 0 ) == 0); + /* find free slot in swap_info */ + for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ ) + if (!(p->flags & SWP_USED)) + break; + if (type >= MAX_SWAPFILES) { + printk( KERN_WARNING "stram_swap_init: max. number of " + "swap devices exhausted\n" ); + return( 0 ); + } + if (type >= nr_swapfiles) + nr_swapfiles = type+1; + + stram_swap_info = p; + stram_swap_type = type; + + /* fake some dir cache entries to give us some name in /dev/swaps */ + fake_dentry[0].d_covers = &fake_dentry[1]; + fake_dentry[0].d_parent = &fake_dentry[0]; + fake_dentry[1].d_parent = &fake_dentry[2]; + fake_dentry[1].d_name.name = "stram (internal)"; + fake_dentry[1].d_name.len = 16; + fake_dentry[2].d_covers = &fake_dentry[2]; + fake_dentry[2].d_parent = &fake_dentry[2]; + + p->flags = SWP_USED; + p->swap_file = &fake_dentry[0]; + p->swap_device = 0; + p->swap_lockmap = (unsigned char *)(swap_data); + p->swap_map = (unsigned char *)(swap_data + PAGE_SIZE); + p->cluster_nr = 0; + p->next = -1; + p->prio = 0x7ff0; /* a rather high priority, but not the higest + * to give the user a chance to override */ + + /* call stram_open() directly, avoids at least the overhead in + * constructing a dummy file structure... */ + p->swap_device = MKDEV( STRAM_MAJOR, STRAM_MINOR ); + swap_inode.i_rdev = p->swap_device; + stram_open( &swap_inode, MAGIC_FILE_P ); + p->max = SWAP_NR(swap_end); + + /* initialize lockmap */ + memset( p->swap_lockmap, 0, PAGE_SIZE ); + + /* initialize swap_map: set regions that are already allocated or belong + * to kernel data space to SWP_RSVD, otherwise to free */ + j = 0; /* # of free pages */ + k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ + p->lowest_bit = 0; + p->highest_bit = 0; + for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max; + i++, addr += PAGE_SIZE ) { + if (in_some_region( addr )) { + p->swap_map[i] = SWP_RSVD; + ++k; + } + else if (kernel_in_stram && addr < start_mem ) { + p->swap_map[i] = SWP_RSVD; + } + else { + p->swap_map[i] = 0; + ++j; + if (!p->lowest_bit) p->lowest_bit = i; + p->highest_bit = i; + } + } + /* first page always reserved (and doesn't really belong to swap space) */ + p->swap_map[0] = SWP_RSVD; - if (kernel_in_stram) { - /* Get memory from kernel data space */ - adr = (void *) *start_mem; - *start_mem += size; + /* now swapping to this device ok */ + p->pages = j + k; + nr_swap_pages += j; + p->flags = SWP_WRITEOK; + + /* insert swap space into swap_list */ + prev = -1; + for (i = swap_list.head; i >= 0; i = swap_info[i].next) { + if (p->prio >= swap_info[i].prio) { + break; + } + prev = i; + } + p->next = i; + if (prev < 0) { + swap_list.head = swap_list.next = p - swap_info; + } else { + swap_info[prev].next = p - swap_info; + } + + printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", + p->pages << 2, p->pages ); + return( 1 ); +} + + +/* + * The swap entry has been read in advance, and we return 1 to indicate + * that the page has been used or is no longer needed. + */ +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t pte = *dir; + + if (pte_none(pte)) + return 0; + if (pte_present(pte)) { + struct page *pg; + unsigned long page_nr = MAP_NR(pte_page(pte)); + unsigned long pg_swap_entry; + + if (page_nr >= max_mapnr) + return 0; + pg = mem_map + page_nr; + if (!(pg_swap_entry = in_swap_cache(pg))) + return 0; + if (pg_swap_entry != entry) + return 0; + if (isswap) { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "exchanging to %08lx\n", + page_address(pg), entry, page ); + pg->offset = page; + swap_free(entry); + return 1; + } + else { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "deleted there\n", page_address(pg), entry ); + delete_from_swap_cache(pg); + set_pte(dir, pte_mkdirty(pte)); + free_page(page); + return 1; + } + } + if (pte_val(pte) != entry) + return 0; + + if (isswap) { + DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page ); + set_pte(dir, __pte(page)); } else { - /* Get memory from rsvd_stram_beg */ - if (rsvd_stram_end + size < stram_end) { - adr = (void *) rsvd_stram_end; - rsvd_stram_end += size; + DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx", + entry, page ); + set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page,vma->vm_page_prot)))); + ++vma->vm_mm->rss; + } + swap_free(entry); + return 1; +} + +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*dir)) + return 0; + if (pmd_bad(*dir)) { + printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_clear(dir); + return 0; + } + pte = pte_offset(dir, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (unswap_pte( vma, offset+address-vma->vm_start, pte, entry, + page, isswap )) + return 1; + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, + int isswap ) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + offset = address & PGDIR_MASK; + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + if (unswap_pmd( vma, pmd, address, end - address, offset, entry, + page, isswap )) + return 1; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, + unsigned long entry, unsigned long page, int isswap ) +{ + unsigned long start = vma->vm_start, end = vma->vm_end; + + while( start < end ) { + if (unswap_pgd( vma, pgdir, start, end - start, entry, page, isswap )) + return 1; + start = (start + PGDIR_SIZE) & PGDIR_MASK; + pgdir++; + } + return 0; +} + +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ) +{ + struct vm_area_struct* vma; + + /* + * Go through process' page directory. + */ + if (!mm || mm == &init_mm) + return 0; + for( vma = mm->mmap; vma; vma = vma->vm_next ) { + pgd_t * pgd = pgd_offset(mm, vma->vm_start); + if (unswap_vma( vma, pgd, entry, page, isswap )) + return 1; + } + return 0; +} + + +static int unswap_by_move( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, rover = (start == 1) ? n_pages+1 : 1; + unsigned long i, j; + + DPRINTK( "unswapping %lu..%lu by moving in swap\n", + start, start+n_pages-1 ); + + /* can free the allocated pages by moving them to other swap pages */ + for( i = start; i < start+n_pages; ++i ) { + if (!map[i]) { + map[i] = SWP_RSVD; + DPRINTK( "unswap: page %lu was free\n", i ); + continue; } + else if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + } + DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] ); + + /* find a free page not in our region */ + for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) { + if (j >= start && j < start+n_pages) + continue; + if (!map[j]) { + rover = j+1; + break; + } + } + if (j == rover-1) { + printk( KERN_ERR "get_stram_region: not enough free swap " + "pages now??\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + + --nr_swap_pages; + entry = SWP_ENTRY( stram_swap_type, j ); + if (stram_swap_info->lowest_bit == j) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == j) + stram_swap_info->highest_bit--; + + memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE ); +#ifdef DO_PROC + stat_swap_move++; +#endif + + while( map[i] ) { + for_each_task(p) { + if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ), + entry, 1 )) { + map[j]++; + goto repeat; + } + } + if (map[i] && map[i] != 127) { + printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu " + "not used by any process\n", i ); + /* quit while loop and overwrite bad map entry */ + break; + } + else if (!map[i]) { + /* somebody else must have swapped in that page, so free the + * new one (we're moving to) */ + DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" ); + map[j] = 0; + } + repeat: + } + + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; + } + return( 0 ); +} + +static int unswap_by_read( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, page = 0; + unsigned long i; + + DPRINTK( "unswapping %lu..%lu by reading in\n", + start, start+n_pages-1 ); + + for( i = start; i < start+n_pages; ++i ) { + if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + continue; + } + entry = SWP_ENTRY( stram_swap_type, i ); + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + + while( map[i] ) { + if (!page && !(page = __get_free_page(GFP_KERNEL))) { + printk( KERN_NOTICE "get_stram_region: out of memory\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page ); + read_swap_page( entry, (char *)page ); + + for_each_task(p) { + if (unswap_process( p->mm, entry, page, 0 )) { + page = 0; +#ifdef DO_PROC + stat_swap_force++; +#endif + break; + } + } + if (page) { + /* + * If we couldn't find an entry, there are several + * possible reasons: someone else freed it first, + * we freed the last reference to an overflowed entry, + * or the system has lost track of the use counts. + */ + if (map[i] && map[i] != SWP_RSVD-1) + printk( KERN_ERR "get_stram_region: swap entry %08lx " + "not used by any process\n", entry ); + /* quit while loop and overwrite bad map entry */ + if (!map[i]) { + DPRINTK( "unswap: map[i] became 0\n" ); + } + break; + } + } + + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; } + + if (page) + free_page(page); + return( 0 ); +} + +/* + * reserve a region in ST-RAM swap space for an allocation + */ +static void *get_stram_region( unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long start, total_free, region_free; + int err; + void *ret = NULL; + + DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages ); + + /* disallow writing to the swap device now */ + stram_swap_info->flags = SWP_USED; + + /* find a region of n_pages pages in the swap space including as much free + * pages as possible (and excluding any already-reserved pages). */ + if (!(start = find_free_region( n_pages, &total_free, ®ion_free ))) + goto end; + DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n", + start, region_free ); + + err = ((total_free-region_free >= n_pages-region_free) ? + unswap_by_move( map, max, start, n_pages ) : + unswap_by_read( map, max, start, n_pages )); + if (err) + goto end; + + ret = SWAP_ADDR(start); + end: + /* allow using swap device again */ + stram_swap_info->flags = SWP_WRITEOK; + DPRINTK( "get_stram_region: returning %p\n", ret ); + return( ret ); +} + + +/* + * free a reserved region in ST-RAM swap space + */ +static void free_stram_region( unsigned long offset, unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + + DPRINTK( "free_stram_region(offset=%lu,n_pages=%lu)\n", offset, n_pages ); + + if (offset < 1 || offset + n_pages > stram_swap_info->max) { + printk( KERN_ERR "free_stram_region: Trying to free non-ST-RAM\n" ); + return; + } + + /* un-reserve the freed pages */ + for( ; n_pages > 0; ++offset, --n_pages ) { + if (map[offset] != SWP_RSVD) + printk( KERN_ERR "free_stram_region: Swap page %lu was not " + "reserved\n", offset ); + map[offset] = 0; + } + + /* update swapping meta-data */ + if (offset < stram_swap_info->lowest_bit) + stram_swap_info->lowest_bit = offset; + if (offset+n_pages-1 > stram_swap_info->highest_bit) + stram_swap_info->highest_bit = offset+n_pages-1; + if (stram_swap_info->prio > swap_info[swap_list.next].prio) + swap_list.next = swap_list.head; + nr_swap_pages += n_pages; +} + + +/* ------------------------------------------------------------------------ */ +/* Utility Functions for Swapping */ +/* ------------------------------------------------------------------------ */ + + +/* is addr in some of the allocated regions? */ +static int in_some_region( unsigned long addr ) +{ + BLOCK *p; - return( adr ); + for( p = alloc_list; p; p = p->next ) { + if (p->start <= addr && addr < p->start + p->size) + return( 1 ); + } + return( 0 ); +} + + +static unsigned long find_free_region( unsigned long n_pages, + unsigned long *total_free, + unsigned long *region_free ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long head, tail, max_start; + long nfree, max_free; + + /* first scan the swap space for a suitable place for the allocation */ + head = 1; + max_start = 0; + max_free = -1; + *total_free = 0; + + start_over: + /* increment tail until final window size reached, and count free pages */ + nfree = 0; + for( tail = head; tail-head < n_pages && tail < max-n_pages; ++tail ) { + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; + } + } + if (tail-head < n_pages) + goto out; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } + + /* now shift the window and look for the area where as much pages as + * possible are free */ + while( tail < max ) { + nfree -= (map[head++] == 0); + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; + } + ++tail; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } + } + + out: + if (max_free < 0) { + printk( KERN_NOTICE "get_stram_region: ST-RAM too full or fragmented " + "-- can't allocate %lu pages\n", n_pages ); + return( 0 ); + } + + *region_free = max_free; + return( max_start ); } -void atari_stram_free( void *ptr ) +/* setup parameters from command line */ +void stram_swap_setup( char *str, int *ints ) { - /* Sorry, this is a dummy. It isn't needed anyway. */ + if (ints[0] >= 1) + max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK; } + +/* ------------------------------------------------------------------------ */ +/* ST-RAM device */ +/* ------------------------------------------------------------------------ */ + +static int stram_blocksizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096 }; +static int stram_sizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static int refcnt = 0; + +static void do_stram_request( void ) +{ + unsigned long start, len; + + while( CURRENT ) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic("stram: request list destroyed"); + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) + panic("stram: block not locked"); + } + + start = swap_start + (CURRENT->sector << 9); + len = CURRENT->current_nr_sectors << 9; + if ((start + len) > swap_end) { + printk( KERN_ERR "stram: bad access beyond end of device: " + "block=%ld, count=%ld\n", + CURRENT->sector, + CURRENT->current_nr_sectors ); + end_request( 0 ); + continue; + } + + if (CURRENT->cmd == READ) { + memcpy( CURRENT->buffer, (char *)start, len ); +#ifdef DO_PROC + stat_swap_read += N_PAGES(len); +#endif + } + else { + memcpy( (char *)start, CURRENT->buffer, len ); +#ifdef DO_PROC + stat_swap_write += N_PAGES(len); +#endif + } + end_request( 1 ); + } +} + + +static int stram_open( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" ); + return( -EPERM ); + } + if (MINOR(inode->i_rdev) != STRAM_MINOR) + return( -ENXIO ); + if (refcnt) + return( -EBUSY ); + ++refcnt; + return( 0 ); +} + +static int stram_release( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can close ST-RAM device\n" ); + return( -EPERM ); + } + if (refcnt > 0) + --refcnt; + return( 0 ); +} + + +static struct file_operations stram_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + stram_open, /* open */ + stram_release, /* release */ + block_fsync /* fsync */ +}; + +int stram_device_init( void ) +{ + + if (!MACH_IS_ATARI) + /* no point in initializing this, I hope */ + return( -ENXIO ); + + if (!max_swap_size) + /* swapping not enabled */ + return( -ENXIO ); + + if (register_blkdev( STRAM_MAJOR, "stram", &stram_fops)) { + printk( KERN_ERR "stram: Unable to get major %d\n", STRAM_MAJOR ); + return( -ENXIO ); + } + + blk_dev[STRAM_MAJOR].request_fn = do_stram_request; + blksize_size[STRAM_MAJOR] = stram_blocksizes; + stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024; + blk_size[STRAM_MAJOR] = stram_sizes; + do_z2_request(); /* to avoid warning */ + return( 0 ); +} + +/* to avoid warning */ +static void do_z2_request( void ) { } + +#endif /* CONFIG_STRAM_SWAP */ + + +/* ------------------------------------------------------------------------ */ +/* Misc Utility Functions */ +/* ------------------------------------------------------------------------ */ + + +/* return log2 of #pages for size */ +static int get_gfp_order( unsigned long size ) +{ + int order; + + size = N_PAGES( size + PAGE_SIZE -1 ); + order = -1; + do { + size >>= 1; + order++; + } while (size); + + return( order ); +} + + +/* reserve a range of pages in mem_map[] */ +static void reserve_region( unsigned long addr, unsigned long end ) +{ + mem_map_t *mapp = &mem_map[MAP_NR(addr)]; + + for( ; addr < end; addr += PAGE_SIZE, ++mapp ) + set_bit( PG_reserved, &mapp->flags ); +} + + + +/* ------------------------------------------------------------------------ */ +/* Region Management */ +/* ------------------------------------------------------------------------ */ + + +/* insert a region into the alloced list (sorted) */ +static BLOCK *add_region( void *addr, unsigned long size ) +{ + BLOCK **p, *n = NULL; + int i; + + for( i = 0; i < N_STATIC_BLOCKS; ++i ) { + if (static_blocks[i].flags & BLOCK_FREE) { + n = &static_blocks[i]; + n->flags = 0; + break; + } + } + if (!n && mem_init_done) { + /* if statics block pool exhausted and we can call kmalloc() already + * (after mem_init()), try that */ + n = kmalloc( sizeof(BLOCK), GFP_KERNEL ); + if (n) + n->flags = BLOCK_KMALLOCED; + } + if (!n) { + printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); + return( NULL ); + } + n->start = (unsigned long)addr; + n->size = size; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if ((*p)->start > (unsigned long)addr) break; + n->next = *p; + *p = n; + + return( n ); +} + + +/* find a region (by start addr) in the alloced list */ +static BLOCK *find_region( void *addr ) +{ + BLOCK *p; + + for( p = alloc_list; p; p = p->next ) { + if (p->start == (unsigned long)addr) + return( p ); + if (p->start > (unsigned long)addr) + break; + } + return( NULL ); +} + + +/* remove a block from the alloced list */ +static int remove_region( BLOCK *block ) +{ + BLOCK **p; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if (*p == block) break; + if (!*p) + return( 0 ); + + *p = block->next; + if (block->flags & BLOCK_KMALLOCED) + kfree( block ); + else + block->flags |= BLOCK_FREE; + return( 1 ); +} + + + +/* ------------------------------------------------------------------------ */ +/* /proc statistics file stuff */ +/* ------------------------------------------------------------------------ */ + +#ifdef DO_PROC + +#define PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args ) + +int get_stram_list( char *buf ) +{ + int len = 0; + BLOCK *p; +#ifdef CONFIG_STRAM_SWAP + int i; + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned free = 0, used = 0, rsvd = 0; +#endif + +#ifdef CONFIG_STRAM_SWAP + if (max_swap_size) { + for( i = 1; i < max; ++i ) { + if (!map[i]) + ++free; + else if (map[i] == SWP_RSVD) + ++rsvd; + else + ++used; + } + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Total ST-RAM swap: %8lu kB\n" + "Free swap: %8u kB\n" + "Used swap: %8u kB\n" + "Allocated swap: %8u kB\n" + "Swap Reads: %8u\n" + "Swap Writes: %8u\n" + "Swap Moves: %8u\n" + "Swap Forced Reads: %8u\n", + (stram_end - stram_start) >> 10, + (max-1) << (PAGE_SHIFT-10), + free << (PAGE_SHIFT-10), + used << (PAGE_SHIFT-10), + rsvd << (PAGE_SHIFT-10), + stat_swap_read, + stat_swap_write, + stat_swap_move, + stat_swap_force ); + } + else { +#endif + PRINT_PROC( "ST-RAM swapping disabled\n" ); + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Reserved ST-RAM: %8lu kB\n", + (stram_end - stram_start) >> 10, + (rsvd_stram_end - rsvd_stram_beg) >> 10 ); +#ifdef CONFIG_STRAM_SWAP + } #endif + PRINT_PROC( "Allocated regions:\n" ); + for( p = alloc_list; p; p = p->next ) { + if (len + 50 >= PAGE_SIZE) + break; + PRINT_PROC( "0x%08lx-0x%08lx: %s (", + VTOP(p->start), VTOP(p->start+p->size-1), p->owner ); + if (p->flags & BLOCK_STATIC) + PRINT_PROC( "static)\n" ); + else if (p->flags & BLOCK_GFP) + PRINT_PROC( "page-alloced)\n" ); + else if (p->flags & BLOCK_INSWAP) + PRINT_PROC( "in swap)\n" ); + else + PRINT_PROC( "??)\n" ); + } + return( len ); +} + +#endif + + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c new file mode 100644 index 000000000..1e81eb18e --- /dev/null +++ b/arch/m68k/atari/time.c @@ -0,0 +1,415 @@ +/* + * linux/arch/m68k/atari/time.c + * + * Atari time and real time clock stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/types.h> +#include <linux/mc146818rtc.h> +#include <linux/kd.h> +#include <linux/interrupt.h> +#include <linux/init.h> + + +__initfunc(void +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +{ + /* set Timer C data Register */ + mfp.tim_dt_c = INT_TICKS; + /* start timer C, div = 1:100 */ + mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; + /* install interrupt service routine for MFP Timer C */ + request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, + "timer", timer_routine); +} + +/* ++andreas: gettimeoffset fixed to check for pending interrupt */ + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long atari_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read MFP timer C current value */ + ticks = mfp.tim_dt_c; + /* The probability of underflow is less than 2% */ + if (ticks > INT_TICKS - INT_TICKS / 50) + /* Check for pending timer interrupt */ + if (mfp.int_pn_b & (1 << 5)) + offset = TICK_SIZE; + + ticks = INT_TICKS - ticks; + ticks = ticks * 10000L / INT_TICKS; + + return ticks + offset; +} + + +static void mste_read(struct MSTE_RTC *val) +{ +#define COPY(v) val->v=(mste_rtc.v & 0xf) + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from reading the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +static void mste_write(struct MSTE_RTC *val) +{ +#define COPY(v) mste_rtc.v=val->v + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from writing the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +#define RTC_READ(reg) \ + ({ unsigned char __val; \ + outb(reg,&tt_rtc.regsel); \ + __val = tt_rtc.data; \ + __val; \ + }) + +#define RTC_WRITE(reg,val) \ + do { \ + outb(reg,&tt_rtc.regsel); \ + tt_rtc.data = (val); \ + } while(0) + + +void atari_mste_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + int hr24=0, hour; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + mste_read(&val); + *secp = val.sec_ones + val.sec_tens * 10; + *minp = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + *hourp = hour; + *dayp = val.day_ones + val.day_tens * 10; + *monp = val.mon_ones + val.mon_tens * 10; + *yearp = val.year_ones + val.year_tens * 10 + 80; +} + + +void atari_tt_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + unsigned char ctrl; + int hour, pm; + + while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; + while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + + *secp = RTC_READ(RTC_SECONDS); + *minp = RTC_READ(RTC_MINUTES); + hour = RTC_READ(RTC_HOURS); + *dayp = RTC_READ(RTC_DAY_OF_MONTH); + *monp = RTC_READ(RTC_MONTH); + *yearp = RTC_READ(RTC_YEAR); + pm = hour & 0x80; + hour &= ~0x80; + + ctrl = RTC_READ(RTC_CONTROL); + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(*secp); + BCD_TO_BIN(*minp); + BCD_TO_BIN(hour); + BCD_TO_BIN(*dayp); + BCD_TO_BIN(*monp); + BCD_TO_BIN(*yearp); + } + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + *hourp = hour; + + /* Adjust values (let the setup valid) */ + *yearp += atari_rtc_year_offset; +} + +#define HWCLK_POLL_INTERVAL 5 + +int atari_mste_hwclk( int op, struct hwclk_time *t ) +{ + int hour, year; + int hr24=0; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + if (op) { + /* write: prepare values */ + + val.sec_ones = t->sec % 10; + val.sec_tens = t->sec / 10; + val.min_ones = t->min % 10; + val.min_tens = t->min / 10; + hour = t->hour; + if (!hr24) { + if (hour > 11) + hour += 20 - 12; + if (hour == 0 || hour == 20) + hour += 12; + } + val.hr_ones = hour % 10; + val.hr_tens = hour / 10; + val.day_ones = t->day % 10; + val.day_tens = t->day / 10; + val.mon_ones = (t->mon+1) % 10; + val.mon_tens = (t->mon+1) / 10; + year = t->year - 80; + val.year_ones = year % 10; + val.year_tens = year / 10; + val.weekday = t->wday; + mste_write(&val); + mste_rtc.mode=(mste_rtc.mode | 1); + val.year_ones = (year % 4); /* leap year register */ + mste_rtc.mode=(mste_rtc.mode & ~1); + } + else { + mste_read(&val); + t->sec = val.sec_ones + val.sec_tens * 10; + t->min = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + t->hour = hour; + t->day = val.day_ones + val.day_tens * 10; + t->mon = val.mon_ones + val.mon_tens * 10 - 1; + t->year = val.year_ones + val.year_tens * 10 + 80; + t->wday = val.weekday; + } + return 0; +} + +int atari_tt_hwclk( int op, struct hwclk_time *t ) +{ + int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; + unsigned long flags; + unsigned char ctrl; + int pm = 0; + + ctrl = RTC_READ(RTC_CONTROL); /* control registers are + * independent from the UIP */ + + if (op) { + /* write: prepare values */ + + sec = t->sec; + min = t->min; + hour = t->hour; + day = t->day; + mon = t->mon + 1; + year = t->year - atari_rtc_year_offset; + wday = t->wday + (t->wday >= 0); + + if (!(ctrl & RTC_24H)) { + if (hour > 11) { + pm = 0x80; + if (hour != 12) + hour -= 12; + } + else if (hour == 0) + hour = 12; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(year); + if (wday >= 0) BIN_TO_BCD(wday); + } + } + + /* Reading/writing the clock registers is a bit critical due to + * the regular update cycle of the RTC. While an update is in + * progress, registers 0..9 shouldn't be touched. + * The problem is solved like that: If an update is currently in + * progress (the UIP bit is set), the process sleeps for a while + * (50ms). This really should be enough, since the update cycle + * normally needs 2 ms. + * If the UIP bit reads as 0, we have at least 244 usecs until the + * update starts. This should be enough... But to be sure, + * additionally the RTC_SET bit is set to prevent an update cycle. + */ + + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HWCLK_POLL_INTERVAL; + schedule(); + } + + save_flags(flags); + cli(); + RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); + if (!op) { + sec = RTC_READ( RTC_SECONDS ); + min = RTC_READ( RTC_MINUTES ); + hour = RTC_READ( RTC_HOURS ); + day = RTC_READ( RTC_DAY_OF_MONTH ); + mon = RTC_READ( RTC_MONTH ); + year = RTC_READ( RTC_YEAR ); + wday = RTC_READ( RTC_DAY_OF_WEEK ); + } + else { + RTC_WRITE( RTC_SECONDS, sec ); + RTC_WRITE( RTC_MINUTES, min ); + RTC_WRITE( RTC_HOURS, hour + pm); + RTC_WRITE( RTC_DAY_OF_MONTH, day ); + RTC_WRITE( RTC_MONTH, mon ); + RTC_WRITE( RTC_YEAR, year ); + if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); + } + RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); + restore_flags(flags); + + if (!op) { + /* read: adjust values */ + + if (hour & 0x80) { + hour &= ~0x80; + pm = 1; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(wday); + } + + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + + t->sec = sec; + t->min = min; + t->hour = hour; + t->day = day; + t->mon = mon - 1; + t->year = year + atari_rtc_year_offset; + t->wday = wday - 1; + } + + return( 0 ); +} + + +int atari_mste_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct MSTE_RTC val; + unsigned char rtc_minutes; + + mste_read(&val); + rtc_minutes= val.min_ones + val.min_tens * 10; + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + val.sec_ones = real_seconds % 10; + val.sec_tens = real_seconds / 10; + val.min_ones = real_minutes % 10; + val.min_tens = real_minutes / 10; + mste_write(&val); + } + else + return -1; + return 0; +} + +int atari_tt_set_clock_mmss (unsigned long nowtime) +{ + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + unsigned char save_control, save_freq_select, rtc_minutes; + + save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ + RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); + + save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); + + rtc_minutes = RTC_READ (RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY)) + BCD_TO_BIN (rtc_minutes); + + /* Since we're only adjusting minutes and seconds, don't interfere + with hour overflow. This avoids messing with unknown time zones + but requires your RTC not to be off by more than 30 minutes. */ + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + if (!(save_control & RTC_DM_BINARY)) + { + BIN_TO_BCD (real_seconds); + BIN_TO_BCD (real_minutes); + } + RTC_WRITE (RTC_SECONDS, real_seconds); + RTC_WRITE (RTC_MINUTES, real_minutes); + } + else + retval = -1; + + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); + RTC_WRITE (RTC_CONTROL, save_control); + return retval; +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ |