diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /arch/m68k | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'arch/m68k')
62 files changed, 8705 insertions, 2298 deletions
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index c1dd3072c..939a80387 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -18,19 +18,11 @@ COMPILE_ARCH = $(shell uname -m) # override top level makefile AS += -m68020 -ifdef CONFIG_KERNEL_ELF LD += -m m68kelf ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries CROSS_COMPILE = m68k-linux- endif -else -LD += -m m68klinux -ifneq ($(COMPILE_ARCH),$(ARCH)) - # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linuxaout- -endif -endif # # Set these to indicate how to link it.. @@ -42,53 +34,58 @@ endif # -qmagic (we need to remove the 32 byte header for bootup purposes) # -ifdef CONFIG_KERNEL_ELF LINKFLAGS = -Ttext 0x1000 -else -LINKFLAGS = -qmagic -Ttext 0xFE0 -endif -CFLAGS := $(CFLAGS) -pipe +CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce ifdef CONFIG_OPTIMIZE_040 CFLAGS := $(CFLAGS) -m68040 endif ifdef CONFIG_OPTIMIZE_060 -CFLAGS := $(CFLAGS) -m68020-40 -Wa,-m68060 +CFLAGS := $(CFLAGS) -m68020-40 +endif + +ifdef CONFIG_KGDB +# If configured for kgdb support, include debugging infos and keep the +# frame pointer +CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g endif HEAD := arch/m68k/kernel/head.o -SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/console arch/m68k/lib -ARCHIVES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(ARCHIVES) +SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib +CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) LIBS += arch/m68k/lib/lib.a ifdef CONFIG_AMIGA -ARCHIVES := $(ARCHIVES) arch/m68k/amiga/amiga.o +CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o SUBDIRS := $(SUBDIRS) arch/m68k/amiga endif ifdef CONFIG_ATARI -ARCHIVES := $(ARCHIVES) arch/m68k/atari/atari.o +CORE_FILES := $(CORE_FILES) arch/m68k/atari/atari.o SUBDIRS := $(SUBDIRS) arch/m68k/atari endif ifdef CONFIG_MAC -ARCHIVES := $(ARCHIVES) arch/m68k/mac/mac.o +CORE_FILES := $(CORE_FILES) arch/m68k/mac/mac.o SUBDIRS := $(SUBDIRS) arch/m68k/mac endif +ifdef CONFIG_VT # add in console.a after {amiga,atari}.o that need it -ARCHIVES := $(ARCHIVES) arch/m68k/console/console.a +CORE_FILES := $(CORE_FILES) arch/m68k/console/console.a +SUBDIRS := $(SUBDIRS) arch/m68k/console +endif ifdef CONFIG_M68040 -ARCHIVES := $(ARCHIVES) arch/m68k/fpsp040/fpsp.o +CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040 endif ifdef CONFIG_M68060 -ARCHIVES := $(ARCHIVES) arch/m68k/ifpsp060/ifpsp.o +CORE_FILES := $(CORE_FILES) arch/m68k/ifpsp060/ifpsp.o SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060 endif @@ -101,10 +98,24 @@ lilo: vmlinux cp System.map $(INSTALL_PATH)/System.map if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi -bootstrap: +zImage compressed: vmlinux.gz + +vmlinux.gz: vmlinux + +ifdef CONFIG_KGDB + cp vmlinux vmlinux.tmp + $(STRIP) vmlinux.tmp + gzip -9c vmlinux.tmp >vmlinux.gz + rm vmlinux.tmp +else + gzip -9c vmlinux >vmlinux.gz +endif + +bootstrap: dummy @$(MAKEBOOT) bootstrap archclean: + rm -f vmlinux.gz @$(MAKEBOOT) clean archdep: diff --git a/arch/m68k/amiga/Makefile b/arch/m68k/amiga/Makefile index ca540b9d1..9716668ea 100644 --- a/arch/m68k/amiga/Makefile +++ b/arch/m68k/amiga/Makefile @@ -9,10 +9,15 @@ O_TARGET := amiga.o O_OBJS := config.o amikeyb.o amiints.o cia.o \ - chipram.o amisound.o amifb.o zorro.o ksyms.o + chipram.o amisound.o amifb.o zorro.o +OX_OBJS := amiga_ksyms.o ifdef CONFIG_FB_CYBER O_OBJS := $(O_OBJS) cyberfb.o endif +ifdef CONFIG_FB_RETINAZ3 +O_OBJS := $(O_OBJS) retz3fb.o +endif + include $(TOPDIR)/Rules.make diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c index b05e314d2..c97609611 100644 --- a/arch/m68k/amiga/amifb.c +++ b/arch/m68k/amiga/amifb.c @@ -50,7 +50,6 @@ #include <linux/delay.h> #include <linux/config.h> #include <linux/interrupt.h> -#include <asm/setup.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/irq.h> @@ -606,6 +605,8 @@ static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000; #define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ #define DUMMYSPRITEMEMSIZE (8) +#define CHIPRAM_SAFETY_LIMIT (16384) + static u_long videomemory, spritememory; static u_long videomemorysize; @@ -639,7 +640,7 @@ typedef union { u_short w[2]; } copins; -struct copdisplay { +static struct copdisplay { copins *init; copins *wait; copins *list[2][2]; @@ -662,7 +663,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; * Current Video Mode */ -struct amiga_fb_par { +static struct amiga_fb_par { /* General Values */ @@ -835,7 +836,7 @@ static char *amiga_fb_modenames[] = { "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7" }; -struct fb_var_screeninfo amiga_fb_predefined[] = { +static struct fb_var_screeninfo amiga_fb_predefined[] = { /* * Autodetect (Default) Video Mode @@ -1241,6 +1242,7 @@ struct fb_info *amiga_fb_init(long *mem_start); static int amifbcon_switch(int con); static int amifbcon_updatevar(int con); static void amifbcon_blank(int blank); +static int amifbcon_setcmap(struct fb_cmap *cmap, int con); /* * Internal routines @@ -1314,7 +1316,15 @@ extern void Cyber_video_setup(char *options, int *ints); extern struct fb_info *Cyber_fb_init(long *mem_start); static int amifb_Cyber = 0; -#endif /* CONFIG_FB_CYBER */ +#endif + +#ifdef CONFIG_FB_RETINAZ3 /* RetinaZ3 */ +extern int retz3_probe(void); +extern void retz3_video_setup(char *options, int *ints); +extern struct fb_info *retz3_fb_init(long *mem_start); + +static int amifb_retz3 = 0; +#endif #ifdef CONFIG_GSP_RESOLVER /* DMI Resolver */ extern int resolver_probe(void); @@ -1322,7 +1332,7 @@ extern void resolver_video_setup(char *options, int *ints); extern struct fb_info *resolver_fb_init(long *mem_start); static int amifb_resolver = 0; -#endif /* CONFIG_GSP_RESOLVER */ +#endif static struct fb_ops amiga_fb_ops = { amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap, @@ -1346,7 +1356,15 @@ void amiga_video_setup(char *options, int *ints) Cyber_video_setup(options, ints); return; } -#endif /* CONFIG_FB_CYBER */ +#endif +#ifdef CONFIG_FB_RETINAZ3 + if (options && *options) + if (!strncmp(options, "retz3", 5) && retz3_probe()) { + amifb_retz3 = 1; + retz3_video_setup(options, ints); + return; + } +#endif #ifdef CONFIG_GSP_RESOLVER if (options && *options) if (!strncmp(options, "resolver", 5) && resolver_probe()) { @@ -1796,7 +1814,14 @@ struct fb_info *amiga_fb_init(long *mem_start) #ifdef CONFIG_FB_CYBER if (amifb_Cyber) return Cyber_fb_init(mem_start); -#endif /* CONFIG_FB_CYBER */ +#endif +#ifdef CONFIG_FB_RETINAZ3 + if (amifb_retz3){ + custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; + return retz3_fb_init(mem_start); + } +#endif #ifdef CONFIG_GSP_RESOLVER if (amifb_resolver){ custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | @@ -1814,7 +1839,7 @@ struct fb_info *amiga_fb_init(long *mem_start) custom.dmacon = DMAF_ALL | DMAF_MASTER; - switch (boot_info.bi_amiga.chipset) { + switch (amiga_chipset) { #ifdef CONFIG_AMIFB_OCS case CS_OCS: strcat(amiga_fb_name, "OCS"); @@ -1825,7 +1850,7 @@ default_chipset: maxdepth[TAG_LORES] = 6; maxfmode = TAG_FMODE_1; if (!amifb_usermode) /* Set the Default Video Mode */ - get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + get_video_mode(amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC); videomemorysize = VIDEOMEMSIZE_OCS; break; @@ -1841,13 +1866,14 @@ default_chipset: maxfmode = TAG_FMODE_1; if (!amifb_usermode) { /* Set the Default Video Mode */ if (AMIGAHW_PRESENT(AMBER_FF)) - get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + get_video_mode(amiga_vblank == 50 ? DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC); else - get_video_mode(boot_info.bi_un.bi_ami.vblank == 50 ? + get_video_mode(amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC); } - if (boot_info.bi_amiga.chip_size > 1048576) + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_1M) videomemorysize = VIDEOMEMSIZE_ECS_2M; else videomemorysize = VIDEOMEMSIZE_ECS_1M; @@ -1864,7 +1890,8 @@ default_chipset: maxfmode = TAG_FMODE_4; if (!amifb_usermode) /* Set the Default Video Mode */ get_video_mode(DEFMODE_AGA); - if (boot_info.bi_amiga.chip_size > 1048576) + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_1M) videomemorysize = VIDEOMEMSIZE_AGA_2M; else videomemorysize = VIDEOMEMSIZE_AGA_1M; @@ -1940,11 +1967,11 @@ default_chipset: check_default_mode(); - if (request_irq(IRQ3, amifb_interrupt, IRQ_FLG_LOCK, + if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, IRQ_FLG_LOCK, "fb vertb handler", NULL)) panic("Couldn't add vblank interrupt\n"); - ami_intena_vals[IRQ_IDX(IRQ_AMIGA_VERTB)] = IF_COPER; - ami_intena_vals[IRQ_IDX(IRQ_AMIGA_COPPER)] = 0; + ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER; + ami_intena_vals[IRQ_AMIGA_COPPER] = 0; custom.intena = IF_VERTB; custom.intena = IF_SETCLR | IF_COPER; @@ -1954,6 +1981,7 @@ default_chipset: fb_info.switch_con = &amifbcon_switch; fb_info.updatevar = &amifbcon_updatevar; fb_info.blank = &amifbcon_blank; + fb_info.setcmap = &amifbcon_setcmap; amiga_fb_set_var(&amiga_fb_predefined[0], 0); @@ -1992,6 +2020,15 @@ static void amifbcon_blank(int blank) do_blank = blank ? blank : -1; } + /* + * Set the colormap + */ + +static int amifbcon_setcmap(struct fb_cmap *cmap, int con) +{ + return(amiga_fb_set_cmap(cmap, 1, con)); +} + /* ---------------------------- Generic routines ---------------------------- */ static struct fb_cmap *get_default_colormap(int bpp) @@ -2210,10 +2247,11 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) { u_short ints = custom.intreqr & custom.intenar; static struct irq_server server = {0, 0}; + unsigned long flags; if (ints & IF_BLIT) { custom.intreq = IF_BLIT; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp); + amiga_do_irq(IRQ_AMIGA_BLIT, fp); } if (ints & IF_COPER) { @@ -2237,8 +2275,11 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) ami_set_sprite(); } - if (get_vbpos() < down2(currentpar.diwstrt_v - 4)) + save_flags(flags); + cli(); + if (get_vbpos() < down2(currentpar.diwstrt_v - 6)) custom.copjmp2 = 0; + restore_flags(flags); if (do_blank) { ami_do_blank(); @@ -2249,7 +2290,7 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) ami_reinit_copper(); do_vmode_full = 0; } - amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server); + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); } if (ints & IF_VERTB) { @@ -2504,7 +2545,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var, AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { par->beamcon0 = BMC0_PAL; par->hsstop = 1; - } else if (boot_info.bi_un.bi_ami.vblank != 50) + } else if (amiga_vblank != 50) return -EINVAL; } else { /* NTSC video mode @@ -2526,7 +2567,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var, AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { par->beamcon0 = 0; par->hsstop = 1; - } else if (boot_info.bi_un.bi_ami.vblank != 60) + } else if (amiga_vblank != 60) return -EINVAL; } if (IS_OCS) { diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c new file mode 100644 index 000000000..fe55f5f69 --- /dev/null +++ b/arch/m68k/amiga/amiga_ksyms.c @@ -0,0 +1,27 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/zorro.h> +#include <asm/amigahw.h> + +extern volatile u_short amiga_audio_min_period; +extern u_short amiga_audio_period; + +/* + * Add things here when you find the need for it. + */ +EXPORT_SYMBOL(amiga_model); +EXPORT_SYMBOL(amiga_hw_present); +EXPORT_SYMBOL(amiga_eclock); +EXPORT_SYMBOL(amiga_colorclock); +EXPORT_SYMBOL(amiga_chip_alloc); +EXPORT_SYMBOL(amiga_chip_free); +EXPORT_SYMBOL(amiga_chip_avail); +EXPORT_SYMBOL(amiga_audio_period); +EXPORT_SYMBOL(amiga_audio_min_period); + +EXPORT_SYMBOL(zorro_find); +EXPORT_SYMBOL(zorro_get_board); +EXPORT_SYMBOL(zorro_config_board); +EXPORT_SYMBOL(zorro_unconfig_board); +EXPORT_SYMBOL(zorro_unused_z2ram); diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index 5fe90949e..b527a8c6c 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -97,7 +97,7 @@ void amiga_init_IRQ(void) cia_init_IRQ(&ciab_base); } -void amiga_insert_irq(irq_node_t **list, irq_node_t *node) +static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) { unsigned long flags; irq_node_t *cur; @@ -135,7 +135,7 @@ void amiga_insert_irq(irq_node_t **list, irq_node_t *node) restore_flags(flags); } -void amiga_delete_irq(irq_node_t **list, void *dev_id) +static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) { unsigned long flags; irq_node_t *node; @@ -172,12 +172,16 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r return -ENXIO; } - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) - return cia_request_irq(&ciab_base, irq - IRQ_IDX(IRQ_AMIGA_CIAB), + if (irq >= IRQ_AMIGA_AUTO) + return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler, + flags, devname, dev_id); + + if (irq >= IRQ_AMIGA_CIAB) + return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, handler, flags, devname, dev_id); - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) - return cia_request_irq(&ciaa_base, irq - IRQ_IDX(IRQ_AMIGA_CIAA), + if (irq >= IRQ_AMIGA_CIAA) + return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, handler, flags, devname, dev_id); if (ami_servers[irq]) { @@ -196,7 +200,7 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r __FUNCTION__, irq, ami_irq_list[irq]->devname); return -EBUSY; } - if (flags & IRQ_FLG_REPLACE) { + if (!(flags & IRQ_FLG_REPLACE)) { printk("%s: %s can't replace IRQ %d from %s\n", __FUNCTION__, devname, irq, ami_irq_list[irq]->devname); return -EBUSY; @@ -209,7 +213,7 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r } /* enable the interrupt */ - if (irq < IRQ_IDX(IRQ_AMIGA_PORTS) && !ami_ablecount[irq]) + if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) custom.intena = IF_SETCLR | ami_intena_vals[irq]; return 0; @@ -222,20 +226,23 @@ void amiga_free_irq(unsigned int irq, void *dev_id) return; } - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) { - cia_free_irq(&ciab_base, irq - IRQ_IDX(IRQ_AMIGA_CIAB), dev_id); + if (irq >= IRQ_AMIGA_AUTO) + sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); + + if (irq >= IRQ_AMIGA_CIAB) { + cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); return; } - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) { - cia_free_irq(&ciaa_base, irq - IRQ_IDX(IRQ_AMIGA_CIAA), dev_id); + if (irq >= IRQ_AMIGA_CIAA) { + cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id); return; } if (ami_servers[irq]) { amiga_delete_irq(&ami_irq_list[irq], dev_id); /* if server list empty, disable the interrupt */ - if (!ami_irq_list[irq] && irq < IRQ_IDX(IRQ_AMIGA_PORTS)) + if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS) custom.intena = ami_intena_vals[irq]; } else { if (ami_irq_list[irq]->dev_id != dev_id) @@ -267,15 +274,22 @@ void amiga_enable_irq(unsigned int irq) if (--ami_ablecount[irq]) return; - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) { + /* No action for auto-vector interrupts */ + if (irq >= IRQ_AMIGA_AUTO){ + printk("%s: Trying to enable auto-vector IRQ %i\n", + __FUNCTION__, irq - IRQ_AMIGA_AUTO); + return; + } + + if (irq >= IRQ_AMIGA_CIAB) { cia_able_irq(&ciab_base, CIA_ICR_SETCLR | - (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB)))); + (1 << (irq - IRQ_AMIGA_CIAB))); return; } - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) { + if (irq >= IRQ_AMIGA_CIAA) { cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | - (1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA)))); + (1 << (irq - IRQ_AMIGA_CIAA))); return; } @@ -293,13 +307,20 @@ void amiga_disable_irq(unsigned int irq) if (ami_ablecount[irq]++) return; - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAB)) { - cia_able_irq(&ciab_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAB))); + /* No action for auto-vector interrupts */ + if (irq >= IRQ_AMIGA_AUTO) { + printk("%s: Trying to disable auto-vector IRQ %i\n", + __FUNCTION__, irq - IRQ_AMIGA_AUTO); + return; + } + + if (irq >= IRQ_AMIGA_CIAB) { + cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); return; } - if (irq >= IRQ_IDX(IRQ_AMIGA_CIAA)) { - cia_able_irq(&ciaa_base, 1 << (irq - IRQ_IDX(IRQ_AMIGA_CIAA))); + if (irq >= IRQ_AMIGA_CIAA) { + cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); return; } @@ -310,13 +331,12 @@ void amiga_disable_irq(unsigned int irq) inline void amiga_do_irq(int irq, struct pt_regs *fp) { kstat.interrupts[SYS_IRQS + irq]++; - ami_irq_list[irq]->handler(irq | IRQ_MACHSPEC, ami_irq_list[irq]->dev_id, fp); + ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) { irq_node_t *node, *slow_nodes; - int mach_irq = irq | IRQ_MACHSPEC; unsigned short flags; kstat.interrupts[SYS_IRQS + irq]++; @@ -326,7 +346,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) for (node = ami_irq_list[irq]; node && (!(node->flags & IRQ_FLG_SLOW)); node = node->next) - node->handler(mach_irq, node->dev_id, fp); + node->handler(irq, node->dev_id, fp); custom.intreq = ami_intena_vals[irq]; if (!node) { server->count--; @@ -338,7 +358,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) slow_nodes = node; for (;;) { for (; node; node = node->next) - node->handler(mach_irq, node->dev_id, fp); + node->handler(irq, node->dev_id, fp); /* if reentrance occured, serve slow handlers again */ custom.intena = ami_intena_vals[irq]; if (!server->reentrance) { @@ -363,19 +383,19 @@ static void ami_int1(int irq, void *dev_id, struct pt_regs *fp) /* if serial transmit buffer empty, interrupt */ if (ints & IF_TBE) { custom.intreq = IF_TBE; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_TBE), fp); + amiga_do_irq(IRQ_AMIGA_TBE, fp); } /* if floppy disk transfer complete, interrupt */ if (ints & IF_DSKBLK) { custom.intreq = IF_DSKBLK; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_DSKBLK), fp); + amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); } /* if software interrupt set, interrupt */ if (ints & IF_SOFT) { custom.intreq = IF_SOFT; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_SOFT), fp); + amiga_do_irq(IRQ_AMIGA_SOFT, fp); } } @@ -387,18 +407,18 @@ static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) /* if a blitter interrupt */ if (ints & IF_BLIT) { custom.intreq = IF_BLIT; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_BLIT), fp); + amiga_do_irq(IRQ_AMIGA_BLIT, fp); } /* if a copper interrupt */ if (ints & IF_COPER) { custom.intreq = IF_COPER; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_COPPER), fp); + amiga_do_irq(IRQ_AMIGA_COPPER, fp); } /* if a vertical blank interrupt */ if (ints & IF_VERTB) - amiga_do_irq_list(IRQ_IDX(IRQ_AMIGA_VERTB), fp, &server); + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); } static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) @@ -408,25 +428,25 @@ static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) /* if audio 0 interrupt */ if (ints & IF_AUD0) { custom.intreq = IF_AUD0; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD0), fp); + amiga_do_irq(IRQ_AMIGA_AUD0, fp); } /* if audio 1 interrupt */ if (ints & IF_AUD1) { custom.intreq = IF_AUD1; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD1), fp); + amiga_do_irq(IRQ_AMIGA_AUD1, fp); } /* if audio 2 interrupt */ if (ints & IF_AUD2) { custom.intreq = IF_AUD2; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD2), fp); + amiga_do_irq(IRQ_AMIGA_AUD2, fp); } /* if audio 3 interrupt */ if (ints & IF_AUD3) { custom.intreq = IF_AUD3; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_AUD3), fp); + amiga_do_irq(IRQ_AMIGA_AUD3, fp); } } @@ -437,13 +457,13 @@ static void ami_int5(int irq, void *dev_id, struct pt_regs *fp) /* if serial receive buffer full interrupt */ if (ints & IF_RBF) { /* acknowledge of IF_RBF must be done by the serial interrupt */ - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_RBF), fp); + amiga_do_irq(IRQ_AMIGA_RBF, fp); } /* if a disk sync interrupt */ if (ints & IF_DSKSYN) { custom.intreq = IF_DSKSYN; - amiga_do_irq(IRQ_IDX(IRQ_AMIGA_DSKSYN), fp); + amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); } } diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c index d0f01dc70..f2e826023 100644 --- a/arch/m68k/amiga/amikeyb.c +++ b/arch/m68k/amiga/amikeyb.c @@ -23,8 +23,6 @@ #include <linux/random.h> #include <linux/kernel.h> -#include <asm/setup.h> -#include <asm/amigatypes.h> #include <asm/amigaints.h> #include <asm/amigahw.h> #include <asm/irq.h> diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index 8b25b1453..b2b2e3055 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -11,7 +11,6 @@ #include <linux/sched.h> #include <linux/timer.h> -#include <asm/amigatypes.h> #include <asm/system.h> #include <asm/amigahw.h> diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c index 28fb0c000..237662c93 100644 --- a/arch/m68k/amiga/chipram.c +++ b/arch/m68k/amiga/chipram.c @@ -8,7 +8,6 @@ #include <linux/types.h> #include <linux/kernel.h> -#include <asm/setup.h> #include <asm/amigahw.h> struct chip_desc { @@ -21,7 +20,7 @@ struct chip_desc { #define DP(ptr) ((struct chip_desc *)(ptr)) -static unsigned long chipsize; +u_long amiga_chip_size; static unsigned long chipavail; /*MILAN*/ /*MILAN*/ @@ -41,22 +40,20 @@ void amiga_chip_init (void) if (!AMIGAHW_PRESENT(CHIP_RAM)) return; - chipsize = boot_info.bi_amiga.chip_size; - /* initialize start boundary */ dp = DP(chipaddr); dp->first = 1; dp->alloced = 0; - dp->length = chipsize - 2*sizeof(*dp); + dp->length = amiga_chip_size - 2*sizeof(*dp); /* initialize end boundary */ - dp = DP(chipaddr + chipsize) - 1; + dp = DP(chipaddr + amiga_chip_size) - 1; dp->last = 1; dp->alloced = 0; - dp->length = chipsize - 2*sizeof(*dp); + dp->length = amiga_chip_size - 2*sizeof(*dp); chipavail = dp->length; /*MILAN*/ #ifdef DEBUG @@ -82,7 +79,7 @@ void *amiga_chip_alloc (long size) * get pointer to descriptor for last chunk by * going backwards from end chunk */ - dp = DP(chipaddr + chipsize) - 1; + dp = DP(chipaddr + amiga_chip_size) - 1; dp = DP((unsigned long)dp - dp->length) - 1; while ((dp->alloced || dp->length < size) diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index 7bf579f39..02b1ad564 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -30,13 +30,13 @@ struct ciabase { irq_handler_t irq_list[CIA_IRQS]; } ciaa_base = { &ciaa, 0, 0, IF_PORTS, - IRQ2, IRQ_AMIGA_CIAA, - IRQ_IDX(IRQ_AMIGA_PORTS), + IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA, + IRQ_AMIGA_PORTS, "CIAA handler", {0, 0} }, ciab_base = { &ciab, 0, 0, IF_EXTER, - IRQ6, IRQ_AMIGA_CIAB, - IRQ_IDX(IRQ_AMIGA_EXTER), + IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB, + IRQ_AMIGA_EXTER, "CIAB handler", {0, 0} }; @@ -95,14 +95,14 @@ int cia_request_irq(struct ciabase *base, unsigned int irq, if (!(base->irq_list[irq].flags & IRQ_FLG_STD)) { if (base->irq_list[irq].flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %ld from %s is not replaceable\n", - __FUNCTION__, IRQ_IDX(base->cia_irq + irq), + printk("%s: IRQ %i from %s is not replaceable\n", + __FUNCTION__, base->cia_irq + irq, base->irq_list[irq].devname); return -EBUSY; } - if (flags & IRQ_FLG_REPLACE) { - printk("%s: %s can't replace IRQ %ld from %s\n", __FUNCTION__, - devname, IRQ_IDX(base->cia_irq + irq), + if (!(flags & IRQ_FLG_REPLACE)) { + printk("%s: %s can't replace IRQ %i from %s\n", __FUNCTION__, + devname, base->cia_irq + irq, base->irq_list[irq].devname); return -EBUSY; } @@ -122,8 +122,8 @@ int cia_request_irq(struct ciabase *base, unsigned int irq, void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id) { if (base->irq_list[irq].dev_id != dev_id) - printk("%s: removing probably wrong IRQ %ld from %s\n", - __FUNCTION__, IRQ_IDX(base->cia_irq + irq), + printk("%s: removing probably wrong IRQ %i from %s\n", + __FUNCTION__, base->cia_irq + irq, base->irq_list[irq].devname); base->irq_list[irq].handler = NULL; @@ -139,7 +139,7 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp) unsigned char ints; mach_irq = base->cia_irq; - irq = SYS_IRQS + IRQ_IDX(mach_irq); + irq = SYS_IRQS + mach_irq; ints = cia_set_irq(base, CIA_ICR_ALL); custom.intreq = base->int_mask; for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) { @@ -176,7 +176,7 @@ int cia_get_irq_list(struct ciabase *base, char *buf) { int i, j, len = 0; - j = IRQ_IDX(base->cia_irq); + j = base->cia_irq; for (i = 0; i < CIA_IRQS; i++) { if (!(base->irq_list[i].flags & IRQ_FLG_STD)) { len += sprintf(buf+len, "cia %2d: %10d ", j + i, diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 72e885d4d..8e6ae531c 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -21,6 +21,7 @@ #include <linux/tty.h> #include <linux/console.h> +#include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -28,13 +29,25 @@ #include <asm/amigaints.h> #include <asm/irq.h> #include <asm/machdep.h> +#include <linux/zorro.h> +u_long amiga_model; +u_long amiga_eclock; u_long amiga_masterclock; u_long amiga_colorclock; +u_long amiga_chipset; +u_char amiga_vblank; +u_char amiga_psfreq; +struct amiga_hw_present amiga_hw_present; + +static const char *amiga_models[] = { + "A500", "A500+", "A600", "A1000", "A1200", "A2000", "A2500", "A3000", + "A3000T", "A3000+", "A4000", "A4000T", "CDTV", "CD32", "Draco" +}; extern char m68k_debug_device[]; -extern void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); @@ -43,143 +56,151 @@ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); extern int amiga_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); -extern int amiga_free_irq (unsigned int irq, void *dev_id); +extern void amiga_free_irq (unsigned int irq, void *dev_id); extern void amiga_enable_irq (unsigned int); extern void amiga_disable_irq (unsigned int); +static void amiga_get_model(char *model); +static int amiga_get_hardware_list(char *buffer); extern int amiga_get_irq_list (char *); /* amiga specific timer functions */ -extern unsigned long amiga_gettimeoffset (void); -extern void a3000_gettod (int *, int *, int *, int *, int *, int *); -extern void a2000_gettod (int *, int *, int *, int *, int *, int *); -extern int amiga_hwclk (int, struct hwclk_time *); -extern int amiga_set_clock_mmss (unsigned long); +static unsigned long amiga_gettimeoffset (void); +static void a3000_gettod (int *, int *, int *, int *, int *, int *); +static void a2000_gettod (int *, int *, int *, int *, int *, int *); +static int amiga_hwclk (int, struct hwclk_time *); +static int amiga_set_clock_mmss (unsigned long); extern void amiga_mksound( unsigned int count, unsigned int ticks ); #ifdef CONFIG_BLK_DEV_FD extern int amiga_floppy_init (void); extern void amiga_floppy_setup(char *, int *); #endif -extern void amiga_reset (void); -extern void amiga_waitbut(void); +static void amiga_reset (void); +static void amiga_wait_key(void); extern struct consw fb_con; extern struct fb_info *amiga_fb_init(long *); extern void zorro_init(void); -static void ami_savekmsg_init(void); -static void ami_mem_print(const char *b); -extern void amiga_debug_init(void); +static void amiga_savekmsg_init(void); +static void amiga_mem_console_write(const char *b, unsigned int count); +static void amiga_serial_console_write(const char *s, unsigned int count); +static void amiga_debug_init(void); + extern void amiga_video_setup(char *, int *); +static struct console amiga_console_driver = { + NULL, NULL, amiga_wait_key +}; + extern void (*kd_mksound)(unsigned int, unsigned int); + /* + * Parse an Amiga-specific record in the bootinfo + */ + +int amiga_parse_bootinfo(const struct bi_record *record) +{ + int unknown = 0; + const u_long *data = record->data; + + switch (record->tag) { + case BI_AMIGA_MODEL: + amiga_model = *data; + break; + + case BI_AMIGA_ECLOCK: + amiga_eclock = *data; + break; + + case BI_AMIGA_CHIPSET: + amiga_chipset = *data; + break; + + case BI_AMIGA_CHIP_SIZE: + amiga_chip_size = *(const int *)data; + break; + + case BI_AMIGA_VBLANK: + amiga_vblank = *(const u_char *)data; + break; + + case BI_AMIGA_PSFREQ: + amiga_psfreq = *(const u_char *)data; + break; + + case BI_AMIGA_AUTOCON: + if (zorro_num_autocon < ZORRO_NUM_AUTO) + memcpy(&zorro_autocon[zorro_num_autocon++], + (const struct ConfigDev *)data, + sizeof(struct ConfigDev)); + else + printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); + break; + + case BI_AMIGA_SERPER: + /* serial port period: ignored here */ + break; + + default: + unknown = 1; + } + return(unknown); +} + + /* + * Setup the Amiga configuration info + */ + void config_amiga(void) { - char *type = NULL; + /* Fill in some default values, if necessary */ + if (amiga_eclock == 0) + amiga_eclock = 709379; + + memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); + + amiga_debug_init(); - switch(boot_info.bi_amiga.model) { - case AMI_500: - type = "A500"; - break; - case AMI_500PLUS: - type = "A500+"; - break; - case AMI_600: - type = "A600"; - break; - case AMI_1000: - type = "A1000"; - break; - case AMI_1200: - type = "A1200"; - break; - case AMI_2000: - type = "A2000"; - break; - case AMI_2500: - type = "A2500"; - break; - case AMI_3000: - type = "A3000"; - break; - case AMI_3000T: - type = "A3000T"; - break; - case AMI_3000PLUS: - type = "A3000+"; - break; - case AMI_4000: - type = "A4000"; - break; - case AMI_4000T: - type = "A4000T"; - break; - case AMI_CDTV: - type = "CDTV"; - break; - case AMI_CD32: - type = "CD32"; - break; - case AMI_DRACO: - type = "Draco"; - break; - } printk("Amiga hardware found: "); - if (type) - printk("[%s] ", type); - switch(boot_info.bi_amiga.model) { - case AMI_UNKNOWN: - goto Generic; + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + printk("[%s] ", amiga_models[amiga_model-AMI_500]); - case AMI_500: - case AMI_500PLUS: - case AMI_1000: - AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - printk("A2000_CLK "); + switch(amiga_model) { + case AMI_UNKNOWN: goto Generic; case AMI_600: case AMI_1200: AMIGAHW_SET(A1200_IDE); - printk("A1200_IDE "); - AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - printk("A2000_CLK "); - goto Generic; - + case AMI_500: + case AMI_500PLUS: + case AMI_1000: case AMI_2000: case AMI_2500: - AMIGAHW_SET(A2000_CLK); - printk("A2000_CLK "); + AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ goto Generic; case AMI_3000: case AMI_3000T: AMIGAHW_SET(AMBER_FF); - printk("AMBER_FF "); AMIGAHW_SET(MAGIC_REKICK); - printk("MAGIC_REKICK "); /* fall through */ case AMI_3000PLUS: AMIGAHW_SET(A3000_SCSI); - printk("A3000_SCSI "); AMIGAHW_SET(A3000_CLK); - printk("A3000_CLK "); + AMIGAHW_SET(ZORRO3); goto Generic; case AMI_4000T: AMIGAHW_SET(A4000_SCSI); - printk("A4000_SCSI "); /* fall through */ case AMI_4000: AMIGAHW_SET(A4000_IDE); - printk("A4000_IDE "); AMIGAHW_SET(A3000_CLK); - printk("A3000_CLK "); + AMIGAHW_SET(ZORRO3); goto Generic; case AMI_CDTV: case AMI_CD32: AMIGAHW_SET(CD_ROM); - printk("CD_ROM "); AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - printk("A2000_CLK "); goto Generic; Generic: @@ -193,61 +214,49 @@ void config_amiga(void) AMIGAHW_SET(AMI_PARALLEL); AMIGAHW_SET(CHIP_RAM); AMIGAHW_SET(PAULA); - printk("VIDEO BLITTER AUDIO FLOPPY KEYBOARD MOUSE SERIAL PARALLEL " - "CHIP_RAM PAULA "); - switch(boot_info.bi_amiga.chipset) { + switch(amiga_chipset) { case CS_OCS: case CS_ECS: case CS_AGA: switch (custom.deniseid & 0xf) { case 0x0c: AMIGAHW_SET(DENISE_HR); - printk("DENISE_HR "); break; case 0x08: AMIGAHW_SET(LISA); - printk("LISA "); break; } break; default: AMIGAHW_SET(DENISE); - printk("DENISE "); break; } switch ((custom.vposr>>8) & 0x7f) { case 0x00: AMIGAHW_SET(AGNUS_PAL); - printk("AGNUS_PAL "); break; case 0x10: AMIGAHW_SET(AGNUS_NTSC); - printk("AGNUS_NTSC "); break; case 0x20: case 0x21: AMIGAHW_SET(AGNUS_HR_PAL); - printk("AGNUS_HR_PAL "); break; case 0x30: case 0x31: AMIGAHW_SET(AGNUS_HR_NTSC); - printk("AGNUS_HR_NTSC "); break; case 0x22: case 0x23: AMIGAHW_SET(ALICE_PAL); - printk("ALICE_PAL "); break; case 0x32: case 0x33: AMIGAHW_SET(ALICE_NTSC); - printk("ALICE_NTSC "); break; } AMIGAHW_SET(ZORRO); - printk("ZORRO "); break; case AMI_DRACO: @@ -256,8 +265,45 @@ void config_amiga(void) default: panic("Unknown Amiga Model"); } + +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + printk(str) + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); + AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); + AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); + AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); + AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); + AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); + AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); + AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); + AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); + AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); + AMIGAHW_ANNOUNCE(PAULA, "PAULA "); + AMIGAHW_ANNOUNCE(DENISE, "DENISE "); + AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); + AMIGAHW_ANNOUNCE(LISA, "LISA "); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); + AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); + if (AMIGAHW_SET(ZORRO)) + printk("ZORRO%s ", AMIGAHW_SET(ZORRO3) ? "3" : ""); printk("\n"); - + +#undef AMIGAHW_ANNOUNCE + mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; @@ -265,8 +311,10 @@ void config_amiga(void) mach_default_handler = &amiga_default_handler; mach_request_irq = amiga_request_irq; mach_free_irq = amiga_free_irq; - mach_enable_irq = amiga_enable_irq; - mach_disable_irq = amiga_disable_irq; + enable_irq = amiga_enable_irq; + disable_irq = amiga_disable_irq; + mach_get_model = amiga_get_model; + mach_get_hardware_list = amiga_get_hardware_list; mach_get_irq_list = amiga_get_irq_list; mach_gettimeoffset = amiga_gettimeoffset; if (AMIGAHW_PRESENT(A3000_CLK)){ @@ -288,22 +336,19 @@ void config_amiga(void) mach_hwclk = amiga_hwclk; mach_set_clock_mmss = amiga_set_clock_mmss; - mach_mksound = amiga_mksound; #ifdef CONFIG_BLK_DEV_FD mach_floppy_init = amiga_floppy_init; mach_floppy_setup = amiga_floppy_setup; #endif mach_reset = amiga_reset; - waitbut = amiga_waitbut; conswitchp = &fb_con; mach_fb_init = amiga_fb_init; - mach_debug_init = amiga_debug_init; mach_video_setup = amiga_video_setup; kd_mksound = amiga_mksound; /* Fill in the clock values (based on the 700 kHz E-Clock) */ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ - amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ + amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ /* clear all DMA bits */ custom.dmacon = DMAF_ALL; @@ -313,10 +358,6 @@ void config_amiga(void) /* initialize chipram allocator */ amiga_chip_init (); - /* initialize only once here, not every time the debug level is raised */ - if (!strcmp( m68k_debug_device, "mem" )) - ami_savekmsg_init(); - /* * if it is an A3000, set the magic bit that forces * a hard rekick @@ -335,7 +376,8 @@ void config_amiga(void) static unsigned short jiffy_ticks; -void amiga_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +static void amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *)) { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -356,7 +398,7 @@ void amiga_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) #define TICK_SIZE 10000 /* This is always executed with interrupts disabled. */ -unsigned long amiga_gettimeoffset (void) +static unsigned long amiga_gettimeoffset (void) { unsigned short hi, lo, hi2; unsigned long ticks, offset = 0; @@ -384,8 +426,8 @@ unsigned long amiga_gettimeoffset (void) return ticks + offset; } -void a3000_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +static void a3000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { volatile struct tod3000 *tod = TOD_3000; @@ -401,8 +443,8 @@ void a3000_gettod (int *yearp, int *monp, int *dayp, tod->cntrl1 = TOD3000_CNTRL1_FREE; } -void a2000_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +static void a2000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { volatile struct tod2000 *tod = TOD_2000; @@ -427,7 +469,7 @@ void a2000_gettod (int *yearp, int *monp, int *dayp, tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; } -int amiga_hwclk(int op, struct hwclk_time *t) +static int amiga_hwclk(int op, struct hwclk_time *t) { if (AMIGAHW_PRESENT(A3000_CLK)) { volatile struct tod3000 *tod = TOD_3000; @@ -511,7 +553,7 @@ int amiga_hwclk(int op, struct hwclk_time *t) return 0; } -int amiga_set_clock_mmss (unsigned long nowtime) +static int amiga_set_clock_mmss (unsigned long nowtime) { short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; @@ -545,7 +587,7 @@ int amiga_set_clock_mmss (unsigned long nowtime) return 0; } -void amiga_waitbut (void) +static void amiga_wait_key (void) { int i; @@ -571,33 +613,6 @@ void amiga_waitbut (void) } } -void ami_serial_print (const char *str) -{ - while (*str) { - if (*str == '\n') { - custom.serdat = (unsigned char)'\r' | 0x100; - while (!(custom.serdatr & 0x2000)) - ; - } - custom.serdat = (unsigned char)*str++ | 0x100; - while (!(custom.serdatr & 0x2000)) - ; - } -} - -void amiga_debug_init (void) -{ - extern void (*debug_print_proc)(const char *); - - if (!strcmp( m68k_debug_device, "ser" )) { - /* no initialization required (?) */ - debug_print_proc = ami_serial_print; - } else if (!strcmp( m68k_debug_device, "mem" )) { - /* already initialized by config_amiga() (needed only once) */ - debug_print_proc = ami_mem_print; - } -} - void dbprintf(const char *fmt , ...) { static char buf[1024]; @@ -612,10 +627,10 @@ void dbprintf(const char *fmt , ...) console_print (buf); } -NORET_TYPE void amiga_reset( void ) +static NORET_TYPE void amiga_reset( void ) ATTRIB_NORET; -void amiga_reset (void) +static void amiga_reset (void) { unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040); unsigned long jmp_addr = VTOP(&&jmp_addr_label); @@ -629,8 +644,10 @@ void amiga_reset (void) ("movel %0,%/d0\n\t" "andl #0xff000000,%/d0\n\t" "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ - ".long 0x4e7b0004\n\t" /* movec d0,itt0 */ - ".long 0x4e7b0006\n\t" /* movec d0,dtt0 */ + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" "jmp %0@\n\t" : /* no outputs */ : "a" (jmp_addr040)); @@ -649,7 +666,9 @@ void amiga_reset (void) /* disable translation on '040 now */ __asm__ __volatile__ ("moveq #0,%/d0\n\t" - ".long 0x4e7b0003\n\t" /* movec d0,tc; disable MMU */ + ".chip 68040\n\t" + "movec %%d0,%%tc\n\t" /* disable MMU */ + ".chip 68k\n\t" : /* no outputs */ : /* no inputs */ : "d0"); @@ -675,12 +694,13 @@ void amiga_reset (void) } -extern void *amiga_chip_alloc(long size); + /* + * Debugging + */ #define SAVEKMSG_MAXMEM 128*1024 - #define SAVEKMSG_MAGIC1 0x53415645 /* 'SAVE' */ #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ @@ -694,8 +714,15 @@ struct savekmsg { static struct savekmsg *savekmsg = NULL; +static void amiga_mem_console_write(const char *s, unsigned int count) +{ + if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { + memcpy(savekmsg->data+savekmsg->size, s, count); + savekmsg->size += count; + } +} -static void ami_savekmsg_init(void) +static void amiga_savekmsg_init(void) { savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM); savekmsg->magic1 = SAVEKMSG_MAGIC1; @@ -704,84 +731,107 @@ static void ami_savekmsg_init(void) savekmsg->size = 0; } - -static void ami_mem_print(const char *b) +static void amiga_serial_putc(char c) { - int len; + custom.serdat = (unsigned char)c | 0x100; + while (!(custom.serdatr & 0x2000)) + ; +} - for (len = 0; b[len]; len++); - if (savekmsg->size+len <= SAVEKMSG_MAXMEM) { - memcpy(savekmsg->data+savekmsg->size, b, len); - savekmsg->size += len; +static void amiga_serial_console_write(const char *s, unsigned int count) +{ + while (count--) { + if (*s == '\n') + amiga_serial_putc('\r'); + amiga_serial_putc(*s++); } } +#ifdef CONFIG_SERIAL_CONSOLE +void amiga_serial_puts(const char *s) +{ + amiga_serial_console_write(s, strlen(s)); +} -void amiga_get_model(char *model) +void amiga_serial_gets(char *s, int len) { - strcpy(model, "Amiga "); - switch (boot_info.bi_amiga.model) { - case AMI_500: - strcat(model, "500"); - break; - case AMI_500PLUS: - strcat(model, "500+"); - break; - case AMI_600: - strcat(model, "600"); - break; - case AMI_1000: - strcat(model, "1000"); - break; - case AMI_1200: - strcat(model, "1200"); - break; - case AMI_2000: - strcat(model, "2000"); - break; - case AMI_2500: - strcat(model, "2500"); - break; - case AMI_3000: - strcat(model, "3000"); - break; - case AMI_3000T: - strcat(model, "3000T"); - break; - case AMI_3000PLUS: - strcat(model, "3000+"); - break; - case AMI_4000: - strcat(model, "4000"); - break; - case AMI_4000T: - strcat(model, "4000T"); - break; - case AMI_CDTV: - strcat(model, "CDTV"); - break; - case AMI_CD32: - strcat(model, "CD32"); - break; - case AMI_DRACO: - strcpy(model, "DRACO"); + int ch, cnt = 0; + + while (1) { + while (!(custom.intreqr & IF_RBF)) + barrier(); + ch = custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + + /* Check for backspace. */ + if (ch == 8 || ch == 127) { + if (cnt == 0) { + amiga_serial_putc('\007'); + continue; + } + cnt--; + amiga_serial_puts("\010 \010"); + continue; + } + + /* Check for enter. */ + if (ch == 10 || ch == 13) break; + + /* See if line is too long. */ + if (cnt >= len + 1) { + amiga_serial_putc(7); + cnt--; + continue; + } + + /* Store and echo character. */ + s[cnt++] = ch; + amiga_serial_putc(ch); + } + /* Print enter. */ + amiga_serial_puts("\r\n"); + s[cnt] = 0; +} +#endif + +static void amiga_debug_init(void) +{ + if (!strcmp( m68k_debug_device, "ser" )) { + /* no initialization required (?) */ + amiga_console_driver.write = amiga_serial_console_write; + } else if (!strcmp( m68k_debug_device, "mem" )) { + amiga_savekmsg_init(); + amiga_console_driver.write = amiga_mem_console_write; } + register_console(&amiga_console_driver); } -int amiga_get_hardware_list(char *buffer) + /* + * Amiga specific parts of /proc + */ + +static void amiga_get_model(char *model) +{ + strcpy(model, "Amiga "); + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + strcat(model, amiga_models[amiga_model-AMI_500]); +} + + +static int amiga_get_hardware_list(char *buffer) { int len = 0; if (AMIGAHW_PRESENT(CHIP_RAM)) - len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", - boot_info.bi_amiga.chip_size>>10); + len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", - boot_info.bi_amiga.psfreq, amiga_eclock); + amiga_psfreq, amiga_eclock); if (AMIGAHW_PRESENT(AMI_VIDEO)) { char *type; - switch(boot_info.bi_amiga.chipset) { + switch(amiga_chipset) { case CS_OCS: type = "OCS"; break; @@ -798,7 +848,7 @@ int amiga_get_hardware_list(char *buffer) len += sprintf(buffer+len, "Graphics:\t%s\n", type); } -#define AMIGAHW_ANNOUNCE(name, str) \ +#define AMIGAHW_ANNOUNCE(name, str) \ if (AMIGAHW_PRESENT(name)) \ len += sprintf (buffer+len, "\t%s\n", str) @@ -833,9 +883,11 @@ int amiga_get_hardware_list(char *buffer) AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); if (AMIGAHW_PRESENT(ZORRO)) - len += sprintf(buffer+len, "\tZorro AutoConfig: %d Expansion Device%s\n", - boot_info.bi_amiga.num_autocon, - boot_info.bi_amiga.num_autocon == 1 ? "" : "s"); + len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n", + AMIGAHW_PRESENT(ZORRO3) ? " III" : "", + zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + +#undef AMIGAHW_ANNOUNCE return(len); } diff --git a/arch/m68k/amiga/cyberfb.c b/arch/m68k/amiga/cyberfb.c index dc2515371..d74d52c4f 100644 --- a/arch/m68k/amiga/cyberfb.c +++ b/arch/m68k/amiga/cyberfb.c @@ -32,7 +32,7 @@ #include <asm/uaccess.h> #include <asm/system.h> #include <asm/irq.h> -#include <asm/zorro.h> +#include <linux/zorro.h> #include <asm/pgtable.h> #include <linux/fb.h> #include "s3blit.h" @@ -235,6 +235,7 @@ struct fb_info *Cyber_fb_init(long *mem_start); /* Through amiga_fb_init() */ static int Cyberfb_switch(int con); static int Cyberfb_updatevar(int con); static void Cyberfb_blank(int blank); +static int Cyberfb_setcmap(struct fb_cmap *cmap, int con); /* @@ -424,6 +425,7 @@ static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, fix->xpanstep = 0; fix->ypanstep = 0; fix->ywrapstep = 0; + fix->line_length = 0; for (i = 0; i < arraysize(fix->reserved); i++) fix->reserved[i] = 0; @@ -896,10 +898,10 @@ static void memcpy_fs(int fsfromto, void *to, void *from, int len) memcpy(to, from, len); return; case 1: - memcpy_fromfs(to, from, len); + copy_from_user(to, from, len); return; case 2: - memcpy_tofs(to, from, len); + copy_to_user(to, from, len); return; } } @@ -1178,6 +1180,7 @@ struct fb_info *Cyber_fb_init(long *mem_start) fb_info.switch_con = &Cyberfb_switch; fb_info.updatevar = &Cyberfb_updatevar; fb_info.blank = &Cyberfb_blank; + fb_info.setcmap = &Cyberfb_setcmap; do_fb_set_var(&Cyber_fb_predefined[0], 1); Cyber_fb_get_var(&disp[0].var, -1); @@ -1225,6 +1228,16 @@ static void Cyberfb_blank(int blank) /* + * Set the colormap + */ + +static int Cyberfb_setcmap(struct fb_cmap *cmap, int con) +{ + return(Cyber_fb_set_cmap(cmap, 1, con)); +} + + + /* * Get a Video Mode */ diff --git a/arch/m68k/amiga/ksyms.c b/arch/m68k/amiga/ksyms.c deleted file mode 100644 index b306867c1..000000000 --- a/arch/m68k/amiga/ksyms.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <linux/module.h> -#include <asm/zorro.h> -#include <asm/amigatypes.h> -#include <asm/amigahw.h> -#include <asm/amigatypes.h> - -extern volatile u_short amiga_audio_min_period; -extern u_short amiga_audio_period; - -static struct symbol_table mach_amiga_symbol_table = { -#include <linux/symtab_begin.h> - - /* - * Add things here when you find the need for it. - */ - X(amiga_colorclock), - X(amiga_chip_alloc), - X(amiga_chip_free), - X(amiga_chip_avail), - X(amiga_audio_period), - X(amiga_audio_min_period), - - X(zorro_find), - X(zorro_get_board), - X(zorro_config_board), - X(zorro_unconfig_board), - X(zorro_unused_z2ram), - - /* example - X(something_you_need), - */ - - -#include <linux/symtab_end.h> -}; - -void mach_amiga_syms_export(void) -{ - register_symtab(&mach_amiga_symbol_table); -} diff --git a/arch/m68k/amiga/retz3fb.c b/arch/m68k/amiga/retz3fb.c new file mode 100644 index 000000000..4885e48f7 --- /dev/null +++ b/arch/m68k/amiga/retz3fb.c @@ -0,0 +1,3504 @@ +/* + * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the + * RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * This file is based on the CyberVision64 frame buffer device and + * the generic Cirrus Logic driver. + * + * cyberfb.c: Copyright (C) 1996 Martin Apel, + * Geert Uytterhoeven + * clgen.c: Copyright (C) 1996 Frank Neumann + * + * History: + * - 22 Jan 97: Initial work + * - 14 Feb 97: Screen initialization works somewhat, still only + * 8-bit packed pixel is supported. + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <linux/zorro.h> +#include <asm/pgtable.h> + +#include "retz3fb.h" + +/* #define DEBUG if(1) */ +#define DEBUG if(0) + +/* + * Reserve space for one pattern line. + * + * For the time being we only support 4MB boards! + */ + +#define PAT_MEM_SIZE 16*3 +#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct retz3_fb_par { + int xres; + int yres; + int xres_vir; + int yres_vir; + int xoffset; + int yoffset; + int bpp; + + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + + int pixclock; + int left_margin; /* time from sync to picture */ + int right_margin; /* time from picture to sync */ + int upper_margin; /* time from sync to picture */ + int lower_margin; + int hsync_len; /* length of horizontal sync */ + int vsync_len; /* length of vertical sync */ + int vmode; +}; + +struct display_data { + long h_total; /* Horizontal Total */ + long h_sstart; /* Horizontal Sync Start */ + long h_sstop; /* Horizontal Sync Stop */ + long h_bstart; /* Horizontal Blank Start */ + long h_bstop; /* Horizontal Blank Stop */ + long h_dispend; /* Horizontal Display End */ + long v_total; /* Vertical Total */ + long v_sstart; /* Vertical Sync Start */ + long v_sstop; /* Vertical Sync Stop */ + long v_bstart; /* Vertical Blank Start */ + long v_bstop; /* Vertical Blank Stop */ + long v_dispend; /* Horizontal Display End */ +}; + +static struct retz3_fb_par current_par; + +static int current_par_valid = 0; +static int currcon = 0; + +static struct display disp[MAX_NR_CONSOLES]; +static struct fb_info fb_info; + +static int node; /* node of the /dev/fb?current file */ + + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned + int *green, unsigned int *blue, unsigned int *transp); + int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int + green, unsigned int blue, unsigned int transp); + void (*blank)(int blank); +} *fbhw; + + +/* + * Frame Buffer Name + */ + +static char retz3_fb_name[16] = "RetinaZ3"; + + +static int z3_key = 0; +static unsigned char retz3_color_table [256][4]; +static unsigned long z3_mem; +static unsigned long z3_fbmem; +static unsigned long z3_size; +static volatile unsigned char *z3_regs; + +static long *memstart; + + +/* + * Predefined Video Mode Names + */ + +static char *retz3_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * Predefined Video Modes + */ + + "640x480", /* RetinaZ3 8 bpp */ + "800x600", /* RetinaZ3 8 bpp */ + "1024x768i", + "640x480-16", /* RetinaZ3 16 bpp */ + "640x480-24", /* RetinaZ3 24 bpp */ + + /* + * Dummy Video Modes + */ + + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + + /* + * User Defined Video Modes + * + * This doesn't work yet!! + */ + + "user0", "user1", "user2", "user3", + "user4", "user5", "user6", "user7" +}; + +/* + * A small info on how to convert XFree86 timing values into fb + * timings - by Frank Neumann: + * +An XFree86 mode line consists of the following fields: + "800x600" 50 800 856 976 1040 600 637 643 666 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + +The fields in the fb_var_screeninfo structure are: + unsigned long pixclock; * pixel clock in ps (pico seconds) * + unsigned long left_margin; * time from sync to picture * + unsigned long right_margin; * time from picture to sync * + unsigned long upper_margin; * time from sync to picture * + unsigned long lower_margin; + unsigned long hsync_len; * length of horizontal sync * + unsigned long vsync_len; * length of vertical sync * + +1) Pixelclock: + xfree: in MHz + fb: In Picoseconds (ps) + + pixclock = 1000000 / DCF + +2) horizontal timings: + left_margin = HFL - SH2 + right_margin = SH1 - HR + hsync_len = SH2 - SH1 + +3) vertical timings: + upper_margin = VFL - SV2 + lower_margin = SV1 - VR + vsync_len = SV2 - SV1 + +Good examples for VESA timings can be found in the XFree86 source tree, +under "programs/Xserver/hw/xfree86/doc/modeDB.txt". +*/ + +/* + * Predefined Video Mode Definitions + */ + +static struct fb_var_screeninfo retz3_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * Predefined Video Modes + */ + + /* + * NB: it is very important to adjust the pixel-clock to the color-depth. + */ + + { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 800 x 600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 1024 x 768, 8 bpp, interlaced */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 24, 0, + {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + + /* + * Dummy Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + + +#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined) +#define NUM_PREDEF_MODES (5) + + +static int z3fb_inverse = 0; +static int z3fb_mode = 0; + + +/* + * Interface used by the world + */ + +int retz3_probe(void); +void retz3_video_setup(char *options, int *ints); + +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con); + + +/* + * Interface to the low level console driver + */ + +struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */ +static int z3fb_switch(int con); +static int z3fb_updatevar(int con); +static void z3fb_blank(int blank); +static int z3fb_setcmap(struct fb_cmap *cmap, int con); + + +/* + * Accelerated Functions used by the low level console driver + */ + +void retz3_bitblt(struct fb_var_screeninfo *scr, + unsigned short curx, unsigned short cury, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); +void retz3_fill(unsigned short x, unsigned short y, unsigned short + width, unsigned short height, unsigned short mode, + unsigned short color); + +/* + * Hardware Specific Routines + */ + +static int retz3_init(void); +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par); +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp); +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp); +static void retz3_blank(int blank); + + +/* + * Internal routines + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par); +static void retz3_fb_set_par(struct retz3_fb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static struct fb_cmap *get_default_colormap(int bpp); +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static void do_install_cmap(int con); +static void memcpy_fs(int fsfromto, void *to, void *from, int len); +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto); +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp); +static void retz3_fb_set_disp(int con); +static int get_video_mode(const char *name); + + +/* -------------------- Hardware specific routines -------------------------- */ + +static unsigned short find_fq(unsigned int freq) +{ + unsigned long f; + long tmp; + long prev = 0x7fffffff; + long n2, n1 = 3; + unsigned long m; + unsigned short res = 0; + + if (freq <= 31250000) + n2 = 3; + else if (freq <= 62500000) + n2 = 2; + else if (freq <= 125000000) + n2 = 1; + else if (freq <= 250000000) + n2 = 0; + else + return(0); + + + do { + f = freq >> (10 - n2); + + m = (f * n1) / (14318180/1024); + + if (m > 129) + break; + + tmp = (((m * 14318180) >> n2) / n1) - freq; + if (tmp < 0) + tmp = -tmp; + + if (tmp < prev) { + prev = tmp; + res = (((n2 << 5) | (n1-2)) << 8) | (m-2); + } + + } while ( (++n1) <= 21); + + return res; +} + + +static int retz3_set_video(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + float freq_f; + long freq; + + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + unsigned char tmp; + unsigned short best_freq; + struct display_data data; + + short clocksel = 0; /* Apparantly this is always zero */ + + int bpp = var->bits_per_pixel; + + /* + * XXX + */ + if (bpp == 24) + return 0; + + if ((bpp != 8) && (bpp != 16) && (bpp != 24)) + return -EFAULT; + + par->xoffset = 0; + par->yoffset = 0; + + xres = var->xres * bpp / 4; + hfront = var->right_margin * bpp / 4; + hsync = var->hsync_len * bpp / 4; + hback = var->left_margin * bpp / 4; + + if (var->vmode & FB_VMODE_DOUBLE) + { + yres = var->yres * 2; + vfront = var->lower_margin * 2; + vsync = var->vsync_len * 2; + vback = var->upper_margin * 2; + } + else if (var->vmode & FB_VMODE_INTERLACED) + { + yres = (var->yres + 1) / 2; + vfront = (var->lower_margin + 1) / 2; + vsync = (var->vsync_len + 1) / 2; + vback = (var->upper_margin + 1) / 2; + } + else + { + yres = var->yres; /* -1 ? */ + vfront = var->lower_margin; + vsync = var->vsync_len; + vback = var->upper_margin; + } + + data.h_total = (hback / 8) + (xres / 8) + + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; + data.h_dispend = ((xres + bpp - 1)/ 8) - 1; + data.h_bstart = xres / 8 /* + 1 */; + + data.h_bstop = data.h_total+1 + 2 + 1; + data.h_sstart = (xres / 8) + (hfront / 8) + 1; + data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; + + data.v_total = yres + vfront + vsync + vback - 1; + + data.v_dispend = yres - 1; + data.v_bstart = yres; + + data.v_bstop = data.v_total; + data.v_sstart = yres + vfront - 1 - 2; + data.v_sstop = yres + vfront + vsync - 1; + +#if 0 /* testing */ + + printk("HBS: %i\n", data.h_bstart); + printk("HSS: %i\n", data.h_sstart); + printk("HSE: %i\n", data.h_sstop); + printk("HBE: %i\n", data.h_bstop); + printk("HT: %i\n", data.h_total); + + printk("hsync: %i\n", hsync); + printk("hfront: %i\n", hfront); + printk("hback: %i\n", hback); + + printk("VBS: %i\n", data.v_bstart); + printk("VSS: %i\n", data.v_sstart); + printk("VSE: %i\n", data.v_sstop); + printk("VBE: %i\n", data.v_bstop); + printk("VT: %i\n", data.v_total); + + printk("vsync: %i\n", vsync); + printk("vfront: %i\n", vfront); + printk("vback: %i\n", vback); +#endif + + if (data.v_total >= 1024) + printk("MAYDAY: v_total >= 1024; bailing out!\n"); + + reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); + reg_w(GREG_FEATURE_CONTROL_W, 0x00); + + seq_w(SEQ_RESET, 0x00); + seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ + + /* + * CLOCKING_MODE bits: + * 2: This one is only set for certain text-modes, wonder if + * it may be for EGA-lines? (it was referred to as CLKDIV2) + * (The CL drivers sets it to 0x21 with the comment: + * FullBandwidth (video off) and 8/9 dot clock) + */ + seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); + + seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ + seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ + seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ + seq_w(SEQ_RESET, 0x01); + seq_w(SEQ_RESET, 0x03); + + seq_w(SEQ_EXTENDED_ENABLE, 0x05); + + seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_LINEAR_0, 0x4a); + seq_w(SEQ_LINEAR_1, 0x00); + + seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); + seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); + seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); + + /* + * The lower 4 bits (0-3) are used to set the font-width for + * text-mode - DON'T try to set this for gfx-mode. + */ + seq_w(SEQ_EXT_CLOCK_MODE, 0x10); + seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); + + /* + * Extended Pixel Control: + * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) + * bit 1: (Packed/Nibble Pixel Format ?) + * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp + */ + seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); + + seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); + seq_w(SEQ_COLOR_EXP_WFG, 0x01); + seq_w(SEQ_COLOR_EXP_WBG, 0x00); + seq_w(SEQ_EXT_RW_CONTROL, 0x00); + seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); + seq_w(SEQ_COLOR_KEY_CNTL, 0x40); + seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); + seq_w(SEQ_CRC_CONTROL, 0x00); + seq_w(SEQ_PERF_SELECT, 0x10); + seq_w(SEQ_ACM_APERTURE_1, 0x00); + seq_w(SEQ_ACM_APERTURE_2, 0x30); + seq_w(SEQ_ACM_APERTURE_3, 0x00); + seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); + + + /* unlock register CRT0..CRT7 */ + crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); + + /* Zuerst zu schreibende Werte nur per printk ausgeben */ + DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); + crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); + + DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); + crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); + + DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); + crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); + + DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); + crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); + + DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); + crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); + + tmp = (data.h_sstop & 0x1f); + if (data.h_bstop & 0x20) + tmp |= 0x80; + DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); + crt_w(CRT_END_HOR_RETR, tmp); + + DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); + crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); + + tmp = 0x10; /* LineCompare bit #9 */ + if (data.v_total & 256) + tmp |= 0x01; + if (data.v_dispend & 256) + tmp |= 0x02; + if (data.v_sstart & 256) + tmp |= 0x04; + if (data.v_bstart & 256) + tmp |= 0x08; + if (data.v_total & 512) + tmp |= 0x20; + if (data.v_dispend & 512) + tmp |= 0x40; + if (data.v_sstart & 512) + tmp |= 0x80; + DEBUG printk("CRT_OVERFLOW: %d\n", tmp); + crt_w(CRT_OVERFLOW, tmp); + + crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ + + tmp = 0x40; /* LineCompare bit #8 */ + if (data.v_bstart & 512) + tmp |= 0x20; + if (var->vmode & FB_VMODE_DOUBLE) + tmp |= 0x80; + DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); + crt_w(CRT_MAX_SCAN_LINE, tmp); + + crt_w(CRT_CURSOR_START, 0x00); + crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ + + crt_w(CRT_START_ADDR_HIGH, 0x00); + crt_w(CRT_START_ADDR_LOW, 0x00); + + crt_w(CRT_CURSOR_LOC_HIGH, 0x00); + crt_w(CRT_CURSOR_LOC_LOW, 0x00); + + DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); + crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); + +#if 1 + /* 5 refresh cycles per scanline */ + DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); +#else + DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); +#endif + DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); + crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); + + DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); + crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); + + DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); + crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); + + DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); + crt_w(CRT_MODE_CONTROL, 0xe3); + + DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); + crt_w(CRT_LINE_COMPARE, 0xff); + + tmp = (var->xres_virtual / 8) * (bpp / 8); + crt_w(CRT_OFFSET, tmp); + + crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ + + tmp = 0x20; /* Enable extended end bits */ + if (data.h_total & 0x100) + tmp |= 0x01; + if ((data.h_dispend) & 0x100) + tmp |= 0x02; + if (data.h_bstart & 0x100) + tmp |= 0x04; + if (data.h_sstart & 0x100) + tmp |= 0x08; + if (var->vmode & FB_VMODE_INTERLACED) + tmp |= 0x10; + DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); + crt_w(CRT_EXT_HOR_TIMING1, tmp); + + tmp = 0x00; + if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) + tmp |= 0x10; + crt_w(CRT_EXT_START_ADDR, tmp); + + tmp = 0x00; + if (data.h_total & 0x200) + tmp |= 0x01; + if ((data.h_dispend) & 0x200) + tmp |= 0x02; + if (data.h_bstart & 0x200) + tmp |= 0x04; + if (data.h_sstart & 0x200) + tmp |= 0x08; + tmp |= ((data.h_bstop & 0xc0) >> 2); + tmp |= ((data.h_sstop & 0x60) << 1); + crt_w(CRT_EXT_HOR_TIMING2, tmp); + DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); + + tmp = 0x10; /* Line compare bit 10 */ + if (data.v_total & 0x400) + tmp |= 0x01; + if ((data.v_dispend) & 0x400) + tmp |= 0x02; + if (data.v_bstart & 0x400) + tmp |= 0x04; + if (data.v_sstart & 0x400) + tmp |= 0x08; + tmp |= ((data.v_bstop & 0x300) >> 3); + if (data.v_sstop & 0x10) + tmp |= 0x80; + crt_w(CRT_EXT_VER_TIMING, tmp); + DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); + + crt_w(CRT_MONITOR_POWER, 0x00); + + /* + * Convert from ps to Hz. + */ + freq_f = (1.0/(float)var->pixclock) * 1000000000; + freq = ((long)freq_f) * 1000; + + best_freq = find_fq(freq); + pll_w(0x02, best_freq); + best_freq = find_fq(61000000); + pll_w(0x0a, best_freq); + pll_w(0x0e, 0x22); + + gfx_w(GFX_SET_RESET, 0x00); + gfx_w(GFX_ENABLE_SET_RESET, 0x00); + gfx_w(GFX_COLOR_COMPARE, 0x00); + gfx_w(GFX_DATA_ROTATE, 0x00); + gfx_w(GFX_READ_MAP_SELECT, 0x00); + gfx_w(GFX_GRAPHICS_MODE, 0x00); + gfx_w(GFX_MISC, 0x05); + gfx_w(GFX_COLOR_XCARE, 0x0f); + gfx_w(GFX_BITMASK, 0xff); + + reg_r(ACT_ADDRESS_RESET); + attr_w(ACT_PALETTE0 , 0x00); + attr_w(ACT_PALETTE1 , 0x01); + attr_w(ACT_PALETTE2 , 0x02); + attr_w(ACT_PALETTE3 , 0x03); + attr_w(ACT_PALETTE4 , 0x04); + attr_w(ACT_PALETTE5 , 0x05); + attr_w(ACT_PALETTE6 , 0x06); + attr_w(ACT_PALETTE7 , 0x07); + attr_w(ACT_PALETTE8 , 0x08); + attr_w(ACT_PALETTE9 , 0x09); + attr_w(ACT_PALETTE10, 0x0a); + attr_w(ACT_PALETTE11, 0x0b); + attr_w(ACT_PALETTE12, 0x0c); + attr_w(ACT_PALETTE13, 0x0d); + attr_w(ACT_PALETTE14, 0x0e); + attr_w(ACT_PALETTE15, 0x0f); + reg_r(ACT_ADDRESS_RESET); + + attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ + + attr_w(ACT_OVERSCAN_COLOR, 0x00); + attr_w(ACT_COLOR_PLANE_ENA, 0x0f); + attr_w(ACT_HOR_PEL_PANNING, 0x00); + attr_w(ACT_COLOR_SELECT, 0x00); + + reg_r(ACT_ADDRESS_RESET); + reg_w(ACT_DATA, 0x20); + + reg_w(VDAC_MASK, 0xff); + + /* + * Extended palette adressing ??? + */ + switch (bpp){ + case 8: + reg_w(0x83c6, 0x00); + break; + case 16: + reg_w(0x83c6, 0x60); + break; + case 24: + reg_w(0x83c6, 0xe0); + break; + default: + printk("Illegal color-depth: %i\n", bpp); + } + + reg_w(VDAC_ADDRESS, 0x00); + + seq_w(SEQ_MAP_MASK, 0x0f ); + + return 0; +} + +/* + * Initialization + * + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int retz3_init(void) +{ + int i; +#if 0 + volatile unsigned long *CursorBase; +#endif + unsigned long board_addr, board_size; + struct ConfigDev *cd; + + cd = zorro_get_board (z3_key); + zorro_config_board (z3_key, 0); + board_addr = (unsigned long)cd->cd_BoardAddr; + board_size = (unsigned long)cd->cd_BoardSize; + + for (i = 0; i < 256; i++){ + for (i = 0; i < 256; i++){ + retz3_color_table [i][0] = i; + retz3_color_table [i][1] = i; + retz3_color_table [i][2] = i; + retz3_color_table [i][3] = 0; + } + } + + *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + z3_mem = kernel_map (board_addr, board_size, + KERNELMAP_NOCACHE_SER, memstart); + + z3_regs = (char*) z3_mem; + z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; + + /* Get memory size - for now we asume its a 4MB board */ + + z3_size = 0x00400000; /* 4 MB */ + + memset ((char*)z3_fbmem, 0, z3_size); + + /* Disable hardware cursor */ + + seq_w(SEQ_CURSOR_Y_INDEX, 0x00); + + +#if 0 + /* Initialize hardware cursor */ + CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); + for (i=0; i < 8; i++){ + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i=8; i < 64; i++){ + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } +#endif + + retz3_setcolreg (255, 56, 100, 160, 0); + retz3_setcolreg (254, 0, 0, 0, 0); + + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par) +{ + int i; + + strcpy(fix->id, retz3_fb_name); + fix->smem_start = z3_fbmem; + fix->smem_len = z3_size; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_DIRECTCOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + + return 0; +} + + +/* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + par->xres = var->xres; + par->yres = var->yres; + par->xres_vir = var->xres_virtual; + par->yres_vir = var->yres_virtual; + par->bpp = var->bits_per_pixel; + par->pixclock = var->pixclock; + par->vmode = var->vmode; + + par->red = var->red; + par->green = var->green; + par->blue = var->blue; + par->transp = var->transp; + + par->left_margin = var->left_margin; + par->right_margin = var->right_margin; + par->upper_margin = var->upper_margin; + par->lower_margin = var->lower_margin; + par->hsync_len = var->hsync_len; + par->vsync_len = var->vsync_len; + + return 0; +} + + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + int i; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->xres_vir; + var->yres_virtual = par->yres_vir; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red = par->red; + var->green = par->green; + var->blue = par->blue; + var->transp = par->transp; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->accel = FB_ACCEL_RETINAZ3; + + var->pixclock = par->pixclock; + + var->sync = 0; /* ??? */ + var->left_margin = par->left_margin; + var->right_margin = par->right_margin; + var->upper_margin = par->upper_margin; + var->lower_margin = par->lower_margin; + var->hsync_len = par->hsync_len; + var->vsync_len = par->vsync_len; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + var->vmode = par->vmode; + return 0; +} + + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp) +{ + /* We'll get to this */ + + if (regno > 255) + return 1; + + retz3_color_table [regno][0] = red & 0xff; + retz3_color_table [regno][1] = green & 0xff; + retz3_color_table [regno][2] = blue & 0xff; + retz3_color_table [regno][3] = transp; + + reg_w(VDAC_ADDRESS_W, regno); + reg_w(VDAC_DATA, (red & 0xff) >> 2); + reg_w(VDAC_DATA, (green & 0xff) >> 2); + reg_w(VDAC_DATA, (blue & 0xff) >> 2); + + return 0; +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp) +{ + if (regno > 255) + return 1; + *red = retz3_color_table [regno][0]; + *green = retz3_color_table [regno][1]; + *blue = retz3_color_table [regno][2]; + *transp = retz3_color_table [regno][3]; + return 0; +} + + +/* + * (Un)Blank the screen + */ + +void retz3_blank(int blank) +{ + int i; + + if (blank) + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + } + else + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); + } +} + + +void retz3_bitblt (struct fb_var_screeninfo *var, + unsigned short srcx, unsigned short srcy, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask) +{ + + volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); + unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); + + unsigned short mod; + unsigned long tmp; + unsigned long pat, src, dst; + unsigned char blt_status; + + int i, xres_virtual = var->xres_virtual; + short bpp = (var->bits_per_pixel & 0xff); + + if (bpp < 8) + bpp = 8; + + tmp = mask | (mask << 16); + +#if 0 + /* + * Check for blitter finished before we start messing with the + * pattern. + */ + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + }while ((blt_status & 1) == 0); +#endif + + i = 0; + do{ + *pattern++ = tmp; + }while(i++ < bpp/4); + + tmp = cmd << 8; + *(acm + ACM_RASTEROP_ROTATION/4) = tmp; + + mod = 0xc0c2; + + pat = 8 * PAT_MEM_OFF; + dst = bpp * (destx + desty * xres_virtual); + + /* + * Source is not set for clear. + */ + if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { + src = bpp * (srcx + srcy * xres_virtual); + + if (destx > srcx) { + mod &= ~0x8000; + src += bpp * (width - 1); + dst += bpp * (width - 1); + pat += bpp * 2; + } + if (desty > srcy) { + mod &= ~0x4000; + src += bpp * (height - 1) * xres_virtual; + dst += bpp * (height - 1) * xres_virtual; + pat += bpp * 4; + } + + *(acm + ACM_SOURCE/4) = cpu_to_le32(src); + } + + *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); + + *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); + + tmp = mod << 16; + *(acm + ACM_CONTROL/4) = tmp; + + tmp = width | (height << 16); + + *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); + + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; + + /* + * No reason to wait for the blitter to finish, it is better + * just to check if it has finished before we use it again. + */ +#if 1 +#if 0 + while ((*(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)) & 1) == 0); +#else + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + } + while ((blt_status & 1) == 0); +#endif +#endif +} + +#if 0 +void retz3_fill (unsigned short x, unsigned short y, unsigned + short width, unsigned short height, + unsigned short mode, unsigned short color) +{ + +} +#endif + + +/************************************************************** + * Move cursor to x, y + */ +void retz3_MoveCursor (unsigned short x, unsigned short y) +{ + /* Guess we gotta deal with the cursor at some point */ +} + + +/* -------------------- Interfaces to hardware functions -------------------- */ + + +static struct fb_hwswitch retz3_switch = { + retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, + retz3_getcolreg, retz3_setcolreg, retz3_blank +}; + + +/* -------------------- Generic routines ------------------------------------ */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par) +{ + if (current_par_valid) + *par = current_par; + else + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par); +} + + +static void retz3_fb_set_par(struct retz3_fb_par *par) +{ + current_par = *par; + current_par_valid = 1; +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct retz3_fb_par par; + + if ((err = fbhw->decode_var(var, &par))) + return err; + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + retz3_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + +#if 1 + retz3_set_video(var, ¤t_par); +#endif + return 0; +} + + +/* + * Default Colormaps + */ + +static unsigned short red16[] = + { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, + 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }; +static unsigned short green16[] = + { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000, + 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }; +static unsigned short blue16[] = + { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, + 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff }; + + +static struct fb_cmap default_16_colors = + { 0, 16, red16, green16, blue16, NULL }; + + +static struct fb_cmap *get_default_colormap(int bpp) +{ + return &default_16_colors; +} + + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) +#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ + ((1<<(width))-1)) : 0)) + +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + unsigned short *red, *green, *blue, *transp; + unsigned int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) + return 0; + hred = CNVT_FROMHW(hred, var->red.length); + hgreen = CNVT_FROMHW(hgreen, var->green.length); + hblue = CNVT_FROMHW(hblue, var->blue.length); + htransp = CNVT_FROMHW(htransp, var->transp.length); + if (kspc) { + *red = hred; + *green = hgreen; + *blue = hblue; + if (transp) + *transp = htransp; + } else { + put_user(hred, red); + put_user(hgreen, green); + put_user(hblue, blue); + if (transp) + put_user(htransp, transp); + } + red++; + green++; + blue++; + if (transp) + transp++; + } + return 0; +} + + +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + unsigned short *red, *green, *blue, *transp; + unsigned int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (kspc) { + hred = *red; + hgreen = *green; + hblue = *blue; + htransp = transp ? *transp : 0; + } else { + get_user(hred, red); + get_user(hgreen, green); + get_user(hblue, blue); + if (transp) + get_user(htransp, transp); + else + htransp = 0; + } + hred = CNVT_TOHW(hred, var->red.length); + hgreen = CNVT_TOHW(hgreen, var->green.length); + hblue = CNVT_TOHW(hblue, var->blue.length); + htransp = CNVT_TOHW(htransp, var->transp.length); + red++; + green++; + blue++; + if (transp) + transp++; + if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) + return 0; + } + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (disp[con].cmap.len) + do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1); + else + do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel), + &disp[con].var, 1); +} + + +static void memcpy_fs(int fsfromto, void *to, void *from, int len) +{ + switch (fsfromto) { + case 0: + memcpy(to, from, len); + return; + case 1: + copy_from_user(to, from, len); + return; + case 2: + copy_to_user(to, from, len); + return; + } +} + + +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) +{ + int size; + int tooff = 0, fromoff = 0; + + if (to->start > from->start) + fromoff = to->start-from->start; + else + tooff = from->start-to->start; + size = to->len-tooff; + if (size > from->len-fromoff) + size = from->len-fromoff; + if (size < 0) + return; + size *= sizeof(unsigned short); + memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); + memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); + memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy_fs(fsfromto, to->transp+tooff, + from->transp+fromoff, size); +} + + +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + int size = len*sizeof(unsigned short); + + if (cmap->len != len) { + if (cmap->red) + kfree(cmap->red); + if (cmap->green) + kfree(cmap->green); + if (cmap->blue) + kfree(cmap->blue); + if (cmap->transp) + kfree(cmap->transp); + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; + if (!len) + return 0; + if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) + return -1; + if (transp) { + if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + return -1; + } else + cmap->transp = NULL; + } + cmap->start = 0; + cmap->len = len; + copy_cmap(get_default_colormap(len), cmap, 0); + return 0; +} + + +/* + * Get the Fixed Part of the Display + */ + +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) + retz3_fb_get_par(&par); + else + error = fbhw->decode_var(&disp[con].var, &par); + return(error ? error : fbhw->encode_fix(fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) { + retz3_fb_get_par(&par); + error = fbhw->encode_var(var, &par); + } else + *var = disp[con].var; + return error; +} + + +static void retz3_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + retz3_fb_get_fix(&fix, con); + if (con == -1) + con = 0; + disp[con].screen_base = (unsigned char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = z3fb_inverse; +} + + +/* + * Set the User Defined Part of the Display + */ + +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; + + if ((err = do_fb_set_var(var, con == currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = disp[con].var.xres; + oldyres = disp[con].var.yres; + oldvxres = disp[con].var.xres_virtual; + oldvyres = disp[con].var.yres_virtual; + oldbpp = disp[con].var.bits_per_pixel; + disp[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + retz3_fb_set_disp(con); + (*fb_info.changevar)(con); + alloc_cmap(&disp[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate = 0; + return 0; +} + + +/* + * Get the Colormap + */ + +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return(do_fb_get_cmap(cmap, &disp[con].var, kspc)); + else if (disp[con].cmap.len) /* non default colormap? */ + copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); + else + copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + +/* + * Set the Colormap + */ + +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!disp[con].cmap.len) { /* no colormap allocated? */ + if ((err = alloc_cmap(&disp[con].cmap, + 1<<disp[con].var.bits_per_pixel, 0))) + return err; + } + if (con == currcon) /* current console? */ + return(do_fb_set_cmap(cmap, &disp[con].var, kspc)); + else + copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1); + return 0; +} + + +/* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + return -EINVAL; +} + + +/* + * RetinaZ3 Frame Buffer Specific ioctls + */ + +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con) +{ + return -EINVAL; +} + + +static struct fb_ops retz3_fb_ops = { + retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap, + retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl +}; + + +int retz3_probe(void) +{ + z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0); + return(z3_key); +} + + +void retz3_video_setup(char *options, int *ints) +{ + char *this_opt; + int i; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")){ + if (!strcmp(this_opt, "inverse")) { + z3fb_inverse = 1; + for (i = 0; i < 16; i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else + z3fb_mode = get_video_mode(this_opt); + } +} + + +/* + * Initialization + */ + +struct fb_info *retz3_fb_init(long *mem_start) +{ + int err; + struct retz3_fb_par par; + + memstart = mem_start; + + fbhw = &retz3_switch; + + err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops, + NUM_TOTAL_MODES, retz3_fb_predefined); + if (err < 0) + panic("Cannot register frame buffer\n"); + + fbhw->init(); + + if (z3fb_mode == -1) + z3fb_mode = 1; + + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par); + fbhw->encode_var(&retz3_fb_predefined[0], &par); + + strcpy(fb_info.modename, retz3_fb_name); + fb_info.disp = disp; + fb_info.switch_con = &z3fb_switch; + fb_info.updatevar = &z3fb_updatevar; + fb_info.blank = &z3fb_blank; + fb_info.setcmap = &z3fb_setcmap; + + do_fb_set_var(&retz3_fb_predefined[0], 0); + retz3_fb_get_var(&disp[0].var, -1); + retz3_fb_set_disp(-1); + do_install_cmap(0); + + return &fb_info; +} + + +static int z3fb_switch(int con) +{ + /* Do we have to save the colormap? */ + if (disp[currcon].cmap.len) + do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1); + + do_fb_set_var(&disp[con].var, 1); + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int z3fb_updatevar(int con) +{ + return 0; +} + + +/* + * Blank the display. + */ + +static void z3fb_blank(int blank) +{ + fbhw->blank(blank); +} + + +/* + * Set the colormap + */ + +static int z3fb_setcmap(struct fb_cmap *cmap, int con) +{ + return(retz3_fb_set_cmap(cmap, 1, con)); +} + + +/* + * Get a Video Mode + */ + +static int get_video_mode(const char *name) +{ + int i; + + for (i = 1; i <= NUM_PREDEF_MODES; i++) + if (!strcmp(name, retz3_fb_modenames[i])){ + retz3_fb_predefined[0] = retz3_fb_predefined[i]; + return i; + } + return -1; +} +/* + * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the + * RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * This file is based on the CyberVision64 frame buffer device and + * the generic Cirrus Logic driver. + * + * cyberfb.c: Copyright (C) 1996 Martin Apel, + * Geert Uytterhoeven + * clgen.c: Copyright (C) 1996 Frank Neumann + * + * History: + * - 22 Jan 97: Initial work + * - 14 Feb 97: Screen initialization works somewhat, still only + * 8-bit packed pixel is supported. + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <linux/zorro.h> +#include <asm/pgtable.h> + +#include "retz3fb.h" + +/* #define DEBUG if(1) */ +#define DEBUG if(0) + +/* + * Reserve space for one pattern line. + * + * For the time being we only support 4MB boards! + */ + +#define PAT_MEM_SIZE 16*3 +#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct retz3_fb_par { + int xres; + int yres; + int xres_vir; + int yres_vir; + int xoffset; + int yoffset; + int bpp; + + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + + int pixclock; + int left_margin; /* time from sync to picture */ + int right_margin; /* time from picture to sync */ + int upper_margin; /* time from sync to picture */ + int lower_margin; + int hsync_len; /* length of horizontal sync */ + int vsync_len; /* length of vertical sync */ + int vmode; +}; + +struct display_data { + long h_total; /* Horizontal Total */ + long h_sstart; /* Horizontal Sync Start */ + long h_sstop; /* Horizontal Sync Stop */ + long h_bstart; /* Horizontal Blank Start */ + long h_bstop; /* Horizontal Blank Stop */ + long h_dispend; /* Horizontal Display End */ + long v_total; /* Vertical Total */ + long v_sstart; /* Vertical Sync Start */ + long v_sstop; /* Vertical Sync Stop */ + long v_bstart; /* Vertical Blank Start */ + long v_bstop; /* Vertical Blank Stop */ + long v_dispend; /* Horizontal Display End */ +}; + +static struct retz3_fb_par current_par; + +static int current_par_valid = 0; +static int currcon = 0; + +static struct display disp[MAX_NR_CONSOLES]; +static struct fb_info fb_info; + +static int node; /* node of the /dev/fb?current file */ + + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned + int *green, unsigned int *blue, unsigned int *transp); + int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int + green, unsigned int blue, unsigned int transp); + void (*blank)(int blank); +} *fbhw; + + +/* + * Frame Buffer Name + */ + +static char retz3_fb_name[16] = "RetinaZ3"; + + +static int z3_key = 0; +static unsigned char retz3_color_table [256][4]; +static unsigned long z3_mem; +static unsigned long z3_fbmem; +static unsigned long z3_size; +static volatile unsigned char *z3_regs; + +static long *memstart; + + +/* + * Predefined Video Mode Names + */ + +static char *retz3_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * Predefined Video Modes + */ + + "640x480", /* RetinaZ3 8 bpp */ + "800x600", /* RetinaZ3 8 bpp */ + "1024x768i", + "640x480-16", /* RetinaZ3 16 bpp */ + "640x480-24", /* RetinaZ3 24 bpp */ + + /* + * Dummy Video Modes + */ + + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + + /* + * User Defined Video Modes + * + * This doesn't work yet!! + */ + + "user0", "user1", "user2", "user3", + "user4", "user5", "user6", "user7" +}; + +/* + * A small info on how to convert XFree86 timing values into fb + * timings - by Frank Neumann: + * +An XFree86 mode line consists of the following fields: + "800x600" 50 800 856 976 1040 600 637 643 666 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + +The fields in the fb_var_screeninfo structure are: + unsigned long pixclock; * pixel clock in ps (pico seconds) * + unsigned long left_margin; * time from sync to picture * + unsigned long right_margin; * time from picture to sync * + unsigned long upper_margin; * time from sync to picture * + unsigned long lower_margin; + unsigned long hsync_len; * length of horizontal sync * + unsigned long vsync_len; * length of vertical sync * + +1) Pixelclock: + xfree: in MHz + fb: In Picoseconds (ps) + + pixclock = 1000000 / DCF + +2) horizontal timings: + left_margin = HFL - SH2 + right_margin = SH1 - HR + hsync_len = SH2 - SH1 + +3) vertical timings: + upper_margin = VFL - SV2 + lower_margin = SV1 - VR + vsync_len = SV2 - SV1 + +Good examples for VESA timings can be found in the XFree86 source tree, +under "programs/Xserver/hw/xfree86/doc/modeDB.txt". +*/ + +/* + * Predefined Video Mode Definitions + */ + +static struct fb_var_screeninfo retz3_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * Predefined Video Modes + */ + + /* + * NB: it is very important to adjust the pixel-clock to the color-depth. + */ + + { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 800 x 600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 1024 x 768, 8 bpp, interlaced */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 24, 0, + {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + + /* + * Dummy Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + + +#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined) +#define NUM_PREDEF_MODES (5) + + +static int z3fb_inverse = 0; +static int z3fb_mode = 0; + + +/* + * Interface used by the world + */ + +int retz3_probe(void); +void retz3_video_setup(char *options, int *ints); + +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con); + + +/* + * Interface to the low level console driver + */ + +struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */ +static int z3fb_switch(int con); +static int z3fb_updatevar(int con); +static void z3fb_blank(int blank); +static int z3fb_setcmap(struct fb_cmap *cmap, int con); + + +/* + * Accelerated Functions used by the low level console driver + */ + +void retz3_bitblt(struct fb_var_screeninfo *scr, + unsigned short curx, unsigned short cury, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); +void retz3_fill(unsigned short x, unsigned short y, unsigned short + width, unsigned short height, unsigned short mode, + unsigned short color); + +/* + * Hardware Specific Routines + */ + +static int retz3_init(void); +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par); +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp); +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp); +static void retz3_blank(int blank); + + +/* + * Internal routines + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par); +static void retz3_fb_set_par(struct retz3_fb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static struct fb_cmap *get_default_colormap(int bpp); +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc); +static void do_install_cmap(int con); +static void memcpy_fs(int fsfromto, void *to, void *from, int len); +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto); +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp); +static void retz3_fb_set_disp(int con); +static int get_video_mode(const char *name); + + +/* -------------------- Hardware specific routines -------------------------- */ + +static unsigned short find_fq(unsigned int freq) +{ + unsigned long f; + long tmp; + long prev = 0x7fffffff; + long n2, n1 = 3; + unsigned long m; + unsigned short res = 0; + + if (freq <= 31250000) + n2 = 3; + else if (freq <= 62500000) + n2 = 2; + else if (freq <= 125000000) + n2 = 1; + else if (freq <= 250000000) + n2 = 0; + else + return(0); + + + do { + f = freq >> (10 - n2); + + m = (f * n1) / (14318180/1024); + + if (m > 129) + break; + + tmp = (((m * 14318180) >> n2) / n1) - freq; + if (tmp < 0) + tmp = -tmp; + + if (tmp < prev) { + prev = tmp; + res = (((n2 << 5) | (n1-2)) << 8) | (m-2); + } + + } while ( (++n1) <= 21); + + return res; +} + + +static int retz3_set_video(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + float freq_f; + long freq; + + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + unsigned char tmp; + unsigned short best_freq; + struct display_data data; + + short clocksel = 0; /* Apparantly this is always zero */ + + int bpp = var->bits_per_pixel; + + /* + * XXX + */ + if (bpp == 24) + return 0; + + if ((bpp != 8) && (bpp != 16) && (bpp != 24)) + return -EFAULT; + + par->xoffset = 0; + par->yoffset = 0; + + xres = var->xres * bpp / 4; + hfront = var->right_margin * bpp / 4; + hsync = var->hsync_len * bpp / 4; + hback = var->left_margin * bpp / 4; + + if (var->vmode & FB_VMODE_DOUBLE) + { + yres = var->yres * 2; + vfront = var->lower_margin * 2; + vsync = var->vsync_len * 2; + vback = var->upper_margin * 2; + } + else if (var->vmode & FB_VMODE_INTERLACED) + { + yres = (var->yres + 1) / 2; + vfront = (var->lower_margin + 1) / 2; + vsync = (var->vsync_len + 1) / 2; + vback = (var->upper_margin + 1) / 2; + } + else + { + yres = var->yres; /* -1 ? */ + vfront = var->lower_margin; + vsync = var->vsync_len; + vback = var->upper_margin; + } + + data.h_total = (hback / 8) + (xres / 8) + + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; + data.h_dispend = ((xres + bpp - 1)/ 8) - 1; + data.h_bstart = xres / 8 /* + 1 */; + + data.h_bstop = data.h_total+1 + 2 + 1; + data.h_sstart = (xres / 8) + (hfront / 8) + 1; + data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; + + data.v_total = yres + vfront + vsync + vback - 1; + + data.v_dispend = yres - 1; + data.v_bstart = yres; + + data.v_bstop = data.v_total; + data.v_sstart = yres + vfront - 1 - 2; + data.v_sstop = yres + vfront + vsync - 1; + +#if 0 /* testing */ + + printk("HBS: %i\n", data.h_bstart); + printk("HSS: %i\n", data.h_sstart); + printk("HSE: %i\n", data.h_sstop); + printk("HBE: %i\n", data.h_bstop); + printk("HT: %i\n", data.h_total); + + printk("hsync: %i\n", hsync); + printk("hfront: %i\n", hfront); + printk("hback: %i\n", hback); + + printk("VBS: %i\n", data.v_bstart); + printk("VSS: %i\n", data.v_sstart); + printk("VSE: %i\n", data.v_sstop); + printk("VBE: %i\n", data.v_bstop); + printk("VT: %i\n", data.v_total); + + printk("vsync: %i\n", vsync); + printk("vfront: %i\n", vfront); + printk("vback: %i\n", vback); +#endif + + if (data.v_total >= 1024) + printk("MAYDAY: v_total >= 1024; bailing out!\n"); + + reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); + reg_w(GREG_FEATURE_CONTROL_W, 0x00); + + seq_w(SEQ_RESET, 0x00); + seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ + + /* + * CLOCKING_MODE bits: + * 2: This one is only set for certain text-modes, wonder if + * it may be for EGA-lines? (it was referred to as CLKDIV2) + * (The CL drivers sets it to 0x21 with the comment: + * FullBandwidth (video off) and 8/9 dot clock) + */ + seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); + + seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ + seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ + seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ + seq_w(SEQ_RESET, 0x01); + seq_w(SEQ_RESET, 0x03); + + seq_w(SEQ_EXTENDED_ENABLE, 0x05); + + seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_LINEAR_0, 0x4a); + seq_w(SEQ_LINEAR_1, 0x00); + + seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); + seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); + seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); + + /* + * The lower 4 bits (0-3) are used to set the font-width for + * text-mode - DON'T try to set this for gfx-mode. + */ + seq_w(SEQ_EXT_CLOCK_MODE, 0x10); + seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); + + /* + * Extended Pixel Control: + * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) + * bit 1: (Packed/Nibble Pixel Format ?) + * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp + */ + seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); + + seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); + seq_w(SEQ_COLOR_EXP_WFG, 0x01); + seq_w(SEQ_COLOR_EXP_WBG, 0x00); + seq_w(SEQ_EXT_RW_CONTROL, 0x00); + seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); + seq_w(SEQ_COLOR_KEY_CNTL, 0x40); + seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); + seq_w(SEQ_CRC_CONTROL, 0x00); + seq_w(SEQ_PERF_SELECT, 0x10); + seq_w(SEQ_ACM_APERTURE_1, 0x00); + seq_w(SEQ_ACM_APERTURE_2, 0x30); + seq_w(SEQ_ACM_APERTURE_3, 0x00); + seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); + + + /* unlock register CRT0..CRT7 */ + crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); + + /* Zuerst zu schreibende Werte nur per printk ausgeben */ + DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); + crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); + + DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); + crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); + + DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); + crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); + + DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); + crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); + + DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); + crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); + + tmp = (data.h_sstop & 0x1f); + if (data.h_bstop & 0x20) + tmp |= 0x80; + DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); + crt_w(CRT_END_HOR_RETR, tmp); + + DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); + crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); + + tmp = 0x10; /* LineCompare bit #9 */ + if (data.v_total & 256) + tmp |= 0x01; + if (data.v_dispend & 256) + tmp |= 0x02; + if (data.v_sstart & 256) + tmp |= 0x04; + if (data.v_bstart & 256) + tmp |= 0x08; + if (data.v_total & 512) + tmp |= 0x20; + if (data.v_dispend & 512) + tmp |= 0x40; + if (data.v_sstart & 512) + tmp |= 0x80; + DEBUG printk("CRT_OVERFLOW: %d\n", tmp); + crt_w(CRT_OVERFLOW, tmp); + + crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ + + tmp = 0x40; /* LineCompare bit #8 */ + if (data.v_bstart & 512) + tmp |= 0x20; + if (var->vmode & FB_VMODE_DOUBLE) + tmp |= 0x80; + DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); + crt_w(CRT_MAX_SCAN_LINE, tmp); + + crt_w(CRT_CURSOR_START, 0x00); + crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ + + crt_w(CRT_START_ADDR_HIGH, 0x00); + crt_w(CRT_START_ADDR_LOW, 0x00); + + crt_w(CRT_CURSOR_LOC_HIGH, 0x00); + crt_w(CRT_CURSOR_LOC_LOW, 0x00); + + DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); + crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); + +#if 1 + /* 5 refresh cycles per scanline */ + DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); +#else + DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); +#endif + DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); + crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); + + DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); + crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); + + DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); + crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); + + DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); + crt_w(CRT_MODE_CONTROL, 0xe3); + + DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); + crt_w(CRT_LINE_COMPARE, 0xff); + + tmp = (var->xres_virtual / 8) * (bpp / 8); + crt_w(CRT_OFFSET, tmp); + + crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ + + tmp = 0x20; /* Enable extended end bits */ + if (data.h_total & 0x100) + tmp |= 0x01; + if ((data.h_dispend) & 0x100) + tmp |= 0x02; + if (data.h_bstart & 0x100) + tmp |= 0x04; + if (data.h_sstart & 0x100) + tmp |= 0x08; + if (var->vmode & FB_VMODE_INTERLACED) + tmp |= 0x10; + DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); + crt_w(CRT_EXT_HOR_TIMING1, tmp); + + tmp = 0x00; + if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) + tmp |= 0x10; + crt_w(CRT_EXT_START_ADDR, tmp); + + tmp = 0x00; + if (data.h_total & 0x200) + tmp |= 0x01; + if ((data.h_dispend) & 0x200) + tmp |= 0x02; + if (data.h_bstart & 0x200) + tmp |= 0x04; + if (data.h_sstart & 0x200) + tmp |= 0x08; + tmp |= ((data.h_bstop & 0xc0) >> 2); + tmp |= ((data.h_sstop & 0x60) << 1); + crt_w(CRT_EXT_HOR_TIMING2, tmp); + DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); + + tmp = 0x10; /* Line compare bit 10 */ + if (data.v_total & 0x400) + tmp |= 0x01; + if ((data.v_dispend) & 0x400) + tmp |= 0x02; + if (data.v_bstart & 0x400) + tmp |= 0x04; + if (data.v_sstart & 0x400) + tmp |= 0x08; + tmp |= ((data.v_bstop & 0x300) >> 3); + if (data.v_sstop & 0x10) + tmp |= 0x80; + crt_w(CRT_EXT_VER_TIMING, tmp); + DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); + + crt_w(CRT_MONITOR_POWER, 0x00); + + /* + * Convert from ps to Hz. + */ + freq_f = (1.0/(float)var->pixclock) * 1000000000; + freq = ((long)freq_f) * 1000; + + best_freq = find_fq(freq); + pll_w(0x02, best_freq); + best_freq = find_fq(61000000); + pll_w(0x0a, best_freq); + pll_w(0x0e, 0x22); + + gfx_w(GFX_SET_RESET, 0x00); + gfx_w(GFX_ENABLE_SET_RESET, 0x00); + gfx_w(GFX_COLOR_COMPARE, 0x00); + gfx_w(GFX_DATA_ROTATE, 0x00); + gfx_w(GFX_READ_MAP_SELECT, 0x00); + gfx_w(GFX_GRAPHICS_MODE, 0x00); + gfx_w(GFX_MISC, 0x05); + gfx_w(GFX_COLOR_XCARE, 0x0f); + gfx_w(GFX_BITMASK, 0xff); + + reg_r(ACT_ADDRESS_RESET); + attr_w(ACT_PALETTE0 , 0x00); + attr_w(ACT_PALETTE1 , 0x01); + attr_w(ACT_PALETTE2 , 0x02); + attr_w(ACT_PALETTE3 , 0x03); + attr_w(ACT_PALETTE4 , 0x04); + attr_w(ACT_PALETTE5 , 0x05); + attr_w(ACT_PALETTE6 , 0x06); + attr_w(ACT_PALETTE7 , 0x07); + attr_w(ACT_PALETTE8 , 0x08); + attr_w(ACT_PALETTE9 , 0x09); + attr_w(ACT_PALETTE10, 0x0a); + attr_w(ACT_PALETTE11, 0x0b); + attr_w(ACT_PALETTE12, 0x0c); + attr_w(ACT_PALETTE13, 0x0d); + attr_w(ACT_PALETTE14, 0x0e); + attr_w(ACT_PALETTE15, 0x0f); + reg_r(ACT_ADDRESS_RESET); + + attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ + + attr_w(ACT_OVERSCAN_COLOR, 0x00); + attr_w(ACT_COLOR_PLANE_ENA, 0x0f); + attr_w(ACT_HOR_PEL_PANNING, 0x00); + attr_w(ACT_COLOR_SELECT, 0x00); + + reg_r(ACT_ADDRESS_RESET); + reg_w(ACT_DATA, 0x20); + + reg_w(VDAC_MASK, 0xff); + + /* + * Extended palette adressing ??? + */ + switch (bpp){ + case 8: + reg_w(0x83c6, 0x00); + break; + case 16: + reg_w(0x83c6, 0x60); + break; + case 24: + reg_w(0x83c6, 0xe0); + break; + default: + printk("Illegal color-depth: %i\n", bpp); + } + + reg_w(VDAC_ADDRESS, 0x00); + + seq_w(SEQ_MAP_MASK, 0x0f ); + + return 0; +} + +/* + * Initialization + * + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int retz3_init(void) +{ + int i; +#if 0 + volatile unsigned long *CursorBase; +#endif + unsigned long board_addr, board_size; + struct ConfigDev *cd; + + cd = zorro_get_board (z3_key); + zorro_config_board (z3_key, 0); + board_addr = (unsigned long)cd->cd_BoardAddr; + board_size = (unsigned long)cd->cd_BoardSize; + + for (i = 0; i < 256; i++){ + for (i = 0; i < 256; i++){ + retz3_color_table [i][0] = i; + retz3_color_table [i][1] = i; + retz3_color_table [i][2] = i; + retz3_color_table [i][3] = 0; + } + } + + *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + z3_mem = kernel_map (board_addr, board_size, + KERNELMAP_NOCACHE_SER, memstart); + + z3_regs = (char*) z3_mem; + z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; + + /* Get memory size - for now we asume its a 4MB board */ + + z3_size = 0x00400000; /* 4 MB */ + + memset ((char*)z3_fbmem, 0, z3_size); + + /* Disable hardware cursor */ + + seq_w(SEQ_CURSOR_Y_INDEX, 0x00); + + +#if 0 + /* Initialize hardware cursor */ + CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); + for (i=0; i < 8; i++){ + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i=8; i < 64; i++){ + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } +#endif + + retz3_setcolreg (255, 56, 100, 160, 0); + retz3_setcolreg (254, 0, 0, 0, 0); + + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par) +{ + int i; + + strcpy(fix->id, retz3_fb_name); + fix->smem_start = z3_fbmem; + fix->smem_len = z3_size; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_DIRECTCOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + + return 0; +} + + +/* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + par->xres = var->xres; + par->yres = var->yres; + par->xres_vir = var->xres_virtual; + par->yres_vir = var->yres_virtual; + par->bpp = var->bits_per_pixel; + par->pixclock = var->pixclock; + par->vmode = var->vmode; + + par->red = var->red; + par->green = var->green; + par->blue = var->blue; + par->transp = var->transp; + + par->left_margin = var->left_margin; + par->right_margin = var->right_margin; + par->upper_margin = var->upper_margin; + par->lower_margin = var->lower_margin; + par->hsync_len = var->hsync_len; + par->vsync_len = var->vsync_len; + + return 0; +} + + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + int i; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->xres_vir; + var->yres_virtual = par->yres_vir; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red = par->red; + var->green = par->green; + var->blue = par->blue; + var->transp = par->transp; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->accel = FB_ACCEL_RETINAZ3; + + var->pixclock = par->pixclock; + + var->sync = 0; /* ??? */ + var->left_margin = par->left_margin; + var->right_margin = par->right_margin; + var->upper_margin = par->upper_margin; + var->lower_margin = par->lower_margin; + var->hsync_len = par->hsync_len; + var->vsync_len = par->vsync_len; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + var->vmode = par->vmode; + return 0; +} + + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp) +{ + /* We'll get to this */ + + if (regno > 255) + return 1; + + retz3_color_table [regno][0] = red & 0xff; + retz3_color_table [regno][1] = green & 0xff; + retz3_color_table [regno][2] = blue & 0xff; + retz3_color_table [regno][3] = transp; + + reg_w(VDAC_ADDRESS_W, regno); + reg_w(VDAC_DATA, (red & 0xff) >> 2); + reg_w(VDAC_DATA, (green & 0xff) >> 2); + reg_w(VDAC_DATA, (blue & 0xff) >> 2); + + return 0; +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp) +{ + if (regno > 255) + return 1; + *red = retz3_color_table [regno][0]; + *green = retz3_color_table [regno][1]; + *blue = retz3_color_table [regno][2]; + *transp = retz3_color_table [regno][3]; + return 0; +} + + +/* + * (Un)Blank the screen + */ + +void retz3_blank(int blank) +{ + int i; + + if (blank) + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + } + else + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); + } +} + + +void retz3_bitblt (struct fb_var_screeninfo *var, + unsigned short srcx, unsigned short srcy, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask) +{ + + volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); + unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); + + unsigned short mod; + unsigned long tmp; + unsigned long pat, src, dst; + unsigned char blt_status; + + int i, xres_virtual = var->xres_virtual; + short bpp = (var->bits_per_pixel & 0xff); + + if (bpp < 8) + bpp = 8; + + tmp = mask | (mask << 16); + +#if 0 + /* + * Check for blitter finished before we start messing with the + * pattern. + */ + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + }while ((blt_status & 1) == 0); +#endif + + i = 0; + do{ + *pattern++ = tmp; + }while(i++ < bpp/4); + + tmp = cmd << 8; + *(acm + ACM_RASTEROP_ROTATION/4) = tmp; + + mod = 0xc0c2; + + pat = 8 * PAT_MEM_OFF; + dst = bpp * (destx + desty * xres_virtual); + + /* + * Source is not set for clear. + */ + if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { + src = bpp * (srcx + srcy * xres_virtual); + + if (destx > srcx) { + mod &= ~0x8000; + src += bpp * (width - 1); + dst += bpp * (width - 1); + pat += bpp * 2; + } + if (desty > srcy) { + mod &= ~0x4000; + src += bpp * (height - 1) * xres_virtual; + dst += bpp * (height - 1) * xres_virtual; + pat += bpp * 4; + } + + *(acm + ACM_SOURCE/4) = cpu_to_le32(src); + } + + *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); + + *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); + + tmp = mod << 16; + *(acm + ACM_CONTROL/4) = tmp; + + tmp = width | (height << 16); + + *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); + + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; + + /* + * No reason to wait for the blitter to finish, it is better + * just to check if it has finished before we use it again. + */ +#if 1 +#if 0 + while ((*(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)) & 1) == 0); +#else + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + } + while ((blt_status & 1) == 0); +#endif +#endif +} + +#if 0 +void retz3_fill (unsigned short x, unsigned short y, unsigned + short width, unsigned short height, + unsigned short mode, unsigned short color) +{ + +} +#endif + + +/************************************************************** + * Move cursor to x, y + */ +void retz3_MoveCursor (unsigned short x, unsigned short y) +{ + /* Guess we gotta deal with the cursor at some point */ +} + + +/* -------------------- Interfaces to hardware functions -------------------- */ + + +static struct fb_hwswitch retz3_switch = { + retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, + retz3_getcolreg, retz3_setcolreg, retz3_blank +}; + + +/* -------------------- Generic routines ------------------------------------ */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par) +{ + if (current_par_valid) + *par = current_par; + else + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par); +} + + +static void retz3_fb_set_par(struct retz3_fb_par *par) +{ + current_par = *par; + current_par_valid = 1; +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct retz3_fb_par par; + + if ((err = fbhw->decode_var(var, &par))) + return err; + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + retz3_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + +#if 1 + retz3_set_video(var, ¤t_par); +#endif + return 0; +} + + +/* + * Default Colormaps + */ + +static unsigned short red16[] = + { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, + 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }; +static unsigned short green16[] = + { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000, + 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }; +static unsigned short blue16[] = + { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, + 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff }; + + +static struct fb_cmap default_16_colors = + { 0, 16, red16, green16, blue16, NULL }; + + +static struct fb_cmap *get_default_colormap(int bpp) +{ + return &default_16_colors; +} + + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) +#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ + ((1<<(width))-1)) : 0)) + +static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + unsigned short *red, *green, *blue, *transp; + unsigned int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) + return 0; + hred = CNVT_FROMHW(hred, var->red.length); + hgreen = CNVT_FROMHW(hgreen, var->green.length); + hblue = CNVT_FROMHW(hblue, var->blue.length); + htransp = CNVT_FROMHW(htransp, var->transp.length); + if (kspc) { + *red = hred; + *green = hgreen; + *blue = hblue; + if (transp) + *transp = htransp; + } else { + put_user(hred, red); + put_user(hgreen, green); + put_user(hblue, blue); + if (transp) + put_user(htransp, transp); + } + red++; + green++; + blue++; + if (transp) + transp++; + } + return 0; +} + + +static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, + int kspc) +{ + int i, start; + unsigned short *red, *green, *blue, *transp; + unsigned int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (kspc) { + hred = *red; + hgreen = *green; + hblue = *blue; + htransp = transp ? *transp : 0; + } else { + get_user(hred, red); + get_user(hgreen, green); + get_user(hblue, blue); + if (transp) + get_user(htransp, transp); + else + htransp = 0; + } + hred = CNVT_TOHW(hred, var->red.length); + hgreen = CNVT_TOHW(hgreen, var->green.length); + hblue = CNVT_TOHW(hblue, var->blue.length); + htransp = CNVT_TOHW(htransp, var->transp.length); + red++; + green++; + blue++; + if (transp) + transp++; + if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) + return 0; + } + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (disp[con].cmap.len) + do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1); + else + do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel), + &disp[con].var, 1); +} + + +static void memcpy_fs(int fsfromto, void *to, void *from, int len) +{ + switch (fsfromto) { + case 0: + memcpy(to, from, len); + return; + case 1: + copy_from_user(to, from, len); + return; + case 2: + copy_to_user(to, from, len); + return; + } +} + + +static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) +{ + int size; + int tooff = 0, fromoff = 0; + + if (to->start > from->start) + fromoff = to->start-from->start; + else + tooff = from->start-to->start; + size = to->len-tooff; + if (size > from->len-fromoff) + size = from->len-fromoff; + if (size < 0) + return; + size *= sizeof(unsigned short); + memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); + memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); + memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy_fs(fsfromto, to->transp+tooff, + from->transp+fromoff, size); +} + + +static int alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + int size = len*sizeof(unsigned short); + + if (cmap->len != len) { + if (cmap->red) + kfree(cmap->red); + if (cmap->green) + kfree(cmap->green); + if (cmap->blue) + kfree(cmap->blue); + if (cmap->transp) + kfree(cmap->transp); + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; + if (!len) + return 0; + if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) + return -1; + if (transp) { + if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + return -1; + } else + cmap->transp = NULL; + } + cmap->start = 0; + cmap->len = len; + copy_cmap(get_default_colormap(len), cmap, 0); + return 0; +} + + +/* + * Get the Fixed Part of the Display + */ + +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) + retz3_fb_get_par(&par); + else + error = fbhw->decode_var(&disp[con].var, &par); + return(error ? error : fbhw->encode_fix(fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) { + retz3_fb_get_par(&par); + error = fbhw->encode_var(var, &par); + } else + *var = disp[con].var; + return error; +} + + +static void retz3_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + + retz3_fb_get_fix(&fix, con); + if (con == -1) + con = 0; + disp[con].screen_base = (unsigned char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = z3fb_inverse; +} + + +/* + * Set the User Defined Part of the Display + */ + +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; + + if ((err = do_fb_set_var(var, con == currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = disp[con].var.xres; + oldyres = disp[con].var.yres; + oldvxres = disp[con].var.xres_virtual; + oldvyres = disp[con].var.yres_virtual; + oldbpp = disp[con].var.bits_per_pixel; + disp[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + retz3_fb_set_disp(con); + (*fb_info.changevar)(con); + alloc_cmap(&disp[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate = 0; + return 0; +} + + +/* + * Get the Colormap + */ + +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return(do_fb_get_cmap(cmap, &disp[con].var, kspc)); + else if (disp[con].cmap.len) /* non default colormap? */ + copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); + else + copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + +/* + * Set the Colormap + */ + +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!disp[con].cmap.len) { /* no colormap allocated? */ + if ((err = alloc_cmap(&disp[con].cmap, + 1<<disp[con].var.bits_per_pixel, 0))) + return err; + } + if (con == currcon) /* current console? */ + return(do_fb_set_cmap(cmap, &disp[con].var, kspc)); + else + copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1); + return 0; +} + + +/* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + return -EINVAL; +} + + +/* + * RetinaZ3 Frame Buffer Specific ioctls + */ + +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con) +{ + return -EINVAL; +} + + +static struct fb_ops retz3_fb_ops = { + retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap, + retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl +}; + + +int retz3_probe(void) +{ + z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0); + return(z3_key); +} + + +void retz3_video_setup(char *options, int *ints) +{ + char *this_opt; + int i; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")){ + if (!strcmp(this_opt, "inverse")) { + z3fb_inverse = 1; + for (i = 0; i < 16; i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else + z3fb_mode = get_video_mode(this_opt); + } +} + + +/* + * Initialization + */ + +struct fb_info *retz3_fb_init(long *mem_start) +{ + int err; + struct retz3_fb_par par; + + memstart = mem_start; + + fbhw = &retz3_switch; + + err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops, + NUM_TOTAL_MODES, retz3_fb_predefined); + if (err < 0) + panic("Cannot register frame buffer\n"); + + fbhw->init(); + + if (z3fb_mode == -1) + z3fb_mode = 1; + + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par); + fbhw->encode_var(&retz3_fb_predefined[0], &par); + + strcpy(fb_info.modename, retz3_fb_name); + fb_info.disp = disp; + fb_info.switch_con = &z3fb_switch; + fb_info.updatevar = &z3fb_updatevar; + fb_info.blank = &z3fb_blank; + fb_info.setcmap = &z3fb_setcmap; + + do_fb_set_var(&retz3_fb_predefined[0], 0); + retz3_fb_get_var(&disp[0].var, -1); + retz3_fb_set_disp(-1); + do_install_cmap(0); + + return &fb_info; +} + + +static int z3fb_switch(int con) +{ + /* Do we have to save the colormap? */ + if (disp[currcon].cmap.len) + do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1); + + do_fb_set_var(&disp[con].var, 1); + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int z3fb_updatevar(int con) +{ + return 0; +} + + +/* + * Blank the display. + */ + +static void z3fb_blank(int blank) +{ + fbhw->blank(blank); +} + + +/* + * Set the colormap + */ + +static int z3fb_setcmap(struct fb_cmap *cmap, int con) +{ + return(retz3_fb_set_cmap(cmap, 1, con)); +} + + +/* + * Get a Video Mode + */ + +static int get_video_mode(const char *name) +{ + int i; + + for (i = 1; i <= NUM_PREDEF_MODES; i++) + if (!strcmp(name, retz3_fb_modenames[i])){ + retz3_fb_predefined[0] = retz3_fb_predefined[i]; + return i; + } + return -1; +} diff --git a/arch/m68k/amiga/retz3fb.h b/arch/m68k/amiga/retz3fb.h new file mode 100644 index 000000000..9ff209060 --- /dev/null +++ b/arch/m68k/amiga/retz3fb.h @@ -0,0 +1,572 @@ +/* + * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the + * RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * History: + * - 22 Jan 97: Initial work + * + * + * 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. + */ + +/* + * Macros to read and write to registers. + */ +#define reg_w(reg,dat) (*(z3_regs + reg) = dat) +#define reg_r(reg) (*(z3_regs + reg)) + +/* + * Macro to access the sequencer. + */ +#define seq_w(sreg,sdat) \ + do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) + +/* + * Macro to access the CRT controller. + */ +#define crt_w(creg,cdat) \ + do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) + +/* + * Macro to access the graphics controller. + */ +#define gfx_w(greg,gdat) \ + do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) + +/* + * Macro to access the attribute controller. + */ +#define attr_w(areg,adat) \ + do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) + +/* + * Macro to access the pll. + */ +#define pll_w(preg,pdat) \ + do{ reg_w(PLL_IDX, preg); \ + reg_w(PLL_DATA, (pdat & 0xff)); \ + reg_w(PLL_DATA, (pdat >> 8));\ + } while(0) + +/* + * Offsets + */ +#define VIDEO_MEM_OFFSET 0x00c00000 +#define ACM_OFFSET 0x00b00000 + +/* + * Accelerator Control Menu + */ +#define ACM_PRIMARY_OFFSET 0x00 +#define ACM_SECONDARY_OFFSET 0x04 +#define ACM_MODE_CONTROL 0x08 +#define ACM_CURSOR_POSITION 0x0c +#define ACM_START_STATUS 0x30 +#define ACM_CONTROL 0x34 +#define ACM_RASTEROP_ROTATION 0x38 +#define ACM_BITMAP_DIMENSION 0x3c +#define ACM_DESTINATION 0x40 +#define ACM_SOURCE 0x44 +#define ACM_PATTERN 0x48 +#define ACM_FOREGROUND 0x4c +#define ACM_BACKGROUND 0x50 + +/* + * Video DAC addresses + */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + +/* + * Sequencer + */ +#define SEQ_IDX 0x03c4 /* Sequencer Index */ +#define SEQ_DATA 0x03c5 +#define SEQ_RESET 0x00 +#define SEQ_CLOCKING_MODE 0x01 +#define SEQ_MAP_MASK 0x02 +#define SEQ_CHAR_MAP_SELECT 0x03 +#define SEQ_MEMORY_MODE 0x04 +#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ +#define SEQ_UNKNOWN1 0x06 +#define SEQ_UNKNOWN2 0x07 +#define SEQ_CHIP_ID 0x08 +#define SEQ_UNKNOWN3 0x09 +#define SEQ_CURSOR_COLOR1 0x0a +#define SEQ_CURSOR_COLOR0 0x0b +#define SEQ_CURSOR_CONTROL 0x0c +#define SEQ_CURSOR_X_LOC_HI 0x0d +#define SEQ_CURSOR_X_LOC_LO 0x0e +#define SEQ_CURSOR_Y_LOC_HI 0x0f +#define SEQ_CURSOR_Y_LOC_LO 0x10 +#define SEQ_CURSOR_X_INDEX 0x11 +#define SEQ_CURSOR_Y_INDEX 0x12 +#define SEQ_CURSOR_STORE_HI 0x13 +#define SEQ_CURSOR_STORE_LO 0x14 +#define SEQ_CURSOR_ST_OFF_HI 0x15 +#define SEQ_CURSOR_ST_OFF_LO 0x16 +#define SEQ_CURSOR_PIXELMASK 0x17 +#define SEQ_PRIM_HOST_OFF_HI 0x18 +#define SEQ_PRIM_HOST_OFF_LO 0x19 +#define SEQ_LINEAR_0 0x1a +#define SEQ_LINEAR_1 0x1b +#define SEQ_SEC_HOST_OFF_HI 0x1c +#define SEQ_SEC_HOST_OFF_LO 0x1d +#define SEQ_EXTENDED_MEM_ENA 0x1e +#define SEQ_EXT_CLOCK_MODE 0x1f +#define SEQ_EXT_VIDEO_ADDR 0x20 +#define SEQ_EXT_PIXEL_CNTL 0x21 +#define SEQ_BUS_WIDTH_FEEDB 0x22 +#define SEQ_PERF_SELECT 0x23 +#define SEQ_COLOR_EXP_WFG 0x24 +#define SEQ_COLOR_EXP_WBG 0x25 +#define SEQ_EXT_RW_CONTROL 0x26 +#define SEQ_MISC_FEATURE_SEL 0x27 +#define SEQ_COLOR_KEY_CNTL 0x28 +#define SEQ_COLOR_KEY_MATCH0 0x29 +#define SEQ_COLOR_KEY_MATCH1 0x2a +#define SEQ_COLOR_KEY_MATCH2 0x2b +#define SEQ_UNKNOWN6 0x2c +#define SEQ_CRC_CONTROL 0x2d +#define SEQ_CRC_DATA_LOW 0x2e +#define SEQ_CRC_DATA_HIGH 0x2f +#define SEQ_MEMORY_MAP_CNTL 0x30 +#define SEQ_ACM_APERTURE_1 0x31 +#define SEQ_ACM_APERTURE_2 0x32 +#define SEQ_ACM_APERTURE_3 0x33 +#define SEQ_BIOS_UTILITY_0 0x3e +#define SEQ_BIOS_UTILITY_1 0x3f + +/* + * Graphics Controller + */ +#define GFX_IDX 0x03ce +#define GFX_DATA 0x03cf +#define GFX_SET_RESET 0x00 +#define GFX_ENABLE_SET_RESET 0x01 +#define GFX_COLOR_COMPARE 0x02 +#define GFX_DATA_ROTATE 0x03 +#define GFX_READ_MAP_SELECT 0x04 +#define GFX_GRAPHICS_MODE 0x05 +#define GFX_MISC 0x06 +#define GFX_COLOR_XCARE 0x07 +#define GFX_BITMASK 0x08 + +/* + * CRT Controller + */ +#define CRT_IDX 0x03d4 +#define CRT_DATA 0x03d5 +#define CRT_HOR_TOTAL 0x00 +#define CRT_HOR_DISP_ENA_END 0x01 +#define CRT_START_HOR_BLANK 0x02 +#define CRT_END_HOR_BLANK 0x03 +#define CRT_START_HOR_RETR 0x04 +#define CRT_END_HOR_RETR 0x05 +#define CRT_VER_TOTAL 0x06 +#define CRT_OVERFLOW 0x07 +#define CRT_PRESET_ROW_SCAN 0x08 +#define CRT_MAX_SCAN_LINE 0x09 +#define CRT_CURSOR_START 0x0a +#define CRT_CURSOR_END 0x0b +#define CRT_START_ADDR_HIGH 0x0c +#define CRT_START_ADDR_LOW 0x0d +#define CRT_CURSOR_LOC_HIGH 0x0e +#define CRT_CURSOR_LOC_LOW 0x0f +#define CRT_START_VER_RETR 0x10 +#define CRT_END_VER_RETR 0x11 +#define CRT_VER_DISP_ENA_END 0x12 +#define CRT_OFFSET 0x13 +#define CRT_UNDERLINE_LOC 0x14 +#define CRT_START_VER_BLANK 0x15 +#define CRT_END_VER_BLANK 0x16 +#define CRT_MODE_CONTROL 0x17 +#define CRT_LINE_COMPARE 0x18 +#define CRT_UNKNOWN1 0x19 +#define CRT_UNKNOWN2 0x1a +#define CRT_UNKNOWN3 0x1b +#define CRT_UNKNOWN4 0x1c +#define CRT_UNKNOWN5 0x1d +#define CRT_UNKNOWN6 0x1e +#define CRT_UNKNOWN7 0x1f +#define CRT_UNKNOWN8 0x20 +#define CRT_UNKNOWN9 0x21 +#define CRT_UNKNOWN10 0x22 +#define CRT_UNKNOWN11 0x23 +#define CRT_UNKNOWN12 0x24 +#define CRT_UNKNOWN13 0x25 +#define CRT_UNKNOWN14 0x26 +#define CRT_UNKNOWN15 0x27 +#define CRT_UNKNOWN16 0x28 +#define CRT_UNKNOWN17 0x29 +#define CRT_UNKNOWN18 0x2a +#define CRT_UNKNOWN19 0x2b +#define CRT_UNKNOWN20 0x2c +#define CRT_UNKNOWN21 0x2d +#define CRT_UNKNOWN22 0x2e +#define CRT_UNKNOWN23 0x2f +#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ +#define CRT_EXT_START_ADDR 0x31 +#define CRT_EXT_HOR_TIMING2 0x32 +#define CRT_EXT_VER_TIMING 0x33 +#define CRT_MONITOR_POWER 0x34 + +/* + * General Registers + */ +#define GREG_STATUS0_R 0x03c2 +#define GREG_STATUS1_R 0x03da +#define GREG_MISC_OUTPUT_R 0x03cc +#define GREG_MISC_OUTPUT_W 0x03c2 +#define GREG_FEATURE_CONTROL_R 0x03ca +#define GREG_FEATURE_CONTROL_W 0x03da +#define GREG_POS 0x0102 + +/* + * Attribute Controller + */ +#define ACT_IDX 0x03C0 +#define ACT_ADDRESS_R 0x03C0 +#define ACT_DATA 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_PALETTE0 0x00 +#define ACT_PALETTE1 0x01 +#define ACT_PALETTE2 0x02 +#define ACT_PALETTE3 0x03 +#define ACT_PALETTE4 0x04 +#define ACT_PALETTE5 0x05 +#define ACT_PALETTE6 0x06 +#define ACT_PALETTE7 0x07 +#define ACT_PALETTE8 0x08 +#define ACT_PALETTE9 0x09 +#define ACT_PALETTE10 0x0A +#define ACT_PALETTE11 0x0B +#define ACT_PALETTE12 0x0C +#define ACT_PALETTE13 0x0D +#define ACT_PALETTE14 0x0E +#define ACT_PALETTE15 0x0F +#define ACT_ATTR_MODE_CNTL 0x10 +#define ACT_OVERSCAN_COLOR 0x11 +#define ACT_COLOR_PLANE_ENA 0x12 +#define ACT_HOR_PEL_PANNING 0x13 +#define ACT_COLOR_SELECT 0x14 + +/* + * PLL + */ +#define PLL_IDX 0x83c8 +#define PLL_DATA 0x83c9 + +/* + * Blitter operations + */ +#define Z3BLTclear 0x00 /* 0 */ +#define Z3BLTand 0x80 /* src AND dst */ +#define Z3BLTandReverse 0x40 /* src AND NOT dst */ +#define Z3BLTcopy 0xc0 /* src */ +#define Z3BLTandInverted 0x20 /* NOT src AND dst */ +#define Z3BLTnoop 0xa0 /* dst */ +#define Z3BLTxor 0x60 /* src XOR dst */ +#define Z3BLTor 0xe0 /* src OR dst */ +#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ +#define Z3BLTequiv 0x90 /* NOT src XOR dst */ +#define Z3BLTinvert 0x50 /* NOT dst */ +#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ +#define Z3BLTcopyInverted 0x30 /* NOT src */ +#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ +#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ +#define Z3BLTset 0xf0 /* 1 */ +/* + * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the + * RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * History: + * - 22 Jan 97: Initial work + * + * + * 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. + */ + +/* + * Macros to read and write to registers. + */ +#define reg_w(reg,dat) (*(z3_regs + reg) = dat) +#define reg_r(reg) (*(z3_regs + reg)) + +/* + * Macro to access the sequencer. + */ +#define seq_w(sreg,sdat) \ + do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) + +/* + * Macro to access the CRT controller. + */ +#define crt_w(creg,cdat) \ + do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) + +/* + * Macro to access the graphics controller. + */ +#define gfx_w(greg,gdat) \ + do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) + +/* + * Macro to access the attribute controller. + */ +#define attr_w(areg,adat) \ + do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) + +/* + * Macro to access the pll. + */ +#define pll_w(preg,pdat) \ + do{ reg_w(PLL_IDX, preg); \ + reg_w(PLL_DATA, (pdat & 0xff)); \ + reg_w(PLL_DATA, (pdat >> 8));\ + } while(0) + +/* + * Offsets + */ +#define VIDEO_MEM_OFFSET 0x00c00000 +#define ACM_OFFSET 0x00b00000 + +/* + * Accelerator Control Menu + */ +#define ACM_PRIMARY_OFFSET 0x00 +#define ACM_SECONDARY_OFFSET 0x04 +#define ACM_MODE_CONTROL 0x08 +#define ACM_CURSOR_POSITION 0x0c +#define ACM_START_STATUS 0x30 +#define ACM_CONTROL 0x34 +#define ACM_RASTEROP_ROTATION 0x38 +#define ACM_BITMAP_DIMENSION 0x3c +#define ACM_DESTINATION 0x40 +#define ACM_SOURCE 0x44 +#define ACM_PATTERN 0x48 +#define ACM_FOREGROUND 0x4c +#define ACM_BACKGROUND 0x50 + +/* + * Video DAC addresses + */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + +/* + * Sequencer + */ +#define SEQ_IDX 0x03c4 /* Sequencer Index */ +#define SEQ_DATA 0x03c5 +#define SEQ_RESET 0x00 +#define SEQ_CLOCKING_MODE 0x01 +#define SEQ_MAP_MASK 0x02 +#define SEQ_CHAR_MAP_SELECT 0x03 +#define SEQ_MEMORY_MODE 0x04 +#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ +#define SEQ_UNKNOWN1 0x06 +#define SEQ_UNKNOWN2 0x07 +#define SEQ_CHIP_ID 0x08 +#define SEQ_UNKNOWN3 0x09 +#define SEQ_CURSOR_COLOR1 0x0a +#define SEQ_CURSOR_COLOR0 0x0b +#define SEQ_CURSOR_CONTROL 0x0c +#define SEQ_CURSOR_X_LOC_HI 0x0d +#define SEQ_CURSOR_X_LOC_LO 0x0e +#define SEQ_CURSOR_Y_LOC_HI 0x0f +#define SEQ_CURSOR_Y_LOC_LO 0x10 +#define SEQ_CURSOR_X_INDEX 0x11 +#define SEQ_CURSOR_Y_INDEX 0x12 +#define SEQ_CURSOR_STORE_HI 0x13 +#define SEQ_CURSOR_STORE_LO 0x14 +#define SEQ_CURSOR_ST_OFF_HI 0x15 +#define SEQ_CURSOR_ST_OFF_LO 0x16 +#define SEQ_CURSOR_PIXELMASK 0x17 +#define SEQ_PRIM_HOST_OFF_HI 0x18 +#define SEQ_PRIM_HOST_OFF_LO 0x19 +#define SEQ_LINEAR_0 0x1a +#define SEQ_LINEAR_1 0x1b +#define SEQ_SEC_HOST_OFF_HI 0x1c +#define SEQ_SEC_HOST_OFF_LO 0x1d +#define SEQ_EXTENDED_MEM_ENA 0x1e +#define SEQ_EXT_CLOCK_MODE 0x1f +#define SEQ_EXT_VIDEO_ADDR 0x20 +#define SEQ_EXT_PIXEL_CNTL 0x21 +#define SEQ_BUS_WIDTH_FEEDB 0x22 +#define SEQ_PERF_SELECT 0x23 +#define SEQ_COLOR_EXP_WFG 0x24 +#define SEQ_COLOR_EXP_WBG 0x25 +#define SEQ_EXT_RW_CONTROL 0x26 +#define SEQ_MISC_FEATURE_SEL 0x27 +#define SEQ_COLOR_KEY_CNTL 0x28 +#define SEQ_COLOR_KEY_MATCH0 0x29 +#define SEQ_COLOR_KEY_MATCH1 0x2a +#define SEQ_COLOR_KEY_MATCH2 0x2b +#define SEQ_UNKNOWN6 0x2c +#define SEQ_CRC_CONTROL 0x2d +#define SEQ_CRC_DATA_LOW 0x2e +#define SEQ_CRC_DATA_HIGH 0x2f +#define SEQ_MEMORY_MAP_CNTL 0x30 +#define SEQ_ACM_APERTURE_1 0x31 +#define SEQ_ACM_APERTURE_2 0x32 +#define SEQ_ACM_APERTURE_3 0x33 +#define SEQ_BIOS_UTILITY_0 0x3e +#define SEQ_BIOS_UTILITY_1 0x3f + +/* + * Graphics Controller + */ +#define GFX_IDX 0x03ce +#define GFX_DATA 0x03cf +#define GFX_SET_RESET 0x00 +#define GFX_ENABLE_SET_RESET 0x01 +#define GFX_COLOR_COMPARE 0x02 +#define GFX_DATA_ROTATE 0x03 +#define GFX_READ_MAP_SELECT 0x04 +#define GFX_GRAPHICS_MODE 0x05 +#define GFX_MISC 0x06 +#define GFX_COLOR_XCARE 0x07 +#define GFX_BITMASK 0x08 + +/* + * CRT Controller + */ +#define CRT_IDX 0x03d4 +#define CRT_DATA 0x03d5 +#define CRT_HOR_TOTAL 0x00 +#define CRT_HOR_DISP_ENA_END 0x01 +#define CRT_START_HOR_BLANK 0x02 +#define CRT_END_HOR_BLANK 0x03 +#define CRT_START_HOR_RETR 0x04 +#define CRT_END_HOR_RETR 0x05 +#define CRT_VER_TOTAL 0x06 +#define CRT_OVERFLOW 0x07 +#define CRT_PRESET_ROW_SCAN 0x08 +#define CRT_MAX_SCAN_LINE 0x09 +#define CRT_CURSOR_START 0x0a +#define CRT_CURSOR_END 0x0b +#define CRT_START_ADDR_HIGH 0x0c +#define CRT_START_ADDR_LOW 0x0d +#define CRT_CURSOR_LOC_HIGH 0x0e +#define CRT_CURSOR_LOC_LOW 0x0f +#define CRT_START_VER_RETR 0x10 +#define CRT_END_VER_RETR 0x11 +#define CRT_VER_DISP_ENA_END 0x12 +#define CRT_OFFSET 0x13 +#define CRT_UNDERLINE_LOC 0x14 +#define CRT_START_VER_BLANK 0x15 +#define CRT_END_VER_BLANK 0x16 +#define CRT_MODE_CONTROL 0x17 +#define CRT_LINE_COMPARE 0x18 +#define CRT_UNKNOWN1 0x19 +#define CRT_UNKNOWN2 0x1a +#define CRT_UNKNOWN3 0x1b +#define CRT_UNKNOWN4 0x1c +#define CRT_UNKNOWN5 0x1d +#define CRT_UNKNOWN6 0x1e +#define CRT_UNKNOWN7 0x1f +#define CRT_UNKNOWN8 0x20 +#define CRT_UNKNOWN9 0x21 +#define CRT_UNKNOWN10 0x22 +#define CRT_UNKNOWN11 0x23 +#define CRT_UNKNOWN12 0x24 +#define CRT_UNKNOWN13 0x25 +#define CRT_UNKNOWN14 0x26 +#define CRT_UNKNOWN15 0x27 +#define CRT_UNKNOWN16 0x28 +#define CRT_UNKNOWN17 0x29 +#define CRT_UNKNOWN18 0x2a +#define CRT_UNKNOWN19 0x2b +#define CRT_UNKNOWN20 0x2c +#define CRT_UNKNOWN21 0x2d +#define CRT_UNKNOWN22 0x2e +#define CRT_UNKNOWN23 0x2f +#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ +#define CRT_EXT_START_ADDR 0x31 +#define CRT_EXT_HOR_TIMING2 0x32 +#define CRT_EXT_VER_TIMING 0x33 +#define CRT_MONITOR_POWER 0x34 + +/* + * General Registers + */ +#define GREG_STATUS0_R 0x03c2 +#define GREG_STATUS1_R 0x03da +#define GREG_MISC_OUTPUT_R 0x03cc +#define GREG_MISC_OUTPUT_W 0x03c2 +#define GREG_FEATURE_CONTROL_R 0x03ca +#define GREG_FEATURE_CONTROL_W 0x03da +#define GREG_POS 0x0102 + +/* + * Attribute Controller + */ +#define ACT_IDX 0x03C0 +#define ACT_ADDRESS_R 0x03C0 +#define ACT_DATA 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_PALETTE0 0x00 +#define ACT_PALETTE1 0x01 +#define ACT_PALETTE2 0x02 +#define ACT_PALETTE3 0x03 +#define ACT_PALETTE4 0x04 +#define ACT_PALETTE5 0x05 +#define ACT_PALETTE6 0x06 +#define ACT_PALETTE7 0x07 +#define ACT_PALETTE8 0x08 +#define ACT_PALETTE9 0x09 +#define ACT_PALETTE10 0x0A +#define ACT_PALETTE11 0x0B +#define ACT_PALETTE12 0x0C +#define ACT_PALETTE13 0x0D +#define ACT_PALETTE14 0x0E +#define ACT_PALETTE15 0x0F +#define ACT_ATTR_MODE_CNTL 0x10 +#define ACT_OVERSCAN_COLOR 0x11 +#define ACT_COLOR_PLANE_ENA 0x12 +#define ACT_HOR_PEL_PANNING 0x13 +#define ACT_COLOR_SELECT 0x14 + +/* + * PLL + */ +#define PLL_IDX 0x83c8 +#define PLL_DATA 0x83c9 + +/* + * Blitter operations + */ +#define Z3BLTclear 0x00 /* 0 */ +#define Z3BLTand 0x80 /* src AND dst */ +#define Z3BLTandReverse 0x40 /* src AND NOT dst */ +#define Z3BLTcopy 0xc0 /* src */ +#define Z3BLTandInverted 0x20 /* NOT src AND dst */ +#define Z3BLTnoop 0xa0 /* dst */ +#define Z3BLTxor 0x60 /* src XOR dst */ +#define Z3BLTor 0xe0 /* src OR dst */ +#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ +#define Z3BLTequiv 0x90 /* NOT src XOR dst */ +#define Z3BLTinvert 0x50 /* NOT dst */ +#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ +#define Z3BLTcopyInverted 0x30 /* NOT src */ +#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ +#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ +#define Z3BLTset 0xf0 /* 1 */ diff --git a/arch/m68k/amiga/zorro.c b/arch/m68k/amiga/zorro.c index ccc9c7249..acca3e6bc 100644 --- a/arch/m68k/amiga/zorro.c +++ b/arch/m68k/amiga/zorro.c @@ -16,7 +16,7 @@ #include <asm/setup.h> #include <asm/bitops.h> #include <asm/amigahw.h> -#include <asm/zorro.h> +#include <linux/zorro.h> #ifdef CONFIG_ZORRO @@ -82,6 +82,10 @@ BEGIN_PROD(MEMPHIS) PROD("Stormbringer", STORMBRINGER) END +BEGIN_PROD(3_STATE) + PROD("Megamix 2000 RAM", MEGAMIX_2000) +END + BEGIN_PROD(COMMODORE2) PROD("A2088 XT Bridgeboard", A2088) PROD("A2286 AT Bridgeboard", A2286) @@ -141,8 +145,12 @@ BEGIN_PROD(MICROBOTICS) PROD("StarDrive", STARDRIVE) PROD("8-Up (Rev A)", 8_UP_A) PROD("8-Up (Rev Z)", 8_UP_Z) + PROD("Delta Card RAM", DELTA_RAM) + PROD("8-Star RAM", 8_STAR_RAM) + PROD("8-Star", 8_STAR) PROD("VXL RAM", VXL_RAM) PROD("VXL-30 Turbo Board", VXL_30) + PROD("Delta Card", DELTA) PROD("MBX 1200", MBX_1200) PROD("Hardframe 2000", HARDFRAME_2000) PROD("MBX 1200", MBX_1200_2) @@ -180,8 +188,8 @@ BEGIN_PROD(SUPRA) PROD("SupraDrive 4x4 SCSI Controller", SUPRADRIVE_4x4) PROD("2000 DMA HD", SUPRA_2000) PROD("500 HD/RAM", SUPRA_500) + PROD("500XP/2000 RAM", SUPRA_500XP) PROD("500RX/2000 RAM", SUPRA_500RX) - PROD("500RX/2000 RAM", SUPRA_500RX_2) PROD("2400zi Modem", SUPRA_2400ZI) PROD("Wordsync SCSI Controller", WORDSYNC) PROD("Wordsync II SCSI Controller", WORDSYNC_II) @@ -193,6 +201,10 @@ BEGIN_PROD(CSA) PROD("12 Gauge SCSI Controller", 12GAUGE) END +BEGIN_PROD(MTEC2) + PROD("AT500 RAM", AT500_2) +END + BEGIN_PROD(GVP3) PROD("Impact SCSI/Memory", IMPACT) END @@ -203,7 +215,11 @@ END BEGIN_PROD(POWER_COMPUTING) PROD("DKB 3128 RAM", DKB_3128) + PROD("Rapid Fire SCSI Controller", RAPID_FIRE) + PROD("DKB 1202 RAM", DKB_1202) PROD("DKB Cobra / Viper II Turbo Board", VIPER_II_COBRA) + PROD("WildFire 060 Turbo Board", WILDFIRE_060) + PROD("WildFire 060 Turbo Board", WILDFIRE_060_2) END BEGIN_PROD(GVP) @@ -257,6 +273,9 @@ BEGIN_PROD(PPI) PROD("PP&S A500 68040 Turbo Board", PPS_A500_040) END +BEGIN_PROD(XEBEC) +END + BEGIN_PROD(SPIRIT) PROD("HDA 506 Harddisk", HDA_506) PROD("OctaByte RAM", OCTABYTE_RAM) @@ -268,6 +287,7 @@ END BEGIN_PROD(BSC3) PROD("ALF 2 SCSI Controller", ALF_2_SCSI) + PROD("ALF 2 SCSI Controller", ALF_2_SCSI_2) PROD("ALF 3 SCSI Controller", ALF_3_SCSI_2) END @@ -291,9 +311,17 @@ END BEGIN_PROD(KUPKE2) PROD("Golem SCSI-II Controller", KUPKE_SCSI_II) PROD("Golem Box", GOLEM_BOX) + PROD("030/882 Turbo Board", KUPKE_TURBO) PROD("Golem SCSI/AT Controller", KUPKE_SCSI_AT) END +BEGIN_PROD(GVP4) + PROD("A2000-RAM8/2", A2000_RAM8) +END + +BEGIN_PROD(INTERWORKS_NET) +END + BEGIN_PROD(HARDITAL) PROD("TQM 68030+68882 Turbo Board", TQM) END @@ -301,10 +329,14 @@ END BEGIN_PROD(BSC2) PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI) PROD("Tandem AT-2008/508 IDE Controller", TANDEM) + PROD("Alpha RAM 1200", ALPHA_RAM_1200) PROD("Oktagon 2008 RAM", OKTAGON_RAM) PROD("Alfa Data MultiFace I", MULTIFACE_I) PROD("Alfa Data MultiFace II", MULTIFACE_II) PROD("Alfa Data MultiFace III", MULTIFACE_III) + PROD("Framebuffer", BSC_FRAEMBUFFER) + PROD("Graffiti Graphics Board (RAM)", GRAFFITI_RAM) + PROD("Graffiti Graphics Board (REG)", GRAFFITI_REG) PROD("ISDN MasterCard", ISDN_MASTERCARD) PROD("ISDN MasterCard II", ISDN_MASTERCARD_2) END @@ -319,12 +351,15 @@ BEGIN_PROD(IMPULSE) END BEGIN_PROD(IVS) - PROD("GrandSlam RAM", GRANDSLAM) + PROD("GrandSlam PIC 2 RAM", GRANDSLAM_PIC_2) + PROD("GrandSlam PIC 1 RAM", GRANDSLAM_PIC_1) PROD("OverDrive HD", IVS_OVERDRIVE) PROD("Trumpcard Classic SCSI Controller", TRUMPCARD_CLASSIC) PROD("Trumpcard Pro SCSI Controller", TRUMPCARD_PRO) PROD("Meta-4 RAM", META_4) + PROD("Wavetools Sound Board", WAVETOOLS) PROD("Vector SCSI Controller", VECTOR) + PROD("Vector SCSI Controller", VECTOR_2) END BEGIN_PROD(VECTOR) @@ -336,6 +371,7 @@ BEGIN_PROD(XPERT_PRODEV) PROD("Visiona Graphics Board (REG)", VISIONA_REG) PROD("Merlin Graphics Board (RAM)", MERLIN_RAM) PROD("Merlin Graphics Board (REG)", MERLIN_REG) + PROD("Merlin Graphics Board (REG)", MERLIN_REG_2) END BEGIN_PROD(HYDRA_SYSTEMS) @@ -388,7 +424,11 @@ BEGIN_PROD(VILLAGE_TRONIC) PROD("Domino Graphics Board (REG)", DOMINO_REG) PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM) PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG) - PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG_2) + PROD("Picasso II/II+ Graphics Board (Segmented Mode)", PICASSO_II_SEGM) + PROD("Picassio IV Graphics Board", PICASSO_IV) + PROD("Picassio IV Graphics Board", PICASSO_IV_2) + PROD("Picassio IV Graphics Board", PICASSO_IV_3) + PROD("Picassio IV Graphics Board", PICASSO_IV_4) PROD("Ariadne Ethernet Card", ARIADNE) END @@ -402,8 +442,18 @@ BEGIN_PROD(AMITRIX) PROD("CD-RAM Memory", AMITRIX_CD_RAM) END +BEGIN_PROD(ARMAX) + PROD("OmniBus Graphics Board", OMNIBUS) +END + +BEGIN_PROD(NEWTEK) + PROD("VideoToaster", VIDEOTOASTER) +END + BEGIN_PROD(MTEC) + PROD("AT500 IDE Controller", AT500) PROD("68030 Turbo Board", MTEC_68030) + PROD("68020i Turbo Board", MTEC_68020I) PROD("A1200 T68030/42 RTC Turbo Board", MTEC_T1230) PROD("8MB RAM", MTEC_RAM) END @@ -439,6 +489,11 @@ BEGIN_PROD(MICRONIK) PROD("RCA 120 RAM", RCA_120) END +BEGIN_PROD(MEGA_MICRO) + PROD("SCRAM 500 SCSI Controller", SCRAM_500_SCSI) + PROD("SCRAM 500 RAM", SCRAM_500_RAM) +END + BEGIN_PROD(IMTRONICS2) PROD("Hurricane 2800 68030", HURRICANE_2800_3) PROD("Hurricane 2800 68030", HURRICANE_2800_4) @@ -448,6 +503,15 @@ BEGIN_PROD(KUPKE3) PROD("Golem HD 3000", GOLEM_3000) END +BEGIN_PROD(ITH) + PROD("ISDN-Master II", ISDN_MASTER_II) +END + +BEGIN_PROD(VMC) + PROD("ISDN Blaster Z2", ISDN_BLASTER_Z2) + PROD("HyperCom 4", HYPERCOM_4) +END + BEGIN_PROD(INFORMATION) PROD("ISDN Engine I", ISDN_ENGINE_I) END @@ -479,6 +543,8 @@ BEGIN_PROD(PHASE5) PROD("Blizzard 2060 SCSI Controller", BLIZZARD_2060SCSI) PROD("CyberStorm Mk II", CYBERSTORM_II) PROD("CyberVision64 Graphics Board", CYBERVISION) + PROD("CyberVision64-3D Graphics Board Prototype)", CYBERVISION3D_PRT) + PROD("CyberVision64-3D Graphics Board", CYBERVISION3D) END BEGIN_PROD(DPS) @@ -487,6 +553,7 @@ END BEGIN_PROD(APOLLO2) PROD("A620 68020 Accelerator", A620) + PROD("A620 68020 Accelerator", A620_2) END BEGIN_PROD(APOLLO) @@ -494,6 +561,10 @@ BEGIN_PROD(APOLLO) PROD("Turbo Board", APOLLO_TURBO) END +BEGIN_PROD(PETSOFF) + PROD("Delfina DSP", DELFINA) +END + BEGIN_PROD(UWE_GERLACH) PROD("RAM/ROM", UG_RAM_ROM) END @@ -507,6 +578,7 @@ BEGIN_PROD(MACROSYSTEMS2) PROD("Toccata Sound Board", TOCCATA) PROD("Retina Z3 Graphics Board", RETINA_Z3) PROD("VLab Motion", VLAB_MOTION) + PROD("Altais Graphics Board", ALTAIS) PROD("Falcon '040 Turbo Board", FALCON_040) END @@ -514,11 +586,12 @@ BEGIN_PROD(COMBITEC) END BEGIN_PROD(SKI) + PROD("MAST Fireball SCSI Controller", MAST_FIREBALL) PROD("SCSI / Dual Serial", SKI_SCSI_SERIAL) END BEGIN_PROD(CAMERON) - PROD("Scanner Interface", CAMERON_SCANNER) + PROD("Personal A4", PERSONAL_A4) END BEGIN_PROD(REIS_WARE) @@ -530,6 +603,7 @@ BEGIN_MANUF MANUF("Pacific Peripherals", PACIFIC) MANUF("Kupke", KUPKE) MANUF("Memphis", MEMPHIS) + MANUF("3-State", 3_STATE) MANUF("Commodore", COMMODORE2) MANUF("Commodore", COMMODORE) MANUF("Commodore", COMMODORE3) @@ -546,7 +620,8 @@ BEGIN_MANUF MANUF("University of Lowell", UNIV_OF_LOWELL) MANUF("Ameristar", AMERISTAR) MANUF("Supra", SUPRA) - MANUF("CSA", CSA) + MANUF("Computer Systems Ass.", CSA) + MANUF("M-Tech", MTEC2) MANUF("Great Valley Products", GVP3) MANUF("ByteBox", BYTEBOX) MANUF("Power Computing", POWER_COMPUTING) @@ -554,6 +629,7 @@ BEGIN_MANUF MANUF("Synergy", SYNERGY) MANUF("Xetec", XETEC) MANUF("Progressive Peripherals", PPI) + MANUF("Xebec", XEBEC) MANUF("Spirit", SPIRIT) MANUF("BSC", BSC) MANUF("BSC", BSC3) @@ -562,6 +638,8 @@ BEGIN_MANUF MANUF("Checkpoint Technologies", CHECKPOINT) MANUF("ICD", ICD) MANUF("Kupke", KUPKE2) + MANUF("Great Valley Products", GVP4) + MANUF("Interworks Network", INTERWORKS_NET) MANUF("Hardital Synthesis", HARDITAL) MANUF("BSC", BSC2) MANUF("Advanced Systems & Software", ADV_SYS_SOFT) @@ -582,15 +660,20 @@ BEGIN_MANUF MANUF("Village Tronic", VILLAGE_TRONIC) MANUF("Utilities Unlimited", UTILITIES_ULTD) MANUF("Amitrix", AMITRIX) - MANUF("MTEC", MTEC) + MANUF("ArMax", ARMAX) + MANUF("NewTek", NEWTEK) + MANUF("M-Tech", MTEC) MANUF("Great Valley Products", GVP2) MANUF("Helfrich", HELFRICH2) MANUF("MacroSystems", MACROSYSTEMS) MANUF("ElBox Computer", ELBOX) MANUF("Harms Professional", HARMS_PROF) MANUF("Micronik", MICRONIK) + MANUF("MegaMicro", MEGA_MICRO) MANUF("Imtronics", IMTRONICS2) MANUF("Kupke", KUPKE3) + MANUF("ITH", ITH) + MANUF("VMC", VMC) MANUF("Information", INFORMATION) MANUF("Vortex", VORTEX) MANUF("DataFlyer", DATAFLYER) @@ -599,6 +682,7 @@ BEGIN_MANUF MANUF("DPS", DPS) MANUF("Apollo", APOLLO2) MANUF("Apollo", APOLLO) + MANUF("Petsoff LP", PETSOFF) MANUF("Uwe Gerlach", UWE_GERLACH) MANUF("MacroSystems", MACROSYSTEMS2) MANUF("Combitec", COMBITEC) @@ -614,10 +698,12 @@ END /* - * Configured Expansion Devices + * Expansion Devices */ -static u_long BoardPartFlags[NUM_AUTO] = { 0, }; +int zorro_num_autocon; +struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO]; +static u_long BoardPartFlags[ZORRO_NUM_AUTO] = { 0, }; /* @@ -657,14 +743,14 @@ int zorro_find(int manuf, int prod, int part, int index) return(0); } - for (key = index + 1; key <= boot_info.bi_amiga.num_autocon; key++) { - cd = &boot_info.bi_amiga.autocon[key-1]; + for (key = index + 1; key <= zorro_num_autocon; key++) { + cd = &zorro_autocon[key-1]; if ((cd->cd_Rom.er_Manufacturer == manuf) && (cd->cd_Rom.er_Product == prod) && !(BoardPartFlags[key-1] & (1<<part))) break; } - return(key <= boot_info.bi_amiga.num_autocon ? key : 0); + return(key <= zorro_num_autocon ? key : 0); } @@ -676,10 +762,10 @@ struct ConfigDev *zorro_get_board(int key) { struct ConfigDev *cd = NULL; - if ((key < 1) || (key > boot_info.bi_amiga.num_autocon)) + if ((key < 1) || (key > zorro_num_autocon)) printk("zorro_get_board: bad key %d\n", key); else - cd = &boot_info.bi_amiga.autocon[key-1]; + cd = &zorro_autocon[key-1]; return(cd); } @@ -691,7 +777,7 @@ struct ConfigDev *zorro_get_board(int key) void zorro_config_board(int key, int part) { - if ((key < 1) || (key > boot_info.bi_amiga.num_autocon)) + if ((key < 1) || (key > zorro_num_autocon)) printk("zorro_config_board: bad key %d\n", key); else if ((part < 0) || (part > 31)) printk("zorro_config_board: bad part %d\n", part); @@ -708,7 +794,7 @@ void zorro_config_board(int key, int part) void zorro_unconfig_board(int key, int part) { - if ((key < 1) || (key > boot_info.bi_amiga.num_autocon)) + if ((key < 1) || (key > zorro_num_autocon)) printk("zorro_unconfig_board: bad key %d\n", key); else if ((part < 0) || (part > 31)) printk("zorro_unconfig_board: bad part %d\n", part); @@ -738,7 +824,7 @@ static int identify(int devnum, char *buf) int i, j, k, len = 0; enum GVP_ident epc; - cd = &boot_info.bi_amiga.autocon[devnum]; + cd = &zorro_autocon[devnum]; manuf = cd->cd_Rom.er_Manufacturer; prod = cd->cd_Rom.er_Product; addr = (u_long)cd->cd_BoardAddr; @@ -756,7 +842,11 @@ static int identify(int devnum, char *buf) identified = 1; break; } else { - epc = *(enum GVP_ident *)ZTWO_VADDR(addr+0x8000) & + /* + * The epc must be read as a short from the + * hardware. + */ + epc = *(unsigned short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK; for (k = 0; k < NUM_GVP_PROD; k++) if (Ext_Prod_GVP[k].ID == epc) { @@ -820,11 +910,11 @@ void zorro_identify(void) return; printk("Probing AutoConfig expansion device(s):\n"); - for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { + for (i = 0; i < zorro_num_autocon; i++) { identify(i, tmp); printk(tmp); } - if (!boot_info.bi_amiga.num_autocon) + if (!zorro_num_autocon) printk("No AutoConfig expansion devices present.\n"); } @@ -840,7 +930,7 @@ int zorro_get_list(char *buffer) if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { len = sprintf(buffer, "AutoConfig expansion devices:\n"); - for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { + for (i = 0; i < zorro_num_autocon; i++) { j = identify(i, tmp); if (len+j >= 4075) { len += sprintf(buffer+len, "4K limit reached!\n"); @@ -911,12 +1001,12 @@ void zorro_init(void) return; /* Mark all available Zorro II memory */ - for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) { - cd = &boot_info.bi_amiga.autocon[i]; + for (i = 0; i < zorro_num_autocon; i++) { + cd = &zorro_autocon[i]; if (cd->cd_Rom.er_Type & ERTF_MEMLIST) mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); } /* Unmark all used Zorro II memory */ - for (i = 0; i < boot_info.num_memory; i++) - mark_region(boot_info.memory[i].addr, boot_info.memory[i].size, 0); + for (i = 0; i < m68k_num_memory; i++) + mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0); } diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 77324bc10..77d5c7c2b 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -7,10 +7,9 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -EXTRA_CFLAGS := -Wa,-m68030 - O_TARGET := atari.o O_OBJS := config.o atakeyb.o ataints.o \ - stdma.o atasound.o joystick.o stram.o atafb.o ksyms.o + stdma.o atasound.o joystick.o stram.o atafb.o +OX_OBJS := atari_ksyms.o include $(TOPDIR)/Rules.make diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c index 488ecc302..64c9a62d3 100644 --- a/arch/m68k/atari/atafb.c +++ b/arch/m68k/atari/atafb.c @@ -210,11 +210,11 @@ And on the MV300 it's difficult to read out the hardware palette. So we just keep track of the set colors in our own array here, and use that! */ -struct { unsigned char red,green,blue,pad; } MV300_color[256]; +static struct { unsigned char red,green,blue,pad; } MV300_color[256]; #endif /* ATAFB_EXT */ -int inverse=0; +static int inverse=0; extern int fontheight_8x8; extern int fontwidth_8x8; @@ -332,7 +332,7 @@ static char *user6_names[] = {"user6", NULL}; static char *user7_names[] = {"user7", NULL}; static char *dummy_names[] = {"dummy", NULL}; -char **fb_var_names[] = { +static char **fb_var_names[] = { /* Writing the name arrays directly in this array (via "(char *[]){...}") * crashes gcc 2.5.8 (sigsegv) if the inner array * contains more than two items. I've also seen that all elements @@ -365,7 +365,7 @@ char **fb_var_names[] = { /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ }; -struct fb_var_screeninfo atari_fb_predefined[] = { +static struct fb_var_screeninfo atari_fb_predefined[] = { /* * yres_virtual==0 means use hw-scrolling if possible, else yres */ @@ -467,7 +467,7 @@ struct fb_var_screeninfo atari_fb_predefined[] = { 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 } }; -int num_atari_fb_predefined=arraysize(atari_fb_predefined); +static int num_atari_fb_predefined=arraysize(atari_fb_predefined); static int @@ -2348,7 +2348,7 @@ static int pan_display( struct fb_var_screeninfo *var, #ifdef ATAFB_TT -struct fb_hwswitch tt_switch = { +static struct fb_hwswitch tt_switch = { tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg, set_screen_base, NULL, pan_display @@ -2356,7 +2356,7 @@ struct fb_hwswitch tt_switch = { #endif #ifdef ATAFB_FALCON -struct fb_hwswitch falcon_switch = { +static struct fb_hwswitch falcon_switch = { falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, falcon_get_par, falcon_set_par, falcon_getcolreg, falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display @@ -2364,7 +2364,7 @@ struct fb_hwswitch falcon_switch = { #endif #ifdef ATAFB_STE -struct fb_hwswitch st_switch = { +static struct fb_hwswitch st_switch = { stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg, stste_set_screen_base, NULL, pan_display @@ -2372,7 +2372,7 @@ struct fb_hwswitch st_switch = { #endif #ifdef ATAFB_EXT -struct fb_hwswitch ext_switch = { +static struct fb_hwswitch ext_switch = { ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL }; @@ -2463,9 +2463,15 @@ static short green2[]= static short blue2[]= { 0x0000,0xffff}; -struct fb_cmap default_16_colors = { 0, 16, red16, green16, blue16, NULL }; -struct fb_cmap default_4_colors = { 0, 4, red4, green4, blue4, NULL }; -struct fb_cmap default_2_colors = { 0, 2, red2, green2, blue2, NULL }; +static struct fb_cmap default_16_colors = { + 0, 16, red16, green16, blue16, NULL +}; +static struct fb_cmap default_4_colors = { + 0, 4, red4, green4, blue4, NULL +}; +static struct fb_cmap default_2_colors = { + 0, 2, red2, green2, blue2, NULL +}; static struct fb_cmap * get_default_colormap(int bpp) @@ -2899,6 +2905,12 @@ atafb_blank(int blank) do_install_cmap(currcon); } +static int +atafb_setcmap(struct fb_cmap *cmap, int con) +{ + return(atari_fb_set_cmap(cmap, 1, con)); +} + struct fb_info * atari_fb_init(long *mem_start) { @@ -2993,6 +3005,7 @@ atari_fb_init(long *mem_start) fb_info.switch_con=&atafb_switch; fb_info.updatevar=&fb_update_var; fb_info.blank=&atafb_blank; + fb_info.setcmap=&atafb_setcmap; var=atari_fb_predefined+default_par-1; do_fb_set_var(var,1); strcat(fb_info.modename,fb_var_names[default_par-1][0]); diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 642ff027b..b65beefb1 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -40,7 +40,6 @@ #include <linux/ptrace.h> #include <linux/kernel_stat.h> -#include <asm/setup.h> #include <asm/system.h> #include <asm/traps.h> @@ -57,9 +56,7 @@ * All interrupt source have an internal number (defined in * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can - * be allocated by atari_register_vme_int(). Currently, all int source numbers - * have the IRQ_MACHSPEC bit set, to keep the general int handling functions - * in kernel/ints.c from them. + * be allocated by atari_register_vme_int(). * * Each interrupt can be of three types: * @@ -181,7 +178,7 @@ asmlinkage void IRQ_NAME(n); \ void atari_slow_irq_##n##_dummy (void) { \ __asm__ (ALIGN_STR "\n" \ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ -" addql #1,"SYMBOL_NAME_STR(intr_count)"\n" \ +" addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" \ SAVE_ALL "\n" \ " andb #~(1<<(" #n "&7))," /* mask this interrupt */ \ "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n" \ @@ -193,7 +190,7 @@ SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t" \ " lea "SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n" \ " pea %%sp@\n" /* push addr of frame */ \ " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ -" pea (" #n "+0x10000008)\n" /* push int number */ \ +" pea (" #n "+8)\n" /* push int number */ \ " movel %%a0@,%%a0\n" \ " jbsr %%a0@\n" /* call the handler */ \ " addql #8,%%sp\n" \ @@ -284,7 +281,7 @@ __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 - addql #1,"SYMBOL_NAME_STR(intr_count)"\n" + addql #1,"SYMBOL_NAME_STR(local_irq_count)"\n" SAVE_ALL " /* get vector number from stack frame and convert to source */ bfextu %%sp@(" FORMATVEC "){#4,#10},%%d0 @@ -297,7 +294,6 @@ SYMBOL_NAME_STR(atari_fast_irq_handler) ": lea %%a0@(%%d0:l:8),%%a0 pea %%sp@ /* push frame address */ movel %%a0@(4),%%sp@- /* push handler data */ - bset #28,%%d0 /* set MACHSPEC bit */ movel %%d0,%%sp@- /* push int number */ movel %%a0@,%%a0 jsr %%a0@ /* and call the handler */ @@ -588,14 +584,12 @@ unsigned long atari_register_vme_int(void) return 0; free_vme_vec_bitmap |= 1 << i; - return (VME_SOURCE_BASE + i) | IRQ_MACHSPEC; + return (VME_SOURCE_BASE + i); } void atari_unregister_vme_int(unsigned long irq) { - irq &= ~IRQ_MACHSPEC; - if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { irq -= VME_SOURCE_BASE; free_vme_vec_bitmap &= ~(1 << irq); diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 95cc0245f..4f57cb928 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -14,6 +14,7 @@ */ #include <linux/sched.h> +#include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/keyboard.h> @@ -40,6 +41,15 @@ void (*atari_MIDI_interrupt_hook) (void); /* Hook for mouse driver */ void (*atari_mouse_interrupt_hook) (char *); +/* variables for IKBD self test: */ + +/* state: 0: off; >0: in progress; >1: 0xf1 received */ +static volatile int ikbd_self_test; +/* timestamp when last received a char */ +static volatile unsigned long self_test_last_rcv; +/* bitmap of keys reported as broken */ +static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; + #define BREAK_MASK (0x80) /* @@ -331,12 +341,15 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) { /* a very fast typist or a slow system, give a warning */ /* ...happens often if interrupts were disabled for too long */ - printk( "Keyboard overrun\n" ); + printk( KERN_DEBUG "Keyboard overrun\n" ); scancode = acia.key_data; /* Turn off autorepeating in case a break code has been lost */ del_timer( &atakeyb_rep_timer ); rep_scancode = 0; - if (IS_SYNC_CODE(scancode)) { + if (ikbd_self_test) + /* During self test, don't do resyncing, just process the code */ + goto interpret_scancode; + else if (IS_SYNC_CODE(scancode)) { /* This code seem already to be the start of a new packet or a * single scancode */ kb_state.state = KEYBOARD; @@ -386,10 +399,47 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) kb_state.buf[0] = scancode; break; + case 0xF1: + /* during self-test, note that 0xf1 received */ + if (ikbd_self_test) { + ++ikbd_self_test; + self_test_last_rcv = jiffies; + break; + } + /* FALL THROUGH */ + default: break_flag = scancode & BREAK_MASK; scancode &= ~BREAK_MASK; + if (ikbd_self_test) { + /* Scancodes sent during the self-test stand for broken + * keys (keys being down). The code *should* be a break + * code, but nevertheless some AT keyboard interfaces send + * make codes instead. Therefore, simply ignore + * break_flag... + * */ + int keyval = ataplain_map[scancode], keytyp; + + set_bit( scancode, broken_keys ); + self_test_last_rcv = jiffies; + keyval = ataplain_map[scancode]; + keytyp = KTYP(keyval) - 0xf0; + keyval = KVAL(keyval); + + printk( KERN_WARNING "Key with scancode %d ", scancode ); + if (keytyp == KT_LATIN || keytyp == KT_LETTER) { + if (keyval < ' ') + printk( "('^%c') ", keyval + '@' ); + else + printk( "('%c') ", keyval ); + } + printk( "is broken -- will be ignored.\n" ); + break; + } + else if (test_bit( scancode, broken_keys )) + break; + if (break_flag) { del_timer( &atakeyb_rep_timer ); rep_scancode = 0; @@ -815,7 +865,18 @@ int atari_keyb_init(void) mfp.active_edge &= ~0x10; atari_turnon_irq(IRQ_MFP_ACIA); + ikbd_self_test = 1; ikbd_reset(); + /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's + * self-test is finished */ + self_test_last_rcv = jiffies; + while( jiffies < self_test_last_rcv + HZ/4 ) + barrier(); + /* if not incremented: no 0xf1 received */ + if (ikbd_self_test == 1) + printk( KERN_ERR "WARNING: keyboard self test failed!\n" ); + ikbd_self_test = 0; + ikbd_mouse_disable(); ikbd_joystick_disable(); diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c new file mode 100644 index 000000000..c2a9da86e --- /dev/null +++ b/arch/m68k/atari/atari_ksyms.c @@ -0,0 +1,35 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <asm/ptrace.h> +#include <asm/traps.h> +#include <asm/atarihw.h> +#include <asm/atariints.h> +#include <asm/atarikb.h> +#include <asm/atari_joystick.h> +#include <asm/atari_stdma.h> + +extern void atari_microwire_cmd( int cmd ); +extern int atari_SCC_reset_done; + +EXPORT_SYMBOL(atari_mch_cookie); +EXPORT_SYMBOL(atari_hw_present); +EXPORT_SYMBOL(is_medusa); +EXPORT_SYMBOL(is_hades); +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_mouse_buttons); +EXPORT_SYMBOL(atari_mouse_interrupt_hook); +EXPORT_SYMBOL(atari_MIDI_interrupt_hook); +EXPORT_SYMBOL(atari_SCC_reset_done); +EXPORT_SYMBOL(ikbd_write); +EXPORT_SYMBOL(ikbd_mouse_y0_top); +EXPORT_SYMBOL(ikbd_mouse_thresh); +EXPORT_SYMBOL(ikbd_mouse_rel_pos); +EXPORT_SYMBOL(ikbd_mouse_disable); + +EXPORT_SYMBOL(atari_microwire_cmd); diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c index 33f7f79c6..51f8b6823 100644 --- a/arch/m68k/atari/atasound.c +++ b/arch/m68k/atari/atasound.c @@ -21,7 +21,6 @@ for more details. #include <linux/errno.h> #include <linux/mm.h> -#include <asm/setup.h> #include <asm/atarihw.h> #include <asm/system.h> #include <asm/irq.h> diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index f314fcbbd..0d0607da0 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -33,6 +33,7 @@ #include <linux/console.h> #include <linux/interrupt.h> +#include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/atarihw.h> #include <asm/atarihdreg.h> @@ -44,7 +45,16 @@ #include <asm/pgtable.h> #include <asm/machdep.h> -extern void atari_sched_init(void (*)(int, void *, struct pt_regs *)); +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +#endif + +u_long atari_mch_cookie; +struct atari_hw_present atari_hw_present; + +extern char m68k_debug_device[]; + +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 *); @@ -53,30 +63,38 @@ extern void atari_kbd_leds (unsigned int); extern void atari_init_IRQ (void); extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); -extern int atari_free_irq (unsigned int irq, void *dev_id); +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 */ -extern unsigned long atari_gettimeoffset (void); -extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *); -extern void atari_gettod (int *, int *, int *, int *, int *, int *); -extern int atari_mste_hwclk (int, struct hwclk_time *); -extern int atari_hwclk (int, struct hwclk_time *); -extern int atari_mste_set_clock_mmss (unsigned long); -extern int atari_set_clock_mmss (unsigned long); +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 ); -extern void atari_reset( void ); +static void atari_reset( void ); #ifdef CONFIG_BLK_DEV_FD extern int atari_floppy_init (void); extern void atari_floppy_setup(char *, int *); #endif -extern void atari_waitbut (void); extern struct consw fb_con; extern struct fb_info *atari_fb_init(long *); -extern void atari_debug_init (void); +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; + + extern void (*kd_mksound)(unsigned int, unsigned int); /* This function tests for the presence of an address, specially a @@ -205,8 +223,36 @@ static int scc_test( volatile char *ctla ) return( 1 ); } + + /* + * Parse an Atari-specific record in the bootinfo + */ + +int atari_parse_bootinfo(const struct bi_record *record) +{ + int unknown = 0; + const u_long *data = record->data; + + switch (record->tag) { + case BI_ATARI_MCH_COOKIE: + atari_mch_cookie = *data; + break; + default: + unknown = 1; + } + return(unknown); +} + + /* + * Setup the Atari configuration info + */ + void config_atari(void) { + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); + + atari_debug_init(); + mach_sched_init = atari_sched_init; mach_keyb_init = atari_keyb_init; mach_kbdrate = atari_kbdrate; @@ -214,21 +260,20 @@ void config_atari(void) mach_init_IRQ = atari_init_IRQ; mach_request_irq = atari_request_irq; mach_free_irq = atari_free_irq; - mach_enable_irq = atari_enable_irq; - mach_disable_irq = atari_disable_irq; + enable_irq = atari_enable_irq; + disable_irq = atari_disable_irq; + mach_get_model = atari_get_model; + mach_get_hardware_list = atari_get_hardware_list; mach_get_irq_list = atari_get_irq_list; mach_gettimeoffset = atari_gettimeoffset; - mach_mksound = atari_mksound; mach_reset = atari_reset; #ifdef CONFIG_BLK_DEV_FD mach_floppy_init = atari_floppy_init; mach_floppy_setup = atari_floppy_setup; #endif conswitchp = &fb_con; - waitbut = atari_waitbut; mach_fb_init = atari_fb_init; mach_max_dma_address = 0xffffff; - mach_debug_init = atari_debug_init; mach_video_setup = atari_video_setup; kd_mksound = atari_mksound; @@ -237,7 +282,7 @@ void config_atari(void) */ printk( "Atari hardware found: " ); - if (is_medusa) { + if (is_medusa || is_hades) { /* There's no Atari video hardware on the Medusa, but all the * addresses below generate a DTACK so no bus error occurs! */ } @@ -279,7 +324,7 @@ void config_atari(void) ATARIHW_SET(SCSI_DMA); printk( "TT_SCSI_DMA " ); } - if (hwreg_present( &st_dma.dma_hi )) { + if (!is_hades && hwreg_present( &st_dma.dma_hi )) { ATARIHW_SET(STND_DMA); printk( "STND_DMA " ); } @@ -301,21 +346,25 @@ void config_atari(void) ATARIHW_SET(YM_2149); printk( "YM2149 " ); } - if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) { + if (!is_medusa && !is_hades && hwreg_present( &tt_dmasnd.ctrl )) { ATARIHW_SET(PCM_8BIT); printk( "PCM " ); } - if (hwreg_present( (void *)(0xffff8940) )) { + if (!is_hades && hwreg_present( &codec.unused5 )) { ATARIHW_SET(CODEC); printk( "CODEC " ); } + if (hwreg_present( &dsp56k_host_interface.icr )) { + ATARIHW_SET(DSP56K); + printk( "DSP56K " ); + } if (hwreg_present( &tt_scc_dma.dma_ctrl ) && #if 0 /* This test sucks! Who knows some better? */ (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_medusa && !is_hades #endif ) { ATARIHW_SET(SCC_DMA); @@ -329,7 +378,12 @@ void config_atari(void) ATARIHW_SET( ST_ESCC ); printk( "ST_ESCC " ); } - if (hwreg_present( &tt_scu.sys_mask )) { + if (is_hades) + { + ATARIHW_SET( VME ); + printk( "VME " ); + } + else if (hwreg_present( &tt_scu.sys_mask )) { ATARIHW_SET(SCU); /* Assume a VME bus if there's a SCU */ ATARIHW_SET( VME ); @@ -339,7 +393,7 @@ void config_atari(void) ATARIHW_SET(ANALOG_JOY); printk( "ANALOG_JOY " ); } - if (hwreg_present( blitter.halftone )) { + if (!is_hades && hwreg_present( blitter.halftone )) { ATARIHW_SET(BLITTER); printk( "BLITTER " ); } @@ -348,7 +402,7 @@ void config_atari(void) printk( "IDE " ); } #if 1 /* This maybe wrong */ - if (!is_medusa && + if (!is_medusa && !is_hades && hwreg_present( &tt_microwire.data ) && hwreg_present( &tt_microwire.mask ) && (tt_microwire.mask = 0x7ff, @@ -366,20 +420,20 @@ void config_atari(void) mach_hwclk = atari_hwclk; mach_set_clock_mmss = atari_set_clock_mmss; } - if (hwreg_present( &mste_rtc.sec_ones)) { + if (!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 && + if (!is_medusa && !is_hades && hwreg_present( &dma_wd.fdc_speed ) && hwreg_write( &dma_wd.fdc_speed, 0 )) { ATARIHW_SET(FDCSPEED); printk( "FDC_SPEED "); } - if (!ATARIHW_PRESENT(ST_SCSI)) { + if (!is_hades && !ATARIHW_PRESENT(ST_SCSI)) { ATARIHW_SET(ACSI); printk( "ACSI " ); } @@ -390,9 +444,11 @@ void config_atari(void) * translation (the one that must not be turned off in * head.S...) */ - __asm__ volatile ("moveq #0,%/d0;" - ".long 0x4e7b0004;" /* movec d0,itt0 */ - ".long 0x4e7b0006;" /* movec d0,dtt0 */ + __asm__ volatile ("moveq #0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k" : /* no outputs */ : /* no inputs */ : "d0"); @@ -416,13 +472,18 @@ void config_atari(void) tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache * inhibit, read and write, FDC mask = 3, * FDC val = 4 -> Supervisor only */ - __asm__ __volatile__ ( "pmove %0@,%/tt1" : : "a" (&tt1_val) ); + __asm__ __volatile__ ( ".chip 68030\n\t" + "pmove %0@,%/tt1\n\t" + ".chip 68k" + : : "a" (&tt1_val) ); } else { __asm__ __volatile__ ( "movel %0,%/d0\n\t" - ".long 0x4e7b0005\n\t" /* movec d0,itt1 */ - ".long 0x4e7b0007" /* movec d0,dtt1 */ + ".chip 68040\n\t" + "movec %%d0,%%itt1\n\t" + "movec %%d0,%%dtt1\n\t" + ".chip 68k" : : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, * supervisor only, non-cacheable/ @@ -432,7 +493,7 @@ void config_atari(void) } } -void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; @@ -448,7 +509,7 @@ void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) #define TICK_SIZE 10000 /* This is always executed with interrupts disabled. */ -unsigned long atari_gettimeoffset (void) +static unsigned long atari_gettimeoffset (void) { unsigned long ticks, offset = 0; @@ -511,8 +572,8 @@ mste_write(struct MSTE_RTC *val) } while(0) -void atari_mste_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +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; @@ -538,8 +599,8 @@ void atari_mste_gettod (int *yearp, int *monp, int *dayp, } -void atari_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +static void atari_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { unsigned char ctrl; unsigned short tos_version; @@ -585,13 +646,13 @@ 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 ? 0xfff : *(unsigned short *)0xFF000002; + tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xFF000002; *yearp += (tos_version < 0x306) ? 70 : 68; } #define HWCLK_POLL_INTERVAL 5 -int atari_mste_hwclk( int op, struct hwclk_time *t ) +static int atari_mste_hwclk( int op, struct hwclk_time *t ) { int hour, year; int hr24=0; @@ -650,7 +711,7 @@ int atari_mste_hwclk( int op, struct hwclk_time *t ) return 0; } -int atari_hwclk( int op, struct hwclk_time *t ) +static int atari_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; @@ -660,7 +721,7 @@ int atari_hwclk( int op, struct hwclk_time *t ) /* Tos version at Physical 2. See above for explanation why we cannot use PTOV(2). */ - tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002; + tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xff000002; ctrl = RTC_READ(RTC_CONTROL); /* control registers are * independent from the UIP */ @@ -777,7 +838,7 @@ int atari_hwclk( int op, struct hwclk_time *t ) } -int atari_mste_set_clock_mmss (unsigned long nowtime) +static int atari_mste_set_clock_mmss (unsigned long nowtime) { short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; struct MSTE_RTC val; @@ -800,7 +861,7 @@ int atari_mste_set_clock_mmss (unsigned long nowtime) return 0; } -int atari_set_clock_mmss (unsigned long nowtime) +static int atari_set_clock_mmss (unsigned long nowtime) { int retval = 0; short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; @@ -839,13 +900,6 @@ int atari_set_clock_mmss (unsigned long nowtime) return retval; } - -void atari_waitbut (void) -{ - /* sorry, no-op */ -} - - static inline void ata_mfp_out (char c) { while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ @@ -853,12 +907,12 @@ static inline void ata_mfp_out (char c) mfp.usart_dta = c; } -void ata_mfp_print (const char *str) +static void atari_mfp_console_write (const char *str, unsigned int count) { - for( ; *str; ++str ) { + while (count--) { if (*str == '\n') ata_mfp_out( '\r' ); - ata_mfp_out( *str ); + ata_mfp_out( *str++ ); } } @@ -871,12 +925,12 @@ static inline void ata_scc_out (char c) scc.cha_b_data = c; } -void ata_scc_print (const char *str) +static void atari_scc_console_write (const char *str, unsigned int count) { - for( ; *str; ++str ) { + while (count--) { if (*str == '\n') ata_scc_out( '\r' ); - ata_scc_out( *str ); + ata_scc_out( *str++ ); } } @@ -901,20 +955,20 @@ static int ata_par_out (char c) return( 1 ); } -void ata_par_print (const char *str) +static void atari_par_console_write (const char *str, unsigned int count) { static int printer_present = 1; if (!printer_present) return; - for( ; *str; ++str ) { + while (count--) { if (*str == '\n') if (!ata_par_out( '\r' )) { printer_present = 0; return; } - if (!ata_par_out( *str )) { + if (!ata_par_out( *str++ )) { printer_present = 0; return; } @@ -922,15 +976,18 @@ void ata_par_print (const char *str) } -void atari_debug_init( void ) +static void atari_debug_init(void) { - extern void (*debug_print_proc)(const char *); - extern char m68k_debug_device[]; - +#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, - ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ? + ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON) ? "ser2" : "ser1" ); } @@ -943,7 +1000,7 @@ void atari_debug_init( void ) mfp.tim_dt_d = 2; /* 9600 bps */ mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ mfp.trn_stat |= 0x01; /* enable TX */ - debug_print_proc = ata_mfp_print; + atari_console_driver.write = atari_mfp_console_write; } else if (!strcmp( m68k_debug_device, "ser2" )) { /* SCC Modem2 serial port */ @@ -969,7 +1026,7 @@ void atari_debug_init( void ) scc.cha_b_ctrl = *p++; MFPDELAY(); } - debug_print_proc = ata_scc_print; + atari_console_driver.write = atari_scc_console_write; } else if (!strcmp( m68k_debug_device, "par" )) { /* parallel printer */ @@ -980,29 +1037,10 @@ void atari_debug_init( void ) 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 */ - debug_print_proc = ata_par_print; - } - else - debug_print_proc = NULL; -} - - -void ata_serial_print (const char *str) -{ - int c; - - while (c = *str++, c != 0) - { - if (c == '\n') - { - while (!(mfp.trn_stat & (1 << 7))) - barrier (); - mfp.usart_dta = '\r'; - } - while (!(mfp.trn_stat & (1 << 7))) - barrier (); - mfp.usart_dta = c; + atari_console_driver.write = atari_par_console_write; } + if (atari_console_driver.write) + register_console(&atari_console_driver); } /* ++roman: @@ -1036,14 +1074,15 @@ void ata_serial_print (const char *str) /* ++andreas: no need for complicated code, just depend on prefetch */ -void atari_reset (void) +static void atari_reset (void) { long tc_val = 0; long reset_addr; /* 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_medusa ? 0xe00030 : *(unsigned long *) 0xff000004; + 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 */ @@ -1062,7 +1101,9 @@ void atari_reset (void) /* 68060: clear PCR to turn off superscalar operation */ __asm__ __volatile__ ("moveq #0,%/d0\n\t" - ".long 0x4e7b0808" /* movec d0,pcr */ + ".chip 68060\n\t" + "movec %%d0,%%pcr\n\t" + ".chip 68k" : : : "d0" ); } @@ -1070,8 +1111,10 @@ void atari_reset (void) ("movel %0,%/d0\n\t" "andl #0xff000000,%/d0\n\t" "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ - ".long 0x4e7b0004\n\t" /* movec d0,itt0 */ - ".long 0x4e7b0006\n\t" /* movec d0,dtt0 */ + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" "jmp %0@\n\t" : /* no outputs */ : "a" (jmp_addr040) @@ -1080,9 +1123,11 @@ void atari_reset (void) __asm__ __volatile__ ("moveq #0,%/d0\n\t" "nop\n\t" - ".word 0xf4d8\n\t" /* cinva i/d */ - ".word 0xf518\n\t" /* pflusha */ - ".long 0x4e7b0003\n\t" /* movec d0,tc */ + ".chip 68040\n\t" + "cinva %%bc\n\t" + "pflusha\n\t" + "movec %%d0,%%tc\n\t" + ".chip 68k\n\t" "jmp %0@" : /* no outputs */ : "a" (reset_addr) @@ -1097,10 +1142,10 @@ void atari_reset (void) } -void atari_get_model(char *model) +static void atari_get_model(char *model) { strcpy(model, "Atari "); - switch (boot_info.bi_atari.mch_cookie >> 16) { + switch (atari_mch_cookie >> 16) { case ATARI_MCH_ST: if (ATARIHW_PRESENT(MSTE_CLK)) strcat (model, "Mega ST"); @@ -1108,7 +1153,7 @@ void atari_get_model(char *model) strcat (model, "ST"); break; case ATARI_MCH_STE: - if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10) + if ((atari_mch_cookie & 0xffff) == 0x10) strcat (model, "Mega STE"); else strcat (model, "STE"); @@ -1117,6 +1162,8 @@ void atari_get_model(char *model) if (is_medusa) /* Medusa has TT _MCH cookie */ strcat (model, "Medusa"); + else if (is_hades) + strcat(model, "Hades"); else strcat (model, "TT"); break; @@ -1125,21 +1172,20 @@ void atari_get_model(char *model) break; default: sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", - boot_info.bi_atari.mch_cookie); + atari_mch_cookie); break; } } -int atari_get_hardware_list(char *buffer) +static int atari_get_hardware_list(char *buffer) { int len = 0, i; - for (i = 0; i < boot_info.num_memory; i++) + for (i = 0; i < m68k_num_memory; i++) len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", - boot_info.memory[i].size >> 20, - boot_info.memory[i].addr, - (boot_info.memory[i].addr & 0xff000000 ? + m68k_memory[i].size >> 20, m68k_memory[i].addr, + (m68k_memory[i].addr & 0xff000000 ? "alternate RAM" : "ST-RAM")); #define ATARIHW_ANNOUNCE(name,str) \ @@ -1174,6 +1220,7 @@ int atari_get_hardware_list(char *buffer) ATARIHW_ANNOUNCE(SCU, "System Control Unit"); ATARIHW_ANNOUNCE(BLITTER, "Blitter"); ATARIHW_ANNOUNCE(VME, "VME Bus"); + ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); return(len); } diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c index 67acec33b..de6014171 100644 --- a/arch/m68k/atari/joystick.c +++ b/arch/m68k/atari/joystick.c @@ -10,6 +10,7 @@ #include <linux/sched.h> #include <linux/errno.h> #include <linux/major.h> +#include <linux/poll.h> #include <asm/atarikb.h> #include <asm/atari_joystick.h> @@ -54,7 +55,7 @@ void atari_joystick_interrupt(char *buf) /* ikbd_joystick_event_on(); */ } -static void release_joystick(struct inode *inode, struct file *file) +static int release_joystick(struct inode *inode, struct file *file) { int minor = DEVICE_NR(inode->i_rdev); @@ -63,6 +64,7 @@ static void release_joystick(struct inode *inode, struct file *file) if ((joystick[0].active == 0) && (joystick[1].active == 0)) ikbd_joystick_disable(); + return 0; } static int open_joystick(struct inode *inode, struct file *file) @@ -89,30 +91,28 @@ static long read_joystick(struct inode *inode, struct file *file, char *buffer, unsigned long count) { int minor = DEVICE_NR(inode->i_rdev); - int i; if (count < 2) return -EINVAL; if (!joystick[minor].ready) return -EAGAIN; - put_user(joystick[minor].fire, buffer++); - put_user(joystick[minor].dir, buffer++); - for (i = 0; i < count; i++) - put_user(0, buffer++); joystick[minor].ready = 0; - - return i; + if (put_user(joystick[minor].fire, buffer++) || + put_user(joystick[minor].dir, buffer++)) + return -EFAULT; + if (count > 2) + if (clear_user(buffer, count - 2)) + return -EFAULT; + return count; } -static int joystick_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) +static unsigned int joystick_poll(struct file *file, poll_table *wait) { - int minor = DEVICE_NR(inode->i_rdev); + int minor = DEVICE_NR(file->f_inode->i_rdev); - if (sel_type != SEL_IN) - return 0; + poll_wait(&joystick[minor].wait, wait); if (joystick[minor].ready) - return 1; - select_wait(&joystick[minor].wait, wait); + return POLLIN | POLLRDNORM; return 0; } @@ -121,7 +121,7 @@ struct file_operations atari_joystick_fops = { read_joystick, write_joystick, NULL, /* joystick_readdir */ - joystick_select, + joystick_poll, NULL, /* joystick_ioctl */ NULL, /* joystick_mmap */ open_joystick, @@ -134,7 +134,7 @@ int atari_joystick_init(void) joystick[0].ready = joystick[1].ready = 0; joystick[0].wait = joystick[1].wait = NULL; - if (register_chrdev(MAJOR_NR, "joystick", &atari_joystick_fops)) + if (register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops)) printk("unable to get major %d for joystick devices\n", MAJOR_NR); return 0; diff --git a/arch/m68k/atari/ksyms.c b/arch/m68k/atari/ksyms.c deleted file mode 100644 index 303babbe1..000000000 --- a/arch/m68k/atari/ksyms.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <linux/module.h> -#include <asm/ptrace.h> -#include <asm/traps.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atarikb.h> -#include <asm/atari_joystick.h> -#include <asm/atari_stdma.h> - -extern void atari_microwire_cmd( int cmd ); - -static struct symbol_table mach_atari_symbol_table = { -#include <linux/symtab_begin.h> - - X(is_medusa), - X(atari_register_vme_int), - X(atari_unregister_vme_int), - X(stdma_lock), - X(stdma_release), - X(stdma_others_waiting), - X(stdma_islocked), - - X(atari_mouse_buttons), - X(atari_mouse_interrupt_hook), - X(atari_MIDI_interrupt_hook), - X(ikbd_write), - X(ikbd_mouse_y0_top), - X(ikbd_mouse_thresh), - X(ikbd_mouse_rel_pos), - X(ikbd_mouse_disable), - - X(atari_microwire_cmd), - -#include <linux/symtab_end.h> -}; - -void mach_atari_syms_export(void) -{ - register_symtab(&mach_atari_symbol_table); -} diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index af4a6c7b6..247b9f684 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -32,7 +32,6 @@ #include <linux/types.h> #include <linux/genhd.h> #include <linux/sched.h> -#include <asm/setup.h> #include <asm/atari_stdma.h> #include <asm/atariints.h> #include <asm/atarihw.h> diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index a82988dae..565b20535 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -26,8 +26,8 @@ void atari_stram_init (void) { struct stram_desc *dp; - stramaddr = boot_info.bi_atari.stram_start; - stramsize = boot_info.bi_atari.stram_size; + stramaddr = atari_stram_start; + stramsize = atari_stram_size; /* initialize start boundary */ dp = DP (stramaddr); @@ -194,11 +194,11 @@ void atari_stram_init( void ) { int i; - for( i = 0; i < boot_info.num_memory; ++i ) { - if (boot_info.memory[i].addr == 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! */ rsvd_stram_end = rsvd_stram_beg; - stram_end = rsvd_stram_beg - 0x800 + boot_info.memory[i].size; + stram_end = rsvd_stram_beg - 0x800 + m68k_memory[i].size; return; } } diff --git a/arch/m68k/boot/Makefile b/arch/m68k/boot/Makefile index e67a9c4d1..822030ebb 100644 --- a/arch/m68k/boot/Makefile +++ b/arch/m68k/boot/Makefile @@ -8,14 +8,16 @@ ifdef CONFIG_AMIGA AMIGA_BOOTSTRAP = amiga_bootstrap AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o -AMIGA_HOSTCC = m68k-cbm-amigados-gcc -I$(TOPDIR)/include +AMIGA_HOSTCC = m68k-cbm-amigados-gcc +AMIGA_HOSTINC = -I$(TOPDIR)/include AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux endif ifdef CONFIG_ATARI ATARI_BOOTSTRAP = atari_bootstrap ATARI_BOOTOBJS := atari/bootstrap.o -ATARI_HOSTCC = m68k-mint-gcc -I$(TOPDIR)/include +ATARI_HOSTCC = m68k-mint-gcc +ATARI_HOSTINC = -I$(TOPDIR)/include ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall # BOOTP/TFTP support in bootstrap? @@ -36,27 +38,28 @@ endif ifdef CONFIG_ATARI atari_bootstrap: $(ATARI_BOOTOBJS) - $(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS) + $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS) rm -f ../../../bootstrap ln $@ ../../../bootstrap endif ifdef CONFIG_AMIGA amiga_bootstrap: $(AMIGA_BOOTOBJS) - $(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS) + $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS) rm -f ../../../bootstrap ln $@ ../../../bootstrap endif $(AMIGA_BOOTOBJS): %.o: %.c - $(AMIGA_HOSTCC) $(AMIGA_HOSTFLAGS) -c $< -o $@ + $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -c $< -o $@ $(ATARI_BOOTOBJS): %.o: %.c - $(ATARI_HOSTCC) $(ATARI_HOSTFLAGS) -c $< -o $@ + $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -c $< -o $@ bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP) clean: - rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap + rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap \ + ../../../bootstrap dep: diff --git a/arch/m68k/boot/amiga/bootstrap.c b/arch/m68k/boot/amiga/bootstrap.c index 20ca0621f..b109466ed 100644 --- a/arch/m68k/boot/amiga/bootstrap.c +++ b/arch/m68k/boot/amiga/bootstrap.c @@ -21,6 +21,8 @@ ** Modified 9-Sep-96 by Geert Uytterhoeven ** - Rewritten option parsing ** - New parameter passing to linuxboot() (linuxboot_args) +** Modified 6-Oct-96 by Geert Uytterhoeven +** - Updated for the new boot information structure ** ** 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 @@ -40,7 +42,7 @@ /* required Linux/m68k include files */ #include <linux/a.out.h> #include <linux/elf.h> -#include <asm/setup.h> +#include <asm/amigahw.h> #include <asm/page.h> /* Amiga bootstrap include files */ @@ -49,9 +51,8 @@ /* Library Bases */ +long __oslibversion = 36; extern const struct ExecBase *SysBase; -const struct ExpansionBase *ExpansionBase; -const struct GfxBase *GfxBase; static const char *memfile_name = NULL; @@ -78,23 +79,25 @@ static int Read(int fd, char *buf, int count); static void Close(int fd); static int FileSize(const char *path); static void Sleep(u_long micros); -static int ModifyBootinfo(struct bootinfo *bi); static void Usage(void) { fprintf(stderr, - "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n" - "Usage: %s [options] [kernel command line]\n\n" - "Valid options are:\n" - " -h, --help Display this usage information\n" - " -k, --kernel file Use kernel image `file' (default is `vmlinux')\n" - " -r, --ramdisk file Use ramdisk image `file'\n" - " -d, --debug Enable debug mode\n" - " -m, --memfile file Use memory file `file'\n" - " -v, --keep-video Don't reset the video mode\n" - " -t, --model id Set the Amiga model to `id'\n\n", - ProgramName); + "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n" + "Usage: %s [options] [kernel command line]\n\n" + "Basic options:\n" + " -h, --help Display this usage information\n" + " -k, --kernel file Use kernel image `file' (default is `vmlinux')\n" + " -r, --ramdisk file Use ramdisk image `file'\n" + "Advanced options:\n" + " -d, --debug Enable debug mode\n" + " -b, --baud speed Set the serial port speed (default is 9600)\n" + " -m, --memfile file Use memory file `file'\n" + " -v, --keep-video Don't reset the video mode\n" + " -t, --model id Set the Amiga model to `id'\n" + " -p, --processor cfm Set the processor type to `cfm\n\n", + ProgramName); exit(EXIT_FAILURE); } @@ -102,7 +105,8 @@ static void Usage(void) int main(int argc, char *argv[]) { int i; - int debugflag = 0, keep_video = 0; + int processor = 0, debugflag = 0, keep_video = 0; + u_int baud = 0; const char *kernel_name = NULL; const char *ramdisk_name = NULL; char commandline[CL_SIZE] = ""; @@ -113,33 +117,45 @@ int main(int argc, char *argv[]) if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) Usage(); else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel")) - if (--argc && !kernel_name) { - kernel_name = argv[1]; - argv++; - } else - Usage(); + if (--argc && !kernel_name) { + kernel_name = argv[1]; + argv++; + } else + Usage(); else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk")) - if (--argc && !ramdisk_name) { - ramdisk_name = argv[1]; - argv++; - } else - Usage(); + if (--argc && !ramdisk_name) { + ramdisk_name = argv[1]; + argv++; + } else + Usage(); else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug")) debugflag = 1; + else if (!strcmp(argv[0], "-b") || !strcmp(argv[0], "--baud")) + if (--argc && !baud) { + baud = atoi(argv[1]); + argv++; + } else + Usage(); else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile")) - if (--argc && !memfile_name) { - memfile_name = argv[1]; - argv++; - } else - Usage(); + if (--argc && !memfile_name) { + memfile_name = argv[1]; + argv++; + } else + Usage(); else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video")) keep_video = 1; else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model")) - if (--argc && !model) { - model = atoi(argv[1]); - argv++; - } else - Usage(); + if (--argc && !model) { + model = atoi(argv[1]); + argv++; + } else + Usage(); + else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--processor")) + if (--argc && !processor) { + processor = atoi(argv[1]); + argv++; + } else + Usage(); else break; } @@ -148,22 +164,6 @@ int main(int argc, char *argv[]) SysBase = *(struct ExecBase **)4; - /* open Expansion Library */ - ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", - 36); - if (!ExpansionBase) { - fputs("Unable to open expansion.library V36 or greater! Aborting...\n", - stderr); - exit(EXIT_FAILURE); - } - - /* open Graphics Library */ - GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0); - if (!GfxBase) { - fputs("Unable to open graphics.library! Aborting...\n", stderr); - exit(EXIT_FAILURE); - } - /* * Join command line options */ @@ -177,12 +177,56 @@ int main(int argc, char *argv[]) } } + memset(&args.bi, 0, sizeof(args.bi)); + if (processor) { + int cpu = processor/100%10; + int fpu = processor/10%10; + int mmu = processor%10; + if (cpu) + args.bi.cputype = 1<<(cpu-1); + if (fpu) + args.bi.fputype = 1<<(fpu-1); + if (mmu) + args.bi.mmutype = 1<<(mmu-1); + } + /* + * If we have a memory file, read the memory information from it + */ + if (memfile_name) { + FILE *fp; + int i; + + if ((fp = fopen(memfile_name, "r")) == NULL) { + perror("open memory file"); + fprintf(stderr, "Cannot open memory file %s\n", memfile_name); + return(FALSE); + } + + if (fscanf(fp, "%lu", &args.bi.chip_size) != 1) { + fprintf(stderr, "memory file does not contain chip memory size\n"); + fclose(fp); + return(FALSE); + } + + for (i = 0; i < NUM_MEMINFO; i++) + if (fscanf(fp, "%lx %lu", &args.bi.memory[i].addr, + &args.bi.memory[i].size) != 2) + break; + + fclose(fp); + args.bi.num_memory = i; + } + strncpy(args.bi.command_line, commandline, CL_SIZE); + args.bi.command_line[CL_SIZE-1] = '\0'; + if (model != AMI_UNKNOWN) + args.bi.model = model; + args.kernelname = kernel_name; args.ramdiskname = ramdisk_name; - args.commandline = commandline; args.debugflag = debugflag; args.keep_video = keep_video; args.reset_boards = 1; + args.baud = baud; args.puts = Puts; args.getchar = GetChar; args.putchar = PutChar; @@ -193,14 +237,10 @@ int main(int argc, char *argv[]) args.close = Close; args.filesize = FileSize; args.sleep = Sleep; - args.modify_bootinfo = ModifyBootinfo; /* Do The Right Stuff */ linuxboot(&args); - CloseLibrary((struct Library *)GfxBase); - CloseLibrary((struct Library *)ExpansionBase); - /* if we ever get here, something went wrong */ exit(EXIT_FAILURE); } @@ -213,6 +253,7 @@ int main(int argc, char *argv[]) static void Puts(const char *str) { fputs(str, stderr); + fflush(stderr); } static long GetChar(void) @@ -223,6 +264,7 @@ static long GetChar(void) static void PutChar(char c) { fputc(c, stderr); + fflush(stderr); } static void Printf(const char *fmt, ...) @@ -232,6 +274,7 @@ static void Printf(const char *fmt, ...) va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); + fflush(stderr); } static int Open(const char *path) @@ -260,8 +303,8 @@ static int FileSize(const char *path) int fd, size = -1; if ((fd = open(path, O_RDONLY)) != -1) { - size = lseek(fd, 0, SEEK_END); - close(fd); + size = lseek(fd, 0, SEEK_END); + close(fd); } return(size); } @@ -288,46 +331,3 @@ static void Sleep(u_long micros) DeleteMsgPort(TimerPort); } } - - -static int ModifyBootinfo(struct bootinfo *bi) -{ - /* - * if we have a memory file, read the memory information from it - */ - if (memfile_name) { - FILE *fp; - int i; - - if ((fp = fopen(memfile_name, "r")) == NULL) { - perror("open memory file"); - fprintf(stderr, "Cannot open memory file %s\n", memfile_name); - return(FALSE); - } - - if (fscanf(fp, "%lu", &bi->bi_amiga.chip_size) != 1) { - fprintf(stderr, "memory file does not contain chip memory size\n"); - fclose(fp); - return(FALSE); - } - - for (i = 0; i < NUM_MEMINFO; i++) { - if (fscanf(fp, "%lx %lu", &bi->memory[i].addr, &bi->memory[i].size) - != 2) - break; - } - - fclose(fp); - - if (i != bi->num_memory && i > 0) - bi->num_memory = i; - } - - /* - * change the Amiga model, if necessary - */ - if (model != AMI_UNKNOWN) - bi->bi_amiga.model = model; - - return(TRUE); -} diff --git a/arch/m68k/boot/amiga/bootstrap.h b/arch/m68k/boot/amiga/bootstrap.h index d7a5c44fd..4d072cc75 100644 --- a/arch/m68k/boot/amiga/bootstrap.h +++ b/arch/m68k/boot/amiga/bootstrap.h @@ -20,8 +20,6 @@ ** */ -#include <asm/amigatypes.h> - struct MsgPort { u_char fill1[15]; @@ -61,30 +59,6 @@ struct Library; struct IORequest; -static __inline void CloseLibrary(struct Library *library) -{ - register const struct ExecBase *a6 __asm("a6") = SysBase; - register struct Library *a1 __asm("a1") = library; - __asm __volatile ("jsr a6@(-0x19e)" - : /* no output */ - : "r" (a6), "r" (a1) - : "a0","a1","d0","d1", "memory"); -} - -static __inline struct Library *OpenLibrary(char *libName, - unsigned long version) -{ - register struct Library * _res __asm("d0"); - register const struct ExecBase *a6 __asm("a6") = SysBase; - register u_char *a1 __asm("a1") = libName; - register unsigned long d0 __asm("d0") = version; - __asm __volatile ("jsr a6@(-0x228)" - : "=r" (_res) - : "r" (a6), "r" (a1), "r" (d0) - : "a0","a1","d0","d1", "memory"); - return _res; -} - static __inline char OpenDevice(u_char *devName, u_long unit, struct IORequest *ioRequest, u_long flags) { diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c index 975868c45..d35966686 100644 --- a/arch/m68k/boot/amiga/linuxboot.c +++ b/arch/m68k/boot/amiga/linuxboot.c @@ -20,6 +20,24 @@ * 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. + * + * History: + * 03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's + * code for ataboot) + * 30 Dec 1996 Reverted the CPU detection to the old scheme + * New boot parameter override scheme (Geert) + * 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert) + * 9 Sep 1996 Rewritten option parsing + * New parameter passing to linuxboot() (linuxboot_args) + * (Geert) + * 18 Aug 1996 Updated for the new boot information structure (Geert) + * 10 Jan 1996 The real Linux/m68k boot code moved to linuxboot.[ch] + * (Geert) + * 11 Jul 1995 Support for ELF kernel (untested!) (Andreas) + * 7 Mar 1995 Memory block sizes are rounded to a multiple of 256K + * instead of 1M (Geert) + * 31 May 1994 Memory thrash problem solved (Geert) + * 11 May 1994 A3640 MapROM check (Geert) */ @@ -28,6 +46,10 @@ #endif /* __GNUC__ */ +#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */ +/* support compressed kernels? */ +#define ZKERNEL + #include <stddef.h> #include <string.h> #include <errno.h> @@ -36,8 +58,7 @@ #include <linux/a.out.h> #include <linux/elf.h> #include <linux/linkage.h> -#include <asm/setup.h> -#include <asm/amigatypes.h> +#include <asm/bootinfo.h> #include <asm/amigahw.h> #include <asm/page.h> @@ -48,22 +69,36 @@ #define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR))) /* temporary stack size */ -#define TEMP_STACKSIZE (256) +#define TEMP_STACKSIZE (256) + +#define DEFAULT_BAUD (9600) extern char copyall, copyallend; static struct exec kexec; static Elf32_Ehdr kexec_elf; -static struct bootinfo bi; - static const struct linuxboot_args *linuxboot_args; +/* Bootinfo */ +struct amiga_bootinfo bi; + +#ifdef BOOTINFO_COMPAT_1_0 +static struct compat_bootinfo compat_bootinfo; +#endif /* BOOTINFO_COMPAT_1_0 */ + +#define MAX_BI_SIZE (4096) +static u_long bi_size; +static union { + struct bi_record record; + u_char fake[MAX_BI_SIZE]; +} bi_union; + #define kernelname linuxboot_args->kernelname #define ramdiskname linuxboot_args->ramdiskname -#define commandline linuxboot_args->commandline #define debugflag linuxboot_args->debugflag #define keep_video linuxboot_args->keep_video #define reset_boards linuxboot_args->reset_boards +#define baud linuxboot_args->baud #define Puts linuxboot_args->puts #define GetChar linuxboot_args->getchar @@ -75,23 +110,38 @@ static const struct linuxboot_args *linuxboot_args; #define Close linuxboot_args->close #define FileSize linuxboot_args->filesize #define Sleep linuxboot_args->sleep -#define ModifyBootinfo linuxboot_args->modify_bootinfo - /* * Function Prototypes */ static u_long get_chipset(void); -static u_long get_cpu(void); +static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu); static u_long get_model(u_long chipset); static int probe_resident(const char *name); static int probe_resource(const char *name); +static int create_bootinfo(void); +#ifdef BOOTINFO_COMPAT_1_0 +static int create_compat_bootinfo(void); +#endif /* BOOTINFO_COMPAT_1_0 */ +static int add_bi_record(u_short tag, u_short size, const void *data); +static int add_bi_string(u_short tag, const u_char *s); static int check_bootinfo_version(const char *memptr); static void start_kernel(void (*startfunc)(), char *stackp, char *memptr, u_long start_mem, u_long mem_size, u_long rd_size, u_long kernel_size) __attribute__ ((noreturn)); asmlinkage u_long maprommed(void); +asmlinkage u_long check346(void); +#ifdef ZKERNEL +static int load_zkernel(int fd); +static int KRead(int fd, void *buf, int cnt); +static int KSeek(int fd, int offset); +static int KClose(int fd); +#else +#define KRead Read +#define KSeek Seek +#define KClose Close +#endif /* @@ -126,7 +176,7 @@ static struct boardreset boardresetdb[] = { }; #define NUM_BOARDRESET sizeof(boardresetdb)/sizeof(*boardresetdb) -static void (*boardresetfuncs[NUM_AUTO])(const struct ConfigDev *cd); +static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd); const char *amiga_models[] = { @@ -151,7 +201,7 @@ const u_long last_amiga_model = AMI_DRACO; u_long linuxboot(const struct linuxboot_args *args) { - int kfd = -1, rfd = -1, elf_kernel = 0; + int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip; int i, j; const struct MemHeader *mnp; struct ConfigDev *cdp = NULL; @@ -159,11 +209,13 @@ u_long linuxboot(const struct linuxboot_args *args) u_long *stack = NULL; u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size; u_long kernel_size; + u_int realbaud; u_long memreq = 0, text_offset = 0; Elf32_Phdr *kernel_phdrs = NULL; void (*startfunc)(void); u_short manuf; u_char prod; + void *bi_ptr; linuxboot_args = args; @@ -171,37 +223,42 @@ u_long linuxboot(const struct linuxboot_args *args) Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n"); Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n"); + /* Note: Initial values in bi override detected values */ + bi = args->bi; + /* machine is Amiga */ bi.machtype = MACH_AMIGA; /* determine chipset */ - bi.bi_amiga.chipset = get_chipset(); + if (!bi.chipset) + bi.chipset = get_chipset(); - /* determine CPU type */ - bi.cputype = get_cpu(); + /* determine CPU, FPU and MMU type */ + if (!bi.cputype) + get_processor(&bi.cputype, &bi.fputype, &bi.mmutype); /* determine Amiga model */ - bi.bi_amiga.model = get_model(bi.bi_amiga.chipset); - model_mask = (bi.bi_amiga.model != AMI_UNKNOWN) ? 1<<bi.bi_amiga.model : 0; + if (!bi.model) + bi.model = get_model(bi.chipset); + model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0; /* Memory & AutoConfig based on 'unix_boot.c' by C= */ /* find all of the autoconfig boards in the system */ - bi.bi_amiga.num_autocon = 0; - for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++) { - if (bi.bi_amiga.num_autocon < NUM_AUTO) { - /* copy the contents of each structure into our boot info */ - memcpy(&bi.bi_amiga.autocon[bi.bi_amiga.num_autocon], cdp, - sizeof(struct ConfigDev)); - /* count this device */ - bi.bi_amiga.num_autocon++; - } else - Printf("Warning: too many AutoConfig devices. Ignoring device at " - "0x%08lx\n", cdp->cd_BoardAddr); - } - + if (!bi.num_autocon) + for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++) + if (bi.num_autocon < ZORRO_NUM_AUTO) + /* copy the contents of each structure into our boot info and + count this device */ + memcpy(&bi.autocon[bi.num_autocon++], cdp, + sizeof(struct ConfigDev)); + else + Printf("Warning: too many AutoConfig devices. Ignoring device at " + "0x%08lx\n", cdp->cd_BoardAddr); + + do_fast = bi.num_memory ? 0 : 1; + do_chip = bi.chip_size ? 0 : 1; /* find out the memory in the system */ - bi.num_memory = 0; for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head; mnp->mh_Node.ln_Succ; mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) { @@ -240,7 +297,7 @@ u_long linuxboot(const struct linuxboot_args *args) mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000); /* if fast memory */ - if (mh.mh_Attributes & MEMF_FAST) { + if (do_fast && mh.mh_Attributes & MEMF_FAST) { /* set the size value to the size of this block and mask off to a 256K increment */ u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000; @@ -253,38 +310,36 @@ u_long linuxboot(const struct linuxboot_args *args) bi.num_memory++; } else Printf("Warning: too many memory blocks. Ignoring block " - "of %ldK at 0x%08x\n", size>>10, + "of %ldK at 0x%08x\n", size>>10, (u_long)mh.mh_Lower); - } else if (mh.mh_Attributes & MEMF_CHIP) + } else if (do_chip && mh.mh_Attributes & MEMF_CHIP) /* if CHIP memory, record the size */ - bi.bi_amiga.chip_size = (u_long)mh.mh_Upper; + bi.chip_size = (u_long)mh.mh_Upper; } /* get info from ExecBase */ - bi.bi_amiga.vblank = SysBase->VBlankFrequency; - bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency; - bi.bi_amiga.eclock = SysBase->ex_EClockFrequency; - - /* copy command line options into the kernel command line */ - strncpy(bi.command_line, commandline, CL_SIZE); - bi.command_line[CL_SIZE-1] = '\0'; - - - /* modify the bootinfo, e.g. to change the memory configuration */ - if (ModifyBootinfo && !ModifyBootinfo(&bi)) - goto Fail; - + if (!bi.vblank) + bi.vblank = SysBase->VBlankFrequency; + if (!bi.psfreq) + bi.psfreq = SysBase->PowerSupplyFrequency; + if (!bi.eclock) + bi.eclock = SysBase->ex_EClockFrequency; + + /* serial port */ + if (!bi.serper) { + realbaud = baud ? baud : DEFAULT_BAUD; + bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1; + } /* display Amiga model */ - if (bi.bi_amiga.model >= first_amiga_model && - bi.bi_amiga.model <= last_amiga_model) - Printf("%s ", amiga_models[bi.bi_amiga.model-first_amiga_model]); + if (bi.model >= first_amiga_model && bi.model <= last_amiga_model) + Printf("%s ", amiga_models[bi.model-first_amiga_model]); else Puts("Amiga "); /* display the CPU type */ Puts("CPU: "); - switch (bi.cputype & CPU_MASK) { + switch (bi.cputype) { case CPU_68020: Puts("68020 (Do you have an MMU?)"); break; @@ -302,7 +357,7 @@ u_long linuxboot(const struct linuxboot_args *args) Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags); goto Fail; } - switch (bi.cputype & ~CPU_MASK) { + switch (bi.fputype) { case FPU_68881: Puts(" with 68881 FPU"); break; @@ -319,7 +374,7 @@ u_long linuxboot(const struct linuxboot_args *args) } /* display the chipset */ - switch(bi.bi_amiga.chipset) { + switch (bi.chipset) { case CS_STONEAGE: Puts(", old or unknown chipset"); break; @@ -340,21 +395,21 @@ u_long linuxboot(const struct linuxboot_args *args) Printf("Command line is '%s'\n", bi.command_line); /* display the clock statistics */ - Printf("Vertical Blank Frequency: %ldHz\n", bi.bi_amiga.vblank); - Printf("Power Supply Frequency: %ldHz\n", bi.bi_amiga.psfreq); - Printf("EClock Frequency: %ldHz\n\n", bi.bi_amiga.eclock); + Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank); + Printf("Power Supply Frequency: %ldHz\n", bi.psfreq); + Printf("EClock Frequency: %ldHz\n\n", bi.eclock); /* display autoconfig devices */ - if (bi.bi_amiga.num_autocon) { - Printf("Found %ld AutoConfig Device%s\n", bi.bi_amiga.num_autocon, - bi.bi_amiga.num_autocon > 1 ? "s" : ""); - for (i = 0; i < bi.bi_amiga.num_autocon; i++) { + if (bi.num_autocon) { + Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon, + bi.num_autocon > 1 ? "s" : ""); + for (i = 0; i < bi.num_autocon; i++) { Printf("Device %ld: addr = 0x%08lx", i, - (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr); + (u_long)bi.autocon[i].cd_BoardAddr); boardresetfuncs[i] = NULL; if (reset_boards) { - manuf = bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer; - prod = bi.bi_amiga.autocon[i].cd_Rom.er_Product; + manuf = bi.autocon[i].cd_Rom.er_Manufacturer; + prod = bi.autocon[i].cd_Rom.er_Product; for (j = 0; j < NUM_BOARDRESET; j++) if ((manuf == boardresetdb[j].manuf) && (prod == boardresetdb[j].prod)) { @@ -383,7 +438,7 @@ u_long linuxboot(const struct linuxboot_args *args) } /* display chip memory size */ - Printf("%ldK of CHIP memory\n", bi.bi_amiga.chip_size>>10); + Printf("%ldK of CHIP memory\n", bi.chip_size>>10); start_mem = bi.memory[0].addr; mem_size = bi.memory[0].size; @@ -392,7 +447,7 @@ u_long linuxboot(const struct linuxboot_args *args) Printf("\nThe kernel will be located at 0x%08lx\n", start_mem); /* verify that there is enough Chip RAM */ - if (bi.bi_amiga.chip_size < 512*1024) { + if (bi.chip_size < 512*1024) { Puts("Not enough Chip RAM in this system. Aborting...\n"); goto Fail; } @@ -414,22 +469,39 @@ u_long linuxboot(const struct linuxboot_args *args) goto Fail; } /* record ramdisk size */ - bi.ramdisk_size = (size+1023)>>10; + bi.ramdisk.size = size; } else - bi.ramdisk_size = 0; - rd_size = bi.ramdisk_size<<10; - bi.ramdisk_addr = start_mem+mem_size-rd_size; + bi.ramdisk.size = 0; + rd_size = bi.ramdisk.size; + bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size; + + /* create the bootinfo structure */ + if (!create_bootinfo()) + goto Fail; /* open kernel executable and read exec header */ if ((kfd = Open(kernelname)) == -1) { Printf("Unable to open kernel file `%s'\n", kernelname); goto Fail; } - if (Read(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) { + if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) { Puts("Unable to read exec header from kernel file\n"); goto Fail; } +#ifdef ZKERNEL + if (((unsigned char *)&kexec)[0] == 037 && + (((unsigned char *)&kexec)[1] == 0213 || + ((unsigned char *)&kexec)[1] == 0236)) { + /* That's a compressed kernel */ + Puts("Kernel is compressed\n"); + if (load_zkernel(kfd)) { + Puts("Decompression error -- aborting\n"); + goto Fail; + } + } +#endif + switch (N_MAGIC(kexec)) { case ZMAGIC: if (debugflag) @@ -447,8 +519,8 @@ u_long linuxboot(const struct linuxboot_args *args) default: /* Try to parse it as an ELF header */ - Seek(kfd, 0); - if ((Read(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) == + KSeek(kfd, 0); + if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) == sizeof(kexec_elf)) && (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) { elf_kernel = 1; @@ -469,8 +541,8 @@ u_long linuxboot(const struct linuxboot_args *args) Puts("Unable to allocate memory for program headers\n"); goto Fail; } - Seek(kfd, kexec_elf.e_phoff); - if (Read(kfd, (void *)kernel_phdrs, + KSeek(kfd, kexec_elf.e_phoff); + if (KRead(kfd, (void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(*kernel_phdrs)) != kexec_elf.e_phnum*sizeof(*kernel_phdrs)) { Puts("Unable to read program headers from kernel file\n"); @@ -511,7 +583,11 @@ u_long linuxboot(const struct linuxboot_args *args) kernel_size = max_addr-min_addr; } else kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss; - memreq = kernel_size+sizeof(struct bootinfo)+rd_size; + memreq = kernel_size+bi_size+rd_size; +#ifdef BOOTINFO_COMPAT_1_0 + if (sizeof(compat_bootinfo) > bi_size) + memreq = kernel_size+sizeof(compat_bootinfo)+rd_size; +#endif /* BOOTINFO_COMPAT_1_0 */ if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC | MEMF_CLEAR))) { Puts("Unable to allocate memory\n"); @@ -521,48 +597,63 @@ u_long linuxboot(const struct linuxboot_args *args) /* read the text and data segments from the kernel image */ if (elf_kernel) for (i = 0; i < kexec_elf.e_phnum; i++) { - if (Seek(kfd, kernel_phdrs[i].p_offset) == -1) { + if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) { Printf("Failed to seek to segment %ld\n", i); goto Fail; } - if (Read(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE, - kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) { + if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE, + kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) { Printf("Failed to read segment %ld\n", i); goto Fail; } } else { - if (Seek(kfd, text_offset) == -1) { - Printf("Failed to seek to text\n"); + if (KSeek(kfd, text_offset) == -1) { + Puts("Failed to seek to text\n"); goto Fail; } - if (Read(kfd, memptr, kexec.a_text) != kexec.a_text) { - Printf("Failed to read text\n"); + if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) { + Puts("Failed to read text\n"); goto Fail; } /* data follows immediately after text */ - if (Read(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) { - Printf("Failed to read data\n"); + if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) { + Puts("Failed to read data\n"); goto Fail; } } - Close(kfd); + KClose(kfd); kfd = -1; /* Check kernel's bootinfo version */ - if (!check_bootinfo_version(memptr)) - goto Fail; + switch (check_bootinfo_version(memptr)) { + case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION): + bi_ptr = &bi_union.record; + break; + +#ifdef BOOTINFO_COMPAT_1_0 + case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION): + if (!create_compat_bootinfo()) + goto Fail; + bi_ptr = &compat_bootinfo; + bi_size = sizeof(compat_bootinfo); + break; +#endif /* BOOTINFO_COMPAT_1_0 */ + + default: + goto Fail; + } /* copy the bootinfo to the end of the kernel image */ - memcpy((void *)(memptr+kernel_size), &bi, sizeof(struct bootinfo)); + memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size); if (ramdiskname) { if ((rfd = Open(ramdiskname)) == -1) { Printf("Unable to open ramdisk file `%s'\n", ramdiskname); goto Fail; } - if (Read(rfd, memptr+kernel_size+sizeof(bi), rd_size) != rd_size) { - Printf("Failed to read ramdisk file\n"); + if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) { + Puts("Failed to read ramdisk file\n"); goto Fail; } Close(rfd); @@ -587,9 +678,9 @@ u_long linuxboot(const struct linuxboot_args *args) memcpy(startfunc, ©all, startcodesize); if (debugflag) { - if (bi.ramdisk_size) + if (bi.ramdisk.size) Printf("RAM disk at 0x%08lx, size is %ldK\n", - (u_long)memptr+kernel_size, bi.ramdisk_size); + (u_long)memptr+kernel_size, bi.ramdisk.size>>10); if (elf_kernel) { PutChar('\n'); @@ -611,9 +702,10 @@ u_long linuxboot(const struct linuxboot_args *args) kexec.a_entry); Printf("ramdisk dest top is 0x%08lx\n", start_mem+mem_size); - Printf("ramdisk lower limit is 0x%08lx\n", (u_long)memptr+kernel_size); + Printf("ramdisk lower limit is 0x%08lx\n", + (u_long)(memptr+kernel_size)); Printf("ramdisk src top is 0x%08lx\n", - (u_long)memptr+kernel_size+rd_size); + (u_long)(memptr+kernel_size)+rd_size); Puts("\nType a key to continue the Linux/m68k boot..."); GetChar(); @@ -631,9 +723,9 @@ u_long linuxboot(const struct linuxboot_args *args) /* reset nasty Zorro boards */ if (reset_boards) - for (i = 0; i < bi.bi_amiga.num_autocon; i++) + for (i = 0; i < bi.num_autocon; i++) if (boardresetfuncs[i]) - boardresetfuncs[i](&bi.bi_amiga.autocon[i]); + boardresetfuncs[i](&bi.autocon[i]); /* Turn off all DMA */ custom.dmacon = DMAF_ALL | DMAF_MASTER; @@ -654,7 +746,7 @@ u_long linuxboot(const struct linuxboot_args *args) /* Clean up and exit in case of a failure */ Fail: if (kfd != -1) - Close(kfd); + KClose(kfd); if (rfd != -1) Close(rfd); if (memptr) @@ -696,32 +788,29 @@ static u_long get_chipset(void) * Determine the CPU Type */ -static u_long get_cpu(void) +static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu) { - u_long cpu = 0; - - if (SysBase->AttnFlags & AFF_68060) { - cpu = CPU_68060; - if (SysBase->AttnFlags & AFF_FPU40) - cpu |= FPU_68060; - } else if (SysBase->AttnFlags & AFF_68040) { - cpu = CPU_68040; + *cpu = *fpu = 0; + if (SysBase->AttnFlags & AFF_68060) + *cpu = CPU_68060; + else if (SysBase->AttnFlags & AFF_68040) + *cpu = CPU_68040; + else if (SysBase->AttnFlags & AFF_68030) + *cpu = CPU_68030; + else if (SysBase->AttnFlags & AFF_68020) + *cpu = CPU_68020; + if (*cpu == CPU_68040 || *cpu == CPU_68060) { if (SysBase->AttnFlags & AFF_FPU40) - cpu |= FPU_68040; + *fpu = *cpu; } else { - if (SysBase->AttnFlags & AFF_68030) - cpu = CPU_68030; - else if (SysBase->AttnFlags & AFF_68020) - cpu = CPU_68020; if (SysBase->AttnFlags & AFF_68882) - cpu |= FPU_68882; + *fpu = FPU_68882; else if (SysBase->AttnFlags & AFF_68881) - cpu |= FPU_68881; + *fpu = FPU_68881; } - return(cpu); + *mmu = *cpu; } - /* * Determine the Amiga Model */ @@ -737,7 +826,7 @@ static u_long get_model(u_long chipset) else { if (debugflag) Puts(" Chipset: "); - switch(chipset) { + switch (chipset) { case CS_STONEAGE: if (debugflag) Puts("Old or unknown\n"); @@ -810,7 +899,7 @@ static int probe_resident(const char *name) if (res) Printf("0x%08lx\n", res); else - Printf("not present\n"); + Puts("not present\n"); return(res ? TRUE : FALSE); } @@ -830,12 +919,179 @@ static int probe_resource(const char *name) if (res) Printf("0x%08lx\n", res); else - Printf("not present\n"); + Puts("not present\n"); return(res ? TRUE : FALSE); } /* + * Create the Bootinfo structure + */ + +static int create_bootinfo(void) +{ + int i; + struct bi_record *record; + + /* Initialization */ + bi_size = 0; + + /* Generic tags */ + if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype)) + return(0); + if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype)) + return(0); + if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype)) + return(0); + if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype)) + return(0); + for (i = 0; i < bi.num_memory; i++) + if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i])) + return(0); + if (bi.ramdisk.size) + if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk)) + return(0); + if (!add_bi_string(BI_COMMAND_LINE, bi.command_line)) + return(0); + + /* Amiga tags */ + if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model)) + return(0); + for (i = 0; i < bi.num_autocon; i++) + if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]), + &bi.autocon[i])) + return(0); + if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size)) + return(0); + if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank)) + return(0); + if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq)) + return(0); + if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock)) + return(0); + if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset)) + return(0); + if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper)) + return(0); + + /* Trailer */ + record = (struct bi_record *)((u_long)&bi_union.record+bi_size); + record->tag = BI_LAST; + bi_size += sizeof(bi_union.record.tag); + + return(1); +} + + + /* + * Add a Record to the Bootinfo Structure + */ + +static int add_bi_record(u_short tag, u_short size, const void *data) +{ + struct bi_record *record; + u_int size2; + + size2 = (sizeof(struct bi_record)+size+3)&-4; + if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) { + Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n"); + return(0); + } + record = (struct bi_record *)((u_long)&bi_union.record+bi_size); + record->tag = tag; + record->size = size2; + memcpy(record->data, data, size); + bi_size += size2; + return(1); +} + + + /* + * Add a String Record to the Bootinfo Structure + */ + +static int add_bi_string(u_short tag, const u_char *s) +{ + return(add_bi_record(tag, strlen(s)+1, (void *)s)); +} + + +#ifdef BOOTINFO_COMPAT_1_0 + + /* + * Create the Bootinfo structure for backwards compatibility mode + */ + +static int create_compat_bootinfo(void) +{ + u_int i; + + compat_bootinfo.machtype = bi.machtype; + if (bi.cputype & CPU_68020) + compat_bootinfo.cputype = COMPAT_CPU_68020; + else if (bi.cputype & CPU_68030) + compat_bootinfo.cputype = COMPAT_CPU_68030; + else if (bi.cputype & CPU_68040) + compat_bootinfo.cputype = COMPAT_CPU_68040; + else if (bi.cputype & CPU_68060) + compat_bootinfo.cputype = COMPAT_CPU_68060; + else { + Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype); + return(0); + } + if (bi.fputype & FPU_68881) + compat_bootinfo.cputype |= COMPAT_FPU_68881; + else if (bi.fputype & FPU_68882) + compat_bootinfo.cputype |= COMPAT_FPU_68882; + else if (bi.fputype & FPU_68040) + compat_bootinfo.cputype |= COMPAT_FPU_68040; + else if (bi.fputype & FPU_68060) + compat_bootinfo.cputype |= COMPAT_FPU_68060; + else { + Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype); + return(0); + } + compat_bootinfo.num_memory = bi.num_memory; + if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) { + Printf("Warning: using only %ld blocks of memory\n", + COMPAT_NUM_MEMINFO); + compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO; + } + for (i = 0; i < compat_bootinfo.num_memory; i++) { + compat_bootinfo.memory[i].addr = bi.memory[i].addr; + compat_bootinfo.memory[i].size = bi.memory[i].size; + } + if (bi.ramdisk.size) { + compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024; + compat_bootinfo.ramdisk_addr = bi.ramdisk.addr; + } else { + compat_bootinfo.ramdisk_size = 0; + compat_bootinfo.ramdisk_addr = 0; + } + strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE); + compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0'; + + compat_bootinfo.bi_amiga.model = bi.model; + compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon; + if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) { + Printf("Warning: using only %ld AutoConfig devices\n", + COMPAT_NUM_AUTO); + compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO; + } + for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++) + compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i]; + compat_bootinfo.bi_amiga.chip_size = bi.chip_size; + compat_bootinfo.bi_amiga.vblank = bi.vblank; + compat_bootinfo.bi_amiga.psfreq = bi.psfreq; + compat_bootinfo.bi_amiga.eclock = bi.eclock; + compat_bootinfo.bi_amiga.chipset = bi.chipset; + compat_bootinfo.bi_amiga.hw_present = 0; + return(1); +} +#endif /* BOOTINFO_COMPAT_1_0 */ + + + /* * Compare the Bootstrap and Kernel Versions */ @@ -852,7 +1108,7 @@ static int check_bootinfo_version(const char *memptr) break; } if (!version) - Printf("Kernel has no bootinfo version info, assuming 0.0\n"); + Puts("Kernel has no bootinfo version info, assuming 0.0\n"); kernel_major = BI_VERSION_MAJOR(version); kernel_minor = BI_VERSION_MINOR(version); @@ -863,16 +1119,27 @@ static int check_bootinfo_version(const char *memptr) Printf("Kernel's bootinfo version : %ld.%ld\n", kernel_major, kernel_minor); - if (kernel_major != boots_major) { - Printf("\nThis bootstrap is too %s for this kernel!\n", - boots_major < kernel_major ? "old" : "new"); - return(0); - } - if (kernel_minor > boots_minor) { - Printf("Warning: Bootinfo version of bootstrap and kernel differ!\n" ); - Printf(" Certain features may not work.\n"); + switch (kernel_major) { + case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION): + if (kernel_minor > boots_minor) { + Puts("Warning: Bootinfo version of bootstrap and kernel " + "differ!\n"); + Puts(" Certain features may not work.\n"); + } + break; + +#ifdef BOOTINFO_COMPAT_1_0 + case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION): + Puts("(using backwards compatibility mode)\n"); + break; +#endif /* BOOTINFO_COMPAT_1_0 */ + + default: + Printf("\nThis bootstrap is too %s for this kernel!\n", + boots_major < kernel_major ? "old" : "new"); + return(0); } - return(1); + return(kernel_major); } @@ -891,7 +1158,7 @@ static void start_kernel(void (*startfunc)(), char *stackp, char *memptr, register u_long d0 __asm("d0") = mem_size; register u_long d1 __asm("d1") = rd_size; register u_long d2 __asm("d2") = kernel_size; - register u_long d3 __asm("d3") = sizeof(struct bootinfo); + register u_long d3 __asm("d3") = bi_size; __asm __volatile ("movel a2,sp;" "jmp a0@" @@ -915,7 +1182,7 @@ static void start_kernel(void (*startfunc)(), char *stackp, char *memptr, * d0 = mem_size * d1 = rd_size * d2 = kernel_size - * d3 = sizeof(struct bootinfo) + * d3 = bi_size */ asm(".text\n" @@ -931,10 +1198,10 @@ SYMBOL_NAME_STR(copyall) ": moveb a0@+,a1@+ | *dest++ = *src++; jra 1b 2: - | /* copy early bootinfo to end of bss */ + | /* copy bootinfo to end of bss */ movel a3,a0 | src = (u_long *)(memptr+kernel_size); addl d2,a0 | dest = end of bss (already in a1) - movel d3,d7 | count = sizeof(struct bootinfo) + movel d3,d7 | count = bi_size subql #1,d7 1: moveb a0@+,a1@+ | while (--count > -1) dbra d7,1b | *dest++ = *src++ @@ -944,7 +1211,7 @@ SYMBOL_NAME_STR(copyall) ": movel a4,a1 | dest = (u_long *)(start_mem+mem_size); addl d0,a1 movel a3,a2 | limit = (u_long *)(memptr+kernel_size + - addl d2,a2 | sizeof(struct bootinfo)); + addl d2,a2 | bi_size); addl d3,a2 movel a2,a0 | src = (u_long *)((u_long)limit+rd_size); addl d1,a0 @@ -1114,7 +1381,7 @@ static void reset_hydra(const struct ConfigDev *cd) Disable(); *nic_cr = 0x21; /* nic command register: software reset etc. */ - while(((*nic_isr & 0x80) == 0) && --n) /* wait for reset to complete */ + while (((*nic_isr & 0x80) == 0) && --n) /* wait for reset to complete */ ; Enable(); @@ -1126,3 +1393,294 @@ static void reset_a2060(const struct ConfigDev *cd) #error reset_a2060: not yet implemented } #endif + + +#ifdef ZKERNEL + +#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */ +#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS) +#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1) +#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE) + +/* variables for storing the uncompressed data */ +static char *ZFile[ZFILE_N_CHUNKS]; +static int ZFileSize = 0; +static int ZFpos = 0; +static int Zwpos = 0; + +static int Zinfd = 0; /* fd of compressed file */ + +/* + * gzip declarations + */ + +#define OF(args) args + +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define INBUFSIZ 4096 +#define WSIZE 0x8000 /* window size--must be a power of two, and */ + /* at least 32K for zip's deflate method */ + +static uch *inbuf; +static uch *window; + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ +static int exit_code = 0; +static long bytes_out = 0; + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions (stubbed out) */ +#define Assert(cond,msg) +#define Trace(x) +#define Tracev(x) +#define Tracevv(x) +#define Tracec(c,x) +#define Tracecv(c,x) + +#define STATIC static + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +#define malloc(x) AllocVec(x, MEMF_FAST | MEMF_PUBLIC) +#define free(x) FreeVec(x) + +#ifdef LILO +#include "inflate.c" +#else +#include "../../../../lib/inflate.c" +#endif + +static void gzip_mark(void **ptr) +{ +} + +static void gzip_release(void **ptr) +{ +} + + +/* + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + if (exit_code) + return -1; + + insize = Read(Zinfd, inbuf, INBUFSIZ); + if (insize <= 0) + return -1; + + inptr = 1; + return(inbuf[0]); +} + +/* + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + int chunk = Zwpos >> ZFILE_CHUNK_BITS; + + if (exit_code) + return; + + if (chunk >= ZFILE_N_CHUNKS) { + error("Compressed image too large! Aborting.\n"); + return; + } + if (!ZFile[chunk]) { + if (!(ZFile[chunk] = (char *)AllocMem(ZFILE_CHUNK_SIZE, + MEMF_FAST | MEMF_PUBLIC))) { + error("Out of memory for decompresing kernel image\n"); + return; + } + } + memcpy(ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt); + Zwpos += outcnt; + +#define DISPLAY_BITS 10 + if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) + PutChar('.'); + + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + Printf("\n%s", x); + exit_code = 1; +} + +static inline int call_sub(int (*func)(void), void *stackp) +{ + register int _res __asm("d0"); + register int (*a0)(void) __asm("a0") = func; + register int (*a1)(void) __asm("a1") = stackp; + + __asm __volatile ("movel sp,a2;" + "movel a1,sp;" + "jsr a0@;" + "movel a2,sp" + : "=r" (_res) + : "r" (a0), "r" (a1) + : "a0", "a1", "a2", "d0", "d1", "memory"); + return(_res); +} + +static int load_zkernel(int fd) +{ + int i, err = -1; +#define ZSTACKSIZE (16384) + u_long *zstack; + + for (i = 0; i < ZFILE_N_CHUNKS; ++i) + ZFile[i] = NULL; + Zinfd = fd; + Seek(fd, 0); + + if (!(inbuf = (uch *)AllocMem(INBUFSIZ, MEMF_FAST | MEMF_PUBLIC))) + Puts("Couldn't allocate gunzip buffer\n"); + else { + if (!(window = (uch *)AllocMem(WSIZE, MEMF_FAST | MEMF_PUBLIC))) + Puts("Couldn't allocate gunzip window\n"); + else { + if (!(zstack = (u_long *)AllocMem(ZSTACKSIZE, + MEMF_FAST | MEMF_PUBLIC))) + Puts("Couldn't allocate gunzip stack\n"); + else { + Puts("Uncompressing kernel image "); + makecrc(); + if (!(err = call_sub(gunzip, (char *)zstack+ZSTACKSIZE))) + Puts("done\n"); + ZFileSize = Zwpos; + FreeMem(zstack, ZSTACKSIZE); + } + FreeMem(window, WSIZE); + window = NULL; + } + FreeMem(inbuf, INBUFSIZ); + inbuf = NULL; + } + Close(Zinfd); /* input file not needed anymore */ + return(err); +} + + +/* Note about the read/lseek wrapper and its memory management: It assumes + * that all seeks are only forward, and thus data already read or skipped can + * be freed. This is true for current organization of bootstrap and kernels. + * Little exception: The struct kexec at the start of the file. After reading + * it, there may be a seek back to the end of the file. But this currently + * doesn't hurt. (Roman) + */ + +static int KRead(int fd, void *buf, int cnt) +{ + unsigned done = 0; + + if (!ZFileSize) + return(Read(fd, buf, cnt)); + + if (ZFpos + cnt > ZFileSize) + cnt = ZFileSize - ZFpos; + + while (cnt > 0) { + unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS; + unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS; + unsigned n = cnt; + + if (ZFpos + n > endchunk) + n = endchunk - ZFpos; + memcpy(buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n); + cnt -= n; + buf += n; + done += n; + ZFpos += n; + + if (ZFpos == endchunk) { + FreeMem(ZFile[chunk], ZFILE_CHUNK_SIZE); + ZFile[chunk] = NULL; + } + } + + return(done); +} + + +static int KSeek(int fd, int offset) +{ + unsigned oldpos, oldchunk, newchunk; + + if (!ZFileSize) + return(Seek(fd, offset)); + + oldpos = ZFpos; + ZFpos = offset; + if (ZFpos < 0) { + ZFpos = 0; + return(-1); + } else if (ZFpos > ZFileSize) { + ZFpos = ZFileSize; + return(-1); + } + + /* free memory of skipped-over data */ + oldchunk = oldpos >> ZFILE_CHUNK_BITS; + newchunk = ZFpos >> ZFILE_CHUNK_BITS; + while(oldchunk < newchunk) { + if (ZFile[oldchunk]) { + FreeMem(ZFile[oldchunk], ZFILE_CHUNK_SIZE); + ZFile[oldchunk] = NULL; + } + ++oldchunk; + } + return(ZFpos); +} + + +static void free_zfile(void) +{ + int i; + + for (i = 0; i < ZFILE_N_CHUNKS; ++i) + if (ZFile[i]) { + FreeMem(ZFile[i], ZFILE_CHUNK_SIZE); + ZFile[i] = NULL; + } +} + +static int KClose(int fd) +{ + if (ZFileSize) { + free_zfile(); + ZFileSize = 0; + } else + Close(fd); + return(0); +} +#endif /* ZKERNEL */ diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h index 2331a994d..8ebfe63b4 100644 --- a/arch/m68k/boot/amiga/linuxboot.h +++ b/arch/m68k/boot/amiga/linuxboot.h @@ -24,14 +24,42 @@ #include <asm/setup.h> -#include <asm/zorro.h> +#include <linux/zorro.h> /* * Amiboot Version */ -#define AMIBOOT_VERSION "4.0" +#define AMIBOOT_VERSION "5.4" + + + /* + * Amiga Bootinfo Definitions + * + * All limits herein are `soft' limits, i.e. they don't put constraints + * on the actual parameters in the kernel. + */ + +struct amiga_bootinfo { + u_long machtype; /* machine type = MACH_AMIGA */ + u_long cputype; /* system CPU */ + u_long fputype; /* system FPU */ + u_long mmutype; /* system MMU */ + int num_memory; /* # of memory blocks found */ + struct mem_info memory[NUM_MEMINFO];/* memory description */ + struct mem_info ramdisk; /* ramdisk description */ + char command_line[CL_SIZE]; /* kernel command line parameters */ + u_long model; /* Amiga Model */ + int num_autocon; /* # of autoconfig devices found */ + struct ConfigDev autocon[ZORRO_NUM_AUTO]; /* autoconfig devices */ + u_long chip_size; /* size of chip memory (bytes) */ + u_char vblank; /* VBLANK frequency */ + u_char psfreq; /* power supply frequency */ + u_long eclock; /* EClock frequency */ + u_long chipset; /* native chipset present */ + u_short serper; /* serial port period */ +}; /* @@ -39,12 +67,13 @@ */ struct linuxboot_args { + struct amiga_bootinfo bi; /* Initial values override detected values */ const char *kernelname; const char *ramdiskname; - const char *commandline; int debugflag; int keep_video; int reset_boards; + u_int baud; void (*puts)(const char *str); long (*getchar)(void); void (*putchar)(char c); @@ -55,7 +84,6 @@ struct linuxboot_args { void (*close)(int fd); int (*filesize)(const char *path); void (*sleep)(u_long micros); - int (*modify_bootinfo)(struct bootinfo *bi); }; diff --git a/arch/m68k/boot/atari/bootp.c b/arch/m68k/boot/atari/bootp.c index db4fc284f..affe636b8 100644 --- a/arch/m68k/boot/atari/bootp.c +++ b/arch/m68k/boot/atari/bootp.c @@ -203,18 +203,20 @@ static int eth_rcv( Packet *pkt, int *len ); /* get_remote_kernel(): * Perform all necessary steps to get the kernel image * from the boot server. If successfull (retval == 0), subsequent calls to - * kread() can access the data. + * kread() can access the data. Fatal errors (i.e., retrying is useless) + * return -2, others -1. */ int get_remote_kernel( const char *kname /* optional */ ) { char image_name[256]; - + int rv; + /* Check if a Ethernet interface is present and determine the Ethernet * address */ if (check_ethif() < 0) { printf( "No Ethernet interface found -- no remote boot possible.\n" ); - return( -1 ); + return( -2 ); } /* Do a BOOTP request to find out our IP address and the kernel image's @@ -223,23 +225,23 @@ int get_remote_kernel( const char *kname /* optional */ ) strcpy( image_name, kname ); else *image_name = 0; - if (bootp( image_name ) < 0) - return( -1 ); + if ((rv = bootp( image_name )) < 0) + return( rv ); /* Now start a TFTP connection to receive the kernel image */ - if (tftp( image_name ) < 0) - return( -1 ); + if ((rv = tftp( image_name )) < 0) + return( rv ); return( 0 ); } -/* kread(), klseek(), kclose(): +/* ll_read(), ll_lseek(), ll_close(): * Functions for accessing the received kernel image like with read(), * lseek(), close(). */ -int kread( int fd, void *buf, unsigned cnt ) +int ll_read( int fd, void *buf, unsigned cnt ) { unsigned done = 0; @@ -261,18 +263,26 @@ int kread( int fd, void *buf, unsigned cnt ) buf += n; done += n; KFpos += n; + + if (KFpos == endchunk) { + free( KFile[chunk] ); + KFile[chunk] = NULL; + } } return( done ); } -int klseek( int fd, int where, int whence ) +int ll_lseek( int fd, int where, int whence ) { + unsigned oldpos, oldchunk, newchunk; + if (!KFileSize) return( lseek( fd, where, whence ) ); + oldpos = KFpos; switch( whence ) { case SEEK_SET: KFpos = where; @@ -295,11 +305,22 @@ int klseek( int fd, int where, int whence ) return( -1 ); } + /* free memory of skipped-over data */ + oldchunk = oldpos >> KFILE_CHUNK_BITS; + newchunk = KFpos >> KFILE_CHUNK_BITS; + while( oldchunk < newchunk ) { + if (KFile[oldchunk]) { + free( KFile[oldchunk] ); + KFile[oldchunk] = NULL; + } + ++oldchunk; + } + return( KFpos ); } -int kclose( int fd ) +int ll_close( int fd ) { if (!KFileSize) @@ -382,7 +403,7 @@ static int bootp( char *image_name ) } if (retry >= BOOTP_RETRYS) { printf( "No response from a bootp server\n" ); - return( -1 ); + return( -2 ); } ServerIPaddr = reply->bootp.siaddr; @@ -433,7 +454,7 @@ static int tftp( char *image_name ) printf( "TFTP RREQ: %s\n", ErrStr[-err-1] ); if (--retries > 0) goto repeat_req; - return( -1 ); + return( err == ETIMEO ? -2 : -1 ); } retries = 5; diff --git a/arch/m68k/boot/atari/bootp.h b/arch/m68k/boot/atari/bootp.h index 02988edaf..0ee96cdcc 100644 --- a/arch/m68k/boot/atari/bootp.h +++ b/arch/m68k/boot/atari/bootp.h @@ -34,9 +34,9 @@ typedef unsigned long IPADDR; /***************************** Prototypes *****************************/ int get_remote_kernel( const char *kname ); -int kread( int fd, void *buf, unsigned cnt ); -int klseek( int fd, int where, int whence ); -int kclose( int fd ); +int ll_read( int fd, void *buf, unsigned cnt ); +int ll_lseek( int fd, int where, int whence ); +int ll_close( int fd ); /************************* End of Prototypes **************************/ diff --git a/arch/m68k/boot/atari/bootstrap.c b/arch/m68k/boot/atari/bootstrap.c index dbf5fada0..84c6a6e4b 100644 --- a/arch/m68k/boot/atari/bootstrap.c +++ b/arch/m68k/boot/atari/bootstrap.c @@ -8,7 +8,13 @@ ** for more details. ** ** History: -** 10 Dec 1995 BOOTP/TFTP support (Roman) +** 01 Feb 1997 Implemented kernel decompression (Roman) +** 28 Nov 1996 Fixed and tested previous change (James) +** 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert) +** 12 Nov 1996 Fixed and tested previous change (Andreas) +** 18 Aug 1996 Updated for the new boot information structure (untested!) +** (Geert) +** 10 Dec 1995 BOOTP/TFTP support (Roman) ** 03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas) ** 11 Jul 1995 Add support for ELF format kernel (Andreas) ** 16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram @@ -26,6 +32,11 @@ ** 14 Mar 1994 New mini-copy routine used (rdv) */ + +#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */ +/* support compressed kernels? */ +#define ZKERNEL + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -43,6 +54,7 @@ #include <asm/page.h> #define _LINUX_TYPES_H /* Hack to prevent including <linux/types.h> */ +#include <asm/bootinfo.h> #include <asm/setup.h> /* Atari bootstrap include file */ @@ -54,10 +66,29 @@ extern char *optarg; extern int optind; static void get_default_args( int *argc, char ***argv ); +static int create_bootinfo(void); +#ifdef BOOTINFO_COMPAT_1_0 +static int create_compat_bootinfo(void); +#endif /* BOOTINFO_COMPAT_1_0 */ +static int add_bi_record(u_short tag, u_short size, const void *data); +static int add_bi_string(u_short tag, const u_char *s); /* This is missing in <unistd.h> */ extern int sync (void); -struct bootinfo bi; +/* Bootinfo */ +static struct atari_bootinfo bi; + +#ifdef BOOTINFO_COMPAT_1_0 +static struct compat_bootinfo compat_bootinfo; +#endif /* BOOTINFO_COMPAT_1_0 */ + +#define MAX_BI_SIZE (4096) +static u_long bi_size; +static union { +struct bi_record record; + u_char fake[MAX_BI_SIZE]; +} bi_union; + u_long *cookiejar; u_long userstk; @@ -132,6 +163,9 @@ extern char copyall, copyallend; * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is * in the range where the Medusa always asserts DTACK. + * On the Hades address 0 is writeable as well and it asserts DTACK on + * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000 + * is tested. On the Medusa this gives a bus error. */ int test_medusa( void ) @@ -150,7 +184,10 @@ int test_medusa( void ) "nop \n\t" "tstb 0x00ff82fe\n\t" "nop \n\t" - "moveq #1,%0\n" + "moveq #1,%0\n\t" + "tstb 0xb0000000\n\t" + "nop \n\t" + "moveq #0,%0\n" "Lberr:\t" "movel a1,sp\n\t" "movel a0,0x8" @@ -303,27 +340,48 @@ static int check_bootinfo_version(char *memptr) printf("Kernel's bootinfo version : %d.%d\n", kernel_major, kernel_minor); - if (kernel_major != boots_major) { - printf("\nThis bootstrap is too %s for this kernel!\n", - boots_major < kernel_major ? "old" : "new"); - return 0; - } - if (kernel_minor > boots_minor) { - printf("Warning: Bootinfo version of bootstrap and kernel differ!\n"); - printf(" Certain features may not work.\n"); + switch (kernel_major) { + case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION): + if (kernel_minor > boots_minor) { + printf("Warning: Bootinfo version of bootstrap and kernel " + "differ!\n"); + printf(" Certain features may not work.\n"); + } + break; + +#ifdef BOOTINFO_COMPAT_1_0 + case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION): + printf("(using backwards compatibility mode)\n"); + break; +#endif /* BOOTINFO_COMPAT_1_0 */ + + default: + printf("\nThis bootstrap is too %s for this kernel!\n", + boots_major < kernel_major ? "old" : "new"); + return 0; } - return 1; + return kernel_major; } #ifdef USE_BOOTP # include "bootp.h" #else -# define kread read -# define klseek lseek -# define kclose close +# define ll_read read +# define ll_lseek lseek +# define ll_close close #endif +#ifdef ZKERNEL +static int load_zkernel( int fd ); +static int kread( int fd, void *buf, unsigned cnt ); +static int klseek( int fd, int where, int whence ); +static int kclose( int fd ); +#else +# define kread read +# define klseek lseek +# define kclose close +#endif /* ++andreas: this must be inline due to Super */ static inline void boot_exit (int) __attribute__ ((noreturn)); @@ -347,15 +405,18 @@ int main(int argc, char *argv[]) Elf32_Ehdr kexec_elf; Elf32_Phdr *kernel_phdrs = NULL; u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size; + int prefer_bootp = 1, kname_set = 0, n_knames; #ifdef USE_BOOTP - int prefer_bootp = 1, kname_set = 0; + int err; #endif + char kname_list[5][64]; + void *bi_ptr; ramdisk_name = NULL; kernel_name = "vmlinux"; /* print the startup message */ - puts("\fLinux/68k Atari Bootstrap version 1.8" + puts("\fLinux/68k Atari Bootstrap version 2.2" #ifdef USE_BOOTP " (with BOOTP)" #endif @@ -371,11 +432,7 @@ int main(int argc, char *argv[]) bi.machtype = MACH_ATARI; /* check arguments */ -#ifdef USE_BOOTP while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF) -#else - while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF) -#endif switch (ch) { case 'd': debugflag = 1; @@ -388,18 +445,14 @@ int main(int argc, char *argv[]) break; case 'k': kernel_name = optarg; -#ifdef USE_BOOTP kname_set = 1; -#endif break; case 'r': ramdisk_name = optarg; break; -#ifdef USE_BOOTP case 'b': prefer_bootp = 0; break; -#endif case '?': default: usage(); @@ -447,10 +500,10 @@ int main(int argc, char *argv[]) switch(cpu_type) { case 0: case 10: break; - case 20: bi.cputype = CPU_68020; break; - case 30: bi.cputype = CPU_68030; break; - case 40: bi.cputype = CPU_68040; break; - case 60: bi.cputype = CPU_68060; break; + case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break; + case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break; + case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break; + case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break; default: fprintf(stderr, "Error: Unknown CPU type. Aborting...\n"); boot_exit(EXIT_FAILURE); @@ -463,11 +516,11 @@ int main(int argc, char *argv[]) /* check for FPU; in case of a '040 or '060, don't look at _FPU itself, * some software may set it to wrong values (68882 or the like) */ if (cpu_type == 40) { - bi.cputype |= FPU_68040; + bi.fputype = FPU_68040; puts( "68040\n" ); } else if (cpu_type == 60) { - bi.cputype |= FPU_68060; + bi.fputype = FPU_68060; puts( "68060\n" ); } else { @@ -484,12 +537,12 @@ int main(int argc, char *argv[]) goto m68882; /* fall through */ case 4: - bi.cputype |= FPU_68881; + bi.fputype = FPU_68881; puts("68881\n"); break; case 6: m68882: - bi.cputype |= FPU_68882; + bi.fputype = FPU_68882; puts("68882\n"); break; default: @@ -499,15 +552,13 @@ int main(int argc, char *argv[]) } /* ++roman: If an FPU was announced in the cookie, test whether it is a real hardware FPU or a software emulator! */ - if (bi.cputype & FPU_MASK) { + if (bi.fputype) { if (test_software_fpu()) { - bi.cputype &= ~FPU_MASK; + bi.fputype = 0; puts("FPU: software emulated. Assuming no FPU."); } } - memset(&bi.bi_atari.hw_present, 0, sizeof(bi.bi_atari.hw_present)); - /* Get the amounts of ST- and TT-RAM. */ /* The size must be a multiple of 1MB. */ i = 0; @@ -678,7 +729,7 @@ int main(int argc, char *argv[]) #endif /* Pass contents of the _MCH cookie to the kernel */ - bi.bi_atari.mch_cookie = mch_type; + bi.mch_cookie = mch_type; /* * Copy command line options into the kernel command line. @@ -707,38 +758,60 @@ int main(int argc, char *argv[]) boot_exit(-1); #endif /* TEST */ + i = 0; #ifdef USE_BOOTP + if (!kname_set) + kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */ +#endif +#ifdef ZKERNEL + strcpy( kname_list[i], kernel_name ); + strcat( kname_list[i], ".gz" ); + ++i; +#endif + strcpy( kname_list[i++], kernel_name ); +#ifdef ZKERNEL + if (!kname_set) + strcpy( kname_list[i++], "vmlinuz" ); +#endif + n_knames = i; + kfd = -1; +#ifdef USE_BOOTP if (prefer_bootp) { - /* First try to get a remote kernel, then use a local kernel (if - * present) */ - if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) { - printf( "\nremote boot failed; trying local kernel\n" ); - if ((kfd = open (kernel_name, O_RDONLY)) == -1) { - fprintf (stderr, "Unable to open kernel file %s\n", - kernel_name); - boot_exit (EXIT_FAILURE); - } + for( i = 0; i < n_knames; ++i ) { + if ((err = get_remote_kernel( kname_list[i] )) >= 0) + goto kernel_open; + if (err < -1) /* fatal error; retries don't help... */ + break; } + printf( "\nremote boot failed; trying local kernel\n" ); } - else { - /* Try BOOTP if local kernel cannot be opened */ - if ((kfd = open (kernel_name, O_RDONLY)) == -1) { - printf( "\nlocal kernel failed; trying remote boot\n" ); - if (get_remote_kernel( kname_set ? kernel_name : NULL ) < 0) { - fprintf (stderr, "Unable to remote boot and " - "to open kernel file %s\n", kernel_name); - boot_exit (EXIT_FAILURE); - } - } +#endif + for( i = 0; i < n_knames; ++i ) { + if ((kfd = open( kname_list[i], O_RDONLY )) != -1) + goto kernel_open; } -#else - /* open kernel executable and read exec header */ - if ((kfd = open (kernel_name, O_RDONLY)) == -1) { - fprintf (stderr, "Unable to open kernel file %s\n", kernel_name); - boot_exit (EXIT_FAILURE); +#ifdef USE_BOOTP + if (!prefer_bootp) { + printf( "\nlocal kernel failed; trying remote boot\n" ); + for( i = 0; i < n_knames; ++i ) { + if ((err = get_remote_kernel( kname_list[i] )) >= 0) + goto kernel_open; + if (err < -1) /* fatal error; retries don't help... */ + break; + } } #endif + fprintf( stderr, "Unable to open any kernel file\n(Tried " ); + for( i = 0; i < n_knames; ++i ) { + fprintf( stderr, "%s%s", kname_list[i], + i < n_knames-2 ? ", " : + i == n_knames-2 ? ", and " : + ")\n" ); + } + boot_exit( EXIT_FAILURE ); + + kernel_open: if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) { @@ -746,6 +819,19 @@ int main(int argc, char *argv[]) boot_exit (EXIT_FAILURE); } +#ifdef ZKERNEL + if (((unsigned char *)&kexec)[0] == 037 && + (((unsigned char *)&kexec)[1] == 0213 || + ((unsigned char *)&kexec)[1] == 0236)) { + /* That's a compressed kernel */ + printf( "Kernel is compressed\n" ); + if (load_zkernel( kfd )) { + printf( "Decompression error -- aborting\n" ); + boot_exit( EXIT_FAILURE ); + } + } +#endif + switch (N_MAGIC(kexec)) { case ZMAGIC: text_offset = N_TXTOFF(kexec); @@ -806,19 +892,11 @@ int main(int argc, char *argv[]) ramdisk_name); boot_exit(EXIT_FAILURE); } - bi.ramdisk_size = (lseek(rfd, 0, SEEK_END) + 1023) / 1024; + bi.ramdisk.size = lseek(rfd, 0, SEEK_END); } else - bi.ramdisk_size = 0; - - rd_size = bi.ramdisk_size << 10; - if (mem_size - rd_size < MB && bi.num_memory > 1) - /* If running low on ST ram load ramdisk into alternate ram. */ - bi.ramdisk_addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size; - else - /* Else hopefully there is enough ST ram. */ - bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size; - + bi.ramdisk.size = 0; + /* calculate the total required amount of memory */ if (elf_kernel) { @@ -844,7 +922,24 @@ int main(int argc, char *argv[]) } else kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss; - memreq = kernel_size + sizeof (bi); + + rd_size = bi.ramdisk.size; + if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1) + /* If running low on ST ram load ramdisk into alternate ram. */ + bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size; + else + /* Else hopefully there is enough ST ram. */ + bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size; + + /* create the bootinfo structure */ + if (!create_bootinfo()) + boot_exit (EXIT_FAILURE); + + memreq = kernel_size + bi_size; +#ifdef BOOTINFO_COMPAT_1_0 + if (sizeof(compat_bootinfo) > bi_size) + memreq = kernel_size+sizeof(compat_bootinfo); +#endif /* BOOTINFO_COMPAT_1_0 */ /* align load address of ramdisk image, read() is sloooow on odd addr. */ memreq = ((memreq + 3) & ~3) + rd_size; @@ -905,14 +1000,29 @@ int main(int argc, char *argv[]) kclose (kfd); /* Check kernel's bootinfo version */ - if (!check_bootinfo_version(memptr)) { - Mfree ((void *)memptr); - boot_exit (EXIT_FAILURE); + switch (check_bootinfo_version(memptr)) { + case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION): + bi_ptr = &bi_union.record; + break; + +#ifdef BOOTINFO_COMPAT_1_0 + case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION): + if (!create_compat_bootinfo()) { + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); + } + bi_ptr = &compat_bootinfo; + bi_size = sizeof(compat_bootinfo); + break; +#endif /* BOOTINFO_COMPAT_1_0 */ + + default: + Mfree ((void *)memptr); + boot_exit (EXIT_FAILURE); } - + /* copy the boot_info struct to the end of the kernel image */ - memcpy ((void *)(memptr + kernel_size), - &bi, sizeof(bi)); + memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size); /* read the ramdisk image */ if (rfd != -1) @@ -936,10 +1046,10 @@ int main(int argc, char *argv[]) /* for those who want to debug */ if (debugflag) { - if (bi.ramdisk_size) - printf ("RAM disk at %#lx, size is %ldK\n", + if (bi.ramdisk.size) + printf ("RAM disk at %#lx, size is %ld\n", (u_long)(memptr + memreq - rd_size), - bi.ramdisk_size); + bi.ramdisk.size); if (elf_kernel) { @@ -963,7 +1073,7 @@ int main(int argc, char *argv[]) start_mem + kernel_size); printf ("\nKernel entry is %#lx\n", elf_kernel ? kexec_elf.e_entry : kexec.a_entry); - printf ("ramdisk dest top is %#lx\n", bi.ramdisk_addr + rd_size); + printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size); printf ("ramdisk lower limit is %#lx\n", (u_long)(memptr + memreq - rd_size)); printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq)); @@ -1013,9 +1123,8 @@ int main(int argc, char *argv[]) */ jump_to_mover((char *) start_mem, memptr, - (char *) bi.ramdisk_addr + rd_size, memptr + memreq, - kernel_size + sizeof (bi), - rd_size, + (char *) bi.ramdisk.addr + rd_size, memptr + memreq, + kernel_size + bi_size, rd_size, (void *) 0x400); for (;;); @@ -1081,3 +1190,413 @@ static void get_default_args( int *argc, char ***argv ) nargv[*argc] = 0; } + + /* + * Create the Bootinfo Structure + */ + +static int create_bootinfo(void) +{ + int i; + struct bi_record *record; + + /* Initialization */ + bi_size = 0; + + /* Generic tags */ + if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype)) + return(0); + if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype)) + return(0); + if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype)) + return(0); + if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype)) + return(0); + for (i = 0; i < bi.num_memory; i++) + if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i])) + return(0); + if (bi.ramdisk.size) + if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk)) + return(0); + if (!add_bi_string(BI_COMMAND_LINE, bi.command_line)) + return(0); + + /* Atari tags */ + if (!add_bi_record(BI_ATARI_MCH_COOKIE, sizeof(bi.mch_cookie), + &bi.mch_cookie)) + return(0); + + /* Trailer */ + record = (struct bi_record *)((u_long)&bi_union.record+bi_size); + record->tag = BI_LAST; + bi_size += sizeof(bi_union.record.tag); + + return(1); +} + + + /* + * Add a Record to the Bootinfo Structure + */ + +static int add_bi_record(u_short tag, u_short size, const void *data) +{ + struct bi_record *record; + u_short size2; + + size2 = (sizeof(struct bi_record)+size+3)&-4; + if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) { + fprintf (stderr, "Can't add bootinfo record. Ask a wizard to enlarge me.\n"); + return(0); + } + record = (struct bi_record *)((u_long)&bi_union.record+bi_size); + record->tag = tag; + record->size = size2; + memcpy(record->data, data, size); + bi_size += size2; + return(1); +} + + + /* + * Add a String Record to the Bootinfo Structure + */ + +static int add_bi_string(u_short tag, const u_char *s) +{ + return add_bi_record(tag, strlen(s)+1, (void *)s); +} + + +#ifdef BOOTINFO_COMPAT_1_0 + + /* + * Create the Bootinfo structure for backwards compatibility mode + */ + +static int create_compat_bootinfo(void) +{ + u_int i; + + compat_bootinfo.machtype = bi.machtype; + if (bi.cputype & CPU_68020) + compat_bootinfo.cputype = COMPAT_CPU_68020; + else if (bi.cputype & CPU_68030) + compat_bootinfo.cputype = COMPAT_CPU_68030; + else if (bi.cputype & CPU_68040) + compat_bootinfo.cputype = COMPAT_CPU_68040; + else if (bi.cputype & CPU_68060) + compat_bootinfo.cputype = COMPAT_CPU_68060; + else { + printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype); + return(0); + } + if (bi.fputype & FPU_68881) + compat_bootinfo.cputype |= COMPAT_FPU_68881; + else if (bi.fputype & FPU_68882) + compat_bootinfo.cputype |= COMPAT_FPU_68882; + else if (bi.fputype & FPU_68040) + compat_bootinfo.cputype |= COMPAT_FPU_68040; + else if (bi.fputype & FPU_68060) + compat_bootinfo.cputype |= COMPAT_FPU_68060; + else { + printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype); + return(0); + } + compat_bootinfo.num_memory = bi.num_memory; + if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) { + printf("Warning: using only %d blocks of memory\n", + COMPAT_NUM_MEMINFO); + compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO; + } + for (i = 0; i < compat_bootinfo.num_memory; i++) { + compat_bootinfo.memory[i].addr = bi.memory[i].addr; + compat_bootinfo.memory[i].size = bi.memory[i].size; + } + if (bi.ramdisk.size) { + compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024; + compat_bootinfo.ramdisk_addr = bi.ramdisk.addr; + } else { + compat_bootinfo.ramdisk_size = 0; + compat_bootinfo.ramdisk_addr = 0; + } + strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE); + compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0'; + + compat_bootinfo.bi_atari.hw_present = 0; + compat_bootinfo.bi_atari.mch_cookie = bi.mch_cookie; + return(1); +} +#endif /* BOOTINFO_COMPAT_1_0 */ + + +#ifdef ZKERNEL + +#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */ +#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS) +#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1) +#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE) + +/* variables for storing the uncompressed data */ +static char *ZFile[ZFILE_N_CHUNKS]; +static int ZFileSize = 0; +static int ZFpos = 0; +static int Zwpos = 0; + +static int Zinfd = 0; /* fd of compressed file */ + +/* + * gzip declarations + */ + +#define OF(args) args + +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define INBUFSIZ 4096 +#define WSIZE 0x8000 /* window size--must be a power of two, and */ + /* at least 32K for zip's deflate method */ + +static uch *inbuf; +static uch *window; + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ +static int exit_code = 0; +static long bytes_out = 0; + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions (stubbed out) */ +#define Assert(cond,msg) +#define Trace(x) +#define Tracev(x) +#define Tracevv(x) +#define Tracec(c,x) +#define Tracecv(c,x) + +#define STATIC static + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +#include "../../../../lib/inflate.c" + +static void gzip_mark( void **ptr ) +{ +} + +static void gzip_release( void **ptr ) +{ +} + + +/* + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf( void ) +{ + if (exit_code) + return -1; + + insize = ll_read( Zinfd, inbuf, INBUFSIZ ); + if (insize <= 0) + return -1; + + inptr = 1; + return( inbuf[0] ); +} + +/* + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window( void ) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + int chunk = Zwpos >> ZFILE_CHUNK_BITS; + + if (chunk >= ZFILE_N_CHUNKS) { + fprintf( stderr, "compressed image too large! Aborting.\n" ); + boot_exit( EXIT_FAILURE ); + } + if (!ZFile[chunk]) { + if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) { + fprintf( stderr, "Out of memory for decompresing kernel image\n" ); + boot_exit( EXIT_FAILURE ); + } + } + memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt ); + Zwpos += outcnt; + +#define DISPLAY_BITS 13 + if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) { + printf( "." ); + fflush( stdout ); + } + + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void error( char *x ) +{ + fprintf( stderr, "\n%s", x); + exit_code = 1; +} + +static int load_zkernel( int fd ) +{ + int i, err; + + for( i = 0; i < ZFILE_N_CHUNKS; ++i ) + ZFile[i] = NULL; + Zinfd = fd; + ll_lseek( fd, 0, SEEK_SET ); + + if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) { + fprintf( stderr, "Couldn't allocate gunzip buffer\n" ); + boot_exit( EXIT_FAILURE ); + } + if (!(window = (uch *)Malloc( WSIZE ))) { + fprintf( stderr, "Couldn't allocate gunzip window\n" ); + boot_exit( EXIT_FAILURE ); + } + + printf( "Uncompressing kernel image " ); + fflush( stdout ); + makecrc(); + if (!(err = gunzip())) + printf( "done\n" ); + ZFileSize = Zwpos; + ll_close( Zinfd ); /* input file not needed anymore */ + + Mfree( inbuf ); + Mfree( window ); + return( err ); +} + +/* Note about the read/lseek wrapper and its memory management: It assumes + * that all seeks are only forward, and thus data already read or skipped can + * be freed. This is true for current organization of bootstrap and kernels. + * Little exception: The struct kexec at the start of the file. After reading + * it, there may be a seek back to the end of the file. But this currently + * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman) + */ + +static int kread( int fd, void *buf, unsigned cnt ) +{ + unsigned done = 0; + + if (!ZFileSize) + return( ll_read( fd, buf, cnt ) ); + + if (ZFpos + cnt > ZFileSize) + cnt = ZFileSize - ZFpos; + + while( cnt > 0 ) { + unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS; + unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS; + unsigned n = cnt; + + if (ZFpos + n > endchunk) + n = endchunk - ZFpos; + memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n ); + cnt -= n; + buf += n; + done += n; + ZFpos += n; + + if (ZFpos == endchunk) { + Mfree( ZFile[chunk] ); + ZFile[chunk] = NULL; + } + } + + return( done ); +} + + +static int klseek( int fd, int where, int whence ) +{ + unsigned oldpos, oldchunk, newchunk; + + if (!ZFileSize) + return( ll_lseek( fd, where, whence ) ); + + oldpos = ZFpos; + switch( whence ) { + case SEEK_SET: + ZFpos = where; + break; + case SEEK_CUR: + ZFpos += where; + break; + case SEEK_END: + ZFpos = ZFileSize + where; + break; + default: + return( -1 ); + } + if (ZFpos < 0) { + ZFpos = 0; + return( -1 ); + } + else if (ZFpos > ZFileSize) { + ZFpos = ZFileSize; + return( -1 ); + } + + /* free memory of skipped-over data */ + oldchunk = oldpos >> ZFILE_CHUNK_BITS; + newchunk = ZFpos >> ZFILE_CHUNK_BITS; + while( oldchunk < newchunk ) { + if (ZFile[oldchunk]) { + Mfree( ZFile[oldchunk] ); + ZFile[oldchunk] = NULL; + } + ++oldchunk; + } + + return( ZFpos ); +} + + +static void free_zfile( void ) +{ + int i; + + for( i = 0; i < ZFILE_N_CHUNKS; ++i ) + if (ZFile[i]) Mfree( ZFile[i] ); +} + +static int kclose( int fd ) +{ + if (ZFileSize) { + free_zfile(); + return( 0 ); + } + else + return( ll_close( fd ) ); +} + + + +#endif /* ZKERNEL */ diff --git a/arch/m68k/boot/atari/bootstrap.h b/arch/m68k/boot/atari/bootstrap.h index 5f8644f44..594916dfe 100644 --- a/arch/m68k/boot/atari/bootstrap.h +++ b/arch/m68k/boot/atari/bootstrap.h @@ -4,7 +4,11 @@ ** Copyright 1993 by Arjan Knor ** ** Modified by Andreas Schwab -** - clear transparent translation registers +** - clear transparent translation registers +** Modified 18-Aug-96 by Geert Uytterhoeven +** - Updated for the new boot information structure (untested!) +** Modified 1996-11-12 by Andreas Schwab +** - Fixed and tested previous change ** ** 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 @@ -15,6 +19,26 @@ #ifndef BOOTSTRAP_H #define BOOTSTRAP_H + /* + * Atari Bootinfo Definitions + * + * All limits herein are `soft' limits, i.e. they don't put constraints + * on the actual parameters in the kernel. + */ + +struct atari_bootinfo { + unsigned long machtype; /* machine type */ + unsigned long cputype; /* system CPU */ + unsigned long fputype; /* system FPU */ + unsigned long mmutype; /* system MMU */ + int num_memory; /* # of memory blocks found */ + struct mem_info memory[NUM_MEMINFO]; /* memory description */ + struct mem_info ramdisk; /* ramdisk description */ + char command_line[CL_SIZE]; /* kernel command line parameters */ + unsigned long mch_cookie; /* _MCH cookie from TOS */ +}; + + /* _MCH cookie values */ #define MACH_ST 0 #define MACH_STE 1 @@ -74,7 +98,7 @@ static __inline void disable_interrupts (void) __asm__ volatile ("orw #0x700,sr":); } -extern struct bootinfo bi; +extern struct atari_bootinfo bi; static __inline void disable_cache (void) { __asm__ volatile ("movec %0,cacr" :: "d" (0)); diff --git a/arch/m68k/config.in b/arch/m68k/config.in index a42e6557b..df6a45a9d 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -49,15 +49,18 @@ comment 'General setup' bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC +bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga AutoConfig Identification' CONFIG_ZORRO bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS bool 'Amiga ECS chipset support' CONFIG_AMIFB_ECS bool 'Amiga AGA chipset support' CONFIG_AMIFB_AGA bool 'Amiga Cybervision support' CONFIG_FB_CYBER + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 + fi # bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP # if [ "$CONFIG_AMIGA_GSP" = "y" ]; then # bool 'DMI Resolver support' CONFIG_GSP_RESOLVER @@ -79,17 +82,18 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE + dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE fi if [ "$CONFIG_AMIGA" = "y" ]; then -tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM + tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM fi if [ "$CONFIG_ATARI" = "y" ]; then -tristate 'Atari ACSI support' CONFIG_ATARI_ACSI -if [ "$CONFIG_ATARI_ACSI" != "n" ]; then -comment 'Some devices (e.g. CD jukebox) support multiple LUNs' -bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN -dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI -fi + tristate 'Atari ACSI support' CONFIG_ATARI_ACSI + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + comment 'Some devices (e.g. CD jukebox) support multiple LUNs' + bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN + dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI + fi fi comment 'Additional Block Devices' @@ -122,6 +126,9 @@ comment 'SCSI support type (disk, tape, CD-ROM)' dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI +if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then + bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR +fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' @@ -134,17 +141,23 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' if [ "$CONFIG_AMIGA" = "y" ]; then -tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI -tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI -tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI -bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI -bool 'CyberStorm SCSI Mk II support' CONFIG_CYBERSTORMII_SCSI -bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI -bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI + tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI + tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI + tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI + bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI + bool 'CyberStorm SCSI Mk II support' CONFIG_CYBERSTORMII_SCSI + bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI + bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI + bool 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4000T SCSI support' CONFIG_A4000T_SCSI + bool 'A4091 SCSI support' CONFIG_A4091_SCSI + bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI + fi fi if [ "$CONFIG_ATARI" = "y" ]; then -dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI -bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY + dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI + bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI endmenu @@ -196,6 +209,10 @@ source fs/Config.in mainmenu_option next_comment comment 'Character devices' +define_bool CONFIG_VT y +define_bool CONFIG_VT_CONSOLE y +define_bool CONFIG_FB_CONSOLE y + tristate 'Parallel printer support' CONFIG_PRINTER if [ "$CONFIG_AMIGA" = "y" ]; then dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER @@ -207,13 +224,26 @@ fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER tristate 'Atari SCC serial support' CONFIG_ATARI_SCC + if [ "$CONFIG_ATARI_SCC" = "y" -o "$CONFIG_ATARI_SCC" = "m" ]; then + bool 'Atari SCC serial DMA support' CONFIG_ATARI_SCC_DMA + fi tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K + fi fi if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL - bool 'GVP IO-Extender support' CONFIG_GVPIOEXT + tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT + dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT + dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY fi +if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ + "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ + "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then + bool 'Serial console support' CONFIG_SERIAL_CONSOLE +fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then @@ -221,6 +251,9 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG fi bool 'Support for user misc device modules' CONFIG_UMISC +if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then + define_bool CONFIG_ABSTRACT_CONSOLE y +fi endmenu mainmenu_option next_comment @@ -240,4 +273,5 @@ bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Remote debugging support' CONFIG_KGDB endmenu diff --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c index ecb926f88..376249c90 100644 --- a/arch/m68k/console/fbcon.c +++ b/arch/m68k/console/fbcon.c @@ -61,7 +61,7 @@ #endif #ifdef CONFIG_FB_CYBER #include "../amiga/s3blit.h" -#endif /* CONFIG_FB_CYBER */ +#endif #include <linux/fb.h> #include <asm/font.h> #include <asm/machdep.h> @@ -70,7 +70,7 @@ #include <asm/uaccess.h> #include "../../../drivers/char/vt_kern.h" /* vt_cons and vc_resize_con() */ - +#include "../../../drivers/char/console_struct.h" /* Import console_blanked from console.c */ @@ -95,6 +95,7 @@ extern int console_blanked; #undef CONFIG_FBCON_24PACKED #undef CONFIG_FBCON_32PACKED #undef CONFIG_FBCON_CYBER +#undef CONFIG_FBCON_RETINAZ3 /* Monochrome is default */ @@ -117,7 +118,18 @@ extern int console_blanked; #ifndef CONFIG_FBCON_CYBER #define CONFIG_FBCON_CYBER #endif -#endif /* CONFIG_FB_CYBER */ +#endif + +/* RetinaZ3 Graphics Board */ + +#ifdef CONFIG_FB_RETINAZ3 +#ifndef CONFIG_FBCON_RETINAZ3 +#define CONFIG_FBCON_RETINAZ3 +#endif +#ifndef CONFIG_FBCON_8PACKED +#define CONFIG_FBCON_8PACKED +#endif +#endif #endif /* CONFIG_AMIGA */ @@ -151,17 +163,17 @@ extern int console_blanked; #undef CONFIG_FBCON_IPLAN2 #endif -#if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_8PACKED) || \ - defined(CONFIG_FBCON_16PACKED) || defined(CONFIG_FBCON_24PACKED) || \ - defined(CONFIG_FBCON_32PACKED) +#if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_RETINAZ3) || \ + defined(CONFIG_FBCON_8PACKED) || defined(CONFIG_FBCON_16PACKED) || \ + defined(CONFIG_FBCON_24PACKED) || defined(CONFIG_FBCON_32PACKED) #define CONFIG_FBCON_PACKED #else #undef CONFIG_FBCON_PACKED #endif -struct fb_info *fb_info; -struct display *disp; +static struct fb_info *fb_info; +static struct display *disp; /* ++Geert: Sorry, no hardware cursor support at the moment; @@ -224,21 +236,24 @@ static __inline__ int CURSOR_UNDRAWN(void) * Interface used by the world */ -static u_long fbcon_startup(u_long kmem_start, char **display_desc); +static u_long fbcon_startup(u_long kmem_start, const char **display_desc); static void fbcon_init(struct vc_data *conp); static int fbcon_deinit(struct vc_data *conp); static int fbcon_changevar(int con); static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, int width); -static int fbcon_putc(struct vc_data *conp, int c, int y, int x); -static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, - int x); +static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx); +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy, + int xx); static int fbcon_cursor(struct vc_data *conp, int mode); static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count); static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, int height, int width); static int fbcon_switch(struct vc_data *conp); static int fbcon_blank(int blank); +static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data); +static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data); +static int fbcon_set_palette(struct vc_data *conp, unsigned char *table); /* @@ -264,14 +279,22 @@ static __inline__ void memset_even_8p(void *d, size_t count, u_long val1, u_long val2, u_long val3, u_long val4); static __inline__ void memmove_8p_col(void *d, void *s, int h, int bpr); static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2); -static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr); +static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, + int bpr); static __inline__ void memset_even_2p(void *d, size_t count, u_long val); static __inline__ void memmove_2p_col(void *d, void *s, int h, int bpr); static __inline__ u_short expand2w(u_char c); static __inline__ u_long expand2l(u_char c); static __inline__ u_short dup2w(u_char c); -static __inline__ int real_y(struct display *p, int y); +static __inline__ int real_y(struct display *p, int yy); static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp); +static __inline__ void updatescrollmode(struct display *p); +static __inline__ void ywrap_up(int unit, struct display *p, int count); +static __inline__ void ywrap_down(int unit, struct display *p, int count); +static __inline__ void ypan_up(int unit, struct vc_data *conp, + struct display *p, int count); +static __inline__ void ypan_down(int unit, struct vc_data *conp, + struct display *p, int count); static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break); @@ -285,11 +308,11 @@ static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_mono(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x); -static void rev_char_mono(struct display *p, int x, int y); + int count, int yy, int xx); +static void rev_char_mono(struct display *p, int xx, int yy); #endif /* CONFIG_FBCON_MONO */ @@ -302,11 +325,11 @@ static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x); -static void rev_char_ilbm(struct display *p, int x, int y); + int count, int yy, int xx); +static void rev_char_ilbm(struct display *p, int xx, int yy); #endif /* CONFIG_FBCON_ILBM */ @@ -319,11 +342,11 @@ static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x); -static void rev_char_plan(struct display *p, int x, int y); + int count, int yy, int xx); +static void rev_char_plan(struct display *p, int xx, int yy); #endif /* CONFIG_FBCON_PLANES */ @@ -336,11 +359,11 @@ static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_2_plane(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_2_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x); -static void rev_char_2_plane(struct display *display, int x, int y); + const char *s, int count, int yy, int xx); +static void rev_char_2_plane(struct display *display, int xx, int yy); #endif /* CONFIG_FBCON_2PLANE */ @@ -353,11 +376,11 @@ static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_4_plane(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_4_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x); -static void rev_char_4_plane(struct display *p, int x, int y); + const char *s, int count, int yy, int xx); +static void rev_char_4_plane(struct display *p, int xx, int yy); #endif /* CONFIG_FBCON_4PLANE */ @@ -370,11 +393,11 @@ static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_8_plane(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_8_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x); -static void rev_char_8_plane(struct display *display, int x, int y); + const char *s, int count, int yy, int xx); +static void rev_char_8_plane(struct display *display, int xx, int yy); #endif /* CONFIG_FBCON_8PLANE */ @@ -387,11 +410,11 @@ static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_8_packed(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_8_packed(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x); -static void rev_char_8_packed(struct display *p, int x, int y); + const char *s, int count, int yy, int xx); +static void rev_char_8_packed(struct display *p, int xx, int yy); #endif /* CONFIG_FBCON_8PACKED */ @@ -405,10 +428,10 @@ static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx, static void clear_16_packed(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); static void putc_16_packed(struct vc_data *conp, struct display *p, int c, - int y, int x); + int yy, int xx); static void putcs_16_packed(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x); -static void rev_char_16_packed(struct display *p, int x, int y); + const char *s, int count, int yy, int xx); +static void rev_char_16_packed(struct display *p, int xx, int yy); #endif */ CONFIG_FBCON_8PACKED */ @@ -421,22 +444,38 @@ static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, int height, int width); static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); -static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y, - int x); +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy, + int xx); static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x); -static void rev_char_cyber(struct display *p, int x, int y); + int count, int yy, int xx); +static void rev_char_cyber(struct display *p, int xx, int yy); extern void Cyber_WaitQueue(u_short fifo); extern void Cyber_WaitBlit(void); extern void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, u_short width, u_short height, u_short mode); -extern void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height, +extern void Cyber_RectFill(u_short xx, u_short yy, u_short width, u_short height, u_short mode, u_short color); -extern void Cyber_MoveCursor(u_short x, u_short y); +extern void Cyber_MoveCursor(u_short xx, u_short yy); #endif /* CONFIG_FBCON_CYBER */ +#ifdef CONFIG_FBCON_RETINAZ3 +static void clear_retz3(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width); +static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +extern void retz3_bitblt(struct fb_var_screeninfo *scr, + unsigned short srcx, unsigned short srcy, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); +static void putc_retz3(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void putcs_retz3(struct vc_data *conp, struct display *p, const + char *s, int count, int yy, int xx); +static void rev_char_retz3(struct display *p, int xx, int yy); +#endif /* * `switch' for the Low Level Operations @@ -447,70 +486,77 @@ struct display_switch { int width); void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width); - void (*putc)(struct vc_data *conp, struct display *p, int c, int y, int x); + void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, int xx); void (*putcs)(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x); - void (*rev_char)(struct display *p, int x, int y); + int count, int yy, int xx); + void (*rev_char)(struct display *p, int xx, int yy); }; #ifdef CONFIG_FBCON_MONO -struct display_switch dispsw_mono = { +static struct display_switch dispsw_mono = { bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono }; #endif /* CONFIG_FBCON_MONO */ #ifdef CONFIG_FBCON_ILBM -struct display_switch dispsw_ilbm = { +static struct display_switch dispsw_ilbm = { bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm }; #endif /* CONFIG_FBCON_ILBM */ #ifdef CONFIG_FBCON_PLANES -struct display_switch dispsw_plan = { +static struct display_switch dispsw_plan = { bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan }; #endif /* CONFIG_FBCON_PLANES */ #ifdef CONFIG_FBCON_2PLANE -struct display_switch dispsw_2_plane = { +static struct display_switch dispsw_2_plane = { bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane }; #endif /* CONFIG_FBCON_2PLANE */ #ifdef CONFIG_FBCON_4PLANE -struct display_switch dispsw_4_plane = { +static struct display_switch dispsw_4_plane = { bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane }; #endif /* CONFIG_FBCON_4PLANE */ #ifdef CONFIG_FBCON_8PLANE -struct display_switch dispsw_8_plane = { +static struct display_switch dispsw_8_plane = { bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane }; #endif /* CONFIG_FBCON_8PLANE */ #ifdef CONFIG_FBCON_8PACKED -struct display_switch dispsw_8_packed = { +static struct display_switch dispsw_8_packed = { bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed }; #endif /* CONFIG_FBCON_8PACKED */ #ifdef CONFIG_FBCON_16PACKED -struct display_switch dispsw_16_packed = { +static struct display_switch dispsw_16_packed = { bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed, rev_char_16_packed }; #endif /* CONFIG_FBCON_16PACKED */ #ifdef CONFIG_FBCON_CYBER -struct display_switch dispsw_cyber = { +static struct display_switch dispsw_cyber = { bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber }; #endif /* CONFIG_FBCON_CYBER */ +#ifdef CONFIG_FBCON_RETINAZ3 +static struct display_switch dispsw_retz3 = { + bmove_retz3, clear_retz3, putc_retz3, + putcs_retz3, rev_char_retz3 +}; +#endif + -static u_long fbcon_startup(u_long kmem_start, char **display_desc) +static u_long fbcon_startup(u_long kmem_start, const char **display_desc) { int irqres = 0; @@ -566,6 +612,19 @@ static int fbcon_changevar(int con) } +static __inline__ void updatescrollmode(struct display *p) +{ + if (divides(p->ywrapstep, p->fontheight) && + divides(p->fontheight, p->var.yres_virtual)) + p->scrollmode = SCROLL_YWRAP; + else if (divides(p->ypanstep, p->fontheight) && + p->var.yres_virtual >= p->var.yres+p->fontheight) + p->scrollmode = SCROLL_YPAN; + else + p->scrollmode = SCROLL_YMOVE; +} + + static void fbcon_setup(int con, int setcol, int init) { struct display *p = &disp[con]; @@ -579,16 +638,12 @@ static void fbcon_setup(int con, int setcol, int init) &p->fontdata) || p->fontwidth != 8) getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth, &p->fontheight, &p->fontdata); - if (p->fontwidth != 8) - panic("fbcon_setup: No support for fontwidth != 8"); - - if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual)) - p->scrollmode = SCROLL_YWRAP; - else if (divides(p->ypanstep, p->fontheight) && - p->var.yres_virtual >= p->var.yres+p->fontheight) - p->scrollmode = SCROLL_YPAN; - else - p->scrollmode = SCROLL_YMOVE; + if (p->fontwidth != 8) { + /* ++Geert: changed from panic() to `correct and continue' */ + printk("fbcon_setup: No support for fontwidth != 8"); + p->fontwidth = 8; + } + updatescrollmode(p); nr_cols = p->var.xres/p->fontwidth; nr_rows = p->var.yres/p->fontheight; @@ -638,7 +693,8 @@ static void fbcon_setup(int con, int setcol, int init) if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) { if (p->line_length) { p->next_line = p->line_length*p->var.bits_per_pixel; - p->next_plane = p->line_length; + p->next_plane = p->line_length +; } else { p->next_line = p->type_aux; p->next_plane = p->type_aux/p->var.bits_per_pixel; @@ -658,13 +714,18 @@ static void fbcon_setup(int con, int setcol, int init) #endif /* CONFIG_FBCON_PLANES */ #ifdef CONFIG_FBCON_PACKED if (p->type == FB_TYPE_PACKED_PIXELS) { - p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3; + p->next_line = (p->var.xres_virtual*p->var.bits_per_pixel)>>3; p->next_plane = 0; #ifdef CONFIG_FBCON_CYBER if (p->var.accel == FB_ACCEL_CYBERVISION) p->dispsw = &dispsw_cyber; else -#endif /* CONFIG_FBCON_CYBER */ +#endif +#ifdef CONFIG_FBCON_RETINAZ3 + if (p->var.accel == FB_ACCEL_RETINAZ3) + p->dispsw = &dispsw_retz3; + else +#endif #ifdef CONFIG_FBCON_8PACKED if (p->var.bits_per_pixel == 8) p->dispsw = &dispsw_8_packed; @@ -1399,12 +1460,12 @@ static __inline__ u_short dup2w(u_char c) * restriction is simplicity & efficiency at the moment. */ -static __inline__ int real_y(struct display *p, int y) +static __inline__ int real_y(struct display *p, int yy) { int rows = p->vrows; - y += p->yscroll; - return(y < rows ? y : y-rows); + yy += p->yscroll; + return(yy < rows ? yy : yy-rows); } @@ -1436,7 +1497,7 @@ static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, } -static int fbcon_putc(struct vc_data *conp, int c, int y, int x) +static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx) { int unit = conp->vc_num; struct display *p = &disp[unit]; @@ -1444,17 +1505,17 @@ static int fbcon_putc(struct vc_data *conp, int c, int y, int x) if (!p->can_soft_blank && console_blanked) return(0); - if ((p->cursor_x == x) && (p->cursor_y == y)) + if ((p->cursor_x == xx) && (p->cursor_y == yy)) CURSOR_UNDRAWN(); - p->dispsw->putc(conp, p, c, real_y(p, y), x); + p->dispsw->putc(conp, p, c, real_y(p, yy), xx); return(0); } -static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, - int x) +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy, + int xx) { int unit = conp->vc_num; struct display *p = &disp[unit]; @@ -1462,10 +1523,10 @@ static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, if (!p->can_soft_blank && console_blanked) return(0); - if ((p->cursor_y == y) && (x <= p->cursor_x) && (p->cursor_x < x+count)) + if ((p->cursor_y == yy) && (xx <= p->cursor_x) && (p->cursor_x < xx+count)) CURSOR_UNDRAWN(); - p->dispsw->putcs(conp, p, s, count, real_y(p, y), x); + p->dispsw->putcs(conp, p, s, count, real_y(p, yy), xx); return(0); } @@ -1520,6 +1581,62 @@ static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp) } +static __inline__ void ywrap_up(int unit, struct display *p, int count) +{ + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + fb_info->updatevar(unit); +} + + +static __inline__ void ywrap_down(int unit, struct display *p, int count) +{ + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + fb_info->updatevar(unit); +} + + +static __inline__ void ypan_up(int unit, struct vc_data *conp, + struct display *p, int count) +{ + p->yscroll += count; + if (p->yscroll+conp->vc_rows > p->vrows) { + p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count, + conp->vc_cols); + p->yscroll = 0; + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + fb_info->updatevar(unit); +} + + +static __inline__ void ypan_down(int unit, struct vc_data *conp, + struct display *p, int count) +{ + p->yscroll -= count; + if (p->yscroll < 0) { + p->yscroll = p->vrows-conp->vc_rows; + p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, conp->vc_rows-count, + conp->vc_cols); + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + fb_info->updatevar(unit); +} + + static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) { int unit = conp->vc_num; @@ -1536,84 +1653,98 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (dir) { case SM_UP: - if (t == 0 && b == conp->vc_rows && - vt_cons[unit]->vc_mode == KD_TEXT) { - if (count > conp->vc_rows) /* Maximum realistic size */ - count = conp->vc_rows; - switch (p->scrollmode) { - case SCROLL_YWRAP: - p->yscroll += count; - if (p->yscroll >= p->vrows) /* Deal with wrap */ - p->yscroll -= p->vrows; - p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; - p->var.vmode |= FB_VMODE_YWRAP; - fb_info->updatevar(unit); - break; - - case SCROLL_YPAN: - p->yscroll += count; - if (p->yscroll+conp->vc_rows > p->vrows) { - p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count, - conp->vc_cols); - p->yscroll = 0; - } - p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; - p->var.vmode &= ~FB_VMODE_YWRAP; - fb_info->updatevar(unit); - break; - - case SCROLL_YMOVE: - p->dispsw->bmove(p, count, 0, 0, 0, b-count, conp->vc_cols); - break; - } - } else - fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); - fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + if (vt_cons[unit]->vc_mode == KD_TEXT) + switch (p->scrollmode) { + case SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols); + ywrap_up(unit, p, count); + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b, + conp->vc_cols); + } else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SCROLL_YPAN: + if (b-t-count > 3*conp->vc_rows>>2) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols); + ypan_up(unit, conp, p, count); + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b, + conp->vc_cols); + } else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, b-count, 0, count, conp->vc_cols); + break; + } + else { + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + } break; case SM_DOWN: - if (t == 0 && b == conp->vc_rows && - vt_cons[unit]->vc_mode == KD_TEXT) { - if (count > conp->vc_rows) /* Maximum realistic size */ - count = conp->vc_rows; - switch (p->scrollmode) { - case SCROLL_YWRAP: - p->yscroll -= count; - if (p->yscroll < 0) /* Deal with wrap */ - p->yscroll += p->vrows; - p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; - p->var.vmode |= FB_VMODE_YWRAP; - fb_info->updatevar(unit); - break; - - case SCROLL_YPAN: - p->yscroll -= count; - if (p->yscroll < 0) { - p->yscroll = p->vrows-conp->vc_rows; - p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count, - conp->vc_cols); - } - p->var.xoffset = 0; - p->var.yoffset = p->yscroll*p->fontheight; - p->var.vmode &= ~FB_VMODE_YWRAP; - fb_info->updatevar(unit); - break; - - case SCROLL_YMOVE: - p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols); - break; - } - } else - fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); - - /* Fixed bmove() should end Arno's frustration with copying? - * Confucius says: - * Man who copies in wrong direction, end up with trashed data - */ - fbcon_clear(conp, t, 0, count, conp->vc_cols); + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + if (vt_cons[unit]->vc_mode == KD_TEXT) + switch (p->scrollmode) { + case SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b, + conp->vc_cols); + ywrap_down(unit, p, count); + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols); + } else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SCROLL_YPAN: + if (b-t-count > 3*conp->vc_rows>>2) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b, + conp->vc_cols); + ypan_down(unit, conp, p, count); + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols); + } else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols); + break; + } + else { + /* + * Fixed bmove() should end Arno's frustration with copying? + * Confucius says: + * Man who copies in wrong direction, end up with trashed data + */ + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + } break; case SM_LEFT: @@ -1832,14 +1963,7 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data) /* Adjust the virtual screen-size to fontheight*rows */ p->var.yres_virtual = (p->var.yres/h)*h; p->vrows = p->var.yres_virtual/h; - if (divides(p->ywrapstep, p->fontheight)) - p->scrollmode = SCROLL_YWRAP; - else if (divides(p->ypanstep, p->fontheight) && - p->var.yres_virtual >= p->var.yres+p->fontheight) - p->scrollmode = SCROLL_YPAN; - else - p->scrollmode = SCROLL_YMOVE; - + updatescrollmode(p); vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); } else if (unit == fg_console) @@ -1854,6 +1978,38 @@ static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data) return( 0 ); } +static unsigned short palette_red[16]; +static unsigned short palette_green[16]; +static unsigned short palette_blue[16]; + +static struct fb_cmap palette_cmap = { + 0, 16, palette_red, palette_green, palette_blue, NULL +}; + +static int fbcon_set_palette(struct vc_data *conp, unsigned char *table) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + int i, j, k; + u_char val; + + if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked)) + return(-EINVAL); + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = conp->vc_palette[j++]; + palette_red[k] = (val<<8)|val; + val = conp->vc_palette[j++]; + palette_green[k] = (val<<8)|val; + val = conp->vc_palette[j++]; + palette_blue[k] = (val<<8)|val; + } + palette_cmap.len = 1<<p->var.bits_per_pixel; + if (palette_cmap.len > 16) + palette_cmap.len = 16; + return(fb_info->setcmap(&palette_cmap, unit)); +} + /* ====================================================================== */ @@ -1882,8 +2038,8 @@ static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx, u_char *src, *dest; u_int rows; - if (sx == 0 && sy == 0 && width == p->next_line) { - src = p->screen_base; + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*p->fontheight*width; dest = p->screen_base+dy*p->fontheight*width; mymemmove(dest, src, height*p->fontheight*width); } else if (dy <= sy) { @@ -1928,28 +2084,28 @@ static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx, } -static void putc_mono(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy, + int xx) { u_char *dest, *cdat; - u_int rows, bold, reverse, underline; + u_int rows, bold, revs, underl; u_char d; c &= 0xff; - dest = p->screen_base+y*p->fontheight*p->next_line+x; + dest = p->screen_base + yy*p->fontheight*p->next_line + xx; cdat = p->fontdata+c*p->fontheight; bold = attr_bold(p,conp); - reverse = attr_reverse(p,conp); - underline = attr_underline(p,conp); + revs = attr_reverse(p,conp); + underl = attr_underline(p,conp); for (rows = p->fontheight; rows--; dest += p->next_line) { d = *cdat++; - if (underline && !rows) + if (underl && !rows) d = 0xff; else if (bold) d |= d>>1; - if (reverse) + if (revs) d = ~d; *dest = d; } @@ -1957,16 +2113,16 @@ static void putc_mono(struct vc_data *conp, struct display *p, int c, int y, static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x) + int count, int yy, int xx) { u_char *dest, *dest0, *cdat; - u_int rows, bold, reverse, underline; + u_int rows, bold, revs, underl; u_char c, d; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; bold = attr_bold(p,conp); - reverse = attr_reverse(p,conp); - underline = attr_underline(p,conp); + revs = attr_reverse(p,conp); + underl = attr_underline(p,conp); while (count--) { c = *s++; @@ -1974,11 +2130,11 @@ static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, cdat = p->fontdata+c*p->fontheight; for (rows = p->fontheight; rows--; dest += p->next_line) { d = *cdat++; - if (underline && !rows) + if (underl && !rows) d = 0xff; else if (bold) d |= d>>1; - if (reverse) + if (revs) d = ~d; *dest = d; } @@ -1986,12 +2142,12 @@ static void putcs_mono(struct vc_data *conp, struct display *p, const char *s, } -static void rev_char_mono(struct display *p, int x, int y) +static void rev_char_mono(struct display *p, int xx, int yy) { u_char *dest; u_int rows; - dest = p->screen_base+y*p->fontheight*p->next_line+x; + dest = p->screen_base + yy*p->fontheight*p->next_line + xx; for (rows = p->fontheight; rows--; dest += p->next_line) *dest = ~*dest; } @@ -2017,8 +2173,9 @@ static void rev_char_mono(struct display *p, int x, int y) static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, int height, int width) { - if (sx == 0 && sy == 0 && width == p->next_plane) - mymemmove(p->screen_base+dy*p->fontheight*p->next_line, p->screen_base, + if (sx == 0 && dx == 0 && width == p->next_plane) + mymemmove(p->screen_base+dy*p->fontheight*p->next_line, + p->screen_base+sy*p->fontheight*p->next_line, height*p->fontheight*p->next_line); else { u_char *src, *dest; @@ -2068,8 +2225,8 @@ static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, } -static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy, + int xx) { u_char *dest, *cdat; u_int rows, i; @@ -2078,7 +2235,7 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, c &= 0xff; - dest = p->screen_base+y*p->fontheight*p->next_line+x; + dest = p->screen_base + yy*p->fontheight*p->next_line + xx; cdat = p->fontdata+c*p->fontheight; fg0 = attr_fgcol(p,conp); bg0 = attr_bgcol(p,conp); @@ -2114,14 +2271,14 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, * address, to reduce the number of expensive Chip RAM * accesses. * - * Experiments on my A4000/040 revealed that this makes a console switch on a - * 640x400 screen with 256 colors about 3 times faster. + * Experiments on my A4000/040 revealed that this makes a console + * switch on a 640x400 screen with 256 colors about 3 times faster. * * Geert */ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x) + int count, int yy, int xx) { u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4; u_int rows, i; @@ -2129,15 +2286,15 @@ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, u_long d; int fg0, bg0, fg, bg; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; fg0 = attr_fgcol(p,conp); bg0 = attr_bgcol(p,conp); while (count--) - if (x&3 || count < 3) { /* Slow version */ + if (xx & 3 || count < 3) { /* Slow version */ c1 = *s++; dest = dest0++; - x++; + xx++; cdat1 = p->fontdata+c1*p->fontheight; for (rows = p->fontheight; rows--;) { @@ -2191,19 +2348,19 @@ static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, } s += 4; dest0 += 4; - x += 4; + xx += 4; count -= 3; } } -static void rev_char_ilbm(struct display *p, int x, int y) +static void rev_char_ilbm(struct display *p, int xx, int yy) { u_char *dest, *dest0; u_int rows, i; int mask; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; mask = p->fgcol ^ p->bgcol; /* @@ -2239,8 +2396,8 @@ static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx, u_char *src, *dest, *src0, *dest0; u_int i, rows; - if (sx == 0 && sy == 0 && width == p->next_line) { - src = p->screen_base; + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*p->fontheight*width; dest = p->screen_base+dy*p->fontheight*width; for (i = p->var.bits_per_pixel; i--;) { mymemmove(dest, src, height*p->fontheight*width); @@ -2301,8 +2458,8 @@ static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx, } -static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy, + int xx) { u_char *dest, *dest0, *cdat, *cdat0; u_int rows, i; @@ -2311,7 +2468,7 @@ static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, c &= 0xff; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; cdat0 = p->fontdata+c*p->fontheight; fg = attr_fgcol(p,conp); bg = attr_bgcol(p,conp); @@ -2344,7 +2501,7 @@ static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, */ static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x) + int count, int yy, int xx) { u_char *dest, *dest0, *dest1; u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40; @@ -2353,15 +2510,15 @@ static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, u_long d; int fg0, bg0, fg, bg; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; fg0 = attr_fgcol(p,conp); bg0 = attr_bgcol(p,conp); while (count--) - if (x&3 || count < 3) { /* Slow version */ + if (xx & 3 || count < 3) { /* Slow version */ c1 = *s++; dest1 = dest0++; - x++; + xx++; cdat10 = p->fontdata+c1*p->fontheight; fg = fg0; @@ -2424,19 +2581,19 @@ static void putcs_plan(struct vc_data *conp, struct display *p, const char *s, } s += 4; dest0 += 4; - x += 4; + xx += 4; count -= 3; } } -static void rev_char_plan(struct display *p, int x, int y) +static void rev_char_plan(struct display *p, int xx, int yy) { u_char *dest, *dest0; u_int rows, i; int mask; - dest0 = p->screen_base+y*p->fontheight*p->next_line+x; + dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx; mask = p->fgcol ^ p->bgcol; /* @@ -2499,8 +2656,8 @@ static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx, * done with memmove() */ mymemmove(p->screen_base + dy * p->next_line * p->fontheight, - p->screen_base + sy * p->next_line * p->fontheight, - p->next_line * height * p->fontheight); + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); } else { int rows, cols; u_char *src; @@ -2607,8 +2764,8 @@ static void clear_2_plane(struct vc_data *conp, struct display *p, int sy, int bytes = p->next_line; int lines = height * p->fontheight; ulong size; - u_long cval; - u_short pcval; + u_long cval; + u_short pcval; cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp))); @@ -2650,43 +2807,45 @@ static void clear_2_plane(struct vc_data *conp, struct display *p, int sy, } -static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_2_plane(struct vc_data *conp, struct display *p, int + c, int yy, int xx) { - u_char *dest; - u_char *cdat; - int rows; - int bytes = p->next_line; - ulong eorx, fgx, bgx, fdx; + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; c &= 0xff; - dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1); - cdat = p->fontdata + (c * p->fontheight); + dest = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*4 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); eorx = fgx ^ bgx; - for(rows = p->fontheight ; rows-- ; dest += bytes) { + for(rows = p->fontheight ; rows-- ; dest += bytes) { fdx = dup2w(*cdat++); __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */ - : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); } } static void putcs_2_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x) + const char *s, int count, int yy, int xx) { u_char *dest, *dest0; - u_char *cdat, c; - int rows; - int bytes; - ulong eorx, fgx, bgx, fdx; - - bytes = p->next_line; - dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*4 + (x & 1); + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*4 + (xx & 1); fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); eorx = fgx ^ bgx; @@ -2699,32 +2858,33 @@ static void putcs_2_plane(struct vc_data *conp, struct display *p, for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { fdx = dup2w(*cdat++); __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */ - : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); } INC_2P(dest0); } } -static void rev_char_2_plane(struct display *p, int x, int y) +static void rev_char_2_plane(struct display *p, int xx, int yy) { - u_char *dest; - int j; - int bytes; - - dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*4 + (x & 1); - j = p->fontheight; - bytes = p->next_line; - while (j--) - { - /* This should really obey the individual character's - * background and foreground colors instead of simply - * inverting. - */ - dest[0] = ~dest[0]; - dest[2] = ~dest[2]; - dest += bytes; - } + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + yy * p->fontheight * p->next_line + + (xx >> 1)*4 + (xx & 1); + j = p->fontheight; + bytes = p->next_line; + while (j--) + { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest += bytes; + } } #endif /* CONFIG_FBCON_2PLANE */ @@ -2763,8 +2923,8 @@ static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx, * done with memmove() */ mymemmove(p->screen_base + dy * p->next_line * p->fontheight, - p->screen_base + sy * p->next_line * p->fontheight, - p->next_line * height * p->fontheight); + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); } else { int rows, cols; u_char *src; @@ -2871,9 +3031,9 @@ static void clear_4_plane(struct vc_data *conp, struct display *p, int sy, int bytes = p->next_line; int lines = height * p->fontheight; ulong size; - u_long cval1, cval2, pcval; + u_long cval1, cval2, pcval; - expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); + expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); if (sx == 0 && width == bytes/4) { @@ -2913,43 +3073,45 @@ static void clear_4_plane(struct vc_data *conp, struct display *p, int sy, } -static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_4_plane(struct vc_data *conp, struct display *p, int + c, int yy, int xx) { u_char *dest; - u_char *cdat; - int rows; - int bytes = p->next_line; - ulong eorx, fgx, bgx, fdx; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; c &= 0xff; - dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1); - cdat = p->fontdata + (c * p->fontheight); + dest = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*8 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); fgx = expand4l(attr_fgcol(p,conp)); bgx = expand4l(attr_bgcol(p,conp)); eorx = fgx ^ bgx; - for(rows = p->fontheight ; rows-- ; dest += bytes) { + for(rows = p->fontheight ; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */ - : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); } } static void putcs_4_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x) + const char *s, int count, int yy, int xx) { u_char *dest, *dest0; - u_char *cdat, c; - int rows; - int bytes; - ulong eorx, fgx, bgx, fdx; - - bytes = p->next_line; - dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*8 + (x & 1); + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*8 + (xx & 1); fgx = expand4l(attr_fgcol(p,conp)); bgx = expand4l(attr_bgcol(p,conp)); eorx = fgx ^ bgx; @@ -2969,20 +3131,21 @@ static void putcs_4_plane(struct vc_data *conp, struct display *p, for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */ - : "a" (dest), "d" ((fdx & eorx) ^ bgx)); + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); } INC_4P(dest0); } } -static void rev_char_4_plane(struct display *p, int x, int y) +static void rev_char_4_plane(struct display *p, int xx, int yy) { u_char *dest; int j; int bytes; - dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*8 + (x & 1); + dest = p->screen_base + yy * p->fontheight * p->next_line + + (xx >> 1)*8 + (xx & 1); j = p->fontheight; bytes = p->next_line; @@ -3150,15 +3313,16 @@ static void clear_8_plane(struct vc_data *conp, struct display *p, int sy, int bytes = p->next_line; int lines = height * p->fontheight; ulong size; - u_long cval1, cval2, cval3, cval4, pcval1, pcval2; + u_long cval1, cval2, cval3, cval4, pcval1, pcval2; - expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4); + expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4); if (sx == 0 && width == bytes/8) { offset = sy * bytes * p->fontheight; size = lines * bytes; - memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4); + memset_even_8p(p->screen_base+offset, size, cval1, + cval2, cval3, cval4); } else { @@ -3193,48 +3357,50 @@ static void clear_8_plane(struct vc_data *conp, struct display *p, int sy, } -static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy, + int xx) { u_char *dest; - u_char *cdat; - int rows; - int bytes = p->next_line; - ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; c &= 0xff; - dest = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1); - cdat = p->fontdata + (c * p->fontheight); + dest = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*16 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; - for(rows = p->fontheight ; rows-- ; dest += bytes) { + for(rows = p->fontheight ; rows-- ; dest += bytes) { fdx = dup4l(*cdat++); __asm__ __volatile__ ("movepl %1,%0@(0)\n\t" - "movepl %2,%0@(8)" - : /* no outputs */ - : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), - "d" ((fdx & eorx2) ^ bgx2) + "movepl %2,%0@(8)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), + "d" ((fdx & eorx2) ^ bgx2) ); } } static void putcs_8_plane(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x) + const char *s, int count, int yy, int xx) { u_char *dest, *dest0; - u_char *cdat, c; - int rows; - int bytes; - ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; - bytes = p->next_line; - dest0 = p->screen_base + y * p->fontheight * bytes + (x>>1)*16 + (x & 1); + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + + (xx >> 1)*16 + (xx & 1); expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); @@ -3267,30 +3433,31 @@ static void putcs_8_plane(struct vc_data *conp, struct display *p, } -static void rev_char_8_plane(struct display *p, int x, int y) +static void rev_char_8_plane(struct display *p, int xx, int yy) { - u_char *dest; - int j; - int bytes; - - dest = p->screen_base + y * p->fontheight * p->next_line + (x>>1)*16 + (x & 1); - j = p->fontheight; - bytes = p->next_line; - - while (j--) - { - /* This should really obey the individual character's - * background and foreground colors instead of simply - * inverting. For 8 plane mode, only the lower 4 bits of the - * color are inverted, because only that color registers have - * been set up. - */ - dest[0] = ~dest[0]; - dest[2] = ~dest[2]; - dest[4] = ~dest[4]; - dest[6] = ~dest[6]; - dest += bytes; - } + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + yy * p->fontheight * p->next_line + + (xx >> 1)*16 + (xx & 1); + j = p->fontheight; + bytes = p->next_line; + + while (j--) + { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. For 8 plane mode, only the lower 4 bits of the + * color are inverted, because only that color registers have + * been set up. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest[4] = ~dest[4]; + dest[6] = ~dest[6]; + dest += bytes; + } } #endif /* CONFIG_FBCON_8PLANE */ @@ -3378,8 +3545,8 @@ static void clear_8_packed(struct vc_data *conp, struct display *p, int sy, } -static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_8_packed(struct vc_data *conp, struct display *p, int c, + int yy, int xx) { u_char *dest,*cdat; int bytes=p->next_line,rows; @@ -3387,7 +3554,7 @@ static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, c &= 0xff; - dest = p->screen_base + y * p->fontheight * bytes + x * 8; + dest = p->screen_base + yy * p->fontheight * bytes + xx * 8; cdat = p->fontdata + c * p->fontheight; fgx=attr_fgcol(p,conp); @@ -3408,13 +3575,13 @@ static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int y, static void putcs_8_packed(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x) + const char *s, int count, int yy, int xx) { u_char *cdat, c, *dest, *dest0; int rows,bytes=p->next_line; u_long eorx, fgx, bgx; - dest0 = p->screen_base + y * p->fontheight * bytes + x * 8; + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 8; fgx=attr_fgcol(p,conp); bgx=attr_bgcol(p,conp); fgx |= (fgx << 8); @@ -3437,12 +3604,12 @@ static void putcs_8_packed(struct vc_data *conp, struct display *p, } -static void rev_char_8_packed(struct display *p, int x, int y) +static void rev_char_8_packed(struct display *p, int xx, int yy) { u_char *dest; int bytes=p->next_line, rows; - dest = p->screen_base + y * p->fontheight * bytes + x * 8; + dest = p->screen_base + yy * p->fontheight * bytes + xx * 8; for (rows = p->fontheight ; rows-- ; dest += bytes) { ((u_long *)dest)[0] ^= 0x0f0f0f0f; ((u_long *)dest)[1] ^= 0x0f0f0f0f; @@ -3539,7 +3706,7 @@ static void clear_16_packed(struct vc_data *conp, struct display *p, int sy, static void putc_16_packed(struct vc_data *conp, struct display *p, int c, - int y, int x) + int yy, int xx) { u_char *dest,*cdat; int bytes=p->next_line,rows; @@ -3547,7 +3714,7 @@ static void putc_16_packed(struct vc_data *conp, struct display *p, int c, c &= 0xff; - dest = p->screen_base + y * p->fontheight * bytes + x * 16; + dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; cdat = p->fontdata + c * p->fontheight; fgx = attr_fgcol(p,conp); @@ -3573,13 +3740,13 @@ static void putc_16_packed(struct vc_data *conp, struct display *p, int c, /* TODO */ static void putcs_16_packed(struct vc_data *conp, struct display *p, - const char *s, int count, int y, int x) + const char *s, int count, int yy, int xx) { u_char *cdat, c, *dest, *dest0; int rows,bytes=p->next_line; u_long eorx, fgx, bgx; - dest0 = p->screen_base + y * p->fontheight * bytes + x * 16; + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16; fgx = attr_fgcol(p,conp); fgx = packed16_cmap[fgx]; bgx = attr_bgcol(p,conp); @@ -3606,12 +3773,12 @@ static void putcs_16_packed(struct vc_data *conp, struct display *p, } -static void rev_char_16_packed(struct display *p, int x, int y) +static void rev_char_16_packed(struct display *p, int xx, int yy) { u_char *dest; int bytes=p->next_line, rows; - dest = p->screen_base + y * p->fontheight * bytes + x * 16; + dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; for (rows = p->fontheight ; rows-- ; dest += bytes) { ((u_long *)dest)[0] ^= 0xffffffff; ((u_long *)dest)[1] ^= 0xffffffff; @@ -3641,87 +3808,90 @@ static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, } -static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx, - int height, int width) +static void clear_cyber(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width) { - u_char bg; + unsigned char bg; sx *= 8; width *= 8; bg = attr_bgcol_ec(p,conp); - Cyber_RectFill((u_short)sx, (u_short)(sy*p->fontheight), (u_short)width, - (u_short)(height*p->fontheight), (u_short)S3_NEW, - (u_short)bg); + Cyber_RectFill((u_short)sx, + (u_short)(sy*p->fontheight), + (u_short)width, + (u_short)(height*p->fontheight), + (u_short)S3_NEW, + (u_short)bg); } -static void putc_cyber(struct vc_data *conp, struct display *p, int c, int y, - int x) +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy, + int xx) { u_char *dest, *cdat; u_long tmp; - u_int rows, reverse, underline; + u_int rows, revs, underl; u_char d; - u_char fg, bg; + u_char fg, bg; - c &= 0xff; + c &= 0xff; dest = p->screen_base+y*p->fontheight*p->next_line+8*x; cdat = p->fontdata+(c*p->fontheight); - fg = disp->fgcol; - bg = disp->bgcol; - reverse = conp->vc_reverse; - underline = conp->vc_underline; + fg = disp->fgcol; + bg = disp->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; Cyber_WaitBlit(); for (rows = p->fontheight; rows--; dest += p->next_line) { d = *cdat++; - if (underline && !rows) + if (underl && !rows) d = 0xff; - if (reverse) + if (revs) d = ~d; - tmp = ((d & 0x80) ? fg : bg) << 24; - tmp |= ((d & 0x40) ? fg : bg) << 16; - tmp |= ((d & 0x20) ? fg : bg) << 8; - tmp |= ((d & 0x10) ? fg : bg); - *((u_long*) dest) = tmp; - tmp = ((d & 0x8) ? fg : bg) << 24; - tmp |= ((d & 0x4) ? fg : bg) << 16; - tmp |= ((d & 0x2) ? fg : bg) << 8; - tmp |= ((d & 0x1) ? fg : bg); - *((u_long*) dest + 1) = tmp; + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((u_long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((u_long*) dest + 1) = tmp; } } static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, - int count, int y, int x) + int count, int yy, int xx) { u_char *dest, *dest0, *cdat; - u_long tmp; - u_int rows, reverse, underline; + u_long tmp; + u_int rows, revs, underl; u_char c, d; - u_char fg, bg; + u_char fg, bg; dest0 = p->screen_base+y*p->fontheight*p->next_line+8*x; - fg = disp->fgcol; - bg = disp->bgcol; - reverse = conp->vc_reverse; - underline = conp->vc_underline; + fg = disp->fgcol; + bg = disp->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; Cyber_WaitBlit(); while (count--) { c = *s++; dest = dest0; - dest0 += 8; + dest0 += 8; cdat = p->fontdata+(c*p->fontheight); for (rows = p->fontheight; rows--; dest += p->next_line) { d = *cdat++; - if (underline && !rows) + if (underl && !rows) d = 0xff; - if (reverse) + if (revs) d = ~d; tmp = ((d & 0x80) ? fg : bg) << 24; @@ -3739,32 +3909,208 @@ static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, } -static void rev_char_cyber(struct display *p, int x, int y) +static void rev_char_cyber(struct display *p, int xx, int yy) { - u_char *dest; - u_int rows; - u_char fg, bg; + unsigned char *dest; + unsigned int rows; + unsigned char fg, bg; - fg = disp->fgcol; - bg = disp->bgcol; + fg = disp->fgcol; + bg = disp->bgcol; dest = p->screen_base+y*p->fontheight*p->next_line+8*x; Cyber_WaitBlit(); for (rows = p->fontheight; rows--; dest += p->next_line) { *dest = (*dest == fg) ? bg : fg; - *(dest+1) = (*(dest + 1) == fg) ? bg : fg; - *(dest+2) = (*(dest + 2) == fg) ? bg : fg; - *(dest+3) = (*(dest + 3) == fg) ? bg : fg; - *(dest+4) = (*(dest + 4) == fg) ? bg : fg; - *(dest+5) = (*(dest + 5) == fg) ? bg : fg; - *(dest+6) = (*(dest + 6) == fg) ? bg : fg; - *(dest+7) = (*(dest + 7) == fg) ? bg : fg; + *(dest+1) = (*(dest + 1) == fg) ? bg : fg; + *(dest+2) = (*(dest + 2) == fg) ? bg : fg; + *(dest+3) = (*(dest + 3) == fg) ? bg : fg; + *(dest+4) = (*(dest + 4) == fg) ? bg : fg; + *(dest+5) = (*(dest + 5) == fg) ? bg : fg; + *(dest+6) = (*(dest + 6) == fg) ? bg : fg; + *(dest+7) = (*(dest + 7) == fg) ? bg : fg; } } #endif /* CONFIG_FBCON_CYBER */ +#ifdef CONFIG_FBCON_RETINAZ3 + +/* + * RetinaZ3 (accelerated) + */ + +#define Z3BLTcopy 0xc0 +#define Z3BLTset 0xf0 + +static void clear_retz3(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width) +{ + unsigned short col; + int fontwidth = p->fontwidth; + + sx *= fontwidth; + width *= fontwidth; + + col = attr_bgcol_ec(p, conp); + col &= 0xff; + col |= (col << 8); + + retz3_bitblt(&p->var, + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)width, + (unsigned short)(height*p->fontheight), + Z3BLTset, + col); +} + +static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int fontwidth = p->fontwidth; + + sx *= fontwidth; + dx *= fontwidth; + width *= fontwidth; + + retz3_bitblt(&p->var, + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)dx, + (unsigned short)(dy*p->fontheight), + (unsigned short)width, + (unsigned short)(height*p->fontheight), + Z3BLTcopy, + 0xffff); +} + +static void putc_retz3(struct vc_data *conp, struct display *p, + int c, int yy, int xx) +{ + unsigned char *dest, *cdat; + unsigned long tmp; + unsigned int rows, revs, underl, bytes; + unsigned char d; + unsigned char fg, bg; + + c &= 0xff; + + bytes = p->next_line; + + dest = p->screen_base + yy*p->fontheight*bytes + + xx*p->var.bits_per_pixel; + cdat = p->fontdata + c * p->fontheight; + + fg = disp->fgcol; + bg = disp->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; + + for (rows = p->fontheight; rows--; dest += bytes) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + if (revs) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((unsigned long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((unsigned long*) dest + 1) = tmp; + } +} + + +static void putcs_retz3(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx) +{ + unsigned char *dest, *dest0, *cdat; + unsigned long tmp; + unsigned int rows, revs, underl, bytes; + unsigned char c, d; + unsigned char fg, bg; + + bytes = p->next_line; + + dest0 = p->screen_base + yy*p->fontheight*bytes + + xx * p->var.bits_per_pixel; + fg = disp->fgcol; + bg = disp->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; + + while (count--) { + c = *s++; + dest = dest0; + dest0 += 8; + + cdat = p->fontdata + c * p->fontheight; + for (rows = p->fontheight; rows--; dest += bytes) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + if (revs) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((unsigned long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((unsigned long*) dest + 1) = tmp; + } + } +} + +static void rev_char_retz3(struct display *p, int xx, int yy) +{ + unsigned char *dest; + int bytes=p->next_line, rows; + unsigned int bpp, mask; + + bpp = p->var.bits_per_pixel; + + switch (bpp){ + case 8: + mask = 0x0f0f0f0f; + break; + case 16: + mask = 0xffffffff; + break; + case 24: + mask = 0xffffffff; /* ??? */ + break; + default: + printk("illegal depth for rev_char_retz3(), bpp = %i\n", bpp); + return; + } + + dest = p->screen_base + yy * p->fontheight * bytes + xx * bpp; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((unsigned long *)dest)[0] ^= mask; + ((unsigned long *)dest)[1] ^= mask; + } +} + +#endif + /* ====================================================================== */ /* @@ -3774,5 +4120,5 @@ static void rev_char_cyber(struct display *p, int x, int y) struct consw fb_con = { fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc, fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch, - fbcon_blank, fbcon_get_font, fbcon_set_font + fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette }; diff --git a/arch/m68k/console/txtcon.c b/arch/m68k/console/txtcon.c index a080c12a7..b85808558 100644 --- a/arch/m68k/console/txtcon.c +++ b/arch/m68k/console/txtcon.c @@ -22,7 +22,7 @@ * Interface used by the world */ -static u_long txtcon_startup(u_long kmem_start, char **display_desc); +static u_long txtcon_startup(u_long kmem_start, const char **display_desc); static void txtcon_init(struct vc_data *conp); static int txtcon_deinit(struct vc_data *conp); static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height, @@ -36,10 +36,12 @@ static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, int height, int width); static int txtcon_switch(struct vc_data *conp); static int txtcon_blank(int blank); +static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data); +static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data); +static int txtcon_set_palette(struct vc_data *conp, unsigned char *table); - -static u_long txtcon_startup(u_long kmem_start, char **display_desc) +static u_long txtcon_startup(u_long kmem_start, const char **display_desc) { *display_desc = "Not yet implemented"; return(kmem_start); @@ -113,6 +115,24 @@ static int txtcon_blank(int blank) } +static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data) +{ + return(0); +} + + +static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data) +{ + return(0); +} + + +static int txtcon_set_palette(struct vc_data *conp, unsigned char *table) +{ + return(0); +} + + /* ====================================================================== */ /* @@ -122,6 +142,6 @@ static int txtcon_blank(int blank) struct consw txt_con = { txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc, txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch, - txtcon_blank + txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette }; diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index e97326929..65f71d5a9 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -38,14 +38,15 @@ CONFIG_M68040=y # CONFIG_NET=y CONFIG_SYSVIPC=y +CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y CONFIG_ZORRO=y CONFIG_AMIFB_OCS=y CONFIG_AMIFB_ECS=y CONFIG_AMIFB_AGA=y # CONFIG_FB_CYBER is not set +# CONFIG_FB_RETINAZ3 is not set # CONFIG_AMIGA_GSP is not set # CONFIG_GSP_RESOLVER is not set # CONFIG_GSP_A2410 is not set @@ -60,6 +61,7 @@ CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_AMIGA_Z2RAM is not set # CONFIG_ATARI_ACSI is not set # CONFIG_ACSI_MULTI_LUN is not set @@ -74,21 +76,21 @@ CONFIG_BLK_DEV_INITRD=y # # Networking options # +# CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set CONFIG_INET=y -# CONFIG_IP_FORWARD is not set # CONFIG_IP_MULTICAST is not set -# CONFIG_IP_FIREWALL is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set # # (it is safe to leave these untouched) # # CONFIG_INET_PCTCP is not set # CONFIG_INET_RARP is not set -# CONFIG_NO_PATH_MTU_DISCOVERY is not set -# CONFIG_TCP_NAGLE_OFF is not set +CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set @@ -100,7 +102,6 @@ CONFIG_IP_NOSR=y # CONFIG_ATALK is not set # CONFIG_AX25 is not set # CONFIG_BRIDGE is not set -# CONFIG_NETLINK is not set # # SCSI support @@ -124,18 +125,19 @@ CONFIG_BLK_DEV_SR=y # SCSI low-level drivers # CONFIG_A3000_SCSI=y -# CONFIG_A2091_SCSI is not set -# CONFIG_GVP11_SCSI is not set +CONFIG_A2091_SCSI=y +CONFIG_GVP11_SCSI=y # CONFIG_CYBERSTORM_SCSI is not set # CONFIG_CYBERSTORMII_SCSI is not set # CONFIG_BLZ2060_SCSI is not set # CONFIG_BLZ1230_SCSI is not set +# CONFIG_FASTLANE_SCSI is not set CONFIG_ATARI_SCSI=y # # Network device support # -# CONFIG_NETDEVICES is not set +CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_SLIP is not set # CONFIG_PPP is not set @@ -151,9 +153,7 @@ CONFIG_ATARI_SCSI=y # # CONFIG_QUOTA is not set CONFIG_MINIX_FS=y -# CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y -# CONFIG_XIA_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_VFAT_FS is not set @@ -167,16 +167,21 @@ CONFIG_NFS_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_ROMFS_FS is not set # CONFIG_UFS_FS is not set # # Character devices # +CONFIG_VT=y +CONFIG_VT_CONSOLE=y # CONFIG_PRINTER is not set CONFIG_AMIGAMOUSE=y CONFIG_ATARIMOUSE=y CONFIG_AMIGA_BUILTIN_SERIAL=y # CONFIG_GVPIOEXT is not set +# CONFIG_GVPIOEXT_LP is not set +# CONFIG_GVPIOEXT_PLIP is not set # CONFIG_MULTIFACE_III_TTY is not set # CONFIG_USERIAL is not set # CONFIG_WATCHDOG is not set diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile index b6a8c0279..d3ec21217 100644 --- a/arch/m68k/fpsp040/Makefile +++ b/arch/m68k/fpsp040/Makefile @@ -9,7 +9,6 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< -# $(AS) -o $*.o $< OS_TARGET := fpsp.o diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 4e4eab64e..5768516bd 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -513,9 +513,12 @@ copyout: movel 12(%sp),%d0 | count subl #1,%d0 | dec count by 1 for dbra movel #1,%d1 - movec %d1,%DFC | set dfc for user data space + +| DFC is already set +| movec %d1,%DFC | set dfc for user data space moreout: moveb (%a0)+,%d1 | fetch supervisor byte +out_ea: movesb %d1,(%a1)+ | write user byte dbf %d0,moreout rts @@ -526,11 +529,24 @@ copyin: movel 12(%sp),%d0 | count subl #1,%d0 | dec count by 1 for dbra movel #1,%d1 - movec %d1,%SFC | set sfc for user space +| SFC is already set +| movec %d1,%SFC | set sfc for user space morein: +in_ea: movesb (%a0)+,%d1 | fetch user byte moveb %d1,(%a1)+ | write supervisor byte dbf %d0,morein rts + .section .fixup,#alloc,#execinstr + .even +1: + jbra SYMBOL_NAME(fpsp040_die) + + .section __ex_table,#alloc + .align 4 + + .long in_ea,1b + .long out_ea,1b + |end diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile index fe66cf033..94eea44a4 100644 --- a/arch/m68k/ifpsp060/Makefile +++ b/arch/m68k/ifpsp060/Makefile @@ -5,7 +5,6 @@ # for more details. .S.o: -# $(AS) -o $*.o $< $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< OS_TARGET := ifpsp.o diff --git a/arch/m68k/ifpsp060/os.S b/arch/m68k/ifpsp060/os.S index 3e0e30701..b58e0635b 100644 --- a/arch/m68k/ifpsp060/os.S +++ b/arch/m68k/ifpsp060/os.S @@ -153,7 +153,7 @@ _060_dmem_read_byte: btst #0x5,0x4(%a6) | check for supervisor state bnes dmrbs | supervisor dmrbu: clr.l %d0 | clear whole longword - movs.b (%a0),%d0 | fetch user byte +dmrbuae:movs.b (%a0),%d0 | fetch user byte bras dmrbr dmrbs: clr.l %d0 | clear whole longword move.b (%a0),%d0 | fetch super byte @@ -190,7 +190,7 @@ _060_imem_read_word: btst #0x5,0x4(%a6) | check for supervisor state bnes dmrws | supervisor dmrwu: clr.l %d0 | clear whole longword - movs.w (%a0), %d0 | fetch user word +dmrwuae:movs.w (%a0), %d0 | fetch user word bras dmrwr dmrws: clr.l %d0 | clear whole longword move.w (%a0), %d0 | fetch super word @@ -226,7 +226,8 @@ _060_dmem_read_long: _060_imem_read_long: btst #0x5,0x4(%a6) | check for supervisor state bnes dmrls | supervisor -dmrlu: movs.l (%a0),%d0 | fetch user longword +dmrlu: +dmrluae:movs.l (%a0),%d0 | fetch user longword bras dmrlr dmrls: move.l (%a0),%d0 | fetch super longword dmrlr: clr.l %d1 | return success @@ -248,7 +249,8 @@ dmrlr: clr.l %d1 | return success _060_dmem_write_byte: btst #0x5,0x4(%a6) | check for supervisor state bnes dmwbs | supervisor -dmwbu: movs.b %d0,(%a0) | store user byte +dmwbu: +dmwbuae:movs.b %d0,(%a0) | store user byte bras dmwbr dmwbs: move.b %d0,(%a0) | store super byte dmwbr: clr.l %d1 | return success @@ -270,7 +272,8 @@ dmwbr: clr.l %d1 | return success _060_dmem_write_word: btst #0x5,0x4(%a6) | check for supervisor state bnes dmwws | supervisor -dmwwu: movs.w %d0,(%a0) | store user word +dmwwu: +dmwwuae:movs.w %d0,(%a0) | store user word bras dmwwr dmwws: move.w %d0,(%a0) | store super word dmwwr: clr.l %d1 | return success @@ -292,7 +295,8 @@ dmwwr: clr.l %d1 | return success _060_dmem_write_long: btst #0x5,0x4(%a6) | check for supervisor state bnes dmwls | supervisor -dmwlu: movs.l %d0,(%a0) | store user longword +dmwlu: +dmwluae:movs.l %d0,(%a0) | store user longword bra dmwlr dmwls: move.l %d0,(%a0) | store super longword dmwlr: clr.l %d1 | return success @@ -322,9 +326,10 @@ _copyout: subq.l #1,%d0 moreout: move.b (%a0)+,%d1 | fetch supervisor byte +copyoutae: movs.b %d1,(%a1)+ | store user byte dbra %d0,moreout | are we through yet? - moveq #0,%d0 | return success + moveq #0,%d0 | return success rts | @@ -337,11 +342,12 @@ _copyin: move.l 12(%sp),%d0 | count subq.l #1,%d0 morein: +copyinae: movs.b (%a0)+,%d1 | fetch user byte move.b %d1,(%a1)+ | write supervisor byte subq.l #0x1,%d0 | are we through yet? dbra %d0,morein | are we through yet? - moveq #0,%d0 | return success + moveq #0,%d0 | return success rts |########################################################################### @@ -374,3 +380,22 @@ _060_real_trace: .global _060_real_access _060_real_access: bral SYMBOL_NAME(buserr) + + + +| Execption handling for movs access to illegal memory + .section .fixup,#alloc,#execinstr + .even +1: moveq #-1,%d1 + rts +.section __ex_table,#alloc + .align 4 + .long dmrbuae,1b + .long dmrwuae,1b + .long dmrluae,1b + .long dmwbuae,1b + .long dmwwuae,1b + .long dmwluae,1b + .long copyoutae,1b + .long copyinae,1b + .text diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 339e1b5db..67d87c1b9 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -13,7 +13,15 @@ all: kernel.o head.o O_TARGET := kernel.o O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ - setup.o bios32.o sys_m68k.o console.o time.o ksyms.o + setup.o bios32.o sys_m68k.o time.o +ifdef CONFIG_VT +O_OBJS += console.o +endif +OX_OBJS := m68k_ksyms.o + +ifdef CONFIG_KGDB +O_OBJS += kgdb.o +endif head.o: head.S diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c index cac94e7d4..468ae0b59 100644 --- a/arch/m68k/kernel/console.c +++ b/arch/m68k/kernel/console.c @@ -20,7 +20,7 @@ * 'unsigned long con_init(unsigned long)' * 'int con_open(struct tty_struct *tty, struct file * filp)' * 'void con_write(struct tty_struct * tty)' - * 'void console_print(const char * b)' + * 'void vt_console_print(const char * b)' * 'void update_screen(int new_console)' * * 'void do_blank_screen(int)' @@ -103,11 +103,13 @@ * interrupt, as we use trap-gates. Hopefully all is well. */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/console.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> @@ -127,6 +129,7 @@ #include "../../../drivers/char/vt_kern.h" #include "../../../drivers/char/consolemap.h" #include "../../../drivers/char/selection.h" +#include "../../../drivers/char/console_struct.h" #ifndef MIN @@ -146,12 +149,13 @@ static void gotoxy(int currcons, int new_x, int new_y); static void save_cur(int currcons); static void blank_screen(void); static void unblank_screen(void); +static int con_open(struct tty_struct *, struct file *); extern void change_console(unsigned int); static inline void set_cursor(int currcons); static void reset_terminal(int currcons, int do_clear); extern void reset_vc(unsigned int new_console); extern void vt_init(void); -extern void register_console(void (*proc)(const char *)); +static void set_vesa_blanking(unsigned long arg); extern void vesa_blank(void); extern void vesa_unblank(void); extern void compute_shiftstate(void); @@ -170,6 +174,7 @@ int video_mode_512ch = 0; /* 512-character mode */ static unsigned short console_charmask = 0x0ff; static unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; +struct vc vc_cons [MAX_NR_CONSOLES]; /* used by kbd_bh - set by keyboard_interrupt */ int do_poke_blanked_console = 0; @@ -178,13 +183,17 @@ static int blankinterval = 10*60*HZ; static int vesa_off_interval = 0; static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static struct vc { - struct vc_data *d; +/* + * fg_console is the current virtual console, + * last_console is the last used one, + * want_console is the console we want to switch to, + * kmsg_redirect is the console for kernel messages, + */ +int fg_console = 0; +int last_console = 0; +int want_console = -1; +int kmsg_redirect = 0; - /* might add scrmem, vt_struct, kbd at some time, - to have everything in one place - the disadvantage - would be that vc_cons etc can no longer be static */ -} vc_cons [MAX_NR_CONSOLES]; struct consw *conswitchp; #define cols (vc_cons[currcons].d->vc_cols) @@ -259,8 +268,6 @@ struct consw *conswitchp; #define vtnewvt (vt_cons[currcons]->vt_newvt) #endif -#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) - int vc_cons_allocated(unsigned int i) { return (i < MAX_NR_CONSOLES && vc_cons[i].d); @@ -610,8 +617,7 @@ void scrollback(int l) return; } -static void scrup(int currcons, unsigned int t, unsigned int b, - int nr) +static void scrup(int currcons, unsigned int t, unsigned int b, int nr) { unsigned short *p; int i; @@ -625,10 +631,10 @@ static void scrup(int currcons, unsigned int t, unsigned int b, p = video_mem_start + (b - nr) * cols; for (i = nr * cols; i > 0; i--) - *p++ = video_erase_char; + *p++ = video_erase_char; if (currcons != fg_console) - return; + return; /* * Arno: * Scrolling has now been moved to amicon.c where it should have @@ -801,8 +807,8 @@ static void csi_X(int currcons, int vpar) /* erase the following vpar positions if (!vpar) vpar++; - start=pos; - count=(vpar > cols-x) ? (cols-x) : vpar; + start = pos; + count = (vpar > cols-x) ? (cols-x) : vpar; if (currcons == fg_console) sw->con_clear(vc_cons[currcons].d,y,x,1,count); @@ -970,7 +976,7 @@ static void respond_string(const char * p, struct tty_struct * tty) tty_schedule_flip(tty); } -static void cursor_report(int currcons, struct tty_struct * tty) +static inline void cursor_report(int currcons, struct tty_struct * tty) { char buf[40]; @@ -997,7 +1003,7 @@ void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) respond_string(buf, tty); } -/* invoked via ioctl(TIOCLINUX) */ +/* invoked via ioctl(TIOCLINUX) and through set_selection */ int mouse_reporting(void) { int currcons = fg_console; @@ -1005,6 +1011,56 @@ int mouse_reporting(void) return report_mouse; } +int tioclinux(struct tty_struct *tty, unsigned long arg) +{ + char type, data; + + if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + return -EINVAL; + if (current->tty != tty && !suser()) + return -EPERM; + if (get_user(type, (char *)arg)) + return -EFAULT; + switch (type) + { + case 2: + return set_selection(arg, tty, 1); + case 3: + return paste_selection(tty); + case 4: + do_unblank_screen(); + return 0; + case 5: + return sel_loadlut(arg); + case 6: + + /* + * Make it possible to react to Shift+Mousebutton. + * Note that 'shift_state' is an undocumented + * kernel-internal variable; programs not closely + * related to the kernel should not use this. + */ + data = shift_state; + return put_user(data, (char *) arg); + case 7: + data = mouse_reporting(); + return put_user(data, (char *) arg); + case 10: + set_vesa_blanking(arg); + return 0; + case 11: /* set kmsg redirect */ + if (!suser()) + return -EPERM; + if (get_user(data, (char *)arg+1)) + return -EFAULT; + kmsg_redirect = data; + return 0; + case 12: /* get fg_console */ + return fg_console; + } + return -EINVAL; +} + static inline unsigned short *screenpos(int currcons, int offset, int viewed) { unsigned short *p = (unsigned short *)(origin + offset); @@ -1242,18 +1298,18 @@ static void setterm_command(int currcons) } } -static void insert_char(int currcons) +static inline void insert_char(int currcons) { int i; unsigned short *p = pos; for (i = cols - x - 2; i >= 0; i--) - p[i + 1] = p[i]; + p[i + 1] = p[i]; *pos = video_erase_char; need_wrap = 0; if (currcons != fg_console) - return; + return; /* Arno: * Move the remainder of the line (-1 character) one spot to the right @@ -1277,19 +1333,19 @@ static void csi_at(int currcons, unsigned int nr) p = pos + cols - x - nr; while (--p >= pos) - p[nr] = *p; + p[nr] = *p; for (i = 0; i < nr; i++) - *++p = video_erase_char; + *++p = video_erase_char; need_wrap = 0; if (currcons != fg_console) - return; + return; sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr, 1, cols - x - nr); while (nr--) - sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, - y, x + nr); + sw->con_putc (vc_cons[currcons].d, + video_erase_char & 0x00ff, y, x + nr); } static void csi_L(int currcons, unsigned int nr) @@ -1584,9 +1640,9 @@ static int do_con_write(struct tty_struct * tty, int from_user, */ /* Only use this for the foreground console, - where we really draw the chars */ + where we really draw the chars */ - if (count > 2 && + if (count > 2 && !decim && !utf && currcons == fg_console) { static char putcs_buf[256]; char *p = putcs_buf; @@ -1599,13 +1655,11 @@ static int do_con_write(struct tty_struct * tty, int from_user, if (nextx == cols) { sw->con_putc(vc_cons[currcons].d, *putcs_buf, y, x); - pos--; + ((unsigned short *)pos)--; need_wrap = decawm; continue; } - /* TAB TAB TAB - Arghh!!!! */ - while (count) { enable_bh(CONSOLE_BH); @@ -2068,12 +2122,13 @@ void poke_blanked_console(void) /* DPC: New version of console_print using putcs */ -void console_print(const char * b) +#ifdef CONFIG_VT_CONSOLE +void vt_console_print(const char * b, unsigned int count) { int currcons = fg_console; unsigned char c; const char *start = b; - ushort count = 0; + ushort cnt = 0; ushort myx = x; static int printing = 0; @@ -2086,7 +2141,7 @@ void console_print(const char * b) if (!vc_cons_allocated(currcons)) { /* impossible */ - printk("console_print: tty %d not allocated ??\n", currcons+1); + printk("vt_console_print: tty %d not allocated ??\n", currcons+1); printing = 0; return; } @@ -2096,52 +2151,51 @@ void console_print(const char * b) /* Contrived structure to try to emulate original need_wrap behaviour * Problems caused when we have need_wrap set on '\n' character */ - - while ((c = *(b++)) != 0) { - if (c == 10 || c == 13 || c == 8 || need_wrap) { - if ((count = b - start - 1) > 0) { - sw->con_putcs(vc_cons[currcons].d, start, count , - y, x); - x += count; - if (need_wrap) - x--; - } - - if (c == 8) { /* backspace */ - bs(currcons); - start = b; - myx = x; - continue; + + while (count-- > 0) { + c = *(b++); + if (c == 10 || c == 13 || c == 8 || need_wrap) { + if ((cnt = b - start - 1) > 0) { + sw->con_putcs(vc_cons[currcons].d, + start, cnt, y, x); + x += cnt; + if (need_wrap) + x--; + } + + if (c == 8) { /* backspace */ + bs(currcons); + start = b; + myx = x; + continue; + } + if (c != 13) + lf(currcons); + cr(currcons); + + if (c == 10 || c == 13) { + start = b; myx = x; continue; + } + + start = b-1; myx = x; + } + + *pos = c | (attr << 8); + if (myx == cols - 1) { + need_wrap = 1; + continue; } - if (c != 13) - lf(currcons); - cr(currcons); - - if (c == 10 || c == 13) { - start = b; myx = x; continue; - } - - start = b-1; myx = x; - } - - *pos = c | (attr << 8); - if (myx == cols - 1) { - need_wrap = 1; - continue; - } - pos++; - myx++; + pos++; + myx++; } - if ((count = b - start -1) > 0) { - sw->con_putcs(vc_cons[currcons].d, start, count , - y, x); - x += count; - if (x == cols) - { - x--; - need_wrap = 1; - } + if ((cnt = b - start) > 0) { + sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); + x += cnt; + if (x == cols){ + x--; + need_wrap = 1; + } } set_cursor(currcons); @@ -2149,6 +2203,18 @@ void console_print(const char * b) printing = 0; } +static int vt_console_device(void) +{ + return MKDEV(TTY_MAJOR, fg_console + 1); +} + +extern void keyboard_wait_for_keypress(void); + +struct console vt_console_driver = { + vt_console_print, do_unblank_screen, + keyboard_wait_for_keypress, vt_console_device +}; +#endif /* * con_throttle and con_unthrottle are only used for @@ -2219,7 +2285,7 @@ static void console_bh(void) */ unsigned long con_init(unsigned long kmem_start) { - char *display_desc = "????"; + const char *display_desc = "????"; unsigned int currcons = 0; extern int serial_debug; @@ -2293,14 +2359,15 @@ unsigned long con_init(unsigned long kmem_start) printable = 1; /* If "serdebug" cmd line option was present, don't register for printk */ +#ifdef CONFIG_VT_CONSOLE if (!serial_debug) - register_console(console_print); + register_console(&vt_console_driver); printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n", can_do_color ? "colour":"mono", display_desc, cols,rows, MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); - +#endif init_bh(CONSOLE_BH, console_bh); return kmem_start; } @@ -2466,7 +2533,7 @@ static void unblank_screen(void) /* * Allocate the console screen memory. */ -int con_open(struct tty_struct *tty, struct file * filp) +static int con_open(struct tty_struct *tty, struct file * filp) { unsigned int currcons; int i; @@ -2603,7 +2670,7 @@ int con_adjust_height(unsigned long fontheight) return -EINVAL; } -void set_vesa_blanking(int arg) +static void set_vesa_blanking(unsigned long arg) { char *argp = (char *)arg + 1; unsigned int mode; diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 603afe9ab..2cb35e67f 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -52,6 +52,10 @@ #include <linux/linkage.h> #include <asm/setup.h> #include <asm/segment.h> +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +.globl SYMBOL_NAME(kgdb_registers) +#endif LENOSYS = 38 @@ -66,7 +70,7 @@ LTASK_BLOCKED = 16 LTASK_FLAGS = 20 /* the following macro is used when enabling interrupts */ -#if defined(CONFIG_ATARI_ONLY) +#if defined(MACH_ATARI_ONLY) /* block out HSYNC on the atari */ #define ALLOWINT 0xfbff #define MAX_NOINT_IPL 3 @@ -87,11 +91,23 @@ LFORMATVEC = 0x2E * regs are a2-a6 and d6-d7 preserved by C code * the kernel doesn't mess with usp unless it needs to */ +#ifndef CONFIG_KGDB #define SAVE_ALL \ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ moveml %d1-%d5/%a0-%a1,%sp@- +#else +/* Need to save the "missing" registers for kgdb... + */ +#define SAVE_ALL \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + moveml %d1-%d5/%a0-%a1,%sp@-; \ + moveml %d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6; \ + moveml %a2-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A2 +#endif #define RESTORE_ALL \ moveml %sp@+,%a0-%a1/%d1-%d5; \ @@ -148,37 +164,18 @@ ENTRY(reschedule) pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) -ENTRY(system_call) - SAVE_ALL - movel #-LENOSYS,LD0(%sp) | default return value in d0 - | original D0 is in orig_d0 - movel %d0,%d2 - - | save top of frame - pea %sp@ - jbsr SYMBOL_NAME(set_esp0) - addql #4,%sp - - cmpl #NR_syscalls,%d2 - jcc SYMBOL_NAME(ret_from_exception) - lea SYMBOL_NAME(sys_call_table),%a0 - movel %a0@(%d2:l:4),%d3 - jeq SYMBOL_NAME(ret_from_exception) - movel SYMBOL_NAME(current_set),%a0 - btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS - bnes 1f - movel %d3,%a0 - jbsr %a0@ - movel %d0,%sp@(LD0) | save the return value +badsys: + movel #-LENOSYS,LD0(%sp) jra SYMBOL_NAME(ret_from_exception) -1: + +do_trace: + movel #-LENOSYS,LD0(%sp) | needed for strace subql #4,%sp SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) RESTORE_SWITCH_STACK addql #4,%sp - movel %d3,%a0 - jbsr %a0@ + jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) movel %d0,%sp@(LD0) | save the return value subql #4,%sp | dummy return address SAVE_SWITCH_STACK @@ -187,6 +184,24 @@ ENTRY(system_call) SYMBOL_NAME_LABEL(ret_from_signal) RESTORE_SWITCH_STACK addql #4,%sp + jra SYMBOL_NAME(ret_from_exception) + +ENTRY(system_call) + SAVE_ALL + movel %d0,%d2 + + | save top of frame + pea %sp@ + jbsr SYMBOL_NAME(set_esp0) + addql #4,%sp + + cmpl #NR_syscalls,%d2 + jcc badsys + movel SYMBOL_NAME(current_set),%a0 + btst #5,%a0@(LTASK_FLAGS+3) | PF_TRACESYS + jne do_trace + jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0) + movel %d0,%sp@(LD0) | save the return value SYMBOL_NAME_LABEL(ret_from_exception) btst #5,%sp@(LSR) | check if returning to kernel @@ -197,17 +212,8 @@ SYMBOL_NAME_LABEL(ret_from_exception) cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals jeq 2f bclr #5,%a0@(LTASK_FLAGS+1) | check for delayed trace - jeq 1f - bclr #7,%sp@(LSR) | clear trace bit in SR - pea 1 | send SIGTRAP - movel %a0,%sp@- - pea 5 - jbsr SYMBOL_NAME(send_sig) - addql #8,%sp - addql #4,%sp - movel SYMBOL_NAME(current_set),%a0 - -1: + jne do_delayed_trace +5: tstl %a0@(LTASK_STATE) | state jne SYMBOL_NAME(reschedule) tstl %a0@(LTASK_COUNTER) | counter @@ -234,6 +240,17 @@ Lsignal_return: addql #4,%sp RESTORE_ALL +do_delayed_trace: + bclr #7,%sp@(LSR) | clear trace bit in SR + pea 1 | send SIGTRAP + movel %a0,%sp@- + pea 5 + jbsr SYMBOL_NAME(send_sig) + addql #8,%sp + addql #4,%sp + movel SYMBOL_NAME(current_set),%a0 + jra 5b + /* ** This is the main interrupt handler, responsible for calling process_int() */ @@ -243,7 +260,7 @@ SYMBOL_NAME_LABEL(inthandler) movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall - addql #1,SYMBOL_NAME(intr_count) + addql #1,SYMBOL_NAME(local_irq_count) | put exception # in d0 bfextu %sp@(LFORMATVEC){#4,#10},%d0 @@ -254,27 +271,26 @@ SYMBOL_NAME_LABEL(inthandler) SYMBOL_NAME_LABEL(ret_from_interrupt) /* check if we need to do software interrupts */ -1: - movel SYMBOL_NAME(intr_count),%d1 + movel SYMBOL_NAME(local_irq_count),%d1 subql #1,%d1 jne 4f - bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt. +#if 0 + bfextu %sp@(LSR){#5,#3},%d0 | Check for nested interrupt. #if MAX_NOINT_IPL > 0 cmpiw #MAX_NOINT_IPL,%d0 #endif jhi 4f -2: +#endif movel SYMBOL_NAME(bh_active),%d0 andl SYMBOL_NAME(bh_mask),%d0 - jne 3f + jeq 3f - clrl SYMBOL_NAME(intr_count) | deliver signals, reschedule etc.. - jra SYMBOL_NAME(ret_from_exception) -3: jbsr SYMBOL_NAME(do_bottom_half) - jbra 2b +3: + clrl SYMBOL_NAME(local_irq_count) + jra SYMBOL_NAME(ret_from_exception) 4: - movel %d1,SYMBOL_NAME(intr_count) + movel %d1,SYMBOL_NAME(local_irq_count) RESTORE_ALL @@ -338,8 +354,10 @@ SYMBOL_NAME_LABEL(resume) /* save sr */ movew %sr,%a0@(LTSS_SR) +#if 0 /* disable interrupts */ oriw #0x0700,%sr +#endif /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ movec %sfc,%d0 @@ -360,18 +378,18 @@ SYMBOL_NAME_LABEL(resume) fsave %a0@(LTSS_FPCTXT+27*4) #if defined(CONFIG_M68060) -#if !defined(CONFIG_M68060_ONLY) - btst #3,SYMBOL_NAME(boot_info)+BI_cputype+3 +#if !defined(CPU_M68060_ONLY) + btst #3,SYMBOL_NAME(m68k_cputype)+3 beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ tstb %a0@(LTSS_FPCTXT+27*4+2) jeq 3f -#if !defined(CONFIG_M68060_ONLY) +#if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ -#if !defined(CONFIG_M68060_ONLY) +#if !defined(CPU_M68060_ONLY) 1: tstb %a0@(LTSS_FPCTXT+27*4) jeq 3f #endif @@ -387,12 +405,12 @@ SYMBOL_NAME_LABEL(resume) tstb %d2 jne 4f -#if defined(CONFIG_M68020_OR_M68030) && defined(CONFIG_M68040_OR_M68060) +#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) /* 68040 or 68060 ? */ tstl SYMBOL_NAME(m68k_is040or060) bnes 1f #endif -#if defined(CONFIG_M68020_OR_M68030) +#if defined(CPU_M68020_OR_M68030) /* * switch address space */ @@ -406,49 +424,51 @@ SYMBOL_NAME_LABEL(resume) pmove %a1@(LTSS_CRP),%crp #endif -#if defined(CONFIG_M68020_OR_M68030) && defined(CONFIG_M68040_OR_M68060) +#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) jra 2f /* skip m68040 stuff */ 1: #endif -#if defined(CONFIG_M68040_OR_M68060) +#if defined(CPU_M68040_OR_M68060) /* * switch address space */ + .chip 68040 /* flush address translation cache (user entries) */ - .word 0xf510 /* pflushan */ + pflushan /* switch the root pointer */ movel %a1@(LTSS_CRP+4),%d0 - .long 0x4e7b0806 /* movec d0,urp */ + movec %d0,%urp #if defined (CONFIG_M68060) /* is it a '060 ? */ - btst #3,SYMBOL_NAME(boot_info)+BI_cputype+3 + btst #3,SYMBOL_NAME(m68k_cputype)+3 beqs 2f /* clear user entries in the branch cache */ movec %cacr,%d0 orl #0x00200000,%d0 movec %d0,%cacr #endif /* CONFIG_M68060 */ -#endif /* CONFIG_M68040_OR_M68060 */ + .chip 68k +#endif /* CPU_M68040_OR_M68060 */ 2: 4: /* restore floating point context */ #if defined(CONFIG_M68060) -#if !defined(CONFIG_M68060_ONLY) - btst #3,SYMBOL_NAME(boot_info)+BI_cputype+3 +#if !defined(CPU_M68060_ONLY) + btst #3,SYMBOL_NAME(m68k_cputype)+3 beqs 1f #endif /* The 060 FPU keeps status in bits 15-8 of the first longword */ tstb %a1@(LTSS_FPCTXT+27*4+2) jeq 3f -#if !defined(CONFIG_M68060_ONLY) +#if !defined(CPU_M68060_ONLY) jra 2f #endif #endif /* CONFIG_M68060 */ -#if !defined(CONFIG_M68060_ONLY) +#if !defined(CPU_M68060_ONLY) 1: tstb %a1@(LTSS_FPCTXT+27*4) jeq 3f #endif @@ -592,7 +612,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ .long SYMBOL_NAME(sys_vhangup) .long SYMBOL_NAME(sys_idle) - .long SYMBOL_NAME(sys_ni_syscall) /* vm86 for i386 */ + .long SYMBOL_NAME(sys_ni_syscall) /* vm86old for i386 */ .long SYMBOL_NAME(sys_wait4) .long SYMBOL_NAME(sys_swapoff) /* 115 */ .long SYMBOL_NAME(sys_sysinfo) @@ -644,5 +664,11 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) .long SYMBOL_NAME(sys_setresuid) - .long SYMBOL_NAME(sys_getresuid) - .space (NR_syscalls-165)*4 + .long SYMBOL_NAME(sys_getresuid) /* 165 */ + .long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */ + .long SYMBOL_NAME(sys_query_module) + .long SYMBOL_NAME(sys_poll) + .long SYMBOL_NAME(sys_nfsservctl) + .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 + .long SYMBOL_NAME(sys_ni_syscall) + .endr diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 3dab4b2eb..c2b72aa2d 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -67,11 +67,13 @@ #include <linux/config.h> #include <linux/linkage.h> +#include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/pgtable.h> .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt) .globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa) +.globl SYMBOL_NAME(is_hades) .globl SYMBOL_NAME(m68k_pgtable_cachemode) .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir) @@ -178,21 +180,29 @@ ENTRY(_start) lea %pc@(SYMBOL_NAME(_stext):w),%sp /* - * Copy bootinfo from position after BSS to final resting place - */ - lea %pc@(SYMBOL_NAME(_end)),%a0 - lea %pc@(SYMBOL_NAME(boot_info)),%a1 - movel %pc@(SYMBOL_NAME(bisize)),%d0 - subql #1,%d0 -1: moveb %a0@+,%a1@+ - dbra %d0,1b - -/* * Record the CPU and machine type. */ - lea %pc@(SYMBOL_NAME(boot_info)),%a0 - movel %a0@(BI_machtype),%d4 - movel %a0@(BI_cputype),%d0 + + movew #BI_MACHTYPE,%d0 + jbsr Lget_bi_record + movel %a0@,%d4 + lea %pc@(SYMBOL_NAME(m68k_machtype)),%a0 + movel %d4,%a0@ + movew #BI_FPUTYPE,%d0 + jbsr Lget_bi_record + movel %a0@,%d0 + lea %pc@(SYMBOL_NAME(m68k_fputype)),%a0 + movel %d0,%a0@ + movew #BI_MMUTYPE,%d0 + jbsr Lget_bi_record + movel %a0@,%d0 + lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a0 + movel %d0,%a0@ + movew #BI_CPUTYPE,%d0 + jbsr Lget_bi_record + movel %a0@,%d0 + lea %pc@(SYMBOL_NAME(m68k_cputype)),%a0 + movel %d0,%a0@ btst #CPUB_68060,%d0 jeq 1f @@ -226,18 +236,68 @@ ENTRY(_start) #endif /* + If running on an Atari, determine the I/O base of the + serial port and test if we are running on a Medusa or Hades. + This test is necessary here, because on the Hades the serial + port is only accessible in the high I/O memory area. + + The test whether it is a Medusa is done by writing to the byte at + phys. 0x0. This should result in a bus error on all other machines. + + ...should, but doesn't. The Afterburner040 for the Falcon has the + same behaviour (0x0..0x7 are no ROM shadow). So we have to do + another test to distinguish Medusa and AB040. This is a + read attempt for 0x00ff82fe phys. that should bus error on a Falcon + (+AB040), but is in the range where the Medusa always asserts DTACK. + + The test for the Hades is done by reading address 0xb0000000. This + should give a bus error on the Medusa. + */ + +#ifdef CONFIG_ATARI + is_not_atari(Lnotypetest) + + moveq #0,%d3 /* base addr for others: 0x00000000 */ + moveq #0,%d2 /* no Hades */ + movec %d3,%vbr + lea %pc@(Ltest_berr),%a0 + movel %a0,0x8 + movel %sp,%a0 + moveb 0x0,%d1 + clrb 0x0 + nop + moveb %d1,0x0 + nop + tstb 0x00ff82fe + nop + movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */ + tstb 0xb0000000 + nop + movel #0xff000000,%d2 /* Computer is a Hades */ + moveq #0,%d3 +Ltest_berr: + movel %a0,%sp + lea %pc@(SYMBOL_NAME(is_hades)),%a0 + movel %d2,%a0@ + lea %pc@(SYMBOL_NAME(is_medusa)),%a0 + movel %d3,%a0@ +Lnotypetest: +#endif + +/* * Initialize serial port */ + jbsr Lserial_init putr() putc('A') /* - * Get address at end of kernel code/data/bss and - * mask off at a page boundary. + * Get address at end of bootinfo and mask off at a page boundary. */ - lea %pc@(SYMBOL_NAME(_end)),%a0 + moveq #0,%d0 + jbsr Lget_bi_record addw #PAGESIZE-1,%a0 movel %a0,%d0 andl #-PAGESIZE,%d0 @@ -250,10 +310,6 @@ ENTRY(_start) */ lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 movel %a0,%d5 -#ifdef HACKER_KERNEL - lea %pc@(Lkernel_start),%a0 - movel %d5,%a0@ -#endif /* * initialize the kernel root table. @@ -486,35 +542,16 @@ Lnotami: For the Medusa it is better to map the I/O region transparently (i.e. 0xffxxxxxx -> 0xffxxxxxx), because some I/O registers are - accessible only in the high area. The test whether it is a Medusa - is done by writing to the byte at phys. 0x0. This should result - in a bus error on all other machines. + accessible only in the high area. - ...should, but doesn't. The Afterburner040 for the Falcon has the - same behaviour (0x0..0x7 are no ROM shadow). So we have to do - another test to distinguish Medusa and AB040. This is a - read attempt for 0x00ff82fe phys. that should bus error on a Falcon - (+AB040), but is in the range where the Medusa always asserts DTACK. + On the Hades all I/O registers are only accessible in the high + area. */ - moveq #0,%d3 /* base addr for others: 0x00000000 */ - movec %d3,%vbr - lea %pc@(Ltest_berr),%a0 - movel %a0,0x8 - movel %sp,%a0 - moveb 0x0,%d1 - clrb 0x0 - nop - moveb %d1,0x0 - nop - tstb 0x00ff82fe - nop - movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */ -Ltest_berr: - movel %a0,%sp - lea %pc@(SYMBOL_NAME(is_medusa)),%a0 - movel %d3,%a0@ - + movel %pc@(is_medusa),%d3 + bne 1f + movel %pc@(is_hades),%d3 +1: /* Let the root table point to the new pointer table */ lea %a4@(PTR_TABLE_SIZE<<2),%a4 movel %a4,%a0 @@ -637,45 +674,47 @@ Lmapphys: /* no limit, 4byte descriptors */ movel #0x80000002,%a3@ movel %a5,%a3@(4) - .long 0xf0134800 /* pmove %a3@,%srp */ - .long 0xf0134c00 /* pmove %a3@,%crp */ - .long 0xf0002400 /* pflusha */ + pmove %a3@,%srp + pmove %a3@,%crp + pflusha /* * enable,super root enable,4096 byte pages,7 bit root index, * 7 bit pointer index, 6 bit page table index. */ movel #0x82c07760,%a3@ - .long 0xf0134000 /* pmove %a3@,%tc (enable the MMU) */ + pmove %a3@,%tc /* enable the MMU */ tstl %d0 jne 1f jmp %pc@(2f+0x80000000) 1: jmp 2f:w 2: movel %d2,%a5@(%d0:w) - .long 0xf0002400 /* pflusha */ + pflusha jmp LdoneMMUenable:w Lamimmu68040: + .chip 68040 lea 2f:w,%a0 movel %d5,%d0 andl #0xff000000,%d0 jne 1f lea %pc@(2f+0x80000000),%a0 1: orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0 - .long 0x4e7b0004 /* movec %d0,%itt0 */ - .long 0x4e7bd806 /* movec %a5,%urp */ - .long 0x4e7bd807 /* movec %a5,%srp */ - .word 0xf518 /* pflusha */ + movec %d0,%itt0 + movec %a5,%urp + movec %a5,%srp + pflusha movel #TC_ENABLE+TC_PAGE4K,%d0 /* * this value is also ok for the 68060, we don`t use the cache * mode/protection defaults */ - .long 0x4e7b0003 /* movec %d0,%tc (enable the MMU) */ + movec %d0,%tc /* enable the MMU */ jmp %a0@ 2: moveq #0,%d0 - .long 0x4e7b0004 /* movec %d0,%itt0 */ + movec %d0,%itt0 jmp LdoneMMUenable:w + .chip 68k Lmapphysnotamiga: #endif @@ -696,6 +735,7 @@ Lmapphysnotamiga: is_040_or_060(Latarimmu68040) + .chip 68030 lea %pc@(Lmmu),%a3 movel %d5,%d0 jne 1f @@ -706,7 +746,7 @@ Lmapphysnotamiga: jeq 2f orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0 movel %d0,%a3@ - .long 0xf0130800 /* pmove %a3@,%tt0 */ + pmove %a3@,%tt0 jra 3f /* tt0 doesn't work if physical and virtual address of kernel is in * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram) @@ -729,23 +769,25 @@ Lmapphysnotamiga: /* no limit, 4byte descriptors */ 3: movel #0x80000002,%a3@ movel %a5,%a3@(4) - .long 0xf0134800 /* pmove %a3@,%srp */ - .long 0xf0134c00 /* pmove %a3@,%crp */ - .long 0xf0002400 /* pflusha */ + pmove %a3@,%srp + pmove %a3@,%crp + pflusha /* * enable,super root enable,4096 byte pages,7 bit root index, * 7 bit pointer index, 6 bit page table index. */ movel #0x82c07760,%a3@ - .long 0xf0134000 /* pmove %a3@,%tc (enable the MMU) */ + pmove %a3@,%tc /* enable the MMU */ jmp %a0@ 4: clrl %a3@ - .long 0xf0130800 /* pmove %a3@,%tt0 */ + pmove %a3@,%tt0 jra LdoneMMUenable 5: movel %d2,%a1@ jra LdoneMMUenable + .chip 68k Latarimmu68040: + .chip 68040 movel %d5,%d0 jne 1f lea LdoneMMUenable:w,%a0 @@ -753,22 +795,22 @@ Latarimmu68040: 1: lea 3f:w,%a0 andl #0xff000000,%d0 /* logical address base */ orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0 - .long 0x4e7b0004 /* movec %d0,%itt0 */ + movec %d0,%itt0 2: nop - .word 0xf518 /* pflusha */ - .long 0x4e7bd807 /* movec %a5,%srp */ - .long 0x4e7bd806 /* movec %a5,%urp */ + pflusha + movec %a5,%srp + movec %a5,%urp movel #TC_ENABLE+TC_PAGE4K,%d0 /* * this value is also ok for the 68060, we don`t use the cache * mode/protection defaults */ - .long 0x4e7b0003 /* movec %d0,%tc (enable the MMU) */ + movec %d0,%tc /* enable the MMU */ jmp %a0@ 3: moveq #0,%d0 - .long 0x4e7b0004 /* movec %d0,%itt0 */ - tstl %a1 + movec %d0,%itt0 jra LdoneMMUenable + .chip 68k Lmapphysnotatari: #endif @@ -830,7 +872,9 @@ LdoneMMUenable: jra 1f Lcache680460: - .word 0xf4f8 /* cpusha %bc */ + .chip 68040 + cpusha %bc + .chip 68k is_060(Lcache68060) @@ -840,12 +884,14 @@ Lcache680460: jra 1f Lcache68060: + .chip 68060 movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0 /* MMU stuff works in copyback mode now, so enable the cache */ movec %d0,%cacr /* enable superscalar dispatch in PCR */ moveq #1,%d0 - .long 0x4e7b0808 /* movec d0,pcr */ + movec %d0,%pcr + .chip 68k 1: /* @@ -859,43 +905,26 @@ Lcache68060: jbsr SYMBOL_NAME(start_kernel) /* - * switch off mmu and exit + * Find a tag record in the bootinfo structure + * The bootinfo structure is located right after the kernel bss + * Returns: d0: size (-1 if not found) + * a0: data pointer (end-of-records if not found) */ - -#ifdef HACKER_KERNEL -ENTRY(kernel_exit) - lea 2f:w,%a0 - movel %pc@(Lkernel_start),%a0 - lea %a0@(2f:w),%a1 - movel %a1,%d0 - andl #0xff000000,%d0 - jne 1f - jmp %a0@(1f+0x80000000) -1: orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0 - .long 0x4e7b0004 /* movec %d0,%itt0 */ - jmp %a1@ +Lget_bi_record: + lea %pc@(SYMBOL_NAME(_end)),%a0 +1: tstw %a0@(BIR_tag) + jeq 3f + cmpw %a0@(BIR_tag),%d0 + jeq 2f + addw %a0@(BIR_size),%a0 + jra 1b 2: moveq #0,%d0 - .long 0x4e7b0003 /* movec %d0,%tc (disable the MMU) */ - .word 0xf518 /* pflusha */ - .long 0x4e7b0004 /* movec %d0,%itt0 */ - movec %d0,%cacr - .word 0xf4f8 /* cpusha %bc */ - - lea %pc@(SYMBOL_NAME(boot_info)),%a0 - jmp %a0@(BI_amiga_exit_func:w)@(0:w) -#endif - -/* - * Serial port output support. - */ -LSERPER = 0xdff032 -LSERDAT = 0xdff030 -LSERDATR = 0xdff018 -LNTSC_PERIOD = 371 -LPAL_PERIOD = 368 -LNTSC_ECLOCK = 7159090 -LSERIAL_CNTRL = 0xbfd000 -LSERIAL_DTR = 7 + movew %a0@(BIR_size),%d0 + lea %a0@(BIR_data),%a0 + rts +3: moveq #-1,%d0 + lea %a0@(BIR_size),%a0 + rts /* * Debug output support @@ -953,8 +982,18 @@ LMFP_UDR = 0xfffa2f #endif /* + * Serial port output support. + */ +LSERPER = 0xdff032 +LSERDAT = 0xdff030 +LSERDATR = 0xdff018 +LSERIAL_CNTRL = 0xbfd000 +LSERIAL_DTR = 7 + +/* * Initialize serial port hardware for 9600/8/1 * a0 thrashed + * Amiga d0 trashed * Atari d0 trashed (a1 in case of SCC) */ .even @@ -962,31 +1001,30 @@ Lserial_init: #ifdef CONFIG_AMIGA cmpil #MACH_AMIGA,%d4 jne 1f - lea %pc@(SYMBOL_NAME(boot_info)),%a0 bclr #LSERIAL_DTR,LSERIAL_CNTRL - movew #LNTSC_PERIOD,LSERPER - cmpl #LNTSC_ECLOCK,%a0@(BI_amiga_eclock) - jeq 9f - movew #LPAL_PERIOD,LSERPER + movew #BI_AMIGA_SERPER,%d0 + jbsr Lget_bi_record + movew %a0@,LSERPER jra 9f 1: #endif #ifdef CONFIG_ATARI cmpil #MACH_ATARI,%d4 jne 4f + movel %pc@(Liobase),%a1 #ifdef USE_PRINTER - bclr #0,LSTMFP_IERB - bclr #0,LSTMFP_DDR - moveb #LPSG_CONTROL,LPSG_SELECT - moveb #0xff,LPSG_WRITE - moveb #LPSG_IO_B,LPSG_SELECT - clrb LPSG_WRITE - moveb #LPSG_IO_A,LPSG_SELECT - moveb LPSG_READ,%d0 + bclr #0,%a1@(LSTMFP_IERB) + bclr #0,%a1@(LSTMFP_DDR) + moveb #LPSG_CONTROL,%a1@(LPSG_SELECT) + moveb #0xff,%a1@(LPSG_WRITE) + moveb #LPSG_IO_B,%a1@(LPSG_SELECT) + clrb %a1@(LPSG_WRITE) + moveb #LPSG_IO_A,%a1@(LPSG_SELECT) + moveb %a1@(LPSG_READ),%d0 bset #5,%d0 - moveb %d0,LPSG_WRITE + moveb %d0,%a1@(LPSG_WRITE) #elif defined(USE_SCC) - lea LSCC_CTRL_B,%a0 + lea %a1@(LSCC_CTRL_B),%a0 lea %pc@(scc_initable:w),%a1 2: moveb %a1@+,%d0 jmi 3f @@ -995,12 +1033,12 @@ Lserial_init: jra 2b 3: clrb %a0@ #elif defined(USE_MFP) - bclr #1,LMFP_TSR - moveb #0x88,LMFP_UCR - andb #0x70,LMFP_TDCDR - moveb #2,LMFP_TDDR - orb #1,LMFP_TDCDR - bset #1,LMFP_TSR + bclr #1,%a1@(LMFP_TSR) + moveb #0x88,%a1@(LMFP_UCR) + andb #0x70,%a1@(LMFP_TDCDR) + moveb #2,%a1@(LMFP_TDDR) + orb #1,%a1@(LMFP_TDCDR) + bset #1,%a1@(LMFP_TSR) #endif 4: #endif @@ -1073,8 +1111,6 @@ Lserial_puts: /* * Output number in d7 in hex notation on serial port. - * d0-d2 trashed. - * d7 trashed. */ Lserial_putnum: @@ -1103,7 +1139,7 @@ Lshowtest: putc('=') putn(%a1) - .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0 + ptestr #5,%a1@,#7,%a0 putc('D') putc('A') @@ -1117,7 +1153,7 @@ Lshowtest: putc('S') putc('=') lea %pc@(Lmmu),%a0 - .long 0xf0106200 | pmove %psr,%a0@ + pmove %psr,%a0@ clrl %d7 movew %a0@,%d7 jbsr Lserial_putnum @@ -1128,10 +1164,6 @@ Lshowtest: .data .even -#ifdef HACKER_KERNEL -Lkernel_start: - .long 0 -#endif Lcustom: Liobase: .long 0 @@ -1142,5 +1174,7 @@ SYMBOL_NAME_LABEL(availmem) .long 0 SYMBOL_NAME_LABEL(is_medusa) .long 0 +SYMBOL_NAME_LABEL(is_hades) + .long 0 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) .long 0 diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 8656b2979..f49c38cd3 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -50,6 +50,24 @@ volatile unsigned int num_spurious; #define NUM_IRQ_NODES 100 static irq_node_t nodes[NUM_IRQ_NODES]; +unsigned int local_irq_count[NR_CPUS]; + +int __m68k_bh_counter; + +static void dummy_enable_irq(unsigned int irq); +static void dummy_disable_irq(unsigned int irq); +static int dummy_request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id); +static void dummy_free_irq(unsigned int irq, void *dev_id); + +void (*enable_irq) (unsigned int) = dummy_enable_irq; +void (*disable_irq) (unsigned int) = dummy_disable_irq; + +int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *), + unsigned long, const char *, void *) = dummy_request_irq; +void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; + /* * void init_IRQ(void) * @@ -92,14 +110,30 @@ irq_node_t *new_irq_node(void) return NULL; } -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) +/* + * We will keep these functions until I have convinced Linus to move + * the declaration of them from include/linux/sched.h to + * include/asm/irq.h. + */ +int request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) { - if (irq & IRQ_MACHSPEC) - return mach_request_irq(IRQ_IDX(irq), handler, flags, devname, dev_id); + return mach_request_irq(irq, handler, flags, devname, dev_id); +} + +void free_irq(unsigned int irq, void *dev_id) +{ + mach_free_irq(irq, dev_id); +} +int sys_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ if (irq < IRQ1 || irq > IRQ7) { - printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); + printk("%s: Incorrect IRQ %d from %s\n", + __FUNCTION__, irq, devname); return -ENXIO; } @@ -109,7 +143,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) __FUNCTION__, irq, irq_list[irq].devname); return -EBUSY; } - if (flags & IRQ_FLG_REPLACE) { + if (!(flags & IRQ_FLG_REPLACE)) { printk("%s: %s can't replace IRQ %d from %s\n", __FUNCTION__, devname, irq, irq_list[irq].devname); return -EBUSY; @@ -122,13 +156,8 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) return 0; } -void free_irq(unsigned int irq, void *dev_id) +void sys_free_irq(unsigned int irq, void *dev_id) { - if (irq & IRQ_MACHSPEC) { - mach_free_irq(IRQ_IDX(irq), dev_id); - return; - } - if (irq < IRQ1 || irq > IRQ7) { printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); return; @@ -157,31 +186,42 @@ int probe_irq_off (unsigned long irqs) return 0; } -void enable_irq(unsigned int irq) +static void dummy_enable_irq(unsigned int irq) +{ + printk("calling uninitialized enable_irq()\n"); +} + +static void dummy_disable_irq(unsigned int irq) +{ + printk("calling uninitialized disable_irq()\n"); +} + +static int dummy_request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) { - if ((irq & IRQ_MACHSPEC) && mach_enable_irq) - mach_enable_irq(IRQ_IDX(irq)); + printk("calling uninitialized request_irq()\n"); + return 0; } -void disable_irq(unsigned int irq) +static void dummy_free_irq(unsigned int irq, void *dev_id) { - if ((irq & IRQ_MACHSPEC) && mach_disable_irq) - mach_disable_irq(IRQ_IDX(irq)); + printk("calling uninitialized disable_irq()\n"); } asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) { - if (vec < VEC_INT1 || vec > VEC_INT7) { + if (vec >= VEC_INT1 && vec <= VEC_INT7) { + vec -= VEC_SPUR; + kstat.interrupts[vec]++; + irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); + } else { if (mach_process_int) mach_process_int(vec, fp); else panic("Can't process interrupt vector %ld\n", vec); return; } - - vec -= VEC_SPUR; - kstat.interrupts[vec]++; - irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); } int get_irq_list(char *buf) diff --git a/arch/m68k/kernel/ksyms.c b/arch/m68k/kernel/ksyms.c deleted file mode 100644 index bf067c782..000000000 --- a/arch/m68k/kernel/ksyms.c +++ /dev/null @@ -1,89 +0,0 @@ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/linkage.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/user.h> -#include <linux/elfcore.h> - -#include <asm/setup.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/semaphore.h> - -asmlinkage long long __ashrdi3 (long long, int); -extern char m68k_debug_device[]; - -#ifdef CONFIG_ATARI -extern void mach_atari_syms_export (void); -#endif -#ifdef CONFIG_AMIGA -extern void mach_amiga_syms_export (void); -#endif -#ifdef CONFIG_MAC -extern void mach_mac_syms_export (void); -#endif - -extern void dump_thread(struct pt_regs *, struct user *); -extern int dump_fpu(elf_fpregset_t *); - -static struct symbol_table arch_symbol_table = { -#include <linux/symtab_begin.h> - /* platform dependent support */ - - X(memcmp), - X(boot_info), - X(m68k_is040or060), - X(cache_push), - X(cache_push_v), - X(cache_clear), - X(mm_vtop), - X(mm_ptov), - X(mm_end_of_chunk), - X(m68k_debug_device), - X(request_irq), - X(free_irq), - X(dump_fpu), - X(dump_thread), - X(strnlen), - X(strrchr), - - /* The following are special because they're not called - explicitly (the C compiler generates them). Fortunately, - their interface isn't gonna change any time soon now, so - it's OK to leave it out of version control. */ - XNOVERS(__ashrdi3), - XNOVERS(memcpy), - XNOVERS(memset), - - XNOVERS(__down_failed), - XNOVERS(__up_wakeup), - -#include <linux/symtab_end.h> -}; - -void arch_syms_export(void) -{ - register_symtab(&arch_symbol_table); - - switch (boot_info.machtype) { -#ifdef CONFIG_ATARI - case MACH_ATARI: - mach_atari_syms_export(); - break; -#endif -#ifdef CONFIG_AMIGA - case MACH_AMIGA: - mach_amiga_syms_export(); - break; -#endif -#ifdef CONFIG_MAC - case MACH_MAC: - mach_mac_syms_export(); - break; -#endif - default: - break; - } -} diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c new file mode 100644 index 000000000..3138d99df --- /dev/null +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -0,0 +1,57 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/linkage.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/user.h> +#include <linux/elfcore.h> + +#include <asm/setup.h> +#include <asm/machdep.h> +#include <asm/pgtable.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <asm/checksum.h> +#include <asm/hardirq.h> + +asmlinkage long long __ashrdi3 (long long, int); +extern char m68k_debug_device[]; + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(elf_fpregset_t *); + +/* platform dependent support */ + +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(m68k_machtype); +EXPORT_SYMBOL(m68k_cputype); +EXPORT_SYMBOL(m68k_is040or060); +EXPORT_SYMBOL(cache_push); +EXPORT_SYMBOL(cache_push_v); +EXPORT_SYMBOL(cache_clear); +EXPORT_SYMBOL(mm_vtop); +EXPORT_SYMBOL(mm_ptov); +EXPORT_SYMBOL(mm_end_of_chunk); +EXPORT_SYMBOL(m68k_debug_device); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(local_irq_count); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* The following are special because they're not called + explicitly (the C compiler generates them). Fortunately, + their interface isn't gonna change any time soon now, so + it's OK to leave it out of version control. */ +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); + +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__up_wakeup); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index cc9664b5f..5422831a8 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -14,12 +14,15 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> #include <linux/malloc.h> #include <linux/user.h> #include <linux/a.out.h> +#include <linux/reboot.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -34,21 +37,40 @@ asmlinkage void ret_from_exception(void); */ asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ + current->priority = -100; current->counter = -100; for (;;) schedule(); + ret = 0; +out: + unlock_kernel(); + return ret; } -void hard_reset_now(void) +void machine_restart(char * __unused) { if (mach_reset) mach_reset(); } +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ +#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) + apm_set_power_state(APM_STATE_OFF); +#endif +} + void show_regs(struct pt_regs * regs) { printk("\n"); @@ -86,27 +108,36 @@ void flush_thread(void) asmlinkage int m68k_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), regs); + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, rdusp(), regs); + unlock_kernel(); + return ret; } asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; + int ret; + lock_kernel(); /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags, newsp, regs); + ret = do_fork(clone_flags, newsp, regs); + unlock_kernel(); + return ret; } void release_thread(struct task_struct *dead_task) { } -void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; @@ -145,11 +176,13 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, : "memory"); /* Restore the state in case the fpu was busy */ asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0])); + + return 0; } /* Fill in the fpu structure for a core dump. */ -int dump_fpu (struct user_m68kfp_struct *fpu) +int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) { char fpustate[216]; @@ -187,7 +220,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) if (dump->start_stack < TASK_SIZE) dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - dump->u_ar0 = (struct pt_regs *)(((int)(&dump->regs)) -((int)(dump))); + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); sw = ((struct switch_stack *)regs) - 1; dump->regs.d1 = regs->d1; dump->regs.d2 = regs->d2; @@ -210,7 +243,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->regs.pc = regs->pc; dump->regs.fmtvec = (regs->format << 12) | regs->vector; /* dump floating point stuff */ - dump->u_fpvalid = dump_fpu (&dump->m68kfp); + dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); } /* @@ -222,10 +255,13 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp) char * filename; struct pt_regs *regs = (struct pt_regs *) &name; + lock_kernel(); error = getname(name, &filename); if (error) - return error; + goto out; error = do_execve(filename, argv, envp, regs); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index dc48a2ec5..70e341b31 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -14,6 +14,8 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> @@ -322,25 +324,28 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - struct user * dummy; - - dummy = NULL; + int ret; + lock_kernel(); + ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; + ret = -EPERM; if (request == PTRACE_ATTACH) { if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || @@ -348,10 +353,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->gid != child->egid) || (current->gid != child->sgid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -359,39 +364,42 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - return -ESRCH; + goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) - return -ESRCH; + goto out; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); - if (res < 0) - return res; - return put_user(tmp, (unsigned long *) data); + ret = read_long(child, addr, &tmp); + if (ret >= 0) + ret = put_user(tmp, (unsigned long *) data); + goto out; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; tmp = 0; /* Default return condition */ addr = addr >> 2; /* temporary hack. */ + ret = -EIO; if (addr < 19) { tmp = get_reg(child, addr); if (addr == PT_SR) @@ -400,23 +408,26 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else if (addr >= 21 && addr < 49) tmp = child->tss.fp[addr - 21]; else - return -EIO; - return put_user(tmp,(unsigned long *) data); + goto out; + ret = put_user(tmp,(unsigned long *) data); + goto out; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + ret = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; addr = addr >> 2; /* temporary hack. */ if (addr == PT_ORIG_D0) - return -EIO; + goto out; if (addr == PT_SR) { data &= SR_MASK; data <<= 16; @@ -424,22 +435,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } if (addr < 19) { if (put_reg(child, addr, data)) - return -EIO; - return 0; + goto out; + ret = 0; + goto out; } if (addr >= 21 && addr < 48) { child->tss.fp[addr - 21] = data; - return 0; + ret = 0; } - return -EIO; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -449,7 +462,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + ret = 0; + goto out; } /* @@ -460,21 +474,23 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_KILL: { long tmp; + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; + goto out; wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + goto out; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~PF_TRACESYS; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); put_reg(child, PT_SR, tmp); @@ -482,14 +498,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -499,19 +517,25 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -524,5 +548,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; - return; +out: + unlock_kernel(); } diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 58987d1cc..dfd91d0d4 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -19,19 +19,26 @@ #include <linux/errno.h> #include <linux/string.h> +#include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/irq.h> #include <asm/machdep.h> -#include <asm/amigatypes.h> +#ifdef CONFIG_AMIGA #include <asm/amigahw.h> +#endif +#ifdef CONFIG_ATARI +#include <asm/atarihw.h> +#endif #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> #include <asm/pgtable.h> #endif -struct bootinfo boot_info = {0,}; -int bisize = sizeof boot_info; +u_long m68k_machtype; +u_long m68k_cputype; +u_long m68k_fputype; +u_long m68k_mmutype; int m68k_is040or060 = 0; @@ -40,12 +47,13 @@ char m68k_debug_device[6] = ""; extern int end; extern unsigned long availmem; -char saved_command_line[CL_SIZE]; +int m68k_num_memory = 0; +struct mem_info m68k_memory[NUM_MEMINFO]; -/* setup some dummy routines */ -static void dummy_waitbut(void) -{ -} +static struct mem_info m68k_ramdisk = { 0, 0 }; + +static char m68k_command_line[CL_SIZE]; +char saved_command_line[CL_SIZE]; void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)); /* machine dependent keyboard functions */ @@ -55,11 +63,8 @@ void (*mach_kbd_leds) (unsigned int) = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void); void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; -int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *), - unsigned long, const char *, void *); -int (*mach_free_irq) (unsigned int, void *); -void (*mach_enable_irq) (unsigned int) = NULL; -void (*mach_disable_irq) (unsigned int) = NULL; +void (*mach_get_model) (char *model) = NULL; +int (*mach_get_hardware_list) (char *buffer) = NULL; int (*mach_get_irq_list) (char *) = NULL; void (*mach_process_int) (int, struct pt_regs *) = NULL; /* machine dependent timer functions */ @@ -67,12 +72,9 @@ unsigned long (*mach_gettimeoffset) (void); void (*mach_gettod) (int*, int*, int*, int*, int*, int*); int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; -void (*mach_mksound)( unsigned int count, unsigned int ticks ); void (*mach_reset)( void ); -void (*waitbut)(void) = dummy_waitbut; struct fb_info *(*mach_fb_init)(long *); long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -void (*mach_debug_init)(void); void (*mach_video_setup) (char *, int *); #ifdef CONFIG_BLK_DEV_FD int (*mach_floppy_init) (void) = NULL; @@ -80,39 +82,75 @@ void (*mach_floppy_setup) (char *, int *) = NULL; void (*mach_floppy_eject) (void) = NULL; #endif +extern int amiga_parse_bootinfo(const struct bi_record *); +extern int atari_parse_bootinfo(const struct bi_record *); + extern void config_amiga(void); extern void config_atari(void); extern void config_mac(void); extern void config_sun3(void); +extern void config_apollo(void); -extern void register_console(void (*proc)(const char *)); -extern void ami_serial_print (const char *str); -extern void ata_serial_print (const char *str); +#define MASK_256K 0xfffc0000 -extern void (*kd_mksound)(unsigned int, unsigned int); -extern void amiga_get_model(char *model); -extern void atari_get_model(char *model); -extern void mac_get_model(char *model); -extern int amiga_get_hardware_list(char *buffer); -extern int atari_get_hardware_list(char *buffer); -extern int mac_get_hardware_list(char *buffer); +static void m68k_parse_bootinfo(const struct bi_record *record) +{ + while (record->tag != BI_LAST) { + int unknown = 0; + const u_long *data = record->data; + switch (record->tag) { + case BI_MACHTYPE: + case BI_CPUTYPE: + case BI_FPUTYPE: + case BI_MMUTYPE: + /* Already set up by head.S */ + break; -#define MASK_256K 0xfffc0000 + case BI_MEMCHUNK: + if (m68k_num_memory < NUM_MEMINFO) { + m68k_memory[m68k_num_memory].addr = data[0]; + m68k_memory[m68k_num_memory].size = data[1]; + m68k_num_memory++; + } else + printk("m68k_parse_bootinfo: too many memory chunks\n"); + break; -void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) + case BI_RAMDISK: + m68k_ramdisk.addr = data[0]; + m68k_ramdisk.size = data[1]; + break; + + case BI_COMMAND_LINE: + strncpy(m68k_command_line, (const char *)data, CL_SIZE); + m68k_command_line[CL_SIZE-1] = '\0'; + break; + + default: + if (MACH_IS_AMIGA) + unknown = amiga_parse_bootinfo(record); + else if (MACH_IS_ATARI) + unknown = atari_parse_bootinfo(record); + else + unknown = 1; + } + if (unknown) + printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", + record->tag); + record = (struct bi_record *)((u_long)record+record->size); + } +} + +void setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p) { unsigned long memory_start, memory_end; extern int _etext, _edata, _end; int i; char *p, *q; - if (MACH_IS_AMIGA) - register_console(ami_serial_print); - - if (MACH_IS_ATARI) - register_console(ata_serial_print); + /* The bootinfo is located right after the kernel bss */ + m68k_parse_bootinfo((const struct bi_record *)&_end); if (CPU_IS_040) m68k_is040or060 = 4; @@ -120,7 +158,7 @@ void setup_arch(char **cmdline_p, m68k_is040or060 = 6; /* clear the fpu if we have one */ - if (boot_info.cputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { + if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; asm __volatile__ ("frestore %0" : : "m" (zero)); } @@ -128,15 +166,15 @@ void setup_arch(char **cmdline_p, memory_start = availmem; memory_end = 0; - for (i = 0; i < boot_info.num_memory; i++) - memory_end += boot_info.memory[i].size & MASK_256K; + for (i = 0; i < m68k_num_memory; i++) + memory_end += m68k_memory[i].size & MASK_256K; init_task.mm->start_code = 0; init_task.mm->end_code = (unsigned long) &_etext; init_task.mm->end_data = (unsigned long) &_edata; init_task.mm->brk = (unsigned long) &_end; - *cmdline_p = boot_info.command_line; + *cmdline_p = m68k_command_line; memcpy(saved_command_line, *cmdline_p, CL_SIZE); /* Parse the command line for arch-specific options. @@ -166,7 +204,7 @@ void setup_arch(char **cmdline_p, *memory_start_p = memory_start; *memory_end_p = memory_end; - switch (boot_info.machtype) { + switch (m68k_machtype) { #ifdef CONFIG_AMIGA case MACH_AMIGA: config_amiga(); @@ -187,21 +225,26 @@ void setup_arch(char **cmdline_p, config_sun3(); break; #endif +#ifdef CONFIG_APOLLO + case MACH_APOLLO: + config_apollo(); + break; +#endif default: panic ("No configuration setup"); } #ifdef CONFIG_BLK_DEV_INITRD - if (boot_info.ramdisk_size) { - initrd_start = PTOV (boot_info.ramdisk_addr); - initrd_end = initrd_start + boot_info.ramdisk_size * 1024; + if (m68k_ramdisk.size) { + initrd_start = PTOV (m68k_ramdisk.addr); + initrd_end = initrd_start + m68k_ramdisk.size; } #endif } int get_cpuinfo(char * buffer) { - char *cpu, *mmu, *fpu; + const char *cpu, *mmu, *fpu; u_long clockfreq, clockfactor; #define LOOP_CYCLES_68020 (8) @@ -211,33 +254,49 @@ int get_cpuinfo(char * buffer) if (CPU_IS_020) { cpu = "68020"; - mmu = "68851"; clockfactor = LOOP_CYCLES_68020; } else if (CPU_IS_030) { - cpu = mmu = "68030"; + cpu = "68030"; clockfactor = LOOP_CYCLES_68030; } else if (CPU_IS_040) { - cpu = mmu = "68040"; + cpu = "68040"; clockfactor = LOOP_CYCLES_68040; } else if (CPU_IS_060) { - cpu = mmu = "68060"; + cpu = "68060"; clockfactor = LOOP_CYCLES_68060; } else { - cpu = mmu = "680x0"; + cpu = "680x0"; clockfactor = 0; } - if (boot_info.cputype & FPU_68881) + if (m68k_fputype & FPU_68881) fpu = "68881"; - else if (boot_info.cputype & FPU_68882) + else if (m68k_fputype & FPU_68882) fpu = "68882"; - else if (boot_info.cputype & FPU_68040) + else if (m68k_fputype & FPU_68040) fpu = "68040"; - else if (boot_info.cputype & FPU_68060) + else if (m68k_fputype & FPU_68060) fpu = "68060"; + else if (m68k_fputype & FPU_SUNFPA) + fpu = "Sun FPA"; else fpu = "none"; + if (m68k_mmutype & MMU_68851) + mmu = "68851"; + else if (m68k_mmutype & MMU_68030) + mmu = "68030"; + else if (m68k_mmutype & MMU_68040) + mmu = "68040"; + else if (m68k_mmutype & MMU_68060) + mmu = "68060"; + else if (m68k_mmutype & MMU_SUN3) + mmu = "Sun-3"; + else if (m68k_mmutype & MMU_APOLLO) + mmu = "Apollo"; + else + mmu = "unknown"; + clockfreq = loops_per_sec*clockfactor; return(sprintf(buffer, "CPU:\t\t%s\n" @@ -260,48 +319,19 @@ int get_hardware_list(char *buffer) u_long mem; int i; - switch (boot_info.machtype) { -#ifdef CONFIG_AMIGA - case MACH_AMIGA: - amiga_get_model(model); - break; -#endif -#ifdef CONFIG_ATARI - case MACH_ATARI: - atari_get_model(model); - break; -#endif -#ifdef CONFIG_MAC - case MACH_MAC: - mac_get_model(model); - break; -#endif - default: - strcpy(model, "Unknown m68k"); - } /* boot_info.machtype */ + if (mach_get_model) + mach_get_model(model); + else + strcpy(model, "Unknown m68k"); len += sprintf(buffer+len, "Model:\t\t%s\n", model); len += get_cpuinfo(buffer+len); - for (mem = 0, i = 0; i < boot_info.num_memory; i++) - mem += boot_info.memory[i].size; + for (mem = 0, i = 0; i < m68k_num_memory; i++) + mem += m68k_memory[i].size; len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); - switch (boot_info.machtype) { -#ifdef CONFIG_AMIGA - case MACH_AMIGA: - len += amiga_get_hardware_list(buffer+len); - break; -#endif -#ifdef CONFIG_ATARI - case MACH_ATARI: - len += atari_get_hardware_list(buffer+len); - break; -#endif -#ifdef CONFIG_MAC - case MACH_MAC: - break; -#endif - } /* boot_info.machtype */ + if (mach_get_hardware_list) + len += mach_get_hardware_list(buffer+len); return(len); } diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 0d2a372f9..c60e82b0b 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -127,26 +127,26 @@ asmlinkage int do_sigreturn(unsigned long __unused) /* Verify the frame format. */ if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version)) goto badframe; - if (boot_info.cputype & FPU_68881) + if (m68k_fputype & FPU_68881) { if (context.sc_fpstate[1] != 0x18 && context.sc_fpstate[1] != 0xb4) goto badframe; } - else if (boot_info.cputype & FPU_68882) + else if (m68k_fputype & FPU_68882) { if (context.sc_fpstate[1] != 0x38 && context.sc_fpstate[1] != 0xd4) goto badframe; } - else if (boot_info.cputype & FPU_68040) + else if (m68k_fputype & FPU_68040) { if (!(context.sc_fpstate[1] == 0x00 || context.sc_fpstate[1] == 0x28 || context.sc_fpstate[1] == 0x60)) goto badframe; } - else if (boot_info.cputype & FPU_68060) + else if (m68k_fputype & FPU_68060) { if (!(context.sc_fpstate[3] == 0x00 || context.sc_fpstate[3] == 0x60 || @@ -174,7 +174,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) if (context.sc_usp != fp+fsize) current->flags &= ~PF_ONSIGSTK; - + /* OK. Make room on the supervisor stack for the extra junk, * if necessary. */ @@ -200,7 +200,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) " .align 4\n" " .long 2b,4b\n" " .long 3b,4b\n" - ".text" + ".previous" : /* no outputs, it doesn't ever return */ : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), "n" (frame_offset), "a" (fp) @@ -261,8 +261,8 @@ badframe: #define UFRAME_SIZE(fs) (sizeof(struct sigcontext)/4 + 6 + fs/4) -static void setup_frame (struct sigaction * sa, struct pt_regs *regs, - int signr, unsigned long oldmask) +static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs, + int signr, unsigned long oldmask) { struct sigcontext context; unsigned long *frame, *tframe; @@ -291,20 +291,23 @@ static void setup_frame (struct sigaction * sa, struct pt_regs *regs, tframe = frame; /* return address points to code on stack */ - put_user((ulong)(frame+4), tframe); tframe++; + + if(put_user((ulong)(frame+4), tframe)) + do_exit(SIGSEGV); + tframe++; if (current->exec_domain && current->exec_domain->signal_invmap) - put_user(current->exec_domain->signal_invmap[signr], tframe); + __put_user(current->exec_domain->signal_invmap[signr], tframe); else - put_user(signr, tframe); + __put_user(signr, tframe); tframe++; - put_user(regs->vector, tframe); tframe++; + __put_user(regs->vector, tframe); tframe++; /* "scp" parameter. points to sigcontext */ - put_user((ulong)(frame+6), tframe); tframe++; + __put_user((ulong)(frame+6), tframe); tframe++; /* set up the return code... */ - put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ - put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ + __put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ + __put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ /* Flush caches so the instructions will be correctly executed. (MA) */ cache_push_v ((unsigned long)frame, (int)tframe - (int)frame); @@ -360,9 +363,9 @@ static void setup_frame (struct sigaction * sa, struct pt_regs *regs, /* * OK, we're invoking a handler - */ -static void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs) + */ +static inline void handle_signal(unsigned long signr, struct sigaction *sa, + unsigned long oldmask, struct pt_regs *regs) { /* are we from a system call? */ if (regs->orig_d0 >= 0) { @@ -482,7 +485,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs) continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & SA_NOCLDSTOP)) notify_parent(current); schedule(); diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index d187e3d57..5acfd1cbd 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -9,6 +9,8 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/sem.h> #include <linux/msg.h> #include <linux/shm.h> @@ -31,15 +33,14 @@ asmlinkage int sys_pipe(unsigned long * fildes) int fd[2]; int error; - error = verify_area(VERIFY_WRITE,fildes,8); - if (error) - return error; + lock_kernel(); error = do_pipe(fd); - if (error) - return error; - put_user(fd[0],0+fildes); - put_user(fd[1],1+fildes); - return 0; + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + unlock_kernel(); + return error; } /* @@ -64,16 +65,20 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) struct file * file = NULL; struct mmap_arg_struct a; - error = verify_area(VERIFY_READ, arg, sizeof(*arg)); - if (error) - return error; - copy_from_user(&a, arg, sizeof(a)); + lock_kernel(); + error = -EFAULT; + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) - return -EBADF; + goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); +out: + unlock_kernel(); return error; } @@ -92,6 +97,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; + /* sys_select() does the appropriate kernel locking */ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } @@ -102,7 +108,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; @@ -110,46 +116,57 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) - return err; - get_user(fourth.__pad, (void **)ptr); - return sys_semctl (first, second, third, fourth); + goto out; + if ((ret = get_user(fourth.__pad, (void **) ptr))) + goto out; + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; + ret = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + ret = -EFAULT; if (copy_from_user (&tmp, ptr, sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -157,30 +174,30 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) - return err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; - put_user (raddr, (ulong *) third); - return 0; - } - case 1: /* iBCS2 emulator entry point */ - if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; + ret = put_user (raddr, (ulong *) third); + goto out; + } } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + ret = -EINVAL; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) @@ -192,15 +209,14 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) in VALID whether the virtual address is actually mapped. */ #define virt_to_phys_040(vaddr, paddr, valid) \ { \ - register unsigned long _tmp1 __asm__ ("a0") = (vaddr); \ - register unsigned long _tmp2 __asm__ ("d0"); \ unsigned long _mmusr; \ \ - __asm__ __volatile__ (".word 0xf568 /* ptestr (%1) */\n\t" \ - ".long 0x4e7a0805 /* movec %%mmusr,%0 */" \ - : "=d" (_tmp2) \ - : "a" (_tmp1)); \ - _mmusr = _tmp2; \ + __asm__ __volatile__ (".chip 68040\n\t" \ + "ptestr (%1)\n\t" \ + "movec %%mmusr,%0\n\t" \ + ".chip 68k" \ + : "=r" (_mmusr) \ + : "a" (vaddr)); \ if (!(_mmusr & MMU_R_040)) \ (valid) = 0; \ else \ @@ -224,16 +240,22 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) case FLUSH_CACHE_DATA: /* This nop is needed for some broken versions of the 68040. */ __asm__ __volatile__ ("nop\n\t" - ".word 0xf478 /* cpusha %%dc */"); + ".chip 68040\n\t" + "cpusha %dc\n\t" + ".chip 68k"); break; case FLUSH_CACHE_INSN: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4b8 /* cpusha %%ic */"); + ".chip 68040\n\t" + "cpusha %ic\n\t" + ".chip 68k"); break; default: case FLUSH_CACHE_BOTH: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4f8 /* cpusha %%bc */"); + ".chip 68040\n\t" + "cpusha %bc\n\t" + ".chip 68k"); break; } break; @@ -254,23 +276,28 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) } while (len--) { - register unsigned long tmp __asm__ ("a0") = paddr; switch (cache) { case FLUSH_CACHE_DATA: __asm__ __volatile__ ("nop\n\t" - ".word 0xf468 /* cpushl %%dc,(%0) */" - : : "a" (tmp)); + ".chip 68040\n\t" + "cpushl %%dc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; case FLUSH_CACHE_INSN: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4a8 /* cpushl %%ic,(%0) */" - : : "a" (tmp)); + ".chip 68040\n\t" + "cpushl %%ic,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4e8 /* cpushl %%bc,(%0) */" + ".chip 68040\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" : : "a" (paddr)); break; } @@ -302,28 +329,32 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) case FLUSH_SCOPE_PAGE: for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) { - register unsigned long tmp __asm__ ("a0"); virt_to_phys_040 (addr, paddr, valid); if (!valid) continue; - tmp = paddr; switch (cache) { case FLUSH_CACHE_DATA: __asm__ __volatile__ ("nop\n\t" - ".word 0xf470 /* cpushp %%dc,(%0) */" - : : "a" (tmp)); + ".chip 68040\n\t" + "cpushp %%dc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; case FLUSH_CACHE_INSN: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4b0 /* cpushp %%ic,(%0) */" - : : "a" (tmp)); + ".chip 68040\n\t" + "cpushp %%ic,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH: __asm__ __volatile__ ("nop\n\t" - ".word 0xf4f0 /* cpushp %%bc,(%0) */" - : : "a" (tmp)); + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; } } @@ -334,13 +365,12 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) #define virt_to_phys_060(vaddr, paddr, valid) \ { \ - register unsigned long _tmp __asm__ ("a0") = (vaddr); \ - \ - __asm__ __volatile__ (".word 0xf5c8 /* plpar (%1) */" \ - : "=a" (_tmp) \ - : "0" (_tmp)); \ + __asm__ __volatile__ (".chip 68060\n\t" \ + "plpar (%0)\n\t" \ + ".chip 68k" \ + : "=a" (paddr) \ + : "0" (vaddr)); \ (valid) = 1; /* XXX */ \ - (paddr) = _tmp; \ } static inline int @@ -355,17 +385,23 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) switch (cache) { case FLUSH_CACHE_DATA: - __asm__ __volatile__ (".word 0xf478 /* cpusha %%dc */\n\t" - ".word 0xf458 /* cinva %%dc */"); + __asm__ __volatile__ (".chip 68060\n\t" + "cpusha %dc\n\t" + "cinva %dc\n\t" + ".chip 68k"); break; case FLUSH_CACHE_INSN: - __asm__ __volatile__ (".word 0xf4b8 /* cpusha %%ic */\n\t" - ".word 0xf498 /* cinva %%ic */"); + __asm__ __volatile__ (".chip 68060\n\t" + "cpusha %ic\n\t" + "cinva %ic\n\t" + ".chip 68k"); break; default: case FLUSH_CACHE_BOTH: - __asm__ __volatile__ (".word 0xf4f8 /* cpusha %%bc */\n\t" - ".word 0xf4d8 /* cinva %%bc */"); + __asm__ __volatile__ (".chip 68060\n\t" + "cpusha %bc\n\t" + "cinva %bc\n\t" + ".chip 68k"); break; } break; @@ -386,23 +422,28 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) } while (len--) { - register unsigned long tmp __asm__ ("a0") = paddr; switch (cache) { case FLUSH_CACHE_DATA: - __asm__ __volatile__ (".word 0xf468 /* cpushl %%dc,(%0) */\n\t" - ".word 0xf448 /* cinv %%dc,(%0) */" - : : "a" (tmp)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%dc,(%0)\n\t" + "cinvl %%dc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; case FLUSH_CACHE_INSN: - __asm__ __volatile__ (".word 0xf4a8 /* cpushl %%ic,(%0) */\n\t" - ".word 0xf488 /* cinv %%ic,(%0) */" - : : "a" (tmp)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%ic,(%0)\n\t" + "cinvl %%ic,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH: - __asm__ __volatile__ (".word 0xf4e8 /* cpushl %%bc,(%0) */\n\t" - ".word 0xf4c8 /* cinv %%bc,(%0) */" + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%bc,(%0)\n\t" + "cinvl %%bc,(%0)\n\t" + ".chip 68k" : : "a" (paddr)); break; } @@ -434,28 +475,32 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) case FLUSH_SCOPE_PAGE: for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) { - register unsigned long tmp __asm__ ("a0"); virt_to_phys_060 (addr, paddr, valid); if (!valid) continue; - tmp = paddr; switch (cache) { case FLUSH_CACHE_DATA: - __asm__ __volatile__ (".word 0xf470 /* cpushp %%dc,(%0) */\n\t" - ".word 0xf450 /* cinv %%dc,(%0) */" - : : "a" (tmp)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushp %%dc,(%0)\n\t" + "cinvp %%dc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; case FLUSH_CACHE_INSN: - __asm__ __volatile__ (".word 0xf4b0 /* cpushp %%ic,(%0) */\n\t" - ".word 0xf490 /* cinv %%ic,(%0) */" - : : "a" (tmp)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushp %%ic,(%0)\n\t" + "cinvp %%ic,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; default: case FLUSH_CACHE_BOTH: - __asm__ __volatile__ (".word 0xf4f0 /* cpushp %%bc,(%0) */\n\t" - ".word 0xf4d0 /* cinv %%bc,(%0) */" - : : "a" (tmp)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushp %%bc,(%0)\n\t" + "cinvp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); break; } } @@ -468,41 +513,63 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) asmlinkage int sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) { - struct vm_area_struct *vma; + struct vm_area_struct *vma; + int ret = -EINVAL; - if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL - || cache & ~FLUSH_CACHE_BOTH) - return -EINVAL; + lock_kernel(); + if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || + cache & ~FLUSH_CACHE_BOTH) + goto out; - if (scope == FLUSH_SCOPE_ALL) - { - /* Only the superuser may flush the whole cache. */ - if (!suser ()) - return -EPERM; - } - else - { - /* Verify that the specified address region actually belongs to - this process. */ - vma = find_vma (current->mm, addr); - if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) - return -EINVAL; - } + if (scope == FLUSH_SCOPE_ALL) { + /* Only the superuser may flush the whole cache. */ + ret = -EPERM; + if (!suser ()) + goto out; + } else { + /* Verify that the specified address region actually belongs to + * this process. + */ + vma = find_vma (current->mm, addr); + ret = -EINVAL; + if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) + goto out; + } - if (CPU_IS_020_OR_030) { - /* Always flush the whole cache, everything else would not be - worth the hassle. */ - __asm__ __volatile__ - ("movec %%cacr, %%d0\n\t" - "or %0, %%d0\n\t" - "movec %%d0, %%cacr" - : /* no outputs */ - : "di" ((cache & FLUSH_CACHE_INSN ? 8 : 0) - | (cache & FLUSH_CACHE_DATA ? 0x800 : 0)) - : "d0"); - return 0; - } else if (CPU_IS_040) - return cache_flush_040 (addr, scope, cache, len); - else if (CPU_IS_060) - return cache_flush_060 (addr, scope, cache, len); + if (CPU_IS_020_OR_030) { + if (scope == FLUSH_SCOPE_LINE) { + unsigned long cacr; + __asm__ ("movec %%cacr, %0" : "=r" (cacr)); + if (cache & FLUSH_CACHE_INSN) + cacr |= 4; + if (cache & FLUSH_CACHE_DATA) + cacr |= 0x400; + len >>= 4; + while (len--) { + __asm__ __volatile__ ("movec %1, %%caar\n\t" + "movec %0, %%cacr" + : /* no outputs */ + : "r" (cacr), "r" (addr)); + addr += 16; + } + } else { + /* Flush the whole cache, even if page granularity requested. */ + unsigned long cacr; + __asm__ ("movec %%cacr, %0" : "=r" (cacr)); + if (cache & FLUSH_CACHE_INSN) + cacr |= 8; + if (cache & FLUSH_CACHE_DATA) + cacr |= 0x800; + __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); + } + ret = 0; + goto out; + } else if (CPU_IS_040) { + ret = cache_flush_040 (addr, scope, cache, len); + } else if (CPU_IS_060) { + ret = cache_flush_060 (addr, scope, cache, len); + } +out: + unlock_kernel(); + return ret; } diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 39625f3b6..1cc547907 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -29,11 +29,15 @@ #include <linux/linkage.h> #include <asm/setup.h> +#include <asm/fpu.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/traps.h> #include <asm/pgtable.h> #include <asm/machdep.h> +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +#endif /* assembler routines */ asmlinkage void system_call(void); @@ -140,10 +144,9 @@ static inline void console_verbose(void) { extern int console_loglevel; console_loglevel = 15; - mach_debug_init(); } -char *vec_names[] = { +static char *vec_names[] = { "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", @@ -162,17 +165,17 @@ char *vec_names[] = { "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", "FPCP UNSUPPORTED OPERATION", - "MMU CONFIGUATION ERROR" + "MMU CONFIGURATION ERROR" }; -char *space_names[] = { +static char *space_names[] = { "Space 0", "User Data", "User Program", "Space 3", "Space 4", "Super Data", "Super Program", "CPU" }; -extern void die_if_kernel(char *,struct pt_regs *,int); +void die_if_kernel(char *,struct pt_regs *,int); asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); @@ -184,7 +187,7 @@ static inline void access_error060 (struct frame *fp) unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ #ifdef DEBUG - printk("fslw=%#lx, fa=%#lx\n", ssw, fp->un.fmt4.effaddr); + printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); #endif if (fslw & MMU060_BPE) { @@ -194,7 +197,7 @@ static inline void access_error060 (struct frame *fp) "movec %/d0,%/cacr" : : : "d0" ); /* return if there's no other error */ - if (!(fslw & MMU060_ERR_BITS)) + if ((!(fslw & MMU060_ERR_BITS)) && !(fslw & MMU060_SEE)) return; } @@ -209,8 +212,13 @@ static inline void access_error060 (struct frame *fp) if (fslw & MMU060_MA) addr = PAGE_ALIGN(addr); do_page_fault(&fp->ptregs, addr, errorcode); - } - else { + } else if (fslw & (MMU060_SEE)){ + /* Software Emulation Error. Probably an instruction + * using an unsupported addressing mode + */ + send_sig (SIGSEGV, current, 1); + } else { + printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); printk( "68060 access error, fslw=%lx\n", fslw ); trap_c( fp ); } @@ -218,7 +226,7 @@ static inline void access_error060 (struct frame *fp) #endif /* CONFIG_M68060 */ #if defined (CONFIG_M68040) -static unsigned long probe040 (int iswrite, int fc, unsigned long addr) +static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr) { unsigned long mmusr; unsigned long fs = get_fs(); @@ -227,28 +235,26 @@ static unsigned long probe040 (int iswrite, int fc, unsigned long addr) if (iswrite) /* write */ - asm volatile ("movel %1,%/a0\n\t" - ".word 0xf548\n\t" /* ptestw (a0) */ - ".long 0x4e7a8805\n\t" /* movec mmusr,a0 */ - "movel %/a0,%0" - : "=g" (mmusr) - : "g" (addr) - : "a0"); + asm volatile (".chip 68040\n\t" + "ptestw (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (mmusr) + : "a" (addr)); else - asm volatile ("movel %1,%/a0\n\t" - ".word 0xf568\n\t" /* ptestr (a0) */ - ".long 0x4e7a8805\n\t" /* movec mmusr,a0 */ - "movel %/a0,%0" - : "=g" (mmusr) - : "g" (addr) - : "a0"); + asm volatile (".chip 68040\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (mmusr) + : "a" (addr)); set_fs (fs); return mmusr; } -static void do_040writeback (unsigned short ssw, +static inline void do_040writeback (unsigned short ssw, unsigned short wbs, unsigned long wba, unsigned long wbd, @@ -313,11 +319,9 @@ static inline void access_error040 (struct frame *fp) /* MMU error, get the MMUSR info for this access */ mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr); - /* #ifdef DEBUG printk("mmusr = %lx\n", mmusr); #endif -*/ errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | ((ssw & RW_040) ? 0 : 2); do_page_fault (&fp->ptregs, addr, errorcode); @@ -353,7 +357,7 @@ static inline void access_error040 (struct frame *fp) } #endif /* CONFIG_M68040 */ -#if defined(CONFIG_M68020_OR_M68030) +#if defined(CPU_M68020_OR_M68030) static inline void bus_error030 (struct frame *fp) { volatile unsigned short temp; @@ -605,7 +609,7 @@ static inline void bus_error030 (struct frame *fp) printk ("level 0 mmusr is %#x\n", mmusr); #ifdef DEBUG - if (boot_info.cputype & CPU_68030) { + if (m68k_cputype & CPU_68030) { asm volatile ("pmove %/tt0,%0@" : /* no outputs */ : "a" (&tlong)); @@ -632,7 +636,7 @@ create_atc_entry: asm volatile ("ploadr #2,%0@" : /* no outputs */ : "a" (addr)); } -#endif /* CONFIG_M68020_OR_M68030 */ +#endif /* CPU_M68020_OR_M68030 */ asmlinkage void buserr_c(struct frame *fp) { @@ -655,7 +659,7 @@ asmlinkage void buserr_c(struct frame *fp) access_error040 (fp); break; #endif -#if defined (CONFIG_M68020_OR_M68030) +#if defined (CPU_M68020_OR_M68030) case 0xa: case 0xb: bus_error030 (fp); @@ -679,6 +683,11 @@ int kstack_depth_to_print = 48; static void dump_stack(struct frame *fp) { +#ifdef CONFIG_KGDB + /* This will never return to here, if kgdb has been initialized. And if + * it returns from there, then to where the error happened... */ + enter_kgdb( &fp->ptregs ); +#else unsigned long *stack, *endstack, addr, module_start, module_end; extern char _start, _etext; int i; @@ -776,10 +785,15 @@ static void dump_stack(struct frame *fp) for (i = 0; i < 10; i++) printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); printk ("\n"); +#endif } void bad_super_trap (struct frame *fp) { +#ifdef CONFIG_KGDB + /* Save the register dump if we'll enter kgdb anyways */ + if (!kgdb_initialized) { +#endif console_verbose(); if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) printk ("*** %s *** FORMAT=%X\n", @@ -809,6 +823,9 @@ void bad_super_trap (struct frame *fp) fp->ptregs.pc); } printk ("Current process id is %d\n", current->pid); +#ifdef CONFIG_KGDB + } +#endif die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); } @@ -867,14 +884,18 @@ asmlinkage void trap_c(struct frame *fp) case VEC_FPOVER: case VEC_FPNAN: { - unsigned char fstate[216]; + unsigned char fstate[FPSTATESIZE]; - __asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory"); + __asm__ __volatile__ (".chip 68k/68881\n\t" + "fsave %0@\n\t" + ".chip 68k" : : "a" (fstate) : "memory"); /* Set the exception pending bit in the 68882 idle frame */ if (*(unsigned short *) fstate == 0x1f38) { fstate[fstate[1]] |= 1 << 3; - __asm__ __volatile__ ("frestore %0@" : : "a" (fstate)); + __asm__ __volatile__ (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (fstate)); } } /* fall through */ @@ -905,9 +926,13 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr) if (!(fp->sr & PS_S)) return; +#ifdef CONFIG_KGDB + /* Save the register dump if we'll enter kgdb anyways */ + if (!kgdb_initialized) { +#endif console_verbose(); printk("%s: %08x\n",str,nr); - printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); + printk("PC: [<%08lx>]\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", fp->d0, fp->d1, fp->d2, fp->d3); printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", @@ -917,6 +942,18 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr) printk("Corrupted stack page\n"); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, current->kernel_stack_page); +#ifdef CONFIG_KGDB + } +#endif dump_stack((struct frame *)fp); do_exit(SIGSEGV); } + +/* + * This function is called if an error occur while accessing + * user-space from the fpsp040 code. + */ +asmlinkage void fpsp040_die(void) +{ + do_exit(SIGSEGV); +} diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c index 786e80dd3..35bf38d1e 100644 --- a/arch/m68k/lib/checksum.c +++ b/arch/m68k/lib/checksum.c @@ -19,8 +19,8 @@ * (%1). Thanks to Roman Hodek for pointing this out. * B: GCC seems to mess up if one uses too many * data-registers to hold input values and one tries to - * specify d0 and d1 as scratch registers. Letting gcc choose these - * registers itself solves the problem. + * specify d0 and d1 as scratch registers. Letting gcc + * choose these registers itself solves the problem. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -124,13 +124,20 @@ csum_partial (const unsigned char *buff, int len, unsigned int sum) /* - * copy from user space while checksumming, otherwise like csum_partial + * copy from user space while checksumming, with exception handling. */ unsigned int -csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum) +csum_partial_copy_from_user(const char *src, char *dst, int len, + int sum, int *csum_err) { + /* + * GCC doesn't like more than 10 operands for the asm + * statements so we have to use tmp2 for the error + * code. + */ unsigned long tmp1, tmp2; + __asm__("movel %2,%4\n\t" "btst #1,%4\n\t" /* Check alignment */ "jeq 2f\n\t" @@ -226,28 +233,50 @@ csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum) "6:\t" "addl %5,%0\n\t" /* now add rest long to sum */ "clrl %5\n\t" - "addxl %5,%0\n" /* add X bit */ - "7:\n" + "addxl %5,%0\n\t" /* add X bit */ + "7:\t" + "clrl %5\n" /* no error - clear return value */ + "8:\n" + ".section .fixup,\"ax\"\n" + ".even\n" + "9:\t" + "moveq #-14,%5\n\t" /* -EFAULT, out of inputs to asm ;( */ + "jra 8b\n" + ".previous\n" ".section __ex_table,\"a\"\n" - ".long 10b,7b\n" - ".long 11b,7b\n" - ".long 12b,7b\n" - ".long 13b,7b\n" - ".long 14b,7b\n" - ".long 15b,7b\n" - ".long 16b,7b\n" - ".long 17b,7b\n" - ".long 18b,7b\n" - ".long 19b,7b\n" - ".long 20b,7b\n" - ".long 21b,7b\n" - ".text" + ".long 10b,9b\n" + ".long 11b,9b\n" + ".long 12b,9b\n" + ".long 13b,9b\n" + ".long 14b,9b\n" + ".long 15b,9b\n" + ".long 16b,9b\n" + ".long 17b,9b\n" + ".long 18b,9b\n" + ".long 19b,9b\n" + ".long 20b,9b\n" + ".long 21b,9b\n" + ".previous" : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), - "=&d" (tmp1), "=&d" (tmp2) + "=&d" (tmp1), "=d" (tmp2) : "0" (sum), "1" (len), "2" (src), "3" (dst) ); + + *csum_err = tmp2; + return(sum); } + +/* + * This one will go away soon. + */ +unsigned int +csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum) +{ + int dummy; + + return csum_partial_copy_from_user(src, dst, len, sum, &dummy); +} /* * copy from kernel space while checksumming, otherwise like csum_partial */ diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S index be5501f50..76ffc3cc5 100644 --- a/arch/m68k/lib/semaphore.S +++ b/arch/m68k/lib/semaphore.S @@ -9,21 +9,29 @@ #include <linux/linkage.h> /* - * "down_failed" is called with the eventual return address - * in %a0, and the address of the semaphore in %a1. We need - * to call "__down()", and then re-try until we succeed.. + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. */ ENTRY(__down_failed) moveml %a0/%d0/%d1,-(%sp) -1: movel %a1,-(%sp) + movel %a1,-(%sp) jbsr SYMBOL_NAME(__down) movel (%sp)+,%a1 - subql #1,(%a1) - jmi 1b movel (%sp)+,%d0 movel (%sp)+,%d1 rts +ENTRY(__down_failed_interruptible) + movel %a0,-(%sp) + movel %d1,-(%sp) + movel %a1,-(%sp) + jbsr SYMBOL_NAME(__down_interruptible) + movel (%sp)+,%a1 + movel (%sp)+,%d1 + rts + ENTRY(__up_wakeup) moveml %a0/%d0/%d1,-(%sp) movel %a1,-(%sp) diff --git a/arch/m68k/mm/extable.c b/arch/m68k/mm/extable.c index 6104120b7..1f8d9e8c3 100644 --- a/arch/m68k/mm/extable.c +++ b/arch/m68k/mm/extable.c @@ -34,24 +34,22 @@ unsigned long search_exception_table(unsigned long addr) { unsigned long ret; -#ifdef CONFIG_MODULES - struct module *mp; -#endif - /* Search the kernel's table first. */ +#ifndef CONFIG_MODULES + /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - if (ret) - return ret; - -#ifdef CONFIG_MODULES + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->exceptinfo.start != NULL) { - ret = search_one_table(mp->exceptinfo.start, - mp->exceptinfo.stop-1, addr); - if (ret) - return ret; - } + if (mp->ex_table_start == NULL) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end-1, addr); + if (ret) return ret; } #endif + return 0; } diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 9da322208..71b46e2d9 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -96,7 +96,8 @@ good_area: * Until I found it, this one cures the problem and makes * 1.2 run on the 68040 (Martin Apel). */ - flush_tlb_page(vma, address); + if (CPU_IS_040_OR_060) + flush_tlb_page(vma, address); return 0; /* @@ -107,13 +108,10 @@ bad_area: up(&mm->mmap_sem); /* Are we prepared to handle this fault? */ - if (CPU_IS_060 && regs->format == 4) - fault_pc = ((struct frame *)regs)->un.fmt4.pc; - else - fault_pc = regs->pc; + fault_pc = regs->pc; if ((fixup = search_exception_table(fault_pc)) != 0) { struct pt_regs *tregs; - printk("Exception at %lx (%lx)\n", fault_pc, fixup); + printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", fault_pc, fixup); /* Create a new four word stack frame, discarding the old one. */ regs->stkadj = frame_extra_sizes[regs->format]; diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 3fcc2d904..01cd315dd 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -71,12 +71,12 @@ void show_mem(void) total++; if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; - else if (mem_map[i].count == 1) + else if (atomic_read(&mem_map[i].count) == 1) nonshared++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -102,9 +102,15 @@ pte_t *kernel_page_table (unsigned long *memavailp) { pte_t *ptablep; - ptablep = (pte_t *)*memavailp; - *memavailp += PAGE_SIZE; + if (memavailp) { + ptablep = (pte_t *)*memavailp; + *memavailp += PAGE_SIZE; + } + else + ptablep = (pte_t *)__get_free_page(GFP_KERNEL); + flush_page_to_ram((unsigned long) ptablep); + flush_tlb_kernel_page((unsigned long) ptablep); nocache_page ((unsigned long)ptablep); return ptablep; @@ -289,8 +295,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) { int chunk; unsigned long mem_avail = 0; - /* pointer to page table for kernel stacks */ - extern unsigned long availmem; #ifdef DEBUG { @@ -318,24 +322,14 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) * tables and thus modify availmem. */ - for (chunk = 0; chunk < boot_info.num_memory; chunk++) { - mem_avail = map_chunk (boot_info.memory[chunk].addr, - boot_info.memory[chunk].size, - &availmem); + for (chunk = 0; chunk < m68k_num_memory; chunk++) { + mem_avail = map_chunk (m68k_memory[chunk].addr, + m68k_memory[chunk].size, &start_mem); } flush_tlb_all(); #ifdef DEBUG printk ("memory available is %ldKB\n", mem_avail >> 10); -#endif - - /* - * virtual address after end of kernel - * "availmem" is setup by the code in head.S. - */ - start_mem = availmem; - -#ifdef DEBUG printk ("start_mem is %#lx\nvirtual_end is %#lx\n", start_mem, end_mem); #endif @@ -374,17 +368,17 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) #endif if (CPU_IS_040_OR_060) - asm __volatile__ ("movel %0,%/d0\n\t" - ".long 0x4e7b0806" /* movec d0,urp */ + asm __volatile__ (".chip 68040\n\t" + "movec %0,%%urp\n\t" + ".chip 68k" : /* no outputs */ - : "g" (task[0]->tss.crp[1]) - : "d0"); + : "r" (task[0]->tss.crp[1])); else - asm __volatile__ ("movel %0,%/a0\n\t" - ".long 0xf0104c00" /* pmove %/a0@,%/crp */ + asm __volatile__ (".chip 68030\n\t" + "pmove %0,%%crp\n\t" + ".chip 68k" : /* no outputs */ - : "g" (task[0]->tss.crp) - : "a0"); + : "m" (task[0]->tss.crp[0])); #ifdef DEBUG printk ("set crp\n"); #endif @@ -398,7 +392,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) printk ("before free_area_init\n"); #endif - return free_area_init (start_mem, end_mem); + return PAGE_ALIGN(free_area_init (start_mem, end_mem)); } void mem_init(unsigned long start_mem, unsigned long end_mem) @@ -410,7 +404,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) end_mem &= PAGE_MASK; high_memory = (void *) end_mem; - max_mapnr = MAP_NR(end_mem); + max_mapnr = num_physpages = MAP_NR(end_mem); start_mem = PAGE_ALIGN(start_mem); while (start_mem < end_mem) { @@ -460,7 +454,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) datapages++; continue; } - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end)) @@ -474,6 +468,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) datapages << (PAGE_SHIFT-10)); } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { unsigned long i; @@ -487,9 +486,9 @@ void si_meminfo(struct sysinfo *val) if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 05aa8499d..55d5e98f3 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -63,11 +63,12 @@ pmd_t *get_pointer_table (void) return 0; } - if (!(dp->page = __get_free_page (GFP_KERNEL))) { + if (!(dp->page = get_free_page (GFP_KERNEL))) { kfree (dp); return 0; } + flush_tlb_kernel_page((unsigned long) dp->page); nocache_page (dp->page); dp->alloced = 0; @@ -210,10 +211,11 @@ pmd_t *get_kpointer_table (void) return NULL; } if (!(page = kptr_pages.page[i])) { - if (!(page = (pmd_tablepage *)__get_free_page(GFP_KERNEL))) { + if (!(page = (pmd_tablepage *)get_free_page(GFP_KERNEL))) { printk("No space for kernel pointer table!\n"); return NULL; } + flush_tlb_kernel_page((unsigned long) page); nocache_page((u_long)(kptr_pages.page[i] = page)); } asm volatile("bfset %0@{%1,#1}" @@ -250,31 +252,94 @@ void free_kpointer_table (pmd_t *pmdp) } } +static unsigned long transp_transl_matches( unsigned long regval, + unsigned long vaddr ) +{ + unsigned long base, mask; + + /* enabled? */ + if (!(regval & 0x8000)) + return( 0 ); + + if (CPU_IS_030) { + /* function code match? */ + base = (regval >> 4) & 7; + mask = ~(regval & 7); + if ((SUPER_DATA & mask) != (base & mask)) + return( 0 ); + } + else { + /* must not be user-only */ + if ((regval & 0x6000) == 0) + return( 0 ); + } + + /* address match? */ + base = regval & 0xff000000; + mask = ~((regval << 8) & 0xff000000); + return( (vaddr & mask) == (base & mask) ); +} + /* * The following two routines map from a physical address to a kernel * virtual address and vice versa. */ unsigned long mm_vtop (unsigned long vaddr) { - int i; + int i=0; unsigned long voff = vaddr; unsigned long offset = 0; - for (i = 0; i < boot_info.num_memory; i++) - { - if (voff < offset + boot_info.memory[i].size) { + do{ + if (voff < offset + m68k_memory[i].size) { #ifdef DEBUGPV printk ("VTOP(%lx)=%lx\n", vaddr, - boot_info.memory[i].addr + voff - offset); + m68k_memory[i].addr + voff - offset); #endif - return boot_info.memory[i].addr + voff - offset; + return m68k_memory[i].addr + voff - offset; } else - offset += boot_info.memory[i].size; + offset += m68k_memory[i].size; + i++; + }while (i < m68k_num_memory); + + /* not in one of the memory chunks; test for applying transparent + * translation */ + + if (CPU_IS_030) { + unsigned long ttreg; + + asm volatile( ".chip 68030\n\t" + "pmove %/tt0,%0@\n\t" + ".chip 68k" + : : "a" (&ttreg) ); + if (transp_transl_matches( ttreg, vaddr )) + return vaddr; + asm volatile( ".chip 68030\n\t" + "pmove %/tt1,%0@\n\t" + ".chip 68k" + : : "a" (&ttreg) ); + if (transp_transl_matches( ttreg, vaddr )) + return vaddr; + } + else if (CPU_IS_040_OR_060) { + unsigned long ttreg; + + asm volatile( ".chip 68040\n\t" + "movec %%dtt0,%0\n\t" + ".chip 68k" + : "=d" (ttreg) ); + if (transp_transl_matches( ttreg, vaddr )) + return vaddr; + asm volatile( ".chip 68040\n\t" + "movec %%dtt1,%0\n\t" + ".chip 68k" + : "=d" (ttreg) ); + if (transp_transl_matches( ttreg, vaddr )) + return vaddr; } - /* not in one of the memory chunks; get the actual - * physical address from the MMU. - */ + /* no match, too, so get the actual physical address from the MMU. */ + if (CPU_IS_060) { unsigned long fs = get_fs(); unsigned long paddr; @@ -284,12 +349,11 @@ unsigned long mm_vtop (unsigned long vaddr) /* The PLPAR instruction causes an access error if the translation * is not possible. We don't catch that here, so a bad kernel trap * will be reported in this case. */ - asm volatile ("movel %1,%/a0\n\t" - ".word 0xf5c8\n\t" /* plpar (a0) */ - "movel %/a0,%0" - : "=g" (paddr) - : "g" (vaddr) - : "a0" ); + asm volatile (".chip 68060\n\t" + "plpar (%0)\n\t" + ".chip 68k" + : "=a" (paddr) + : "0" (vaddr)); set_fs (fs); return paddr; @@ -300,13 +364,12 @@ unsigned long mm_vtop (unsigned long vaddr) set_fs (SUPER_DATA); - asm volatile ("movel %1,%/a0\n\t" - ".word 0xf568\n\t" /* ptestr (a0) */ - ".long 0x4e7a8805\n\t" /* movec mmusr, a0 */ - "movel %/a0,%0" - : "=g" (mmusr) - : "g" (vaddr) - : "a0", "d0"); + asm volatile (".chip 68040\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr, %0\n\t" + ".chip 68k" + : "=r" (mmusr) + : "a" (vaddr)); set_fs (fs); if (mmusr & MMU_R_040) @@ -347,22 +410,22 @@ unsigned long mm_vtop (unsigned long vaddr) unsigned long mm_ptov (unsigned long paddr) { - int i; + int i = 0; unsigned long offset = 0; - for (i = 0; i < boot_info.num_memory; i++) - { - if (paddr >= boot_info.memory[i].addr && - paddr < (boot_info.memory[i].addr - + boot_info.memory[i].size)) { + do{ + if (paddr >= m68k_memory[i].addr && + paddr < (m68k_memory[i].addr + + m68k_memory[i].size)) { #ifdef DEBUGPV printk ("PTOV(%lx)=%lx\n", paddr, - (paddr - boot_info.memory[i].addr) + offset); + (paddr - m68k_memory[i].addr) + offset); #endif - return (paddr - boot_info.memory[i].addr) + offset; + return (paddr - m68k_memory[i].addr) + offset; } else - offset += boot_info.memory[i].size; - } + offset += m68k_memory[i].size; + i++; + }while (i < m68k_num_memory); /* * assume that the kernel virtual address is the same as the @@ -389,62 +452,67 @@ unsigned long mm_ptov (unsigned long paddr) } /* invalidate page in both caches */ -#define clear040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ - "nop\n\t"\ - ".word 0xf4d0"\ - /* CINVP I/D (a0) */\ - : : "g" ((paddr))\ - : "a0") +#define clear040(paddr) \ + __asm__ __volatile__ ("nop\n\t" \ + ".chip 68040\n\t" \ + "cinvp %%bc,(%0)\n\t" \ + ".chip 68k" \ + : : "a" (paddr)) /* invalidate page in i-cache */ -#define cleari040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ - /* CINVP I (a0) */\ - "nop\n\t"\ - ".word 0xf490"\ - : : "g" ((paddr))\ - : "a0") +#define cleari040(paddr) \ + __asm__ __volatile__ ("nop\n\t" \ + ".chip 68040\n\t" \ + "cinvp %%ic,(%0)\n\t" \ + ".chip 68k" \ + : : "a" (paddr)) /* push page in both caches */ -#define push040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ - "nop\n\t"\ - ".word 0xf4f0"\ - /* CPUSHP I/D (a0) */\ - : : "g" ((paddr))\ - : "a0") +#define push040(paddr) \ + __asm__ __volatile__ ("nop\n\t" \ + ".chip 68040\n\t" \ + "cpushp %%bc,(%0)\n\t" \ + ".chip 68k" \ + : : "a" (paddr)) /* push and invalidate page in both caches */ -#define pushcl040(paddr) do { push040((paddr));\ - if (CPU_IS_060) clear040((paddr));\ - } while(0) +#define pushcl040(paddr) \ + do { push040(paddr); \ + if (CPU_IS_060) clear040(paddr); \ + } while(0) /* push page in both caches, invalidate in i-cache */ -#define pushcli040(paddr) do { push040((paddr));\ - if (CPU_IS_060) cleari040((paddr));\ - } while(0) +#define pushcli040(paddr) \ + do { push040(paddr); \ + if (CPU_IS_060) cleari040(paddr); \ + } while(0) /* push page defined by virtual address in both caches */ -#define pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ - /* ptestr (a0) */\ - "nop\n\t"\ - ".word 0xf568\n\t"\ - /* movec mmusr,d0 */\ - ".long 0x4e7a0805\n\t"\ - "andw #0xf000,%/d0\n\t"\ - "movel %/d0,%/a0\n\t"\ - /* CPUSHP I/D (a0) */\ - "nop\n\t"\ - ".word 0xf4f0"\ - : : "g" ((vaddr))\ - : "a0", "d0") +#define pushv040(vaddr) \ + do { unsigned long _tmp1, _tmp2; \ + __asm__ __volatile__ ("nop\n\t" \ + ".chip 68040\n\t" \ + "ptestr (%2)\n\t" \ + "movec %%mmusr,%0\n\t" \ + "andw #0xf000,%0\n\t" \ + "movel %0,%1\n\t" \ + "nop\n\t" \ + "cpushp %%bc,(%1)\n\t" \ + ".chip 68k" \ + : "=d" (_tmp1), "=a" (_tmp2) \ + : "a" (vaddr)); \ + } while (0) /* push page defined by virtual address in both caches */ -#define pushv060(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ - /* plpar (a0) */\ - ".word 0xf5c8\n\t"\ - /* CPUSHP I/D (a0) */\ - ".word 0xf4f0"\ - : : "g" ((vaddr))\ - : "a0") +#define pushv060(vaddr) \ + do { unsigned long _tmp; \ + __asm__ __volatile__ (".chip 68060\n\t" \ + "plpar (%0)\n\t" \ + "cpushp %%bc,(%0)\n\t" \ + ".chip 68k" \ + : "=a" (_tmp) \ + : "0" (vaddr)); \ + } while (0) /* @@ -633,9 +701,8 @@ int mm_end_of_chunk (unsigned long addr, int len) { int i; - for (i = 0; i < boot_info.num_memory; i++) - if (boot_info.memory[i].addr + boot_info.memory[i].size - == addr + len) + for (i = 0; i < m68k_num_memory; i++) + if (m68k_memory[i].addr + m68k_memory[i].size == addr + len) return 1; return 0; } |