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)
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
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
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
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
===============
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
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)
=========================
4.1) video=
---------------
+-----------
Syntax: video=<fbname>:<sub-options...>
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.
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
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
-----------
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=
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.
-----------
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
------------
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: */
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
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
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
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)
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
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
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
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
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
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
# 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
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
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
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
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
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
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)
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
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 */
** 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 */
#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
.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)
/*
* 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)
/*
* 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)
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))
#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))
* 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)
* 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)
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'
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.
/* Extract the highest bit set
*/
bfffo ARG3{#0,#32},%d1
- cmpw #8,%d0
+ cmpw #8,%d1
jcc L(do_map)
/* And get the mask
/* 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)"
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
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)
/*
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)
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
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
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
#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];
/*
* 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;
}
*/
#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
#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[];
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);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
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)
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,
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
+ unsigned long flags;
int ret;
lock_kernel();
(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;
}
case PTRACE_DETACH: { /* detach a process that was attached. */
- unsigned long flags;
long tmp;
ret = -EIO;
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
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
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;
}
config_apollo();
break;
#endif
+#ifdef CONFIG_MVME147
+ case MACH_MVME147:
+ config_mvme147();
+ break;
+#endif
#ifdef CONFIG_MVME16x
case MACH_MVME16x:
config_mvme16x();
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");
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)
#endif
/* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+__initfunc(void kbd_reset_setup(char *str, int *ints))
{
}
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+ write_unlock_irq(&xtime_lock);
}
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)
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;
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)
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)
* 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;
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;
/* 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]));
}
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
}
}
- while (size > 0) {
+ while ((long)size > 0) {
#ifdef DEBUG
if (!(virtaddr & (PTRTREESIZE-1)))
printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
}
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;
*/
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
}
/*
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));
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;
}
}
- 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));
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] &
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/pagemap.h>
#include <asm/setup.h>
#include <asm/segment.h>
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;
(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)
/* 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 */
/* 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
--- /dev/null
+/*
+ * 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)
+{
+}
+
--- /dev/null
+#
+# 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
+
--- /dev/null
+/*
+ * 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);
+}
+
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)
--- /dev/null
+#
+# 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
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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)
+{
+
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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
/*
* 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
*
*/
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 */
}
}
{
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 );
initrd_end = initrd_start + INITRD_SIZE;
puts("relocated to: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
+#endif
}
avail_ram = (char *)0x00400000;
CONFIG_ALL_PPC=y
# CONFIG_APUS is not set
# CONFIG_MBX is not set
-CONFIG_SMP=y
+# CONFIG_SMP is not set
#
# General setup
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
#
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
#
# Kernel hacking
#
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
# CONFIG_KGDB is not set
# CONFIG_XMON is not set
-# $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.
#
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
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
#
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
# 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
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
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
# 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
# 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
# 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
# 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
#
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
#
# 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
# 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
#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;
}
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;
}
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;
}
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);
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),
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);
{
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);
void __init
chrp_setup_pci_ptrs(void)
{
+ struct device_node *py;
+
if ( !strncmp("MOT",
get_property(find_path_device("/"), "model", NULL),3) )
{
}
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
{
*
* 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 */
/*
* 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)
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
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 */
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
#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 )
extern struct hw_interrupt_type i8259_pic;
void i8259_init(void);
+int i8259_irq(int);
#endif /* _PPC_KERNEL_i8259_H */
}
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;
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);
}
#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);
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);
-#include <linux/config.h>
+
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/sched.h>
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,
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;
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)
/*
- * $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)
/* 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 */
{
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 */
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 =
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 =
{
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 */
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 =
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
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;
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;
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))
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
- }
}
}
#include <asm/machdep.h>
#include <asm/mk48t59.h>
#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+
#include "time.h"
#include "local_irq.h"
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;
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;
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 );
}
{
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)
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 )
{
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;
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;
/*
- * $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;
}
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();
#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
* 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))
#endif /* __SMP__ */
new_tss = &new->tss;
old_tss = ¤t->tss;
- _switch(old_tss, new_tss, new->mm->context);
+ *last = _switch(old_tss, new_tss, new->mm->context);
_enable_interrupts(s);
}
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)
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);
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;
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.
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.
/*
- * $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.
* 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
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
/*
- * $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)
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 */
/* 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));
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,
*/
if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
goto out;
-#endif
#endif /* CONFIG_8xx */
if (mem_init_done) {
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)
* 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 */
-/* $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)
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
-/* $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)
/* 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;
/* endless idle loop with no priority at all */
current->priority = 0;
current->counter = -100;
+ init_idle();
+
while(1) {
if(current->need_resched) {
schedule();
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. */
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++)
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. */
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... */
-/* $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
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
-/* $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)
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,
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();
long ver, fpu_vers;
long fprs;
- cpuid = smp_processor_id();
+ cpuid = hard_smp_processor_id();
fprs = fprs_read ();
fprs_write (FPRS_FEF);
prom_cpu_nodes[0] = prom_node_cpu;
+ mem_start = central_probe(mem_start);
+
cpu_probe();
- return central_probe(mem_start);
+
+ return mem_start;
}
-/* $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)
#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
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
#endif
-#ifdef CONFIG_SPARCAUDIO
- sparcaudio_init();
-#endif
#ifdef CONFIG_SUN_BPP
bpp_init();
#endif
-/* $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)
*/
#ifdef __SMP__
andn %o7, 0x100, %l0
+ mov %g5, %o0 /* 'prev' */
call schedule_tail
sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
#else
-/* $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)
#include <linux/vt_kern.h>
#include <linux/fb.h>
#include <linux/ext2_fs.h>
+#include <linux/videodev.h>
#include <scsi/scsi.h>
/* Ugly hack. */
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;
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...
*/
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:
-/* $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)
/* 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
{
current->priority = 0;
current->counter = -100;
+ init_idle();
+
while(1) {
if (current->need_resched != 0) {
unidle_me();
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;
__sti();
smp_store_cpu_info(boot_cpu_id);
smp_tune_scheduling();
+ init_idle();
if(linux_num_cpus == 1)
return;
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)
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.
/* 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);
-/* $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)
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
/* used by various drivers */
#ifdef __SMP__
/* Kernel wide locking */
-EXPORT_SYMBOL(scheduler_lock);
EXPORT_SYMBOL(kernel_flag);
/* Software-IRQ BH locking */
-/* $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)
#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
#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. */
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)
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
--- /dev/null
+#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
+
--- /dev/null
+/* 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
+
+
--- /dev/null
+/* 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
#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;
}
--- /dev/null
+/* 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
+
+
#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))
ether_setup(dev);
- dev->hard_header_len = 16;
dev->tx_queue_len = 0;
dev->flags|=IFF_NOARP;
tap_map[dev->base_addr]=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)) {
* 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
#include <linux/kmod.h>
#endif
-typedef ssize_t rw_ret_t;
-typedef size_t rw_count_t;
-
/*
* Local functions
*/
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);
* 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,
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;
* 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
* 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;
*/
ppp_send_ctrl(ppp, skb);
- return (rw_ret_t) count;
+ return (ssize_t) count;
}
/*
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().
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);
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);
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);
done = 1;
}
ppp->optr = ppp->olim;
+ wmb();
ppp->tty_pushing = 0;
return done;
}
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
-/* $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)
prev_scancode = 0;
return 0;
}
+ scancode &= 0x7f;
if(prev_scancode) {
if(prev_scancode != 0xe0) {
if(prev_scancode == 0xe1 && scancode == 0x1d) {
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:
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.
+
-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
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);
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
*/
/* #define OHCI_DBG */ /* printk some debug information */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
* ohci-hcd.h
*/
+#include <linux/config.h>
+
#ifdef CONFIG_USB_OHCI_VROOTHUB
#define VROOTHUB
#endif
*
* 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>
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)
{
/* 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() */
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 */
/*
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);
} /* 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)
{
* 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
*/
/* 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) {
}
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));
return 0;
}
+
/*
* functions for the generic USB driver
*/
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() */
*/
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]);
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
* Do generic USB device tree processing on the new device.
*/
usb_new_device(usb_dev);
+
} /* ohci_connect_change() */
*/
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(®s->roothub.portstatus[num]) & PORT_CSC) {
+ /* reset the connect status change bit */
+ writel(PORT_CSC, ®s->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(®s->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(®s->intrstatus);
+ status &= readl(®s->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, ®s->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, ®s->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, ®s->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, ®s->intrenable);
-
+ /* Check those "other" pesky bits */
+ if (context & (OHCI_INTR_FNO)) {
+ writel(OHCI_INTR_FNO, ®s->intrstatus);
+ context &= ~OHCI_INTR_FNO; /* mark this as checked */
+ }
+ if (context & OHCI_INTR_SO) {
+ writel(OHCI_INTR_SO, ®s->intrstatus);
+ context &= ~OHCI_INTR_SO; /* mark this as checked */
+ }
+ if (context & OHCI_INTR_RD) {
+ writel(OHCI_INTR_RD, ®s->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, ®s->intrstatus);
+ context &= ~OHCI_INTR_UE; /* mark this as checked */
+ }
+ if (context & OHCI_INTR_OC) {
+ writel(OHCI_INTR_OC, ®s->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, ®s->intrdisable);
+ }
+
+ /* Re-enable HC interrupts */
+ writel(OHCI_INTR_MIE, ®s->intrenable);
+
} /* ohci_interrupt() */
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;
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
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) {
}
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)
* 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)
/*
* 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() */
*/
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;
}
/* 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();
* 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);
/*
* 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(¤t->sigmask_lock);
+ signr = dequeue_signal(¤t->blocked, &info);
+ spin_unlock_irq(¤t->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() */
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
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() */
*/
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
*/
#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
return -ENODEV;
}
+ printk("OHCI USB Driver loading\n");
+
retval = -ENODEV;
for (;;) {
/* Find an OHCI USB controller */
/* 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
return 0; /* no error */
}
return retval;
-} /* init_module() */
+} /* ohci_init */
/* vim:sw=8
*/
*
* (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
*/
/* 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] */
/* 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)
/*
* 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 : \
#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
*/
#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
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
# 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
+
#!/bin/sh
-killall uhci-control
-killall khubd
+killall ohci-control
-sleep 1
+sleep 2
-rmmod usb-uhci
+rmmod usb-ohci
/*
* 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 *);
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/mtrr.h>
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;
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
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);
* 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;
{
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);
/*
- * 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;
}
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) {
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
* 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
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(¤t->sigmask_lock);
- flush_signals(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- interruptible_sleep_on(&bdflush_wait);
- }
}
}
int block, toread, i, err;
*res_dir = NULL;
- if (!dir)
- return NULL;
sb = dir->i_sb;
if (namelen > EXT2_NAME_LEN)
char c;
*ino = 0;
- if (!dir) return NULL;
if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
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;
}
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) {
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;
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);
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) {
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) {
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;
struct buffer_head * bh;
*res_dir = NULL;
- if (!dir)
- return NULL;
sb = dir->i_sb;
if (namelen > SYSV_NAMELEN) {
if (sb->sv_truncate)
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;
#ifndef __ALPHA_SYSTEM_H
#define __ALPHA_SYSTEM_H
+#include <linux/config.h>
#include <asm/pal.h>
#include <asm/page.h>
#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 ??? */
#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
--- /dev/null
+/* $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) */
--- /dev/null
+/*
+ * 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;
+}
+
+
+
#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");
}
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 */
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);
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
#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; \
})
#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; \
} \
})
-#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) \
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__ \
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) \
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__ \
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 */
#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;
}
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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));
/* 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__ */
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]));
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]));
}
}
}
--- /dev/null
+/*
+ * 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__ */
+
+
+
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
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. */
--- /dev/null
+#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
#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
"| 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"
"| 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"
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).
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 */
/*
- * 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
#define MACH_MVME16x 7
#define MACH_BVME6000 8
#define MACH_HP300 9
+#define MACH_Q40 10
+#define MACH_SUN3X 11
#ifdef __KERNEL__
#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
#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
#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
#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
# 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
#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
#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
--- /dev/null
+#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
* 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))))
#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")
#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.
*/
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)
(struct pt_regs *)INIT_SP - 1, /* regs */ \
KERNEL_DS, /*fs*/ \
0, /* last_syscall */ \
- {0}, 0, 0, 0 \
+ {0}, 0, 0 \
}
/*
--- /dev/null
+/*
+ * 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
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 *);
#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) { }
-/* $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
#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]; \
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" \
"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)
-/* $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
#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)
#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; \
#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)
-/* $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
({ unsigned long retval; \
__asm__ __volatile__("rdpr %%pil, %0\n\t" \
"wrpr %1, %%pil" \
- : "=r" (retval) \
+ : "=&r" (retval) \
: "r" (__new_pil) \
: "memory"); \
retval; \
/* 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); \
__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" \
"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)), \
-/* $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 (); \
} \
spitfire_set_secondary_context(current->tss.ctx); \
__asm__ __volatile__("flush %g6"); \
- spin_unlock(&scheduler_lock); \
} \
} while(0)
#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.
#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) \
#ifdef CONFIG_DIO
dio_init();
#endif
+#ifdef CONFIG_MAC
+ nubus_init();
+#endif
/* Networking initialization needs a process context */
sock_init();
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;