patch-1.3.94 linux/arch/m68k/amiga/config.c
Next file: linux/arch/m68k/amiga/ksyms.c
Previous file: linux/arch/m68k/amiga/chipram.c
Back to the patch index
Back to the overall index
- Lines: 882
- Date:
Fri Apr 19 02:41:15 1996
- Orig file:
v1.3.93/linux/arch/m68k/amiga/config.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.93/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
@@ -0,0 +1,881 @@
+/*
+ * linux/amiga/config.c
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Miscellaneous Amiga stuff
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+u_long amiga_masterclock;
+u_long amiga_colorclock;
+
+extern char m68k_debug_device[];
+
+extern void amiga_sched_init(isrfunc handler);
+extern int amiga_keyb_init(void);
+extern int amiga_kbdrate (struct kbd_repeat *);
+extern void amiga_init_INTS (void);
+extern int amiga_add_isr (unsigned long, isrfunc, int, void *, char *);
+extern int amiga_remove_isr (unsigned long, isrfunc);
+extern int amiga_get_irq_list (char *, int);
+extern void amiga_enable_irq(unsigned int);
+extern void amiga_disable_irq(unsigned int);
+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);
+extern void amiga_check_partition (struct gendisk *hd, unsigned int dev);
+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);
+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);
+extern void amiga_video_setup(char *, int *);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+void config_amiga(void)
+{
+ char *type = NULL;
+
+ 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;
+
+ case AMI_500:
+ case AMI_500PLUS:
+ case AMI_1000:
+ AMIGAHW_SET(A2000_CLK); /* Is this correct? */
+ printk("A2000_CLK ");
+ 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_2000:
+ case AMI_2500:
+ AMIGAHW_SET(A2000_CLK);
+ printk("A2000_CLK ");
+ 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 ");
+ 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 ");
+ 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:
+ AMIGAHW_SET(AMI_VIDEO);
+ AMIGAHW_SET(AMI_BLITTER);
+ AMIGAHW_SET(AMI_AUDIO);
+ AMIGAHW_SET(AMI_FLOPPY);
+ AMIGAHW_SET(AMI_KEYBOARD);
+ AMIGAHW_SET(AMI_MOUSE);
+ AMIGAHW_SET(AMI_SERIAL);
+ 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) {
+ 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:
+ panic("No support for Draco yet");
+
+ default:
+ panic("Unknown Amiga Model");
+ }
+ printk("\n");
+
+ mach_sched_init = amiga_sched_init;
+ mach_keyb_init = amiga_keyb_init;
+ mach_kbdrate = amiga_kbdrate;
+ mach_init_INTS = amiga_init_INTS;
+ mach_add_isr = amiga_add_isr;
+#if 0 /* ++1.3++ */
+ mach_remove_isr = amiga_remove_isr;
+ mach_enable_irq = amiga_enable_irq;
+ mach_disable_irq = amiga_disable_irq;
+#endif
+ mach_get_irq_list = amiga_get_irq_list;
+ mach_gettimeoffset = amiga_gettimeoffset;
+ if (AMIGAHW_PRESENT(A3000_CLK)){
+ mach_gettod = a3000_gettod;
+ mach_max_dma_address = 0xffffffff; /*
+ * default MAX_DMA 0xffffffff
+ * on Z3 machines - we should
+ * consider adding something
+ * like a dma_mask in kmalloc
+ * later on, so people using Z2
+ * boards in Z3 machines won't
+ * get into trouble - Jes
+ */
+ }
+ else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
+ mach_gettod = a2000_gettod;
+ mach_max_dma_address = 0x00ffffff; /*
+ * default MAX_DMA 0x00ffffff
+ * on Z2 machines.
+ */
+ }
+ mach_hwclk = amiga_hwclk;
+ mach_set_clock_mmss = amiga_set_clock_mmss;
+ mach_check_partition = amiga_check_partition;
+ 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 */
+
+ /* clear all DMA bits */
+ custom.dmacon = DMAF_ALL;
+ /* ensure that the DMA master bit is set */
+ custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
+
+ /* 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
+ */
+ if (AMIGAHW_PRESENT(MAGIC_REKICK))
+ *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80;
+
+ zorro_init();
+#ifdef CONFIG_ZORRO
+ /*
+ * Identify all known AutoConfig Expansion Devices
+ */
+ zorro_identify();
+#endif /* CONFIG_ZORRO */
+}
+
+extern long time_finetune; /* from kernel/sched.c */
+
+static unsigned short jiffy_ticks;
+
+#if 1 /* ++1.3++ */
+static void timer_wrapper( int irq, struct pt_regs *fp, void *otimerf )
+ {
+ unsigned short flags, old_flags;
+
+ ciab.icr = 0x01;
+
+ save_flags(flags);
+ old_flags = (flags & ~0x0700) | (fp->sr & 0x0700);
+
+ restore_flags(old_flags);
+
+ (*(isrfunc)otimerf)( irq, fp, NULL );
+
+ restore_flags(flags);
+ ciab.icr = 0x81;
+}
+#endif
+
+void amiga_sched_init (isrfunc timer_routine)
+{
+
+#if 0 /* XXX */ /* I think finetune was removed by the 1.3.29 patch */
+ double finetune;
+#endif
+
+ jiffy_ticks = (amiga_eclock+50)/100;
+#if 0 /* XXX */
+ finetune = (jiffy_ticks-amiga_eclock/HZ)/amiga_eclock*1000000*(1<<24);
+ time_finetune = finetune+0.5;
+#endif
+
+ ciab.cra &= 0xC0; /* turn off timer A, continous mode, from Eclk */
+ ciab.talo = jiffy_ticks % 256;
+ ciab.tahi = jiffy_ticks / 256;
+ /* CIA interrupts when counter underflows, so adjust ticks by 1 */
+ jiffy_ticks -= 1;
+
+ /* install interrupt service routine for CIAB Timer A */
+ /*
+ * Please don't change this to use ciaa, as it interfers with the
+ * SCSI code. We'll have to take a look at this later
+ */
+#if 0
+ add_isr (IRQ_AMIGA_CIAB_TA, timer_routine, 0, NULL, "timer");
+#else
+ add_isr (IRQ_AMIGA_CIAB_TA, timer_wrapper, 0, timer_routine, "timer");
+#endif
+ /* start timer */
+ ciab.cra |= 0x01;
+}
+
+#define TICK_SIZE 10000
+
+/* This is always executed with interrupts disabled. */
+unsigned long amiga_gettimeoffset (void)
+{
+ unsigned short hi, lo, hi2;
+ unsigned long ticks, offset = 0;
+
+ /* read CIA A timer A current value */
+ hi = ciab.tahi;
+ lo = ciab.talo;
+ hi2 = ciab.tahi;
+
+ if (hi != hi2) {
+ lo = ciab.talo;
+ hi = hi2;
+ }
+
+ ticks = hi << 8 | lo;
+
+#if 0 /* XXX */
+/* reading the ICR clears all interrupts. bad idea! */
+ if (ticks > jiffy_ticks - jiffy_ticks / 100)
+ /* check for pending interrupt */
+ if (ciab.icr & CIA_ICR_TA)
+ offset = 10000;
+#endif
+
+ ticks = (jiffy_ticks-1) - ticks;
+ ticks = (10000 * ticks) / jiffy_ticks;
+
+ return ticks + offset;
+}
+
+void a3000_gettod (int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp)
+{
+ volatile struct tod3000 *tod = TOD_3000;
+
+ tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+ *secp = tod->second1 * 10 + tod->second2;
+ *minp = tod->minute1 * 10 + tod->minute2;
+ *hourp = tod->hour1 * 10 + tod->hour2;
+ *dayp = tod->day1 * 10 + tod->day2;
+ *monp = tod->month1 * 10 + tod->month2;
+ *yearp = tod->year1 * 10 + tod->year2;
+
+ tod->cntrl1 = TOD3000_CNTRL1_FREE;
+}
+
+void a2000_gettod (int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp)
+{
+ volatile struct tod2000 *tod = TOD_2000;
+
+ tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+
+ while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+ ;
+
+ *secp = tod->second1 * 10 + tod->second2;
+ *minp = tod->minute1 * 10 + tod->minute2;
+ *hourp = (tod->hour1 & 3) * 10 + tod->hour2;
+ *dayp = tod->day1 * 10 + tod->day2;
+ *monp = tod->month1 * 10 + tod->month2;
+ *yearp = tod->year1 * 10 + tod->year2;
+
+ if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+ if ((!tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
+ *hourp = 0;
+ else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
+ *hourp += 12;
+
+ tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+}
+
+int amiga_hwclk(int op, struct hwclk_time *t)
+{
+ if (AMIGAHW_PRESENT(A3000_CLK)) {
+ volatile struct tod3000 *tod = TOD_3000;
+
+ tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+ if (!op) { /* read */
+ t->sec = tod->second1 * 10 + tod->second2;
+ t->min = tod->minute1 * 10 + tod->minute2;
+ t->hour = tod->hour1 * 10 + tod->hour2;
+ t->day = tod->day1 * 10 + tod->day2;
+ t->wday = tod->weekday;
+ t->mon = tod->month1 * 10 + tod->month2 - 1;
+ t->year = tod->year1 * 10 + tod->year2;
+ } else {
+ tod->second1 = t->sec / 10;
+ tod->second2 = t->sec % 10;
+ tod->minute1 = t->min / 10;
+ tod->minute2 = t->min % 10;
+ tod->hour1 = t->hour / 10;
+ tod->hour2 = t->hour % 10;
+ tod->day1 = t->day / 10;
+ tod->day2 = t->day % 10;
+ if (t->wday != -1)
+ tod->weekday = t->wday;
+ tod->month1 = (t->mon + 1) / 10;
+ tod->month2 = (t->mon + 1) % 10;
+ tod->year1 = t->year / 10;
+ tod->year2 = t->year % 10;
+ }
+
+ tod->cntrl1 = TOD3000_CNTRL1_FREE;
+ } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+ volatile struct tod2000 *tod = TOD_2000;
+
+ tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+
+ while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+ ;
+
+ if (!op) { /* read */
+ t->sec = tod->second1 * 10 + tod->second2;
+ t->min = tod->minute1 * 10 + tod->minute2;
+ t->hour = (tod->hour1 & 3) * 10 + tod->hour2;
+ t->day = tod->day1 * 10 + tod->day2;
+ t->wday = tod->weekday;
+ t->mon = tod->month1 * 10 + tod->month2 - 1;
+ t->year = tod->year1 * 10 + tod->year2;
+
+ if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+ if ((!tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12)
+ t->hour = 0;
+ else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12)
+ t->hour += 12;
+ } else {
+ tod->second1 = t->sec / 10;
+ tod->second2 = t->sec % 10;
+ tod->minute1 = t->min / 10;
+ tod->minute2 = t->min % 10;
+ if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
+ tod->hour1 = t->hour / 10;
+ else if (t->hour >= 12)
+ tod->hour1 = TOD2000_HOUR1_PM +
+ (t->hour - 12) / 10;
+ else
+ tod->hour1 = t->hour / 10;
+ tod->hour2 = t->hour % 10;
+ tod->day1 = t->day / 10;
+ tod->day2 = t->day % 10;
+ if (t->wday != -1)
+ tod->weekday = t->wday;
+ tod->month1 = (t->mon + 1) / 10;
+ tod->month2 = (t->mon + 1) % 10;
+ tod->year1 = t->year / 10;
+ tod->year2 = t->year % 10;
+ }
+
+ tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+ }
+
+ return 0;
+}
+
+int amiga_set_clock_mmss (unsigned long nowtime)
+{
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+ if (AMIGAHW_PRESENT(A3000_CLK)) {
+ volatile struct tod3000 *tod = TOD_3000;
+
+ tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+
+ tod->second1 = real_seconds / 10;
+ tod->second2 = real_seconds % 10;
+ tod->minute1 = real_minutes / 10;
+ tod->minute2 = real_minutes % 10;
+
+ tod->cntrl1 = TOD3000_CNTRL1_FREE;
+ } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+ volatile struct tod2000 *tod = TOD_2000;
+
+ tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+
+ while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
+ ;
+
+ tod->second1 = real_seconds / 10;
+ tod->second2 = real_seconds % 10;
+ tod->minute1 = real_minutes / 10;
+ tod->minute2 = real_minutes % 10;
+
+ tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+ }
+
+ return 0;
+}
+
+void amiga_waitbut (void)
+{
+ int i;
+
+ while (1) {
+ while (ciaa.pra & 0x40);
+
+ /* debounce */
+ for (i = 0; i < 1000; i++);
+
+ if (!(ciaa.pra & 0x40))
+ break;
+ }
+
+ /* wait for button up */
+ while (1) {
+ while (!(ciaa.pra & 0x40));
+
+ /* debounce */
+ for (i = 0; i < 1000; i++);
+
+ if (ciaa.pra & 0x40)
+ break;
+ }
+}
+
+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];
+ va_list args;
+ extern void console_print (const char *str);
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ console_print (buf);
+}
+
+NORET_TYPE void amiga_reset( void )
+ ATTRIB_NORET;
+
+void amiga_reset (void)
+{
+ unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
+ unsigned long jmp_addr = VTOP(&&jmp_addr_label);
+
+ cli();
+ if (m68k_is040or060)
+ /* Setup transparent translation registers for mapping
+ * of 16 MB kernel segment before disabling translation
+ */
+ __asm__ __volatile__
+ ("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 */
+ "jmp %0@\n\t"
+ : /* no outputs */
+ : "a" (jmp_addr040));
+ else
+ /* for 680[23]0, just disable translation and jump to the physical
+ * address of the label
+ */
+ __asm__ __volatile__
+ ("pmove %/tc,%@\n\t"
+ "bclr #7,%@\n\t"
+ "pmove %@,%/tc\n\t"
+ "jmp %0@\n\t"
+ : /* no outputs */
+ : "a" (jmp_addr));
+ jmp_addr_label040:
+ /* disable translation on '040 now */
+ __asm__ __volatile__
+ ("moveq #0,%/d0\n\t"
+ ".long 0x4e7b0003\n\t" /* movec d0,tc; disable MMU */
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+
+ jmp_addr_label:
+ /* pickup reset address from AmigaOS ROM, reset devices and jump
+ * to reset address
+ */
+ __asm__ __volatile__
+ ("movew #0x2700,%/sr\n\t"
+ "leal 0x01000000,%/a0\n\t"
+ "subl %/a0@(-0x14),%/a0\n\t"
+ "movel %/a0@(4),%/a0\n\t"
+ "subql #2,%/a0\n\t"
+ "bra 1f\n\t"
+ /* align on a longword boundary */
+ __ALIGN_STR "\n"
+ "1:\n\t"
+ "reset\n\t"
+ "jmp %/a0@" : /* Just that gcc scans it for % escapes */ );
+
+ for (;;);
+
+}
+
+extern void *amiga_chip_alloc(long size);
+
+
+#define SAVEKMSG_MAXMEM 128*1024
+
+
+#define SAVEKMSG_MAGIC1 0x53415645 /* 'SAVE' */
+#define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */
+
+struct savekmsg {
+ u_long magic1; /* SAVEKMSG_MAGIC1 */
+ u_long magic2; /* SAVEKMSG_MAGIC2 */
+ u_long magicptr; /* address of magic1 */
+ u_long size;
+ char data[0];
+};
+
+static struct savekmsg *savekmsg = NULL;
+
+
+static void ami_savekmsg_init(void)
+{
+ savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM);
+ savekmsg->magic1 = SAVEKMSG_MAGIC1;
+ savekmsg->magic2 = SAVEKMSG_MAGIC2;
+ savekmsg->magicptr = VTOP(savekmsg);
+ savekmsg->size = 0;
+}
+
+
+static void ami_mem_print(const char *b)
+{
+ int len;
+
+ for (len = 0; b[len]; len++);
+ if (savekmsg->size+len <= SAVEKMSG_MAXMEM) {
+ memcpy(savekmsg->data+savekmsg->size, b, len);
+ savekmsg->size += len;
+ }
+}
+
+
+void amiga_get_model(char *model)
+{
+ 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");
+ break;
+ }
+}
+
+
+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, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
+ boot_info.bi_amiga.psfreq, amiga_eclock);
+ if (AMIGAHW_PRESENT(AMI_VIDEO)) {
+ char *type;
+ switch(boot_info.bi_amiga.chipset) {
+ case CS_OCS:
+ type = "OCS";
+ break;
+ case CS_ECS:
+ type = "ECS";
+ break;
+ case CS_AGA:
+ type = "AGA";
+ break;
+ default:
+ type = "Old or Unknown";
+ break;
+ }
+ len += sprintf(buffer+len, "Graphics:\t%s\n", type);
+ }
+
+#define AMIGAHW_ANNOUNCE(name, str) \
+ if (AMIGAHW_PRESENT(name)) \
+ len += sprintf (buffer+len, "\t%s\n", str)
+
+ len += sprintf (buffer + len, "Detected hardware:\n");
+
+ AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
+ AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
+ AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
+ AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
+ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
+ AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
+ AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
+ AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
+ AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
+ AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
+ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
+ AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
+ AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
+ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
+ AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
+ AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
+ AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
+ AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
+ AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
+ AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
+ AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
+ AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
+ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
+ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
+ 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");
+
+ return(len);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this