]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.8 2.2.8
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:57 +0000 (15:18 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:57 +0000 (15:18 -0500)
Most of 2.2.8 by far is just architecture updates: arm, ppc and m68k stand
out as having been pretty much synchronized to their respective devel
trees, but there are some fixes to alpha and x86 too.

The one major fix in 2.2.8 is the SMP fix for disable_irq(), courtesy of
Andrea Arcangeli (I disagreed in details and did it differently in the
end, but all the heavy lifting was done by Andrea). This is the thing that
caused silenth deaths for some people with certain network adapters (3c509
and 8390-based cards in particular: the latter covers ne2000 clones which
are fairly common).

There are lots of smaller things (driver updates, filesystem cleanups and
some networking fixes), but the SMP irq thing is the one to kill for if
you happened to have any of the affected cards.

131 files changed:
CREDITS
Documentation/Configure.help
Documentation/m68k/kernel-options.txt
arch/m68k/Makefile
arch/m68k/bvme6000/config.c
arch/m68k/config.in
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/ints.c
arch/m68k/kernel/m68k_defs.h
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/setup.c
arch/m68k/kernel/time.c
arch/m68k/lib/semaphore.S
arch/m68k/mm/init.c
arch/m68k/mm/kmap.c
arch/m68k/mm/memory.c
arch/m68k/mvme147/147ints.c [new file with mode: 0644]
arch/m68k/mvme147/Makefile [new file with mode: 0644]
arch/m68k/mvme147/config.c [new file with mode: 0644]
arch/m68k/mvme16x/config.c
arch/m68k/q40/Makefile [new file with mode: 0644]
arch/m68k/q40/README [new file with mode: 0644]
arch/m68k/q40/config.c [new file with mode: 0644]
arch/m68k/q40/q40ints.c [new file with mode: 0644]
arch/m68k/sun3x/Makefile [new file with mode: 0644]
arch/m68k/sun3x/config.c [new file with mode: 0644]
arch/m68k/sun3x/dvma.c [new file with mode: 0644]
arch/m68k/sun3x/sbus.c [new file with mode: 0644]
arch/m68k/sun3x/time.c [new file with mode: 0644]
arch/m68k/sun3x/time.h [new file with mode: 0644]
arch/ppc/boot/misc.c
arch/ppc/common_defconfig
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/head.S
arch/ppc/kernel/i8259.c
arch/ppc/kernel/i8259.h
arch/ppc/kernel/indirect_pci.c
arch/ppc/kernel/mk_defs.c
arch/ppc/kernel/open_pic.c
arch/ppc/kernel/pmac_pic.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/process.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/mm/iommu.c
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/mm/init.c
drivers/block/ide-cd.h
drivers/misc/Makefile
drivers/misc/multiface.h [new file with mode: 0644]
drivers/misc/parport_amiga.c [new file with mode: 0644]
drivers/misc/parport_atari.c [new file with mode: 0644]
drivers/misc/parport_init.c
drivers/misc/parport_mfc3.c [new file with mode: 0644]
drivers/net/de4x5.h
drivers/net/ethertap.c
drivers/net/ppp.c
drivers/sbus/char/pcikbd.c
drivers/usb/CREDITS
drivers/usb/README.ohci
drivers/usb/ohci-debug.c
drivers/usb/ohci-hcd.c
drivers/usb/ohci-hcd.h
drivers/usb/ohci.c
drivers/usb/ohci.h
drivers/usb/restart
drivers/usb/stopusb
drivers/usb/usb.h
drivers/video/vesafb.c
fs/adfs/namei.c
fs/buffer.c
fs/ext2/namei.c
fs/isofs/namei.c
fs/locks.c
fs/minix/namei.c
fs/qnx4/namei.c
fs/sysv/namei.c
fs/ufs/namei.c
include/asm-alpha/system.h
include/asm-m68k/atari_SCCserial.h
include/asm-m68k/bootinfo.h
include/asm-m68k/dvma.h [new file with mode: 0644]
include/asm-m68k/floppy.h [new file with mode: 0644]
include/asm-m68k/ide.h
include/asm-m68k/keyboard.h
include/asm-m68k/mvme147hw.h [new file with mode: 0644]
include/asm-m68k/oplib.h [new file with mode: 0644]
include/asm-m68k/page.h
include/asm-m68k/pgtable.h
include/asm-m68k/q40_keyboard.h [new file with mode: 0644]
include/asm-m68k/q40_master.h [new file with mode: 0644]
include/asm-m68k/q40ints.h [new file with mode: 0644]
include/asm-m68k/scatterlist.h
include/asm-m68k/semaphore-helper.h [new file with mode: 0644]
include/asm-m68k/semaphore.h
include/asm-m68k/serial.h
include/asm-m68k/setup.h
include/asm-m68k/sun3x.h [new file with mode: 0644]
include/asm-m68k/system.h
include/asm-m68k/uaccess.h
include/asm-ppc/processor.h
include/asm-ppc/raven.h [new file with mode: 0644]
include/asm-ppc/system.h
include/asm-sparc/smp.h
include/asm-sparc/system.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/system.h
include/asm-sparc64/uaccess.h
init/main.c
mm/filemap.c

diff --git a/CREDITS b/CREDITS
index afaa94d0109ba94e464b91ab8bc8f37377e628cc..52021ec29bccfa794d7a934570430ed919f2645c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2222,6 +2222,12 @@ S: 1507 145th Place SE #B5
 S: Bellevue, Washington 98007
 S: USA
 
+N: Richard Zidlicky
+E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de
+W: http://www.geocities.com/SiliconValley/Bay/2602/
+D: Q40 port - see arch/m68k/q40/README
+S: Germany
+
 N: Werner Zimmermann
 E: Werner.Zimmermann@fht-esslingen.de
 D: CDROM driver "aztcd" (Aztech/Okano/Orchid/Wearnes)
index 90c4851fb729ad6ace57432a105ed5c57b858158..3e09463a601ef063bc5bccb304ff5444e52df6ca 100644 (file)
@@ -10170,27 +10170,11 @@ CONFIG_M68040
   MC68EC040 will not work, as it does not include an MMU (Memory
   Management Unit).
 
-Use -m68040 flag for 68040 specific optimizations
-CONFIG_OPTIMIZE_040
-  If you will only be running this kernel on a 68040-series processor,
-  this will make the kernel run somewhat faster. However, it will no
-  longer run on a 68020 or 68030, no matter whether you included 68020
-  and 68030 support or not. Say N unless the only processor you are
-  compiling support for is the 68040 (or 68LC040).
-
 68060 support
 CONFIG_M68060
   If you anticipate running this kernel on a computer with a MC68060
   processor, say Y. Otherwise, say N.
 
-Use -m68060 flag for 68060 specific optimizations
-CONFIG_OPTIMIZE_060
-  If you will only be running this kernel on a 68060-series processor,
-  this will make the kernel run somewhat faster. However, it will no
-  longer run on a 68020, 68030 or 68040, no matter whether you
-  included support for those processors or not. Say N unless the only
-  processor you are compiling support for is the 68060.
-
 Advanced processor options
 CONFIG_ADVANCED_CPU
   This gives you access to some advanced options for the CPU. The
@@ -10223,25 +10207,9 @@ CONFIG_ZORRO
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
 
-Amiga OCS chipset support
-CONFIG_AMIFB_OCS
-  This enables support for the original Agnus and Denise video chips,
-  found in the Amiga 1000 and most A500's and A2000's. If you intend
-  to run Linux on any of these systems, say Y; otherwise say N.
-
-Amiga ECS chipset support
-CONFIG_AMIFB_ECS
-  This enables support for the Enhanced Chip Set, found in later
-  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If
-  you intend to run Linux on any of these systems, say Y; otherwise
-  say N.
-
-Amiga AGA chipset support
-CONFIG_AMIFB_AGA
-  This enables support for the Advanced Graphics Architecture (also
-  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
-  and CD32. If you intend to run Linux on any of these systems, say Y;
-  otherwise say N.
+CONFIG_AMIGA_PCMCIA
+  Include support in the kernel for pcmcia on Amiga 1200 and Amiga 600.
+  If you intend to use pcmcia cards say Y; otherwise say N.
 
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
@@ -10447,6 +10415,16 @@ CONFIG_HYDRA
   want). The module is called hydra.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Pcmcia NE2000 compatible support
+CONFIG_APNE
+  If you have a pcmcia ne2000 compatible adapter, say Y.  Otherwise,
+  say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called apne.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 Atari Lance support
 CONFIG_ATARILANCE
   Say Y to include support for several Atari Ethernet adapters based
index 22a35a3016844c6b904d24649630dde0db8ffe86..5938cb8cf90f024756c65bdff83952f6098b524c 100644 (file)
@@ -3,10 +3,10 @@
                                  Command Line Options for Linux/m68k
                                  ===================================
 
-Last Update: Nov 28, 1997
-Linux/m68k version: 2.1.64
+Last Update: 2 May 1999
+Linux/m68k version: 2.2.6
 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek)
-Update: jds@kom.auc.dk (Jes Sorensen)
+Update: jds@kom.auc.dk (Jes Sorensen) and faq@linux-m68k.org (Chris Lawrence)
 
 0) Introduction
 ===============
@@ -145,7 +145,7 @@ Syntax: ro
 
 These two options tell the kernel whether it should mount the root
 filesystem read-only or read-write. The default is read-only, except
-for ramdisks which are read-write.
+for ramdisks, which default to read-write.
 
 
 2.3) debug
@@ -216,23 +216,10 @@ drive (with "root=").
 
 
 2.7) swap=
------------
-
-Syntax: swap=<max_age>,<adv>,<decl>,<init_age>,<cl_fract>,<cl_min>,\
-        <pgout_wgt>,<bfout_wgt>
-(All optional)
-
-TODO
-
-
 2.8) buff=
 -----------
 
-Syntax: buff=<max_age>,<adv>,<decl>,<init_age>,<bfout_wgt>,<mem_grace>
-(All optional)
-
-TODO
-
+  I can't find any sign of these options in 2.2.6.
 
 
 3) General Device Options (Amiga and Atari)
@@ -311,7 +298,7 @@ don't need to expand the sound.
 =========================
 
 4.1) video=
---------------
+-----------
 
 Syntax: video=<fbname>:<sub-options...>
 
@@ -322,8 +309,8 @@ below.
 
 NB: Please notice that this option was renamed from `atavideo' to
     `video' during the development of the 1.3.x kernels, thus you
-    might need to update your boot-scripts if upgrading to 2.0.x from
-    an 1.2.13ply kernel.
+    might need to update your boot-scripts if upgrading to 2.x from
+    an 1.2.x kernel.
 
 NBB: The behavior of video= was changed in 2.1.57 so the recommended
 option is to specify the name of the frame buffer.
@@ -705,10 +692,11 @@ down).
 Syntax: video=<fbname>:<sub-options...>
 
 The <fbname> parameter specifies the name of the frame buffer, valid
-options are `amifb', `cyberfb', `retz3' and `clgen', provided that the
-respective frame buffer devices have been compiled into the kernel (or
-compiled as loadable modules). The behavior of the <fbname> option was
-changed in 2.1.57 so it is now recommended to specify this option.
+options are `amifb', `cyber', 'virge', `retz3' and `clgen', provided
+that the respective frame buffer devices have been compiled into the
+kernel (or compiled as loadable modules). The behavior of the <fbname>
+option was changed in 2.1.57 so it is now recommended to specify this
+option.
 
 The <sub-options> is a comma-separated list of the sub-options listed
 below. This option is organized similar to the Atari version of the
@@ -762,8 +750,8 @@ Specify the number of bit-planes for the selected video-mode.
 5.1.3) inverse
 --------------
 
-Use inverted display. Functionally the same as the "inverse"
-sub-option for the Atari.
+Use inverted display (black on white). Functionally the same as the
+"inverse" sub-option for the Atari.
 
 5.1.4) font
 -----------
@@ -787,7 +775,7 @@ the color frame buffer uses the settings of "monitorcap:".
 your monitor can work with, in Hz. <hmin> and <hmax> are the same for
 the horizontal frequency, in kHz.
 
-  The defaults are 50;90;15;38 (Generic Amiga monitor).
+  The defaults are 50;90;15;38 (Generic Amiga multisync monitor).
 
 
 5.2) fd_def_df0=
@@ -804,6 +792,9 @@ hexadecimal with "0x" prefix.
 
 Syntax: wd33c93=<sub-options...>
 
+These options affect the A590/A2091, A3000 and GVP Series II SCSI
+controllers.
+
 The <sub-options> is a comma-separated list of the sub-options listed
 below.
 
@@ -861,7 +852,7 @@ hostadapters.
 -----------
 
   No argument. Used to separate blocks of keywords when there's more
-than one host adapter in the system.
+than one wd33c93-based host adapter in the system.
 
 5.3.7) nodma
 ------------
@@ -905,6 +896,69 @@ controller and should be autodetected by the driver. An example is the
 24 bit region which is specified by a mask of 0x00fffffe.
 
 
+5.5) 53c7xx=
+------------
+
+Syntax: 53c7xx=<sub-options...>
+
+These options affect the A4000T, A4091, WarpEngine, Blizzard 603e+,
+and GForce 040/060 SCSI controllers on the Amiga, as well as the
+builtin MVME 16x SCSI controller.
+
+The <sub-options> is a comma-separated list of the sub-options listed
+below.
+
+5.5.1) nosync
+-------------
+
+Syntax: nosync:0
+
+  Disables sync negotiation for all devices.  Any value after the
+  colon is acceptable (and has the same effect).
+
+5.5.2) noasync
+--------------
+
+Syntax: noasync:0
+
+  Disables async and sync negotiation for all devices.  Any value
+  after the colon is acceptable (and has the same effect).
+
+5.5.3) nodisconnect
+-------------------
+
+Syntax: nodisconnect:0
+
+  Disables SCSI disconnects.  Any value after the colon is acceptable
+  (and has the same effect).
+
+5.5.4) validids
+---------------
+
+Syntax: validids:0xNN
+
+  Specify which SCSI ids the driver should pay attention to.  This is
+  a bitmask (i.e. to only pay attention to ID#4, you'd use 0x10).
+  Default is 0x7f (devices 0-6).
+
+5.5.5) opthi
+5.5.6) optlo
+------------
+
+Syntax: opthi:M,optlo:N
+
+  Specify options for "hostdata->options".  The acceptable definitions
+  are listed in drivers/scsi/53c7xx.h; the 32 high bits should be in
+  opthi and the 32 low bits in optlo.  They must be specified in the
+  order opthi=M,optlo=N.
+
+5.5.7) next
+-----------
+
+  No argument. Used to separate blocks of keywords when there's more
+  than one 53c7xx host adapter in the system.
+
+
 /* Local Variables: */
 /* mode: text       */
 /* End:             */
index cb60ea26802d5ba2b127255ee74eb08a16f805b9..3a5957b095e2cf64919fae67c92175b91291d1c8 100644 (file)
@@ -56,6 +56,11 @@ 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_Q40
+CORE_FILES := $(CORE_FILES) arch/m68k/q40/q40.o
+SUBDIRS := $(SUBDIRS) arch/m68k/q40
+endif
+
 ifdef CONFIG_AMIGA
 CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o
 SUBDIRS := $(SUBDIRS) arch/m68k/amiga
@@ -81,6 +86,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
 SUBDIRS := $(SUBDIRS) arch/m68k/apollo
 endif
 
+ifdef CONFIG_MVME147
+CORE_FILES := $(CORE_FILES) arch/m68k/mvme147/mvme147.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mvme147
+endif
+
 ifdef CONFIG_MVME16x
 CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
 SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
@@ -91,6 +101,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
 SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
 endif
 
+ifdef CONFIG_SUN3X
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
+endif
+
 ifdef CONFIG_M68040
 CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
index 543b04c7499686d3a1eab5a0c3dc5c76de5a4a7c..fc1b5627f859fc461c034972c856a6b68ee42e52 100644 (file)
@@ -417,10 +417,10 @@ void bvme6000_init_console_port (struct console *co, int cflag)
 static void scc_delay (void)
 {
         int n;
-        char i;
+       volatile int trash;
 
         for (n = 0; n < 20; n++)
-                i = *(volatile char *)0;
+               trash = n;
 }
 
 static void scc_write (char ch)
index d8e0457c99368c8962ba735d721938d5d8a405f8..a8dacc904c557bf33d097ea58b78f5dea43d5d4b 100644 (file)
@@ -37,6 +37,7 @@ fi
 bool 'Apollo support' CONFIG_APOLLO
 bool 'VME (Motorola and BVM) support' CONFIG_VME
 if [ "$CONFIG_VME" = "y" ]; then
+  bool 'MVME147 support' CONFIG_MVME147
   bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
   bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
 fi
@@ -44,10 +45,13 @@ bool 'HP9000/300 support' CONFIG_HP300
 if [ "$CONFIG_HP300" = "y" ]; then
   bool 'DIO bus support' CONFIG_DIO
 fi
+bool 'Sun3x support' CONFIG_SUN3X
+  
 define_bool CONFIG_SUN3 n
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
+bool 'Q40/Q60 support' CONFIG_Q40
 
 comment 'Processor type'
 bool '68020 support' CONFIG_M68020
@@ -94,6 +98,29 @@ else
   fi
 fi
 bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT" != "n" ]; then
+    if [ "$CONFIG_AMIGA" != "n" ]; then
+      dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+      if [ "$CONFIG_ZORRO" != "n" ]; then
+        dep_tristate '    Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+      fi
+    fi
+    if [ "$CONFIG_Q40" != "n" ]; then
+       tristate '    Q40 Parallel port' CONFIG_PARPORT
+       if [ "$CONFIG_PARPORT" != "n" ]; then
+         define_bool CONFIG_PARPORT_PC y
+       fi
+    fi
+  fi
+  if [ "$CONFIG_ATARI" == "y" ]; then
+    dep_tristate '    Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  fi
+fi
+
+
 endmenu
 
 source drivers/block/Config.in
@@ -147,6 +174,7 @@ if [ "$CONFIG_ZORRO" = "y" ]; then
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
     bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
+    dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
     bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
@@ -167,6 +195,10 @@ if [ "$CONFIG_MAC" = "y" ]; then
 fi
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
+fi
+
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
 fi
@@ -175,6 +207,10 @@ if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
   bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
 fi
 
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+fi
+
 endmenu
 
 fi
@@ -219,6 +255,9 @@ if [ "$CONFIG_MAC" = "y" ]; then
 #  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
   bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
+fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
 fi
@@ -232,9 +271,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
     tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
   fi
 fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x Lance support' CONFIG_SUNLANCE
+fi
 if [ "$CONFIG_HP300" = "y" ]; then
   bool 'HP on-board LANCE support' CONFIG_HPLANCE
 fi
+if [ "$CONFIG_Q40" = "y" ]; then
+  if [ ! "$CONFIG_PARPORT" = "n" ]; then
+    dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+  fi
+fi
 fi
 endmenu
 
@@ -243,6 +290,23 @@ fi
 mainmenu_option next_comment
 comment 'Character devices'
  
+if [ "$CONFIG_Q40" = "y" ]; then
+   tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL
+fi
+
+if [ "$CONFIG_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+fi
+
+if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
+   bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+   bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+#   bool '   Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
+   bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+   bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
+fi
+
 if [ "$CONFIG_VME" = "n" ]; then
   define_bool CONFIG_VT y
   if [ "$CONFIG_VT" = "y" ]; then
@@ -254,10 +318,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
   define_bool CONFIG_NVRAM y
 fi
 
-tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
-fi
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
+  fi
+else
+  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+  if [ "$CONFIG_PRINTER" != "n" ]; then
+    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+  fi
+fi   
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
 fi
@@ -280,13 +351,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
+  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+  fi
 fi
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  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
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    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
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
   bool 'Mac SCC serial support' CONFIG_MAC_SCC
@@ -294,18 +369,32 @@ fi
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
   tristate 'HP DCA serial support' CONFIG_HPDCA
 fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
+  if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+    bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
+    bool 'Sun mouse support' CONFIG_SUN_MOUSE
+    define_bool CONFIG_SBUS y
+    define_bool CONFIG_SBUSCHAR y
+    define_bool CONFIG_SUN_SERIAL y
+  fi  
+fi
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
-     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
+     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
+     "$CONFIG_SUN3X" = "y" ]; then
   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
        "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
        "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
        "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-       "$CONFIG_HPDCA" = "y" ]; then
+       "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
   fi
 fi
 if [ "$CONFIG_VME" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
+  if [ "$CONFIG_MVME147" = "y" ]; then
+    bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+  fi
   if [ "$CONFIG_MVME16x" = "y" ]; then
     bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
     bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
index e21e4b21c7c9f5dca3e9c888278eb702b9634176..61482c3a86544021e6d45d10b69d99c607be934b 100644 (file)
@@ -164,8 +164,17 @@ SYMBOL_NAME_LABEL(inthandler)
 
        movel   %sp,%sp@-
        movel   %d0,%sp@-               |  put vector # on stack
+#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
+       btstb   #4,0xff000000   | Q40 floppy needs very special treatment ...
+       jbeq    1f
+       btstb   #3,0xff000004           
+       jbeq    1f
+       jbsr    SYMBOL_NAME(floppy_hardint)
+       jbra    3f
+1:             
+#endif         
        jbsr    SYMBOL_NAME(process_int)|  process the IRQ
-       addql   #8,%sp                  |  pop parameters off stack
+3:             addql   #8,%sp                  |  pop parameters off stack
 
 SYMBOL_NAME_LABEL(ret_from_interrupt)
        subql   #1,SYMBOL_NAME(local_irq_count)
@@ -295,6 +304,8 @@ SYMBOL_NAME_LABEL(resume)
 2:     fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
        fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
 3:
+       /* Return previous task in %d1 */
+       movel   %curptr,%d1
 
        /* switch to new task (a1 contains new task) */
        movel   %a1,%curptr
@@ -320,8 +331,15 @@ SYMBOL_NAME_LABEL(resume)
        movec   %d0,%cacr
 
        /* switch the root pointer */
+#ifdef CPU_M68030_ONLY
+       .chip   68030
+       pmovefd %a1@(TASK_TSS+TSS_CRP),%crp
+       .chip   68k
+       pflush  #0,#4
+#else
        pmove   %a1@(TASK_TSS+TSS_CRP),%crp
 #endif
+#endif
 
 #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
        jra     2f      /* skip m68040 stuff */
index 482c15f5084181432e7ddfa2d669f1d7c93af47b..361b10cb663a3681a9b730fbc87220d7590945bd 100644 (file)
@@ -23,6 +23,7 @@
 ** 98/04/25 Phil Blundell: added HP300 support
 ** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
 **            for linux-2.1.115
+** 9/02/11  Richard Zidlicky: added Q40 support (initial vesion 99/01/01) 
 **
 ** 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
 .globl SYMBOL_NAME(availmem)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#ifdef CONFIG_MVME16x
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+#ifdef CONFIG_Q40
+.globl SYMBOL_NAME(q40_mem_cptr)       
+#endif         
 
 CPUTYPE_040    = 1     /* indicates an 040 */
 CPUTYPE_060    = 2     /* indicates an 060 */
@@ -512,13 +519,15 @@ func_define       putn,1
 #endif
 .endm
 
-
 #define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
 #define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
 #define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab
 #define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
 #define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
 #define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
+#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
 
 #define is_040_or_060(lab)     btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
 #define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
@@ -552,9 +561,11 @@ ENTRY(_stext)
        .long   BOOTINFOV_MAGIC
        .long   MACH_AMIGA, AMIGA_BOOTI_VERSION
        .long   MACH_ATARI, ATARI_BOOTI_VERSION
+       .long   MACH_MVME147, MVME147_BOOTI_VERSION
        .long   MACH_MVME16x, MVME16x_BOOTI_VERSION
        .long   MACH_BVME6000, BVME6000_BOOTI_VERSION
        .long   MACH_MAC, MAC_BOOTI_VERSION
+       .long   MACH_Q40, Q40_BOOTI_VERSION     
        .long   0
 1:     jra     SYMBOL_NAME(__start)
 
@@ -859,7 +870,12 @@ L(mmu_init_amiga):
        /*
         * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
         */
-       mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+       mmu_map         #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+       /*
+        * Map the Zorro III I/O space with transparent translation
+        * for frame buffer memory etc.
+        */
+       mmu_map_tt      #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S
 
        jbra    L(mmu_init_done)
 
@@ -867,7 +883,8 @@ L(mmu_init_amiga):
        /*
         * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000
         */
-       mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+       mmu_map         #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+       mmu_map_tt      #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030
 
        jbra    L(mmu_init_done)
 
@@ -926,6 +943,25 @@ L(spata68040):
 L(mmu_init_not_atari):
 #endif
 
+#ifdef CONFIG_Q40
+       is_not_q40(L(notq40))
+       /*
+        * add transparent mapping for 0xff00 0000 - 0xffff ffff
+        * non-cached serialized etc..
+        * this includes master chip, DAC, RTC and ISA ports
+        * 0xfe000000-0xfeffffff is for screen and ROM
+        */
+
+       putc    'Q'
+
+       mmu_map_tt      #0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W
+       mmu_map_tt      #1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S
+       
+       jbra    L(mmu_init_done)
+       
+L(notq40):             
+#endif 
+       
 #ifdef CONFIG_HP300
        is_not_hp300(L(nothp300))
 
@@ -940,6 +976,24 @@ L(nothp300):
 
 #endif
 
+#ifdef CONFIG_MVME147
+
+       is_not_mvme147(L(not147))
+
+       /*
+       * On MVME147 we have already created kernel page tables for
+       * 4MB of RAM at address 0, so now need to do a transparent
+       * mapping of the top of memory space.  Make it 0.5GByte for now,
+       * so we can access on-board i/o areas.
+       */
+
+       mmu_map_tt      #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030
+
+       jbra    L(mmu_init_done)
+
+L(not147):
+#endif /* CONFIG_MVME147 */
+
 #ifdef CONFIG_MVME16x
 
        is_not_mvme16x(L(not16x))
@@ -965,7 +1019,7 @@ L(nothp300):
         * 0xffe00000->0xffe1ffff.
         */
 
-       mmu_map_tt      1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+       mmu_map_tt      #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
 
        jbra    L(mmu_init_done)
 
@@ -985,7 +1039,7 @@ L(not16x):
         * clash with User code virtual address space.
         */
 
-       mmu_map_tt      1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+       mmu_map_tt      #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
 
        jbra    L(mmu_init_done)
 
@@ -1052,13 +1106,23 @@ L(mmu_init_mac):
        mmu_map_eq      #0x50000000,#0x02000000,%d3
        mmu_map_eq      #0x60000000,#0x00400000,%d3
        mmu_map_eq      #0x9c000000,#0x00400000,%d3
-       mmu_map_tt      1,#0xf8000000,#0x08000000,%d3
+       mmu_map_tt      #1,#0xf8000000,#0x08000000,%d3
 
        jbra    L(mmu_init_done)
 
 L(mmu_init_not_mac):
 #endif
 
+#ifdef CONFIG_SUN3X
+       is_not_sun3x(L(notsun3x))
+
+       /* setup tt1 for I/O */
+       mmu_map_tt      #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S
+
+L(notsun3x):
+       jbra    L(mmu_init_done)
+#endif
+
 L(mmu_init_done):
 
        putc    'G'
@@ -1214,6 +1278,14 @@ L(mmu_fixup_done):
 1:
 #endif
 
+#ifdef CONFIG_SUN3X
+       is_not_sun3x(1f)
+
+       /* enable copro */
+       oriw    #0x4000,0x61000000
+1:
+#endif
+
 /*
  * Fixup the addresses for the kernel pointer table and availmem.
  * Convert them from physical addresses to virtual addresses.
@@ -1780,7 +1852,7 @@ func_start        mmu_map_tt,%d0/%d1/%a0,4
        /* Extract the highest bit set
         */
        bfffo   ARG3{#0,#32},%d1
-       cmpw    #8,%d0
+       cmpw    #8,%d1
        jcc     L(do_map)
 
        /* And get the mask
@@ -2155,7 +2227,9 @@ func_start        mmu_temp_map,%d0/%d1/%a0/%a1
        /* Temporary allocate a page table and insert it into the ptr table
         */
        movel   %a1@,%d0
-       addl    #PTR_TABLE_SIZE*4,%a1@
+       /* The 512 should be PAGE_TABLE_SIZE*4, but that violates the
+          alignment restriction for pointer tables on the '0[46]0.  */
+       addl    #512,%a1@
        orw     #_PAGE_TABLE+_PAGE_ACCESSED,%d0
        movel   %d0,%a0@
        dputs   " (new)"
@@ -2703,6 +2777,31 @@ func_start       serial_init,%d0/%d1/%a0/%a1
 L(serial_init_not_mac):
 #endif /* CONFIG_MAC */
 
+#ifdef CONFIG_Q40
+       is_not_q40(2f)
+/* debug output goes into SRAM, so we don't do it unless requested
+   - check for '%LX$' signature in SRAM   */
+       lea     %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+       move.l  #0xff020010,%a1@  /* must be inited - also used by debug=mem */
+       move.l  #0xff020000,%a1   
+       cmp.b   #'%',%a1@
+       bne     2f      /*nodbg*/
+       addq.w  #4,%a1
+       cmp.b   #'L',%a1@
+       bne     2f      /*nodbg*/
+       addq.w  #4,%a1
+       cmp.b   #'X',%a1@
+       bne     2f      /*nodbg*/
+       addq.w  #4,%a1
+       cmp.b   #'$',%a1@
+       bne     2f      /*nodbg*/
+       /* signature OK */
+       lea     %pc@(L(q40_do_debug)),%a1
+       tas     %a1@
+/*nodbg: q40_do_debug is 0 by default*/        
+2:             
+#endif 
+       
 L(serial_init_done):
 func_return    serial_init
 
@@ -2792,6 +2891,15 @@ func_start       serial_putc,%d0/%d1/%a0/%a1
 4:
 #endif /* CONFIG_ATARI */
 
+#ifdef CONFIG_MVME147
+       is_not_mvme147(2f)
+1:     btst    #2,M147_SCC_CTRL_A
+       jeq     1b
+       moveb   %d0,M147_SCC_DATA_A
+       jbra    L(serial_putc_done)
+2:
+#endif
+
 #ifdef CONFIG_MVME16x
        is_not_mvme16x(2f)
        /*
@@ -2805,7 +2913,7 @@ func_start        serial_putc,%d0/%d1/%a0/%a1
        moveml  %sp@+,%d0-%d7/%a2-%a6
        jbra    L(serial_putc_done)
 2:
-#endif CONFIG_MVME162 | CONFIG_MVME167
+#endif CONFIG_MVME16x
 
 #ifdef CONFIG_BVME6000
        is_not_bvme6000(2f)
@@ -2819,6 +2927,18 @@ func_start       serial_putc,%d0/%d1/%a0/%a1
 2:
 #endif
 
+#ifdef CONFIG_Q40
+       is_not_q40(2f)
+       tst.l   %pc@(L(q40_do_debug))   /* only debug if requested */
+       beq     2f
+       lea     %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+       move.l  %a1@,%a0
+       move.b  %d0,%a0@
+       addq.l  #4,%a0
+       move.l  %a0,%a1@
+2:             
+#endif 
+
 L(serial_putc_done):
 func_return    serial_putc
 
@@ -3472,6 +3592,10 @@ L(kernel_pgdir_ptr):
 L(temp_mmap_mem):
        .long   0
 
+#if defined (CONFIG_MVME147)
+M147_SCC_CTRL_A = 0xfffe3002
+M147_SCC_DATA_A = 0xfffe3003
+#endif
 
 #if defined (CONFIG_BVME6000)
 BVME_SCC_CTRL_A        = 0xffb0000b
@@ -3509,3 +3633,9 @@ SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
 SYMBOL_NAME_LABEL(mvme_bdid_ptr)
        .long   0
 #endif
+#if defined(CONFIG_Q40)
+SYMBOL_NAME_LABEL(q40_mem_cptr)
+       .long 0
+L(q40_do_debug):       
+       .long 0 
+#endif
index 20e39f17f6b62a1c765ecc77d20e9eeda4f557d2..66fc41064066f7234e2e8b39b784e7514fcc42be 100644 (file)
 #include <asm/page.h>
 #include <asm/machdep.h>
 
+#ifdef CONFIG_Q40
+#include <asm/q40ints.h>
+#endif
+
 /* table for system interrupt handlers */
 static irq_handler_t irq_list[SYS_IRQS];
 
@@ -177,14 +181,24 @@ void sys_free_irq(unsigned int irq, void *dev_id)
 
 /*
  * Do we need these probe functions on the m68k?
+ *
+ *  ... may be usefull with ISA devices
  */
 unsigned long probe_irq_on (void)
 {
+#ifdef CONFIG_Q40
+       if (MACH_IS_Q40)
+               return q40_probe_irq_on();
+#endif
        return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
+#ifdef CONFIG_Q40
+       if (MACH_IS_Q40)
+               return q40_probe_irq_off(irqs);
+#endif
        return 0;
 }
 
index b32e6a1c99410232aac9c931e8192ddb0f2c7729..4926a6dadac17cc3d7332f0d9f88af04eb096829 100644 (file)
@@ -3,6 +3,47 @@
  */
 
 #define TS_MAGICKEY    0x5a5a5a5a
-#define TS_TSS 482
-#define TS_ESP0 502
-#define TS_FPU 506
+#define TASK_STATE 0
+#define TASK_FLAGS 4
+#define TASK_SIGPENDING 8
+#define TASK_NEEDRESCHED 20
+#define TASK_TSS 470
+#define TASK_MM 622
+#define TSS_KSP 0
+#define TSS_USP 4
+#define TSS_SR 8
+#define TSS_FS 10
+#define TSS_CRP 12
+#define TSS_ESP0 20
+#define TSS_FPREG 24
+#define TSS_FPCNTL 120
+#define TSS_FPSTATE 132
+#define PT_D0 32
+#define PT_ORIG_D0 36
+#define PT_SR 44
+#define PT_VECTOR 50
+#define IRQ_HANDLER 0
+#define IRQ_DEVID 8
+#define IRQ_NEXT 16
+#define STAT_IRQ 120
+#define BIR_TAG 0
+#define BIR_SIZE 2
+#define BIR_DATA 4
+#define FBCON_FONT_DESC_IDX 0
+#define FBCON_FONT_DESC_NAME 4
+#define FBCON_FONT_DESC_WIDTH 8
+#define FBCON_FONT_DESC_HEIGHT 12
+#define FBCON_FONT_DESC_DATA 16
+#define FBCON_FONT_DESC_PREF 20
+#define CUSTOMBASE -2132807680
+#define C_INTENAR 28
+#define C_INTREQR 30
+#define C_INTENA 154
+#define C_INTREQ 156
+#define C_SERDATR 24
+#define C_SERDAT 48
+#define C_SERPER 50
+#define CIAABASE -2134908927
+#define CIABBASE -2134913024
+#define C_PRA 0
+#define ZTWOBASE -2147483648
index 793ca6ec77f68273ccc86935ed91c1dd1b109761..5aae5953cc7dd0f0d78e7cf31699e8fdce07c16a 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
+#include <asm/m68kserial.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 extern char m68k_debug_device[];
@@ -54,6 +55,8 @@ EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_set_cachemode);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
@@ -69,4 +72,5 @@ EXPORT_SYMBOL_NOVERS(memcmp);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
index c7c3f458ee48055a4f38f918b366b914de1a728e..97f3bd15134dcbba1f1724cb5d0649f7e820b1e4 100644 (file)
@@ -169,15 +169,7 @@ asmlinkage int m68k_fork(struct pt_regs *regs)
 
 asmlinkage int m68k_vfork(struct pt_regs *regs)
 {
-       int     child;
-       struct semaphore sem = MUTEX_LOCKED;
-
-       child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
-
-       if (child > 0)
-               down(&sem);
-
-       return child;
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
 }
 
 asmlinkage int m68k_clone(struct pt_regs *regs)
@@ -190,7 +182,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
        newsp = regs->d2;
        if (!newsp)
                newsp = rdusp();
-       return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
+       return do_fork(clone_flags, newsp, regs);
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
index 5aeb2534bece3f8ddd5a6acc08a3750a962ee33c..e9254cfa7e311cb42a2e18ad0e20fb788b5e4c83 100644 (file)
@@ -312,6 +312,7 @@ 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;
+       unsigned long flags;
        int ret;
 
        lock_kernel();
@@ -343,21 +344,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                    (current->uid != child->uid) ||
                    (current->gid != child->egid) ||
                    (current->gid != child->sgid) ||
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
                    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
                        goto out;
                /* the same process cannot be attached many times */
                if (child->flags & PF_PTRACED)
                        goto out;
                child->flags |= PF_PTRACED;
-               if (child->p_pptr != current) {
-                       unsigned long flags;
 
-                       write_lock_irqsave(&tasklist_lock, flags);
+               write_lock_irqsave(&tasklist_lock, flags);
+               if (child->p_pptr != current) {
                        REMOVE_LINKS(child);
                        child->p_pptr = current;
                        SET_LINKS(child);
-                       write_unlock_irqrestore(&tasklist_lock, flags);
                }
+               write_unlock_irqrestore(&tasklist_lock, flags);
+
                send_sig(SIGSTOP, child, 1);
                ret = 0;
                goto out;
@@ -502,7 +504,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                }
 
                case PTRACE_DETACH: { /* detach a process that was attached. */
-                       unsigned long flags;
                        long tmp;
 
                        ret = -EIO;
index ade12c46d9d6f486669cf357b289c98c162a20d6..39dcd9c15ae60ab7a0e93337ccb75972ba93d11b 100644 (file)
@@ -77,10 +77,26 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
 void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
 void (*mach_floppy_eject) (void) = NULL;
 #endif
+struct serial_struct;
+#ifdef CONFIG_SERIAL
+long serial_rs_init(void);
+int serial_register_serial(struct serial_struct *);
+void serial_unregister_serial(int);
+long ser_console_init(long, long );
+#endif
+#if defined(CONFIG_USERIAL)||defined(CONFIG_BVME6000_SCC)||defined(CONFIG_MVME162_SCC)||defined(CONFIG_HPDCA)||defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)||defined(CONFIG_MAC_SCC)||defined(CONFIG_ATARI_MIDI)||defined(CONFIG_ATARI_SCC)||defined(CONFIG_ATARI_MFPSER)
+#define M68K_SERIAL
+#endif
+#ifdef M68K_SERIAL
+long m68k_rs_init(void);
+int m68k_register_serial(struct serial_struct *);
+void m68k_unregister_serial(int);
+long m68k_serial_console_init(long, long );
+#endif
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int) = NULL;
 #endif
@@ -97,15 +113,19 @@ char *mach_sysrq_xlate = NULL;
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
 extern int mac_parse_bootinfo(const struct bi_record *);
+extern int q40_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 config_mvme147(void);
 extern void config_mvme16x(void);
 extern void config_bvme6000(void);
 extern void config_hp300(void);
+extern void config_q40(void);
+extern void config_sun3x(void);
 
 #define MASK_256K 0xfffc0000
 
@@ -149,6 +169,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
                    unknown = atari_parse_bootinfo(record);
                else if (MACH_IS_MAC)
                    unknown = mac_parse_bootinfo(record);
+               else if (MACH_IS_Q40)
+                   unknown = q40_parse_bootinfo(record);
                else
                    unknown = 1;
        }
@@ -258,6 +280,11 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
                config_apollo();
                break;
 #endif
+#ifdef CONFIG_MVME147
+           case MACH_MVME147:
+               config_mvme147();
+               break;
+#endif
 #ifdef CONFIG_MVME16x
            case MACH_MVME16x:
                config_mvme16x();
@@ -272,6 +299,16 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
            case MACH_HP300:
                config_hp300();
                break;
+#endif
+#ifdef CONFIG_Q40
+           case MACH_Q40:
+               config_q40();
+               break;
+#endif
+#ifdef CONFIG_SUN3X
+           case MACH_SUN3X:
+               config_sun3x();
+               break;
 #endif
            default:
                panic ("No configuration setup");
@@ -384,7 +421,52 @@ int get_hardware_list(char *buffer)
     return(len);
 }
 
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_SERIAL) || defined(M68K_SERIAL)
+int rs_init(void)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_rs_init();
+#endif
+#ifdef M68K_SERIAL  
+    return m68k_rs_init();
+#endif
+}
+int register_serial(struct serial_struct *p)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_register_serial(p);
+#endif
+#ifdef M68K_SERIAL
+  return m68k_register_serial(p);
+#endif
+}
+void unregister_serial(int i)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    serial_unregister_serial(i);
+#endif
+#ifdef M68K_SERIAL
+  m68k_unregister_serial(i);
+#endif
+}
+#ifdef CONFIG_SERIAL_CONSOLE
+long serial_console_init(long kmem_start, long kmem_end)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return ser_console_init(kmem_start, kmem_end);
+#endif
+#if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE)
+  return m68k_serial_console_init(kmem_start, kmem_end);
+#endif
+}
+#endif
+#endif
+
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
 __initfunc(void floppy_setup(char *str, int *ints))
 {
        if (mach_floppy_setup)
@@ -399,7 +481,7 @@ void floppy_eject(void)
 #endif
 
 /* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+__initfunc(void kbd_reset_setup(char *str, int *ints))
 {
 }
 
index 1b38e4c7cae50c6ed06b78cc1d9a2799c5a55aca..9b98fdb757d250d0ea6fa2e875fde8332bacfd6b 100644 (file)
@@ -200,5 +200,5 @@ void do_settimeofday(struct timeval *tv)
        time_status |= STA_UNSYNC;
        time_maxerror = NTP_PHASE_LIMIT;
        time_esterror = NTP_PHASE_LIMIT;
-       sti();
+       write_unlock_irq(&xtime_lock);
 }
index 8e4141149b10874e8119cc67e05e17f779c9e7fd..842f83f64e36af6a89134aef6164305057a6fc4b 100644 (file)
@@ -32,6 +32,16 @@ ENTRY(__down_failed_interruptible)
        movel (%sp)+,%a0
        rts
 
+ENTRY(__down_failed_trylock)
+       movel %a0,-(%sp)
+       movel %d1,-(%sp)
+       movel %a1,-(%sp)
+       jbsr SYMBOL_NAME(__down_trylock)
+       movel (%sp)+,%a1
+       movel (%sp)+,%d1
+       movel (%sp)+,%a0
+       rts
+
 ENTRY(__up_wakeup)
        moveml %a0/%d0/%d1,-(%sp)
        movel %a1,-(%sp)
index 8e520702fca79a82c277c6c478e79e000a88791a..9a41dc2795641df1183f405d3940ea73f0810208 100644 (file)
@@ -123,7 +123,7 @@ void show_mem(void)
 unsigned long mm_cachebits = 0;
 #endif
 
-static pte_t *__init kernel_page_table(unsigned long *memavailp)
+__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp))
 {
        pte_t *ptablep;
 
@@ -140,15 +140,19 @@ static pte_t *__init kernel_page_table(unsigned long *memavailp)
 
 static pmd_t *last_pgtable __initdata = NULL;
 
-static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
 {
        if (!last_pgtable) {
                unsigned long pmd, last;
                int i;
 
+               /* Find the last ptr table that was used in head.S and
+                * reuse the remaining space in that page for further
+                * ptr tables.
+                */
                last = (unsigned long)kernel_pg_dir;
                for (i = 0; i < PTRS_PER_PGD; i++) {
-                       if (!pgd_val(kernel_pg_dir[i]))
+                       if (!pgd_present(kernel_pg_dir[i]))
                                continue;
                        pmd = pgd_page(kernel_pg_dir[i]);
                        if (pmd > last)
@@ -175,8 +179,8 @@ static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
        return last_pgtable;
 }
 
-static unsigned long __init
-map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, long size, unsigned long *memavailp))
 {
 #define PTRTREESIZE (256*1024)
 #define ROOTTREESIZE (32*1024*1024)
@@ -282,8 +286,8 @@ extern char __init_begin, __init_end;
  * paging_init() continues the virtual memory environment setup which
  * was begun by the code in arch/head.S.
  */
-unsigned long __init paging_init(unsigned long start_mem,
-                                unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+                                    unsigned long end_mem))
 {
        int chunk;
        unsigned long mem_avail = 0;
@@ -392,7 +396,7 @@ unsigned long __init paging_init(unsigned long start_mem,
        return PAGE_ALIGN(free_area_init(start_mem, end_mem));
 }
 
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
        int codepages = 0;
        int datapages = 0;
@@ -443,7 +447,7 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
        /* insert pointer tables allocated so far into the tablelist */
        init_pointer_table((unsigned long)kernel_pg_dir);
        for (i = 0; i < PTRS_PER_PGD; i++) {
-               if (pgd_val(kernel_pg_dir[i]))
+               if (pgd_present(kernel_pg_dir[i]))
                        init_pointer_table(pgd_page(kernel_pg_dir[i]));
        }
 
index d2cd29011a88c62a6d8c5cf03da32fbd11d06726..3fefe4e03fbabf8a04a31e2613f09da1a13e7552 100644 (file)
@@ -116,6 +116,14 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
        if (!size || size > physaddr + size)
                return NULL;
 
+#ifdef CONFIG_AMIGA
+       if (MACH_IS_AMIGA) {
+               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+                   && (cacheflag == IOMAP_NOCACHE_SER))
+                       return (void *)physaddr;
+       }
+#endif
+
 #ifdef DEBUG
        printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
 #endif
@@ -174,7 +182,7 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
                }
        }
 
-       while (size > 0) {
+       while ((long)size > 0) {
 #ifdef DEBUG
                if (!(virtaddr & (PTRTREESIZE-1)))
                        printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
@@ -187,7 +195,7 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
                }
 
                if (CPU_IS_020_OR_030) {
-                       pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
                        physaddr += PTRTREESIZE;
                        virtaddr += PTRTREESIZE;
                        size -= PTRTREESIZE;
@@ -217,7 +225,14 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
  */
 void iounmap(void *addr)
 {
+#ifdef CONFIG_AMIGA
+       if ((!MACH_IS_AMIGA) ||
+           (((unsigned long)addr < 0x40000000) ||
+            ((unsigned long)addr > 0x60000000)))
+                       free_io_area(addr);
+#else
        free_io_area(addr);
+#endif
 }
 
 /*
@@ -232,7 +247,7 @@ void __iounmap(void *addr, unsigned long size)
        pmd_t *pmd_dir;
        pte_t *pte_dir;
 
-       while (size > 0) {
+       while ((long)size > 0) {
                pgd_dir = pgd_offset_k(virtaddr);
                if (pgd_bad(*pgd_dir)) {
                        printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -242,7 +257,7 @@ void __iounmap(void *addr, unsigned long size)
                pmd_dir = pmd_offset(pgd_dir, virtaddr);
 
                if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
 
                        if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
                                pmd_dir->pmd[pmd_off] = 0;
@@ -308,7 +323,7 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
                }
        }
 
-       while (size > 0) {
+       while ((long)size > 0) {
                pgd_dir = pgd_offset_k(virtaddr);
                if (pgd_bad(*pgd_dir)) {
                        printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -318,7 +333,7 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
                pmd_dir = pmd_offset(pgd_dir, virtaddr);
 
                if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
 
                        if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
                                pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
index a97578ec24b354e2864ee0045648d13c7413a466..a6d496571bd509d6997e4ed040ad766697c6f5f9 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/pagemap.h>
 
 #include <asm/setup.h>
 #include <asm/segment.h>
@@ -93,12 +94,11 @@ typedef struct page ptable_desc;
 static ptable_desc ptable_list = { &ptable_list, &ptable_list };
 
 #define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset)
-#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT))
 #define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)])
 
 #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
 
-void __init init_pointer_table(unsigned long ptable)
+__initfunc(void init_pointer_table(unsigned long ptable))
 {
        ptable_desc *dp;
        unsigned long page = ptable & PAGE_MASK;
@@ -166,7 +166,7 @@ pmd_t *get_pointer_table (void)
                (dp->next = last->next)->prev = dp;
                (dp->prev = last)->next = dp;
        }
-       return (pmd_t *) (PD_PAGE(dp) + off);
+       return (pmd_t *) (page_address(dp) + off);
 }
 
 int free_pointer_table (pmd_t *ptable)
@@ -215,8 +215,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
        /* function code match? */
        base = (regval >> 4) & 7;
        mask = ~(regval & 7);
-       if ((SUPER_DATA & mask) != (base & mask))
-           return( 0 );
+       if (((SUPER_DATA ^ base) & mask) != 0)
+           return 0;
     }
     else {
        /* must not be user-only */
@@ -226,8 +226,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
 
     /* address match? */
     base = regval & 0xff000000;
-    mask = ~((regval << 8) & 0xff000000);
-    return( (vaddr & mask) == (base & mask) );
+    mask = ~(regval << 8) & 0xff000000;
+    return ((vaddr ^ base) & mask) == 0;
 }
 
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
diff --git a/arch/m68k/mvme147/147ints.c b/arch/m68k/mvme147/147ints.c
new file mode 100644 (file)
index 0000000..3121ad9
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * arch/m68k/mvme147/147ints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * 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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+       void            (*handler)(int, void *, struct pt_regs *);
+       unsigned long   flags;
+       void            *dev_id;
+       const char      *devname;
+       unsigned        count;
+} irq_tab[256];
+
+/*
+ * void mvme147_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns:    Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ (void)
+{
+       int i;
+
+       for (i = 0; i < 256; i++) {
+               irq_tab[i].handler = mvme147_defhand;
+               irq_tab[i].flags = IRQ_FLG_STD;
+               irq_tab[i].dev_id = NULL;
+               irq_tab[i].devname = NULL;
+               irq_tab[i].count = 0;
+       }
+}
+
+int mvme147_request_irq(unsigned int irq,
+               void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+       if (irq > 255) {
+               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+               return -ENXIO;
+       }
+       if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+               if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+                       printk("%s: IRQ %d from %s is not replaceable\n",
+                              __FUNCTION__, irq, irq_tab[irq].devname);
+                       return -EBUSY;
+               }
+               if (flags & IRQ_FLG_REPLACE) {
+                       printk("%s: %s can't replace IRQ %d from %s\n",
+                              __FUNCTION__, devname, irq, irq_tab[irq].devname);
+                       return -EBUSY;
+               }
+       }
+       irq_tab[irq].handler = handler;
+       irq_tab[irq].flags   = flags;
+       irq_tab[irq].dev_id  = dev_id;
+       irq_tab[irq].devname = devname;
+       return 0;
+}
+
+void mvme147_free_irq(unsigned int irq, void *dev_id)
+{
+       if (irq > 255) {
+               printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+               return;
+       }
+       if (irq_tab[irq].dev_id != dev_id)
+               printk("%s: Removing probably wrong IRQ %d from %s\n",
+                      __FUNCTION__, irq, irq_tab[irq].devname);
+
+       irq_tab[irq].handler = mvme147_defhand;
+       irq_tab[irq].flags   = IRQ_FLG_STD;
+       irq_tab[irq].dev_id  = NULL;
+       irq_tab[irq].devname = NULL;
+}
+
+void mvme147_process_int (unsigned long vec, struct pt_regs *fp)
+{
+       if (vec > 255)
+               printk ("mvme147_process_int: Illegal vector %ld\n", vec);
+       else
+       {
+               irq_tab[vec].count++;
+               irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+       }
+}
+
+int mvme147_get_irq_list (char *buf)
+{
+       int i, len = 0;
+
+       for (i = 0; i < 256; i++) {
+               if (irq_tab[i].count)
+                       len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+                           i, irq_tab[i].count,
+                           irq_tab[i].devname ? irq_tab[i].devname : "free");
+       }
+       return len;
+}
+
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+       printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void mvme147_enable_irq (unsigned int irq)
+{
+}
+
+
+void mvme147_disable_irq (unsigned int irq)
+{
+}
+
diff --git a/arch/m68k/mvme147/Makefile b/arch/m68k/mvme147/Makefile
new file mode 100644 (file)
index 0000000..c0f0641
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/mvme147 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+O_TARGET := mvme147.o
+O_OBJS   := config.o 147ints.o
+
+
+include $(TOPDIR)/Rules.make
+
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
new file mode 100644 (file)
index 0000000..639d5f6
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ *  arch/m68k/mvme147/config.c
+ *
+ *  Copyright (C) 1996 Dave Frascone [chaos@mindspring.com]
+ *  Cloned from        Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <stdarg.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 <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/mvme147hw.h>
+
+
+extern void mvme147_process_int (int level, struct pt_regs *regs);
+extern void mvme147_init_IRQ (void);
+extern void mvme147_free_irq (unsigned int, void *);
+extern int  mvme147_get_irq_list (char *);
+extern void mvme147_enable_irq (unsigned int);
+extern void mvme147_disable_irq (unsigned int);
+static void mvme147_get_model(char *model);
+static int  mvme147_get_hardware_list(char *buffer);
+extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int mvme147_keyb_init(void);
+extern int mvme147_kbdrate (struct kbd_repeat *);
+extern unsigned long mvme147_gettimeoffset (void);
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int mvme147_hwclk (int, struct hwclk_time *);
+extern int mvme147_set_clock_mmss (unsigned long);
+extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev);
+extern void mvme147_reset (void);
+extern void mvme147_waitbut(void);
+
+
+static int bcd2int (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme147_process_int() */
+
+void (*tick_handler)(int, void *, struct pt_regs *);
+
+
+int mvme147_kbdrate (struct kbd_repeat *k)
+{
+       return 0;
+}
+
+void mvme147_reset()
+{
+       printk ("\r\n\nCalled mvme147_reset\r\n");
+       m147_pcc->watchdog = 0x0a;      /* Clear timer */
+       m147_pcc->watchdog = 0xa5;      /* Enable watchdog - 100ms to reset */
+       while (1)
+               ;
+}
+
+static void mvme147_get_model(char *model)
+{
+       sprintf(model, "Motorola MVME147");
+}
+
+
+static int mvme147_get_hardware_list(char *buffer)
+{
+       *buffer = '\0';
+
+       return 0;
+}
+
+
+__initfunc(void config_mvme147(void))
+{
+       mach_sched_init         = mvme147_sched_init;
+       mach_keyb_init          = mvme147_keyb_init;
+       mach_kbdrate            = mvme147_kbdrate;
+       mach_init_IRQ           = mvme147_init_IRQ;
+       mach_gettimeoffset      = mvme147_gettimeoffset;
+       mach_gettod             = mvme147_gettod;
+       mach_hwclk              = mvme147_hwclk;
+       mach_set_clock_mmss     = mvme147_set_clock_mmss;
+       mach_reset              = mvme147_reset;
+       mach_free_irq           = mvme147_free_irq;
+       mach_process_int        = mvme147_process_int;
+       mach_get_irq_list       = mvme147_get_irq_list;
+       mach_request_irq        = mvme147_request_irq;
+       enable_irq              = mvme147_enable_irq;
+       disable_irq             = mvme147_disable_irq;
+       mach_get_model          = mvme147_get_model;
+       mach_get_hardware_list  = mvme147_get_hardware_list;
+}
+
+
+/* Using pcc tick timer 1 */
+
+static void mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+       m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  
+       m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+       tick_handler(irq, dev_id, fp);
+}
+
+
+void mvme147_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+       tick_handler = timer_routine;
+       request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, 
+               IRQ_FLG_REPLACE, "timer 1", NULL);
+       
+       /* Init the clock with a value */
+       /* our clock goes off every 6.25us */
+       m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
+       m147_pcc->t1_cntrl = 0x0;       /* clear timer */
+       m147_pcc->t1_cntrl = 0x3;       /* start timer */
+       m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  /* clear pending ints */
+       m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+}
+
+/* This is always executed with interrupts disabled.  */
+/* XXX There are race hazards in this code XXX */
+unsigned long mvme147_gettimeoffset (void)
+{
+       volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
+       unsigned short n;
+
+       n = *cp;
+       while (n != *cp)
+               n = *cp;
+
+       n -= PCC_TIMER_PRELOAD;
+       return (unsigned long)n * 25 / 4;
+}
+
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+       m147_rtc->ctrl = RTC_READ;
+       *year = bcd2int (m147_rtc->bcd_year);
+       *mon = bcd2int (m147_rtc->bcd_mth);
+       *day = bcd2int (m147_rtc->bcd_dom);
+       *hour = bcd2int (m147_rtc->bcd_hr);
+       *min = bcd2int (m147_rtc->bcd_min);
+       *sec = bcd2int (m147_rtc->bcd_sec);
+       m147_rtc->ctrl = 0;
+}
+
+static int bcd2int (unsigned char b)
+{
+       return ((b>>4)*10 + (b&15));
+}
+
+int mvme147_hwclk(int op, struct hwclk_time *t)
+{
+       return 0;
+}
+
+int mvme147_set_clock_mmss (unsigned long nowtime)
+{
+       return 0;
+}
+
+int mvme147_keyb_init (void)
+{
+       return 0;
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+void m147_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void mvme147_init_console_port (struct console *co, int cflag)
+{
+       co->write = m147_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+       int n;
+       volatile int trash;
+
+       for (n = 0; n < 20; n++)
+               trash = n;
+}
+
+static void scc_write (char ch)
+{
+       volatile char *p = (volatile char *)M147_SCC_A_ADDR;
+
+       do {
+               scc_delay();
+       }
+       while (!(*p & 4));
+       scc_delay();
+       *p = 8;
+       scc_delay();
+       *p = ch;
+}
+
+
+void m147_scc_write (struct console *co, const char *str, unsigned count)
+{
+       unsigned long   flags;
+
+       save_flags(flags);
+       cli();
+
+       while (count--)
+       {
+               if (*str == '\n')
+                       scc_write ('\r');
+               scc_write (*str++);
+       }
+       restore_flags(flags);
+}
+
index 838c3bbacf027921ff13f1d79af529408ff651f4..db7eb3137e083cf3eac6a9246d64551b0687f775 100644 (file)
@@ -335,10 +335,10 @@ void mvme16x_init_console_port (struct console *co, int cflag)
 static void scc_delay (void)
 {
        int n;
-       char i;
+       volatile int trash;
 
        for (n = 0; n < 20; n++)
-               i = *(volatile char *)0;
+               trash = n;
 }
 
 static void scc_write (char ch)
diff --git a/arch/m68k/q40/Makefile b/arch/m68k/q40/Makefile
new file mode 100644 (file)
index 0000000..9085888
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/q40 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := q40.o
+O_OBJS   := config.o q40ints.o 
+
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README
new file mode 100644 (file)
index 0000000..5433796
--- /dev/null
@@ -0,0 +1,121 @@
+Linux for the Q40
+=================
+
+You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
+some up to date information. Booter and other tools will be also
+available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
+and mirrors.
+
+Hints to documentation usually refer to the linux source tree in
+/usr/src/linux unless URL given.
+
+It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is 
+not yet implemented - do not try it! (See below)
+
+For a list of kernel commandline options read the documentation for the
+particular device drivers.
+
+The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
+When something blocks interrupts (HD) it will loose some of them, so far 
+this is not known to have caused any data loss. On hihgly loaded systems
+it can make the floppy very slow. Other Q40 OS' simply poll the floppy
+for this reason - something that can't be done in Linux.
+Only possible cure is getting a 82072 contoler with fifo instead of 
+the 8272A
+
+drivers used by the Q40, appart from the very obvious (console etc.):
+       drivers/char/q40_keyb.c         # use PC keymaps for national keyboards
+                    serial.c           # normal PC driver - any speed
+                    lp.c               # printer driver
+               char/joystick/*         # most of this should work
+               block/q40ide.c          # startup for ide
+                     ide*              # see Documentation/ide.txt
+                     floppy.c          # normal PC driver, DMA emu in asm/floppy.h
+                                       # and arch/m68k/kernel/entry.S
+                                       # see drivers/block/README.fd
+               video/q40fb.c
+               misc/parport_pc.c
+
+Various other PC drivers can be enabled simply by adding them to 
+arch/m68k/config.in, especially 8 bit devices should be without any
+problems. For cards using 16bit io/mem more care is required, like 
+checking byteorder issues, hacking memcpy_*_io etc.
+
+
+Debugging
+=========
+
+Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, 
+preceded by the booter signature. This is a trace just in case something 
+went wrong during earliest setup stages. 
+*Changed* to preserve SRAM contents by default, this is only done when 
+requested - SRAM must start with '%LX$' signature to do this. '-d' option 
+to 'lxx' loader enables this.
+
+SRAM can also be used as additional console device, use debug=mem.
+This will save kernel startup msgs into SRAM, the screen will display 
+only the penguin - and shell prompt if it gets that far..
+
+Serial console works and can also be used for debugging, provided serial
+initialisation works.
+
+Most problems seem to be caused by fawlty or badly configured io-cards or 
+harddrives anyway..there are so many things that can go wrong here.
+Make sure to configure the parallel port as SPP for first testing..the
+Q40 may have trouble with parallel interrupts.
+
+
+Q40 Hardware Description
+========================
+
+This is just an overview, see asm-m68k/* for details ask if you have any 
+questions.
+
+The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
+keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB
+shadow ROM.
+
+Most interfacing like floppy, hd, serial, parallel ports is done via ISA 
+slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate 
+regions of the memory.
+The main interrupt register IIRQ_REG will indicate whether an IRQ was internal 
+or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
+
+The Q40 custom chip is programmable to provide 2 periodic timers:
+       - 50 or 200 Hz - level 2,  !!THIS CANT BE DISABLED!!
+       - 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..)
+
+Linux uses the 200 Hz interrupt for timer and beep by default.
+
+
+Interrupts
+==========
+
+q40 master chip handles only level triggered interrupts :-((
+further limitation is no disabling etc. Unless someone finds 
+some ingenious clue this means autoprobing will never work.
+Parallel port interrupts cause most trouble..
+
+IRQ sharing is not yet implemented.
+
+
+Keyboard
+========
+
+q40 receives AT make/break codes from the keyboard, these are translated to
+the PC scancodes x86 Linux uses. So by theory every national keyboard should
+work just by loading the apropriate x86 keytable - see any national-HOWTO.
+
+Unfortunately the AT->PC translation isn't quite trivial and even worse, my 
+documentation of it is absolutely minimal - thus some exotic keys may not 
+behave exactly as expected.
+
+There is still hope that it can be fixed completely though. If you encounter 
+problems, email me idealy this:
+       - exact keypress/release sequence
+       - 'showkey -s' run on q40, non-X session
+       - 'showkey -s' run on a PC, non-X session
+       - AT codes as displayed by the q40 debuging ROM
+btw if the showkey output from PC and Q40 doesn't differ then you have some
+classic configuration problem - don't send me anything in this case
+
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
new file mode 100644 (file)
index 0000000..e3c35c6
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ *  arch/m68k/q40/config.c
+ *
+ * originally based on:
+ *
+ *  linux/bvme/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.
+ */
+
+#include <stdarg.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 <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/q40_master.h>
+#include <asm/keyboard.h>
+
+extern void fd_floppy_eject(void);
+extern void fd_floppy_setup(char *str, int *ints);
+
+extern void q40_process_int (int level, struct pt_regs *regs);
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+extern void q40_init_IRQ (void);
+extern void q40_free_irq (unsigned int, void *);
+extern int  q40_get_irq_list (char *);
+extern void q40_enable_irq (unsigned int);
+extern void q40_disable_irq (unsigned int);
+static void q40_get_model(char *model);
+static int  q40_get_hardware_list(char *buffer);
+extern int  q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  q40_keyb_init(void);
+extern int  q40_kbdrate (struct kbd_repeat *);
+extern unsigned long q40_gettimeoffset (void);
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int q40_hwclk (int, struct hwclk_time *);
+extern int q40_set_clock_mmss (unsigned long);
+extern void q40_reset (void);
+extern void q40_waitbut(void);
+void q40_set_vectors (void);
+extern void (*kd_mksound)(unsigned int, unsigned int);
+void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+
+extern char *saved_command_line;
+extern char m68k_debug_device[];
+static void q40_mem_console_write(struct console *co, const char *b,
+                                   unsigned int count);
+
+static int ql_ticks=0;
+static int sound_ticks=0;
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+static int q40_wait_key(struct console *co){return 0;}
+static struct console q40_console_driver = {
+       "debug",
+       NULL,                   /* write */
+       NULL,                   /* read */
+       NULL,                   /* device */
+       q40_wait_key,           /* wait_key */
+       NULL,                   /* unblank */
+       NULL,                   /* setup */
+       CON_PRINTBUFFER,
+       -1,
+       0,
+       NULL
+};
+
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c */
+
+/* static void (*tick_handler)(int, void *, struct pt_regs *); */
+
+
+/* early debugging function:*/
+extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
+static int _cpleft;
+
+static void q40_mem_console_write(struct console *co, const char *s,
+                                 unsigned int count)
+{
+  char *p=(char *)s;
+
+  if (count<_cpleft)
+    while (count-- >0){
+      *q40_mem_cptr=*p++;
+      q40_mem_cptr+=4;
+      _cpleft--;
+    }
+}
+#if 0
+void printq40(char *str)
+{
+  int l=strlen(str);
+  char *p=q40_mem_cptr;
+
+  while (l-- >0 && _cpleft-- >0)
+    {
+      *p=*str++;
+      p+=4;
+    }
+  q40_mem_cptr=p;
+}
+#endif
+
+#if 0
+int q40_kbdrate (struct kbd_repeat *k)
+{
+       return 0;
+}
+#endif
+
+void q40_reset()
+{
+
+       printk ("\n\n*******************************************\n"
+                     "Called q40_reset : press the RESET button!! \n");
+       printk(     "*******************************************\n");
+
+       while(1)
+               ;
+}
+
+static void q40_get_model(char *model)
+{
+    sprintf(model, "Q40");
+}
+
+
+/* No hardware options on Q40? */
+
+static int q40_get_hardware_list(char *buffer)
+{
+    *buffer = '\0';
+    return 0;
+}
+
+
+__initfunc(void config_q40(void))
+{
+    mach_sched_init      = q40_sched_init;           /* ok */
+    /*mach_kbdrate         = q40_kbdrate;*/          /* unneeded ?*/
+    mach_keyb_init       = q40_keyb_init;            /* OK */
+    mach_init_IRQ        = q40_init_IRQ;   
+    mach_gettimeoffset   = q40_gettimeoffset; 
+    mach_gettod         = q40_gettod;
+    mach_hwclk           = q40_hwclk; 
+    mach_set_clock_mmss         = q40_set_clock_mmss;
+/*  mach_mksound         = q40_mksound; */
+    mach_reset          = q40_reset;           /* use reset button instead !*/
+    mach_free_irq       = q40_free_irq; 
+    mach_process_int    = q40_process_int;
+    mach_get_irq_list   = q40_get_irq_list;
+    mach_request_irq    = q40_request_irq;
+    enable_irq          = q40_enable_irq;
+    disable_irq          = q40_disable_irq;
+    mach_default_handler = &q40_sys_default_handler;
+    mach_get_model       = q40_get_model; /* no use..*/
+    mach_get_hardware_list = q40_get_hardware_list; /* no use */
+    kd_mksound             = q40_mksound;
+    /*mach_kbd_leds        = q40kbd_leds;*/
+#ifdef CONFIG_MAGIC_SYSRQ
+    mach_sysrq_key       = 0x54;
+#endif
+    conswitchp = &dummy_con;
+#ifdef CONFIG_BLK_DEV_FD
+    mach_floppy_setup    = fd_floppy_setup;
+    mach_floppy_eject    = fd_floppy_eject;
+    /**/
+#endif
+
+    mach_max_dma_address = 0;   /* no DMA at all */
+
+
+/* userfull for early debuging stages writes kernel messages into SRAM */
+
+    if (!strncmp( m68k_debug_device,"mem",3 ))
+      {
+       /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+       _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
+       q40_console_driver.write = q40_mem_console_write;
+       register_console(&q40_console_driver);
+      }
+}
+
+
+int q40_parse_bootinfo(const struct bi_record *rec)
+{
+  return 1;  /* unknown */
+}
+
+#define DAC_LEFT  ((unsigned char *)0xff008000)
+#define DAC_RIGHT ((unsigned char *)0xff008004)
+void q40_mksound(unsigned int hz, unsigned int ticks)
+{
+  /* for now ignore hz, except that hz==0 switches off sound */
+  /* simply alternate the ampl 0-255-0-.. at 200Hz */
+  if (hz==0)
+    {
+      if (sound_ticks)
+       sound_ticks=1; /* atomic - no irq spinlock used */
+
+      *DAC_LEFT=0;
+      *DAC_RIGHT=0;
+
+      return;
+    }
+  /* sound itself is done in q40_timer_int */
+  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
+  sound_ticks=ticks<<1;
+}
+
+static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+
+static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if (HZ==10000)
+    master_outb(-1,SAMPLE_CLEAR_REG);
+#else /* must be 50 or 100 */
+    master_outb(-1,FRAME_CLEAR_REG);
+#endif
+
+#if (HZ==100)
+    ql_ticks = ql_ticks ? 0 : 1;
+    if (sound_ticks)
+      {
+       unsigned char sval=(sound_ticks & 1) ? 0 : 255;
+       sound_ticks--;
+       *DAC_LEFT=sval;
+       *DAC_RIGHT=sval;
+      }
+    if (ql_ticks) return;
+#endif
+    q40_timer_routine(irq, dev_id, fp);
+}
+
+
+void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    int timer_irq;
+
+    q40_timer_routine = timer_routine;
+
+#if (HZ==10000)
+    timer_irq=Q40_IRQ_TIMER;
+#else
+    timer_irq=Q40_IRQ_FRAME;
+#endif
+
+    /*printk("registering sched/timer IRQ %d\n", timer_irq);*/
+
+    if (request_irq(timer_irq, q40_timer_int, 0,
+                               "timer", q40_timer_int))
+       panic ("Couldn't register timer int");
+
+#if (HZ==10000)
+    master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
+    master_outb(-1,SAMPLE_CLEAR_REG);
+    master_outb(1,SAMPLE_ENABLE_REG);
+#else
+    master_outb(-1,FRAME_CLEAR_REG);   /* not necessary ? */
+#if (HZ==100)
+    master_outb( 1,FRAME_RATE_REG);
+#endif
+#endif
+}
+
+
+unsigned long q40_gettimeoffset (void)
+{
+#if (HZ==100)
+    return 5000*(ql_ticks!=0);
+#else
+    return 0;
+#endif
+}
+
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+       RTC_CTRL |= RTC_READ;
+       *year = bcd2bin (RTC_YEAR);
+       *mon = bcd2bin (RTC_MNTH)-1;
+       *day = bcd2bin (RTC_DATE);
+       *hour = bcd2bin (RTC_HOUR);
+       *min = bcd2bin (RTC_MINS);
+       *sec = bcd2bin (RTC_SECS);
+       RTC_CTRL &= ~(RTC_READ);
+
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+       return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+       return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ *  struct hwclk_time {
+ *         unsigned        sec;       0..59
+ *         unsigned        min;       0..59
+ *         unsigned        hour;      0..23
+ *         unsigned        day;       1..31
+ *         unsigned        mon;       0..11
+ *         unsigned        year;      00...
+ *         int             wday;      0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int q40_hwclk(int op, struct hwclk_time *t)
+{
+        if (op)
+       {       /* Write.... */
+               RTC_CTRL |= RTC_WRITE;
+
+               RTC_SECS = bin2bcd(t->sec);
+               RTC_MINS = bin2bcd(t->min);
+               RTC_HOUR = bin2bcd(t->hour);
+               RTC_DATE = bin2bcd(t->day);
+               RTC_MNTH = bin2bcd(t->mon + 1);
+               RTC_YEAR = bin2bcd(t->year%100);
+               if (t->wday >= 0)
+                       RTC_DOW = bin2bcd(t->wday+1);
+
+               RTC_CTRL &= ~(RTC_WRITE);
+       }
+       else
+       {       /* Read....  */
+         RTC_CTRL |= RTC_READ;
+
+         t->year = bcd2bin (RTC_YEAR);
+         t->mon  = bcd2bin (RTC_MNTH)-1;
+         t->day  = bcd2bin (RTC_DATE);
+         t->hour = bcd2bin (RTC_HOUR);
+         t->min  = bcd2bin (RTC_MINS);
+         t->sec  = bcd2bin (RTC_SECS);
+
+         RTC_CTRL &= ~(RTC_READ);
+         
+         if (t->year < 70)
+           t->year += 100;
+         t->wday = bcd2bin(RTC_DOW)-1;
+
+       }
+
+       return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
+ * clock is out by > 30 minutes.  Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int q40_set_clock_mmss (unsigned long nowtime)
+{
+       int retval = 0;
+       short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+       int rtc_minutes;
+
+
+       rtc_minutes = bcd2bin (RTC_MINS);
+
+       if ((rtc_minutes < real_minutes
+               ? real_minutes - rtc_minutes
+                       : rtc_minutes - real_minutes) < 30)
+       {          
+               RTC_CTRL |= RTC_WRITE;
+               RTC_MINS = bin2bcd(real_minutes);
+               RTC_SECS = bin2bcd(real_seconds);
+               RTC_CTRL &= ~(RTC_WRITE);
+       }
+       else
+               retval = -1;
+
+
+       return retval;
+}
+
+extern void q40kbd_init_hw(void);
+
+int q40_keyb_init (void)
+{
+        q40kbd_init_hw();
+       return 0;
+}
+
+#if 0
+/* dummy to cause */
+void q40_slow_io()
+{
+  return;
+}
+#endif
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
new file mode 100644 (file)
index 0000000..e9b5a5b
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * arch/m68k/q40/q40ints.c
+ *
+ * Copyright (C) 1999 Richard Zidlicky
+ *
+ * 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.
+ *
+ * losely based on bvme6000ints.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+#include <asm/q40_master.h>
+#include <asm/q40ints.h>
+
+/* 
+ * Q40 IRQs are defined as follows: 
+ *            3,4,5,6,7,10,11,14,15 : ISA dev IRQs
+ *            16-31: reserved
+ *            32   : keyboard int
+ *            33   : frame int (50 Hz periodic timer)
+ *            34   : sample int (10/20 KHz periodic timer)
+ *          
+*/
+
+extern int ints_inited;
+
+
+void q40_irq2_handler (int, void *, struct pt_regs *fp);
+
+
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+#define DEVNAME_SIZE 24
+
+static struct {
+       void            (*handler)(int, void *, struct pt_regs *);
+       unsigned long   flags;
+       void            *dev_id;
+        char           devname[DEVNAME_SIZE];
+       unsigned        count;
+} irq_tab[Q40_IRQ_MAX+1];
+
+/*
+ * void q40_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns:    Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the q40 IRQ handling routines.
+ */
+
+void q40_init_IRQ (void)
+{
+       int i;
+
+       for (i = 0; i <= Q40_IRQ_MAX; i++) {
+               irq_tab[i].handler = q40_defhand;
+               irq_tab[i].flags = IRQ_FLG_STD;
+               irq_tab[i].dev_id = NULL;
+               irq_tab[i].devname[0] = 0;
+               irq_tab[i].count = 0;
+       }
+
+       /* setup handler for ISA ints */
+       sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL);
+
+       /* now enable some ints.. */
+
+#if 0  /* has been abandoned */
+       master_outb(1,SER_ENABLE_REG);
+#endif
+       master_outb(1,EXT_ENABLE_REG);
+
+       /* would be spurious ints by now, q40kbd_init_hw() does that */
+       master_outb(0,KEY_IRQ_ENABLE_REG);
+}
+
+int q40_request_irq(unsigned int irq,
+               void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+  /*printk("q40_request_irq %d, %s\n",irq,devname);*/
+
+       if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+               printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+               return -ENXIO;
+       }
+
+       /* test for ISA ints not implemented by HW */
+       if (irq<15) 
+         {
+           switch (irq){
+           case 1: case 2: case 8: case 9:
+           case 12: case 13:
+             printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+             return -ENXIO;
+           default:
+           }
+         }
+
+       if (irq<Q40_IRQ_TIMER)
+         {
+           if (irq==11) {
+             printk("warning IRQ 10 and 11 not distinguishable\n");
+             irq=10;
+           }
+           if (!(irq_tab[irq].flags & IRQ_FLG_STD)) 
+             {
+               if (irq_tab[irq].flags & IRQ_FLG_LOCK) 
+                 {
+                   printk("%s: IRQ %d from %s is not replaceable\n",
+                          __FUNCTION__, irq, irq_tab[irq].devname);
+                   return -EBUSY;
+                 }
+               if (flags & IRQ_FLG_REPLACE) 
+                 {
+                   printk("%s: %s can't replace IRQ %d from %s\n",
+                          __FUNCTION__, devname, irq, irq_tab[irq].devname);
+                   return -EBUSY;
+                 }
+             }
+           /*printk("IRQ %d set to handler %p\n",irq,handler);*/
+           irq_tab[irq].handler = handler;
+           irq_tab[irq].flags   = flags;
+           irq_tab[irq].dev_id  = dev_id;
+           strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+           return 0;
+         }
+       else {
+         /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
+         sys_request_irq(4,handler,flags,devname,dev_id);
+         sys_request_irq(6,handler,flags,devname,dev_id);
+         return 0;
+       }
+}
+
+void q40_free_irq(unsigned int irq, void *dev_id)
+{
+       if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+               printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
+               return;
+       }
+
+       /* test for ISA ints not implemented by HW */
+       if (irq<15) {
+         switch (irq){
+         case 1: case 2: case 8: case 9:
+         case 12: case 13:
+               printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+               return;
+         default:
+                 }
+       }
+       
+       if (irq<Q40_IRQ_TIMER){
+         if (irq==11) irq=10;
+         if (irq_tab[irq].dev_id != dev_id)
+           printk("%s: Removing probably wrong IRQ %d from %s\n",
+                  __FUNCTION__, irq, irq_tab[irq].devname);
+         
+         irq_tab[irq].handler = q40_defhand;
+         irq_tab[irq].flags   = IRQ_FLG_STD;
+         irq_tab[irq].dev_id  = NULL;
+         /* irq_tab[irq].devname = NULL; */
+       } else { /* == Q40_IRQ_TIMER */
+         sys_free_irq(4,dev_id);
+         sys_free_irq(6,dev_id);
+       }
+}
+
+#if 1
+void q40_process_int (int level, struct pt_regs *fp)
+{
+  printk("unexpected interrupt %x\n",level);
+}
+#endif
+
+/* 
+ * tables to translate bits into IRQ numbers 
+ * it is a good idea to order the entries by priority
+ * 
+*/
+
+struct IRQ_TABLE{ unsigned mask; int irq ;};
+
+static struct IRQ_TABLE iirqs[]={
+  {IRQ_FRAME_MASK,Q40_IRQ_FRAME},
+  {IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {0,0}};
+static struct IRQ_TABLE eirqs[]={
+  {IRQ3_MASK,3},                   /* ser 1 */
+  {IRQ4_MASK,4},                   /* ser 2 */
+  {IRQ14_MASK,14},                 /* IDE 1 */
+  {IRQ15_MASK,15},                 /* IDE 2 */
+  {IRQ6_MASK,6},                   /* floppy */
+  {IRQ7_MASK,7},                   /* par */
+
+  {IRQ5_MASK,5},
+  {IRQ10_MASK,10},
+
+
+
+
+  {0,0}};
+
+/* complaiun only this many times about spurious ints : */
+static int ccleirq=60;    /* ISA dev IRQ's*/
+static int cclirq=60;     /* internal */
+
+/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+
+void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+{
+  /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
+
+        unsigned mir=master_inb(IIRQ_REG);
+       unsigned mer;
+       int irq,i;
+
+       /*
+        *  more than 1 bit might be set, must handle atmost 1 int source,
+        *  - handle only those with explicitly set handler
+        */
+
+       if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK)) 
+         {
+           
+           /* some ISA dev caused the int */
+           
+           mer=master_inb(EIRQ_REG);
+           
+           for (i=0; eirqs[i].mask; i++)
+             {
+               if (mer&(eirqs[i].mask)) 
+                 {
+                   irq=eirqs[i].irq;
+                   irq_tab[irq].count++;
+                   if (irq_tab[irq].handler == q40_defhand )
+                     continue; /* ignore uninited INTs :-( */
+                   
+                   irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+                   return;
+                 }
+             }
+           if (ccleirq>0) 
+             printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
+         } 
+       else 
+         {
+           /* internal */
+
+           for (i=0; iirqs[i].mask; i++)
+             {
+               if (mir&(iirqs[i].mask)) 
+                 {
+                   irq=iirqs[i].irq;
+                   irq_tab[irq].count++;
+                   if (irq_tab[irq].handler == q40_defhand )
+                     continue; /* ignore uninited INTs :-( */
+                   
+                   irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+                   return;
+                 }
+             }
+           if (cclirq>0)
+             printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
+         }
+}
+
+int q40_get_irq_list (char *buf)
+{
+       int i, len = 0;
+
+       for (i = 0; i <= Q40_IRQ_MAX; i++) {
+               if (irq_tab[i].count)
+                       len += sprintf (buf+len, "Vec 0x%02x: %8d  %s%s\n",
+                           i, irq_tab[i].count,
+                           irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
+                           irq_tab[i].handler == q40_defhand ? 
+                                       " (now unassigned)" : "");
+       }
+       return len;
+}
+
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if 0
+       printk ("Unknown q40 interrupt 0x%02x\n", irq);
+#endif
+}
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+{
+#if 0
+        if (ints_inited)
+#endif
+         printk ("Uninitialised interrupt level %d\n", lev);
+#if 0
+       else
+         printk ("Interrupt before interrupt initialisation\n");
+#endif
+}
+
+ void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
+ };
+
+void q40_enable_irq (unsigned int irq)
+{
+}
+
+
+void q40_disable_irq (unsigned int irq)
+{
+}
+
+unsigned long q40_probe_irq_on (void)
+{
+  printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
+  return 0;
+}
+int q40_probe_irq_off (unsigned long irqs)
+{
+  return -1;
+}
diff --git a/arch/m68k/sun3x/Makefile b/arch/m68k/sun3x/Makefile
new file mode 100644 (file)
index 0000000..ba1f2bb
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/sun3x source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sun3x.o
+O_OBJS   := config.o time.o dvma.o sbus.o
+OX_OBJS  := 
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
new file mode 100644 (file)
index 0000000..5054cd8
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Setup kernel for a Sun3x machine
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * based on code from Oliver Jowett <oliver@jowett.manawatu.gen.nz>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG;
+extern int serial_console;
+
+void sun3x_halt(void)
+{
+    /* Disable interrupts */
+    cli();
+
+    /* we can't drop back to PROM, so we loop here */
+    for (;;);
+}
+
+void sun3x_reboot(void)
+{
+    /* This never returns, don't bother saving things */
+    cli();
+
+    /* no idea, whether this works */
+    asm ("reset");
+}
+
+__initfunc(int sun3x_keyb_init(void))
+{
+    return 0;
+}
+
+int sun3x_kbdrate(struct kbd_repeat *r)
+{
+    return 0;
+}
+
+void sun3x_kbd_leds(unsigned int i)
+{
+
+}
+
+static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp)
+{
+    printk ("received spurious interrupt %d\n",irq);
+    num_spurious += 1;
+}
+
+void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint,
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint
+};
+
+void sun3x_enable_irq(unsigned int irq)
+{
+    *sun3x_intreg |= (1 << irq);
+}
+
+void sun3x_disable_irq(unsigned int irq)
+{
+    *sun3x_intreg &= ~(1 << irq);
+}
+
+__initfunc(void sun3x_init_IRQ(void))
+{
+    /* disable all interrupts initially */
+    *sun3x_intreg = 1;  /* master enable only */
+}
+
+int sun3x_get_irq_list(char *buf)
+{
+    return 0;
+}
+
+/*
+ *  Setup the sun3x configuration info
+ */
+__initfunc(void config_sun3x(void))
+{
+    mach_get_irq_list   = sun3x_get_irq_list;
+    mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
+
+    mach_keyb_init       = sun3x_keyb_init;
+    mach_kbdrate         = sun3x_kbdrate;
+    mach_kbd_leds        = sun3x_kbd_leds;
+
+    mach_sched_init      = sun3x_sched_init;
+    mach_init_IRQ        = sun3x_init_IRQ;
+    enable_irq           = sun3x_enable_irq;
+    disable_irq          = sun3x_disable_irq;
+    mach_request_irq     = sys_request_irq;
+    mach_free_irq        = sys_free_irq;
+    mach_default_handler = &sun3x_default_handler;
+    mach_gettimeoffset   = sun3x_gettimeoffset;
+    mach_reset           = sun3x_reboot;
+
+    mach_gettod          = sun3x_gettod;
+    
+    switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+       case 0x10:
+           serial_console = 1;
+           conswitchp = NULL;
+           break;
+       case 0x11:
+           serial_console = 2;
+           conswitchp = NULL;
+           break;
+       default:
+           serial_console = 0;
+           conswitchp = &dummy_con;
+           break;
+    }
+
+}
diff --git a/arch/m68k/sun3x/dvma.c b/arch/m68k/sun3x/dvma.c
new file mode 100644 (file)
index 0000000..9ef3471
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Virtual DMA allocation
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+/* IOMMU support */
+
+#define IOMMU_ENTRIES             2048
+#define IOMMU_ADDR_MASK            0x03ffe000
+#define IOMMU_CACHE_INHIBIT        0x00000040
+#define IOMMU_FULL_BLOCK           0x00000020
+#define IOMMU_MODIFIED             0x00000010
+#define IOMMU_USED                 0x00000008
+#define IOMMU_WRITE_PROTECT        0x00000004
+#define IOMMU_DT_MASK              0x00000003
+#define IOMMU_DT_INVALID           0x00000000
+#define IOMMU_DT_VALID             0x00000001
+#define IOMMU_DT_BAD               0x00000002
+
+#define DVMA_PAGE_SHIFT        13
+#define DVMA_PAGE_SIZE (1UL << DVMA_PAGE_SHIFT)
+#define DVMA_PAGE_MASK (~(DVMA_PAGE_SIZE-1))
+
+
+static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
+static unsigned long iommu_use[IOMMU_ENTRIES];
+static unsigned long iommu_bitmap[IOMMU_ENTRIES/32];
+
+
+#define dvma_entry_paddr(index)        (iommu_pte[index] & IOMMU_ADDR_MASK)
+#define dvma_entry_vaddr(index,paddr)  ((index << DVMA_PAGE_SHIFT) |  \
+                                        (paddr & (DVMA_PAGE_SIZE-1)))
+#define dvma_entry_set(index,addr)     (iommu_pte[index] =            \
+                                           (addr & IOMMU_ADDR_MASK) | \
+                                            IOMMU_DT_VALID)
+#define dvma_entry_clr(index)          (iommu_pte[index] = IOMMU_DT_INVALID)
+#define dvma_entry_use(index)          (iommu_use[index])
+#define dvma_entry_inc(index)          (iommu_use[index]++)
+#define dvma_entry_dec(index)          (iommu_use[index]--)
+#define dvma_entry_hash(addr)          ((addr >> DVMA_PAGE_SHIFT) ^ \
+                                        ((addr & 0x03c00000) >>     \
+                                               (DVMA_PAGE_SHIFT+4)))
+#define dvma_map                       iommu_bitmap
+#define dvma_map_size                  (IOMMU_ENTRIES/2)
+#define dvma_slow_offset               (IOMMU_ENTRIES/2)
+#define dvma_is_slow(addr)             ((addr) &                     \
+                                        (dvma_slow_offset << DVMA_PAGE_SHIFT))
+
+static int fixed_dvma;
+
+void __init dvma_init(void)
+{
+    unsigned long tmp;
+
+    if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) {
+       printk ("Sun3x fixed DVMA mapping\n");
+       fixed_dvma = 1;
+       for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE)
+       dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp));
+       fixed_dvma = 1;
+    } else {
+       printk ("Sun3x variable DVMA mapping\n");
+       for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++)
+           dvma_entry_clr (tmp);
+       fixed_dvma = 0;
+    }
+}
+
+unsigned long dvma_slow_alloc (unsigned long paddr, int npages)
+{
+    int scan, base;
+    
+    scan = 0;
+    for (;;) {
+       scan = find_next_zero_bit(dvma_map, dvma_map_size, scan);
+       if ((base = scan) + npages > dvma_map_size) {
+           printk ("dvma_slow_alloc failed for %d pages\n",npages);
+           return 0;
+       }
+       for  (;;) {
+           if (scan >= base + npages) goto found;
+           if (test_bit(scan, dvma_map)) break;
+           scan++;
+       }
+    }
+
+found:
+    for (scan = base; scan < base+npages; scan++) {
+       dvma_entry_set(scan+dvma_slow_offset, paddr);
+       paddr += DVMA_PAGE_SIZE;
+       set_bit(scan, dvma_map);
+    }
+    return (dvma_entry_vaddr((base+dvma_slow_offset),paddr));
+}
+
+unsigned long dvma_alloc (unsigned long paddr, unsigned long size)
+{
+    int index;
+    int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+               DVMA_PAGE_SHIFT;
+
+    if (fixed_dvma)
+       return ((unsigned long)phys_to_virt (paddr));
+
+    if (pages > 1) /* multi page, allocate from slow pool */
+       return dvma_slow_alloc (paddr, pages);
+    
+    index = dvma_entry_hash (paddr);
+
+    if (dvma_entry_use(index)) {
+       if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) {
+           dvma_entry_inc(index);
+           return dvma_entry_vaddr(index,paddr);
+       }
+       /* collision, allocate from slow pool */
+       return dvma_slow_alloc (paddr, pages);
+    }
+    
+    dvma_entry_set(index,paddr); 
+    dvma_entry_inc(index);
+    return dvma_entry_vaddr(index,paddr);
+}
+
+void dvma_free (unsigned long dvma_addr, unsigned long size)
+{
+    int npages;
+    int index;
+    
+    if (fixed_dvma)
+       return;
+
+    if (!dvma_is_slow(dvma_addr)) {
+       index = (dvma_addr >> DVMA_PAGE_SHIFT);
+       if (dvma_entry_use(index) == 0) {
+           printk ("dvma_free: %lx entry already free\n",dvma_addr);
+           return;
+       }
+        dvma_entry_dec(index);
+       if (dvma_entry_use(index) == 0)
+           dvma_entry_clr(index);
+       return;
+    }
+
+    /* free in slow pool */
+    npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+           DVMA_PAGE_SHIFT;
+    for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) {
+       dvma_entry_clr(index);
+       clear_bit (index,dvma_map);
+    }
+}
diff --git a/arch/m68k/sun3x/sbus.c b/arch/m68k/sun3x/sbus.c
new file mode 100644 (file)
index 0000000..f1a89df
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SBus helper functions
+ *
+ * Sun3x don't have a sbus, but many of the used devices are also
+ * used on Sparc machines with sbus. To avoid having a lot of
+ * duplicate code, we provide necessary glue stuff to make using
+ * of the sbus driver code possible.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+__initfunc(void sbus_init(void))
+{
+
+}
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+                      u32 bus_type, int rdonly)
+{
+       return (void *)address;
+}
+
+int prom_getintdefault(int node, char *property, int deflt)
+{
+       return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+       return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+
+}
+
+void prom_halt (void)
+{
+
+}
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
new file mode 100644 (file)
index 0000000..39fa5f6
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  linux/arch/m68k/sun3x/time.c
+ *
+ *  Sun3x-specific time handling
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+#define M_CONTROL 0xf8
+#define M_SEC     0xf9
+#define M_MIN     0xfa
+#define M_HOUR    0xfb
+#define M_DAY     0xfc
+#define M_DATE    0xfd
+#define M_MONTH   0xfe
+#define M_YEAR    0xff
+
+#define C_WRITE   0x80
+#define C_READ    0x40
+#define C_SIGN    0x20
+#define C_CALIB   0x1f
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+
+/* Read the Mostek */
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp)
+{
+    volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM;
+
+    /* Stop updates */
+    *(eeprom + M_CONTROL) |= C_READ;
+
+    /* Read values */
+    *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
+    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH));
+    *dayp  = BCD_TO_BIN(*(eeprom + M_DATE));
+    *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
+    *minp  = BCD_TO_BIN(*(eeprom + M_MIN));
+    *secp  = BCD_TO_BIN(*(eeprom + M_SEC));
+
+    /* Restart updates */
+    *(eeprom + M_CONTROL) &= ~C_READ;
+}
+
+/* Not much we can do here */
+unsigned long sun3x_gettimeoffset (void)
+{
+    return 0L;
+}
+
+static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+    void (*vector)(int, void *, struct pt_regs *) = dev_id;
+
+    /* Clear the pending interrupt - pulse the enable line low */
+    disable_irq(5);
+    enable_irq(5);
+    
+    vector(irq, NULL, regs);
+}
+
+__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+    sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector);
+
+    /* Pulse enable low to get the clock started */
+    disable_irq(5);
+    enable_irq(5);
+}
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
new file mode 100644 (file)
index 0000000..873742d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef SUN3X_TIME_H
+#define SUN3X_TIME_H
+
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp);
+unsigned long sun3x_gettimeoffset (void);
+void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
+
+#endif
index e1d6f693aaf9021a69bf74305f9872ef353715f3..15d347df5720f5e0c4a8c4b8d50c47c8b3c2048a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.63 1999/04/05 21:48:20 cort Exp $
+ * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -362,8 +362,9 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
                         */
                        if (board_type == 0xe0) {       
                                base_mod = inb(0x803);
-                               /* if a MVME2300 or a MCME2400 then no keyboard */
-                               if((base_mod == 0x9) || (base_mod == 0xF9)) {
+                               /* if a MVME2300/2400 or a Sitka then no keyboard */
+                               if((base_mod == 0x9) || (base_mod == 0xF9) ||
+                                  (base_mod == 0xE1)) {
                                        keyb_present = 0;       /* no keyboard */
                                }
                        }
@@ -471,6 +472,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
        {
                puts("initrd at:     "); puthex(initrd_start);
                puts(" "); puthex(initrd_end); puts("\n");
+#ifdef OMIT
                avail_ram = (char *)PAGE_ALIGN(
                        (unsigned long)zimage_size+(unsigned long)zimage_start);
                memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
@@ -478,6 +480,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
                initrd_end = initrd_start + INITRD_SIZE;
                puts("relocated to:  "); puthex(initrd_start);
                puts(" "); puthex(initrd_end); puts("\n");
+#endif
        }
 
        avail_ram = (char *)0x00400000;
index c69c0a6a3dcb73a0c6681cbc6efb990d32b8088d..131244790395120820a96d308da46d440554e9a4 100644 (file)
@@ -14,7 +14,7 @@ CONFIG_6xx=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-CONFIG_SMP=y
+# CONFIG_SMP is not set
 
 #
 # General setup
@@ -42,6 +42,7 @@ CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADBMOUSE=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
@@ -336,7 +337,7 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
@@ -474,6 +475,6 @@ CONFIG_DMASOUND=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
index 688d4cc83693a9d391ac1d68e485f09c82844564..43493a540ad6b22711a21acaf337bfdb2f3a3331 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.91 1999/04/09 07:07:47 cort Exp $
+# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -89,9 +89,9 @@ bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
 bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
 bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
 if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'PReP bootloader ernel arguments' CONFIG_CMDLINE_BOOL n
+  bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y
   if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
-    string 'Initial kernel command string' CONFIG_CMDLINE ""
+    string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2
   fi
 fi
 
index 274f6c679acd02f564ba8b4b5307a21e41b184ff..131244790395120820a96d308da46d440554e9a4 100644 (file)
@@ -8,13 +8,12 @@
 CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-CONFIG_MACH_SPECIFIC=y
 # CONFIG_SMP is not set
 
 #
@@ -36,20 +35,20 @@ CONFIG_KERNEL_ELF=y
 CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -76,15 +75,13 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -119,7 +116,6 @@ CONFIG_IP_ALIAS=y
 # (it is safe to leave these untouched)
 #
 CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 
@@ -155,12 +151,12 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -188,16 +184,28 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -228,7 +236,7 @@ CONFIG_BMAC=y
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -275,7 +283,7 @@ CONFIG_PPP=y
 # CONFIG_ISDN is not set
 
 #
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
 #
 # CONFIG_CD_NO_IDESCSI is not set
 
@@ -283,22 +291,37 @@ CONFIG_PPP=y
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -314,15 +337,25 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 
 #
@@ -334,11 +367,20 @@ CONFIG_NVRAM=y
 # Joystick support
 #
 # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
 
 #
 # Filesystems
@@ -429,3 +471,10 @@ CONFIG_DMASOUND=y
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
index 7e93e03fe0e5275597f6380031c64839094b8d46..fa4dda10b5a51153c80d278c505148678d2ee9cf 100644 (file)
@@ -96,11 +96,12 @@ int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
 #define PYTHON_CFA(b, d, o)    (0x80 | ((b<<6) << 8) | ((d) << 16) \
                                 | (((o) & ~3) << 24))
-     
+unsigned int python_busnr = 1;
+
 int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned char *val)
 {
-       if (bus > 2) {
+       if (bus > python_busnr) {
                *val = 0xff;
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
@@ -112,7 +113,7 @@ int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned short *val)
 {
-       if (bus > 2) {
+       if (bus > python_busnr) {
                *val = 0xffff;
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
@@ -125,7 +126,7 @@ int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned int *val)
 {
-       if (bus > 2) {
+       if (bus > python_busnr) {
                *val = 0xffffffff;
                return PCIBIOS_DEVICE_NOT_FOUND;
        }
@@ -137,7 +138,7 @@ int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned char val)
 {
-       if (bus > 2)
+       if (bus > python_busnr)
                return PCIBIOS_DEVICE_NOT_FOUND;
        out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
        out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
@@ -147,7 +148,7 @@ int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned short val)
 {
-       if (bus > 2)
+       if (bus > python_busnr)
                return PCIBIOS_DEVICE_NOT_FOUND;
        out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
        out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
@@ -158,7 +159,7 @@ int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
                                      unsigned char offset, unsigned int val)
 {
-       if (bus > 2)
+       if (bus > python_busnr)
                return PCIBIOS_DEVICE_NOT_FOUND;
        out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
        out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
@@ -217,9 +218,9 @@ chrp_pcibios_fixup(void)
 {
        struct pci_dev *dev;
        
-       /* get the other 2 busses on the F50 */
-       if ( !strncmp("F5", get_property(find_path_device("/"),
-                                        "ibm,model-class", NULL),2) )
+       /* some of IBM chrps have > 1 bus */
+       if ( !strncmp("IBM", get_property(find_path_device("/"),
+                                        "name", NULL),3) )
        {
                pci_scan_peer_bridge(1);
                pci_scan_peer_bridge(2);
@@ -258,6 +259,8 @@ decl_config_access_method(indirect);
 void __init
 chrp_setup_pci_ptrs(void)
 {
+       struct device_node *py;
+       
         if ( !strncmp("MOT",
                       get_property(find_path_device("/"), "model", NULL),3) )
         {
@@ -268,16 +271,28 @@ chrp_setup_pci_ptrs(void)
         }
         else
         {
-               if ( find_compatible_devices( "pci", "IBM,python" ) )
+               if ( (py = find_compatible_devices( "pci", "IBM,python" )) )
                {
+                       /* find out how many pythons */
+                       while ( (py = py->next) ) python_busnr++;
+                        set_config_access_method(python);
                        /*
-                        * We assume these values but should someday get them
-                        * from the device tree or python itself instead -- Cort
+                        * We base these values on the machine type but should
+                        * try to read them from the python controller itself.
+                        * -- Cort
                         */
-                       pci_dram_offset = 0x80000000;
-                       isa_mem_base = 0xa0000000;
-                       isa_io_base = 0x88000000;
-                        set_config_access_method(python);
+                       if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) )
+                       {
+                               pci_dram_offset = 0x80000000;
+                               isa_mem_base = 0xa0000000;
+                               isa_io_base = 0x88000000;
+                       } else if ( !strncmp("IBM,7043-260",
+                          get_property(find_path_device("/"), "name", NULL),12) )
+                       {
+                               pci_dram_offset = 0x80000000;
+                               isa_mem_base = 0xc0000000;
+                               isa_io_base = 0xf8000000;
+                       }
                 }
                 else
                 {
index 9296dc6ee5c2ed05578517bdc2e0097c1a120f5f..2c652f0498c18437f91d3c1c0d32883183a921cc 100644 (file)
@@ -400,7 +400,10 @@ chrp_do_IRQ(struct pt_regs *regs,
                  *
                  * This should go in the above mask/ack code soon. -- Cort
                  */
-                irq = *chrp_int_ack_special;
+               if ( chrp_int_ack_special )
+                       irq = *chrp_int_ack_special;
+               else
+                       irq = i8259_irq(0);
                 /*
                  * Acknowledge as soon as possible to allow i8259
                  * interrupt nesting                         */
index b13ee5b3e8ba915cb76e2852fb49869affc702fd..b9ecc2dccd9d820ae4ca90b537c11a75b6844525 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.127 1999/04/07 07:26:55 paulus Exp $
+ *  $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -2045,8 +2045,9 @@ _GLOBAL(_switch)
        stw     r0,GPR0(r1)
        lwz     r0,0(r1)
        stw     r0,GPR1(r1)
-       SAVE_10GPRS(2, r1)
-       SAVE_10GPRS(12, r1)
+       /* r3-r13 are caller saved -- Cort */
+       SAVE_GPR(2, r1)
+       SAVE_8GPRS(14, r1)
        SAVE_10GPRS(22, r1)
        mflr    r20             /* Return to switch caller */
        mfmsr   r22
@@ -2069,6 +2070,8 @@ _GLOBAL(_switch)
        mtspr   SPRG3,r0        /* Update current TSS phys addr */
        SYNC
        lwz     r1,KSP(r4)      /* Load new stack pointer */
+       /* save the old current 'last' for return value */
+       mr      r3,r2
        addi    r2,r4,-TSS      /* Update current */
 #ifndef CONFIG_8xx
        /* Set up segment registers for new task */
@@ -2076,39 +2079,62 @@ _GLOBAL(_switch)
        addis   r5,r5,0x6000    /* Set Ks, Ku bits */
        li      r0,12           /* TASK_SIZE / SEGMENT_SIZE */
        mtctr   r0
-       li      r3,0
-3:     mtsrin  r5,r3
+       li      r9,0
+3:     mtsrin  r5,r9
        addi    r5,r5,1         /* next VSID */
-       addis   r3,r3,0x1000    /* address of next segment */
+       addis   r9,r9,0x1000    /* address of next segment */
        bdnz    3b
 #else
 /* On the MPC8xx, we place the physical address of the new task
  * page directory loaded into the MMU base register, and set the
  * ASID compare register with the new "context".
  */
-        lwz     r3,MM-TSS(r4)           /* Get virtual address of mm */
-        lwz     r3,PGD(r3)              /* get new->mm->pgd */
-        addis   r3,r3,-KERNELBASE@h     /* convert to phys addr */
-        mtspr   M_TWB, r3               /* Update MMU base address */
+        lwz     r9,MM-TSS(r4)           /* Get virtual address of mm */
+        lwz     r9,PGD(r9)              /* get new->mm->pgd */
+        addis   r9,r9,-KERNELBASE@h     /* convert to phys addr */
+        mtspr   M_TWB, r9               /* Update MMU base address */
         mtspr   M_CASID, r5             /* Update context */
         tlbia
 #endif
        SYNC
-
-/* FALL THROUGH into int_return */
-#ifdef __SMP__
-       /* call schedule_tail if this is the first time for a child process */
-       lwz     r5,TSS_SMP_FORK_RET(r4)
-       cmpi    0,r5,0
-       beq+    int_return
-       li      r3,0
-       stw     r3,TSS_SMP_FORK_RET(r4)
-       bl      schedule_tail
-#endif /* __SMP__ */
+2:     lwz     r9,_MSR(r1)     /* Returning to user mode? */
+       andi.   r9,r9,MSR_PR
+       beq+    10f             /* if not, don't adjust kernel stack */
+8:     addi    r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD    /* size of frame */
+       stw     r4,TSS+KSP(r2)  /* save kernel stack pointer */
+       tophys(r9,r1,r9)
+       mtspr   SPRG2,r9        /* phys exception stack pointer */
+10:    lwz     r2,_CTR(r1)
+       lwz     r0,_LINK(r1)
+       mtctr   r2
+       mtlr    r0
+       lwz     r2,_XER(r1)
+       lwz     r0,_CCR(r1)
+       mtspr   XER,r2
+       mtcrf   0xFF,r0
+       /* r3-r13 are destroyed -- Cort */
+       REST_GPR(14, r1)
+       REST_8GPRS(15, r1)
+       REST_8GPRS(23, r1)
+       REST_GPR(31, r1)
+       lwz     r2,_NIP(r1)     /* Restore environment */
+       lwz     r0,_MSR(r1)
+       mtspr   SRR0,r2
+       mtspr   SRR1,r0
+       lwz     r0,GPR0(r1)
+       lwz     r2,GPR2(r1)
+       lwz     r1,GPR1(r1)
+       SYNC
+       rfi
 
 /*
  * Trap exit.
  */
+#ifdef __SMP__ 
+       .globl  ret_from_smpfork
+ret_from_smpfork:
+       bl      schedule_tail
+#endif 
        .globl  ret_from_syscall
 ret_from_syscall:      
        .globl  int_return
index 11d17ad9d4bbdd39221203093851e2283fee691b..4ec6d3e118f8e688121ee6c62d89d63e0acc4431 100644 (file)
@@ -10,6 +10,40 @@ unsigned char cached_8259[2] = { 0xff, 0xff };
 #define cached_A1 (cached_8259[0])
 #define cached_21 (cached_8259[1])
 
+int i8259_irq(int cpu)
+{
+       int irq;
+       
+        /*
+         * Perform an interrupt acknowledge cycle on controller 1
+         */                                                             
+        outb(0x0C, 0x20);
+        irq = inb(0x20) & 7;                                   
+        if (irq == 2)                                                     
+        {                                                                   
+                /*                                     
+                 * Interrupt is cascaded so perform interrupt
+                 * acknowledge on controller 2
+                 */
+                outb(0x0C, 0xA0);                      
+                irq = (inb(0xA0) & 7) + 8;
+        }
+        else if (irq==7)                                
+        {
+                /*                               
+                 * This may be a spurious interrupt
+                 *                         
+                 * Read the interrupt status register. If the most
+                 * significant bit is not set then there is no valid
+                * interrupt
+                */
+               outb(0x0b, 0x20);
+               if(~inb(0x20)&0x80)
+                       return -1;
+       }
+       return irq;
+}
+
 static void i8259_mask_and_ack_irq(unsigned int irq_nr)
 {
         if ( irq_nr >= i8259_pic.irq_offset )
index 1d2888d14f11b9a4adb4a84690a088936f41835e..a1d6df0a148e94d7d6623aa882c3312563f77c4f 100644 (file)
@@ -7,5 +7,6 @@
 extern struct hw_interrupt_type i8259_pic;
 
 void i8259_init(void);
+int i8259_irq(int);
 
 #endif /* _PPC_KERNEL_i8259_H */
index f51eac55264b5c1b85f3eb4a43563d9cabdea23b..641d77a5253d71257c08934d26d91dd85f1efde6 100644 (file)
@@ -103,7 +103,7 @@ int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-                            unsigned char offset, unsigned short val)
+                            unsigned char offset, unsigned int val)
 {
        unsigned flags;
 
index 08ff38e21e751407c1d6e7ebe334cca52c20193f..b66ccffa8b5d0939ec70a457885e32d531538a76 100644 (file)
@@ -48,7 +48,6 @@ main(void)
        DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
        DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
        DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
-       DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
        /* Interrupt register frame */
        DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
        DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
index 68bb7e302ee06dcc3d50ed8af002046c556ec805..2ca879dd83e727482965e427e09fdbb688fd02b0 100644 (file)
@@ -14,13 +14,13 @@ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
 }
 #endif /* __SMP__ */
 
-void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
+void chrp_mask_and_ack_irq(unsigned int irq_nr)
 {
        if (is_8259_irq(irq_nr))
            i8259_pic.mask_and_ack(irq_nr);
 }
 
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
+static void chrp_mask_irq(unsigned int irq_nr)
 {
        if (is_8259_irq(irq_nr))
                i8259_pic.disable(irq_nr);
@@ -28,7 +28,7 @@ static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
                openpic_disable_irq(irq_to_openpic(irq_nr));
 }
 
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
+static void chrp_unmask_irq(unsigned int irq_nr)
 {
        if (is_8259_irq(irq_nr))
                i8259_pic.enable(irq_nr);
index 6b9d8ca5388153e7fa881827e8277ad5dffc19d8..6a49f14052ea03fba70270739361e1f9526a4b1a 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/config.h>
+
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
index b25c63b671b9928afca139a4af55560d647607f4..9f8638021576dfc46c5fffbf2aedba9753f82581 100644 (file)
@@ -75,7 +75,9 @@ extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
 extern char mackbd_unexpected_up(unsigned char keycode);
 extern void mackbd_leds(unsigned char leds);
 extern void mackbd_init_hw(void);
-extern unsigned char mackbd_sysrq_xlate[128];
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -575,7 +577,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.get_rtc_time   = pmac_get_rtc_time;
        ppc_md.calibrate_decr = pmac_calibrate_decr;
 
-#ifdef CONFIG_VT
+#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
        ppc_md.kbd_setkeycode    = mackbd_setkeycode;
        ppc_md.kbd_getkeycode    = mackbd_getkeycode;
        ppc_md.kbd_translate     = mackbd_translate;
@@ -584,7 +586,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
        ppc_md.kbd_sysrq_xlate   = mackbd_sysrq_xlate;
-#endif 
+#endif
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE_PMAC)
index b997f892d015819d4f25908607398a96dd2fa340..dd7f1eee1cf3e75549356bac7521cc62e6e07503 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.31 1999/04/21 18:21:37 cort Exp $
+ * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -35,6 +35,9 @@ unsigned char *Motherboard_map_name;
 /* How is the 82378 PIRQ mapping setup? */
 unsigned char *Motherboard_routes;
 
+/* Used for Motorola to store system config register */
+static unsigned long   *ProcInfo;
+
 /* Tables for known hardware */   
 
 /* Motorola PowerStackII - Utah */
@@ -42,38 +45,39 @@ static char Utah_pci_IRQ_map[23] __prepdata =
 {
         0,   /* Slot 0  - unused */
         0,   /* Slot 1  - unused */
-        4,   /* Slot 2  - SCSI - NCR825A  */
+        5,   /* Slot 2  - SCSI - NCR825A  */
         0,   /* Slot 3  - unused */
         1,   /* Slot 4  - Ethernet - DEC2114x */
         0,   /* Slot 5  - unused */
-        2,   /* Slot 6  - PCI Card slot #1 */
-        3,   /* Slot 7  - PCI Card slot #2 */
-        4,   /* Slot 8  - PCI Card slot #3 */
-        4,   /* Slot 9  - PCI Bridge */
+        3,   /* Slot 6  - PCI Card slot #1 */
+        4,   /* Slot 7  - PCI Card slot #2 */
+        5,   /* Slot 8  - PCI Card slot #3 */
+        5,   /* Slot 9  - PCI Bridge */
              /* added here in case we ever support PCI bridges */
              /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
         0,   /* Slot 10 - unused */
         0,   /* Slot 11 - unused */
-        4,   /* Slot 12 - SCSI - NCR825A */
+        5,   /* Slot 12 - SCSI - NCR825A */
         0,   /* Slot 13 - unused */
-        2,   /* Slot 14 - enet */
+        3,   /* Slot 14 - enet */
         0,   /* Slot 15 - unused */
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
+        2,   /* Slot 16 - unused */
+        3,   /* Slot 17 - unused */
+        5,   /* Slot 18 - unused */
+        0,   /* Slot 19 - unused */
+        0,   /* Slot 20 - unused */
+        0,   /* Slot 21 - unused */
+        0,   /* Slot 22 - unused */
 };
 
 static char Utah_pci_IRQ_routes[] __prepdata =
 {
         0,   /* Line 0 - Unused */
         9,   /* Line 1 */
-        11,  /* Line 2 */
-        14,  /* Line 3 */
-        15,  /* Line 4 */
+       10,  /* Line 2 */
+        11,  /* Line 3 */
+        14,  /* Line 4 */
+        15,  /* Line 5 */
 };
 
 /* Motorola PowerStackII - Omaha */
@@ -133,9 +137,9 @@ static char Blackhawk_pci_IRQ_map[19] __prepdata =
        0,      /* Slot 13 - unused */
        1,      /* Slot 14 - Ethernet */
        0,      /* Slot 15 - unused */
-       1,      /* Slot P7 */
-       2,      /* Slot P6 */
-       3,      /* Slot P5 */
+       1,      /* Slot P7 */
+       2,      /* Slot P6 */
+       3,      /* Slot P5 */
 };
 
 static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -147,6 +151,122 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata =
        15      /* Line 4 */
 };
    
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+       0,      /* Slot 0  - unused */
+       0,      /* Slot 1  - unused */
+       0,      /* Slot 2  - unused */
+       0,      /* Slot 3  - unused */
+       0,      /* Slot 4  - unused */
+       0,      /* Slot 5  - unused */
+       0,      /* Slot 6  - unused */
+       0,      /* Slot 7  - unused */
+       0,      /* Slot 8  - unused */
+       0,      /* Slot 9  - unused */
+       0,      /* Slot 10 - unxued */
+       0,      /* Slot 11 - unused */
+       0,      /* Slot 12 - unused */
+       0,      /* Slot 13 - unused */
+       2,      /* Slot 14 - Ethernet */
+       0,      /* Slot 15 - unused */
+       3,      /* Slot 16 - PMC */
+       0,      /* Slot 17 - unused */
+       0,      /* Slot 18 - unused */
+       0,      /* Slot 19 - unused */
+       0,      /* Slot 20 - unused */
+       0,      /* Slot 21 - unused */
+       0,      /* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+       0,      /* Slot 0  - unused */
+       0,      /* Slot 1  - unused */
+       0,      /* Slot 2  - unused */
+       0,      /* Slot 3  - unused */
+       0,      /* Slot 4  - unused */
+       0,      /* Slot 5  - unused */
+       0,      /* Slot 6  - unused */
+       0,      /* Slot 7  - unused */
+       0,      /* Slot 8  - unused */
+       0,      /* Slot 9  - unused */
+       0,      /* Slot 10 - unxued */
+       0,      /* Slot 11 - unused */
+       0,      /* Slot 12 - unused */
+       0,      /* Slot 13 - unused */
+       2,      /* Slot 14 - Ethernet */
+       0,      /* Slot 15 - unused */
+       9,      /* Slot 16 - PMC 1  */
+       12,     /* Slot 17 - PMC 2  */
+       0,      /* Slot 18 - unused */
+       0,      /* Slot 19 - unused */
+       4,      /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+       0,      /* Slot 0  - unused */
+       0,      /* Slot 1  - unused */
+       0,      /* Slot 2  - unused */
+       0,      /* Slot 3  - unused */
+       0,      /* Slot 4  - unused */
+       0,      /* Slot 5  - unused */
+       0,      /* Slot 6  - unused */
+       0,      /* Slot 7  - unused */
+       0,      /* Slot 8  - unused */
+       0,      /* Slot 9  - unused */
+       0,      /* Slot 10 - unused */
+       0,      /* Slot 11 - unused */
+       3,      /* Slot 12 - SCSI */
+       0,      /* Slot 13 - unused */
+       2,      /* Slot 14 - Ethernet */
+       0,      /* Slot 15 - unused */
+       9,      /* Slot 16 - PCI/PMC slot 1 */
+       10,     /* Slot 17 - PCI/PMC slot 2 */
+       11,     /* Slot 18 - PCI slot 3 */
+       0,      /* Slot 19 - unused */
+       0,      /* Slot 20 - unused */
+       0,      /* Slot 21 - unused */
+       0,      /* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+        0,      /* Slot 0  - unused */
+        0,      /* Slot 1  - unused */
+        0,      /* Slot 2  - unused */
+        0,      /* Slot 3  - unused */
+        0,      /* Slot 4  - unused */
+        0,      /* Slot 5  - unused */
+        0,      /* Slot 6  - unused */
+        0,      /* Slot 7  - unused */
+        0,      /* Slot 8  - unused */
+        0,      /* Slot 9  - unused */
+        0,      /* Slot 10 - unused */
+        0,      /* Slot 11 - unused */
+        3,      /* Slot 12 - SCSI */
+        0,      /* Slot 13 - unused */
+        2,      /* Slot 14 - Ethernet 1 */
+        0,      /* Slot 15 - unused */
+        9,      /* Slot 16 - PCI slot 1P */
+        10,     /* Slot 17 - PCI slot 2P */
+        11,     /* Slot 18 - PCI slot 3P */
+        10,     /* Slot 19 - Ethernet 2 */
+        0,      /* Slot 20 - P2P Bridge */
+        0,      /* Slot 21 - unused */
+        0,      /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+       0,      /* This is a dummy structure */
+};
+   
 /* Motorola MVME16xx */
 static char Genesis_pci_IRQ_map[16] __prepdata =
 {
@@ -177,48 +297,35 @@ static char Genesis_pci_IRQ_routes[] __prepdata =
        15      /* Line 4 */
 };
    
-/* Motorola Genesis2 MVME26XX, MVME 36XX */
-/* The final version for these boards should use the Raven PPC/PCI bridge 
-interrupt controller which is much sophisticated and allows more
-devices on the PCI bus. */
 static char Genesis2_pci_IRQ_map[23] __prepdata =
-  {
-        0,     /* Slot 0  - ECC memory controller/PCI bridge */
+{
+       0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
-       0,      /* Slot 2  - unused */
-       0,      /* Slot 3  - unused */
-       0,      /* Slot 4  - unused */
-       0,      /* Slot 5  - unused */
-       0,      /* Slot 6  - unused */
-       0,      /* Slot 7  - unused */
-       0,      /* Slot 8  - unused */
-       0,      /* Slot 9  - unused */
-       0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - ISA bridge */
-       3,      /* Slot 12 - SCSI */
-       2,      /* Slot 13 - Universe PCI/VME bridge (and 22..24) */
-       1,      /* Slot 14 - Ethernet */
-       0,      /* Slot 15 - Unused (graphics on 3600, would be 20 ?) */
-       4,      /* Slot 16 - PMC slot, assume uses INTA */
-       0,      /* Slot 17 */
-       0,      /* Slot 18 */
-       0,      /* Slot 19 */
-       0,      /* Slot 20 */
-       0,      /* Slot 21 */
-       0,      /* Slot 22 */
-  };
-
-static char Genesis2_pci_IRQ_routes[] __prepdata=
-   {
-       0,      /* Line 0 - Unused */
-       10,     /* Line 1 - INTA */
-       11,     /* Line 2 - INTB */
-       14,     /* Line 3 - INTC */
-       15      /* Line 4 - INTD */
-   };
-   
+       0,      /* Slot 2  - unused */
+       0,      /* Slot 3  - unused */
+       0,      /* Slot 4  - unused */
+       0,      /* Slot 5  - unused */
+       0,      /* Slot 6  - unused */
+       0,      /* Slot 7  - unused */
+       0,      /* Slot 8  - unused */
+       0,      /* Slot 9  - unused */
+       0,      /* Slot 10 - Ethernet */
+       0,      /* Slot 11 - Universe PCI - VME Bridge */
+       3,      /* Slot 12 - unused */
+       0,      /* Slot 13 - unused */
+       2,      /* Slot 14 - SCSI */
+       0,      /* Slot 15 - graphics on 3600 */
+       9,      /* Slot 16 - PMC */
+       12,     /* Slot 17 - pci */
+       11,     /* Slot 18 - pci */
+       10,     /* Slot 19 - pci */
+       0,      /* Slot 20 - pci */
+       0,      /* Slot 21 - unused */
+       0,      /* Slot 22 - unused */
+};
+
 /* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] __prepdata =
+static char Comet_pci_IRQ_map[23] __prepdata =
 {
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
@@ -236,6 +343,13 @@ static char Comet_pci_IRQ_map[16] __prepdata =
        0,      /* Slot 13 - unused */
        1,      /* Slot 14 - Ethernet */
        0,      /* Slot 15 - unused */
+       1,      /* Slot 16 - PCI slot 1 */
+       2,      /* Slot 17 - PCI slot 2 */
+       3,      /* Slot 18 - PCI slot 3 */
+       4,      /* Slot 19 - PCI bridge */
+       0,
+       0,
+       0,
 };
 
 static char Comet_pci_IRQ_routes[] __prepdata =
@@ -247,6 +361,43 @@ static char Comet_pci_IRQ_routes[] __prepdata =
        15      /* Line 4 */
 };
 
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+       0,      /* Slot 0  - unused */
+       0,      /* Slot 1  - unused */
+       3,      /* Slot 2  - SCSI - NCR825A */
+       0,      /* Slot 3  - unused */
+       1,      /* Slot 4  - Ethernet - DEC2104X */
+       0,      /* Slot 5  - unused */
+       1,      /* Slot 6  - PCI slot 1 */
+       2,      /* Slot 7  - PCI slot 2 */
+       3,      /* Slot 8  - PCI slot 3 */
+       4,      /* Slot 9  - PCI bridge  */
+       0,      /* Slot 10 - unused */
+       0,      /* Slot 11 - unused */
+       3,      /* Slot 12 - SCSI - NCR825A */
+       0,      /* Slot 13 - unused */
+       1,      /* Slot 14 - Ethernet - DEC2104X */
+       0,      /* Slot 15 - unused */
+       1,      /* Slot 16 - PCI slot 1 */
+       2,      /* Slot 17 - PCI slot 2 */
+       3,      /* Slot 18 - PCI slot 3 */
+       4,      /* Slot 19 - PCI bridge */
+       0,
+       0,
+       0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+       0,      /* Line 0 - Unused */
+       10,     /* Line 1 */
+       11,     /* Line 2 */
+       14,     /* Line 3 */
+       15,     /* Line 4 */
+};
+
 /*
  * ibm 830 (and 850?).
  * This is actually based on the Carolina motherboard
@@ -502,6 +653,137 @@ prep_pcibios_write_config_byte (unsigned char bus,
        return PCIBIOS_SUCCESSFUL;
 }
 
+#define MOTOROLA_CPUTYPE_REG   0x800
+#define MOTOROLA_BASETYPE_REG  0x803
+#define MPIC_RAVEN_ID          0x48010000
+#define        MPIC_HAWK_ID            0x48030000
+#define        MOT_PROC2_BIT           0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+    1, /* MVME2600_INT_SIO */
+    0, /* MVME2600_INT_FALCN_ECC_ERR */
+    1, /* MVME2600_INT_PCI_ETHERNET */
+    1, /* MVME2600_INT_PCI_SCSI */
+    1, /* MVME2600_INT_PCI_GRAPHICS */
+    1, /* MVME2600_INT_PCI_VME0 */
+    1, /* MVME2600_INT_PCI_VME1 */
+    1, /* MVME2600_INT_PCI_VME2 */
+    1, /* MVME2600_INT_PCI_VME3 */
+    1, /* MVME2600_INT_PCI_INTA */
+    1, /* MVME2600_INT_PCI_INTB */
+    1, /* MVME2600_INT_PCI_INTC */
+    1, /* MVME2600_INT_PCI_INTD */
+    1, /* MVME2600_INT_LM_SIG0 */
+    1, /* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT      0x1
+#define MOT_HAWK_PRESENT       0x2
+
+int prep_keybd_present = 1;
+int MotMPIC = 0;
+
+__initfunc(int raven_init(void))
+{
+       unsigned int    devid;
+       unsigned int    pci_membase;
+       unsigned char   base_mod;
+
+       /* Check to see if the Raven chip exists. */
+       if ( _prep_type != _PREP_Motorola) {
+               OpenPIC = NULL;
+               return 0;
+       }
+
+       /* Check to see if this board is a type that might have a Raven. */
+       if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+               OpenPIC = NULL;
+               return 0;
+       }
+
+       /* Check the first PCI device to see if it is a Raven. */
+       pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &devid);
+
+       switch (devid & 0xffff0000) {
+       case MPIC_RAVEN_ID:
+               MotMPIC = MOT_RAVEN_PRESENT;
+               break;
+       case MPIC_HAWK_ID:
+               MotMPIC = MOT_HAWK_PRESENT;
+               break;
+       default:
+               OpenPIC = NULL;
+               return 0;
+       }
+
+
+       /* Read the memory base register. */
+       pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+       if (pci_membase == 0) {
+               OpenPIC = NULL;
+               return 0;
+       }
+
+       /* Map the Raven MPIC registers to virtual memory. */
+       OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);
+
+       OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+       OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+       /* If raven is present on Motorola store the system config register
+        * for later use.
+        */
+       ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+       /* This is a hack.  If this is a 2300 or 2400 mot board then there is
+        * no keyboard controller and we have to indicate that.
+        */
+       base_mod = inb(MOTOROLA_BASETYPE_REG);
+       if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+           (base_mod == 0xFA) || (base_mod == 0xE1))
+               prep_keybd_present = 0;
+
+       return 1;
+}
+
+struct mot_info {
+       int             cpu_type;       /* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+                                       /* 0x200 if this board has a Hawk chip. */
+       int             base_type;
+       int             max_cpu;        /* ored with 0x80 if this board should be checked for multi CPU */
+       const char      *name;
+       unsigned char   *map;
+       unsigned char   *routes;
+} mot_info[] = {
+       {0x300, 0x00, 0x00, "MVME 2400",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x010, 0x00, 0x00, "Genesis",                          Genesis_pci_IRQ_map,    Genesis_pci_IRQ_routes},
+       {0x020, 0x00, 0x00, "Powerstack (Series E)",            Comet_pci_IRQ_map,      Comet_pci_IRQ_routes},
+       {0x040, 0x00, 0x00, "Blackhawk (Powerstack)",           Blackhawk_pci_IRQ_map,  Blackhawk_pci_IRQ_routes},
+       {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",    Omaha_pci_IRQ_map,      Omaha_pci_IRQ_routes},
+       {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",     Utah_pci_IRQ_map,       Utah_pci_IRQ_routes},
+       {0x0A0, 0x00, 0x00, "Powerstack (Series EX)",           Comet2_pci_IRQ_map,     Comet2_pci_IRQ_routes},
+       {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",           Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",             Sitka_pci_IRQ_map,      Raven_pci_IRQ_routes},
+       {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",    Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xF6, 0x80, "MTX Plus",                         MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes},
+       {0x1E0, 0xF6, 0x81, "Dual MTX Plus",                    MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes},
+       {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",            MTX_pci_IRQ_map,        Raven_pci_IRQ_routes},
+       {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",       MTX_pci_IRQ_map,        Raven_pci_IRQ_routes},
+       {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",             MTX_pci_IRQ_map,        Raven_pci_IRQ_routes},
+       {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",        MTX_pci_IRQ_map,        Raven_pci_IRQ_routes},
+       {0x1E0, 0xF9, 0x00, "MVME 2300",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",                 Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",      Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes},
+       {0x000, 0x00, 0x00, "",                                 NULL,                   NULL}
+};
+
 __initfunc(unsigned long prep_route_pci_interrupts(void))
 {
        unsigned char *ibc_pirq = (unsigned char *)0x80800860;
@@ -511,53 +793,66 @@ __initfunc(unsigned long prep_route_pci_interrupts(void))
        if ( _prep_type == _PREP_Motorola)
        {
                unsigned short irq_mode;
+               unsigned char  cpu_type;
+               unsigned char  base_mod;
+               int            entry;
+               int            mot_entry = -1;
 
-               switch (inb(0x800) & 0xF0)
-               {
-               case 0x10: /* MVME16xx */
-                       Motherboard_map_name = "Genesis";
-                       Motherboard_map = Genesis_pci_IRQ_map;
-                       Motherboard_routes = Genesis_pci_IRQ_routes;
-                       break;
-               case 0x20: /* Series E */
-                       Motherboard_map_name = "Powerstack (Series E)";
-                       Motherboard_map = Comet_pci_IRQ_map;
-                       Motherboard_routes = Comet_pci_IRQ_routes;
-                       break;
-               case 0x50: /* PowerStackII Pro3000 */
-                       Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
-                       Motherboard_map = Omaha_pci_IRQ_map;
-                       Motherboard_routes = Omaha_pci_IRQ_routes;
-                       break;
-               case 0x60: /* PowerStackII Pro4000 */
-                       Motherboard_map_name = "Utah (Powerstack II Pro4000)";
-                       Motherboard_map = Utah_pci_IRQ_map;
-                       Motherboard_routes = Utah_pci_IRQ_routes;
-                       break;
-               case 0xE0: /* MVME 26xx, 36xx, MTX ? */
-                       Motherboard_map_name = "Genesis2";
-                       Motherboard_map = Genesis2_pci_IRQ_map;
-                       Motherboard_routes = Genesis2_pci_IRQ_routes;
-
-                       /* Return: different ibc_pcicon and
-                          pirq already set up by firmware. */
-                       return 0; 
-                       break;
-               case 0x40: /* PowerStack */
-               default: /* Can't hurt, can it? */
-                       Motherboard_map_name = "Blackhawk (Powerstack)";
-                       Motherboard_map = Blackhawk_pci_IRQ_map;
-                       Motherboard_routes = Blackhawk_pci_IRQ_routes;
-                       break;
+               cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+               base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+               for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+                       if (mot_info[entry].cpu_type & 0x200) {                 /* Check for Hawk chip */
+                               if (!(MotMPIC & MOT_HAWK_PRESENT))
+                                       continue;
+                       } else {                                                /* Check non hawk boards */
+                               if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+                                       continue;
+
+                               if (mot_info[entry].base_type == 0) {
+                                       mot_entry = entry;
+                                       break;
+                               }
+
+                               if (mot_info[entry].base_type != base_mod)
+                                       continue;
+                       }
+
+                       if (!(mot_info[entry].max_cpu & 0x80)) {
+                               mot_entry = entry;
+                               break;
+                       }
+
+                       /* processor 1 not present and max processor zero indicated */
+                       if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+                               mot_entry = entry;
+                               break;
+                       }
+
+                       /* processor 1 present and max processor zero indicated */
+                       if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+                               mot_entry = entry;
+                               break;
+                       }
                }
-               /* AJF adjust level/edge control according to routes */
-               irq_mode = 0;
-               for (i = 1;  i <= 4;  i++)
-               {
-                       irq_mode |= ( 1 << Motherboard_routes[i] );
+
+               if (mot_entry == -1)    /* No particular cpu type found - assume Blackhawk */
+                       mot_entry = 3;
+
+               Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+               Motherboard_map = mot_info[mot_entry].map;
+               Motherboard_routes = mot_info[mot_entry].routes;
+
+               if (!(mot_info[entry].cpu_type & 0x100)) {
+                       /* AJF adjust level/edge control according to routes */
+                       irq_mode = 0;
+                       for (i = 1;  i <= 4;  i++)
+                       {
+                               irq_mode |= ( 1 << Motherboard_routes[i] );
+                       }
+                       outb( irq_mode & 0xff, 0x4d0 );
+                       outb( (irq_mode >> 8) & 0xff, 0x4d1 );
                }
-               outb( irq_mode & 0xff, 0x4d0 );
-               outb( (irq_mode >> 8) & 0xff, 0x4d1 );
        } else if ( _prep_type == _PREP_IBM )
        {
                unsigned char pl_id;
@@ -677,71 +972,6 @@ __initfunc(unsigned long prep_route_pci_interrupts(void))
        return 0;
 }
 
-__initfunc(
-static inline void fixup_pci_interrupts(PnP_TAG_PACKET *pkt)) {
-#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData
-        u_int bus = data[16];
-        u_char *End, *p;
-
-        End = data + ld_le16((u_short *)(&pkt->L4_Pack.Count0)) - 1;
-        printk("Interrupt mapping from %d to %d\n", 20, End-data);
-        for (p=data+20; p<End; p+=12){
-                struct pci_dev *dev;
-                for (dev=pci_devices; dev; dev=dev->next) {
-                        unsigned code, irq;
-                        u_char pin;
-
-                        if ( dev->bus->number != bus ||
-                             PCI_SLOT(dev->devfn) != PCI_SLOT(p[1]))
-                                continue;
-                        pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin);
-                        if(!pin) continue;
-                        code=ld_le16((unsigned short *)
-                                    (p+4+2*(pin-1)));
-                        /* Set vector to 0 for unrouted PCI ints. This code
-                         * is ugly but handles correctly the special case of
-                         * interrupt 0 (8259 cascade) on OpenPIC
-                         */
-
-                        irq = (code == 0xffff) ? 0 : code&0x7fff;
-                        if (p[2] == 2) { /* OpenPIC */
-                                if (irq) {
-                                        openpic_set_sense(irq, code<0x8000);
-                                        irq=openpic_to_irq(irq);
-                                } else continue;
-                        } else if (p[2] != 1){ /* Not 8259 */
-                                printk("Unknown or unsupported "
-                                       "interrupt controller"
-                                       "type %d.\n",  p[2]);
-                                continue;
-                        }
-                        dev->irq=irq;
-                }
-
-        }
-}
-
-__initfunc(
-static inline void fixup_bases(struct pci_dev *dev)) {
-        int k;
-        for (k=0; k<6; k++) {
-               /* FIXME: get the base address physical offset from 
-                       the Raven instead of hard coding it.
-                               -- Troy */
-                if (dev->base_address[k] &&
-                    (dev->base_address[k]&PCI_BASE_ADDRESS_SPACE)
-                    == PCI_BASE_ADDRESS_SPACE_MEMORY)
-                        dev->base_address[k]+=0xC0000000;
-                if ((dev->base_address[k] &
-                     (PCI_BASE_ADDRESS_SPACE |
-                      PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-                     == (PCI_BASE_ADDRESS_SPACE_MEMORY |
-                         PCI_BASE_ADDRESS_MEM_TYPE_64))
-                        k++;
-        }
-}
-
-
 __initfunc(
 void
 prep_pcibios_fixup(void))
@@ -754,44 +984,57 @@ prep_pcibios_fixup(void))
         if ( _prep_type == _PREP_Radstone )
         {
                 printk("Radstone boards require no PCI fixups\n");
+               return;
         }
-        else
-        {
-               prep_route_pci_interrupts();
-                for(dev=pci_devices; dev; dev=dev->next)
-                {
-                        /*
-                         * Use our old hard-coded kludge to figure out what
-                         * irq this device uses.  This is necessary on things
-                         * without residual data. -- Cort
-                         */
-                        unsigned char d = PCI_SLOT(dev->devfn);
-                        dev->irq = Motherboard_routes[Motherboard_map[d]];
-                        for ( i = 0 ; i <= 5 ; i++ )
-                        {
-                                if ( dev->base_address[i] > 0x10000000 )
-                                {
-                                        printk("Relocating PCI address %lx -> %lx\n",
-                                               dev->base_address[i],
-                                               (dev->base_address[i] & 0x00FFFFFF)
-                                               | 0x01000000);
-                                        dev->base_address[i] =
-                                          (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-                                        pci_write_config_dword(dev,
-                                                PCI_BASE_ADDRESS_0+(i*0x4),
-                                               dev->base_address[i] );
-                                }
-                        }
+
+       prep_route_pci_interrupts();
+
+       printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+       if (OpenPIC) {
+               /* PCI interrupts are controlled by the OpenPIC */
+               for(dev=pci_devices; dev; dev=dev->next) {
+                       if (dev->bus->number == 0) {
+                                       dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+                               pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
+                       }
+               }
+               return;
+       }
+
+       for(dev=pci_devices; dev; dev=dev->next)
+       {
+               /*
+                * Use our old hard-coded kludge to figure out what
+                * irq this device uses.  This is necessary on things
+                * without residual data. -- Cort
+                */
+               unsigned char d = PCI_SLOT(dev->devfn);
+               dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+               for ( i = 0 ; i <= 5 ; i++ )
+               {
+                       if ( dev->base_address[i] > 0x10000000 )
+                       {
+                               printk("Relocating PCI address %lx -> %lx\n",
+                                      dev->base_address[i],
+                                      (dev->base_address[i] & 0x00FFFFFF)
+                                      | 0x01000000);
+                               dev->base_address[i] =
+                                 (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+                               pci_write_config_dword(dev,
+                                       PCI_BASE_ADDRESS_0+(i*0x4),
+                                      dev->base_address[i] );
+                       }
+               }
 #if 0
-                        /*
-                         * If we have residual data and if it knows about this
-                         * device ask it what the irq is.
-                         *  -- Cort
-                         */
-                        ppcd = residual_find_device_id( ~0L, dev->device,
-                                                        -1,-1,-1, 0);
+               /*
+                * If we have residual data and if it knows about this
+                * device ask it what the irq is.
+                *  -- Cort
+                */
+               ppcd = residual_find_device_id( ~0L, dev->device,
+                                               -1,-1,-1, 0);
 #endif
-               }
        }
 }
 
index bf80d6e2eedf93280285037d74b4b6dce688b06f..de18f465adac7afb4c0b630436e641a884098333 100644 (file)
@@ -45,6 +45,8 @@
 #include <asm/machdep.h>
 #include <asm/mk48t59.h>
 #include <asm/prep_nvram.h>
+#include <asm/raven.h>
+
 
 #include "time.h"
 #include "local_irq.h"
@@ -82,15 +84,7 @@ extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
 
 extern void prep_setup_pci_ptrs(void);
-
-/* these need to be here since PReP uses them for OpenPIC support */
-/* Maybe move these to a 'openpic_irq.c' file instead? --Troy */
-extern void chrp_mask_and_ack_irq(unsigned int irq_nr);
-extern void chrp_mask_irq(unsigned int irq_nr);
-extern void chrp_unmask_irq(unsigned int irq_nr);
 extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
-extern volatile unsigned char *chrp_int_ack_special;
-
 extern char saved_command_line[256];
 
 int _prep_type;
@@ -355,6 +349,8 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
        request_region(0x80,0x10,"dma page reg");
        request_region(0xc0,0x20,"dma2");
 
+       raven_init();
+
 #ifdef CONFIG_VGA_CONSOLE
        /* remap the VGA memory */
        vgacon_remap_base = 0xf0000000;
@@ -595,39 +591,13 @@ void
 prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
 {
         int irq;
-       
-        /*
-         * Perform an interrupt acknowledge cycle on controller 1
-         */                                                             
-        outb(0x0C, 0x20);
-        irq = inb(0x20) & 7;                                   
-        if (irq == 2)                                                     
-        {                                                                   
-                /*                                     
-                 * Interrupt is cascaded so perform interrupt
-                 * acknowledge on controller 2
-                 */
-                outb(0x0C, 0xA0);                      
-                irq = (inb(0xA0) & 7) + 8;
-        }
-        else if (irq==7)                                
-        {
-                /*                               
-                 * This may be a spurious interrupt
-                 *                         
-                 * Read the interrupt status register. If the most
-                 * significant bit is not set then there is no valid
-                * interrupt
-                */
-               outb(0x0b, 0x20);
-                
-               if(~inb(0x20)&0x80)
-               {
-                       printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
-                              regs->nip);
-                        ppc_spurious_interrupts++;
-                        return;
-                }
+
+       if ( (irq = i8259_irq(0)) < 0 )
+       {
+               printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+                      regs->nip);
+               ppc_spurious_interrupts++;
+               return;
        }
         ppc_irq_dispatch_handler( regs, irq );
 }              
@@ -637,9 +607,19 @@ prep_init_IRQ(void))
 {
        int i;
 
+       if (OpenPIC != NULL) {
+               for ( i = 16 ; i < 36 ; i++ )
+                       irq_desc[i].ctl = &open_pic;
+               openpic_init(1);
+       }
+       
         for ( i = 0 ; i < 16  ; i++ )
                 irq_desc[i].ctl = &i8259_pic;
         i8259_init();
+#ifdef __SMP__
+       request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+                   0, "IPI0", 0);
+#endif /* __SMP__ */
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -728,8 +708,6 @@ __initfunc(void
 prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
          unsigned long r6, unsigned long r7))
 {
-       int tmp;
-
        /* make a copy of residual data */
        if ( r3 )
        {
@@ -784,27 +762,15 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
                strcpy(cmd_line, (char *)(r6+KERNELBASE));
        }
 
-       if ( is_powerplus ) {   /* look for a Raven OpenPIC */
-               pcibios_read_config_dword(0, 0, 0, &tmp);
-               if (tmp == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
-                       pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &tmp);
-                       if (tmp) {
-                               OpenPIC=(volatile struct OpenPIC *)
-                                       (tmp + isa_mem_base);
-                               /* printk("OpenPIC found at %p: \n", OpenPIC);*/
-                       }
-               } else {
-                       printk ("prep_init: WARNING: can't find an OpenPIC on what looks like a PowerPlus board\n");
-               }
-       }
-
-
        ppc_md.setup_arch     = prep_setup_arch;
        ppc_md.setup_residual = prep_setup_residual;
        ppc_md.get_cpuinfo    = prep_get_cpuinfo;
        ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
        ppc_md.init_IRQ       = prep_init_IRQ;
-       ppc_md.do_IRQ         = prep_do_IRQ;
+       if ( !OpenPIC )
+               ppc_md.do_IRQ         = prep_do_IRQ;
+       else
+               ppc_md.do_IRQ         = chrp_do_IRQ;
        ppc_md.init           = NULL;
 
        ppc_md.restart        = prep_restart;
@@ -858,9 +824,8 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
         ppc_ide_md.release_region = prep_ide_release_region;
         ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif         
+        ppc_ide_md.io_base = _IO_BASE;
 
 #ifdef CONFIG_VT
        ppc_md.kbd_setkeycode    = pckbd_setkeycode;
index 6cd61b12717e8aee760e535275da2e2079e7439e..db87c2384a8afbb3c89210bd7d339071854a7997 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.78 1999/04/07 07:27:00 paulus Exp $
+ * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
 #include <asm/prom.h>
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-void switch_to(struct task_struct *, struct task_struct *);
-
 extern unsigned long _get_SP(void);
-extern spinlock_t scheduler_lock;
 
 struct task_struct *last_task_used_math = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
@@ -160,7 +157,8 @@ int check_stack(struct task_struct *tsk)
 }
 
 void
-switch_to(struct task_struct *prev, struct task_struct *new)
+_switch_to(struct task_struct *prev, struct task_struct *new,
+         struct task_struct **last)
 {
        struct thread_struct *new_tss, *old_tss;
        int s = _disable_interrupts();
@@ -170,10 +168,10 @@ switch_to(struct task_struct *prev, struct task_struct *new)
 #endif
 
 #ifdef SHOW_TASK_SWITCHES
-       printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
+       printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
               prev->comm,prev->pid,
               new->comm,new->pid,new->tss.regs->nip,new->processor,
-              scheduler_lock.lock,new->fs->root,prev->fs->root);
+              new->fs->root,prev->fs->root);
 #endif
 #ifdef __SMP__
        /* avoid complexity of lazy save/restore of fpu
@@ -181,7 +179,8 @@ switch_to(struct task_struct *prev, struct task_struct *new)
         * this task used the fpu during the last quantum.
         * 
         * If it tries to use the fpu again, it'll trap and
-        * reload its fp regs.
+        * reload its fp regs.  So we don't have to do a restore
+        * every switch, just a save.
         *  -- Cort
         */
        if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
@@ -192,7 +191,7 @@ switch_to(struct task_struct *prev, struct task_struct *new)
 #endif /* __SMP__ */
        new_tss = &new->tss;
        old_tss = &current->tss;
-       _switch(old_tss, new_tss, new->mm->context);
+       *last = _switch(old_tss, new_tss, new->mm->context);
        _enable_interrupts(s);
 }
 
@@ -278,8 +277,12 @@ int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
            struct task_struct * p, struct pt_regs * regs)
 {
-       struct pt_regs * childregs;
-       
+       struct pt_regs * childregs, *kregs;
+#ifdef __SMP__
+       extern void ret_from_smpfork(void);
+#else
+       extern void ret_from_syscall(void);
+#endif
        /* Copy registers */
        childregs = ((struct pt_regs *)
                     ((unsigned long)p + sizeof(union task_union)
@@ -288,8 +291,19 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        if ((childregs->msr & MSR_PR) == 0)
                childregs->gpr[2] = (unsigned long) p;  /* `current' in new task */
        childregs->gpr[3] = 0;  /* Result from fork() */
+       p->tss.regs = childregs;
        p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
-       p->tss.regs = childregs;        
+       p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+       kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD);
+#ifdef __SMP__
+       kregs->nip = (unsigned long)ret_from_smpfork;
+#else  
+       kregs->nip = (unsigned long)ret_from_syscall;
+#endif 
+       kregs->msr = MSR_KERNEL;
+       kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+       kregs->gpr[2] = (unsigned long)p;
+       
        if (usp >= (unsigned long) regs) {
                /* Stack is in kernel space - must adjust */
                childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -311,8 +325,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        childregs->msr &= ~MSR_FP;
 
 #ifdef __SMP__
-       if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
-               p->tss.smp_fork_ret = 1;
        p->last_processor = NO_PROC_ID;
 #endif /* __SMP__ */
        return 0;
@@ -379,11 +391,6 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
        int res;
        lock_kernel();
        res = do_fork(clone_flags, regs->gpr[1], regs);
-       /*
-        * only parent returns here, child returns to either
-        * syscall_ret_1() or kernel_thread()
-        * -- Cort
-        */
 #ifdef __SMP__
        /* When we clone the idle task we keep the same pid but
         * the return value of 0 for both causes problems.
@@ -403,7 +410,6 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
        int res;
        
        res = do_fork(SIGCHLD, regs->gpr[1], regs);
-       /* only parent returns here */
 #ifdef __SMP__
        /* When we clone the idle task we keep the same pid but
         * the return value of 0 for both causes problems.
index 7c1924f257c25737727cfc5cb72c335a3392d700..b2221481aebfb33e7f69feb30b9b9b3ecbf869e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.53 1999/04/22 22:45:42 cort Exp $
+ * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -457,7 +457,7 @@ prom_init(int r3, int r4, prom_entry pp)
         * a holding pattern controlled by the kernel (not OF) before
         * we destroy the OF.
         *
-        * This used a chunk of high memory, puts some holding pattern
+        * This uses a chunk of high memory, puts some holding pattern
         * code there and sends the other processors off to there until
         * smp_boot_cpus tells them to do something.  We do that by using
         * physical address 0x0.  The holding pattern checks that address
index 42e2918b138cf50baddf558329eeac01a83ae539..92299e825b44d36f9fbc9b43efe949055ad15e66 100644 (file)
@@ -140,7 +140,8 @@ good_area:
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       handle_mm_fault(current, vma, address, error_code & 0x02000000);
+       if (!handle_mm_fault(current, vma, address, error_code & 0x02000000))
+               goto bad_area;
        up(&mm->mmap_sem);
        /*
         * keep track of tlb+htab misses that are good addrs but
index dd204895d2e42f8e009474ed163f2acf0e7e6d48..eac750568a27422aef9a38687d36c171d23487a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.163 1999/04/09 06:37:13 cort Exp $
+ *  $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -119,12 +119,19 @@ extern struct task_struct *current_set[NR_CPUS];
 PTE *Hash, *Hash_end;
 unsigned long Hash_size, Hash_mask;
 #ifndef CONFIG_8xx
+#ifdef CONFIG_PPC64
+unsigned long long _SDR1;
+#else
 unsigned long _SDR1;
+#endif
 static void hash_init(void);
 union ubat {                   /* BAT register values to be loaded */
        BAT     bat;
-       P601_BAT bat_601;
+#ifdef CONFIG_PPC64
+       u64     word[2];
+#else
        u32     word[2];
+#endif 
 } BATS[4][2];                  /* 4 pairs of IBAT, DBAT */
 
 struct batrange {              /* stores address ranges mapped by BATs */
@@ -146,7 +153,6 @@ int __map_without_bats = 0;
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
-
 void __bad_pte(pmd_t *pmd)
 {
        printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
@@ -354,7 +360,6 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
                return NULL;
 
 #ifndef CONFIG_8xx
-#if 0  
        /*
         * Is it already mapped?  Perhaps overlapped by a previous
         * BAT mapping.  If the whole area is mapped then we're done,
@@ -368,7 +373,6 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
         */
        if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
                goto out;
-#endif 
 #endif /* CONFIG_8xx */
        
        if (mem_init_done) {
@@ -397,7 +401,8 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
        
        for (i = 0; i < size; i += PAGE_SIZE)
                map_page(&init_task, v+i, p+i, flags);
-       return (void *) (v + (addr & ~PAGE_MASK));
+out:   
+       return (void *) (v + (p & ~PAGE_MASK));
 }
 
 void iounmap(void *addr)
@@ -1500,10 +1505,18 @@ __initfunc(static void hash_init(void))
         * up to a maximum of 2MB.
         */
        ramsize = (ulong)end_of_DRAM - KERNELBASE;
+#ifdef CONFIG_PPC64    
+       Hash_mask = 0;
+       for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
+               ;
+       Hash_size = h;
+       Hash_mask << 10;  /* so setting _SDR1 works the same -- Cort */
+#else
        for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
                ;
        Hash_size = h;
        Hash_mask = (h >> 6) - 1;
+#endif 
        
 #ifdef NO_RELOAD_HTAB
        /* shrink the htab since we don't use it on 603's -- Cort */
index fc6dce28f06f97bcfef9bb670aada2560fa7eb95..8eeac72b0cd2486f749933ee94899c107b3d22ab 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.158 1999/04/27 14:35:07 davem Exp $
+/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1476,7 +1476,7 @@ C_LABEL(ret_from_smpfork):
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
        call    schedule_tail
-        nop
+        mov    %g3, %o0
        b       C_LABEL(ret_sys_call)
         ld     [%sp + REGWIN_SZ + PT_I0], %o0
 #endif
index 23893a315852cb7fb0c9aa85e072b51f9d8f4af8..301747c222513723e2a1c456f1086b464eaa223e 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.136 1999/04/16 01:20:33 anton Exp $
+/*  $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,8 @@ asmlinkage int sys_idle(void)
        /* endless idle loop with no priority at all */
        current->priority = 0;
        current->counter = -100;
+       init_idle();
+
        for (;;) {
                if (ARCH_SUN4C_SUN4) {
                        static int count = HZ;
@@ -111,6 +113,8 @@ int cpu_idle(void *unused)
        /* endless idle loop with no priority at all */
        current->priority = 0;
        current->counter = -100;
+       init_idle();
+
        while(1) {
                if(current->need_resched) {
                        schedule();
index af0aaf58d7af4b582ea5c2d1985ff33597cf9dff..edd736b41bd844e4d88d6380b0c2115d84ca0345 100644 (file)
@@ -190,6 +190,7 @@ __initfunc(void smp4d_boot_cpus(void))
        current->processor = boot_cpu_id;
        smp_store_cpu_info(boot_cpu_id);
        smp_setup_percpu_timer();
+       init_idle();
        local_flush_cache_all();
        if(linux_num_cpus == 1)
                return;  /* Not an MP box. */
@@ -211,6 +212,7 @@ __initfunc(void smp4d_boot_cpus(void))
                        p = task[++cpucount];
 
                        p->processor = i;
+                       p->has_cpu = 1; /* we schedule the first task manually */
                        current_set[i] = p;
                        
                        for (no = 0; no < linux_num_cpus; no++)
index ff2c8e99a006be04b93b3af842b41251e54bf2ac..c9acf609c47e98157031305c055b0cd3c1d68046 100644 (file)
@@ -161,6 +161,7 @@ __initfunc(void smp4m_boot_cpus(void))
        smp_store_cpu_info(boot_cpu_id);
        set_irq_udt(mid_xlate[boot_cpu_id]);
        smp_setup_percpu_timer();
+       init_idle();
        local_flush_cache_all();
        if(linux_num_cpus == 1)
                return;  /* Not an MP box. */
@@ -180,6 +181,7 @@ __initfunc(void smp4m_boot_cpus(void))
                        p = task[++cpucount];
 
                        p->processor = i;
+                       p->has_cpu = 1; /* we schedule the first task manually */
                        current_set[i] = p;
 
                        /* See trampoline.S for details... */
index ab1515f82fea0db83e4f6f46ebffaedabaf4a89d..ed3918c10544d4aa57f5dfeb6cf01e5767322db2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.51 1999/03/20 22:02:00 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -231,7 +231,7 @@ c_sys_nis_syscall (struct pt_regs *regs)
        
        if (count++ > 5) return -ENOSYS;
        lock_kernel();
-       printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
+       printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
 #ifdef DEBUG_UNIMP_SYSCALL     
        show_regs (regs);
 #endif
index c7c6bdd5fe566b1603ac721f299653dddb655bd5..a0f92ea79599c2669bf83e9a240fe08ccb4abb97 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $
+/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -51,8 +51,7 @@ iommu_init(int iommund, struct linux_sbus *sbus))
        unsigned long tmp;
        struct iommu_struct *iommu;
        struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-       int i, j, k, l, m;
-       struct iommu_alloc { unsigned long addr; int next; } *ia;
+       int i;
 
        iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
        prom_getproperty(iommund, "reg", (void *) iommu_promregs,
@@ -97,62 +96,18 @@ iommu_init(int iommund, struct linux_sbus *sbus))
        ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
 
        /* Stupid alignment constraints give me a headache. 
-          We want to get very large aligned memory area, larger than
-          maximum what get_free_pages gives us (128K): we need
-          256K or 512K or 1M or 2M aligned to its size. */
-       ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC);
-       for (i = 0; i < 128; i++) {
-               ia[i].addr = 0;
-               ia[i].next = -1;
-       }
-       k = 0;
-       for (i = 0; i < 128; i++) {
-               ia[i].addr = __get_free_pages(GFP_DMA, 5);
-               if (ia[i].addr <= ia[k].addr) {
-                       if (i) {
-                               ia[i].next = k;
-                               k = i;
-                       }                       
-               } else {
-                       for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next)
-                               if (ia[i].addr <= ia[l].addr) {
-                                       ia[i].next = l;
-                                       ia[m].next = i;
-                               }
-                       if (l == -1)
-                               ia[m].next = i;
-               }
-               for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) {
-                       if (!(ia[l].addr & (ptsize - 1))) {
-                               tmp = ia[l].addr;
-                               m = l;
-                               j = 128 * 1024;
-                       } else if (m != -1) {
-                               if (ia[l].addr != tmp + j)
-                                       m = -1;
-                               else {
-                                       j += 128 * 1024;
-                                       if (j == ptsize) {
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               if (l != -1)
+          We need 256K or 512K or 1M or 2M area aligned to
+           its size and current gfp will fortunately give
+           it to us. */
+       for (i = 6; i < 9; i++)
+               if ((1 << (i + PAGE_SHIFT)) == ptsize)
                        break;
-       }
-       if (i == 128) {
+        tmp = __get_free_pages(GFP_DMA, i);
+       if (!tmp) {
                prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
                prom_halt();
        }
-       for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next)
-               ia[l].addr = 0;
-       for (l = k; l != -1; l = ia[l].next)
-               if (ia[l].addr)
-                       free_pages(ia[l].addr, 5);
-       kfree (ia);
        iommu->lowest = iommu->page_table = (iopte_t *)tmp;
-       
 
        /* Initialize new table. */
        flush_cache_all();
index 02f91a226e30e9a7c3ea7154c097fdf2c45a18f5..86518e50e623c19b609bb3304bff39ad8f5cb469 100644 (file)
@@ -65,7 +65,7 @@ __initfunc(void cpu_probe(void))
        long ver, fpu_vers;
        long fprs;
        
-       cpuid = smp_processor_id();
+       cpuid = hard_smp_processor_id();
 
        fprs = fprs_read ();
        fprs_write (FPRS_FEF);
index 412c953f256032d78382560ace2721aa2375c75e..0aef0b01982be8e0a4c34dd31b4fc503bbffdf49 100644 (file)
@@ -73,6 +73,9 @@ device_scan(unsigned long mem_start))
        
        prom_cpu_nodes[0] = prom_node_cpu;
 
+       mem_start = central_probe(mem_start);
+
        cpu_probe();
-       return central_probe(mem_start);
+
+       return mem_start;
 }
index 273229532232ca39ada2cfb37d060f1b841e9c56..e64e87299a6563d51bb8ba3a206ebe800bfea838 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.35 1999/01/26 14:34:11 jj Exp $
+/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -35,9 +35,6 @@ extern void prom_ebus_intmap_init(struct linux_ebus *);
 #ifdef CONFIG_SUN_OPENPROMIO
 extern int openprom_init(void);
 #endif
-#ifdef CONFIG_SPARCAUDIO
-extern int sparcaudio_init(void);
-#endif
 #ifdef CONFIG_SUN_AUXIO
 extern void auxio_probe(void);
 #endif
@@ -399,9 +396,6 @@ __initfunc(void ebus_init(void))
 #ifdef CONFIG_SUN_OPENPROMIO
        openprom_init();
 #endif
-#ifdef CONFIG_SPARCAUDIO
-       sparcaudio_init();
-#endif
 #ifdef CONFIG_SUN_BPP
        bpp_init();
 #endif
index a9ad1db315fa666bdb77df390cd5047047a6cb7c..4134dcc3afb2b5507833acfb8fb5351cbb0a2bd9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.102 1999/03/29 12:38:09 jj Exp $
+/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -766,6 +766,7 @@ ret_from_syscall:
                 */
 #ifdef __SMP__
                andn            %o7, 0x100, %l0
+               mov             %g5, %o0        /* 'prev' */
                call            schedule_tail
                 sth            %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
 #else
index 11492f9ca7ac14ef31b4ee17a5cae4f57c048d91..84d4de363cfc09b83c06e9f8202baef9f1fc07be 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.61 1999/04/28 19:44:31 davem Exp $
+/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -36,6 +36,7 @@
 #include <linux/vt_kern.h>
 #include <linux/fb.h>
 #include <linux/ext2_fs.h>
+#include <linux/videodev.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -118,6 +119,247 @@ static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        return sys_ioctl(fd, cmd, arg);
 }
  
+struct video_tuner32 {
+       s32 tuner;
+       u8 name[32];
+       u32 rangelow, rangehigh;
+       u32 flags;
+       u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+       int i;
+
+       if(get_user(kp->tuner, &up->tuner))
+               return -EFAULT;
+       for(i = 0; i < 32; i++)
+               __get_user(kp->name[i], &up->name[i]);
+       __get_user(kp->rangelow, &up->rangelow);
+       __get_user(kp->rangehigh, &up->rangehigh);
+       __get_user(kp->flags, &up->flags);
+       __get_user(kp->mode, &up->mode);
+       __get_user(kp->signal, &up->signal);
+       return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+       int i;
+
+       if(put_user(kp->tuner, &up->tuner))
+               return -EFAULT;
+       for(i = 0; i < 32; i++)
+               __put_user(kp->name[i], &up->name[i]);
+       __put_user(kp->rangelow, &up->rangelow);
+       __put_user(kp->rangehigh, &up->rangehigh);
+       __put_user(kp->flags, &up->flags);
+       __put_user(kp->mode, &up->mode);
+       __put_user(kp->signal, &up->signal);
+       return 0;
+}
+
+struct video_buffer32 {
+       /* void * */ u32 base;
+       s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+       u32 tmp;
+
+       if(get_user(tmp, &up->base))
+               return -EFAULT;
+       kp->base = (void *) ((unsigned long)tmp);
+       __get_user(kp->height, &up->height);
+       __get_user(kp->width, &up->width);
+       __get_user(kp->depth, &up->depth);
+       __get_user(kp->bytesperline, &up->bytesperline);
+       return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+       u32 tmp = (u32)((unsigned long)kp->base);
+
+       if(put_user(tmp, &up->base))
+               return -EFAULT;
+       __put_user(kp->height, &up->height);
+       __put_user(kp->width, &up->width);
+       __put_user(kp->depth, &up->depth);
+       __put_user(kp->bytesperline, &up->bytesperline);
+       return 0;
+}
+
+struct video_clip32 {
+       s32 x, y, width, height;
+       /* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+       u32 x, y, width, height, chromakey, flags;
+       /* struct video_clip32 * */ u32 clips;
+       s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+       struct video_clip *cp;
+
+       cp = kp->clips;
+       if(cp != NULL)
+               kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+       struct video_clip32 *ucp;
+       struct video_clip *kcp;
+       int nclips, err, i;
+       u32 tmp;
+
+       if(get_user(kp->x, &up->x))
+               return -EFAULT;
+       __get_user(kp->y, &up->y);
+       __get_user(kp->width, &up->width);
+       __get_user(kp->height, &up->height);
+       __get_user(kp->chromakey, &up->chromakey);
+       __get_user(kp->flags, &up->flags);
+       __get_user(kp->clipcount, &up->clipcount);
+       __get_user(tmp, &up->clips);
+       ucp = (struct video_clip32 *)A(tmp);
+       kp->clips = NULL;
+
+       nclips = kp->clipcount;
+       if(nclips == 0)
+               return 0;
+
+       if(ucp == 0)
+               return -EINVAL;
+
+       /* Peculiar interface... */
+       if(nclips < 0)
+               nclips = VIDEO_CLIPMAP_SIZE;
+
+       kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+       err = -ENOMEM;
+       if(kcp == NULL)
+               goto cleanup_and_err;
+
+       kp->clips = kcp;
+       for(i = 0; i < nclips; i++) {
+               __get_user(kcp[i].x, &ucp[i].x);
+               __get_user(kcp[i].y, &ucp[i].y);
+               __get_user(kcp[i].width, &ucp[i].width);
+               __get_user(kcp[i].height, &ucp[i].height);
+               kcp[nclips].next = NULL;
+       }
+
+       return 0;
+
+cleanup_and_err:
+       free_kvideo_clips(kp);
+       return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+       if(put_user(kp->x, &up->x))
+               return -EFAULT;
+       __put_user(kp->y, &up->y);
+       __put_user(kp->width, &up->width);
+       __put_user(kp->height, &up->height);
+       __put_user(kp->chromakey, &up->chromakey);
+       __put_user(kp->flags, &up->flags);
+       __put_user(kp->clipcount, &up->clipcount);
+       return 0;
+}
+
+#define VIDIOCGTUNER32         _IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32         _IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32           _IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32           _IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32          _IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32          _IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32          _IOR('v',14, u32)
+#define VIDIOCSFREQ32          _IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       union {
+               struct video_tuner vt;
+               struct video_buffer vb;
+               struct video_window vw;
+               unsigned long vx;
+       } karg;
+       mm_segment_t old_fs = get_fs();
+       void *up = (void *)arg;
+       int err = 0;
+
+       /* First, convert the command. */
+       switch(cmd) {
+       case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+       case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+       case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+       case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+       case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+       case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+       case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+       case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+       };
+
+       switch(cmd) {
+       case VIDIOCSTUNER:
+       case VIDIOCGTUNER:
+               err = get_video_tuner32(&karg.vt, up);
+               break;
+
+       case VIDIOCSWIN:
+               err = get_video_window32(&karg.vw, up);
+               break;
+
+       case VIDIOCSFBUF:
+               err = get_video_buffer32(&karg.vb, up);
+               break;
+
+       case VIDIOCSFREQ:
+               err = get_user(karg.vx, (u32 *)up);
+               break;
+       };
+       if(err)
+               goto out;
+
+       set_fs(KERNEL_DS);
+       err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+       set_fs(old_fs);
+
+       if(cmd == VIDIOCSWIN)
+               free_kvideo_clips(&karg.vw);
+
+       if(err == 0) {
+               switch(cmd) {
+               case VIDIOCGTUNER:
+                       err = put_video_tuner32(&karg.vt, up);
+                       break;
+
+               case VIDIOCGWIN:
+                       err = put_video_window32(&karg.vw, up);
+                       break;
+
+               case VIDIOCGFBUF:
+                       err = put_video_buffer32(&karg.vb, up);
+                       break;
+
+               case VIDIOCGFREQ:
+                       err = put_user(((u32)karg.vx), (u32 *)up);
+                       break;
+               };
+       }
+out:
+       return err;
+}
+
 struct timeval32 {
        int tv_sec;
        int tv_usec;
@@ -1601,6 +1843,17 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
                error = do_ext2_ioctl(fd, cmd, arg);
                goto out;
                
+       case VIDIOCGTUNER32:
+       case VIDIOCSTUNER32:
+       case VIDIOCGWIN32:
+       case VIDIOCSWIN32:
+       case VIDIOCGFBUF32:
+       case VIDIOCSFBUF32:
+       case VIDIOCGFREQ32:
+       case VIDIOCSFREQ32:
+               error = do_video_ioctl(fd, cmd, arg);
+               goto out;
+
        /* List here exlicitly which ioctl's are known to have
         * compatable types passed or none at all...
         */
@@ -1794,6 +2047,33 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        case VUIDSFORMAT:
        case VUIDGFORMAT:
 
+       /* Little v, the video4linux ioctls */
+       case VIDIOCGCAP:
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
+       case VIDIOCGPICT:
+       case VIDIOCSPICT:
+       case VIDIOCCAPTURE:
+       case VIDIOCKEY:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       case VIDIOCSYNC:
+       case VIDIOCMCAPTURE:
+       case VIDIOCGMBUF:
+       case VIDIOCGUNIT:
+       case VIDIOCGCAPTURE:
+       case VIDIOCSCAPTURE:
+
+       /* BTTV specific... */
+       case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
+       case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+       case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+       case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+       case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
+
        /* Little p (/dev/rtc, /dev/envctrl, etc.) */
        case RTCGET:
        case RTCSET:
index c255ad51bde32cea268bb2b26df1017cbc36bc20..0d4871132330fef3022f3d38964c68786616bd85 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.90 1999/03/22 02:12:16 davem Exp $
+/*  $Id: process.c,v 1.92 1999/05/08 23:04:48 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -54,6 +54,8 @@ asmlinkage int sys_idle(void)
        /* endless idle loop with no priority at all */
        current->priority = 0;
        current->counter = -100;
+       init_idle();
+
        for (;;) {
                /* If current->need_resched is zero we should really
                 * setup for a system wakup event and execute a shutdown
@@ -79,6 +81,8 @@ asmlinkage int cpu_idle(void)
 {
        current->priority = 0;
        current->counter = -100;
+       init_idle();
+
        while(1) {
                if (current->need_resched != 0) {
                        unidle_me();
index 91c9185e2b9576fa73d41b315b9605d21b0d35ea..27344f4b62e13de167d8712720cb2a28682a8efa 100644 (file)
@@ -97,7 +97,7 @@ __initfunc(void smp_store_cpu_info(int id))
        cpu_data[id].pte_cache                  = NULL;
        cpu_data[id].pgdcache_size              = 0;
        cpu_data[id].pgd_cache                  = NULL;
-       cpu_data[id].idle_volume                = 0;
+       cpu_data[id].idle_volume                = 1;
 
        for(i = 0; i < 16; i++)
                cpu_data[id].irq_worklists[i] = 0;
@@ -196,6 +196,7 @@ __initfunc(void smp_boot_cpus(void))
        __sti();
        smp_store_cpu_info(boot_cpu_id);
        smp_tune_scheduling();
+       init_idle();
 
        if(linux_num_cpus == 1)
                return;
@@ -217,6 +218,7 @@ __initfunc(void smp_boot_cpus(void))
                        kernel_thread(start_secondary, NULL, CLONE_PID);
                        p = task[++cpucount];
                        p->processor = i;
+                       p->has_cpu = 1; /* we schedule the first task manually */
                        callin_flag = 0;
                        for (no = 0; no < linux_num_cpus; no++)
                                if (linux_cpus[no].mid == i)
@@ -460,8 +462,6 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
                        mm->cpu_vm_mask = (1UL << smp_processor_id());
                goto local_flush_and_out;
        } else {
-               spin_lock(&scheduler_lock);
-
                /* Try to handle two special cases to avoid cross calls
                 * in common scenerios where we are swapping process
                 * pages out.
@@ -471,16 +471,12 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
                        /* A dead context cannot ever become "alive" until
                         * a task switch is done to it.
                         */
-                       spin_unlock(&scheduler_lock);
                        return; /* It's dead, nothing to do. */
                }
                if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
-                       spin_unlock(&scheduler_lock);
                        __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
                        return; /* Only local flush is necessary. */
                }
-
-               spin_unlock(&scheduler_lock);
        }
        smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
index d2f9608534ba1439c706901ec2fbe55c4c065073..305f37ad8029c65b73f9c8e2109541ae1c7f69a2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.57 1999/03/14 20:51:28 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -90,7 +90,6 @@ extern int __ashrdi3(int, int);
 extern void dump_thread(struct pt_regs *, struct user *);
 
 #ifdef __SMP__
-extern spinlock_t scheduler_lock;
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
 #ifdef SPIN_LOCK_DEBUG
@@ -120,7 +119,6 @@ __attribute__((section("__ksymtab"))) =                             \
 /* used by various drivers */
 #ifdef __SMP__
 /* Kernel wide locking */
-EXPORT_SYMBOL(scheduler_lock);
 EXPORT_SYMBOL(kernel_flag);
 
 /* Software-IRQ BH locking */
index 1ac22b93be75ff2a29d24cb1dc242c8f8ffff4aa..aeb4b26b73ab01d33b3350afd1cd76298d986812 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.126 1999/04/09 16:16:41 jj Exp $
+/*  $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -949,8 +949,7 @@ void __flush_tlb_all(void)
 #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
 unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
 
-/* We are always protected by scheduler_lock under SMP.
- * Caller does TLB context flushing on local CPU if necessary.
+/* Caller does TLB context flushing on local CPU if necessary.
  *
  * We must be careful about boundary cases so that we never
  * let the user have CTX 0 (nucleus) or we ever use a CTX
index 28f4b9c74ba12bac3c931b31d19a4882693473e4..553013b9df0c9e371cba28ce56c7e110bce4fa3a 100644 (file)
@@ -363,7 +363,7 @@ struct atapi_capabilities_page {
 #endif
 
 #if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved4           : 4;
+       __u8 reserved4           : 1;
        /* Drive can read multisession discs. */
        __u8 multisession        : 1;
        /* Drive can read mode 2, form 2 data. */
index 174c8d413a8b0b4655c0519dd53d88e7063811fc..f247f02b49bbf985d4f17b2c791ed1c6715768d8 100644 (file)
@@ -34,6 +34,27 @@ ifeq ($(CONFIG_PARPORT),y)
       M_OBJS += parport_ax.o
     endif
   endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),y)
+    LX_OBJS += parport_amiga.o
+  else
+    ifeq ($(CONFIG_PARPORT_AMIGA),m)
+      M_OBJS += parport_amiga.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),y)
+    LX_OBJS += parport_mfc3.o
+  else
+    ifeq ($(CONFIG_PARPORT_MFC3),m)
+      M_OBJS += parport_mfc3.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),y)
+    LX_OBJS += parport_atari.o
+  else
+    ifeq ($(CONFIG_PARPORT_ATARI),m)
+      M_OBJS += parport_atari.o
+    endif
+  endif
   LX_OBJS += parport_init.o
 else
   ifeq ($(CONFIG_PARPORT),m)
@@ -50,6 +71,15 @@ else
   ifeq ($(CONFIG_PARPORT_AX),m)
     M_OBJS += parport_ax.o
   endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),m)
+    M_OBJS += parport_amiga.o
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),m)
+    M_OBJS += parport_mfc3.o
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),m)
+    M_OBJS += parport_atari.o
+  endif
 endif
 
 include $(TOPDIR)/Rules.make
diff --git a/drivers/misc/multiface.h b/drivers/misc/multiface.h
new file mode 100644 (file)
index 0000000..56769dd
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ * 
+ * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE   0x0100
+#define ROMBASE   0x0200
+#define PIABASE   0x4000
+
+#endif
+
diff --git a/drivers/misc/parport_amiga.c b/drivers/misc/parport_amiga.c
new file mode 100644 (file)
index 0000000..650d38e
--- /dev/null
@@ -0,0 +1,322 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+       /* Triggers also /STROBE. This behavior cannot be changed */
+       ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+       /* Triggers also /STROBE. This behavior cannot be changed */
+       return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+       unsigned char ret = 0;
+
+       if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+               ;
+       if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+               ;
+       if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+               ;
+       if (control & PARPORT_CONTROL_INIT) /* INITP */
+               /* reset connected to cpu reset pin */;
+       if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+               /* Not connected */;
+       if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+               /* Handled only directly by hardware */;
+       return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+       return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+             PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+       /* fake value: interrupt enable, select in, no reset,
+       no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+       /* No implementation possible */
+}
+       
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+       return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+       unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+       old = amiga_read_control(p);
+       amiga_write_control(p, (old & ~mask) ^ val);
+       return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+       unsigned char ret = 1;
+
+       if (status & PARPORT_STATUS_BUSY) /* Busy */
+               ret &= ~1;
+       if (status & PARPORT_STATUS_ACK) /* Ack */
+               /* handled in hardware */;
+       if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+               ret |= 2;
+       if (status & PARPORT_STATUS_SELECT) /* select */
+               ret |= 4;
+       if (status & PARPORT_STATUS_ERROR) /* error */
+               /* not connected */;
+       return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+       unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+       if (status & 1) /* Busy */
+               ret &= ~PARPORT_STATUS_BUSY;
+       if (status & 2) /* PaperOut */
+               ret |= PARPORT_STATUS_PAPEROUT;
+       if (status & 4) /* Selected */
+               ret |= PARPORT_STATUS_SELECT;
+       /* the rest is not connected or handled autonomously in hardware */
+
+       return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+       ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+       unsigned char status;
+
+       status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+       return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+       /* XXX: This port only has one mode, and I am
+       not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+
+static void amiga_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+       if (p->irq != PARPORT_IRQ_NONE)
+               free_irq(IRQ_AMIGA_CIAA_FLG, p);
+}
+
+static int amiga_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+       return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p);
+}
+
+static void amiga_init_state(struct parport_state *s)
+{
+       s->u.amiga.data = 0;
+       s->u.amiga.datadir = 255;
+       s->u.amiga.status = 0;
+       s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+       s->u.amiga.data = ciaa.prb;
+       s->u.amiga.datadir = ciaa.ddrb;
+       s->u.amiga.status = ciab.pra & 7;
+       s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+       ciaa.prb = s->u.amiga.data;
+       ciaa.ddrb = s->u.amiga.datadir;
+       ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+       ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+       enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+       disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static void amiga_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_amiga_ops = {
+       amiga_write_data,
+       amiga_read_data,
+
+       amiga_write_control,
+       amiga_read_control,
+       amiga_frob_control,
+
+       NULL, /* write_econtrol */
+       NULL, /* read_econtrol */
+       NULL, /* frob_econtrol */
+
+       amiga_write_status,
+       amiga_read_status,
+
+       NULL, /* write fifo */
+       NULL, /* read fifo */
+
+       amiga_change_mode,
+
+
+       amiga_release_resources,
+       amiga_claim_resources,
+
+
+       NULL, /* epp_write_data */
+       NULL, /* epp_read_data */
+       NULL, /* epp_write_addr */
+       NULL, /* epp_read_addr */
+       NULL, /* epp_check_timeout */
+
+       NULL, /* epp_write_block */
+       NULL, /* epp_read_block */
+
+       NULL, /* ecp_write_block */
+       NULL, /* ecp_read_block */
+
+       amiga_init_state,
+       amiga_save_state,
+       amiga_restore_state,
+
+       amiga_enable_irq,
+       amiga_disable_irq,
+       amiga_interrupt, 
+
+       amiga_inc_use_count,
+       amiga_dec_use_count,
+       amiga_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+       struct parport *p;
+
+       if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+               ciaa.ddrb = 0xff;
+               ciab.ddra &= 0xf8;
+               if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+                                       IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+                                       &pp_amiga_ops)))
+                       return 0;
+               this_port = p;
+               printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+               /* XXX: set operating mode */
+               parport_proc_register(p);
+               p->flags |= PARPORT_FLAG_COMA;
+
+               if (parport_probe_hook)
+                       (*parport_probe_hook)(p);
+               return 1;
+
+       }
+       return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
+MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+
+int init_module(void)
+{
+       return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+       if (!(this_port->flags & PARPORT_FLAG_COMA))
+               parport_quiesce(this_port);
+       parport_proc_unregister(this_port);
+       parport_unregister_port(this_port);
+}
+#endif
+
+
diff --git a/drivers/misc/parport_atari.c b/drivers/misc/parport_atari.c
new file mode 100644 (file)
index 0000000..8f28b18
--- /dev/null
@@ -0,0 +1,263 @@
+/* Low-level parallel port routines for the Atari builtin port
+ *
+ * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ *
+ * Based on parport_amiga.c.
+ *
+ * The built-in Atari parallel port provides one port at a fixed address
+ * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
+ * and 1 input status line (BUSY) able to cause an interrupt.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/atariints.h>
+
+static struct parport *this_port = NULL;
+
+static unsigned char
+parport_atari_read_data(struct parport *p)
+{
+       unsigned long flags;
+       unsigned char data;
+
+       save_flags(flags);
+       cli();
+       sound_ym.rd_data_reg_sel = 15;
+       data = sound_ym.rd_data_reg_sel;
+       restore_flags(flags);
+       return data;
+}
+
+static void
+parport_atari_write_data(struct parport *p, unsigned char data)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       sound_ym.rd_data_reg_sel = 15;
+       sound_ym.wd_data = data;
+       restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_read_control(struct parport *p)
+{
+       unsigned long flags;
+       unsigned char control = 0;
+
+       save_flags(flags);
+       cli();
+       sound_ym.rd_data_reg_sel = 14;
+       if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
+               control = PARPORT_CONTROL_STROBE;
+       restore_flags(flags);
+       return control;
+}
+
+static void
+parport_atari_write_control(struct parport *p, unsigned char control)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       sound_ym.rd_data_reg_sel = 14;
+       if (control & PARPORT_CONTROL_STROBE)
+               sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+       else
+               sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+       restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_frob_control(struct parport *p, unsigned char mask,
+                          unsigned char val)
+{
+       unsigned char old = parport_atari_read_control(p);
+       parport_atari_write_control(p, (old & ~mask) ^ val);
+       return old;
+}
+
+static unsigned char
+parport_atari_read_status(struct parport *p)
+{
+       return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+               PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
+}
+
+static void
+parport_atari_write_status(struct parport *p, unsigned char status)
+{
+}
+
+static void
+parport_atari_init_state(struct parport_state *s)
+{
+}
+
+static void
+parport_atari_save_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_restore_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void
+parport_atari_release_resources(struct parport *p)
+{
+       if (p->irq != PARPORT_IRQ_NONE)
+               free_irq(IRQ_MFP_BUSY, p);
+}
+
+static int
+parport_atari_claim_resources(struct parport *p)
+{
+       return request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+                          IRQ_TYPE_SLOW, p->name, p);
+}
+
+static void
+parport_atari_inc_use_count(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void
+parport_atari_dec_use_count(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static void
+parport_atari_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_atari_ops = {
+       parport_atari_write_data,
+       parport_atari_read_data,
+
+       parport_atari_write_control,
+       parport_atari_read_control,
+       parport_atari_frob_control,
+
+       NULL, /* write_econtrol */
+       NULL, /* read_econtrol */
+       NULL, /* frob_econtrol */
+
+       parport_atari_write_status,
+       parport_atari_read_status,
+
+       NULL, /* write fifo */
+       NULL, /* read fifo */
+
+       NULL, /* change_mode */
+
+       parport_atari_release_resources,
+       parport_atari_claim_resources,
+
+       NULL, /* epp_write_data */
+       NULL, /* epp_read_data */
+       NULL, /* epp_write_addr */
+       NULL, /* epp_read_addr */
+       NULL, /* epp_check_timeout */
+
+       NULL, /* epp_write_block */
+       NULL, /* epp_read_block */
+
+       NULL, /* ecp_write_block */
+       NULL, /* ecp_read_block */
+
+       parport_atari_init_state,
+       parport_atari_save_state,
+       parport_atari_restore_state,
+
+       NULL, /* enable_irq */
+       NULL, /* disable_irq */
+       parport_atari_interrupt,
+
+       parport_atari_inc_use_count,
+       parport_atari_dec_use_count,
+       parport_atari_fill_inode
+};
+
+
+int __init
+parport_atari_init(void)
+{
+       struct parport *p;
+       unsigned long flags;
+
+       if (MACH_IS_ATARI) {
+               save_flags(flags);
+               cli();
+               /* Soundchip port A/B as output. */
+               sound_ym.rd_data_reg_sel = 7;
+               sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+               /* STROBE high. */
+               sound_ym.rd_data_reg_sel = 14;
+               sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+               restore_flags(flags);
+               /* MFP port I0 as input. */
+               mfp.data_dir &= ~1;
+               /* MFP port I0 interrupt on high->low edge. */
+               mfp.active_edge &= ~1;
+               p = parport_register_port((unsigned long)&sound_ym.wd_data,
+                                         IRQ_MFP_BUSY, PARPORT_DMA_NONE,
+                                         &parport_atari_ops);
+               if (!p)
+                       return 0;
+               this_port = p;
+               printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
+               parport_proc_register(p);
+               p->flags |= PARPORT_FLAG_COMA;
+
+               if (parport_probe_hook)
+                       (*parport_probe_hook)(p);
+               return 1;
+       }
+       return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Andreas Schwab");
+MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
+MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+
+int
+init_module(void)
+{
+       return parport_atari_init() ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+       if (!(this_port->flags & PARPORT_FLAG_COMA))
+               parport_quiesce(this_port);
+       parport_proc_unregister(this_port);
+       parport_unregister_port(this_port);
+}
+#endif
index 473c1b224683a86565208e9d686529d6e1dd4680..a3d8ee022a8f5a33c61315d69d3a60a5baddb023 100644 (file)
@@ -125,6 +125,15 @@ __initfunc(int parport_init(void))
 #endif
 #ifdef CONFIG_PARPORT_AX
        parport_ax_init();
+#endif
+#ifdef CONFIG_PARPORT_AMIGA
+       parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+       parport_mfc3_init();
+#endif
+#ifdef CONFIG_PARPORT_ATARI
+       parport_atari_init();
 #endif
        return 0;
 }
diff --git a/drivers/misc/parport_mfc3.c b/drivers/misc/parport_mfc3.c
new file mode 100644 (file)
index 0000000..8522066
--- /dev/null
@@ -0,0 +1,420 @@
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ * 
+ * Miscellaneous PIA Details
+ * -------------------------
+ * 
+ *     The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ * 
+ *     The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ * 
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ * 
+ *     The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ * 
+ * 
+ *    Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ *     19 | CB2 | --> | /STROBE (aka /DRDY)
+ *  10-17 | PBx | <-> | DATA0 - DATA7
+ *     18 | CB1 | <-- | /ACK
+ *     40 | CA1 | <-- | BUSY
+ *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ *      4 | PA2 | <-- | SELECTED (aka SEL)
+ *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ *      6 | PA4 | <-- | /ERROR (aka /FAULT)
+ *      7 | PA5 | --> | DIR (aka /SELECT-IN)
+ *      8 | PA6 | --> | /AUTO-FEED-XT
+ *     39 | CA2 | --> | open
+ *      5 | PA3 | <-- | /ACK (same as CB1!)
+ *      2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ * 
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+       dummy = pia(p)->pprb; /* clears irq bit */
+       /* Triggers also /STROBE.*/
+       pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+       /* clears interupt bit. Triggers also /STROBE. */
+       return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+       unsigned char ret = 32|64;
+
+       if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+               ;
+       if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+               ;
+       if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+               ret &= ~32; /* /SELECT_IN */
+       if (control & PARPORT_CONTROL_INIT) /* INITP */
+               ret |= 128;
+       if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+               ret &= ~64;
+       if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+               /* Handled directly by hardware */;
+       return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+       unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE 
+                         | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+       if (control & 128) /* /INITP */
+               ret |= PARPORT_CONTROL_INIT;
+       if (control & 64) /* /AUTOLF */
+               ret &= ~PARPORT_CONTROL_AUTOFD;
+       if (control & 32) /* /SELECT_IN */
+               ret &= ~PARPORT_CONTROL_SELECT;
+       return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+       pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+       
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+       return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+       unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+       old = mfc3_read_control(p);
+       mfc3_write_control(p, (old & ~mask) ^ val);
+       return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+       unsigned char ret = 1;
+
+       if (status & PARPORT_STATUS_BUSY) /* Busy */
+               ret &= ~1;
+       if (status & PARPORT_STATUS_ACK) /* Ack */
+               ret |= 8;
+       if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+               ret |= 2;
+       if (status & PARPORT_STATUS_SELECT) /* select */
+               ret |= 4;
+       if (status & PARPORT_STATUS_ERROR) /* error */
+               ret |= 16;
+       return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+       unsigned char ret = PARPORT_STATUS_BUSY;
+
+       if (status & 1) /* Busy */
+               ret &= ~PARPORT_STATUS_BUSY;
+       if (status & 2) /* PaperOut */
+               ret |= PARPORT_STATUS_PAPEROUT;
+       if (status & 4) /* Selected */
+               ret |= PARPORT_STATUS_SELECT;
+       if (status & 8) /* Ack */
+               ret |= PARPORT_STATUS_ACK;
+       if (status & 16) /* /ERROR */
+               ret |= PARPORT_STATUS_ERROR;
+
+       return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+       pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+       unsigned char status;
+
+       status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+       return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+       /* XXX: This port only has one mode, and I am
+       not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int i;
+
+       for( i = 0; i < MAX_MFC; i++)
+               if (this_port[i] != NULL)
+                       if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+                               dummy = pia(this_port[i])->pprb; /* clear irq bit */
+                               parport_generic_irq(irq, this_port[i], regs);
+                       }
+}
+
+static void mfc3_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+       if (p->irq != PARPORT_IRQ_NONE) 
+               if (--use_cnt == 0) 
+                       free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+       if (p->irq != PARPORT_IRQ_NONE)
+               if (use_cnt++ == 0)
+                       if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+                                return use_cnt--;
+       return 0;
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+       s->u.amiga.data = 0;
+       s->u.amiga.datadir = 255;
+       s->u.amiga.status = 0;
+       s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+       s->u.amiga.data = pia(p)->pprb;
+       pia(p)->crb &= ~PIA_DDR;
+       s->u.amiga.datadir = pia(p)->pddrb;
+       pia(p)->crb |= PIA_DDR;
+       s->u.amiga.status = pia(p)->ppra;
+       pia(p)->cra &= ~PIA_DDR;
+       s->u.amiga.statusdir = pia(p)->pddrb;
+       pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+       pia(p)->pprb = s->u.amiga.data;
+       pia(p)->crb &= ~PIA_DDR;
+       pia(p)->pddrb = s->u.amiga.datadir;
+       pia(p)->crb |= PIA_DDR;
+       pia(p)->ppra = s->u.amiga.status;
+       pia(p)->cra &= ~PIA_DDR;
+       pia(p)->pddrb = s->u.amiga.statusdir;
+       pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+       pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+       pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static void mfc3_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_mfc3_ops = {
+       mfc3_write_data,
+       mfc3_read_data,
+
+       mfc3_write_control,
+       mfc3_read_control,
+       mfc3_frob_control,
+
+       NULL, /* write_econtrol */
+       NULL, /* read_econtrol */
+       NULL, /* frob_econtrol */
+
+       mfc3_write_status,
+       mfc3_read_status,
+
+       NULL, /* write fifo */
+       NULL, /* read fifo */
+
+       mfc3_change_mode,
+
+
+       mfc3_release_resources,
+       mfc3_claim_resources,
+
+
+       NULL, /* epp_write_data */
+       NULL, /* epp_read_data */
+       NULL, /* epp_write_addr */
+       NULL, /* epp_read_addr */
+       NULL, /* epp_check_timeout */
+
+       NULL, /* epp_write_block */
+       NULL, /* epp_read_block */
+
+       NULL, /* ecp_write_block */
+       NULL, /* ecp_read_block */
+
+       mfc3_init_state,
+       mfc3_save_state,
+       mfc3_restore_state,
+
+       mfc3_enable_irq,
+       mfc3_disable_irq,
+       mfc3_interrupt,
+
+       mfc3_inc_use_count,
+       mfc3_dec_use_count,
+       mfc3_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+       struct parport *p;
+       int pias = 0;
+       struct pia *pp;
+       unsigned int key = 0;
+       const struct ConfigDev *cd;
+
+       if (MACH_IS_AMIGA) {
+               while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+                       cd = zorro_get_board(key);
+                       pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+                       if (pias < MAX_MFC) {
+                               pp->crb = 0;
+                               pp->pddrb = 255; /* all data pins output */
+                               pp->crb = PIA_DDR|32|8;
+                               dummy = pp->pddrb; /* reading clears interrupt */
+                               pp->cra = 0;
+                               pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
+                               pp->cra = PIA_DDR;
+                               pp->ppra = 0; /* reset printer */
+                               udelay(10);
+                               pp->ppra = 128;
+                               if ((p = parport_register_port((unsigned long)pp,
+                                       IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+                                       &pp_mfc3_ops))) {
+                                       this_port[pias++] = p;
+                                       printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+                                       /* XXX: set operating mode */
+                                       parport_proc_register(p);
+                                       p->flags |= PARPORT_FLAG_COMA;
+                                       if (parport_probe_hook)
+                                               (*parport_probe_hook)(p);
+                                       zorro_config_board(key, 0);
+                                       p->private_data = (void *)key;
+                               }
+                       }
+               }
+       }
+       return pias;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
+MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+
+int init_module(void)
+{
+       return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_MFC; i++)
+               if (this_port[i] != NULL) {
+                       if (!(this_port[i]->flags & PARPORT_FLAG_COMA))
+                               parport_quiesce(this_port[i]);
+                       parport_proc_unregister(this_port[i]);
+                       parport_unregister_port(this_port[i]);
+                       zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+               }
+}
+#endif
+
+
index 9cffbb0b98d4e4697691839b0fe0dec860e8f1a4..9e40adc74235f5bddb19115137272e51c3b4409b 100644 (file)
@@ -1028,4 +1028,4 @@ struct de4x5_ioctl {
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
-#define MOTO_SROM_BUG    ((lp->active == 8) && ((*((s32 *)le32_to_cpu(get_unaligned(dev->dev_addr)))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
index 7e98d50e23cb032c1bef07bcf0be95ab6c5c6d6a..cc478fb2e9a0d2d4f91c88746d980cfab7dab0cb 100644 (file)
@@ -98,7 +98,6 @@ __initfunc(int ethertap_probe(struct device *dev))
 
        ether_setup(dev);
 
-       dev->hard_header_len = 16;
        dev->tx_queue_len = 0;
        dev->flags|=IFF_NOARP;
        tap_map[dev->base_addr]=dev;
@@ -178,11 +177,21 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev)
 #endif
 
        if (skb_headroom(skb) < 2) {
-               printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name);
+               static int once;
+               struct sk_buff *skb2;
+
+               if (!once) {
+                       once = 1;
+                       printk(KERN_DEBUG "%s: not aligned xmit by protocol %04x\n", dev->name, skb->protocol);
+               }
+
+               skb2 = skb_realloc_headroom(skb, 2);
                dev_kfree_skb(skb);
-               return 0;
+               if (skb2 == NULL)
+                       return 0;
+               skb = skb2;
        }
-       skb_push(skb, 2);
+       __skb_push(skb, 2);
 
        /* Make the same thing, which loopback does. */
        if (skb_shared(skb)) {
index b46ea12b7b9c2f9a32babdc338114ff3fed04b3a..0691956286ddf5b817b992c438ffaca42a855837 100644 (file)
@@ -4,7 +4,7 @@
  *  Al Longyear <longyear@netcom.com>
  *  Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
  *
- *  ==FILEVERSION 990331==
+ *  ==FILEVERSION 990510==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -90,9 +90,6 @@
 #include <linux/kmod.h>
 #endif
 
-typedef ssize_t                rw_ret_t;
-typedef size_t         rw_count_t;
-
 /*
  * Local functions
  */
@@ -109,6 +106,7 @@ static int ppp_tty_push(struct ppp *ppp);
 static int ppp_async_encode(struct ppp *ppp);
 static int ppp_async_send(struct ppp *, struct sk_buff *);
 static int ppp_sync_send(struct ppp *, struct sk_buff *);
+static void ppp_tty_flush_output(struct ppp *);
 
 static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
 static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
@@ -191,10 +189,10 @@ EXPORT_SYMBOL(ppp_unregister_compressor);
  * TTY callbacks
  */
 
-static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
-                            rw_count_t);
-static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
-                             rw_count_t);
+static ssize_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+                           size_t);
+static ssize_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+                            size_t);
 static int ppp_tty_ioctl(struct tty_struct *, struct file *, unsigned int,
                         unsigned long);
 static unsigned int ppp_tty_poll(struct tty_struct *tty, struct file *filp,
@@ -446,6 +444,7 @@ ppp_tty_close (struct tty_struct *tty)
                ppp->tty = ppp->backup_tty;
                if (ppp_tty_push(ppp))
                        ppp_output_wakeup(ppp);
+               wake_up_interruptible(&ppp->read_wait);
        } else {
                ppp->tty = 0;
                ppp->sc_xfer = 0;
@@ -463,13 +462,13 @@ ppp_tty_close (struct tty_struct *tty)
  * Read a PPP frame from the rcv_q list,
  * waiting if necessary
  */
-static rw_ret_t
+static ssize_t
 ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
-            rw_count_t nr)
+            size_t nr)
 {
        struct ppp *ppp = tty2ppp (tty);
        struct sk_buff *skb;
-       rw_ret_t len, err;
+       ssize_t len, err;
 
        /*
         * Validate the pointers
@@ -551,9 +550,9 @@ out:
  * Writing to a tty in ppp line discipline sends a PPP frame.
  * Used by pppd to send control packets (LCP, etc.).
  */
-static rw_ret_t
+static ssize_t
 ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
-             rw_count_t count)
+             size_t count)
 {
        struct ppp *ppp = tty2ppp (tty);
        __u8 *new_data;
@@ -605,7 +604,7 @@ ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
         */
        ppp_send_ctrl(ppp, skb);
 
-       return (rw_ret_t) count;
+       return (ssize_t) count;
 }
 
 /*
@@ -724,6 +723,21 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                error = n_tty_ioctl (tty, file, param2, param3);
                break;
 
+       case TCFLSH:
+               /*
+                * Flush our buffers, then call the generic code to
+                * flush the serial port's buffer.
+                */
+               if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {
+                       struct sk_buff *skb;
+                       while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+                               kfree_skb(skb);
+               }
+               if (param3 == TCIOFLUSH || param3 == TCOFLUSH)
+                       ppp_tty_flush_output(ppp);
+               error = n_tty_ioctl (tty, file, param2, param3);
+               break;
+
        case FIONREAD:
                /*
                 * Returns how many bytes are available for a read().
@@ -882,7 +896,7 @@ ppp_tty_sync_push(struct ppp *ppp)
        save_flags(flags);
        cli();
        if (ppp->tty_pushing) {
-               /* record wakeup attempt so we don't loose */
+               /* record wakeup attempt so we don't lose */
                /* a wakeup call while doing push processing */
                ppp->woke_up=1;
                restore_flags(flags);
@@ -965,16 +979,20 @@ ppp_tty_push(struct ppp *ppp)
        int avail, sent, done = 0;
        struct tty_struct *tty = ppp2tty(ppp);
        
-       if ( ppp->flags & SC_SYNC 
+       if (ppp->flags & SC_SYNC
                return ppp_tty_sync_push(ppp);
 
        CHECK_PPP(0);
-       if (ppp->tty_pushing)
+       if (ppp->tty_pushing) {
+               ppp->woke_up = 1;
                return 0;
+       }
        if (tty == NULL || tty->disc_data != (void *) ppp)
                goto flush;
        while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
                ppp->tty_pushing = 1;
+               mb();
+               ppp->woke_up = 0;
                avail = ppp->olim - ppp->optr;
                if (avail > 0) {
                        tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
@@ -984,18 +1002,24 @@ ppp_tty_push(struct ppp *ppp)
                        ppp->stats.ppp_obytes += sent;
                        ppp->optr += sent;
                        if (sent < avail) {
+                               wmb();
                                ppp->tty_pushing = 0;
+                               mb();
+                               if (ppp->woke_up)
+                                       continue;
                                return done;
                        }
                }
                if (ppp->tpkt != 0)
                        done = ppp_async_encode(ppp);
+               wmb();
                ppp->tty_pushing = 0;
        }
        return done;
 
 flush:
        ppp->tty_pushing = 1;
+       mb();
        ppp->stats.ppp_oerrors++;
        if (ppp->tpkt != 0) {
                kfree_skb(ppp->tpkt);
@@ -1003,6 +1027,7 @@ flush:
                done = 1;
        }
        ppp->optr = ppp->olim;
+       wmb();
        ppp->tty_pushing = 0;
        return done;
 }
@@ -1116,6 +1141,32 @@ ppp_async_encode(struct ppp *ppp)
        return 0;
 }
 
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_tty_flush_output(struct ppp *ppp)
+{
+       struct sk_buff *skb;
+       int done = 0;
+
+       while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+               kfree_skb(skb);
+       ppp->tty_pushing = 1;
+       mb();
+       ppp->optr = ppp->olim;
+       if (ppp->tpkt != NULL) {
+               kfree_skb(ppp->tpkt);
+               ppp->tpkt = 0;
+               done = 1;
+       }
+       wmb();
+       ppp->tty_pushing = 0;
+       if (done)
+               ppp_output_wakeup(ppp);
+}
+
 /*
  * Callback function from tty driver. Return the amount of space left
  * in the receiver's buffer to decide if remote transmitter is to be
index b73740922ac8f53dcde041e1f0efe8bde0ab6547..ef19f74b9d565554998a929d13cf6f5d6e979a39 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.26 1999/04/28 11:55:42 davem Exp $
+/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -276,6 +276,7 @@ int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
                prev_scancode = 0;
                return 0;
        }
+       scancode &= 0x7f;
        if(prev_scancode) {
                if(prev_scancode != 0xe0) {
                        if(prev_scancode == 0xe1 && scancode == 0x1d) {
index ea9e550180404961128a3d3c399f0574977c1e98..6cd211b2270cfe372af54e28a7cf6da414a2a044 100644 (file)
@@ -2,14 +2,16 @@ Credits for the Simple Linux USB Driver:
 
 The following people have contributed to this code (in alphabetical
 order by last name).  I'm sure this list should be longer, its
-difficult to maintain.
+difficult to maintain, add yourself with a patch if desired.
 
+  Alan Cox <alan@lxorguk.ukuu.org.uk>
   Johannes Erdfelt <jerdfelt@sventech.com>
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Vojtech Pavlik <vojtech@twilight.ucw.cz>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
+  Roman Weissgaerber <weissg@vienna.at>
   <Kazuki.Yasumatsu@fujixerox.co.jp>
 
 Special thanks to:
@@ -21,3 +23,132 @@ Special thanks to:
   The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
   and offering suggestions and sharing implementation experiences.
 
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+        The following corporations have helped us in the development
+of Linux USB / UUSBD:
+
+        - USAR Systems provided us with one of their excellent USB
+          Evaluation Kits. It allows us to test the Linux-USB driver
+          for compilance with the latest USB specification. USAR
+          Systems recognized the importance of an up-to-date open
+          Operating System and supports this project with
+          Hardware. Thanks!.
+
+        - Thanks to Intel Corporation for their precious help.
+
+        - We teamed up with Cherry to make Linux the first OS with
+          built-in USB support. Cherry is one of the biggest keyboard
+          makers in the world.
+
+        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+          PCI-to-USB Controller Board to test the OHCI implementation.
+
+        - Due to their support to us, Keytronic can be sure that they
+          will sell keyboards to some of the 3 million (at least)
+          Linux users.
+
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+          It was almost imposible to get a PC backplate USB connector
+          for the motherboard here at Europe (mine, home-made, was
+          quite lowsy :). Now I know where to adquire nice USB stuff!
+
+        - Genius Germany donated a USB mouse to test the mouse boot
+          protocol. They've also donated a F-23 digital joystick and a
+          NetMouse Pro. Thanks! 
+
+        - AVM GmbH Berlin is supporting the development of the Linux
+          USB driver for the AVM ISDN Controller B1 USB. AVM is a
+          leading manufacturer for active and passive ISDN Controllers
+          and CAPI 2.0-based software. The active design of the AVM B1
+          is open for all OS platforms, including Linux.
+
+        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+          USB Floppy Disk Drive, so we could test the bulk transfer
+          code.
+
+        - Many thanks to Logitech for contributing a three axis USB
+          mouse. 
+
+          Logitech designs, manufactures and markets
+          Human Interface Devices, having a long history and
+          experience in making devices such as keyboards, mice,
+          trackballs, cameras, loudspeakers and control devices for
+          gaming and professional use.
+
+          Being a recognized vendor and seller for all these devices,
+          they have donated USB mice, a joystick and a scanner, as a
+          way to acknowledge the importance of Linux and to allow
+          Logitech customers to enjoy support in their favorite
+          operating systems and all Linux users to use Logitech and
+          other USB hardware.
+
+          Logitech is official sponsor of the Linux Conference on
+          Feb. 11th 1999 in Vienna, where we'll will present the
+          current state of the Linux USB effort.
+
+        - CATC has provided means to uncover dark corners of the UHCI
+          inner workings with a USB Inspector.
+
+        - Thanks to Entrega for providing PCI to USB cards, hubs and
+          converter products for development. 
+
+
+        And thanks go to (hey! in no particular order :)
+
+        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
+          all my doubts'bout USB and giving lots of cool ideas.
+
+        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
+          pointing out mortal bugs and giving advice.
+
+        - Edmund Humemberger <ed@atnet.at>, for it's great work on
+          public relationships and general management stuff for the
+          Linux-USB effort.
+
+        - Alberto Menegazzi <flash@flash.iol.it> is starting the
+          documentation for the UUSBD. Go for it!
+
+        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
+          introductory documents (compiting with Alberto's :).
+
+        - Christian Groessler <cpg@aladdin.de>, for it's help on those
+          itchy bits ... :)
+
+        - Paul MacKerras for polishing OHCI and pushing me harder for
+          the iMac support, giving improvements and enhancements.
+
+        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
+          charge of composing, maintaining and feeding the
+          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
+          pointed bugs, as well as started the uusbd-utils package.
+
+        - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+          crazy, as well as making cool suggestions, great :)
+
+        - All the Free Software and Linux community, the FSF & the GNU
+          project, the MIT X consortium, the TeX people ... everyone!
+          You know who you are!
+
+        - Big thanks to Richard Stallman for creating Emacs!
+
+        - The people at the linux-usb mailing list, for reading so
+          many messages :) Ok, no more kidding; for all your advices!
+
+        - All the people at the USB Implementors Forum for their
+          help and assistance.
+
+        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
+          liked Cibeles' party).
+
+        - Linus Torvalds, for starting, developing and managing Linux.
+
+        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+          for convincing me USB Standard hubs are not that standard
+          and that's good to allow for vendor specific quirks on the
+          standard hub driver.
+
index 6a3744847669f653a652cfbec4e2865fc90245c7..7a544eb3353a93526d6482d004f84c849e66d1d9 100644 (file)
@@ -1,8 +1,26 @@
-April 24, 1999 04:37:42 PST
+May 09, 1999 16:25:58
 
-Okay, I've written a lot more of the OHCI code and actually got it back to
-a compiling state now with all of the recent improvements to the way stuff
-is structured.  It is completely untested.
+Cool, things are working "well" now.  (I'm not getting oops's from the
+OHCI code anyways.. ;).  I can attach a usb hub and mouse in any
+possible arrangement of the two and they get configured properly.
+
+You can see that the mouse Interrupt transfers are occuring and being
+acknowledged because /proc/interrupts usb-ohci goes up accordingly with
+mouse movements/events.  That means the TD at least returns some data
+and requeues itself.
+
+Device attach/detach from the root hub is not working well.  Currently
+every interrupt checks for root hub status changes and frame number
+overflow interrupts are enabled.  This means you shouldn't have to
+wait more than 32-33 seconds for the change to occur, less if there is
+other activity.  (due to checking in the WDH caused interrupts)
+My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
+with the RHSC interrupt so it has been disabled.  The ohci_timer
+should be polling but it not currently working, I haven't had time to
+look into that problem.
+
+However, when I tried telling X to use /dev/psaux for the mouse my
+machine locked up...
 
 - greg@electricrain.com
 
index 5f90bbe7260e7c12020f73e139098a7fbb42b2a2..1510bb9da44156b43aef611040dc867b69285309 100644 (file)
@@ -14,40 +14,58 @@ void show_ohci_status(struct ohci *ohci)
        struct ohci_regs regs;
        int i;
 
-       regs.revision = readl(ohci->regs->revision);
-       regs.control = readl(ohci->regs->control);
-       regs.cmdstatus = readl(ohci->regs->cmdstatus);
-       regs.intrstatus = readl(ohci->regs->intrstatus);
-       regs.intrenable = readl(ohci->regs->intrenable);
-       regs.intrdisable = readl(ohci->regs->intrdisable);
-       regs.hcca = readl(ohci->regs->hcca);
-       regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent);
-       regs.ed_controlhead = readl(ohci->regs->ed_controlhead);
-       regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead);
-       regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent);
-       regs.current_donehead = readl(ohci->regs->current_donehead);
-       regs.fminterval = readl(ohci->regs->fminterval);
-       regs.fmremaining = readl(ohci->regs->fmremaining);
-       regs.fmnumber = readl(ohci->regs->fmnumber);
-       regs.periodicstart = readl(ohci->regs->periodicstart);
-       regs.lsthresh = readl(ohci->regs->lsthresh);
-       regs.roothub.a = readl(ohci->regs->roothub.a);
-       regs.roothub.b = readl(ohci->regs->roothub.b);
-       regs.roothub.status = readl(ohci->regs->roothub.status);
+       regs.revision = readl(&ohci->regs->revision);
+       regs.control = readl(&ohci->regs->control);
+       regs.cmdstatus = readl(&ohci->regs->cmdstatus);
+       regs.intrstatus = readl(&ohci->regs->intrstatus);
+       regs.intrenable = readl(&ohci->regs->intrenable);
+       regs.hcca = readl(&ohci->regs->hcca);
+       regs.ed_periodcurrent = readl(&ohci->regs->ed_periodcurrent);
+       regs.ed_controlhead = readl(&ohci->regs->ed_controlhead);
+       regs.ed_controlcurrent = readl(&ohci->regs->ed_controlcurrent);
+       regs.ed_bulkhead = readl(&ohci->regs->ed_bulkhead);
+       regs.ed_bulkcurrent = readl(&ohci->regs->ed_bulkcurrent);
+       regs.current_donehead = readl(&ohci->regs->current_donehead);
+       regs.fminterval = readl(&ohci->regs->fminterval);
+       regs.fmremaining = readl(&ohci->regs->fmremaining);
+       regs.fmnumber = readl(&ohci->regs->fmnumber);
+       regs.periodicstart = readl(&ohci->regs->periodicstart);
+       regs.lsthresh = readl(&ohci->regs->lsthresh);
+       regs.roothub.a = readl(&ohci->regs->roothub.a);
+       regs.roothub.b = readl(&ohci->regs->roothub.b);
+       regs.roothub.status = readl(&ohci->regs->roothub.status);
        for (i=0; i<MAX_ROOT_PORTS; ++i)
-               regs.roothub.portstatus[i] = readl(ohci->regs->roothub.portstatus[i]);
-
-       printk("  ohci revision    =  0x%x\n", regs.revision);
-       printk("  ohci control     =  0x%x\n", regs.control);
-       printk("  ohci cmdstatus   =  0x%x\n", regs.cmdstatus);
-       printk("  ohci intrstatus  =  0x%x\n", regs.intrstatus);
-       printk("  ohci roothub.a   =  0x%x\n", regs.roothub.a);
-       printk("  ohci roothub.b   =  0x%x\n", regs.roothub.b);
-       printk("  ohci root status =  0x%x\n", regs.roothub.status);
+               regs.roothub.portstatus[i] = readl(&ohci->regs->roothub.portstatus[i]);
+
+       printk(KERN_DEBUG "  ohci revision    =  %x\n", regs.revision);
+       printk(KERN_DEBUG "  ohci control     =  %x\n", regs.control);
+       printk(KERN_DEBUG "  ohci cmdstatus   =  %x\n", regs.cmdstatus);
+       printk(KERN_DEBUG "  ohci intrstatus  =  %x\n", regs.intrstatus);
+       printk(KERN_DEBUG "  ohci intrenable  =  %x\n", regs.intrenable);
+
+       printk(KERN_DEBUG "  ohci hcca        =  %x\n", regs.hcca);
+       printk(KERN_DEBUG "  ohci ed_pdcur    =  %x\n", regs.ed_periodcurrent);
+       printk(KERN_DEBUG "  ohci ed_ctrlhead =  %x\n", regs.ed_controlhead);
+       printk(KERN_DEBUG "  ohci ed_ctrlcur  =  %x\n", regs.ed_controlcurrent);
+       printk(KERN_DEBUG "  ohci ed_bulkhead =  %x\n", regs.ed_bulkhead);
+       printk(KERN_DEBUG "  ohci ed_bulkcur  =  %x\n", regs.ed_bulkcurrent);
+       printk(KERN_DEBUG "  ohci curdonehead =  %x\n", regs.current_donehead);
+
+       printk(KERN_DEBUG "  ohci fminterval  =  %x\n", regs.fminterval);
+       printk(KERN_DEBUG "  ohci fmremaining =  %x\n", regs.fmremaining);
+       printk(KERN_DEBUG "  ohci fmnumber    =  %x\n", regs.fmnumber);
+       printk(KERN_DEBUG "  ohci pdstart     =  %x\n", regs.periodicstart);
+       printk(KERN_DEBUG "  ohci lsthresh    =  %x\n", regs.lsthresh);
+
+       printk(KERN_DEBUG "  ohci roothub.a   =  %x\n", regs.roothub.a);
+       printk(KERN_DEBUG "  ohci roothub.b   =  %x\n", regs.roothub.b);
+       printk(KERN_DEBUG "  ohci root status =  %x\n", regs.roothub.status);
+       printk(KERN_DEBUG "    roothub.port0  =  %x\n", regs.roothub.portstatus[0]);
+       printk(KERN_DEBUG "    roothub.port1  =  %x\n", regs.roothub.portstatus[1]);
 } /* show_ohci_status() */
 
 
-static void show_ohci_ed(struct ohci_ed *ed)
+void show_ohci_ed(struct ohci_ed *ed)
 {
        int stat = ed->status;
        int skip = (stat & OHCI_ED_SKIP);
@@ -57,83 +75,104 @@ static void show_ohci_ed(struct ohci_ed *ed)
        int dir = (stat & OHCI_ED_D);
        int endnum = (stat & OHCI_ED_EN) >> 7;
        int funcaddr = (stat & OHCI_ED_FA);
-       int halted = (ed->head_td & 1);
-       int toggle = (ed->head_td & 2) >> 1;
+       int halted = (ed->_head_td & 1);
+       int toggle = (ed->_head_td & 2) >> 1;
 
-       printk("   ohci ED:\n");
-       printk("     status     =  0x%x\n", stat);
-       printk("       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+       printk(KERN_DEBUG "   ohci ED:\n");
+       printk(KERN_DEBUG "     status     =  0x%x\n", stat);
+       printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
                        skip ? "Skip " : "",
                        mps,
                        isoc ? "Isoc. " : "",
-                       low_speed ? "LowSpd " : "",
-                       (dir == OHCI_ED_D_IN) ? "Input " :
-                       (dir == OHCI_ED_D_OUT) ? "Output " : "",
-                       halted ? "Halted " : "",
+                       low_speed ? " LowSpd" : "",
+                       (dir == OHCI_ED_D_IN) ? " Input" :
+                       (dir == OHCI_ED_D_OUT) ? " Output" : "",
+                       halted ? " Halted" : "",
                        toggle,
                        endnum,
                        funcaddr);
-       printk("     tail_td    =  0x%x\n", ed->tail_td);
-       printk("     head_td    =  0x%x\n", ed->head_td);
-       printk("     next_ed    =  0x%x\n", ed->next_ed);
+       printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
+       printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
+       printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
 } /* show_ohci_ed() */
 
 
-static void show_ohci_td(struct ohci_td *td)
+void show_ohci_td(struct ohci_td *td)
 {
        int td_round = td->info & OHCI_TD_ROUND;
        int td_dir = td->info & OHCI_TD_D;
-       int td_int_delay = td->info & OHCI_TD_IOC_DELAY;
-       int td_toggle = td->info & OHCI_TD_DT;
-       int td_errcnt = td_errorcount(td->info);
-       int td_cc = td->info & OHCI_TD_CC;
-
-       printk("   ohci TD hardware fields:\n");
-       printk("      info     =  0x%x\n", td->info);
-       printk("        %s%s%s%d%s%s%d%s%d\n",
+       int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21;
+       int td_toggle = (td->info & OHCI_TD_DT) >> 24;
+       int td_errcnt = td_errorcount(*td);
+       int td_cc = OHCI_TD_CC_GET(td->info);
+
+       printk(KERN_DEBUG "   ohci TD hardware fields:\n");
+       printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
+       printk(KERN_DEBUG "        %s%s%s%d %s\n",
                td_round ? "Rounding " : "",
                (td_dir == OHCI_TD_D_IN) ? "Input " :
                (td_dir == OHCI_TD_D_OUT) ? "Output " :
                (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
-               "IntDelay ", td_int_delay >> 21,
-               td_toggle ? "Data1 " : "Data0 ",
+               "IntDelay ", td_int_delay,
+               (td_toggle < 2) ? " " :
+               (td_toggle & 1) ? "Data1 " : "Data0 ");
+       printk(KERN_DEBUG "        %s%d %s0x%x, %sAccessed, %sActive\n",
                "ErrorCnt ", td_errcnt,
-               "ComplCode ", td_cc);
-       printk("       %sAccessed, %sActive\n",
-                       td_cc_accessed(td->info) ? "" : "Not ",
-                       td_active(td->info) ? "" : "Not ");
-
-       printk("      cur_buf  =  0x%x\n", td->cur_buf);
-       printk("      next_td  =  0x%x\n", td->next_td);
-       printk("      buf_end  =  0x%x\n", td->buf_end);
-       printk("   ohci TD driver fields:\n");
-       printk("      data     =  %p\n", td->data);
-       printk("      dev_id   =  %p\n", td->dev_id);
-       printk("      ed_bus   =  %x\n", td->ed_bus);
+               "ComplCode ", td_cc,
+               td_cc_accessed(*td) ? "" : "Not ",
+               td_active(*td) ? "" : "Not ");
+
+       printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
+       printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
+       printk(KERN_DEBUG "      buf_end  =  0x%x\n", td->buf_end);
+       printk(KERN_DEBUG "   ohci TD driver fields:\n");
+       printk(KERN_DEBUG "      data     =  %p\n", td->data);
+       printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
+       printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
+       if (td->data != NULL) {
+       unsigned char *d = td->data;
+       printk(KERN_DEBUG "   DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                       d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] );
+       }
 } /* show_ohci_td() */
 
 
 void show_ohci_device(struct ohci_device *dev)
 {
        int idx;
-       printk("  ohci_device usb       =  %p\n", dev->usb);
-       printk("  ohci_device ohci      =  %p\n", dev->ohci);
-       printk("  ohci_device ohci_hcca =  %p\n", dev->hcca);
-       for (idx=0; idx<8 /*NUM_EDS*/; ++idx) {
-               printk("   [ed num %d] ", idx);
+       printk(KERN_DEBUG "  ohci_device usb       =  %p\n", dev->usb);
+       printk(KERN_DEBUG "  ohci_device ohci      =  %p\n", dev->ohci);
+       printk(KERN_DEBUG "  ohci_device ohci_hcca =  %p\n", dev->hcca);
+       for (idx=0; idx<3 /*NUM_EDS*/; ++idx) {
+               printk(KERN_DEBUG "   [ed num %d] ", idx);
                show_ohci_ed(&dev->ed[idx]);
        }
-       for (idx=0; idx<8 /*NUM_TDS*/; ++idx) {
-               printk("   [td num %d] ", idx);
+       for (idx=0; idx<3 /*NUM_TDS*/; ++idx) {
+               printk(KERN_DEBUG "   [td num %d] ", idx);
                show_ohci_td(&dev->td[idx]);
        }
-       printk("  ohci_device data\n    ");
+       printk(KERN_DEBUG "  ohci_device data\n    ");
        for (idx=0; idx<4; ++idx) {
-               printk(" %08lx", dev->data[idx]);
+               printk(KERN_DEBUG " %08lx", dev->data[idx]);
        }
-       printk("\n");
+       printk(KERN_DEBUG "\n");
 } /* show_ohci_device() */
 
 
+void show_ohci_hcca(struct ohci_hcca *hcca)
+{
+       int idx;
+
+       printk(KERN_DEBUG "  ohci_hcca\n");
+
+       for (idx=0; idx<NUM_INTS; idx++) {
+               printk(KERN_DEBUG "    int_table[%2d]  == %p\n", idx, hcca->int_table +idx);
+       }
+
+       printk(KERN_DEBUG "    frame_no          == %d\n", hcca->frame_no);
+       printk(KERN_DEBUG "    donehead          == 0x%08x\n", hcca->donehead);
+} /* show_ohci_hcca() */
+
+
 /* vim:sw=8
  */
index 9ee863fcd9118745b92f624e87d86948ba3d126c..da3ef6657dc0e24a5c0ee667fd7c53a736198d71 100644 (file)
@@ -32,6 +32,7 @@
 /* #define OHCI_DBG  */  /* printk some debug information */
 
  
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
index cbcac83d3bc57a6e80c02ab0f8eb9df509336521..aa782bb1df7f05ee5c92905138ebb1f393ecbb99 100644 (file)
@@ -22,6 +22,8 @@
  * ohci-hcd.h
  */
 
+#include <linux/config.h>
+
 #ifdef CONFIG_USB_OHCI_VROOTHUB
 #define VROOTHUB  
 #endif
index 6207dcd9880906f35a41b2578f0598fe4c2f0bc1..b12d0114c6908c61e1f97e154cc1b050f7d987fe 100644 (file)
@@ -29,7 +29,7 @@
  *
  * No filesystems were harmed in the development of this code.
  *
- * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $
+ * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $
  */
 
 #include <linux/config.h>
@@ -59,6 +59,10 @@ static int apm_resume = 0;
 
 static struct wait_queue *ohci_configure = NULL;
 
+#ifdef OHCI_TIMER
+static struct timer_list ohci_timer;   /* timer for root hub polling */
+#endif
+
 
 static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
 {
@@ -69,86 +73,258 @@ static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
        /* TODO Debugging code for TD failures goes here */
 
        return status;
-}
+} /* ohci_td_result() */
 
 
 static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Add a TD to the end of the TD list on a given ED.  td->next_td is
- * assumed to be set correctly for the situation of no TDs already
- * being on the list (ie: pointing to NULL).
+ * Add a TD to the end of the TD list on a given ED.  If td->next_td
+ * points to any more TDs, they will be added as well (naturally).
+ * Otherwise td->next_td must be 0.
+ * 
+ * The SKIP flag will be cleared after this function.
+ *
+ * Important!  This function needs locking and atomicity as it works
+ * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
+ * the function is a must.
+ *
+ * This function can be called by the interrupt handler.
  */
 static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
-       struct ohci_td *tail = bus_to_virt(ed->tail_td);
-       struct ohci_td *head = bus_to_virt(ed->head_td);
-       unsigned long flags;
+       /* don't let the HC pull anything from underneath us */
+       ed->status |= OHCI_ED_SKIP;
 
-       spin_lock_irqsave(&ohci_edtd_lock, flags);
-
-       if (tail == head) {     /* empty list, put it on the head */
-               head = (struct ohci_td *) virt_to_bus(td);
-               tail = 0;
+       if (ed_head_td(ed) == 0) {      /* empty list, put it on the head */
+               set_ed_head_td(ed, virt_to_bus(td));
+               ed->tail_td = 0;
        } else {
+               struct ohci_td *tail, *head;
+               head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed));
+               tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td);
                if (!tail) {    /* no tail, single element list */
                        td->next_td = head->next_td;
                        head->next_td = virt_to_bus(td);
-                       tail = (struct ohci_td *) virt_to_bus(td);
+                       ed->tail_td = virt_to_bus(td);
                } else {        /* append to the list */
                        td->next_td = tail->next_td;
                        tail->next_td = virt_to_bus(td);
-                       tail = (struct ohci_td *) virt_to_bus(td);
+                       ed->tail_td = virt_to_bus(td);
                }
        }
-       /* save the reverse link */
-       td->ed_bus = virt_to_bus(ed);
 
-       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+       /* save the ED link in each of the TDs added */
+       td->ed = ed;
+       while (td->next_td != 0) {
+               td = bus_to_virt(td->next_td);
+               td->ed = ed;
+       }
+
+       /* turn off the SKIP flag */
+       ed->status &= ~OHCI_ED_SKIP;
 } /* ohci_add_td_to_ed() */
 
 
+inline void ohci_start_control(struct ohci *ohci)
+{
+       /* tell the HC to start processing the control list */
+       writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_bulk(struct ohci *ohci)
+{
+       /* tell the HC to start processing the bulk list */
+       writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_periodic(struct ohci *ohci)
+{
+       /* enable processing periodc transfers starting next frame */
+       writel_set(OHCI_USB_PLE, &ohci->regs->control);
+}
+
+inline void ohci_start_isoc(struct ohci *ohci)
+{
+       /* enable processing isoc. transfers starting next frame */
+       writel_set(OHCI_USB_IE, &ohci->regs->control);
+}
+
 /*
- *  Remove a TD from the given EDs TD list
+ * Add an ED to the hardware register ED list pointed to by hw_listhead_p
  */
-static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
 {
-       struct ohci_td *head = bus_to_virt(ed->head_td);
-       struct ohci_td *tmp_td;
+       __u32 listhead;
        unsigned long flags;
 
        spin_lock_irqsave(&ohci_edtd_lock, flags);
+       
+       listhead = readl(hw_listhead_p);
 
-       /* set the "skip me bit" in this ED */
-       writel_set(OHCI_ED_SKIP, ed->status);
+       /* if the list is not empty, insert this ED at the front */
+       /* XXX should they go on the end? */
+       if (listhead) {
+               ed->next_ed = listhead;
+       }
 
-       /* XXX Assuming this list will never be circular */
+       /* update the hardware listhead pointer */
+       writel(virt_to_bus(ed), hw_listhead_p);
 
-       if (td == head) {
-               /* unlink this TD; it was at the beginning */
-               ed->head_td = head->next_td;
-       }
+       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_add_ed() */
 
-       tmp_td = head;
-       head = (struct ohci_td *) ed->head_td;
-       
-       while (head != NULL) {
 
-               if (td == head) {
-                       /* unlink this TD from the middle or end */
-                       tmp_td->next_td = head->next_td;
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+       ohci_add_ed_to_hw(ed, &ohci->regs->ed_controlhead);
+       ohci_start_control(ohci);
+} /* ohci_add_control_ed() */
+
+
+#if 0
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
+{
+       ohci_add_ed_to_hw(ed, /* XXX */);
+       ohci_start_periodic(ohci);
+} /* ohci_add_control_ed() */
+#endif
+
+
+/*
+ *  Remove an ED from the HC list whos bus headpointer is pointed to
+ *  by hw_listhead_p
+ *  
+ *  Note that the SKIP bit is left on in the removed ED.
+ */
+void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p)
+{
+       unsigned long flags;
+       struct ohci_ed *cur;
+       __u32 bus_ed = virt_to_bus(ed);
+       __u32 bus_cur;
+
+       if (ed == NULL || !bus_ed)
+               return;
+
+       /* tell the controller this skip ED */
+       ed->status |= OHCI_ED_SKIP;
+
+       bus_cur = readl(hw_listhead_p);
+
+       if (bus_cur == 0)
+               return;   /* the list is already empty */
+
+       cur = bus_to_virt(bus_cur);
+
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+       /* if its the head ED, move the head */
+       if (bus_cur == bus_ed) {
+               writel(cur->next_ed, hw_listhead_p);
+       } else if (cur->next_ed != 0) {
+               struct ohci_ed *prev;
+
+               /* walk the list and unlink the ED if found */
+               for (;;) {
+                       prev = cur;
+                       cur = bus_to_virt(cur->next_ed);
+
+                       if (virt_to_bus(cur) == bus_ed) {
+                               /* unlink from the list */
+                               prev->next_ed = cur->next_ed;
+                               break;
+                       }
+
+                       if (cur->next_ed == 0)
+                               break;
                }
+       }
+
+       /* clear any links from the ED for safety */
+       ed->next_ed = 0;
+
+       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_remove_ed_from_hw() */
+
+/*
+ *  Remove an ED from the controller's control list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+       ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead);
+}
+
+/*
+ *  Remove an ED from the controller's bulk list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+       ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead);
+}
 
-               tmp_td = head;
-               head = bus_to_virt(head->next_td);
+
+/*
+ *  Remove a TD from the given EDs TD list.
+ */
+static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+       unsigned long flags;
+       struct ohci_td *head_td;
+
+       if ((td == NULL) || (ed == NULL))
+               return;
+
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+       if (ed_head_td(ed) == 0)
+               return;
+
+       /* set the "skip me bit" in this ED */
+       ed->status |= OHCI_ED_SKIP;
+
+       /* XXX Assuming this list will never be circular */
+
+       head_td = bus_to_virt(ed_head_td(ed));
+       if (virt_to_bus(td) == ed_head_td(ed)) {
+               /* It's the first TD, remove it. */
+               set_ed_head_td(ed, head_td->next_td);
+       } else {
+               struct ohci_td *prev_td, *cur_td;
+
+               /* FIXME: collapse this into a nice simple loop :) */
+               if (head_td->next_td != 0) {
+                       prev_td = head_td;
+                       cur_td = bus_to_virt(head_td->next_td);
+                       for (;;) {
+                               if (td == cur_td) {
+                                       /* remove it */
+                                       prev_td->next_td = cur_td->next_td;
+                                       break;
+                               }
+                               if (cur_td->next_td == 0)
+                                       break;
+                               prev_td = cur_td;
+                               cur_td = bus_to_virt(cur_td->next_td);
+                       }
+               }
        }
 
-       td->next_td = virt_to_bus(NULL);  /* remove links to ED list */
+       td->next_td = 0;  /* remove the TDs links */
+       td->ed = NULL;
 
-       /* XXX mark this TD for possible cleanup? */
+       /* TODO return this TD to the pool of free TDs */
 
        /* unset the "skip me bit" in this ED */
-       writel_mask(~(__u32)OHCI_ED_SKIP, ed->status);
+       ed->status &= ~OHCI_ED_SKIP;
 
        spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 } /* ohci_remove_td_from_ed() */
@@ -165,60 +341,67 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
        int idx;
 
        for (idx=0; idx < NUM_TDS; idx++) {
-               if (td_done(dev->td[idx].info)) {
-                       /* XXX should this also zero out the structure? */
-                       /* mark all new TDs as unaccessed */
-                       dev->td[idx].info = OHCI_TD_CC_NEW;
-                       return &dev->td[idx];
+               if (!td_allocated(dev->td[idx])) {
+                       struct ohci_td *new_td = &dev->td[idx];
+                       /* zero out the TD */
+                       memset(new_td, 0, sizeof(*new_td));
+                       /* mark the new TDs as unaccessed */
+                       new_td->info = OHCI_TD_CC_NEW;
+                       /* mark it as allocated */
+                       allocate_td(new_td);
+                       return new_td;
                }
        }
 
+       printk("usb-ohci error: unable to allocate a TD\n");
        return NULL;
 } /* ohci_get_free_td() */
 
 
-/**********************************
- * OHCI interrupt list operations *
- **********************************/
-static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
-
-static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id)
+/*
+ *  Initialize a TD
+ *
+ *     dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
+ *     toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
+ */
+inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
 {
-       unsigned long flags;
-
-       /* save the irq in our private portion of the TD */
-       td->completed = completed;
+       /* hardware fields */
+       td->info = OHCI_TD_CC_NEW |
+               (dir & OHCI_TD_D) |
+               (toggle & OHCI_TD_DT) |
+               flags;
+       td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data);
+       td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1;
+
+       /* driver fields */
+       td->data = data;
        td->dev_id = dev_id;
+       td->completed = completed;
 
-       spin_lock_irqsave(&irqlist_lock, flags);
-       list_add(&td->irq_list, &ohci->interrupt_list);
-       spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_add_irq_list() */
+       return td;
+} /* ohci_fill_new_td() */
 
-static void ohci_remove_irq_list(struct ohci_td *td)
-{
-       unsigned long flags;
 
-       spin_lock_irqsave(&irqlist_lock, flags);
-       list_del(&td->irq_list);
-       spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_remove_irq_list() */
+/**********************************
+ * OHCI interrupt list operations *
+ **********************************/
 
 /*
  * Request an interrupt handler for one "pipe" of a USB device.
  * (this function is pretty minimal right now)
  *
  * At the moment this is only good for input interrupts. (ie: for a
- * mouse)
+ * mouse or keyboard)
  *
- * period is desired polling interval in ms.  The closest, shorter
+ * Period is desired polling interval in ms.  The closest, shorter
  * match will be used.  Powers of two from 1-32 are supported by OHCI.
  */
 static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
        usb_device_irq handler, int period, void *dev_id)
 {
        struct ohci_device *dev = usb_to_ohci(usb);
-       struct ohci_td *td = dev->td;   /* */
+       struct ohci_td *td;
        struct ohci_ed *interrupt_ed;   /* endpoint descriptor for this irq */
 
        /*
@@ -239,42 +422,68 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
                usb_pipe_endpdev(pipe) |
                OHCI_ED_F_NORM;
 
+       td = ohci_get_free_td(dev);
+       /* FIXME: check for NULL */
+
+       /* Fill in the TD */
+       ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
+                       TOGGLE_AUTO,
+                       OHCI_TD_ROUND,
+                       dev->data, DATA_BUF_LEN,
+                       dev_id, handler);
        /*
-        * Set the not accessed condition code, allow odd sized data,
-        * and set the data transfer direction.
+        * TODO: be aware that OHCI won't advance out of the 4kb
+        * page cur_buf started in.  It'll wrap around to the start
+        * of the page...  annoying or useful? you decide.
+        *
+        * We should make sure dev->data doesn't cross a page...
         */
-       td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-               td_set_dir_out(usb_pipeout(pipe));
 
-       /* point it to our data buffer */
-       td->cur_buf = virt_to_bus(dev->data);
+       /* FIXME: this just guarantees that its the end of the list */
+       td->next_td = 0;
 
-       /* FIXME: we're only using 1 TD right now! */
-       td->next_td = virt_to_bus(&td);
+       /* Linus did this. see asm/system.h; scary concept... I don't
+        * know if its needed here or not but it won't hurt. */
+       wmb();
 
        /*
-        * FIXME: be aware that OHCI won't advance out of the 4kb
-        * page cur_buf started in.  It'll wrap around to the start
-        * of the page...  annoying or useful? you decide.
-        *
-        * A pointer to the last *byte* in the buffer (ergh.. we get
-        * to work around C's pointer arithmatic here with a typecast)
+        *  Put the TD onto our ED
         */
-       td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1);
+       {
+               unsigned long flags;
+               spin_lock_irqsave(&ohci_edtd_lock, flags);
+               ohci_add_td_to_ed(td, interrupt_ed);
+               spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+       }
 
-       /* does this make sense for ohci?.. time to think.. */
-       ohci_add_irq_list(dev->ohci, td, handler, dev_id);
-       wmb();     /* found in asm/system.h; scary concept... */
-       ohci_add_td_to_ed(td, interrupt_ed);
+#if 0
+       /* Assimilate the new ED into the collective */
+       /*
+        *  When dynamic ED allocation is done, this call will be
+        *  useful.  For now, the correct ED already on the
+        *  controller's proper periodic ED lists was chosen above.
+        */
+       ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+#else
+       /* enable periodic (interrupt) transfers on the HC */
+       ohci_start_periodic(dev->ohci);
+#endif
 
        return 0;
 } /* ohci_request_irq() */
 
+
 /*
  * Control thread operations:
  */
 static struct wait_queue *control_wakeup;
 
+/*
+ *  This is the handler that gets called when a control transaction
+ *  completes.
+ *
+ *  This function is called from the interrupt handler.
+ */
 static int ohci_control_completed(int stats, void *buffer, void *dev_id)
 {
        wake_up(&control_wakeup);
@@ -282,42 +491,17 @@ static int ohci_control_completed(int stats, void *buffer, void *dev_id)
 } /* ohci_control_completed() */
 
 
-/*
- * Run a control transaction from the root hub's control endpoint.
- * The passed in TD is the control transfer's Status TD.
- */
-static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td)
-{
-       struct wait_queue wait = { current, NULL };
-       struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-
-       current->state = TASK_UNINTERRUPTIBLE;
-       add_wait_queue(&control_wakeup, &wait);
-
-       ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL);
-       ohci_add_td_to_ed(status_td, control_ed);
-
-       /* FIXME? isn't this a little gross */
-       schedule_timeout(HZ/10);
-
-       ohci_remove_irq_list(status_td);
-       ohci_remove_td_from_ed(status_td, control_ed);
-
-       return ohci_td_result(dev, status_td);
-} /* ohci_run_control() */
-
 /*
  * Send or receive a control message on a "pipe"
  *
+ * The cmd parameter is a pointer to the 8 byte setup command to be
+ * sent.  FIXME:  This is a devrequest in usb.h.  The function
+ * should be updated to accept a devrequest* instead of void*..
+ *
  * A control message contains:
  *   - The command itself
- *   - An optional data phase
+ *   - An optional data phase (if len > 0)
  *   - Status complete phase
- *
- * The data phase can be an arbitrary number of TD's.  Currently since
- * we use statically allocated TDs if too many come in we'll just
- * start tossing them and printk() some warning goo...  Most control
- * messages won't have much data anyways.
  */
 static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
 {
@@ -330,10 +514,12 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd
         * anyways? ;)
         */
        struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-       struct ohci_td *control_td;
-       struct ohci_td *data_td;
-       struct ohci_td *last_td;
-       __u32 data_td_info;
+       struct ohci_td *setup_td, *data_td, *status_td;
+       struct wait_queue wait = { current, NULL };
+
+#if 0
+       printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
+#endif
 
        /*
         * Set the max packet size, device speed, endpoint number, usb
@@ -351,95 +537,174 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd
         */
 
        /* get a TD to send this control message with */
-       control_td = ohci_get_free_td(dev);
+       setup_td = ohci_get_free_td(dev);
        /* TODO check for NULL */
 
        /*
         * Set the not accessed condition code, allow odd sized data,
         * and set the data transfer type to SETUP.  Setup DATA always
         * uses a DATA0 packet.
+        *
+        * The setup packet contains a devrequest (usb.h) which
+        * will always be 8 bytes long.  FIXME: the cmd parameter
+        * should be a pointer to one of these instead of a void* !!!
         */
-       control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-               OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0);
-
-       /* point it to the command */
-       control_td->cur_buf = virt_to_bus(cmd);
+       ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
+                       OHCI_TD_IOC_OFF,
+                       cmd, 8,         /* cmd is always 8 bytes long */
+                       NULL, NULL);
 
-       /* link to a free TD for the control data input */
+       /* allocate the next TD */
        data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-       control_td->next_td = virt_to_bus(data_td);
 
-       /*
-        * Build the DATA TDs
-        */
+       /* link to the next TD */
+       setup_td->next_td = virt_to_bus(data_td);
 
-       data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF |
-               td_set_dir_out(usb_pipeout(pipe));
+       if (len > 0) {
 
-       while (len > 0) {
-               int pktsize = len;
-               struct ohci_td *tmp_td;
+               /* build the Control DATA TD, it starts with a DATA1. */
+               ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
+                               TOGGLE_DATA1,
+                               OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
+                               data, len,
+                               NULL, NULL);
 
-               if (pktsize > usb_maxpacket(pipe))
-                       pktsize = usb_maxpacket(pipe);
+               /*
+                * XXX we should check that the data buffer doesn't
+                * cross a 4096 byte boundary.  If so, it needs to be
+                * copied into a single 4096 byte aligned area for the
+                * OHCI's TD logic to see it all, or multiple TDs need
+                * to be made for each page.
+                *
+                * It's not likely a control transfer will run into
+                * this problem.. (famous last words)
+                */
 
-               /* set the data transaction type */
-               data_td->info = data_td_info;
-               /* point to the current spot in the data buffer */
-               data_td->cur_buf = virt_to_bus(data);
-               /* point to the end of this data */
-               data_td->buf_end = virt_to_bus(data+pktsize-1);
+               status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+               data_td->next_td = virt_to_bus(status_td);
+       } else {
+               status_td = data_td; /* no data_td, use it for status */
+       }
 
-               /* allocate the next TD */
-               tmp_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-               data_td->next_td = virt_to_bus(tmp_td);
-               data_td = tmp_td;
+       /* The control status packet always uses a DATA1 */
+       ohci_fill_new_td(status_td,
+                       td_set_dir_in(usb_pipeout(pipe) | (len == 0)),
+                       TOGGLE_DATA1,
+                       0,
+                       NULL, 0,
+                       NULL, ohci_control_completed);
+       status_td->next_td = 0; /* end of TDs */
 
-               /* move on.. */
-               data += pktsize;
-               len -= pktsize;
+       /*
+        * Start the control transaction..
+        */
+       current->state = TASK_UNINTERRUPTIBLE;
+       add_wait_queue(&control_wakeup, &wait);
+
+       /*
+        * Add the chain of 2-3 control TDs to the control ED's TD list
+        */
+       {
+               unsigned long flags;
+               spin_lock_irqsave(&ohci_edtd_lock, flags);
+               ohci_add_td_to_ed(setup_td, control_ed);
+               spin_unlock_irqrestore(&ohci_edtd_lock, flags);
        }
 
-       /* point it at the newly allocated TD from above */
-       last_td = data_td;
+#if 0
+       /* complete transaction debugging output (before) */
+       printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
+       show_ohci_ed(control_ed);
+       printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
+       show_ohci_td(setup_td);
+       if (data_td != status_td) {
+               printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
+               show_ohci_td(data_td);
+       }
+       printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
+       show_ohci_td(status_td);
+#endif
 
-       /* The control status packet always uses a DATA1 */
-       last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1);
-       last_td->next_td = 0; /* end of TDs */
-       last_td->cur_buf = 0; /* no data in this packet */
-       last_td->buf_end = 0;
+       /* Give the ED to the HC */
+       ohci_add_control_ed(dev->ohci, control_ed);
 
-       /*
-        * Start the control transaction.. give it the last TD so the
-        * result can be returned.
+       /* FIXME:
+        * this should really check to see that the transaction completed.
         */
-       return ohci_run_control(dev, last_td);
+       schedule_timeout(HZ/10);
+
+       remove_wait_queue(&control_wakeup, &wait);
+
+#if 0
+       /* complete transaction debugging output (after) */
+       printk(KERN_DEBUG " (after) Control ED:\n");
+       show_ohci_ed(control_ed);
+       printk(KERN_DEBUG " (after) Setup TD:\n");
+       show_ohci_td(setup_td);
+       if (data_td != status_td) {
+               printk(KERN_DEBUG " (after) Data TD:\n");
+               show_ohci_td(data_td);
+       }
+       printk(KERN_DEBUG " (after) Status TD:\n");
+       show_ohci_td(status_td);
+#endif
+
+       /* clean up incase it failed */
+       /* XXX only do this if their ed pointer still points to control_ed
+        * incase they've been reclaimed and used by something else
+        * already. -greg */
+       ohci_remove_td_from_ed(setup_td, control_ed);
+       ohci_remove_td_from_ed(data_td, control_ed);
+       ohci_remove_td_from_ed(status_td, control_ed);
+
+       /* remove the control ED */
+       ohci_remove_control_ed(dev->ohci, control_ed);
+
+#if 0
+       printk(KERN_DEBUG "leaving ohci_control_msg\n");
+#endif
+
+       return ohci_td_result(dev, status_td);
 } /* ohci_control_msg() */
 
 
+/*
+ * Allocate a new USB device to be attached to an OHCI controller
+ */
 static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
 {
        struct usb_device *usb_dev;
        struct ohci_device *dev;
 
+       /*
+        * Allocate the generic USB device
+        */
        usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
        if (!usb_dev)
                return NULL;
 
        memset(usb_dev, 0, sizeof(*usb_dev));
 
+       /*
+        * Allocate an OHCI device (EDs and TDs for this device)
+        */
        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev) {
                kfree(usb_dev);
                return NULL;
        }
 
-       /* Initialize "dev" */
        memset(dev, 0, sizeof(*dev));
 
+       /*
+        * Link them together
+        */
        usb_dev->hcpriv = dev;
        dev->usb = usb_dev;
 
+       /*
+        * Link the device to its parent (hub, etc..) if any.
+        */
        usb_dev->parent = parent;
 
        if (parent) {
@@ -448,8 +713,14 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
        }
 
        return usb_dev;
-}
+} /* ohci_usb_allocate() */
+
 
+/*
+ * Free a usb device.
+ *
+ * TODO This function needs to take better care of the EDs and TDs, etc.
+ */
 static int ohci_usb_deallocate(struct usb_device *usb_dev)
 {
        kfree(usb_to_ohci(usb_dev));
@@ -457,6 +728,7 @@ static int ohci_usb_deallocate(struct usb_device *usb_dev)
        return 0;
 }
 
+
 /*
  * functions for the generic USB driver
  */
@@ -467,42 +739,92 @@ struct usb_operations ohci_device_operations = {
        ohci_request_irq,
 };
 
+
 /*
- * Reset an OHCI controller
+ * Reset an OHCI controller.  Returns >= 0 on success.
+ *
+ * Afterwards the HC will be in the "suspend" state which prevents you
+ * from writing to some registers.  Bring it to the operational state
+ * ASAP.
  */
-static void reset_hc(struct ohci *ohci)
+static int reset_hc(struct ohci *ohci)
 {
-       writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
-       writel(1,  &ohci->regs->cmdstatus);        /* HC Reset */
+       int timeout = 1000;  /* prevent an infinite loop */
+
+#if 0
+       printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci);
+#endif
+
+       writel(~0x0, &ohci->regs->intrdisable);    /* Disable HC interrupts */
+       writel(1, &ohci->regs->cmdstatus);         /* HC Reset */
        writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
+
+       while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
+               if (!--timeout) {
+                       printk("usb-ohci: USB HC reset timed out!\n");
+                       return -1;
+               }
+               udelay(1);
+       }
+
+       printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
+
+       return 0;
 } /* reset_hc() */
 
 
 /*
- * Reset and start an OHCI controller
+ * Reset and start an OHCI controller.  Returns >= 0 on success.
  */
-static void start_hc(struct ohci *ohci)
+static int start_hc(struct ohci *ohci)
 {
-       int timeout = 1000;     /* used to prevent an infinite loop. */
+       int ret = 0;
+       int fminterval;
 
-       reset_hc(ohci);
+       fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+#if 0
+       printk(KERN_DEBUG "entering start_hc %p\n", ohci);
+#endif
 
-       while ((readl(&ohci->regs->control) & 0xc0) == 0) {
-               if (!--timeout) {
-                       printk("USB HC Reset timed out!\n");
-                       break;
-               }
-       }
+       if (reset_hc(ohci) < 0)
+               return -1;
+
+       /* restore registers cleared by the reset */
+       writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca);
 
+       /*
+        * XXX Should fminterval also be set here?
+        * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
+        */
+       fminterval |= (0x2edf << 16);
+       writel(fminterval, &ohci->regs->fminterval);
+       /* Start periodic transfers at 90% of fminterval (fmremaining
+        * counts down; this will put them in the first 10% of the
+        * frame). */
+       writel((0x2edf*9)/10, &ohci->regs->periodicstart);
+
+       /*
+        * FNO (frame number overflow) could be enabled...  they
+        * occur every 32768 frames (every 32-33 seconds).  This is
+        * useful for debugging and as a bus heartbeat. -greg
+        */
        /* Choose the interrupts we care about */
-       writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF |
-               OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE |
-               OHCI_INTR_FNO,
+       writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */
+               OHCI_INTR_WDH | OHCI_INTR_FNO,
                &ohci->regs->intrenable);
 
        /* Enter the USB Operational state & start the frames a flowing.. */
        writel_set(OHCI_USB_OPER, &ohci->regs->control);
+       
+       /* Enable control lists */
+       writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
 
+       /* Turn on power to the root hub ports (thanks Roman!) */
+       writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
+
+       printk("usb-ohci: host controller operational\n");
+
+       return ret;
 } /* start_hc() */
 
 
@@ -511,23 +833,20 @@ static void start_hc(struct ohci *ohci)
  */
 static void ohci_reset_port(struct ohci *ohci, unsigned int port)
 {
-       short ms;
        int status;
 
        /* Don't allow overflows. */
        if (port >= MAX_ROOT_PORTS) {
-               printk("Bad port # passed to ohci_reset_port\n");
+               printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
                port = MAX_ROOT_PORTS-1;
        }
 
        writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
 
        /*
-        * Get the time required for a root hub port to reset and wait
-        * it out (adding 1ms for good measure).
+        * Wait for the reset to complete.
         */
-       ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1;
-       wait_ms(ms);
+       wait_ms(10);
 
        /* check port status to see that the reset completed */
        status = readl(&ohci->regs->roothub.portstatus[port]);
@@ -555,6 +874,8 @@ static void ohci_connect_change(struct ohci * ohci, int port)
        void *portaddr = &ohci->regs->roothub.portstatus[port];
        int portstatus; 
 
+       printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port);
+
        /*
         * Because of the status change we have to forget
         * everything we think we know about the device
@@ -593,6 +914,7 @@ static void ohci_connect_change(struct ohci * ohci, int port)
         * Do generic USB device tree processing on the new device.
         */
        usb_new_device(usb_dev);
+
 } /* ohci_connect_change() */
 
 
@@ -603,66 +925,241 @@ static void ohci_connect_change(struct ohci * ohci, int port)
  */
 static void ohci_check_configuration(struct ohci *ohci)
 {
+       struct ohci_regs *regs = ohci->regs;
        int num = 0;
        int maxport = readl(&ohci->regs->roothub) & 0xff;
 
+#if 1
+       printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci);
+#endif
+
        do {
-               if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC)
+               if (readl(&regs->roothub.portstatus[num]) & PORT_CSC) {
+                       /* reset the connect status change bit */
+                       writel(PORT_CSC, &regs->roothub.portstatus[num]);
+                       /* check the port for a nifty device */
                        ohci_connect_change(ohci, num);
+               }
        } while (++num < maxport);
+
+#if 0
+       printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci);
+#endif
 } /* ohci_check_configuration() */
 
 
+
+/*
+ * Check root hub port status and wake the control thread up if
+ * anything has changed.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_root_hub_events(struct ohci *ohci)
+{
+       if (waitqueue_active(&ohci_configure)) {
+               int num = 0;
+               int maxport = ohci->root_hub->usb->maxchild;
+
+               do {
+                       if (readl(&ohci->regs->roothub.portstatus[num]) &
+                                       PORT_CSC) {
+                               if (waitqueue_active(&ohci_configure))
+                                       wake_up(&ohci_configure);
+                               return;
+                       }
+               } while (++num < maxport);
+       }
+} /* ohci_root_hub_events() */
+
+
+/*
+ * The done list is in reverse order; we need to process TDs in the
+ * order they were finished (FIFO).  This function builds the FIFO
+ * list using the next_dl_td pointer.
+ *
+ * This function originally by Roman Weissgaerber (weissg@vienna.at)
+ *
+ * This function is called from the interrupt handler.
+ */
+static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci)
+{
+       __u32 td_list_hc;
+       struct ohci_hcca *hcca = ohci->root_hub->hcca;
+       struct ohci_td *td_list = NULL;
+       struct ohci_td *td_rev = NULL;
+       
+       td_list_hc = hcca->donehead & 0xfffffff0;
+       hcca->donehead = 0;
+
+       while(td_list_hc) {
+               td_list = (struct ohci_td *) bus_to_virt(td_list_hc);
+               td_list->next_dl_td = td_rev;
+                       
+               td_rev = td_list;
+               td_list_hc = td_list->next_td & 0xfffffff0;
+       }
+
+       return td_list;
+} /* ohci_reverse_donelist() */
+
+
+/*
+ * Collect this interrupt's goodies off of the list of finished TDs
+ * that the OHCI controller is kind enough to setup for us.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_reap_donelist(struct ohci *ohci)
+{
+       struct ohci_td *td;             /* used for walking the list */
+
+       spin_lock(&ohci_edtd_lock);
+
+       /* create the FIFO ordered donelist */
+       td = ohci_reverse_donelist(ohci);
+
+       while (td != NULL) {
+               struct ohci_td *next_td = td->next_dl_td;
+
+               /* FIXME: munge td->info into a future standard status format */
+               /* Check if TD should be re-queued */
+               if ((td->completed != NULL) &&
+                   (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id)))
+               {
+                       /* Mark the TD as active again:
+                        * Set the not accessed condition code
+                        * FIXME: should this reset OHCI_TD_ERRCNT?
+                        */
+                       td->info |= OHCI_TD_CC_NEW;
+
+                       /* point it back to the start of the data buffer */
+                       td->cur_buf = virt_to_bus(td->data);
+
+                       /* XXX disabled for debugging reasons right now.. */
+                       /* insert it back on its ED */
+                       ohci_add_td_to_ed(td, td->ed);
+               } else {
+                       /* return it to the pool of free TDs */
+                       ohci_free_td(td);
+               }
+
+               td = next_td;
+       }
+
+       spin_unlock(&ohci_edtd_lock);
+} /* ohci_reap_donelist() */
+
+
+#if 0
+static int in_int = 0;
+#endif
 /*
  * Get annoyed at the controller for bothering us.
+ * This pretty much follows the OHCI v1.0a spec, section 5.3.
  */
 static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
 {
        struct ohci *ohci = __ohci;
        struct ohci_regs *regs = ohci->regs;
        struct ohci_hcca *hcca = ohci->root_hub->hcca;
-       __u32 donehead = hcca->donehead;
+       __u32 status, context;
 
-       /*
-        * Check the interrupt status register if needed
-        */
-       if (!donehead || (donehead & 1)) {
-               __u32 intrstatus = readl(&regs->intrstatus);
+#if 0
+       /* for debugging to keep IRQs from running away. */
+       if (in_int >= 2)
+               return;
+       ++in_int;
+       return;
+#endif
 
-               /*
-                * XXX eek! printk's in an interrupt handler.  shoot me!
-                */
-               if (intrstatus & OHCI_INTR_SO) {
-                       printk(KERN_DEBUG "usb-ohci: scheduling overrun\n");
-               }
-               if (intrstatus & OHCI_INTR_RD) {
-                       printk(KERN_DEBUG "usb-ohci: resume detected\n");
-               }
-               if (intrstatus & OHCI_INTR_UE) {
-                       printk(KERN_DEBUG "usb-ohci: unrecoverable error\n");
+       /* Save the status of the interrupts that are enabled */
+       status = readl(&regs->intrstatus);
+       status &= readl(&regs->intrenable);
+
+
+       /* make context = the interrupt status bits that we care about */
+       if (hcca->donehead != 0) {
+               context = OHCI_INTR_WDH;   /* hcca donehead needs processing */
+               if (hcca->donehead & 1) {
+                       context |= status;  /* other status change to check */
                }
-               if (intrstatus & OHCI_INTR_OC) {
-                       printk(KERN_DEBUG "usb-ohci: ownership change?\n");
+       } else {
+               context = status;
+               if (!context) {
+                       /* TODO increment a useless interrupt counter here */
+                       return;
                }
+       }
 
-               if (intrstatus & OHCI_INTR_RHSC) {
-                       /* TODO Process events on the root hub */
-               }
+       /* Disable HC interrupts */
+       writel(OHCI_INTR_MIE, &regs->intrdisable);
+
+       /* Process the done list */
+       if (context & OHCI_INTR_WDH) {
+               /* See which TD's completed.. */
+               ohci_reap_donelist(ohci);
+
+               /* reset the done queue and tell the controller */
+               hcca->donehead = 0;
+               writel(OHCI_INTR_WDH, &regs->intrstatus);
+
+               context &= ~OHCI_INTR_WDH;  /* mark this as checked */
        }
 
-       /*
-        * Process the done list
-        */
-       if (donehead &= ~0x1) {
-               /*
-                * TODO See which TD's completed..
+       /* Process any root hub status changes */
+       if (context & OHCI_INTR_RHSC) {
+               /* Wake the thread to process root hub events */
+               if (waitqueue_active(&ohci_configure))
+                       wake_up(&ohci_configure);
+
+               writel(OHCI_INTR_RHSC, &regs->intrstatus);
+               /* 
+                * Don't unset RHSC in context; it should be disabled.
+                * The control thread will re-enable it after it has
+                * checked the root hub status.
                 */
+       } else {
+               /* check the root hub status anyways. Some controllers
+                * might not generate the interrupt properly. (?) */
+               ohci_root_hub_events(ohci);
        }
 
-       /* Re-enable done queue interrupts and reset the donehead */
-       hcca->donehead = 0;
-       writel(OHCI_INTR_WDH, &regs->intrenable);
-       
+       /* Check those "other" pesky bits */
+       if (context & (OHCI_INTR_FNO)) {
+               writel(OHCI_INTR_FNO, &regs->intrstatus);
+               context &= ~OHCI_INTR_FNO;  /* mark this as checked */
+       }
+       if (context & OHCI_INTR_SO) {
+               writel(OHCI_INTR_SO, &regs->intrstatus);
+               context &= ~OHCI_INTR_SO;  /* mark this as checked */
+       }
+       if (context & OHCI_INTR_RD) {
+               writel(OHCI_INTR_RD, &regs->intrstatus);
+               context &= ~OHCI_INTR_RD;  /* mark this as checked */
+       }
+       if (context & OHCI_INTR_UE) {
+               /* FIXME: need to have the control thread reset the
+                * controller now and keep a count of unrecoverable
+                * errors.  If there are too many, it should just shut
+                * the broken controller down entirely. */
+               writel(OHCI_INTR_UE, &regs->intrstatus);
+               context &= ~OHCI_INTR_UE;  /* mark this as checked */
+       }
+       if (context & OHCI_INTR_OC) {
+               writel(OHCI_INTR_OC, &regs->intrstatus);
+               context &= ~OHCI_INTR_OC;  /* mark this as checked */
+       }
+
+       /* Mask out any remaining unprocessed interrupts so we don't
+        * get any more of them. */
+       if (context & ~OHCI_INTR_MIE) {
+               writel(context, &regs->intrdisable);
+       }
+
+       /* Re-enable HC interrupts */
+       writel(OHCI_INTR_MIE, &regs->intrenable);
+
 } /* ohci_interrupt() */
 
 
@@ -682,6 +1179,10 @@ static struct ohci *alloc_ohci(void* mem_base)
        struct ohci_device *dev;
        struct usb_device *usb;
 
+#if 0
+       printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
+#endif
+
        ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
        if (!ohci)
                return NULL;
@@ -703,6 +1204,8 @@ static struct ohci *alloc_ohci(void* mem_base)
        bus->op = &ohci_device_operations;
 
        /*
+        * Allocate the USB device structure and root hub.
+        *
         * Here we allocate our own root hub and TDs as well as the
         * OHCI host controller communications area.  The HCCA is just
         * a nice pool of memory with pointers to endpoint descriptors
@@ -717,17 +1220,22 @@ static struct ohci *alloc_ohci(void* mem_base)
        usb->bus = bus;
 
        /* Initialize the root hub */
-       memset(dev, 0, sizeof(*dev));
        dev->ohci = ohci;    /* link back to the controller */
 
        /*
-        * Allocate the Host Controller Communications Area
+        * Allocate the Host Controller Communications Area on a 256
+        * byte boundary.  XXX take the easy way out and just grab a
+        * page as that's guaranteed to have a nice boundary.
         */
-       dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL);
+       dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
 
        /* Tell the controller where the HCCA is */
        writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
 
+#if 0
+       printk(KERN_DEBUG "usb-ohci: HCCA allocated at %p (bus %p)\n", dev->hcca, (void*)virt_to_bus(dev->hcca));
+#endif
+
        /* Get the number of ports on the root hub */
        usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
        if (usb->maxchild > MAX_ROOT_PORTS) {
@@ -740,11 +1248,6 @@ static struct ohci *alloc_ohci(void* mem_base)
        }
        printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
 
-       printk("alloc_ohci() controller\n");
-       show_ohci_status(ohci);
-       printk("alloc_ohci() root_hub device\n");
-       show_ohci_device(dev);
-
        /*
         * Initialize the ED polling "tree" (for simplicity's sake in
         * this driver many nodes in the tree will be identical)
@@ -759,11 +1262,9 @@ static struct ohci *alloc_ohci(void* mem_base)
         * Initialize the polling table to call interrupts at the
         * intended intervals.
         */
-       for (i = 0; i < NUM_INTS; i++) {
-               if (i == 0)
-                       dev->hcca->int_table[i] =
-                               virt_to_bus(&dev->ed[ED_INT_32]);
-               else if (i & 1)
+       dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
+       for (i = 1; i < NUM_INTS; i++) {
+               if (i & 1)
                        dev->hcca->int_table[i] =
                                virt_to_bus(&dev->ed[ED_INT_16]);
                else if (i & 2)
@@ -782,9 +1283,23 @@ static struct ohci *alloc_ohci(void* mem_base)
 
        /*
         * Tell the controller where the control and bulk lists are
+        * The lists start out empty.
         */
+       writel(0, &ohci->regs->ed_controlhead);
+       writel(0, &ohci->regs->ed_bulkhead);
+       /*
        writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
        writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
+       */
+
+#if 0
+       printk(KERN_DEBUG "alloc_ohci(): controller\n");
+       show_ohci_status(ohci);
+#endif
+
+#if 0
+       printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
+#endif
 
        return ohci;
 } /* alloc_ohci() */
@@ -795,16 +1310,25 @@ static struct ohci *alloc_ohci(void* mem_base)
  */
 static void release_ohci(struct ohci *ohci)
 {
+       printk(KERN_DEBUG "entering release_ohci %p\n", ohci);
+
+#ifdef OHCI_TIMER
+       /* stop our timer */
+       del_timer(&ohci_timer);
+#endif
        if (ohci->irq >= 0) {
                free_irq(ohci->irq, ohci);
                ohci->irq = -1;
        }
 
+       /* stop all OHCI interrupts */
+       writel(~0x0, &ohci->regs->intrdisable);
+
        if (ohci->root_hub) {
                /* ensure that HC is stopped before releasing the HCCA */
                writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-               free_pages((unsigned int) ohci->root_hub->hcca, 1);
-               free_pages((unsigned int) ohci->root_hub, 1);
+               free_page((unsigned long) ohci->root_hub->hcca);
+               kfree(ohci->root_hub);
                ohci->root_hub->hcca = NULL;
                ohci->root_hub = NULL;
        }
@@ -812,20 +1336,26 @@ static void release_ohci(struct ohci *ohci)
        /* unmap the IO address space */
        iounmap(ohci->regs);
 
+       kfree(ohci);
+
+       MOD_DEC_USE_COUNT;
+
        /* If the ohci itself were dynamic we'd free it here */
 
+       printk(KERN_DEBUG "usb-ohci: HC resources released.\n");
 } /* release_ohci() */
 
+
 /*
  * USB OHCI control thread
  */
 static int ohci_control_thread(void * __ohci)
 {
        struct ohci *ohci = (struct ohci *)__ohci;
-       
+
        /*
         * I'm unfamiliar with the SMP kernel locking.. where should
-        * this be released?  -greg
+        * this be released and what does it do?  -greg
         */
        lock_kernel();
 
@@ -833,7 +1363,7 @@ static int ohci_control_thread(void * __ohci)
         * This thread doesn't need any user-level access,
         * so get rid of all of our resources..
         */
-       printk("ohci_control_thread at %p\n", &ohci_control_thread);
+       printk("ohci_control_thread code at %p\n", &ohci_control_thread);
        exit_mm(current);
        exit_files(current);
        exit_fs(current);
@@ -843,23 +1373,64 @@ static int ohci_control_thread(void * __ohci)
        /*
         * Damn the torpedoes, full speed ahead
         */
-       start_hc(ohci);
-       do {
+       if (start_hc(ohci) < 0) {
+               printk("usb-ohci: failed to start the controller\n");
+               release_ohci(ohci);
+               printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+               return 0;
+       }
+
+       for(;;) {
+               siginfo_t info;
+               int unsigned long signr;
+
+               wait_ms(200);
+
+               /* check the root hub configuration for changes. */
+               ohci_check_configuration(ohci);
+
+               /* re-enable root hub status change interrupts. */
+#if 0
+               writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+#endif
+
+               printk(KERN_DEBUG "ohci-control thread sleeping\n");
                interruptible_sleep_on(&ohci_configure);
 #ifdef CONFIG_APM
                if (apm_resume) {
                        apm_resume = 0;
-                       start_hc(ohci);
+                       if (start_hc(ohci) < 0)
+                               break;
                        continue;
                }
 #endif
-               ohci_check_configuration(ohci);
-       } while (!signal_pending(current));
 
-       reset_hc(ohci);
+               /*
+                * If we were woken up by a signal, see if its useful,
+                * otherwise exit.
+                */
+               if (signal_pending(current)) {
+                       /* sending SIGUSR1 makes us print out some info */
+                       spin_lock_irq(&current->sigmask_lock);
+                       signr = dequeue_signal(&current->blocked, &info);
+                       spin_unlock_irq(&current->sigmask_lock);
+
+                       if(signr == SIGUSR1) {
+                               /* FIXME: have it do a full ed/td queue dump */
+                               printk(KERN_DEBUG "OHCI status dump:\n");
+                               show_ohci_status(ohci);
+                       } else {
+                               /* unknown signal, exit the thread */
+                               break;
+                       }
+               }
+       } /* for (;;) */
 
+       reset_hc(ohci);
        release_ohci(ohci);
-       MOD_DEC_USE_COUNT;
+
+       printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+
        return 0;
 } /* ohci_control_thread() */
 
@@ -892,10 +1463,28 @@ static int handle_apm_event(apm_event_t event)
                break;
        }
        return 0;
-}
+} /* handle_apm_event() */
+#endif
+
+
+#ifdef OHCI_TIMER
+/*
+ * Inspired by Iñaky's driver.  This function is a timer routine that
+ * is called OHCI_TIMER_FREQ times per second.  It polls the root hub
+ * for status changes as on my system things are acting a bit odd at
+ * the moment..
+ */
+static void ohci_timer_func (unsigned long ohci_ptr)
+{
+       struct ohci *ohci = (struct ohci*)ohci_ptr;
+
+       ohci_root_hub_events(ohci);
+
+       /* press the snooze button... */
+       mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
+} /* ohci_timer_func() */
 #endif
 
-/* ... */
 
 /*
  * Increment the module usage count, start the control thread and
@@ -906,32 +1495,50 @@ static int found_ohci(int irq, void* mem_base)
        int retval;
        struct ohci *ohci;
 
+#if 0
+       printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base);
+#endif
+
        /* Allocate the running OHCI structures */
        ohci = alloc_ohci(mem_base);
-       if (!ohci)
+       if (!ohci) {
                return -ENOMEM;
+       }
 
-       printk("usb-ohci: alloc_ohci() = %p\n", ohci);
-
-       reset_hc(ohci);
+#ifdef OHCI_TIMER
+       init_timer(&ohci_timer);
+       ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
+       ohci_timer.data = (unsigned long)ohci;
+       ohci_timer.function = ohci_timer_func;
+#endif
 
        retval = -EBUSY;
        if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
                int pid;
 
-               MOD_INC_USE_COUNT;
                ohci->irq = irq;
 
+#if 0
+               printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n");
+#endif
+
                /* fork off the handler */
                pid = kernel_thread(ohci_control_thread, ohci,
                                CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-               if (pid >= 0)
+               if (pid >= 0) {
                        return 0;
+               }
 
-               MOD_DEC_USE_COUNT;
                retval = pid;
+       } else {
+               printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
        }
        release_ohci(ohci);
+
+#if 0
+       printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base);
+#endif
+
        return retval;
 } /* found_ohci() */
 
@@ -941,35 +1548,44 @@ static int found_ohci(int irq, void* mem_base)
  */
 static int init_ohci(struct pci_dev *dev)
 {
-       unsigned int mem_base = dev->base_address[0];
+       unsigned long mem_base = dev->base_address[0];
        
-       printk("usb-ohci: mem_base is %p\n", (void*)mem_base);
-
        /* If its OHCI, its memory */
        if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
                return -ENODEV;
 
        /* Get the memory address and map it for IO */
        mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+       /* no interrupt won't work... */
+       if (dev->irq == 0) {
+               printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
+               return -ENODEV;
+       }
+
        /* 
         * FIXME ioremap_nocache isn't implemented on all CPUs (such
         * as the Alpha) [?]  What should I use instead...
         *
         * The iounmap() is done on in release_ohci.
         */
-       mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+       mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
 
        if (!mem_base) {
                printk("Error mapping OHCI memory\n");
                return -EFAULT;
        }
+        MOD_INC_USE_COUNT;
 
-       return found_ohci(dev->irq, (void *) mem_base);
-} /* init_ohci() */
+       if (found_ohci(dev->irq, (void *) mem_base) < 0) {
+               MOD_DEC_USE_COUNT;
+               return -1;
+       }
 
+       return 0;
+} /* init_ohci() */
 
 #ifdef MODULE
-
 /*
  *  Clean up when unloading the module
  */
@@ -978,6 +1594,10 @@ void cleanup_module(void)
 #ifdef CONFIG_APM
        apm_unregister_callback(&handle_apm_event);
 #endif
+#ifdef CONFIG_USB_MOUSE
+       usb_mouse_cleanup();
+#endif
+       printk("usb-ohci: module unloaded\n");
 }
 
 #define ohci_init init_module
@@ -1005,6 +1625,8 @@ int ohci_init(void)
                return -ENODEV;
        }
 
+       printk("OHCI USB Driver loading\n");
+
        retval = -ENODEV;
        for (;;) {
                /* Find an OHCI USB controller */
@@ -1024,9 +1646,16 @@ int ohci_init(void)
 
                /* TODO check module params here to determine what to load */
 
-/*             usb_mouse_init(); */
-/*             usb_kbd_init();
-               hub_init();     */
+#ifdef CONFIG_USB_MOUSE
+               usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD          
+               usb_kbd_init();
+#endif         
+               hub_init();
+#ifdef CONFIG_USB_AUDIO                
+               usb_audio_init();
+#endif         
 #ifdef CONFIG_APM
                apm_register_callback(&handle_apm_event);
 #endif
@@ -1034,7 +1663,7 @@ int ohci_init(void)
                return 0; /* no error */
        }
        return retval;
-} /* init_module() */
+} /* ohci_init */
 
 /* vim:sw=8
  */
index 6c94bbc53b5cac703369a3261d0ce4b774d07e2d..8714cd2e833b1eb241279801ba6477db296cb8a7 100644 (file)
@@ -6,7 +6,7 @@
  *
  * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
  *
- * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $
+ * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $
  */
 
 #include <linux/list.h>
 
 #include "usb.h"
 
+struct ohci_ed;
+
 /*
  * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
  * it does not state that TDs must be contiguious in memory (due to the
  * use of the next_td field).  This gives us extra room at the end of a
  * TD for our own driver specific data.
  *
- * This structure's size must be a multiple of 16 bytes.
+ * This structure's size must be a multiple of 16 bytes. ?? no way, I
+ * don't see why.  Alignment should be all that matters.
  */
 struct ohci_td {
        /* OHCI Hardware fields */
-       __u32 info;
-       __u32 cur_buf;          /* Current Buffer Pointer */
-       __u32 next_td;          /* Next TD Pointer */
-       __u32 buf_end;          /* Memory Buffer End Pointer */
+       __u32 info;             /* TD status & type flags */
+       __u32 cur_buf;          /* Current Buffer Pointer (bus address) */
+       __u32 next_td;          /* Next TD Pointer (bus address) */
+       __u32 buf_end;          /* Memory Buffer End Pointer (bus address) */
 
        /* Driver specific fields */
-       struct list_head irq_list;      /* Active interrupt list */
+       struct ohci_ed *ed;             /* address of the ED this TD is on */
+       struct ohci_td *next_dl_td;     /* used during donelist processing */
+       void *data;                     /* virt. address of the the buffer */
        usb_device_irq completed;       /* Completion handler routine */
-       void *data;     /* XXX ? */
-       void *dev_id;   /* XXX ? */
-       __u32 ed_bus;                   /* bus address of original ED */
-} __attribute((aligned(32)));
+       int allocated;                  /* boolean: is this TD allocated? */
+
+       /* User or Device class driver specific fields */
+       void *dev_id;   /* user defined pointer passed to irq handler */
+} __attribute((aligned(16)));
 
 #define OHCI_TD_ROUND  (1 << 18)       /* buffer rounding bit */
-#define OHCI_TD_D      (3 << 11)       /* direction of xfer: */
-#define OHCI_TD_D_IN   (2 << 11)
-#define OHCI_TD_D_OUT  (1 << 11)
-#define OHCI_TD_D_SETUP (0)
+#define OHCI_TD_D      (3 << 19)       /* direction of xfer: */
+#define OHCI_TD_D_IN   (2 << 19)
+#define OHCI_TD_D_OUT  (1 << 19)
+#define OHCI_TD_D_SETUP (0 << 19)
 #define td_set_dir_in(d)       ((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
 #define td_set_dir_out(d)      ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
 #define OHCI_TD_IOC_DELAY (7 << 21)    /* frame delay allowed before int. */
 #define OHCI_TD_IOC_OFF        (OHCI_TD_IOC_DELAY)     /* no interrupt on complete */
 #define OHCI_TD_DT     (3 << 24)       /* data toggle bits */
+#define TOGGLE_AUTO    (0 << 24)       /* automatic (from the ED) */
+#define TOGGLE_DATA0   (2 << 24)       /* force Data0 */
+#define TOGGLE_DATA1   (3 << 24)       /* force Data1 */
 #define td_force_toggle(b)     (((b) | 2) << 24)
 #define OHCI_TD_ERRCNT (3 << 26)       /* error count */
-#define td_errorcount(td)      (((td) >> 26) & 3)
+#define td_errorcount(td)      (((td).info >> 26) & 3)
 #define OHCI_TD_CC     (0xf << 28)     /* condition code */
+#define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf)
 #define OHCI_TD_CC_NEW (OHCI_TD_CC)    /* set this on all unaccessed TDs! */
-#define td_cc_notaccessed(td)  ((td >> 29) == 7)
-#define td_cc_accessed(td)     ((td >> 29) != 7)
-#define td_cc_noerror(td)      (((td) & OHCI_TD_CC) == 0)
+#define td_cc_notaccessed(td)  (((td).info >> 29) == 7)
+#define td_cc_accessed(td)     (((td).info >> 29) != 7)
+#define td_cc_noerror(td)      ((((td).info) & OHCI_TD_CC) == 0)
 #define td_active(td)  (!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
 #define td_done(td)    (td_cc_noerror((td)) || (td_errorcount((td)) == 3))
 
+#define td_allocated(td)       ((td).allocated)
+#define allocate_td(td)                ((td)->allocated = 1)
+#define ohci_free_td(td)       ((td)->allocated = 0)
+
+
 /*
  * The endpoint descriptors also requires 16-byte alignment
  */
@@ -65,10 +80,16 @@ struct ohci_ed {
        /* OHCI hardware fields */
        __u32 status;
        __u32 tail_td;  /* TD Queue tail pointer */
-       __u32 head_td;  /* TD Queue head pointer */
+       __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */
        __u32 next_ed;  /* Next ED */
 } __attribute((aligned(16)));
 
+/* get the head_td */
+#define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0)
+
+/* save the carry flag while setting the head_td */
+#define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3))
+
 #define OHCI_ED_SKIP   (1 << 14)
 #define OHCI_ED_MPS    (0x7ff << 16)
 /* FIXME: should cap at the USB max packet size [0x4ff] */
@@ -90,10 +111,10 @@ struct ohci_ed {
 
 /* NOTE: bits 27-31 of the status dword are reserved for the driver */
 /*
- * We'll use this status flag for the non-predefined EDs to mark if
- * they're in use or not.
+ * We'll use this status flag for to mark if an ED is in use by the
+ * driver or not.  If the bit is set, it is used.
  *
- * FIXME: unimplemented (needed?)
+ * FIXME: implement this!
  */
 #define ED_USED        (1 << 31)
 
@@ -174,8 +195,8 @@ struct ohci_device {
 
 /*
  * Given a period p in ms, convert it to the closest endpoint
- * interrupt frequency; rounding down.  I'm sure many feel that this
- * is a gross macro.  Feel free to toss it for actual code.
+ * interrupt frequency; rounding down.  This is a gross macro.
+ * Feel free to toss it for actual code. (gasp!)
  */
 #define ms_to_ed_int(p) \
        ((p >= 32) ? ED_INT_32 : \
@@ -257,6 +278,15 @@ struct ohci_regs {
 #define PORT_OCIC      (1 << 19)       /* port over current indicator chg */
 #define PORT_PRSC      (1 << 20)       /* port reset status change */
 
+/*
+ * Root Hub status register masks
+ */
+#define OHCI_ROOT_LPS  (1)             /* turn off root hub ports power */
+#define OHCI_ROOT_OCI  (1 << 1)        /* Overcurrent Indicator */
+#define OHCI_ROOT_DRWE (1 << 15)       /* Device remote wakeup enable */
+#define OHCI_ROOT_LPSC (1 << 16)       /* turn on root hub ports power */
+#define OHCI_ROOT_OCIC (1 << 17)       /* Overcurrent indicator change */
+#define OHCI_ROOT_CRWE (1 << 31)       /* Clear RemoteWakeupEnable */
 
 /*
  * Interrupt register masks
@@ -276,6 +306,19 @@ struct ohci_regs {
  */
 #define OHCI_USB_OPER          (2 << 6)
 #define OHCI_USB_SUSPEND       (3 << 6)
+#define OHCI_USB_PLE           (1 << 2)  /* Periodic (interrupt) list enable */
+#define OHCI_USB_IE            (1 << 3)  /* Isochronous list enable */
+#define OHCI_USB_CLE           (1 << 4)  /* Control list enable */
+#define OHCI_USB_BLE           (1 << 5)  /* Bulk list enable */
+
+/*
+ * Command status register masks
+ */
+#define OHCI_CMDSTAT_HCR       (1)
+#define OHCI_CMDSTAT_CLF       (1 << 1)
+#define OHCI_CMDSTAT_BLF       (1 << 2)
+#define OHCI_CMDSTAT_OCR       (1 << 3)
+#define OHCI_CMDSTAT_SOC       (3 << 16)
 
 /*
  * This is the full ohci controller description
@@ -291,10 +334,15 @@ struct ohci {
        struct list_head interrupt_list;        /* List of interrupt active TDs for this OHCI */
 };
 
+#define OHCI_TIMER
+#define OHCI_TIMER_FREQ        (1)             /* frequency of OHCI status checks */
+
 /* Debugging code */
-void show_ed(struct ohci_ed *ed);
-void show_td(struct ohci_td *td);
-void show_status(struct ohci *ohci);
+void show_ohci_ed(struct ohci_ed *ed);
+void show_ohci_td(struct ohci_td *td);
+void show_ohci_status(struct ohci *ohci);
+void show_ohci_device(struct ohci_device *dev);
+void show_ohci_hcca(struct ohci_hcca *hcca);
 
 #endif
 /* vim:sw=8
index e90e8464a55791c8443994d5a324badfa749d327..98ca05367e19b1325ae25d2774e5a571ef1758a4 100644 (file)
@@ -11,25 +11,28 @@ ME=`basename $0`
 #  fi
 #fi
 
-UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'`
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
 if test "$UPID"; then
   echo "$ME: killing $UPID"
   kill $UPID
 fi
 
-UMOD=`lsmod | grep '^usb-uhci' | grep -v grep`
+UMOD=`lsmod | grep '^usb-ohci' | grep -v grep`
 if test "$UMOD"; then
-  echo "$ME: removing usb-uhci.o"
+  echo "$ME: removing usb-ohci.o"
   sleep 1
-  if ! rmmod usb-uhci; then
-    echo "$ME: cannot remove usb-uhci.o"
+  if ! rmmod usb-ohci; then
+    echo "$ME: cannot remove usb-ohci.o"
     exit 1
   fi
 fi
 
 dmesg -c > /dev/null
 
-echo "$ME: starting usb-uhci.o"
-insmod -m usb-uhci.o > usb-uhci.map
-#echo "$ME: starting bp-mouse.o"
-#insmod -m bp-mouse.o > bp-mouse.map
+echo "$ME: starting usb-ohci.o"
+insmod -m usb-ohci.o > usb-ohci.map
+
+sleep 1
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
+if test "$UPID"; then echo "$ME: ohci-control is pid $UPID" ; fi
+
index ffd42306b299e0ae40b88167bd01da0763cddd3d..1dc46980b537cedce38153e2f9ceeb345ed27f4d 100644 (file)
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-killall uhci-control
-killall khubd
+killall ohci-control
 
-sleep 1
+sleep 2
 
-rmmod usb-uhci
+rmmod usb-ohci
index 8d35e2eebb1d7d53abff186a28e87a0dc25c4e28..10379ef88da4d97ef56299e86ef834086f42dd51 100644 (file)
@@ -194,6 +194,14 @@ struct usb_driver {
 
 /*
  * Pointer to a device endpoint interrupt function -greg
+ *   Parameters:
+ *     int status - This needs to be defined.  Right now each HCD
+ *         passes different transfer status bits back.  Don't use it
+ *         until we come up with a common meaning.
+ *     void *buffer - This is a pointer to the data used in this
+ *         USB transfer.
+ *     void *dev_id - This is a user defined pointer set when the IRQ
+ *         is requested that is passed back.
  */
 typedef int (*usb_device_irq)(int, void *, void *);
 
index ab11028050e0c8e2e4178a83aced103a960fc951..78af83ef07a233d0ba3e581911597e0a901a115c 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/selection.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/config.h>
 
 #include <asm/io.h>
 #include <asm/mtrr.h>
index 4f6e066845f1df66d2057bd86894a459ee875ba6..df3b5e457addeac687bf226fde8e8aa9a828b858 100644 (file)
@@ -46,7 +46,7 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
        unsigned long parent_object_id, dir_object_id;
        int buffers, pos;
 
-       if (!dir || !S_ISDIR(dir->i_mode))
+       if (!S_ISDIR(dir->i_mode))
                return 0;
 
        sb = dir->i_sb;
index 0abf1894940514a53a61ea984001fb90ceec92f9..afec12e55a18529abaf84a58962fe6d11504367a 100644 (file)
@@ -100,7 +100,8 @@ union bdflush_param{
                                each time we call refill */
                int nref_dirt; /* Dirty buffer threshold for activating bdflush
                                  when trying to refill buffers. */
-               int dummy1;    /* unused */
+               int interval;  /* Interval (seconds) between spontaneous
+                                 bdflush runs */
                int age_buffer;  /* Time for normal buffer to age before 
                                    we flush it */
                int age_super;  /* Time for superblock to age before we 
@@ -109,10 +110,10 @@ union bdflush_param{
                int dummy3;    /* unused */
        } b_un;
        unsigned int data[N_PARAM];
-} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  1,   1*HZ,   1*HZ, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
@@ -1553,7 +1554,6 @@ void __init buffer_init(unsigned long memory_size)
  * response to dirty buffers.  Once this process is activated, we write back
  * a limited number of buffers to the disks and then go back to sleep again.
  */
-static struct wait_queue * bdflush_wait = NULL;
 static struct wait_queue * bdflush_done = NULL;
 struct task_struct *bdflush_tsk = 0;
 
@@ -1561,7 +1561,7 @@ void wakeup_bdflush(int wait)
 {
        if (current == bdflush_tsk)
                return;
-       wake_up(&bdflush_wait);
+       wake_up_process(bdflush_tsk);
        if (wait) {
                run_task_queue(&tq_disk);
                sleep_on(&bdflush_done);
@@ -1570,82 +1570,107 @@ void wakeup_bdflush(int wait)
 
 
 /* 
- * Here we attempt to write back old buffers.  We also try to flush inodes 
- * and supers as well, since this function is essentially "update", and 
- * otherwise there would be no way of ensuring that these quantities ever 
- * get written back.  Ideally, we would have a timestamp on the inodes
- * and superblocks so that we could write back only the old ones as well
- */
+ * Here we attempt to write back old buffers.
+ * To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *     out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *     (otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *     with running out of free buffers for loop's "real" device).
+*/
 
-static int sync_old_buffers(void)
+static inline void sync_old_buffers(void)
 {
        int i;
-       int ndirty, nwritten;
-       int nlist;
-       int ncount;
-       struct buffer_head * bh, *next;
-
-       sync_supers(0);
-       sync_inodes(0);
-
-       ncount = 0;
+       int ndirty = 0;
+       int wrta_cmd = WRITEA;
 #ifdef DEBUG
-       for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-       for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
+       int ncount = 0, nwritten = 0;
 #endif
-       {
-               ndirty = 0;
-               nwritten = 0;
-       repeat:
+       struct buffer_head * bh, *next;
 
-               bh = lru_list[nlist];
-               if(bh) 
-                        for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
-                                /* We may have stalled while waiting for I/O to complete. */
-                                if(bh->b_list != nlist) goto repeat;
-                                next = bh->b_next_free;
-                                if(!lru_list[nlist]) {
-                                        printk("Dirty list empty %d\n", i);
-                                        break;
-                                }
-                                
-                                /* Clean buffer on dirty list?  Refile it */
-                                if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
-                                        refile_buffer(bh);
-                                        continue;
-                                }
-                                 
-                                 /* Unlocked buffer on locked list?  Refile it */
-                                 if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-                                         refile_buffer(bh);
-                                         continue;
-                                 }
-                                
-                                if (buffer_locked(bh) || !buffer_dirty(bh))
-                                         continue;
-                                ndirty++;
-                                if(time_before(jiffies, bh->b_flushtime))
-                                       continue;
-                                nwritten++;
-                                next->b_count++;
-                                bh->b_count++;
-                                bh->b_flushtime = 0;
 #ifdef DEBUG
-                                if(nlist != BUF_DIRTY) ncount++;
+       bh = lru_list[BUF_CLEAN];
+       if(bh)
+               for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
+                       next = bh->b_next_free;
+
+                       /* Dirty/locked buffer on clean list?  Refile it */
+                       if (buffer_locked(bh) || buffer_dirty(bh)) {
+                               ncount++;
+                               refile_buffer(bh);
+                       }
+               }
 #endif
-                                ll_rw_block(WRITE, 1, &bh);
-                                bh->b_count--;
-                                next->b_count--;
-                        }
+
+       bh = lru_list[BUF_LOCKED];
+       if(bh)
+               for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
+                       next = bh->b_next_free;
+
+                       /* Unlocked buffer on locked list?  Refile it */
+                       if (!buffer_locked(bh))
+                               refile_buffer(bh);
+               }
+
+ restart:
+       bh = lru_list[BUF_DIRTY];
+       if(bh) 
+               for (i = nr_buffers_type[BUF_DIRTY];
+                    i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
+                    bh = next) {
+                       /* We may have stalled while waiting for
+                          I/O to complete. */
+                       if(bh->b_list != BUF_DIRTY)
+                               goto restart;
+                       next = bh->b_next_free;
+                       if(!lru_list[BUF_DIRTY]) {
+                               printk("Dirty list empty %d\n", i);
+                               break;
+                       }
+                                         
+                       /* Clean buffer on dirty list?  Refile it */
+                       if (!buffer_dirty(bh)) {
+                               refile_buffer(bh);
+                               continue;
+                       }
+                                         
+                       if (buffer_locked(bh))
+                               continue;
+                       /* Should we write back buffers that are
+                          shared or not??  Currently dirty buffers
+                          are not shared, so it does not matter */
+                       next->b_count++;
+                       bh->b_count++;
+                       ndirty++;
+                       bh->b_flushtime = 0;
+                       if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
+                               ll_rw_block(wrta_cmd,1, &bh);
+                               wrta_cmd = WRITEA;
+                               if (buffer_dirty(bh))
+                                       --ndirty;
+                       }
+                       else
+                               ll_rw_block(WRITE, 1, &bh);
+                       bh->b_count--;
+                       next->b_count--;
+               }
+       /* If we didn't write anything, but there are still
+        * dirty buffers, then make the next write to a
+        * loop device to be a blocking write.
+        * This lets us block--which we _must_ do! */
+       if (ndirty == 0
+           && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+               wrta_cmd = WRITE;
+               goto restart;
        }
-       run_task_queue(&tq_disk);
+
 #ifdef DEBUG
        if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-       printk("Wrote %d/%d buffers\n", nwritten, ndirty);
+       printk("wrote %d/%d buffers...", nwritten, ndirty);
 #endif
        run_task_queue(&tq_disk);
-       return 0;
 }
 
 
@@ -1662,10 +1687,12 @@ asmlinkage int sys_bdflush(int func, long data)
        if (!capable(CAP_SYS_ADMIN))
                goto out;
 
-       if (func == 1) {
-                error = sync_old_buffers();
-                goto out;
-       }
+       if (func == 1)
+               /* Func 1 used to call sync_old_buffers; a user space
+                  daemon would call it periodically.  This is no
+                  longer necessary.  Returning -EPERM here makes the
+                  daemon silently exit.  */
+               goto out;
 
        /* Basically func 1 means read param 1, 2 means write param 1, etc */
        if (func >= 2) {
@@ -1694,27 +1721,17 @@ out:
        return error;
 }
 
-/* This is the actual bdflush daemon itself. It used to be started from
- * the syscall above, but now we launch it ourselves internally with
- * kernel_thread(...)  directly after the first thread in init/main.c */
+/* This is the actual bdflush daemon itself. It used to be started
+ * from the syscall above, but now we launch it ourselves internally
+ * with kernel_thread(...)  directly after the first thread in
+ * init/main.c.  Every so often, or when woken up by another task that
+ * needs memory, we call sync_old_buffers to partially clear the dirty list.
+ */
 
-/* To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- *     out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- *     (otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- *     with running out of free buffers for loop's "real" device).
-*/
 int bdflush(void * unused) 
 {
-       int i;
-       int ndirty;
-       int nlist;
-       int ncount;
-       struct buffer_head * bh, *next;
-       int major;
-       int wrta_cmd = WRITEA;  /* non-blocking write for LOOP */
+       long remaining = HZ * bdf_prm.b_un.interval;
+       struct task_struct *tsk = current;
 
        /*
         *      We have a bare-bones task_struct, and really should fill
@@ -1722,10 +1739,12 @@ int bdflush(void * unused)
         *      display semi-sane things. Not real crucial though...  
         */
 
-       current->session = 1;
-       current->pgrp = 1;
-       sprintf(current->comm, "kflushd");
-       bdflush_tsk = current;
+       tsk->session = 1;
+       tsk->pgrp = 1;
+       tsk->dumpable = 0;  /* inhibit ptrace() */
+       strcpy(tsk->comm, "kflushd");
+       sigfillset(&tsk->blocked);
+       bdflush_tsk = tsk;
 
        /*
         *      As a kernel thread we want to tamper with system buffers
@@ -1735,93 +1754,36 @@ int bdflush(void * unused)
        lock_kernel();
                 
        for (;;) {
+               tsk->state = TASK_INTERRUPTIBLE;
+               remaining = schedule_timeout(remaining);
+
 #ifdef DEBUG
                printk("bdflush() activated...");
 #endif
-
                CHECK_EMERGENCY_SYNC
 
-               ncount = 0;
-#ifdef DEBUG
-               for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-               for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-#endif
-                {
-                        ndirty = 0;
-                repeat:
-
-                        bh = lru_list[nlist];
-                        if(bh) 
-                                 for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
-                                      bh = next) {
-                                         /* We may have stalled while waiting for I/O to complete. */
-                                         if(bh->b_list != nlist) goto repeat;
-                                         next = bh->b_next_free;
-                                         if(!lru_list[nlist]) {
-                                                 printk("Dirty list empty %d\n", i);
-                                                 break;
-                                         }
-                                         
-                                         /* Clean buffer on dirty list?  Refile it */
-                                         if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
-                                                 refile_buffer(bh);
-                                                 continue;
-                                         }
-                                         
-                                         /* Unlocked buffer on locked list?  Refile it */
-                                         if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-                                                 refile_buffer(bh);
-                                                 continue;
-                                         }
-                                         
-                                         if (buffer_locked(bh) || !buffer_dirty(bh))
-                                                  continue;
-                                         major = MAJOR(bh->b_dev);
-                                         /* Should we write back buffers that are shared or not??
-                                            currently dirty buffers are not shared, so it does not matter */
-                                         next->b_count++;
-                                         bh->b_count++;
-                                         ndirty++;
-                                         bh->b_flushtime = 0;
-                                         if (major == LOOP_MAJOR) {
-                                                 ll_rw_block(wrta_cmd,1, &bh);
-                                                 wrta_cmd = WRITEA;
-                                                 if (buffer_dirty(bh))
-                                                         --ndirty;
-                                         }
-                                         else
-                                         ll_rw_block(WRITE, 1, &bh);
-#ifdef DEBUG
-                                         if(nlist != BUF_DIRTY) ncount++;
-#endif
-                                         bh->b_count--;
-                                         next->b_count--;
-                                 }
-                }
+               if (remaining == 0) {
+                       /*
+                        * Also try to flush inodes and supers, since
+                        * otherwise there would be no way of ensuring
+                        * that these quantities ever get written
+                        * back.  Ideally, we would have a timestamp
+                        * on the inodes and superblocks so that we
+                        * could write back only the old ones.
+                        */
+                       sync_supers(0);
+                       sync_inodes(0);
+                       remaining = HZ * bdf_prm.b_un.interval;
+               }
+                       
+               /* Keep flushing till there aren't very many dirty buffers */
+               do {
+                       sync_old_buffers();
+               } while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+
+               wake_up(&bdflush_done);
 #ifdef DEBUG
-               if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
                printk("sleeping again.\n");
 #endif
-               /* If we didn't write anything, but there are still
-                * dirty buffers, then make the next write to a
-                * loop device to be a blocking write.
-                * This lets us block--which we _must_ do! */
-               if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
-                       wrta_cmd = WRITE;
-                       continue;
-               }
-               run_task_queue(&tq_disk);
-               wake_up(&bdflush_done);
-               
-               /* If there are still a lot of dirty buffers around, skip the sleep
-                  and flush some more */
-               if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
-                       spin_lock_irq(&current->sigmask_lock);
-                       flush_signals(current);
-                       spin_unlock_irq(&current->sigmask_lock);
-
-                       interruptible_sleep_on(&bdflush_wait);
-               }
        }
 }
index 762ef1df749d067f4836e41a4aa6904ed9b67663..4a8c4a7d6a522620144f80f03c81d5dd155c785e 100644 (file)
@@ -74,8 +74,6 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
        int block, toread, i, err;
 
        *res_dir = NULL;
-       if (!dir)
-               return NULL;
        sb = dir->i_sb;
 
        if (namelen > EXT2_NAME_LEN)
index e265a7304784f009ae3d27b9ec451a766ea282a8..7d4ca4e980885913fd3ea4a339a10fadea74a8ca 100644 (file)
@@ -74,7 +74,6 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
        char c;
 
        *ino = 0;
-       if (!dir) return NULL;
        
        if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
   
index d1c3ecf81bf49c304c316bc450970acff134698a..01d833eb83cf5fe5a9f56420b4a02010f529922d 100644 (file)
@@ -263,16 +263,18 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
                if (waiter->fl_notify)
                        waiter->fl_notify(waiter);
                wake_up(&waiter->fl_wait);
-               if (wait)
+               if (wait) {
                        /* Let the blocked process remove waiter from the
                         * block list when it gets scheduled.
                         */
+                       current->policy |= SCHED_YIELD;
                        schedule();
-               else
+               } else {
                        /* Remove waiter from the block list, because by the
                         * time it wakes up blocker won't exist any more.
                         */
                        locks_delete_block(blocker, waiter);
+               }
        }
        return;
 }
index e26967d615c5c5e8d465a4d538abf56c35768700..e6d680ecf3e031986469f30370e372a7d09fa527 100644 (file)
@@ -45,7 +45,7 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
        struct minix_dir_entry *de;
 
        *res_dir = NULL;
-       if (!dir || !dir->i_sb)
+       if (!dir->i_sb)
                return NULL;
        info = &dir->i_sb->u.minix_sb;
        if (namelen > info->s_namelen) {
@@ -249,12 +249,6 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
        struct buffer_head * bh;
        struct minix_dir_entry * de;
 
-       bh = minix_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-       if (bh) {
-               brelse(bh);
-               return -EEXIST;
-       }
        inode = minix_new_inode(dir);
        if (!inode)
                return -ENOSPC;
@@ -295,12 +289,6 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
        struct minix_sb_info * info;
 
        info = &dir->i_sb->u.minix_sb;
-       bh = minix_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-       if (bh) {
-               brelse(bh);
-               return -EEXIST;
-       }
        if (dir->i_nlink >= info->s_link_max)
                return -EMLINK;
        inode = minix_new_inode(dir);
@@ -524,15 +512,6 @@ int minix_symlink(struct inode * dir, struct dentry *dentry,
        brelse(name_block);
        inode->i_size = i;
        mark_inode_dirty(inode);
-       bh = minix_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-       if (bh) {
-               inode->i_nlink--;
-               mark_inode_dirty(inode);
-               iput(inode);
-               brelse(bh);
-               return -EEXIST;
-       }
        i = minix_add_entry(dir, dentry->d_name.name,
                            dentry->d_name.len, &bh, &de);
        if (i) {
@@ -562,12 +541,6 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
        if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
                return -EMLINK;
 
-       bh = minix_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-       if (bh) {
-               brelse(bh);
-               return -EEXIST;
-       }
        error = minix_add_entry(dir, dentry->d_name.name,
                                dentry->d_name.len, &bh, &de);
        if (error) {
index 7765bbb9b75fe3a357b751fadca32dd29a9796d3..feb014b8ed236593ddafa65a5a60d7451737a481 100644 (file)
@@ -70,12 +70,8 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
        struct buffer_head *bh;
 
        *res_dir = NULL;
-       if (!dir || !dir->i_sb) {
-               if (!dir) {
-                       printk("qnx4: NULL dir.\n");
-               } else {
-                       printk("qnx4: no superblock on dir.\n");
-               }
+       if (!dir->i_sb) {
+               printk("qnx4: no superblock on dir.\n");
                return NULL;
        }
        bh = NULL;
index 38aebe9a9b80b7952051cb02a1ad53b20bd0bea2..8cea266a8ee5ec1cf1ad6bb3e80166f26ff87a39 100644 (file)
@@ -67,8 +67,6 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
        struct buffer_head * bh;
 
        *res_dir = NULL;
-       if (!dir)
-               return NULL;
        sb = dir->i_sb;
        if (namelen > SYSV_NAMELEN) {
                if (sb->sv_truncate)
index a30b187d390a5c8e9d71930821ff8df4182dbc9c..3daf77c57042d10e86f7773730c37e033b20b39b 100644 (file)
@@ -91,8 +91,6 @@ static struct buffer_head * ufs_find_entry (struct inode * dir,
        UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
        
        *res_dir = NULL;
-       if (!dir) 
-               return NULL;
        
        sb = dir->i_sb;
        flags = sb->u.ufs_sb.s_flags;
index 172543fa27a57e4b176e6b493d8cedbbef53c2c9..b37be73b2bea2a206a637f42e2e42c6dc828bf8e 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ALPHA_SYSTEM_H
 #define __ALPHA_SYSTEM_H
 
+#include <linux/config.h>
 #include <asm/pal.h>
 #include <asm/page.h>
 
index 481bd0e11ebeee365837f9cd81295fc01dd84bfa..9c373bad8c9d7f42ab5a4c83bcd4f3cae19fbd93 100644 (file)
@@ -28,6 +28,8 @@
 #define SCC_BAUD_BASE_NONE     0               /* for not connected or unused
                                                 * clock sources */
 
+#define SCC_BAUD_BASE_M147_PCLK        312500  /* 5 MHz */
+#define SCC_BAUD_BASE_M147     312500  /* 5 MHz */
 #define SCC_BAUD_BASE_MVME_PCLK        781250  /* 12.5 MHz */
 #define SCC_BAUD_BASE_MVME     625000  /* 10.000 MHz */
 #define SCC_BAUD_BASE_BVME_PCLK        781250  /* 12.5 MHz */   /* XXX ??? */
index 74930a3819a6e48fac0ad475f6d361935add8e8f..871d051fe378c76dd65ea0fa8c2ecbd4928bf069 100644 (file)
@@ -219,9 +219,10 @@ struct bootversion {
 #define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
 #define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
 #define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define MVME147_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 #define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
-
+#define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
 
 #ifdef BOOTINFO_COMPAT_1_0
 
diff --git a/include/asm-m68k/dvma.h b/include/asm-m68k/dvma.h
new file mode 100644 (file)
index 0000000..f6976b4
--- /dev/null
@@ -0,0 +1,165 @@
+/* $Id: dvma.h,v 1.4 1999/03/27 20:23:41 tsbogend Exp $
+ * include/asm-m68k/dma.h
+ *
+ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
+ * 
+ * Hacked to fit Sun3x needs by Thomas Bogendoerfer
+ */
+
+#ifndef __M68K_DVMA_H
+#define __M68K_DVMA_H
+
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  __volatile__ unsigned long cond_reg; /* DMA condition register */
+  __volatile__ unsigned long st_addr;  /* Start address of this transfer */
+  __volatile__ unsigned long  cnt;     /* How many bytes to transfer */
+  __volatile__ unsigned long dma_test; /* DMA test register */
+};
+
+/* DVMA chip revisions */
+enum dvma_rev {
+       dvmarev0,
+       dvmaesc1,
+       dvmarev1,
+       dvmarev2,
+       dvmarev3,
+       dvmarevplus,
+       dvmahme
+};
+
+#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+       struct Linux_SBus_DMA *next;
+       struct linux_sbus_device *SBus_dev;
+       struct sparc_dma_registers *regs;
+
+       /* Status, misc info */
+       int node;                /* Prom node for this DMA device */
+       int running;             /* Are we doing DMA now? */
+       int allocated;           /* Are we "owned" by anyone yet? */
+
+       /* Transfer information. */
+       unsigned long addr;      /* Start address of current transfer */
+       int nbytes;              /* Size of current transfer */
+       int realbytes;           /* For splitting up large transfers, etc. */
+
+       /* DMA revision */
+       enum dvma_rev revision;
+};
+
+extern struct Linux_SBus_DMA *dma_chain;
+
+/* Broken hardware... */
+#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
+#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURST8    0x00040000        /* ENET: SBUS r/w burst size */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* Determine highest possible final transfer address given a base */
+#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
+
+/* Yes, I hack a lot of elisp in my spare time... */
+#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
+#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
+#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
+#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
+#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
+#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
+#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
+#define DMA_BEGINDMA_W(regs) \
+        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
+#define DMA_BEGINDMA_R(regs) \
+        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
+
+/* For certain DMA chips, we need to disable ints upon irq entry
+ * and turn them back on when we are done.  So in any ESP interrupt
+ * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
+ * when leaving the handler.  You have been warned...
+ */
+#define DMA_IRQ_ENTRY(dma, dregs) do { \
+        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
+   } while (0)
+
+#define DMA_IRQ_EXIT(dma, dregs) do { \
+       if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
+   } while(0)
+
+/* Reset the friggin' thing... */
+#define DMA_RESET(dma) do { \
+       struct sparc_dma_registers *regs = dma->regs;                      \
+       /* Let the current FIFO drain itself */                            \
+       sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
+       /* Reset the logic */                                              \
+       regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
+       __delay(400);                         /* let the bits set ;) */    \
+       regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
+       sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
+       /* Enable FAST transfers if available */                           \
+       if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
+       dma->running = 0;                                                  \
+} while(0)
+
+extern unsigned long dvma_alloc (unsigned long, unsigned long);
+extern void dvma_free (unsigned long, unsigned long);
+
+#endif /* !(__M68K_DVMA_H) */
diff --git a/include/asm-m68k/floppy.h b/include/asm-m68k/floppy.h
new file mode 100644 (file)
index 0000000..eace8b5
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Q40 Architecture specific parts of the Floppy driver
+ *
+ * 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.
+ *
+ * Copyright (C) 1999
+ */
+
+#include <asm/io.h>
+
+#include <linux/vmalloc.h>
+
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs);
+
+#define MAX_DMA_ADDRESS   0x00  /* nothing like that */
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dma_spin_lock, flags);
+       return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+       spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+
+
+#define fd_inb(port)                   inb_p(port)
+#define fd_outb(port,value)            outb_p(port,value)
+
+
+#define fd_request_dma()        vdma_request_dma(FLOPPY_DMA,"floppy")
+/*#define fd_free_dma()           */
+
+
+#define fd_get_dma_residue()    vdma_get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size) vdma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
+
+
+#define fd_enable_irq()           /* nothing... */
+#define fd_disable_irq()          /* nothing... */
+#define fd_free_irq()          free_irq(FLOPPY_IRQ, NULL)
+
+#define fd_free_dma()             /* nothing */
+
+/* No 64k boundary crossing problems on Q40 - no DMA at all */
+#define CROSS_64KB(a,s) (0)
+
+#define DMA_MODE_READ  0x44    /* i386 look-alike */
+#define DMA_MODE_WRITE 0x48
+
+
+static int q40_floppy_init(void)
+{
+  use_virtual_dma =1;
+  /* FLOPPY_IRQ=6; */
+
+  if (MACH_IS_Q40)  
+    return 0x3f0;
+  else
+    return -1;
+}
+
+
+
+
+/*
+ * Again, the CMOS information doesn't work on the Q40..
+ */
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+
+
+
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+
+
+
+/* basically PC init + set use_virtual_dma */
+#define  FDC1 q40_floppy_init()
+static int FDC2 = -1;
+
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+
+
+/* vdma stuff adapted from asm-i386/floppy.h */
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+
+
+static int fd_request_irq(void)
+{
+  return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+                                                  "floppy", NULL);
+}
+
+/*#define SLOW_DOWN do{outb(0,0x80);}while(0)*/
+#define SLOW_DOWN do{int count=1;do{if(!jiffies)break;}while(count-->0);}while(0)
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+       register unsigned char st;
+
+#undef TRACE_FLPY_INT
+#define NO_FLOPPY_ASSEMBLER
+
+#ifdef TRACE_FLPY_INT 
+       static int calls=0;
+       static int bytes=0;
+       static int dma_wait=0;
+#endif
+       if(!doing_pdma) {
+               floppy_interrupt(irq, dev_id, regs);
+               return;
+       }
+
+#ifdef TRACE_FLPY_INT
+       if(!calls)
+               bytes = virtual_dma_count;
+#endif
+
+       {
+               register int lcount;
+               register char *lptr;
+
+               /* serve 1st byte fast: */
+
+               st=1;
+               for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+                   lcount; lcount--, lptr++) {
+                       st=inb(virtual_dma_port+4) & 0xa0 ;
+                       if(st != 0xa0) 
+                               break;
+                       if(virtual_dma_mode)
+                               outb_p(*lptr, virtual_dma_port+5);
+                       else
+                               *lptr = inb_p(virtual_dma_port+5);
+               }
+
+               virtual_dma_count = lcount;
+               virtual_dma_addr = lptr;
+               st = inb(virtual_dma_port+4);
+       }
+
+#ifdef TRACE_FLPY_INT
+       calls++;
+#endif
+       if(st == 0x20)
+               return;
+       if(!(st & 0x20)) {
+               virtual_dma_residue += virtual_dma_count;
+               virtual_dma_count=0;
+#ifdef TRACE_FLPY_INT
+               printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 
+                      virtual_dma_count, virtual_dma_residue, calls, bytes,
+                      dma_wait);
+               calls = 0;
+               dma_wait=0;
+#endif
+               doing_pdma = 0;
+               floppy_interrupt(irq, dev_id, regs);
+               return;
+       }
+#ifdef TRACE_FLPY_INT
+       if(!virtual_dma_count)
+               dma_wait++;
+#endif
+}
+
+
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+       return 0;
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+       return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+       return (unsigned long) vmalloc(size);
+
+}
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+        vfree((void *)addr);
+}
+#define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
+
+
+/* choose_dma_mode ???*/
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+       doing_pdma = 1;
+       virtual_dma_port = io;
+       virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+       virtual_dma_addr = addr;
+       virtual_dma_count = size;
+       virtual_dma_residue = 0;
+       return 0;
+}
+
+
+
+static void fd_disable_dma(void)
+{
+       doing_pdma = 0;
+       virtual_dma_residue += virtual_dma_count;
+       virtual_dma_count=0;
+}
+
+
+
index a590528a7352707fb2e0542d92c5c948c3c58d6f..da5753ee77f535e6f73db1b76182128def2ae9d8 100644 (file)
 #include <asm/macints.h>
 #endif
 
+
+typedef unsigned int   q40ide_ioreg_t;
+
+
 typedef unsigned char * ide_ioreg_t;
 
+
 #ifndef MAX_HWIFS
 #define MAX_HWIFS      4       /* same as the other archs */
 #endif
 
-static __inline int ide_default_irq (ide_ioreg_t base)
+int q40ide_default_irq(q40ide_ioreg_t);
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-       return 0;
+        if (MACH_IS_Q40)
+             return q40ide_default_irq((q40ide_ioreg_t) base);
+       else return 0;
 }
 
+
 /*
  *  Can we do this in a generic manner??
  */
+void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq);
+
 static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+      return q40_ide_init_hwif_ports((q40ide_ioreg_t *)p,(q40ide_ioreg_t)base,irq);
+#endif
     printk("ide_init_hwif_ports: must not be called\n");
 }
 
@@ -86,6 +102,10 @@ static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, voi
        if (MACH_IS_AMIGA)
                return request_irq(irq, handler, 0, device, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+       if (MACH_IS_Q40)
+               return request_irq(irq, handler, 0, device, dev_id);
+#endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
        if (MACH_IS_MAC)
 #if 0  /* MSch Hack: maybe later we'll call ide_intr without a wrapper */
@@ -103,6 +123,10 @@ static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
        if (MACH_IS_AMIGA)
                free_irq(irq, dev_id);
 #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+       if (MACH_IS_Q40)
+               free_irq(irq, dev_id);
+#endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
        if (MACH_IS_MAC)
                nubus_free_irq(12);
@@ -119,10 +143,18 @@ static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            request_region((q40ide_ioreg_t)from,extent,name);
+#endif
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            release_region((q40ide_ioreg_t)from,extent);
+#endif
 }
 
 #undef SUPPORT_SLOW_DATA_PORTS
@@ -131,14 +163,36 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
+/* this definition is used only on startup .. */
+#ifndef CONFIG_Q40
 #undef HD_DATA
 #define HD_DATA NULL
+#else
+#ifdef MACH_Q40_ONLY
+#undef HD_DATA
+#define HD_DATA ((ide_ioreg_t)0x1f0)
+#else
+#undef HD_DATA
+#define HD_DATA   (MACH_IS_Q40 ? (ide_ioreg_t)0x1f0 : 0)
+#endif
+#endif
+
 
 #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
 #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
 
+#ifdef CONFIG_Q40
+#ifdef MACH_Q40_ONLY
+#define ADDR_TRANS(_addr_) (Q40_ISA_IO_W(_addr_))
+#else
+#define ADDR_TRANS(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#endif
+#else
+#define ADDR_TRANS(_addr_) (_addr_)
+#endif
+
 #define insw(port, buf, nr) ({                         \
-       unsigned char *_port = (unsigned char *)(port); \
+       unsigned char *_port = (unsigned char *) ADDR_TRANS(port);      \
        unsigned char *_buf = (buf);                    \
        int _nr = (nr);                                 \
        unsigned long _tmp;                             \
@@ -179,7 +233,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 })
 
 #define outsw(port, buf, nr) ({                                \
-       unsigned char *_port = (unsigned char *)(port); \
+       unsigned char *_port = (unsigned char *) ADDR_TRANS(port);      \
        unsigned char *_buf = (buf);                    \
        int _nr = (nr);                                 \
        unsigned long _tmp;                             \
@@ -219,7 +273,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
        }                                               \
 })
 
-#ifdef CONFIG_ATARI
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
 #define insl_swapw(data_reg, buffer, wcount) \
     insw_swapw(data_reg, buffer, (wcount)<<1)
 #define outsl_swapw(data_reg, buffer, wcount) \
@@ -236,7 +290,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
                 rolw  #8,%/d0; \
                 movew %/d0,%/a1@+; \
                 dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
+               : "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
                : "d0", "a0", "a1", "d6"); \
     else \
        __asm__ __volatile__ \
@@ -270,8 +324,9 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
                 rolw  #8,%/d0; \
                 movew %/d0,%/a1@+; \
                 dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
-               : "d0", "a0", "a1", "d6")
+               : "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
+               : "d0", "a0", "a1", "d6") 
+
 
 #define outsw_swapw(port, buf, nr) \
     if ((nr) % 8) \
@@ -284,7 +339,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
                 rolw  #8,%/d0; \
                 movew %/d0,%/a0@; \
                 dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
+               : "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
                : "d0", "a0", "a1", "d6"); \
     else \
        __asm__ __volatile__ \
@@ -318,7 +373,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
                 rolw  #8,%/d0; \
                 movew %/d0,%/a0@; \
                 dbra %/d6,1b" : \
-               : "g" (port), "g" (buf), "g" (nr) \
+               : "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
                : "d0", "a0", "a1", "d6")
 
 #endif /* CONFIG_ATARI */
index d14dd3ed5eeb73d79da55a2234a0ab5f5af8419f..555ef68ec6fda2d2dc25bd74c6081a7595b69919 100644 (file)
 
 #include <asm/machdep.h>
 
+#ifdef CONFIG_Q40
+#include <asm/q40_keyboard.h>
+#endif
+
 static __inline__ int kbd_setkeycode(unsigned int scancode,
                                     unsigned int keycode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_setkeycode(scancode,keycode);
+#endif
     return -EOPNOTSUPP;
 }
 
 static __inline__ int kbd_getkeycode(unsigned int scancode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_getkeycode(scancode);
+#endif
     return scancode > 127 ? -EINVAL : scancode;
 }
 
 static __inline__ int kbd_translate(unsigned char scancode,
                                    unsigned char *keycode, char raw_mode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_translate(scancode,keycode,raw_mode);
+#endif
     *keycode = scancode;
     return 1;
 }
 
 static __inline__ char kbd_unexpected_up(unsigned char keycode)
 {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_unexpected_up(keycode);
+#endif
     return 0200;
 }
 
diff --git a/include/asm-m68k/mvme147hw.h b/include/asm-m68k/mvme147hw.h
new file mode 100644 (file)
index 0000000..f57216b
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _MVME147HW_H_
+#define _MVME147HW_H_
+
+typedef struct {
+       unsigned char
+               ctrl,
+               bcd_sec,
+               bcd_min,
+               bcd_hr,
+               bcd_dow,
+               bcd_dom,
+               bcd_mth,
+               bcd_year;
+} MK48T02;
+
+#define RTC_WRITE      0x80
+#define RTC_READ       0x40
+#define RTC_STOP       0x20
+
+#define m147_rtc ((MK48T02 * volatile)0xfffe07f8)
+
+
+struct pcc_regs {
+   volatile u_long     dma_tadr;
+   volatile u_long     dma_dadr;
+   volatile u_long     dma_bcr;
+   volatile u_long     dma_hr;
+   volatile u_short    t1_preload;
+   volatile u_short    t1_count;
+   volatile u_short    t2_preload;
+   volatile u_short    t2_count;
+   volatile u_char     t1_int_cntrl;
+   volatile u_char     t1_cntrl;
+   volatile u_char     t2_int_cntrl;
+   volatile u_char     t2_cntrl;
+   volatile u_char     ac_fail;
+   volatile u_char     watchdog;
+   volatile u_char     lpt_intr;
+   volatile u_char     lpt_cntrl;
+   volatile u_char     dma_intr;
+   volatile u_char     dma_cntrl;
+   volatile u_char     bus_error;
+   volatile u_char     dma_status;
+   volatile u_char     abort;
+   volatile u_char     ta_fnctl;
+   volatile u_char     serial_cntrl;
+   volatile u_char     general_cntrl;
+   volatile u_char     lan_cntrl;
+   volatile u_char     general_status;
+   volatile u_char     scsi_interrupt;
+   volatile u_char     slave;
+   volatile u_char     soft1_cntrl;
+   volatile u_char     int_base;
+   volatile u_char     soft2_cntrl;
+   volatile u_char     revision_level;
+   volatile u_char     lpt_data;
+   volatile u_char     lpt_status;
+   };
+
+#define m147_pcc ((struct pcc_regs * volatile)0xfffe1000)
+
+
+#define PCC_INT_ENAB           0x08
+
+#define PCC_TIMER_INT_CLR      0x80
+#define PCC_TIMER_PRELOAD      63936l
+
+#define PCC_LEVEL_ABORT                0x07
+#define PCC_LEVEL_SERIAL       0x04
+#define PCC_LEVEL_ETH          0x04
+#define PCC_LEVEL_TIMER1       0x04
+#define PCC_LEVEL_SCSI_PORT    0x04
+#define PCC_LEVEL_SCSI_DMA     0x04
+
+#define PCC_IRQ_AC_FAIL                0x40
+#define PCC_IRQ_BERR           0x41
+#define PCC_IRQ_ABORT          0x42
+/* #define PCC_IRQ_SERIAL      0x43 */
+#define PCC_IRQ_PRINTER                0x47
+#define PCC_IRQ_TIMER1         0x48
+#define PCC_IRQ_TIMER2         0x49
+#define PCC_IRQ_SOFTWARE1      0x4a
+#define PCC_IRQ_SOFTWARE2      0x4b
+
+
+#define M147_SCC_A_ADDR                0xfffe3002
+#define M147_SCC_B_ADDR                0xfffe3000
+
+#define MVME147_IRQ_SCSI_PORT  0x45
+#define MVME147_IRQ_SCSI_DMA   0x46
+
+/* SCC interrupts, for MVME162 */
+
+#define MVME147_IRQ_TYPE_PRIO  0
+#define MVME147_IRQ_SCC_BASE           0x60
+#define MVME147_IRQ_SCCB_TX            0x60
+#define MVME147_IRQ_SCCB_STAT          0x62
+#define MVME147_IRQ_SCCB_RX            0x64
+#define MVME147_IRQ_SCCB_SPCOND                0x66
+#define MVME147_IRQ_SCCA_TX            0x68
+#define MVME147_IRQ_SCCA_STAT          0x6a
+#define MVME147_IRQ_SCCA_RX            0x6c
+#define MVME147_IRQ_SCCA_SPCOND                0x6e
+
+#define MVME147_LANCE_BASE     0xfffe1800
+#define MVME147_LANCE_IRQ      0x44
+
+#define ETHERNET_ADDRESS 0xfffe0778
+
+#endif
diff --git a/include/asm-m68k/oplib.h b/include/asm-m68k/oplib.h
new file mode 100644 (file)
index 0000000..4ef5f03
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * prototypes for dummy prom_* routines
+ */
+
+extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getbool(int node, char *prop);
+extern void prom_printf(char *fmt, ...);
+extern void prom_halt(void) __attribute__ ((noreturn));
index a3fe87e71a5b1997b9613d92182ac4b596310788..87384b8ae4ed8dbdfd3f547eac8a72790c5b6c54 100644 (file)
@@ -110,7 +110,22 @@ typedef unsigned long pgprot_t;
 /* This handles the memory map.. */
 #define PAGE_OFFSET            0
 #define __pa(x)                        ((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x)                        ((void *)((unsigned long)(x)+PAGE_OFFSET))
+/*
+ * A hacky workaround for the problems with mmap() of frame buffer
+ * memory in the lower 16MB physical memoryspace.
+ *
+ * This is a short term solution, we will have to deal properly
+ * with this in 2.3.x.
+ */
+extern inline void *__va(unsigned long physaddr)
+{
+#ifdef CONFIG_AMIGA
+       if (MACH_IS_AMIGA && (physaddr < 16*1024*1024))
+               return (void *)0xffffffff;
+       else
+#endif
+               return (void *)(physaddr+PAGE_OFFSET);
+}
 #define MAP_NR(addr)           (__pa(addr) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
index 4e276445e7954ee999f01486d77e5260ac1dfd3a..1e6f317eead92e9981213106a661dfa55077430e 100644 (file)
@@ -507,6 +507,7 @@ extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
        if (tsk == current) {
                if (CPU_IS_040_OR_060)
                        __asm__ __volatile__ (".chip 68040\n\t"
+                                             "pflushan\n\t"
                                              "movec %0,%%urp\n\t"
                                              ".chip 68k"
                                              : : "r" (tsk->tss.crp[1]));
@@ -514,10 +515,22 @@ extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
                        unsigned long tmp;
                        __asm__ __volatile__ ("movec  %%cacr,%0\n\t"
                                              "orw #0x0808,%0\n\t"
-                                             "movec %0,%%cacr\n\t"
-                                             "pmove %1,%%crp\n\t"
-                                             : "=d" (tmp)
-                                             : "m" (tsk->tss.crp[0]));
+                                             "movec %0,%%cacr"
+                                             : "=d" (tmp));
+                       /* For a 030-only kernel, avoid flushing the whole
+                          ATC, we only need to flush the user entries.
+                          The 68851 does this by itself.  Avoid a runtime
+                          check here.  */
+                       __asm__ __volatile__ (
+#ifdef CPU_M68030_ONLY
+                                             ".chip 68030\n\t"
+                                             "pmovefd %0,%%crp\n\t"
+                                             ".chip 68k\n\t"
+                                             "pflush #0,#4"
+#else
+                                             "pmove %0,%%crp"
+#endif
+                                             : : "m" (tsk->tss.crp[0]));
                }
        }
 }
diff --git a/include/asm-m68k/q40_keyboard.h b/include/asm-m68k/q40_keyboard.h
new file mode 100644 (file)
index 0000000..e3712d2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  linux/include/asm-m68k/q40_keyboard.h
+ *
+ *  Created 
+ */
+
+/*
+ *  This file contains the Q40 specific keyboard definitions
+ */
+
+
+#include <linux/config.h> /* CONFIG_MAGIC_SYSRQ */
+
+
+
+#ifdef __KERNEL__
+
+
+#include <asm/machdep.h>
+
+
+
+extern int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int q40kbd_getkeycode(unsigned int scancode);
+extern int q40kbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+                          char raw_mode);
+extern char q40kbd_unexpected_up(unsigned char keycode);
+extern void q40kbd_leds(unsigned char leds);
+extern int q40kbd_is_sysrq(unsigned char keycode);
+extern void q40kbd_init_hw(void);
+extern unsigned char q40kbd_sysrq_xlate[128];
+
+
+#if 0
+#define kbd_setkeycode         q40kbd_setkeycode
+#define kbd_getkeycode         q40kbd_getkeycode
+#define kbd_pretranslate       q40kbd_pretranslate
+#define kbd_translate          q40kbd_translate
+#define kbd_unexpected_up      q40kbd_unexpected_up
+#define kbd_leds               q40kbd_leds
+#define kbd_init_hw            q40kbd_init_hw
+#define kbd_is_sysrq           q40kbd_is_sysrq
+#define kbd_sysrq_xlate                q40kbd_sysrq_xlate
+
+
+#define SYSRQ_KEY 0x54
+#endif
+#endif /* __KERNEL__ */
+
+
+
+
+
diff --git a/include/asm-m68k/q40_master.h b/include/asm-m68k/q40_master.h
new file mode 100644 (file)
index 0000000..b7e365b
--- /dev/null
@@ -0,0 +1,75 @@
+/* 
+ * Q40 master Chip Control 
+ * RTC stuff merged for compactnes..
+*/
+
+#if 1
+#define q40_master_addr 0xff000000
+#define q40_rtc_addr    0xff021ffc
+#else
+extern unsigned long q40_master_addr;  /* wherever it is mapped ... */
+extern unsigned long q40_rtc_addr;
+#endif
+
+#define IIRQ_REG            0x0       /* internal IRQ reg */
+#define EIRQ_REG            0x4       /* external ... */
+#define KEYCODE_REG         0x1c      /* value of received scancode  */
+#define DISPLAY_CONTROL_REG 0x18
+#define FRAME_CLEAR_REG     0x24
+
+#define INTERRUPT_REG       IIRQ_REG  /* "native" ints */
+#define KEY_IRQ_ENABLE_REG  0x08      /**/
+#define KEYBOARD_UNLOCK_REG 0x20      /* clear kb int */
+
+#define SAMPLE_ENABLE_REG   0x14      /* generate SAMPLE ints */
+#define SAMPLE_RATE_REG     0x28
+#define SAMPLE_CLEAR_REG    0x28
+#define SAMPLE_LOW          0x00
+#define SAMPLE_HIGH         0x01
+
+#define FRAME_RATE_REG       0x38      /* generate FRAME ints at 200 HZ rate */
+
+#if 0
+#define SER_ENABLE_REG      0x0c      /* allow serial ints to be generated */
+#endif
+#define EXT_ENABLE_REG      0x10      /* ... rest of the ISA ints ... */
+
+#define master_inb(_reg_)           (*(((unsigned char *)q40_master_addr)+_reg_))
+#define master_outb(_b_,_reg_)      (*(((unsigned char *)q40_master_addr)+_reg_)=(_b_))
+
+
+/* define some Q40 specific ints */
+#include "q40ints.h"
+
+/* RTC defines */
+
+#define Q40_RTC_BASE (q40_rtc_addr)
+
+#define RTC_YEAR        (*(unsigned char *)(Q40_RTC_BASE+0))
+#define RTC_MNTH        (*(unsigned char *)(Q40_RTC_BASE-4))
+#define RTC_DATE        (*(unsigned char *)(Q40_RTC_BASE-8))
+#define RTC_DOW         (*(unsigned char *)(Q40_RTC_BASE-12))
+#define RTC_HOUR        (*(unsigned char *)(Q40_RTC_BASE-16))
+#define RTC_MINS        (*(unsigned char *)(Q40_RTC_BASE-20))
+#define RTC_SECS        (*(unsigned char *)(Q40_RTC_BASE-24))
+#define RTC_CTRL        (*(unsigned char *)(Q40_RTC_BASE-28))
+
+
+#if 0
+struct RTC_STRUCT{ 
+  unsigned char bcd_year;
+  unsigned char bcd_mth;
+  unsigned char bcd_dom;
+  unsigned char bcd_dayofweek;
+  unsigned char bcd_hr;
+  unsigned char bcd_min;
+  unsigned char bcd_sec;
+  unsigned char ctrl;
+};
+typedef struct RTC_STRUCT *RtcPtr_t;
+#endif
+
+
+/* some control bits */
+#define RTC_READ   64  /* prepare for reading */
+#define RTC_WRITE  128
diff --git a/include/asm-m68k/q40ints.h b/include/asm-m68k/q40ints.h
new file mode 100644 (file)
index 0000000..f5e29c9
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * contains some Q40 related interrupt definitions
+ */
+
+#define Q40_IRQ_MAX      (34)
+
+#define Q40_IRQ_TIMER    (34)
+#define Q40_IRQ_KEYBOARD (32)
+#define Q40_IRQ_FRAME    (33)
+
+
+/* masks for interrupt regiosters*/
+/* internal, IIRQ_REG */
+#define IRQ_KEYB_MASK    (2)
+#define IRQ_SER_MASK     (1<<2)
+#define IRQ_FRAME_MASK   (1<<3)
+#define IRQ_EXT_MASK     (1<<4)    /* is a EIRQ */
+/* eirq, EIRQ_REG */
+#define IRQ3_MASK        (1)
+#define IRQ4_MASK        (1<<1)
+#define IRQ5_MASK        (1<<2)
+#define IRQ6_MASK        (1<<3)
+#define IRQ7_MASK        (1<<4)
+#define IRQ10_MASK       (1<<5)
+#define IRQ14_MASK       (1<<6)
+#define IRQ15_MASK       (1<<7)
+
+extern unsigned long q40_probe_irq_on (void);
+extern int q40_probe_irq_off (unsigned long irqs);
index 885ca61468b7902d86c5e428e67edc8c130ca167..08691d6532d5a6a2953d5e2fc2f6401895d46a5a 100644 (file)
@@ -6,6 +6,14 @@ struct scatterlist {
     char * alt_address; /* Location of actual if address is a 
                         * dma indirect buffer.  NULL otherwise */
     unsigned int length;
+    unsigned long dvma_address;
+};
+
+struct mmu_sglist {
+        char *addr;
+        char *__dont_touch;
+        unsigned int len;
+        unsigned long dvma_addr;
 };
 
 /* This is bogus and should go away. */
diff --git a/include/asm-m68k/semaphore-helper.h b/include/asm-m68k/semaphore-helper.h
new file mode 100644 (file)
index 0000000..5e3abe0
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef _M68K_SEMAPHORE_HELPER_H
+#define _M68K_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * m68k version by Andreas Schwab
+ */
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+       atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+       int ret;
+#ifndef CONFIG_RMW_INSNS
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 0;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&sem->waking);
+               ret = 1;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+       int tmp1, tmp2;
+
+       __asm__ __volatile__
+         ("1:  movel   %1,%2\n"
+          "    jle     2f\n"
+          "    subql   #1,%2\n"
+          "    casl    %1,%2,%3\n"
+          "    jne     1b\n"
+          "    moveq   #1,%0\n"
+          "2:"
+          : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+          : "m" (sem->waking), "0" (0), "1" (sem->waking));
+#endif
+
+       return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *     1       got the lock
+ *     0       go to sleep
+ *     -EINTR  interrupted
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+                                               struct task_struct *tsk)
+{
+       int ret;
+#ifndef CONFIG_RMW_INSNS
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 0;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&sem->waking);
+               ret = 1;
+       } else if (signal_pending(tsk)) {
+               atomic_inc(&sem->count);
+               ret = -EINTR;
+       }
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+       int tmp1, tmp2;
+
+       __asm__ __volatile__
+         ("1:  movel   %1,%2\n"
+          "    jle     2f\n"
+          "    subql   #1,%2\n"
+          "    casl    %1,%2,%3\n"
+          "    jne     1b\n"
+          "    moveq   #1,%0\n"
+          "    jra     %a4\n"
+          "2:"
+          : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+          : "m" (sem->waking), "i" (&&next), "0" (0), "1" (sem->waking));
+       if (signal_pending(tsk)) {
+               atomic_inc(&sem->count);
+               ret = -EINTR;
+       }
+next:
+#endif
+
+       return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *     1       failed to lock
+ *     0       got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+       int ret;
+#ifndef CONFIG_RMW_INSNS
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 1;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&sem->waking);
+               ret = 0;
+       } else
+               atomic_inc(&sem->count);
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+       int tmp1, tmp2;
+
+       __asm__ __volatile__
+         ("1:  movel   %1,%2\n"
+          "    jle     2f\n"
+          "    subql   #1,%2\n"
+          "    casl    %1,%2,%3\n"
+          "    jne     1b\n"
+          "    moveq   #0,%0\n"
+          "2:"
+          : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+          : "m" (sem->waking), "0" (1), "1" (sem->waking));
+       if (ret)
+               atomic_inc(&sem->count);
+#endif
+       return ret;
+}
+
+#endif
index 9d05256df3d9e6c7af7b0c937567717484aa215d..271169bbca57ac2c85a34538b9db085686ec2216 100644 (file)
@@ -3,9 +3,10 @@
 
 #include <linux/config.h>
 #include <linux/linkage.h>
-#include <asm/current.h>
+
 #include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/spinlock.h>
 
 /*
  * SMP- and interrupt-safe semaphores..
 
 struct semaphore {
        atomic_t count;
-       unsigned long owner, owner_depth;
        atomic_t waking;
        struct wait_queue * wait;
 };
 
-/*
- * Because we want the non-contention case to be
- * fast, we save the stack pointer into the "owner"
- * field, and to get the true task pointer we have
- * to do the bit masking. That moves the masking
- * operation into the slow path.
- */
-#define semaphore_owner(sem) \
-       ((struct task_struct *)((2*PAGE_MASK) & (sem)->owner))
-
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, 0, ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, 1, ATOMIC_INIT(0), NULL })
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
 asmlinkage void __up_wakeup(void /* special register calling convention */);
 
-extern void __down(struct semaphore * sem);
-extern int  __down_interruptible(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
 
 #define sema_init(sem, val)    atomic_set(&((sem)->count), val)
 
-static inline void wake_one_more(struct semaphore * sem)
-{
-       atomic_inc(&sem->waking);
-}
-
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
-{
-#ifndef CONFIG_RMW_INSNS
-       unsigned long flags;
-       int ret = 0;
-
-       save_flags(flags);
-       cli();
-       if (atomic_read(&sem->waking) > 0 || (owner_depth && semaphore_owner(sem) == tsk)) {
-               sem->owner = (unsigned long)tsk;
-               sem->owner_depth++;
-               atomic_dec(&sem->waking);
-               ret = 1;
-       }
-       restore_flags(flags);
-#else
-       int ret, tmp;
-
-       __asm__ __volatile__
-         ("1:  movel   %2,%0\n"
-          "    jeq     3f\n"
-          "2:  movel   %0,%1\n"
-          "    subql   #1,%1\n"
-          "    casl    %0,%1,%2\n"
-          "    jeq     3f\n"
-          "    tstl    %0\n"
-          "    jne     2b\n"
-          "3:"
-          : "=d" (ret), "=d" (tmp), "=m" (sem->waking));
-
-       ret |= ((sem->owner_depth != 0) && (semaphore_owner(sem) == tsk));
-       if (ret) {
-               sem->owner = (unsigned long)tsk;
-               sem->owner_depth++;
-       }
-
-#endif
-       return ret;
-}
-
 /*
  * This is ugly, but we want the default case to fall through.
  * "down_failed" is a special asm handler that calls the C
@@ -102,8 +49,6 @@ extern inline void down(struct semaphore * sem)
                "| atomic down operation\n\t"
                "subql #1,%0@\n\t"
                "jmi 2f\n\t"
-               "movel %%sp,4(%0)\n"
-               "movel #1,8(%0)\n\t"
                "1:\n"
                ".section .text.lock,\"ax\"\n"
                ".even\n"
@@ -124,9 +69,6 @@ extern inline int down_interruptible(struct semaphore * sem)
                "| atomic interruptible down operation\n\t"
                "subql #1,%1@\n\t"
                "jmi 2f\n\t"
-               "movel %%sp,4(%1)\n"
-               "moveql #1,%0\n"
-               "movel %0,8(%1)\n"
                "clrl %0\n"
                "1:\n"
                ".section .text.lock,\"ax\"\n"
@@ -140,6 +82,28 @@ extern inline int down_interruptible(struct semaphore * sem)
        return result;
 }
 
+extern inline int down_trylock(struct semaphore * sem)
+{
+       register struct semaphore *sem1 __asm__ ("%a1") = sem;
+       register int result __asm__ ("%d0");
+
+       __asm__ __volatile__(
+               "| atomic down trylock operation\n\t"
+               "subql #1,%1@\n\t"
+               "jmi 2f\n\t"
+               "clrl %0\n"
+               "1:\n"
+               ".section .text.lock,\"ax\"\n"
+               ".even\n"
+               "2:\tpea 1b\n\t"
+               "jbra __down_failed_trylock\n"
+               ".previous"
+               : "=d" (result)
+               : "a" (sem1)
+               : "%d0", "memory");
+       return result;
+}
+
 /*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
@@ -151,13 +115,13 @@ extern inline void up(struct semaphore * sem)
        register struct semaphore *sem1 __asm__ ("%a1") = sem;
        __asm__ __volatile__(
                "| atomic up operation\n\t"
-               "subql #1,8(%0)\n\t"
                "addql #1,%0@\n\t"
                "jle 2f\n"
                "1:\n"
                ".section .text.lock,\"ax\"\n"
                ".even\n"
-               "2:\tpea 1b\n\t"
+               "2:\t"
+               "pea 1b\n\t"
                "jbra __up_wakeup\n"
                ".previous"
                : /* no outputs */
index a5f0abeb332db458d4085c2fafd4f62ddccab7c0..15cc547a073b515498870a443a88e390ce856a58 100644 (file)
 /*
- * include/linux/serial.h
+ * include/asm-m68k/serial.h
  *
- * Copyright (C) 1992 by Theodore Ts'o.
- * 
- * Redistribution of this file is permitted under the terms of the GNU 
- * Public License (GPL)
- */
-
-#ifndef _M68K_SERIAL_H
-#define _M68K_SERIAL_H
-
-
-/* m68k serial port types are numbered from 100 to avoid interference
- * with the PC types (1..4)
- */
-#define PORT_UNKNOWN   0
-#define PORT_8250      1
-#define PORT_16450     2
-#define PORT_16550     3
-#define PORT_16550A    4
-#define PORT_CIRRUS     5
-#define PORT_16650V2   7
-#define PORT_16750     8
-
-#define SER_SCC_NORM   100     /* standard SCC channel */
-#define        SER_SCC_DMA     101     /* SCC channel with DMA support */
-#define        SER_MFP_CTRL    102     /* standard MFP port with modem control signals */
-#define        SER_MFP_BARE    103     /* MFP port without modem controls */
-#define        SER_MIDI        104     /* Atari MIDI */
-#define        SER_AMIGA       105     /* Amiga built-in serial port */
-#define SER_IOEXT      106     /* Amiga GVP IO-Extender (16c552) */
-#define SER_MFC_III    107     /* Amiga BSC Multiface Card III (MC68681) */
-#define SER_WHIPPET    108     /* Amiga Hisoft Whippet PCMCIA (16c550B) */
-#define SER_SCC_MVME   109     /* MVME162/MVME172 ports */
-#define SER_SCC_MAC    110     /* Macintosh SCC channel */
-#define SER_HPDCA      111     /* HP DCA serial */
-#define SER_SCC_BVME   112     /* BVME6000 ports */
-
-struct serial_struct {
-       int     type;
-       int     line;
-       int     port;
-       int     irq;
-       int     flags;
-       int     xmit_fifo_size;
-       int     custom_divisor;
-       int     baud_base;
-       unsigned short  close_delay;
-       char    reserved_char[2];
-       int     hub6;
-       unsigned short  closing_wait; /* time to wait before closing */
-       unsigned short  closing_wait2; /* no longer used... */
-       int     reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF 0
-#define ASYNC_CLOSING_WAIT_NONE        65535
-
-/* This function tables does the abstraction from the underlying
- * hardware:
+ * currently this seems usefull only for a Q40,
+ * its an almost exact copy of ../asm/alpha/serial.h 
  *
- *   init(): Initialize the port as necessary, set RTS and DTR and
- *      enable interrupts. It does not need to set the speed and other
- *      parameters, because change_speed() is called, too.
- *   deinit(): Stop and shutdown the port (e.g. disable interrupts, ...)
- *   enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
- *      independently from other interrupt sources. If the int is
- *      enabled, the transmitter should also be restarted, i.e. if there
- *      are any chars to be sent, they should be put into the Tx
- *      register. The real en/disabling of the interrupt may be a no-op
- *      if there is no way to do this or it is too complex. This Tx ints
- *      are just disabled to save some interrupts if the transmitter is
- *      stopped anyway. But the restarting must be implemented!
- *   check_custom_divisor(): Check the given custom divisor for legality
- *      and return 0 if OK, non-zero otherwise.
- *   change_speed(): Set port speed, character size, number of stop
- *      bits and parity from the termios structure. If the user wants
- *      to set the speed with a custom divisor, he is required to
- *      check the baud_base first!
- *   throttle(): Set or clear the RTS line according to 'status'.
- *   set_break(): Set or clear the 'Send a Break' flag.
- *   get_serial_info(): Fill in the baud_base and custom_divisor
- *      fields of a serial_struct. It may also modify other fields, if
- *      needed.
- *   get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
- *   set_modem_info(): Set the status of RTS and DTR according to
- *      'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
- *   ioctl(): Process any port-specific ioctl's. This pointer may be
- *      NULL, if the port has no own ioctl's.
- *   stop_receive(): Turn off the Rx part of the port, so no more characters
- *      will be received. This is called before shutting the port down.
- *   trans_empty(): Return !=0 if there are no more characters still to be
- *      sent out (Tx buffer register and FIFOs empty)
- *   check_open(): Is called before the port is opened. The driver can check
- *      if that's ok and return an error code, or keep track of the opening
- *      even before init() is called. Use deinit() for matching closing of the
- *      port.
- *
- */
-
-struct m68k_async_struct;
-
-typedef struct {
-       void (*init)( struct m68k_async_struct *info );
-       void (*deinit)( struct m68k_async_struct *info, int leave_dtr );
-       void (*enab_tx_int)( struct m68k_async_struct *info, int enab_flag );
-       int  (*check_custom_divisor)( struct m68k_async_struct *info, int baud_base,
-                                    int divisor );
-       void (*change_speed)( struct m68k_async_struct *info );
-       void (*throttle)( struct m68k_async_struct *info, int status );
-       void (*set_break)( struct m68k_async_struct *info, int break_flag );
-       void (*get_serial_info)( struct m68k_async_struct *info,
-                               struct serial_struct *retinfo );
-       unsigned int (*get_modem_info)( struct m68k_async_struct *info );
-       int  (*set_modem_info)( struct m68k_async_struct *info, int new_dtr,
-                              int new_rts );
-       int  (*ioctl)( struct tty_struct *tty, struct file *file,
-                     struct m68k_async_struct *info, unsigned int cmd,
-                     unsigned long arg );
-       void (*stop_receive)( struct m68k_async_struct *info );
-       int  (*trans_empty)( struct m68k_async_struct *info );
-       int  (*check_open)( struct m68k_async_struct *info, struct tty_struct *tty,
-                          struct file *file );
-} SERIALSWITCH;
-
-/*
- * Definitions for m68k_async_struct (and serial_struct) flags field
  */
-#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-                                  on the callout port */
-#define ASYNC_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ASYNC_SAK      0x0004  /* Secure Attention Key (Orange book) */
-#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ASYNC_SPD_MASK 0x1030
-#define ASYNC_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
-
-#define ASYNC_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
-#define ASYNC_SPD_CUST 0x0030  /* Use user-specified divisor */
-
-#define ASYNC_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
-#define ASYNC_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ASYNC_HARDPPS_CD       0x0800  /* Call hardpps when CD goes high  */
-
-#define ASYNC_SPD_SHI  0x1000  /* Use 230400 instead of 38400 bps */
-#define ASYNC_SPD_WARP 0x1010  /* Use 460800 instead of 38400 bps */
-
-#define ASYNC_FLAGS    0x1FFF  /* Possible legal async flags */
-#define ASYNC_USR_MASK 0x1430  /* Legal flags that non-privileged
-                                * users can set or reset */
-
-/* Internal flags used only by drivers/char/m68kserial.c */
-#define ASYNC_INITIALIZED      0x80000000 /* Serial port was initialized */
-#define ASYNC_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
-#define ASYNC_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
-#define ASYNC_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
-#define ASYNC_CLOSING          0x08000000 /* Serial port is closing */
-#define ASYNC_CTS_FLOW         0x04000000 /* Do CTS flow control */
-#define ASYNC_CHECK_CD         0x02000000 /* i.e., CLOCAL */
-
-#define ASYNC_INTERNAL_FLAGS   0xFF000000 /* Internal flags */
-
-/*
- * Serial input interrupt line counters -- external structure
- * Four lines can interrupt: CTS, DSR, RI, DCD
- */
-struct serial_icounter_struct {
-       int cts, dsr, rng, dcd;
-       int rx, tx;
-       int frame, overrun, parity, brk;
-       int buf_overrun;
-       int reserved[9];
-};
 
+#include <linux/config.h>
+#if 0
+#define rs_init serial_rs_init
+#define register_serial serial_register_serial
+#define unregister_serial serial_unregister_serial
+#endif
 
-#ifdef __KERNEL__
 /*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
+ * This assumes you have a 1.8432 MHz clock for your UART.
  *
- * For definitions of the flags field, see tty.h
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
  */
-
-#include <linux/termios.h>
-#include <linux/tqueue.h>
-
-#include <linux/config.h>      /* for Mac SCC extensions */
-
-#ifdef CONFIG_MAC
-#define NUM_ZSREGS    16
-struct mac_zschannel {
-       volatile unsigned char *control;
-       volatile unsigned char *data;
-};
-struct m68k_async_private;
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
 #endif
 
-struct m68k_async_struct {
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     hub6;           /* HUB6 plus one */
-       int                     type;
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       int                     IER;    /* Interrupt Enable Register */
-       int                     MCR;    /* Modem control register */
-       int                     MCR_noint; /* MCR with interrupts off */
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
-       long                    session; /* Session of opening process */
-       long                    pgrp; /* pgrp of opening process */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-       struct tq_struct        tqueue;
-       struct termios          normal_termios;
-       struct termios          callout_termios;
-       struct wait_queue       *open_wait;
-       struct wait_queue       *close_wait;
-       struct wait_queue       *delta_msr_wait;
-       struct async_icount     icount; /* kernel counters for the 4 input interrupts */
-       struct m68k_async_struct        *next_port; /* For the linked list */
-       struct m68k_async_struct        *prev_port;
-       void                    *board_base; /* board-base address for use with
-                                               boards carrying several UART's,
-                                               like some Amiga boards. */
-       unsigned short          nr_uarts;    /* UART-counter, that indicates
-                                               how many UART's there are on
-                                               the board.  If the board has a
-                                               IRQ-register, this can be used
-                                               to check if any of the uarts,
-                                               on the board has requested an
-                                               interrupt, instead of checking
-                                               IRQ-registers on all UART's */
-       SERIALSWITCH            *sw;            /* functions to manage this port */
-#ifdef CONFIG_MAC
-       struct m68k_async_private       *private;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
 #endif
-};
-
-#ifdef CONFIG_MAC
-struct m68k_async_private {
-       struct m68k_async_info  *zs_next;       /* For IRQ servicing chain */
-       struct mac_zschannel    *zs_channel;    /* Channel registers */
-       struct mac_zschannel    *zs_chan_a;     /* A side registers */
-       unsigned char           read_reg_zero;
-
-       char                    soft_carrier;   /* Use soft carrier on this */
-       char                    break_abort;    /* console, process brk/abrt */
-       char                    kgdb_channel;   /* Kgdb running on this channel */
-       char                    is_cons;        /* Is this our console. */
-       unsigned char           tx_active;      /* character being xmitted */
-       unsigned char           tx_stopped;     /* output is suspended */
-
-       /* We need to know the current clock divisor
-        * to read the bps rate the chip has currently
-        * loaded.
-        */
-       unsigned char           clk_divisor;    /* May be 1, 16, 32, or 64 */
-       int                     zs_baud;
-
-       /* Current write register values */
-       unsigned char           curregs[NUM_ZSREGS];
-
-       /* Values we need to set next opportunity */
-       unsigned char           pendregs[NUM_ZSREGS];
-
-       char                    change_needed;
-};
-#endif
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP  0
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Export to allow PCMCIA to use this - Dave Hinds */
-extern int register_serial(struct serial_struct *req);
-extern void unregister_serial(int line);
-extern struct m68k_async_struct rs_table[];
-extern task_queue tq_serial;
-
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static __inline__ void rs_sched_event(struct m68k_async_struct *info, int event)
-{
-       info->event |= 1 << event;
-       queue_task(&info->tqueue, &tq_serial);
-       mark_bh(SERIAL_BH);
-}
-
-static __inline__ void rs_receive_char( struct m68k_async_struct *info,
-                                           int ch, int err )
-{
-       struct tty_struct *tty = info->tty;
-       
-       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-               return;
-       tty->flip.count++;
-       switch(err) {
-       case TTY_BREAK:
-               info->icount.brk++;
-               if (info->flags & ASYNC_SAK)
-                       do_SAK(tty);
-               break;
-       case TTY_PARITY:
-               info->icount.parity++;
-               break;
-       case TTY_OVERRUN:
-               info->icount.overrun++;
-               break;
-       case TTY_FRAME:
-               info->icount.frame++;
-               break;
-       }
-       *tty->flip.flag_buf_ptr++ = err;
-       *tty->flip.char_buf_ptr++ = ch;
-       info->icount.rx++;
-       tty_flip_buffer_push(tty);
-}
-
-static __inline__ int rs_get_tx_char( struct m68k_async_struct *info )
-{
-       unsigned char ch;
-       
-       if (info->x_char) {
-               ch = info->x_char;
-               info->icount.tx++;
-               info->x_char = 0;
-               return( ch );
-       }
-
-       if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped)
-               return( -1 );
-
-       ch = info->xmit_buf[info->xmit_tail++];
-       info->xmit_tail &= SERIAL_XMIT_SIZE - 1;
-       info->icount.tx++;
-       if (--info->xmit_cnt < WAKEUP_CHARS)
-               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-       return( ch );
-}
-
-static __inline__ int rs_no_more_tx( struct m68k_async_struct *info )
-{
-       return( info->xmit_cnt <= 0 ||
-                       info->tty->stopped ||
-                       info->tty->hw_stopped );
-}
-
-static __inline__ void rs_dcd_changed( struct m68k_async_struct *info, int dcd )
-
-{
-       /* update input line counter */
-       info->icount.dcd++;
-       wake_up_interruptible(&info->delta_msr_wait);
-
-       if (info->flags & ASYNC_CHECK_CD) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-               printk("ttyS%d CD now %s...", info->line,
-                      dcd ? "on" : "off");
-#endif         
-               if (dcd) {
-                       wake_up_interruptible(&info->open_wait);
-               } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-                            (info->flags & ASYNC_CALLOUT_NOHUP))) {
-#ifdef SERIAL_DEBUG_OPEN
-                       printk("scheduling hangup...");
-#endif
-                       if (info->tty)
-                               tty_hangup(info->tty);
-               }
-       }
-}
-
-
-void rs_stop( struct tty_struct *tty );
-void rs_start( struct tty_struct *tty );
-
-static __inline__ void rs_check_cts( struct m68k_async_struct *info, int cts )
-{
-       /* update input line counter */
-       info->icount.cts++;
-       wake_up_interruptible(&info->delta_msr_wait);
        
-       if ((info->flags & ASYNC_CTS_FLOW) && info->tty) {
-               if (info->tty->hw_stopped) {
-                       if (cts) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-                               printk("CTS tx start...");
+#define STD_SERIAL_PORT_DEFNS                  \
+       /* UART CLK   PORT IRQ     FLAGS        */                      \
+       { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
+       { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
+       { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
+       { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS                        \
+       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
+       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
+       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
+       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
+       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
+       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
+       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
+       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
+       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
+       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
+       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
+       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
+       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
+       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
+       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
+       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
+       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
+       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
+       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
+       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
+       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
+       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
+       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
+       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
+       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
+       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
 #endif
-                               info->tty->hw_stopped = 0;
-                               rs_start( info->tty );
-                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-                               return;
-                       }
-               } else {
-                       if (!cts) {
-                               info->tty->hw_stopped = 1;
-                               rs_stop( info->tty );
-                       }
-               }
-       }
-}
-
-
-#endif /* __KERNEL__ */
 
-#endif /* _M68K_SERIAL_H */
+#define SERIAL_PORT_DFNS               \
+       STD_SERIAL_PORT_DEFNS           \
+       EXTRA_SERIAL_PORT_DEFNS
index 197d96f1efbd48cee3347dbeb9031fbcd0fc074a..d857208fe2911e8f111e6bfda836658bdd5e9ffe 100644 (file)
@@ -39,6 +39,8 @@
 #define MACH_MVME16x  7
 #define MACH_BVME6000 8
 #define MACH_HP300    9
+#define MACH_Q40     10
+#define MACH_SUN3X   11
 
 #ifdef __KERNEL__
 
@@ -49,7 +51,9 @@ extern unsigned long m68k_machtype;
 #if !defined(CONFIG_AMIGA)
 #  define MACH_IS_AMIGA (0)
 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
 #  define MACH_AMIGA_ONLY
@@ -60,7 +64,9 @@ extern unsigned long m68k_machtype;
 #if !defined(CONFIG_ATARI)
 #  define MACH_IS_ATARI (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
 #  define MACH_ATARI_ONLY
@@ -71,7 +77,9 @@ extern unsigned long m68k_machtype;
 #if !defined(CONFIG_MAC)
 #  define MACH_IS_MAC (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
-       || defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)                 \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                        \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
 #else
 #  define MACH_MAC_ONLY
@@ -88,7 +96,9 @@ extern unsigned long m68k_machtype;
 #if !defined (CONFIG_APOLLO)
 #  define MACH_IS_APOLLO (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+       || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)              \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
 #else
 #  define MACH_APOLLO_ONLY
@@ -96,10 +106,25 @@ extern unsigned long m68k_machtype;
 #  define MACH_TYPE (MACH_APOLLO)
 #endif
 
+#if !defined (CONFIG_MVME147)
+#  define MACH_IS_MVME147 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+       || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)
+#  define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147)
+#else
+#  define MACH_MVME147_ONLY
+#  define MACH_IS_MVME147 (1)
+#  define MACH_TYPE (MACH_MVME147)
+#endif
+
 #if !defined (CONFIG_MVME16x)
 #  define MACH_IS_MVME16x (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+       || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
 #else
 #  define MACH_MVME16x_ONLY
@@ -110,7 +135,9 @@ extern unsigned long m68k_machtype;
 #if !defined (CONFIG_BVME6000)
 #  define MACH_IS_BVME6000 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+       || defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
 #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
 #else
 #  define MACH_BVME6000_ONLY
@@ -121,14 +148,42 @@ extern unsigned long m68k_machtype;
 #if !defined (CONFIG_HP300)
 #  define MACH_IS_HP300 (0)
 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
-#  define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
+       || defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_HP300 (m68k_machtype == MACH_HP300)
 #else
 #  define MACH_HP300_ONLY
 #  define MACH_IS_HP300 (1)
 #  define MACH_TYPE (MACH_HP300)
 #endif
 
+#if !defined (CONFIG_Q40)
+#  define MACH_IS_Q40 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+       || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+       || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_Q40 (m68k_machtype == MACH_Q40)
+#else
+#  define MACH_Q40_ONLY
+#  define MACH_IS_Q40 (1)
+#  define MACH_TYPE (MACH_Q40)
+#endif
+
+#if !defined (CONFIG_SUN3X)
+#  define MACH_IS_SUN3X (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+       || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+       || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+       || defined(CONFIG_Q40) || defined(CONFIG_MVME147)
+#  define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X)
+#else
+#  define CONFIG_SUN3X_ONLY
+#  define MACH_IS_SUN3X (1)
+#  define MACH_TYPE (MACH_SUN3X)
+#endif
+
 #ifndef MACH_TYPE
 #  define MACH_TYPE (m68k_machtype)
 #endif
diff --git a/include/asm-m68k/sun3x.h b/include/asm-m68k/sun3x.h
new file mode 100644 (file)
index 0000000..da13286
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SUN3X_H
+#define SUN3X_H
+
+/* hardware addresses */
+#define SUN3X_IOMMU       0x60000000
+#define SUN3X_ENAREG      0x61000000
+#define SUN3X_INTREG      0x61001400
+#define SUN3X_DIAGREG     0x61001800
+#define SUN3X_ZS1         0x62000000
+#define SUN3X_ZS2         0x62002000
+#define SUN3X_LANCE       0x65002000
+#define SUN3X_EEPROM      0x64000000
+#define SUN3X_IDPROM      0x640007d8
+#define SUN3X_VIDEO_BASE  0x50000000
+#define SUN3X_VIDEO_P4ID  0x50300000
+#define SUN3X_ESP_BASE   0x66000000
+#define SUN3X_ESP_DMA    0x66001000
+
+/* some NVRAM addresses */
+#define SUN3X_EEPROM_CONS      (SUN3X_EEPROM + 0x1f)
+#define SUN3X_EEPROM_PORTA     (SUN3X_EEPROM + 0x58)
+#define SUN3X_EEPROM_PORTB     (SUN3X_EEPROM + 0x60)
+
+#endif
index 86d3d38f1b4c3b6f234240fe4716d5c494da9ddb..03353e44c191e7f9c3851cd3ca6445d7dcec369e 100644 (file)
@@ -43,12 +43,14 @@ extern inline void wrusp(unsigned long usp) {
  * the mm structures are shared in d2 (to avoid atc flushing).
  */
 asmlinkage void resume(void);
-#define switch_to(prev,next) { \
+#define switch_to(prev,next,last) { \
   register void *_prev __asm__ ("a0") = (prev); \
   register void *_next __asm__ ("a1") = (next); \
+  register void *_last __asm__ ("d1"); \
   __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) \
-                      : : "a" (_prev), "a" (_next) \
+                      : "=d" (_last) : "a" (_prev), "a" (_next) \
                       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
+  (last) = _last; \
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
@@ -66,6 +68,8 @@ struct __xchg_dummy { unsigned long a[100]; };
 #define __cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
 #define nop() __asm__ __volatile__ ("nop"::)
 #define mb()  __asm__ __volatile__ (""   : : :"memory")
+#define rmb()  __asm__ __volatile__ (""   : : :"memory")
+#define wmb()  __asm__ __volatile__ (""   : : :"memory")
 
 #define __save_flags(x) \
 __asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
index aa1b4494fc62255b8b766d88cbd24604819b7a00..548ce9ede8a9bbf95acf8ac7df9fc75ee372221c 100644 (file)
@@ -759,6 +759,10 @@ __constant_copy_to_user(void *to, const void *from, unsigned long n)
 #define __copy_from_user(to, from, n) copy_from_user(to, from, n)
 #define __copy_to_user(to, from, n) copy_to_user(to, from, n)
 
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
 /*
  * Copy a null terminated string from userspace.
  */
index eac12bc7c73b71cbf0c9e37af8192b5adac935fa..c8358cb0ba5ae73bf82c9158dea29c52a85a7152 100644 (file)
@@ -235,7 +235,6 @@ struct thread_struct {
        double          fpr[32];        /* Complete floating point set */
        unsigned long   fpscr_pad;      /* fpr ... fpscr must be contiguous */
        unsigned long   fpscr;          /* Floating point status */
-       unsigned long   smp_fork_ret;
 };
 
 #define INIT_SP                (sizeof(init_stack) + (unsigned long) &init_stack)
@@ -247,7 +246,7 @@ struct thread_struct {
        (struct pt_regs *)INIT_SP - 1, /* regs */ \
        KERNEL_DS, /*fs*/ \
        0, /* last_syscall */ \
-       {0}, 0, 0, 0 \
+       {0}, 0, 0 \
 }
 
 /*
diff --git a/include/asm-ppc/raven.h b/include/asm-ppc/raven.h
new file mode 100644 (file)
index 0000000..62f996f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  asm-ppc/raven.h -- Raven MPIC chip.
+ *
+ *  Copyright (C) 1998 Johnnie Peters
+ *
+ *  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.
+ */
+
+#ifndef _ASMPPC_RAVEN_H
+#define _ASMPPC_RAVEN_H
+
+#define MVME2600_INT_SIO               0
+#define MVME2600_INT_FALCN_ECC_ERR     1
+#define MVME2600_INT_PCI_ETHERNET      2
+#define MVME2600_INT_PCI_SCSI          3
+#define MVME2600_INT_PCI_GRAPHICS      4
+#define MVME2600_INT_PCI_VME0          5
+#define MVME2600_INT_PCI_VME1          6
+#define MVME2600_INT_PCI_VME2          7
+#define MVME2600_INT_PCI_VME3          8
+#define MVME2600_INT_PCI_INTA          9
+#define MVME2600_INT_PCI_INTB          10
+#define MVME2600_INT_PCI_INTC          11
+#define MVME2600_INT_PCI_INTD          12
+#define MVME2600_INT_LM_SIG0           13
+#define MVME2600_INT_LM_SIG1           14
+
+extern struct hw_interrupt_type raven_pic;
+
+extern int raven_init(void);
+#endif _ASMPPC_RAVEN_H
index 623ee981f65f5895dd8be279288cbe2785122b7c..427bb5ddd01f5a0a0124e10eecad7c8863813dad 100644 (file)
@@ -80,11 +80,14 @@ struct device_node;
 extern void note_scsi_host(struct device_node *, void *);
 
 struct task_struct;
-extern void switch_to(struct task_struct *prev, struct task_struct *next);
+#define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
+extern void _switch_to(struct task_struct *, struct task_struct *,
+                      struct task_struct **);
 
 struct thread_struct;
-extern void _switch(struct thread_struct *prev, struct thread_struct *next,
-                   unsigned long context);
+extern struct task_struct *_switch(struct thread_struct *prev,
+                                    struct thread_struct *next,
+                                    unsigned long context);
 
 struct pt_regs;
 extern void dump_regs(struct pt_regs *);
index 5b1401b0966c9e30ce1079cd2a351dd6d74f99e5..e1ba06201bd4681d17d00c97523784d0f0160de3 100644 (file)
@@ -157,6 +157,7 @@ extern __inline__ int hard_smp_processor_id(void)
 #endif
 
 #define smp_processor_id() hard_smp_processor_id()
+/* XXX We really need to implement this now.  -DaveM */
 extern __inline__ void smp_send_reschedule(int cpu) { }
 extern __inline__ void smp_send_stop(void) { }
 
index 4196811377f8887231262d3f330d95837146f15e..3a4ee58a3ebec823715a1450d2da851a2e68f310 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.73 1999/04/20 13:22:49 anton Exp $ */
+/* $Id: system.h,v 1.74 1999/05/08 03:03:14 davem Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -84,8 +84,15 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 #define SWITCH_DO_LAZY_FPU if(last_task_used_math != next) next->tss.kregs->psr&=~PSR_EF;
 #endif
 
-       /* Much care has gone into this code, do not touch it. */
-#define switch_to(prev, next) do {                                                     \
+       /* Much care has gone into this code, do not touch it.
+        *
+        * We need to loadup regs l0/l1 for the newly forked child
+        * case because the trap return path relies on those registers
+        * holding certain values, gcc is told that they are clobbered.
+        * Gcc needs registers for 3 values in and 1 value out, so we
+        * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
+        */
+#define switch_to(prev, next, last) do {                                               \
        __label__ here;                                                                 \
        register unsigned long task_pc asm("o7");                                       \
        extern struct task_struct *current_set[NR_CPUS];                                \
@@ -103,21 +110,22 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
        next->mm->cpu_vm_mask |= (1 << smp_processor_id());                             \
        task_pc = ((unsigned long) &&here) - 0x8;                                       \
        __asm__ __volatile__(                                                           \
+       "mov    %%g6, %%g3\n\t"                                                         \
        "rd     %%psr, %%g4\n\t"                                                        \
-       "std    %%sp, [%%g6 + %3]\n\t"                                                  \
+       "std    %%sp, [%%g6 + %4]\n\t"                                                  \
        "rd     %%wim, %%g5\n\t"                                                        \
        "wr     %%g4, 0x20, %%psr\n\t"                                                  \
        "nop\n\t"                                                                       \
-       "std    %%g4, [%%g6 + %2]\n\t"                                                  \
-       "ldd    [%1 + %2], %%g4\n\t"                                                    \
-       "mov    %1, %%g6\n\t"                                                           \
+       "std    %%g4, [%%g6 + %3]\n\t"                                                  \
+       "ldd    [%2 + %3], %%g4\n\t"                                                    \
+       "mov    %2, %%g6\n\t"                                                           \
        ".globl patchme_store_new_current\n"                                            \
 "patchme_store_new_current:\n\t"                                                       \
-       "st     %1, [%0]\n\t"                                                           \
+       "st     %2, [%1]\n\t"                                                           \
        "wr     %%g4, 0x20, %%psr\n\t"                                                  \
        "nop\n\t"                                                                       \
        "nop\n\t"                                                                       \
-       "ldd    [%%g6 + %3], %%sp\n\t"                                                  \
+       "ldd    [%%g6 + %4], %%sp\n\t"                                                  \
        "wr     %%g5, 0x0, %%wim\n\t"                                                   \
        "ldd    [%%sp + 0x00], %%l0\n\t"                                                \
        "ldd    [%%sp + 0x38], %%i6\n\t"                                                \
@@ -125,11 +133,13 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
        "nop\n\t"                                                                       \
        "nop\n\t"                                                                       \
        "jmpl   %%o7 + 0x8, %%g0\n\t"                                                   \
-       " nop\n\t" : : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),       \
+       " mov   %%g3, %0\n\t"                                                           \
+        : "=&r" (last)                                                                 \
+        : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),                   \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),            \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),             \
          "r" (task_pc)                                                                 \
-       : "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3",                               \
+       : "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1",                               \
        "l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",   \
        "o3");                                                                          \
 here:  } while(0)
index 6ea145a19d9f33e3dc1f1e2baaaae869026152b2..d29cb2a35901512f483526b3c7ce0e9b294c4025 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.34 1999/01/11 13:45:44 davem Exp $ */
+/* $Id: mmu_context.h,v 1.35 1999/05/08 03:03:20 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -13,7 +13,6 @@
 #ifndef __ASSEMBLY__
 
 extern unsigned long tlb_context_cache;
-extern spinlock_t scheduler_lock;
 extern unsigned long mmu_context_bmap[];
 
 #define CTX_VERSION_SHIFT      (PAGE_SHIFT - 3)
@@ -38,11 +37,9 @@ extern void get_new_mmu_context(struct mm_struct *mm);
 #define destroy_context(__mm)  do {                                            \
        if ((__mm)->context != NO_CONTEXT &&                                    \
            atomic_read(&(__mm)->count) == 1) {                                 \
-               spin_lock(&scheduler_lock);                                     \
                if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
                        clear_bit((__mm)->context & ~(CTX_VERSION_MASK),        \
                                  mmu_context_bmap);                            \
-               spin_unlock(&scheduler_lock);                                   \
                (__mm)->context = NO_CONTEXT;                                   \
                if(current->mm == (__mm)) {                                     \
                        current->tss.ctx = 0;                                   \
@@ -126,9 +123,7 @@ extern __inline__ void __get_mmu_context(struct task_struct *tsk)
 #define activate_context(__tsk)                \
 do {   flushw_user();                  \
        (__tsk)->mm->cpu_vm_mask = 0;   \
-       spin_lock(&scheduler_lock);     \
        __get_mmu_context(__tsk);       \
-       spin_unlock(&scheduler_lock);   \
        (__tsk)->mm->cpu_vm_mask = (1UL<<smp_processor_id()); \
 } while(0)
 
index 86df4fe514cf3ed1c275d2ef49244c07590679ce..82cf1eb41dc87242b9be6920acc87081ce7091af 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.48 1999/01/02 16:50:28 davem Exp $ */
+/* $Id: system.h,v 1.50 1999/05/08 03:03:22 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -48,7 +48,7 @@ extern unsigned long empty_zero_page;
 ({     unsigned long retval; \
        __asm__ __volatile__("rdpr      %%pil, %0\n\t" \
                             "wrpr      %1, %%pil" \
-                            : "=r" (retval) \
+                            : "=&r" (retval) \
                             : "r" (__new_pil) \
                             : "memory"); \
        retval; \
@@ -127,21 +127,14 @@ extern __inline__ void flushw_user(void)
 
        /* See what happens when you design the chip correctly?
         *
-        * XXX What we are doing here assumes a lot about gcc reload
-        * XXX internals, it heavily risks compiler aborts due to
-        * XXX forbidden registers being spilled.  Rewrite me...  -DaveM
-        *
-        * SMP NOTE: At first glance it looks like there is a tiny
-        *           race window here at the end.  The possible problem
-        *           would be if a tlbcachesync MONDO vector got delivered
-        *           to us right before we set the final %g6 thread reg
-        *           value.  But that is impossible since only the holder
-        *           of scheduler_lock can send a tlbcachesync MONDO and
-        *           by definition we hold it right now.  Normal tlb
-        *           flush xcalls can come in, but those are safe and do
-        *           not reference %g6.
+        * We tell gcc we clobber all non-fixed-usage registers except
+        * for l0/l1.  It will use one for 'next' and the other to hold
+        * the output value of 'last'.  'next' is not referenced again
+        * past the invocation of switch_to in the scheduler, so we need
+        * not preserve it's value.  Hairy, but it lets us remove 2 loads
+        * and 2 stores in this critical code path.  -DaveM
         */
-#define switch_to(prev, next)                                                  \
+#define switch_to(prev, next, last)                                            \
 do {   if (current->tss.flags & SPARC_FLAG_PERFCTR) {                          \
                unsigned long __tmp;                                            \
                read_pcr(__tmp);                                                \
@@ -157,26 +150,23 @@ do {      if (current->tss.flags & SPARC_FLAG_PERFCTR) {                          \
        __get_mmu_context(next);                                                \
        (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());                 \
        __asm__ __volatile__(                                                   \
+       "mov    %%g6, %%g5\n\t"                                                 \
        "wrpr   %%g0, 0x95, %%pstate\n\t"                                       \
-       "stx    %%l0, [%%sp + 2047 + 0x60]\n\t"                                 \
-       "stx    %%l1, [%%sp + 2047 + 0x68]\n\t"                                 \
        "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                 \
        "stx    %%i7, [%%sp + 2047 + 0x78]\n\t"                                 \
        "rdpr   %%wstate, %%o5\n\t"                                             \
-       "stx    %%o6, [%%g6 + %2]\n\t"                                          \
-       "sth    %%o5, [%%g6 + %1]\n\t"                                          \
+       "stx    %%o6, [%%g6 + %3]\n\t"                                          \
+       "sth    %%o5, [%%g6 + %2]\n\t"                                          \
        "rdpr   %%cwp, %%o5\n\t"                                                \
-       "sth    %%o5, [%%g6 + %4]\n\t"                                          \
-       "mov    %0, %%g6\n\t"                                                   \
-       "lduh   [%0 + %4], %%g1\n\t"                                            \
+       "sth    %%o5, [%%g6 + %5]\n\t"                                          \
+       "mov    %1, %%g6\n\t"                                                   \
+       "lduh   [%1 + %5], %%g1\n\t"                                            \
        "wrpr   %%g1, %%cwp\n\t"                                                \
-       "ldx    [%%g6 + %2], %%o6\n\t"                                          \
-       "lduh   [%%g6 + %1], %%o5\n\t"                                          \
-       "lduh   [%%g6 + %3], %%o7\n\t"                                          \
+       "ldx    [%%g6 + %3], %%o6\n\t"                                          \
+       "lduh   [%%g6 + %2], %%o5\n\t"                                          \
+       "lduh   [%%g6 + %4], %%o7\n\t"                                          \
        "mov    %%g6, %%l2\n\t"                                                 \
        "wrpr   %%o5, 0x0, %%wstate\n\t"                                        \
-       "ldx    [%%sp + 2047 + 0x60], %%l0\n\t"                                 \
-       "ldx    [%%sp + 2047 + 0x68], %%l1\n\t"                                 \
        "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                                 \
        "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                                 \
        "wrpr   %%g0, 0x94, %%pstate\n\t"                                       \
@@ -184,8 +174,8 @@ do {        if (current->tss.flags & SPARC_FLAG_PERFCTR) {                          \
        "wrpr   %%g0, 0x96, %%pstate\n\t"                                       \
        "andcc  %%o7, 0x100, %%g0\n\t"                                          \
        "bne,pn %%icc, ret_from_syscall\n\t"                                    \
-       " nop\n\t"                                                              \
-       :                                                                       \
+       " mov   %%g5, %0\n\t"                                                   \
+       : "=&r" (last)                                                          \
        : "r" (next),                                                           \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),  \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),     \
index 93c14ae3f5320a5b1dd5042a25f8cfc00416b5f2..0643d04879a8a679e61d61ae775c6d87e9635030 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
+/* $Id: uaccess.h,v 1.29 1999/05/08 03:03:25 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
 
 #define segment_eq(a,b)  ((a).seg == (b).seg)
 
-extern spinlock_t scheduler_lock;
-
 #define set_fs(val)                                                            \
 do {                                                                           \
        if (current->tss.current_ds.seg != val.seg) {                           \
-               spin_lock(&scheduler_lock);                                     \
                current->tss.current_ds = (val);                                \
                if (segment_eq((val), KERNEL_DS)) {                             \
                        flushw_user ();                                         \
@@ -56,7 +53,6 @@ do {                                                                          \
                }                                                               \
                spitfire_set_secondary_context(current->tss.ctx);               \
                __asm__ __volatile__("flush %g6");                              \
-               spin_unlock(&scheduler_lock);                                   \
        }                                                                       \
 } while(0)
 
index 8ca50174bba24f753a3bde81128dc0ab6f8fdb0d..d8f92fd09163cf05eae2bf12505b324f9deb67da 100644 (file)
 #include <linux/apm_bios.h>
 #endif
 
+#ifdef CONFIG_MAC
+extern void nubus_init(void);
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -789,7 +793,8 @@ static struct kernel_param cooked_params[] __initdata = {
 #endif
 #if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) \
            || defined(CONFIG_A4091_SCSI) || defined(CONFIG_MVME16x_SCSI) \
-           || defined(CONFIG_BVME6000_SCSI)
+           || defined(CONFIG_BVME6000_SCSI) \
+           || defined(CONFIG_BLZ603EPLUS_SCSI)
         { "53c7xx=", ncr53c7xx_setup },
 #endif
 #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
@@ -1277,6 +1282,9 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_DIO
        dio_init();
 #endif
+#ifdef CONFIG_MAC
+       nubus_init();
+#endif
 
        /* Networking initialization needs a process context */ 
        sock_init();
index f10a72951b8e6eeecf2ce2606619ef3586fae5b8..62d85dc02071015825a793be199f7443a7ed7765 100644 (file)
@@ -937,7 +937,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
        unsigned long old_page, new_page;
 
        new_page = 0;
-       offset = (address - area->vm_start + area->vm_offset) & PAGE_MASK;
+       offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
        if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
                goto no_page;