summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/Configure.help110
-rw-r--r--Documentation/filesystems/sysv-fs.txt6
-rw-r--r--MAINTAINERS11
-rw-r--r--Makefile2
-rw-r--r--arch/i386/defconfig2
-rw-r--r--arch/i386/kernel/process.c21
-rw-r--r--arch/i386/kernel/ptrace.c97
-rw-r--r--arch/i386/kernel/signal.c13
-rw-r--r--arch/i386/math-emu/Makefile17
-rw-r--r--arch/i386/math-emu/README24
-rw-r--r--arch/i386/math-emu/div_small.S4
-rw-r--r--arch/i386/math-emu/errors.c242
-rw-r--r--arch/i386/math-emu/fpu_arith.c67
-rw-r--r--arch/i386/math-emu/fpu_asm.h15
-rw-r--r--arch/i386/math-emu/fpu_aux.c86
-rw-r--r--arch/i386/math-emu/fpu_emu.h160
-rw-r--r--arch/i386/math-emu/fpu_entry.c250
-rw-r--r--arch/i386/math-emu/fpu_etc.c132
-rw-r--r--arch/i386/math-emu/fpu_proto.h164
-rw-r--r--arch/i386/math-emu/fpu_system.h52
-rw-r--r--arch/i386/math-emu/fpu_tags.c127
-rw-r--r--arch/i386/math-emu/fpu_trig.c1695
-rw-r--r--arch/i386/math-emu/get_address.c44
-rw-r--r--arch/i386/math-emu/load_store.c92
-rw-r--r--arch/i386/math-emu/poly_2xm1.c38
-rw-r--r--arch/i386/math-emu/poly_atan.c74
-rw-r--r--arch/i386/math-emu/poly_l2.c151
-rw-r--r--arch/i386/math-emu/poly_sin.c111
-rw-r--r--arch/i386/math-emu/poly_tan.c27
-rw-r--r--arch/i386/math-emu/reg_add_sub.c490
-rw-r--r--arch/i386/math-emu/reg_compare.c205
-rw-r--r--arch/i386/math-emu/reg_constant.c71
-rw-r--r--arch/i386/math-emu/reg_convert.c53
-rw-r--r--arch/i386/math-emu/reg_div.S248
-rw-r--r--arch/i386/math-emu/reg_divide.c206
-rw-r--r--arch/i386/math-emu/reg_ld_str.c958
-rw-r--r--arch/i386/math-emu/reg_mul.c156
-rw-r--r--arch/i386/math-emu/reg_norm.S82
-rw-r--r--arch/i386/math-emu/reg_round.S224
-rw-r--r--arch/i386/math-emu/reg_u_add.S58
-rw-r--r--arch/i386/math-emu/reg_u_div.S66
-rw-r--r--arch/i386/math-emu/reg_u_mul.S48
-rw-r--r--arch/i386/math-emu/reg_u_sub.S74
-rw-r--r--arch/i386/math-emu/version.h6
-rw-r--r--arch/i386/math-emu/wm_shrx.S12
-rw-r--r--arch/i386/math-emu/wm_sqrt.S13
-rw-r--r--arch/m68k/amiga/amifb.c3633
-rw-r--r--arch/m68k/amiga/amikeyb.c343
-rw-r--r--arch/m68k/amiga/cyberfb.c1253
-rw-r--r--arch/m68k/amiga/retz3fb.c1754
-rw-r--r--arch/m68k/amiga/retz3fb.h286
-rw-r--r--arch/m68k/atari/atafb.c3292
-rw-r--r--arch/m68k/atari/atafb.h48
-rw-r--r--arch/m68k/console/Makefile24
-rw-r--r--arch/m68k/console/fbcon.c4126
-rw-r--r--arch/m68k/console/font_8x16.c4625
-rw-r--r--arch/m68k/console/font_8x8.c2577
-rw-r--r--arch/m68k/console/fonts.c108
-rw-r--r--arch/m68k/console/pearl_8x8.c2582
-rw-r--r--arch/m68k/console/txtcon.c147
-rw-r--r--drivers/block/Config.in24
-rw-r--r--drivers/block/Makefile18
-rw-r--r--drivers/block/ali14xx.c1
-rw-r--r--drivers/block/cmd640.c1
-rw-r--r--drivers/block/dtc2278.c1
-rw-r--r--drivers/block/ht6560b.c2
-rw-r--r--drivers/block/ide-cd.c93
-rw-r--r--drivers/block/ide-cd.h10
-rw-r--r--drivers/block/ide-disk.c65
-rw-r--r--drivers/block/ide-dma.c473
-rw-r--r--drivers/block/ide-floppy.c113
-rw-r--r--drivers/block/ide-pci.c382
-rw-r--r--drivers/block/ide-probe.c107
-rw-r--r--drivers/block/ide-proc.c505
-rw-r--r--drivers/block/ide-tape.c141
-rw-r--r--drivers/block/ide.c252
-rw-r--r--drivers/block/ide.h93
-rw-r--r--drivers/block/ll_rw_blk.c26
-rw-r--r--drivers/block/ns87415.c228
-rw-r--r--drivers/block/opti621.c28
-rw-r--r--drivers/block/pdc4030.c8
-rw-r--r--drivers/block/qd6580.c1
-rw-r--r--drivers/block/rz1000.c43
-rw-r--r--drivers/block/trm290.c181
-rw-r--r--drivers/block/umc8672.c1
-rw-r--r--drivers/char/pc_keyb.c25
-rw-r--r--drivers/char/pc_keyb.h6
-rw-r--r--drivers/char/pcwd.c7
-rw-r--r--drivers/net/3c505.c8
-rw-r--r--drivers/net/3c59x.c1223
-rw-r--r--drivers/net/Config.in1
-rw-r--r--drivers/net/eth16i.c2
-rw-r--r--drivers/net/hamradio/Config.in1
-rw-r--r--drivers/net/hamradio/dmascc.c1260
-rw-r--r--drivers/net/ipddp.c3
-rw-r--r--drivers/pci/pci.c22
-rw-r--r--drivers/scsi/ide-scsi.c51
-rw-r--r--drivers/scsi/ide-scsi.h3
-rw-r--r--drivers/scsi/st.c1
-rw-r--r--drivers/sgi/Makefile22
-rw-r--r--drivers/sgi/char/Makefile18
-rw-r--r--drivers/sgi/char/cons_newport.c613
-rw-r--r--drivers/sgi/char/gconsole.h33
-rw-r--r--drivers/sgi/char/graphics.c327
-rw-r--r--drivers/sgi/char/graphics.h28
-rw-r--r--drivers/sgi/char/linux_logo.h909
-rw-r--r--drivers/sgi/char/newport.c217
-rw-r--r--drivers/sgi/char/newport.h587
-rw-r--r--drivers/sgi/char/rrm.c69
-rw-r--r--drivers/sgi/char/sgicons.c183
-rw-r--r--drivers/sgi/char/sgiserial.c2019
-rw-r--r--drivers/sgi/char/sgiserial.h444
-rw-r--r--drivers/sgi/char/shmiq.c460
-rw-r--r--drivers/sgi/char/streamable.c363
-rw-r--r--drivers/sgi/char/usema.c191
-rw-r--r--drivers/sgi/char/vga_font.c346
-rw-r--r--drivers/sound/lowlevel/awe_wave.c2
-rw-r--r--fs/dcache.c36
-rw-r--r--fs/ext2/fsync.c197
-rw-r--r--fs/fat/inode.c10
-rw-r--r--fs/isofs/dir.c28
-rw-r--r--fs/isofs/inode.c58
-rw-r--r--fs/isofs/rock.c1
-rw-r--r--fs/msdos/namei.c101
-rw-r--r--fs/namei.c25
-rw-r--r--fs/nfs/dir.c75
-rw-r--r--fs/nfs/inode.c16
-rw-r--r--fs/nfs/write.c7
-rw-r--r--fs/nfsd/vfs.c141
-rw-r--r--fs/proc/generic.c2
-rw-r--r--fs/smbfs/dir.c174
-rw-r--r--fs/smbfs/file.c4
-rw-r--r--fs/smbfs/inode.c138
-rw-r--r--fs/smbfs/ioctl.c21
-rw-r--r--fs/smbfs/proc.c563
-rw-r--r--fs/smbfs/sock.c26
-rw-r--r--fs/sysv/namei.c38
-rw-r--r--include/asm-i386/math_emu.h14
-rw-r--r--include/asm-i386/processor.h5
-rw-r--r--include/asm-i386/ptrace.h6
-rw-r--r--include/asm-i386/system.h22
-rw-r--r--include/linux/blkdev.h2
-rw-r--r--include/linux/dmascc.h43
-rw-r--r--include/linux/fs.h5
-rw-r--r--include/linux/hdreg.h4
-rw-r--r--include/linux/ip_fw.h26
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/pci.h4
-rw-r--r--include/linux/proc_fs.h5
-rw-r--r--include/linux/smb_fs.h17
-rw-r--r--include/linux/socket.h2
-rw-r--r--include/linux/sysctl.h2
-rw-r--r--include/net/ip_autofw.h33
-rw-r--r--include/net/ip_masq.h224
-rw-r--r--include/net/ip_masq_mod.h78
-rw-r--r--include/net/ip_portfw.h29
-rw-r--r--include/net/llc.h7
-rw-r--r--include/net/tcp.h50
-rw-r--r--init/main.c3
-rw-r--r--kernel/ksyms.c2
-rw-r--r--kernel/printk.c9
-rw-r--r--kernel/signal.c5
-rw-r--r--net/Config.in2
-rw-r--r--net/appletalk/ddp.c6
-rw-r--r--net/core/iovec.c16
-rw-r--r--net/ipv4/Config.in6
-rw-r--r--net/ipv4/Makefile20
-rw-r--r--net/ipv4/arp.c5
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/icmp.c12
-rw-r--r--net/ipv4/ip_forward.c22
-rw-r--r--net/ipv4/ip_masq.c1488
-rw-r--r--net/ipv4/ip_masq_app.c62
-rw-r--r--net/ipv4/ip_masq_autofw.c427
-rw-r--r--net/ipv4/ip_masq_cuseeme.c261
-rw-r--r--net/ipv4/ip_masq_ftp.c244
-rw-r--r--net/ipv4/ip_masq_irc.c366
-rw-r--r--net/ipv4/ip_masq_mod.c316
-rw-r--r--net/ipv4/ip_masq_portfw.c461
-rw-r--r--net/ipv4/ip_masq_quake.c10
-rw-r--r--net/ipv4/ip_masq_raudio.c422
-rw-r--r--net/ipv4/ip_masq_vdolive.c291
-rw-r--r--net/ipv4/ip_output.c8
-rw-r--r--net/ipv4/ip_sockglue.c21
-rw-r--r--net/ipv4/route.c5
-rw-r--r--net/ipv4/sysctl_net_ipv4.c14
-rw-r--r--net/ipv4/tcp_ipv4.c95
-rw-r--r--net/ipv4/tcp_timer.c103
-rw-r--r--net/ipv4/udp.c117
-rw-r--r--net/ipv6/addrconf.c16
-rw-r--r--net/sunrpc/svc.c126
192 files changed, 20468 insertions, 30579 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 358677e26..85320397e 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -248,11 +248,13 @@ CONFIG_BLK_DEV_IDETAPE
Include IDE/ATAPI FLOPPY support
CONFIG_BLK_DEV_IDEFLOPPY
- If you have an IDE floppy drive which uses the ATAPI protocol, say
- Y. Chances are that you don't, because these animals are rare.
+ If you have an IDE floppy drive which uses the ATAPI protocol, say Y.
ATAPI is a new protocol used by IDE CDROM/tape/floppy drives,
- similar to the SCSI protocol. At boot time, the FLOPPY drive will
- be identified along with other IDE devices, as "hdb" or "hdc", or
+ similar to the SCSI protocol. IDE floppy drives include the
+ LS-120 and the ATAPI ZIP (ATAPI PD-CD/CDR drives are not supported
+ by this driver; support for PD-CD/CDR drives is available through
+ the SCSI emulation). At boot time, the FLOPPY drive will be
+ identified along with other IDE devices, as "hdb" or "hdc", or
something similar. If you want to compile the driver as a module ( =
code which can be inserted in and removed from the running kernel
whenever you want), say M here and read Documentation/modules.txt.
@@ -263,10 +265,11 @@ CONFIG_BLK_DEV_IDESCSI
This will provide SCSI host adapter emulation for IDE ATAPI devices,
and will allow you to use a SCSI device driver instead of a native
ATAPI driver. This is useful if you have an ATAPI device for which
- no native driver has been written; you can then use this emulation
- together with an appropriate SCSI device driver. If both this SCSI
- emulation and native ATAPI support are compiled into the kernel, the
- native support will be used. Normally, say N.
+ no native driver has been written (for example, an ATAPI PD-CD or
+ CDR drive); you can then use this emulation together with an
+ appropriate SCSI device driver. If both this SCSI emulation and
+ native ATAPI support are compiled into the kernel, the native
+ support will be used. Normally, say N.
CMD640 chipset bugfix/support
CONFIG_BLK_DEV_CMD640
@@ -303,17 +306,24 @@ CONFIG_BLK_DEV_RZ1000
Linux. This may slow disk throughput by a few percent, but at least
things will operate 100% reliably. If unsure, say Y.
-Intel 82371 PIIX (Triton I/II), VIA VP-1 DMA support
+Generic PCI IDE chipset support
+CONFIG_BLK_DEV_IDEPCI
+ Enable this for PCI systems which use IDE drive(s).
+ This option helps the IDE driver to automatically detect and
+ configure all PCI-based IDE interfaces in your system.
+ It is safe to say Y to this question.
+
+Generic PCI bus-master DMA support
CONFIG_BLK_DEV_IDEDMA
- If your PCI system uses IDE drive(s) (as opposed to SCSI, say)
- and is capable of bus-master DMA operation (most Pentium PCI
- systems), you will want to enable this option to allow use of
- bus-mastering DMA data transfers. Read the comments at the
- beginning of drivers/block/idedma.c and Documentation/ide.txt.
- You can get the latest version of the hdparm utility via
- ftp (user: anonymous) from
- sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is
- used to tune your harddisk.
+ If your PCI IDE controller is capable of bus-master DMA
+ (Direct Memory Access) transfers (most newer systems),
+ then you will want to enable this option to reduce CPU overhead.
+ With this option, Linux will automatically enable DMA transfers
+ in most cases, noting this with "DMA" appended to the drive
+ identification info. You can also use the "hdparm" utility to
+ enable DMA for drives which were not enabled automatically.
+ You can get the latest version of the hdparm utility via anonymous
+ FTP from sunsite.unc.edu/pub/Linux/system/hardware/
It is safe to say Y to this question.
Other IDE chipset support
@@ -371,6 +381,12 @@ CONFIG_BLK_DEV_OPTI621
for drives attached to an OPTi MIDE controller.
Please read the comments at the top of drivers/block/opti621.c.
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+ This driver adds detection and support for the NS87415 chip
+ (used in SPARC64, among others).
+ Please read the comments at the top of drivers/block/ns87415.c.
+
QDI QD6580 support
CONFIG_BLK_DEV_QD6580
This driver is enabled at runtime using the "ide0=qd6580" kernel
@@ -886,31 +902,8 @@ CONFIG_BINFMT_AOUT
Kernel support for JAVA binaries
CONFIG_BINFMT_JAVA
- JAVA(tm) is an object oriented programming language developed by
- SUN; JAVA programs are compiled into "JAVA bytecode" binaries which
- can then be interpreted by run time systems on many different
- operating systems. These JAVA binaries are becoming a universal
- executable format. If you want to execute JAVA binaries, read the
- Java on Linux HOWTO, available via ftp (user: anonymous) at
- sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
- the run time system contained in the Java Developers Kit (JDK) as
- described in the HOWTO. This is completely independent of the Linux
- kernel and you do NOT need to say Y here for this to work.
- Saying Y here allows you to execute a JAVA bytecode binary just like
- any other Linux program: by simply typing in its name. (You also
- need to have the JDK installed for this to work). As more and more
- Java programs become available, the use for this will gradually
- increase. You can even execute HTML files containing JAVA applets (=
- JAVA binaries) if those files start with the string
- "<!--applet-->". If you want to use this, say Y here and read
- Documentation/java.txt. If you disable this option it will reduce
- your kernel by about 4kB. This is not much and by itself does not
- warrant removing support. However its removal is a good idea if you
- do not have the JDK installed. You may answer M for module support
- and later load the module when you install the JDK or find an
- interesting Java program that you can't live without. The module
- will be called binfmt_java.o. If you don't know what to answer at
- this point then answer Y.
+ This option is obsolete. Use binfmt_misc instead. It is more
+ flexible.
Kernel support for Linux/Intel ELF binaries
CONFIG_BINFMT_EM86
@@ -1349,6 +1342,37 @@ CONFIG_IP_MASQUERADE
inserted in and removed from the running kernel whenever you want;
read Documentation/modules.txt for details.
+IP: ICMP masquerading
+CONFIG_IP_MASQUERADE_ICMP
+ The basic masquerade code described for CONFIG_IP_MASQUERADE only
+ handles TCP or UDP packets (and ICMP errors for existing
+ connections). This option adds additional support for masquerading
+ ICMP packets, such as ping or the probes used by the Windows 95
+ tracert program.
+ If you want this, say Y.
+
+IP: ipautofw masquerade support
+CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
+ ipautofw is a program by Richard Lynch allowing additional
+ support for masquerading protocols which do not (as yet)
+ have additional protocol helpers.
+ Information and source for ipautofw is available from
+ ftp://ftp.netis.com/pub/members/rlynch/
+ The ipautofw code is still under development and so is currently
+ marked EXPERIMENTAL.
+ If you want this, say Y.
+
+IP: ipportfw masquerade support
+CONFIG_IP_MASQUERADE_IPPORTFW
+ ipportfw is an addition to IP Masquerading written by Steven Clarke
+ to allow some forwarding of packets from outside to inside a
+ firewall on given ports. Information and source for ipportfw is
+ available from
+ http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html
+ The portfw code is still under development and so is currently
+ marked EXPERIMENTAL.
+ If you want this, say Y.
+
IP: always defragment
CONFIG_IP_ALWAYS_DEFRAG
This option means that all incoming fragments (= parts of IP packets
diff --git a/Documentation/filesystems/sysv-fs.txt b/Documentation/filesystems/sysv-fs.txt
index d6ba74af0..8e6df9472 100644
--- a/Documentation/filesystems/sysv-fs.txt
+++ b/Documentation/filesystems/sysv-fs.txt
@@ -28,9 +28,9 @@ Bugs in the present implementation:
Please report any bugs and suggestions to
- Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de> or
- Pascal Haible <haible@izfm.uni-stuttgart.de> .
-
+ Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>
+ Pascal Haible <haible@izfm.uni-stuttgart.de>
+ Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
Bruno Haible
<haible@ma2s2.mathematik.uni-karlsruhe.de>
diff --git a/MAINTAINERS b/MAINTAINERS
index cca41d95e..d27f74d3c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -279,6 +279,12 @@ M: andersee@debian.org
L: linux-kernel@vger.rutgers.edu
S: Maintained
+IDE/ATAPI TAPE/FLOPPY DRIVERS
+P: Gadi Oxman
+M: Gadi Oxman <gadio@netvision.net.il>
+L: linux-kernel@vger.rutgers.edu
+S: Maintained
+
ISDN SUBSYSTEM
P: Fritz Elfert
M: fritz@wuemaus.franken.de
@@ -551,6 +557,11 @@ P: Pavel Machek
M: pavel@atrey.karlin.mff.cuni.cz
S: Maintained
+SYSV FILESYSTEM
+P: Krzysztof G. Baranowski
+M: kgb@manjak.knm.org.pl
+S: Maintained
+
REST:
P: Linus Torvalds
S: Buried alive in diapers
diff --git a/Makefile b/Makefile
index d33fdbd47..2bf6c4447 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 72
+SUBLEVEL = 73
ARCH = mips
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 222b10939..f8793e75f 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -58,6 +58,7 @@ CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_CMD640=y
# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDE_CHIPSETS is not set
@@ -221,7 +222,6 @@ CONFIG_ISO9660_FS=y
# CONFIG_VFAT_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 5a13e0179..352c5552a 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -40,6 +40,10 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ldt.h>
+#include <asm/processor.h>
+#ifdef CONFIG_MATH_EMULATION
+#include <asm/math_emu.h>
+#endif
#ifdef __SMP__
asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
@@ -525,19 +529,16 @@ int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
{
int fpvalid;
-/* Flag indicating the math stuff is valid. We don't support this for the
- soft-float routines yet */
- if (hard_math) {
- if ((fpvalid = current->used_math) != 0) {
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0": :"m" (*fpu));
+ if ((fpvalid = current->used_math) != 0) {
+ if (hard_math) {
+ if (last_task_used_math == current) {
+ __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
+ }
else
memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
+ } else {
+ memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
}
- } else {
- /* we should dump the emulator state here, but we need to
- convert it into standard 387 format first.. */
- fpvalid = 0;
}
return fpvalid;
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 246a6c29b..e08d75100 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -16,6 +16,7 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
+#include <asm/processor.h>
/*
* does not yet catch signals sent when the child dies.
@@ -561,6 +562,102 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
}
+ case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+ if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+ 17*sizeof(long)))
+ {
+ ret = -EIO;
+ goto out;
+ }
+ for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
+ {
+ __put_user(getreg(child, i),(unsigned long *) data);
+ data += sizeof(long);
+ }
+ ret = 0;
+ goto out;
+ };
+
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ unsigned long tmp;
+ if (!access_ok(VERIFY_READ, (unsigned *)data,
+ 17*sizeof(long)))
+ {
+ ret = -EIO;
+ goto out;
+ }
+ for ( i = 0; i < 17*sizeof(long); i += sizeof(long) )
+ {
+ __get_user(tmp, (unsigned long *) data);
+ putreg(child, i, tmp);
+ data += sizeof(long);
+ }
+ ret = 0;
+ goto out;
+ };
+
+ case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+ if (!access_ok(VERIFY_WRITE, (unsigned *)data,
+ sizeof(struct user_i387_struct)))
+ {
+ ret = -EIO;
+ goto out;
+ }
+ ret = 0;
+ if ( !child->used_math ) {
+ /* Simulate an empty FPU. */
+ child->tss.i387.hard.cwd = 0xffff037f;
+ child->tss.i387.hard.swd = 0xffff0000;
+ child->tss.i387.hard.twd = 0xffffffff;
+ }
+#ifdef CONFIG_MATH_EMULATION
+ if ( hard_math ) {
+#endif
+ if (last_task_used_math == child) {
+ clts();
+ __asm__("fnsave %0; fwait":"=m" (child->tss.i387.hard));
+ last_task_used_math = NULL;
+ stts();
+ }
+ __copy_to_user((void *)data, &child->tss.i387.hard,
+ sizeof(struct user_i387_struct));
+#ifdef CONFIG_MATH_EMULATION
+ } else {
+ save_i387_soft(&child->tss.i387.soft,
+ (struct _fpstate *)data);
+ }
+#endif
+ goto out;
+ };
+
+ case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+ if (!access_ok(VERIFY_READ, (unsigned *)data,
+ sizeof(struct user_i387_struct)))
+ {
+ ret = -EIO;
+ goto out;
+ }
+ child->used_math = 1;
+#ifdef CONFIG_MATH_EMULATION
+ if ( hard_math ) {
+#endif
+ if (last_task_used_math == child) {
+ /* Discard the state of the FPU */
+ last_task_used_math = NULL;
+ }
+ __copy_from_user(&child->tss.i387.hard, (void *)data,
+ sizeof(struct user_i387_struct));
+ child->flags &= ~PF_USEDFPU;
+#ifdef CONFIG_MATH_EMULATION
+ } else {
+ restore_i387_soft(&child->tss.i387.soft,
+ (struct _fpstate *)data);
+ }
+#endif
+ ret = 0;
+ goto out;
+ };
+
default:
ret = -EIO;
goto out;
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 7d5cf3a95..853b82100 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -156,7 +156,6 @@ static inline void restore_i387_hard(struct _fpstate *buf)
stts();
}
#endif
- current->used_math = 1;
current->flags &= ~PF_USEDFPU;
__copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
}
@@ -169,8 +168,9 @@ static inline void restore_i387(struct _fpstate *buf)
if (hard_math)
restore_i387_hard(buf);
else
- restore_i387_soft(buf);
+ restore_i387_soft(&current->tss.i387.soft, buf);
#endif
+ current->used_math = 1;
}
static int
@@ -309,7 +309,6 @@ static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
#endif
current->tss.i387.hard.status = current->tss.i387.hard.swd;
copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf));
- current->used_math = 0;
return buf;
}
@@ -318,10 +317,16 @@ static struct _fpstate * save_i387(struct _fpstate *buf)
if (!current->used_math)
return NULL;
+ /* This will cause a "finit" to be triggered by the next
+ attempted FPU operation by the 'current' process.
+ */
+ current->used_math = 0;
+
#ifndef CONFIG_MATH_EMULATION
return save_i387_hard(buf);
#else
- return hard_math ? save_i387_hard(buf) : save_i387_soft(buf);
+ return hard_math ? save_i387_hard(buf)
+ : save_i387_soft(&current->tss.i387.soft, buf);
#endif
}
diff --git a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
index 1bd2cb40d..588f7ada2 100644
--- a/arch/i386/math-emu/Makefile
+++ b/arch/i386/math-emu/Makefile
@@ -12,18 +12,23 @@ CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
.S.o:
$(CC) -D__ASSEMBLY__ $(PARANOID) -c $<
-L_OBJS =fpu_entry.o div_small.o errors.o \
- fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
+# From 'C' language sources:
+C_OBJS =fpu_entry.o errors.o \
+ fpu_arith.o fpu_aux.o fpu_etc.o fpu_tags.o fpu_trig.o \
load_store.o get_address.o \
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
- reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \
- reg_div.o reg_mul.o reg_norm.o \
- reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
- reg_round.o \
+ reg_add_sub.o reg_compare.o reg_constant.o reg_convert.o \
+ reg_ld_str.o reg_divide.o reg_mul.o
+
+# From 80x86 assembler sources:
+A_OBJS =reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \
+ div_small.o reg_norm.o reg_round.o \
wm_shrx.o wm_sqrt.o \
div_Xsig.o polynom_Xsig.o round_Xsig.o \
shr_Xsig.o mul_Xsig.o
+L_OBJS =$(C_OBJS) $(A_OBJS)
+
include $(TOPDIR)/Rules.make
proto:
diff --git a/arch/i386/math-emu/README b/arch/i386/math-emu/README
index 5158b4b81..c6c774092 100644
--- a/arch/i386/math-emu/README
+++ b/arch/i386/math-emu/README
@@ -1,7 +1,7 @@
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
- | Copyright (C) 1992,1993,1994,1995,1996 |
+ | Copyright (C) 1992,1993,1994,1995,1996,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@suburbia.net |
| |
@@ -44,9 +44,12 @@ some differences.
Please report bugs, etc to me at:
billm@suburbia.net
+For more information on the emulator and on floating point topics, see
+my web pages, currently at http://www.suburbia.net/~billm/
+
--Bill Metzenthen
- October 1996
+ December 1997
----------------------- Internals of wm-FPU-emu -----------------------
@@ -95,8 +98,9 @@ form of re-entrancy which is required by the Linux kernel.
----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu
-(version 1.20) and the 80486 FPU (apart from bugs). Some of the more
-important differences are listed below:
+(version 2.00) and the 80486 FPU (apart from bugs). The differences
+are fewer than those which applied to the 1.xx series of the emulator.
+Some of the more important differences are listed below:
The Roundup flag does not have much meaning for the transcendental
functions and its 80486 value with these functions is likely to differ
@@ -122,18 +126,6 @@ and Unnormals. None of these will be generated by an 80486 or by the
emulator. Do not use them. The emulator treats them differently in
detail from the way an 80486 does.
-The emulator treats PseudoDenormals differently from an 80486. These
-numbers are in fact properly normalised numbers with the exponent
-offset by 1, and the emulator treats them as such. Unlike the 80486,
-the emulator does not generate a Denormal Operand exception for these
-numbers. The arithmetical results produced when using such a number as
-an operand are the same for the emulator and a real 80486 (apart from
-any slight precision difference for the transcendental functions).
-Neither the emulator nor an 80486 produces one of these numbers as the
-result of any arithmetic operation. An 80486 can keep one of these
-numbers in an FPU register with its identity as a PseudoDenormal, but
-the emulator will not; they are always converted to a valid number.
-
Self modifying code can cause the emulator to fail. An example of such
code is:
movl %esp,[%ebx]
diff --git a/arch/i386/math-emu/div_small.S b/arch/i386/math-emu/div_small.S
index 13ab2b7ae..47099628f 100644
--- a/arch/i386/math-emu/div_small.S
+++ b/arch/i386/math-emu/div_small.S
@@ -12,13 +12,13 @@
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
- | unsigned long div_small(unsigned long long *x, unsigned long y) |
+ | unsigned long FPU_div_small(unsigned long long *x, unsigned long y) |
+---------------------------------------------------------------------------*/
#include "fpu_emu.h"
.text
-ENTRY(div_small)
+ENTRY(FPU_div_small)
pushl %ebp
movl %esp,%ebp
diff --git a/arch/i386/math-emu/errors.c b/arch/i386/math-emu/errors.c
index 38a72e572..aff145f8a 100644
--- a/arch/i386/math-emu/errors.c
+++ b/arch/i386/math-emu/errors.c
@@ -21,9 +21,9 @@
#include <asm/uaccess.h>
+#include "fpu_emu.h"
#include "fpu_system.h"
#include "exception.h"
-#include "fpu_emu.h"
#include "status_w.h"
#include "control_w.h"
#include "reg_constant.h"
@@ -36,7 +36,7 @@
void Un_impl(void)
{
- unsigned char byte1, FPU_modrm;
+ u_char byte1, FPU_modrm;
unsigned long address = FPU_ORIG_EIP;
RE_ENTRANT_CHECK_OFF;
@@ -46,13 +46,13 @@ void Un_impl(void)
{
while ( 1 )
{
- get_user(byte1, (unsigned char *) address);
+ FPU_get_user(byte1, (u_char *) address);
if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1);
address++;
}
printk("%02x ", byte1);
- get_user(FPU_modrm, 1 + (unsigned char *) address);
+ FPU_get_user(FPU_modrm, 1 + (u_char *) address);
if (FPU_modrm >= 0300)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -82,12 +82,12 @@ void FPU_illegal(void)
-void emu_printall(void)
+void FPU_printall(void)
{
int i;
- static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
- "DeNorm", "Inf", "NaN", "Empty" };
- unsigned char byte1, FPU_modrm;
+ static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
+ "DeNorm", "Inf", "NaN" };
+ u_char byte1, FPU_modrm;
unsigned long address = FPU_ORIG_EIP;
RE_ENTRANT_CHECK_OFF;
@@ -98,7 +98,7 @@ void emu_printall(void)
#define MAX_PRINTED_BYTES 20
for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
{
- get_user(byte1, (unsigned char *) address);
+ FPU_get_user(byte1, (u_char *) address);
if ( (byte1 & 0xf8) == 0xd8 )
{
printk(" %02x", byte1);
@@ -111,7 +111,7 @@ void emu_printall(void)
printk(" [more..]\n");
else
{
- get_user(FPU_modrm, 1 + (unsigned char *) address);
+ FPU_get_user(FPU_modrm, 1 + (u_char *) address);
if (FPU_modrm >= 0300)
printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -166,29 +166,23 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
for ( i = 0; i < 8; i++ )
{
FPU_REG *r = &st(i);
- char tagi = r->tag;
+ u_char tagi = FPU_gettagi(i);
switch (tagi)
{
- case TW_Empty:
+ case TAG_Empty:
continue;
break;
- case TW_Zero:
-#if 0
- printk("st(%d) %c .0000 0000 0000 0000 ",
- i, r->sign ? '-' : '+');
- break;
-#endif
- case TW_Valid:
- case TW_NaN:
-/* case TW_Denormal: */
- case TW_Infinity:
- printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
- r->sign ? '-' : '+',
+ case TAG_Zero:
+ case TAG_Special:
+ tagi = FPU_Special(r);
+ case TAG_Valid:
+ printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
+ getsign(r) ? '-' : '+',
(long)(r->sigh >> 16),
(long)(r->sigh & 0xFFFF),
(long)(r->sigl >> 16),
(long)(r->sigl & 0xFFFF),
- r->exp - EXP_BIAS + 1);
+ exponent(r) - EXP_BIAS + 1);
break;
default:
printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
@@ -262,6 +256,11 @@ static struct {
0x161 in reg_ld_str.c
0x162 in reg_ld_str.c
0x163 in reg_ld_str.c
+ 0x164 in reg_ld_str.c
+ 0x170 in fpu_tags.c
+ 0x171 in fpu_tags.c
+ 0x172 in fpu_tags.c
+ 0x180 in reg_convert.c
0x2nn in an *.S file:
0x201 in reg_u_add.S
0x202 in reg_u_div.S
@@ -347,11 +346,11 @@ void FPU_exception(int n)
if ( n == EX_INTERNAL )
{
printk("FPU emulator: Internal error type 0x%04x\n", int_type);
- emu_printall();
+ FPU_printall();
}
#ifdef PRINT_MESSAGES
else
- emu_printall();
+ FPU_printall();
#endif PRINT_MESSAGES
/*
@@ -369,24 +368,97 @@ void FPU_exception(int n)
}
-/* Real operation attempted on two operands, one a NaN. */
-/* Returns nz if the exception is unmasked */
-asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
+/* Real operation attempted on a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_1op_NaN(FPU_REG *a)
{
- FPU_REG const *x;
- int signalling;
+ int signalling, isNaN;
+
+ isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
/* The default result for the case of two "equal" NaNs (signs may
differ) is chosen to reproduce 80486 behaviour */
- x = a;
- if (a->tag == TW_NaN)
+ signalling = isNaN && !(a->sigh & 0x40000000);
+
+ if ( !signalling )
{
- if (b->tag == TW_NaN)
+ if ( !isNaN ) /* pseudo-NaN, or other unsupported? */
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ reg_copy(&CONST_QNaN, a);
+ }
+ EXCEPTION(EX_Invalid);
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+ }
+ return TAG_Special;
+ }
+
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ if ( !(a->sigh & 0x80000000) ) /* pseudo-NaN ? */
+ {
+ reg_copy(&CONST_QNaN, a);
+ }
+ /* ensure a Quiet NaN */
+ a->sigh |= 0x40000000;
+ }
+
+ EXCEPTION(EX_Invalid);
+
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+}
+
+
+/* Real operation attempted on two operands, one a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_2op_NaN(FPU_REG const *b, u_char tagb,
+ int deststnr,
+ FPU_REG const *defaultNaN)
+{
+ FPU_REG *dest = &st(deststnr);
+ FPU_REG const *a = dest;
+ u_char taga = FPU_gettagi(deststnr);
+ FPU_REG const *x;
+ int signalling, unsupported;
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ /* TW_NaN is also used for unsupported data types. */
+ unsupported = ((taga == TW_NaN)
+ && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000)))
+ || ((tagb == TW_NaN)
+ && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
+ if ( unsupported )
+ {
+ if ( control_word & CW_Invalid )
+ {
+ /* Masked response */
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
+ }
+ EXCEPTION(EX_Invalid);
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+ }
+
+ if (taga == TW_NaN)
+ {
+ x = a;
+ if (tagb == TW_NaN)
{
signalling = !(a->sigh & b->sigh & 0x40000000);
- /* find the "larger" */
- if ( significand(a) < significand(b) )
+ if ( significand(b) > significand(a) )
x = b;
+ else if ( significand(b) == significand(a) )
+ {
+ /* The default result for the case of two "equal" NaNs (signs may
+ differ) is chosen to reproduce 80486 behaviour */
+ x = defaultNaN;
+ }
}
else
{
@@ -396,7 +468,7 @@ asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
}
else
#ifdef PARANOID
- if (b->tag == TW_NaN)
+ if (tagb == TW_NaN)
#endif PARANOID
{
signalling = !(b->sigh & 0x40000000);
@@ -411,33 +483,32 @@ asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
}
#endif PARANOID
- if ( !signalling )
+ if ( (!signalling) || (control_word & CW_Invalid) )
{
- if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
- x = &CONST_QNaN;
- reg_move(x, dest);
- return 0;
- }
+ if ( ! x )
+ x = b;
- if ( control_word & CW_Invalid )
- {
- /* The masked response */
if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
x = &CONST_QNaN;
- reg_move(x, dest);
+
+ FPU_copy_to_regi(x, TAG_Special, deststnr);
+
+ if ( !signalling )
+ return TAG_Special;
+
/* ensure a Quiet NaN */
dest->sigh |= 0x40000000;
}
EXCEPTION(EX_Invalid);
-
- return !(control_word & CW_Invalid);
+
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
}
/* Invalid arith operation on Valid registers */
-/* Returns nz if the exception is unmasked */
-asmlinkage int arith_invalid(FPU_REG *dest)
+/* Returns < 0 if the exception is unmasked */
+asmlinkage int arith_invalid(int deststnr)
{
EXCEPTION(EX_Invalid);
@@ -445,28 +516,31 @@ asmlinkage int arith_invalid(FPU_REG *dest)
if ( control_word & CW_Invalid )
{
/* The masked response */
- reg_move(&CONST_QNaN, dest);
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
}
- return !(control_word & CW_Invalid);
+ return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
}
/* Divide a finite number by zero */
-asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
+asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
{
+ FPU_REG *dest = &st(deststnr);
+ int tag = TAG_Valid;
if ( control_word & CW_ZeroDiv )
{
/* The masked response */
- reg_move(&CONST_INF, dest);
- dest->sign = (unsigned char)sign;
+ FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
+ setsign(dest, sign);
+ tag = TAG_Special;
}
EXCEPTION(EX_ZeroDiv);
- return !(control_word & CW_ZeroDiv);
+ return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
}
@@ -495,7 +569,6 @@ asmlinkage void set_precision_flag_up(void)
partial_status |= (SW_Precision | SW_C1); /* The masked response */
else
EXCEPTION(EX_Precision | SW_C1);
-
}
@@ -517,32 +590,31 @@ asmlinkage int denormal_operand(void)
if ( control_word & CW_Denormal )
{ /* The masked response */
partial_status |= SW_Denorm_Op;
- return 0;
+ return TAG_Special;
}
else
{
EXCEPTION(EX_Denormal);
- return 1;
+ return TAG_Special | FPU_Exception;
}
}
asmlinkage int arith_overflow(FPU_REG *dest)
{
+ int tag = TAG_Valid;
if ( control_word & CW_Overflow )
{
- char sign;
/* The masked response */
/* ###### The response here depends upon the rounding mode */
- sign = dest->sign;
- reg_move(&CONST_INF, dest);
- dest->sign = sign;
+ reg_copy(&CONST_INF, dest);
+ tag = TAG_Special;
}
else
{
/* Subtract the magic number from the exponent */
- dest->exp -= (3 * (1 << 13));
+ addexponent(dest, (-3 * (1 << 13)));
}
EXCEPTION(EX_Overflow);
@@ -553,30 +625,36 @@ asmlinkage int arith_overflow(FPU_REG *dest)
The roundup bit (C1) is also set because we have
"rounded" upwards to Infinity. */
EXCEPTION(EX_Precision | SW_C1);
- return !(control_word & CW_Precision);
+ return tag;
}
- return 0;
+ return tag;
}
asmlinkage int arith_underflow(FPU_REG *dest)
{
+ int tag = TAG_Valid;
if ( control_word & CW_Underflow )
{
/* The masked response */
- if ( dest->exp <= EXP_UNDER - 63 )
+ if ( exponent16(dest) <= EXP_UNDER - 63 )
{
- reg_move(&CONST_Z, dest);
+ reg_copy(&CONST_Z, dest);
partial_status &= ~SW_C1; /* Round down. */
+ tag = TAG_Zero;
+ }
+ else
+ {
+ stdexp(dest);
}
}
else
{
/* Add the magic number to the exponent. */
- dest->exp += (3 * (1 << 13));
+ addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
}
EXCEPTION(EX_Underflow);
@@ -584,22 +662,22 @@ asmlinkage int arith_underflow(FPU_REG *dest)
{
/* The underflow exception is masked. */
EXCEPTION(EX_Precision);
- return !(control_word & CW_Precision);
+ return tag;
}
- return 0;
+ return tag;
}
-void stack_overflow(void)
+void FPU_stack_overflow(void)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
top--;
- reg_move(&CONST_QNaN, &st(0));
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
}
EXCEPTION(EX_StackOver);
@@ -609,13 +687,13 @@ void stack_overflow(void)
}
-void stack_underflow(void)
+void FPU_stack_underflow(void)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
- reg_move(&CONST_QNaN, &st(0));
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
}
EXCEPTION(EX_StackUnder);
@@ -625,13 +703,13 @@ void stack_underflow(void)
}
-void stack_underflow_i(int i)
+void FPU_stack_underflow_i(int i)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
- reg_move(&CONST_QNaN, &(st(i)));
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
}
EXCEPTION(EX_StackUnder);
@@ -641,14 +719,14 @@ void stack_underflow_i(int i)
}
-void stack_underflow_pop(int i)
+void FPU_stack_underflow_pop(int i)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
- reg_move(&CONST_QNaN, &(st(i)));
- pop();
+ FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
+ FPU_pop();
}
EXCEPTION(EX_StackUnder);
diff --git a/arch/i386/math-emu/fpu_arith.c b/arch/i386/math-emu/fpu_arith.c
index 96e6bd89b..fcad7ec08 100644
--- a/arch/i386/math-emu/fpu_arith.c
+++ b/arch/i386/math-emu/fpu_arith.c
@@ -3,9 +3,9 @@
| |
| Code to implement the FPU register/register arithmetic instructions |
| |
- | Copyright (C) 1992,1993 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -19,16 +19,18 @@
void fadd__()
{
/* fadd st,st(i) */
+ int i = FPU_rm;
clear_C1();
- reg_add(&st(0), &st(FPU_rm), &st(0), control_word);
+ FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
}
void fmul__()
{
/* fmul st,st(i) */
+ int i = FPU_rm;
clear_C1();
- reg_mul(&st(0), &st(FPU_rm), &st(0), control_word);
+ FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
}
@@ -37,7 +39,7 @@ void fsub__()
{
/* fsub st,st(i) */
clear_C1();
- reg_sub(&st(0), &st(FPU_rm), &st(0), control_word);
+ FPU_sub(0, FPU_rm, control_word);
}
@@ -45,7 +47,7 @@ void fsubr_()
{
/* fsubr st,st(i) */
clear_C1();
- reg_sub(&st(FPU_rm), &st(0), &st(0), control_word);
+ FPU_sub(REV, FPU_rm, control_word);
}
@@ -53,7 +55,7 @@ void fdiv__()
{
/* fdiv st,st(i) */
clear_C1();
- reg_div(&st(0), &st(FPU_rm), &st(0), control_word);
+ FPU_div(0, FPU_rm, control_word);
}
@@ -61,7 +63,7 @@ void fdivr_()
{
/* fdivr st,st(i) */
clear_C1();
- reg_div(&st(FPU_rm), &st(0), &st(0), control_word);
+ FPU_div(REV, FPU_rm, control_word);
}
@@ -69,8 +71,9 @@ void fdivr_()
void fadd_i()
{
/* fadd st(i),st */
+ int i = FPU_rm;
clear_C1();
- reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+ FPU_add(&st(i), FPU_gettagi(i), i, control_word);
}
@@ -78,27 +81,23 @@ void fmul_i()
{
/* fmul st(i),st */
clear_C1();
- reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+ FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
}
void fsubri()
{
/* fsubr st(i),st */
- /* This is the sense of the 80486 manual
- reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
clear_C1();
- reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+ FPU_sub(DEST_RM, FPU_rm, control_word);
}
void fsub_i()
{
/* fsub st(i),st */
- /* This is the sense of the 80486 manual
- reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
clear_C1();
- reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
+ FPU_sub(REV|DEST_RM, FPU_rm, control_word);
}
@@ -106,7 +105,7 @@ void fdivri()
{
/* fdivr st(i),st */
clear_C1();
- reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
+ FPU_div(DEST_RM, FPU_rm, control_word);
}
@@ -114,7 +113,7 @@ void fdiv_i()
{
/* fdiv st(i),st */
clear_C1();
- reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
+ FPU_div(REV|DEST_RM, FPU_rm, control_word);
}
@@ -122,9 +121,10 @@ void fdiv_i()
void faddp_()
{
/* faddp st(i),st */
+ int i = FPU_rm;
clear_C1();
- if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 )
+ FPU_pop();
}
@@ -132,8 +132,8 @@ void fmulp_()
{
/* fmulp st(i),st */
clear_C1();
- if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 )
+ FPU_pop();
}
@@ -141,22 +141,18 @@ void fmulp_()
void fsubrp()
{
/* fsubrp st(i),st */
- /* This is the sense of the 80486 manual
- reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
clear_C1();
- if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_sub(DEST_RM, FPU_rm, control_word) >= 0 )
+ FPU_pop();
}
void fsubp_()
{
/* fsubp st(i),st */
- /* This is the sense of the 80486 manual
- reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
clear_C1();
- if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_sub(REV|DEST_RM, FPU_rm, control_word) >= 0 )
+ FPU_pop();
}
@@ -164,8 +160,8 @@ void fdivrp()
{
/* fdivrp st(i),st */
clear_C1();
- if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_div(DEST_RM, FPU_rm, control_word) >= 0 )
+ FPU_pop();
}
@@ -173,7 +169,6 @@ void fdivp_()
{
/* fdivp st(i),st */
clear_C1();
- if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
- pop();
+ if ( FPU_div(REV|DEST_RM, FPU_rm, control_word) >= 0 )
+ FPU_pop();
}
-
diff --git a/arch/i386/math-emu/fpu_asm.h b/arch/i386/math-emu/fpu_asm.h
index d08fbc874..d89d676c7 100644
--- a/arch/i386/math-emu/fpu_asm.h
+++ b/arch/i386/math-emu/fpu_asm.h
@@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------+
| fpu_asm.h |
| |
- | Copyright (C) 1992,1995 |
+ | Copyright (C) 1992,1995,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
+---------------------------------------------------------------------------*/
@@ -19,13 +19,14 @@
#define PARAM2 12(%ebp)
#define PARAM3 16(%ebp)
#define PARAM4 20(%ebp)
+#define PARAM5 24(%ebp)
+#define PARAM6 28(%ebp)
+#define PARAM7 32(%ebp)
-#define SIGL_OFFSET 8
-#define SIGN(x) (x)
-#define TAG(x) 1(x)
-#define EXP(x) 4(x)
+#define SIGL_OFFSET 0
+#define EXP(x) 8(x)
#define SIG(x) SIGL_OFFSET##(x)
#define SIGL(x) SIGL_OFFSET##(x)
-#define SIGH(x) 12(x)
+#define SIGH(x) 4(x)
#endif _FPU_ASM_H_
diff --git a/arch/i386/math-emu/fpu_aux.c b/arch/i386/math-emu/fpu_aux.c
index 0d35fe19b..112c173f2 100644
--- a/arch/i386/math-emu/fpu_aux.c
+++ b/arch/i386/math-emu/fpu_aux.c
@@ -3,9 +3,9 @@
| |
| Code to implement some of the FPU auxiliary instructions. |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -32,15 +32,11 @@ void fclex(void)
/* Needs to be externally visible */
void finit()
{
- int r;
control_word = 0x037f;
partial_status = 0;
top = 0; /* We don't keep top in the status word internally. */
- for (r = 0; r < 8; r++)
- {
- regs[r].tag = TW_Empty;
- }
- /* The behaviour is different to that detailed in
+ fpu_tag_word = 0xffff;
+ /* The behaviour is different from that detailed in
Section 15.1.6 of the Intel manual */
operand_address.offset = 0;
operand_address.selector = 0;
@@ -99,19 +95,27 @@ void fp_nop()
void fld_i_()
{
FPU_REG *st_new_ptr;
+ int i;
+ u_char tag;
if ( STACK_OVERFLOW )
- { stack_overflow(); return; }
+ { FPU_stack_overflow(); return; }
/* fld st(i) */
- if ( NOT_EMPTY(FPU_rm) )
- { reg_move(&st(FPU_rm), st_new_ptr); push(); }
+ i = FPU_rm;
+ if ( NOT_EMPTY(i) )
+ {
+ reg_copy(&st(i), st_new_ptr);
+ tag = FPU_gettagi(i);
+ push();
+ FPU_settag0(tag);
+ }
else
{
if ( control_word & CW_Invalid )
{
/* The masked response */
- stack_underflow();
+ FPU_stack_underflow();
}
else
EXCEPTION(EX_StackUnder);
@@ -124,61 +128,77 @@ void fxch_i()
{
/* fxch st(i) */
FPU_REG t;
- register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0);
-
- if ( st0_ptr->tag == TW_Empty )
+ int i = FPU_rm;
+ FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
+ long tag_word = fpu_tag_word;
+ int regnr = top & 7, regnri = ((regnr + i) & 7);
+ u_char st0_tag = (tag_word >> (regnr*2)) & 3;
+ u_char sti_tag = (tag_word >> (regnri*2)) & 3;
+
+ if ( st0_tag == TAG_Empty )
{
- if ( sti_ptr->tag == TW_Empty )
+ if ( sti_tag == TAG_Empty )
{
- stack_underflow();
- stack_underflow_i(FPU_rm);
+ FPU_stack_underflow();
+ FPU_stack_underflow_i(i);
return;
}
if ( control_word & CW_Invalid )
- reg_move(sti_ptr, st0_ptr); /* Masked response */
- stack_underflow_i(FPU_rm);
+ {
+ /* Masked response */
+ FPU_copy_to_reg0(sti_ptr, sti_tag);
+ }
+ FPU_stack_underflow_i(i);
return;
}
- if ( sti_ptr->tag == TW_Empty )
+ if ( sti_tag == TAG_Empty )
{
if ( control_word & CW_Invalid )
- reg_move(st0_ptr, sti_ptr); /* Masked response */
- stack_underflow();
+ {
+ /* Masked response */
+ FPU_copy_to_regi(st0_ptr, st0_tag, i);
+ }
+ FPU_stack_underflow();
return;
}
clear_C1();
- reg_move(st0_ptr, &t);
- reg_move(sti_ptr, st0_ptr);
- reg_move(&t, sti_ptr);
+
+ reg_copy(st0_ptr, &t);
+ reg_copy(sti_ptr, st0_ptr);
+ reg_copy(&t, sti_ptr);
+
+ tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
+ tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
+ fpu_tag_word = tag_word;
}
void ffree_()
{
/* ffree st(i) */
- st(FPU_rm).tag = TW_Empty;
+ FPU_settagi(FPU_rm, TAG_Empty);
}
void ffreep()
{
/* ffree st(i) + pop - unofficial code */
- st(FPU_rm).tag = TW_Empty;
- pop();
+ FPU_settagi(FPU_rm, TAG_Empty);
+ FPU_pop();
}
void fst_i_()
{
/* fst st(i) */
- reg_move(&st(0), &st(FPU_rm));
+ FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
}
void fstp_i()
{
/* fstp st(i) */
- reg_move(&st(0), &st(FPU_rm));
- pop();
+ FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
+ FPU_pop();
}
diff --git a/arch/i386/math-emu/fpu_emu.h b/arch/i386/math-emu/fpu_emu.h
index b8385db1f..e5734c82d 100644
--- a/arch/i386/math-emu/fpu_emu.h
+++ b/arch/i386/math-emu/fpu_emu.h
@@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------+
| fpu_emu.h |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
+---------------------------------------------------------------------------*/
@@ -12,14 +12,6 @@
#define _FPU_EMU_H_
/*
- * Define DENORM_OPERAND to make the emulator detect denormals
- * and use the denormal flag of the status word. Note: this only
- * affects the flag and corresponding interrupt, the emulator
- * will always generate denormals and operate upon them as required.
- */
-#define DENORM_OPERAND
-
-/*
* Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
* rather than behaviour which appears to be cleaner.
* This is a matter of opinion: for all I know, the 80486 may simply
@@ -38,28 +30,51 @@
#define EXP_BIAS Const(0)
#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
+#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but
+ still a 16 bit nr. */
#define EXP_Infinity EXP_OVER
#define EXP_NaN EXP_OVER
+#define EXTENDED_Ebias Const(0x3fff)
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
#define SIGN_POS Const(0)
-#define SIGN_NEG Const(1)
+#define SIGN_NEG Const(0x80)
+
+#define SIGN_Positive Const(0)
+#define SIGN_Negative Const(0x8000)
-/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
-#define TW_Valid Const(0) /* valid */
-#define TW_Zero Const(1) /* zero */
+
+/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
/* The following fold to 2 (Special) in the Tag Word */
-/* #define TW_Denormal Const(4) */ /* De-normal */
+#define TW_Denormal Const(4) /* De-normal */
#define TW_Infinity Const(5) /* + or - infinity */
#define TW_NaN Const(6) /* Not a Number */
+#define TW_Unsupported Const(7) /* Not supported by an 80486 */
+
+#define TAG_Valid Const(0) /* valid */
+#define TAG_Zero Const(1) /* zero */
+#define TAG_Special Const(2) /* De-normal, + or - infinity,
+ or Not a Number */
+#define TAG_Empty Const(3) /* empty */
+
+#define LOADED_DATA Const(10101) /* Special st() number to identify
+ loaded data (not on stack). */
+
+/* A few flags (must be >= 0x10). */
+#define REV 0x10
+#define DEST_RM 0x20
+#define LOADED 0x40
-#define TW_Empty Const(7) /* empty */
+#define FPU_Exception Const(0x80000000) /* Added to tag returns. */
#ifndef __ASSEMBLY__
-#include <asm/sigcontext.h> /* for struct _fpstate */
-#include <asm/math_emu.h>
+#include "fpu_system.h"
+#include <asm/sigcontext.h> /* for struct _fpstate */
+#include <asm/math_emu.h>
#include <linux/linkage.h>
/*
@@ -67,7 +82,7 @@
*/
#ifdef RE_ENTRANT_CHECKING
-extern char emulating;
+extern u_char emulating;
# define RE_ENTRANT_CHECK_OFF emulating = 0
# define RE_ENTRANT_CHECK_ON emulating = 1
#else
@@ -97,18 +112,24 @@ extern char emulating;
struct address {
unsigned int offset;
- unsigned short selector;
- unsigned short opcode:11,
- empty:5;
+ unsigned int selector:16;
+ unsigned int opcode:11;
+ unsigned int empty:5;
+};
+struct fpu__reg {
+ unsigned sigl;
+ unsigned sigh;
+ short exp;
};
+
typedef void (*FUNC)(void);
-typedef struct fpu_reg FPU_REG;
-typedef void (*FUNC_ST0)(FPU_REG *st0_ptr);
-typedef struct { unsigned char address_size, operand_size, segment; }
+typedef struct fpu__reg FPU_REG;
+typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag);
+typedef struct { u_char address_size, operand_size, segment; }
overrides;
/* This structure is 32 bits: */
typedef struct { overrides override;
- unsigned char default_mode; } fpu_addr_modes;
+ u_char default_mode; } fpu_addr_modes;
/* PROTECTED has a restricted meaning in the emulator; it is used
to signal that the emulator needs to do special things to ensure
that protection is respected in a segmented model. */
@@ -117,27 +138,50 @@ typedef struct { overrides override;
#define VM86 SIXTEEN
#define PM16 (SIXTEEN | PROTECTED)
#define SEG32 PROTECTED
-extern unsigned char const data_sizes_16[32];
+extern u_char const data_sizes_16[32];
+
+#define register_base ((u_char *) registers )
+#define fpu_register(x) ( * ((FPU_REG *)( register_base + 10 * (x & 7) )) )
+#define st(x) ( * ((FPU_REG *)( register_base + 10 * ((top+x) & 7) )) )
-#define st(x) ( regs[((top+x) &7 )] )
+#define STACK_OVERFLOW (FPU_stackoverflow(&st_new_ptr))
+#define NOT_EMPTY(i) (!FPU_empty_i(i))
-#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
-#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
-#define NOT_EMPTY_ST0 (st0_tag ^ TW_Empty)
+#define NOT_EMPTY_ST0 (st0_tag ^ TAG_Empty)
-#define pop() { regs[(top++ & 7 )].tag = TW_Empty; }
-#define poppop() { regs[((top + 1) & 7 )].tag \
- = regs[(top & 7 )].tag = TW_Empty; \
- top += 2; }
+#define poppop() { FPU_pop(); FPU_pop(); }
/* push() does not affect the tags */
#define push() { top--; }
+#define signbyte(a) (((u_char *)(a))[9])
+#define getsign(a) (signbyte(a) & 0x80)
+#define setsign(a,b) { if (b) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; }
+#define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \
+ else signbyte(b) &= 0x7f; }
+#define changesign(a) { signbyte(a) ^= 0x80; }
+#define setpositive(a) { signbyte(a) &= 0x7f; }
+#define setnegative(a) { signbyte(a) |= 0x80; }
+#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
+#define signnegative(a) (signbyte(a) & 0x80)
+
+#include "fpu_proto.h"
+
+static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
+{
+ *(short *)&(y->exp) = *(const short *)&(x->exp);
+ *(long long *)&(y->sigl) = *(const long long *)&(x->sigl);
+}
+
+#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias)
+#define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \
+ ((y) + EXTENDED_Ebias) & 0x7fff; }
+#define exponent16(x) (*(short *)&((x)->exp))
+#define setexponent16(x,y) { (*(short *)&((x)->exp)) = (y); }
+#define addexponent(x,y) { (*(short *)&((x)->exp)) += (y); }
+#define stdexp(x) { (*(short *)&((x)->exp)) += EXTENDED_Ebias; }
-#define reg_move(x, y) { \
- *(short *)&((y)->sign) = *(const short *)&((x)->sign); \
- *(long *)&((y)->exp) = *(const long *)&((x)->exp); \
- *(long long *)&((y)->sigl) = *(const long long *)&((x)->sigl); }
+#define isdenormal(ptr) (exponent(ptr) == EXP_BIAS+EXP_UNDER)
#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
@@ -145,24 +189,26 @@ extern unsigned char const data_sizes_16[32];
/*----- Prototypes for functions written in assembler -----*/
/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
-asmlinkage void normalize(FPU_REG *x);
-asmlinkage void normalize_nuo(FPU_REG *x);
-asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2,
- FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
- FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
- FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
- FPU_REG *answ, unsigned int control_w);
-asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
- FPU_REG *answ, unsigned int control_w);
-asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w);
-asmlinkage unsigned shrx(void *l, unsigned x);
-asmlinkage unsigned shrxs(void *v, unsigned x);
-asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y);
-asmlinkage void round_reg(FPU_REG *arg, unsigned int extent,
- unsigned int control_w);
+asmlinkage int FPU_normalize(FPU_REG *x);
+asmlinkage int FPU_normalize_nuo(FPU_REG *x);
+asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, unsigned int control_w, u_char sign,
+ int expa, int expb);
+asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, unsigned int control_w, u_char sign,
+ int expon);
+asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, unsigned int control_w, u_char sign);
+asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
+ FPU_REG *answ, unsigned int control_w, u_char sign,
+ int expa, int expb);
+asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2,
+ unsigned int control_w, u_char sign);
+asmlinkage unsigned FPU_shrx(void *l, unsigned x);
+asmlinkage unsigned FPU_shrxs(void *v, unsigned x);
+asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y);
+asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy,
+ unsigned int control_w, u_char sign);
#ifndef MAKING_PROTO
#include "fpu_proto.h"
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
index 943daf3b9..36ca90a35 100644
--- a/arch/i386/math-emu/fpu_entry.c
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -3,9 +3,9 @@
| |
| The entry functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993,1994,1996 |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- | E-mail billm@jacobi.maths.monash.edu.au |
+ | E-mail billm@suburbia.net |
| |
| See the files "README" and "COPYING" for further copyright and warranty |
| information. |
@@ -54,27 +54,27 @@
#define _df_d8_ fstp_i /* unofficial code (1f) */
static FUNC const st_instr_table[64] = {
- fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
- fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
- fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
- fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
- fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
- fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
- fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
- fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
+ fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
+ fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
+ fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
};
#else /* Support only documented FPU op-codes */
static FUNC const st_instr_table[64] = {
- fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
- fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
- fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
- fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
- fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
- fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
- fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
- fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
};
#endif NO_UNDOC_CODE
@@ -95,7 +95,7 @@ static FUNC const st_instr_table[64] = {
/* Un-documented FPU op-codes supported by default. (see above) */
-static unsigned char const type_table[64] = {
+static u_char const type_table[64] = {
_REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
_REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
_REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
@@ -108,7 +108,7 @@ static unsigned char const type_table[64] = {
#else /* Support only documented FPU op-codes */
-static unsigned char const type_table[64] = {
+static u_char const type_table[64] = {
_REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
_REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
_REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
@@ -123,26 +123,26 @@ static unsigned char const type_table[64] = {
#ifdef RE_ENTRANT_CHECKING
-char emulating=0;
+u_char emulating=0;
#endif RE_ENTRANT_CHECKING
-static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
overrides *override);
asmlinkage void math_emulate(long arg)
{
- unsigned char FPU_modrm, byte1;
+ u_char FPU_modrm, byte1;
unsigned short code;
fpu_addr_modes addr_modes;
int unmasked;
FPU_REG loaded_data;
+ FPU_REG *st0_ptr;
+ u_char loaded_tag, st0_tag;
void *data_address;
struct address data_sel_off;
struct address entry_sel_off;
unsigned long code_base = 0;
unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
- char st0_tag;
- FPU_REG *st0_ptr;
struct desc_struct code_descriptor;
#ifdef RE_ENTRANT_CHECKING
@@ -155,15 +155,6 @@ asmlinkage void math_emulate(long arg)
if (!current->used_math)
{
- int i;
- for ( i = 0; i < 8; i++ )
- {
- /* Make sure that the registers are compatible
- with the assumptions of the emulator. */
- if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
- && (regs[i].sigl == 0)) )
- regs[i].sigh |= 0x80000000;
- }
finit();
current->used_math = 1;
}
@@ -221,7 +212,7 @@ asmlinkage void math_emulate(long arg)
if (current->flags & PF_PTRACED)
FPU_lookahead = 0;
- if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+ if ( !valid_prefix(&byte1, (u_char **)&FPU_EIP,
&addr_modes.override) )
{
RE_ENTRANT_CHECK_OFF;
@@ -264,7 +255,7 @@ do_another_FPU_instruction:
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(FPU_modrm, (unsigned char *) FPU_EIP);
+ FPU_get_user(FPU_modrm, (u_char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
@@ -287,6 +278,7 @@ do_another_FPU_instruction:
* interrupts here.
*/
do_the_FPU_interrupt:
+
FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
RE_ENTRANT_CHECK_OFF;
@@ -309,11 +301,11 @@ do_another_FPU_instruction:
if ( (addr_modes.default_mode & SIXTEEN)
^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
- data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
- addr_modes);
+ data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
+ addr_modes);
else
- data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
- addr_modes);
+ data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
+ addr_modes);
if ( addr_modes.default_mode )
{
@@ -326,7 +318,7 @@ do_another_FPU_instruction:
unsigned short status1 = partial_status;
st0_ptr = &st(0);
- st0_tag = st0_ptr->tag;
+ st0_tag = FPU_gettag0();
/* Stack underflow has priority */
if ( NOT_EMPTY_ST0 )
@@ -342,29 +334,34 @@ do_another_FPU_instruction:
switch ( (byte1 >> 1) & 3 )
{
case 0:
- unmasked = reg_load_single((float *)data_address,
+ unmasked = FPU_load_single((float *)data_address,
&loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
break;
case 1:
- reg_load_int32((long *)data_address, &loaded_data);
+ loaded_tag = FPU_load_int32((long *)data_address, &loaded_data);
break;
case 2:
- unmasked = reg_load_double((double *)data_address,
+ unmasked = FPU_load_double((double *)data_address,
&loaded_data);
+ loaded_tag = unmasked & 0xff;
+ unmasked &= ~0xff;
break;
case 3:
- reg_load_int16((short *)data_address, &loaded_data);
+ default: /* Used here to suppress gcc warnings. */
+ loaded_tag = FPU_load_int16((short *)data_address, &loaded_data);
break;
}
-
+
/* No more access to user memory, it is safe
to use static data now */
/* NaN operands have the next priority. */
/* We have to delay looking at st(0) until after
loading the data, because that data might contain an SNaN */
- if ( (st0_tag == TW_NaN) ||
- (loaded_data.tag == TW_NaN) )
+ if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
+ ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
{
/* Restore the status word; we might have loaded a
denormal. */
@@ -375,22 +372,22 @@ do_another_FPU_instruction:
EXCEPTION(EX_Invalid);
setcc(SW_C3 | SW_C2 | SW_C0);
if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
- pop(); /* fcomp, masked, so we pop. */
+ FPU_pop(); /* fcomp, masked, so we pop. */
}
else
{
+ if ( loaded_tag == TAG_Special )
+ loaded_tag = FPU_Special(&loaded_data);
#ifdef PECULIAR_486
/* This is not really needed, but gives behaviour
identical to an 80486 */
if ( (FPU_modrm & 0x28) == 0x20 )
/* fdiv or fsub */
- real_2op_NaN(&loaded_data, st0_ptr,
- st0_ptr);
+ real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
else
#endif PECULIAR_486
/* fadd, fdivr, fmul, or fsubr */
- real_2op_NaN(st0_ptr, &loaded_data,
- st0_ptr);
+ real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
}
goto reg_mem_instr_done;
}
@@ -401,11 +398,13 @@ do_another_FPU_instruction:
if ( (FPU_modrm & 0x38) == 0x38 )
{
/* fdivr */
- if ( (st0_tag == TW_Zero) &&
- (loaded_data.tag == TW_Valid) )
+ if ( (st0_tag == TAG_Zero) &&
+ ((loaded_tag == TAG_Valid)
+ || (loaded_tag == TAG_Special
+ && isdenormal(&loaded_data))) )
{
- if ( divide_by_zero(loaded_data.sign,
- st0_ptr) )
+ if ( FPU_divide_by_zero(0, getsign(&loaded_data))
+ < 0 )
{
/* We use the fact here that the unmasked
exception in the loaded data was for a
@@ -414,6 +413,8 @@ do_another_FPU_instruction:
partial_status &= ~SW_Denorm_Op;
partial_status |= status1 & SW_Denorm_Op;
}
+ else
+ setsign(st0_ptr, getsign(&loaded_data));
}
}
goto reg_mem_instr_done;
@@ -423,43 +424,38 @@ do_another_FPU_instruction:
{
case 0: /* fadd */
clear_C1();
- reg_add(st0_ptr, &loaded_data, st0_ptr,
- control_word);
+ FPU_add(&loaded_data, loaded_tag, 0, control_word);
break;
case 1: /* fmul */
clear_C1();
- reg_mul(st0_ptr, &loaded_data, st0_ptr,
- control_word);
+ FPU_mul(&loaded_data, loaded_tag, 0, control_word);
break;
case 2: /* fcom */
- compare_st_data(&loaded_data);
+ FPU_compare_st_data(&loaded_data, loaded_tag);
break;
case 3: /* fcomp */
- if ( !compare_st_data(&loaded_data) && !unmasked )
- pop();
+ if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
+ && !unmasked )
+ FPU_pop();
break;
case 4: /* fsub */
clear_C1();
- reg_sub(st0_ptr, &loaded_data, st0_ptr,
- control_word);
+ FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);
break;
case 5: /* fsubr */
clear_C1();
- reg_sub(&loaded_data, st0_ptr, st0_ptr,
- control_word);
+ FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
break;
case 6: /* fdiv */
clear_C1();
- reg_div(st0_ptr, &loaded_data, st0_ptr,
- control_word);
+ FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);
break;
case 7: /* fdivr */
clear_C1();
- if ( st0_tag == TW_Zero )
+ if ( st0_tag == TAG_Zero )
partial_status = status1; /* Undo any denorm tag,
- zero-divide has priority. */
- reg_div(&loaded_data, st0_ptr, st0_ptr,
- control_word);
+ zero-divide has priority. */
+ FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
break;
}
}
@@ -471,10 +467,10 @@ do_another_FPU_instruction:
EXCEPTION(EX_StackUnder);
setcc(SW_C3 | SW_C2 | SW_C0);
if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
- pop(); /* fcomp */
+ FPU_pop(); /* fcomp */
}
else
- stack_underflow();
+ FPU_stack_underflow();
}
reg_mem_instr_done:
operand_address = data_sel_off;
@@ -482,8 +478,8 @@ do_another_FPU_instruction:
else
{
if ( !(no_ip_update =
- load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
- addr_modes, data_address)) )
+ FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+ addr_modes, data_address)) )
{
operand_address = data_sel_off;
}
@@ -493,7 +489,7 @@ do_another_FPU_instruction:
else
{
/* None of these instructions access user memory */
- unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
+ u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
#ifdef PECULIAR_486
/* This is supposed to be undefined, but a real 80486 seems
@@ -503,7 +499,7 @@ do_another_FPU_instruction:
#endif PECULIAR_486
st0_ptr = &st(0);
- st0_tag = st0_ptr->tag;
+ st0_tag = FPU_gettag0();
switch ( type_table[(int) instr_index] )
{
case _NONE_: /* also _REGIc: _REGIn */
@@ -511,28 +507,28 @@ do_another_FPU_instruction:
case _REG0_:
if ( !NOT_EMPTY_ST0 )
{
- stack_underflow();
+ FPU_stack_underflow();
goto FPU_instruction_done;
}
break;
case _REGIi:
if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
{
- stack_underflow_i(FPU_rm);
+ FPU_stack_underflow_i(FPU_rm);
goto FPU_instruction_done;
}
break;
case _REGIp:
if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
{
- stack_underflow_pop(FPU_rm);
+ FPU_stack_underflow_pop(FPU_rm);
goto FPU_instruction_done;
}
break;
case _REGI_:
if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
{
- stack_underflow();
+ FPU_stack_underflow();
goto FPU_instruction_done;
}
break;
@@ -558,14 +554,14 @@ FPU_fwait_done:
#ifdef DEBUG
RE_ENTRANT_CHECK_OFF;
- emu_printall();
+ FPU_printall();
RE_ENTRANT_CHECK_ON;
#endif DEBUG
if (FPU_lookahead && !need_resched)
{
FPU_ORIG_EIP = FPU_EIP - code_base;
- if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+ if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
&addr_modes.override) )
goto do_another_FPU_instruction;
}
@@ -581,17 +577,17 @@ FPU_fwait_done:
all prefix bytes, further changes are needed in the emulator code
which accesses user address space. Access to separate segments is
important for msdos emulation. */
-static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+static int valid_prefix(u_char *Byte, u_char **fpu_eip,
overrides *override)
{
- unsigned char byte;
- unsigned char *ip = *fpu_eip;
+ u_char byte;
+ u_char *ip = *fpu_eip;
*override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(byte, ip);
+ FPU_get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
while ( 1 )
@@ -637,7 +633,7 @@ static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
ip++;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(byte, ip);
+ FPU_get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
break;
case FWAIT_OPCODE:
@@ -677,19 +673,79 @@ void math_abort(struct info * info, unsigned int signal)
-void restore_i387_soft(struct _fpstate *buf)
+#define S387 ((struct i387_soft_struct *)s387)
+#define sstatus_word() \
+ ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
+
+void restore_i387_soft(void *s387, struct _fpstate *buf)
{
- fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+ u_char *d = (u_char *)buf;
+ int offset, other, i, tags, regnr, tag, newtop;
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
+ __copy_from_user(&S387->cwd, d, 7*4);
+ RE_ENTRANT_CHECK_ON;
+
+ d += 7*4;
+
+ S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
+ offset = (S387->ftop & 7) * 10;
+ other = 80 - offset;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* Copy all registers in stack order. */
+ __copy_from_user(((u_char *)&S387->st_space)+offset, d, other);
+ if ( offset )
+ __copy_from_user((u_char *)&S387->st_space, d+other, offset);
+ RE_ENTRANT_CHECK_ON;
+
+ /* The tags may need to be corrected now. */
+ tags = S387->twd;
+ newtop = S387->ftop;
+ for ( i = 0; i < 8; i++ )
+ {
+ regnr = (i+newtop) & 7;
+ if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty )
+ {
+ /* The loaded data over-rides all other cases. */
+ tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr));
+ tags &= ~(3 << (regnr*2));
+ tags |= (tag & 3) << (regnr*2);
+ }
+ }
+ S387->twd = tags;
- frstor(addr_modes, (char *)buf);
}
-struct _fpstate * save_i387_soft(struct _fpstate * buf)
+struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf)
{
- fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+ u_char *d = (u_char *)buf;
+ int offset = (S387->ftop & 7) * 10, other = 80 - offset;
- fsave(addr_modes, (char *)buf);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
+#ifdef PECULIAR_486
+ S387->cwd &= ~0xe080;
+ /* An 80486 sets all the reserved bits to 1. */
+ S387->cwd |= 0xffff0000;
+ S387->swd = sstatus_word() | 0xffff0000;
+ S387->twd |= 0xffff0000;
+ S387->fcs |= 0xf8000000;
+ S387->fos |= 0xffff0000;
+#endif PECULIAR_486
+ __copy_to_user(d, &S387->cwd, 7*4);
+ RE_ENTRANT_CHECK_ON;
+
+ d += 7*4;
+
+ RE_ENTRANT_CHECK_OFF;
+ /* Copy all registers in stack order. */
+ __copy_to_user(d, ((u_char *)&S387->st_space)+offset, other);
+ if ( offset )
+ __copy_to_user(d+other, (u_char *)&S387->st_space, offset);
+ RE_ENTRANT_CHECK_ON;
return buf;
}
diff --git a/arch/i386/math-emu/fpu_etc.c b/arch/i386/math-emu/fpu_etc.c
index 20e3294ca..64c5a70cd 100644
--- a/arch/i386/math-emu/fpu_etc.c
+++ b/arch/i386/math-emu/fpu_etc.c
@@ -3,9 +3,9 @@
| |
| Implement a few FPU instructions. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -17,102 +17,116 @@
#include "reg_constant.h"
-static void fchs(FPU_REG *st0_ptr)
+static void fchs(FPU_REG *st0_ptr, u_char st0tag)
{
- if ( st0_ptr->tag ^ TW_Empty )
+ if ( st0tag ^ TAG_Empty )
{
- st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
+ signbyte(st0_ptr) ^= SIGN_NEG;
clear_C1();
}
else
- stack_underflow();
+ FPU_stack_underflow();
}
-static void fabs(FPU_REG *st0_ptr)
+
+static void fabs(FPU_REG *st0_ptr, u_char st0tag)
{
- if ( st0_ptr->tag ^ TW_Empty )
+ if ( st0tag ^ TAG_Empty )
{
- st0_ptr->sign = SIGN_POS;
+ setpositive(st0_ptr);
clear_C1();
}
else
- stack_underflow();
+ FPU_stack_underflow();
}
-static void ftst_(FPU_REG *st0_ptr)
+static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
{
- switch (st0_ptr->tag)
+ switch (st0tag)
{
- case TW_Zero:
+ case TAG_Zero:
setcc(SW_C3);
break;
- case TW_Valid:
- if (st0_ptr->sign == SIGN_POS)
+ case TAG_Valid:
+ if (getsign(st0_ptr) == SIGN_POS)
setcc(0);
else
setcc(SW_C0);
-
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ break;
+ case TAG_Special:
+ switch ( FPU_Special(st0_ptr) )
{
+ case TW_Denormal:
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ if ( denormal_operand() < 0 )
+ {
#ifdef PECULIAR_486
- /* This is weird! */
- if (st0_ptr->sign == SIGN_POS)
- setcc(SW_C3);
+ /* This is weird! */
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(SW_C3);
#endif PECULIAR_486
- return;
+ return;
+ }
+ break;
+ case TW_NaN:
+ setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Infinity:
+ if (getsign(st0_ptr) == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ default:
+ setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_INTERNAL|0x14);
+ break;
}
-#endif DENORM_OPERAND
-
- break;
- case TW_NaN:
- setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
- EXCEPTION(EX_Invalid);
- break;
- case TW_Infinity:
- if (st0_ptr->sign == SIGN_POS)
- setcc(0);
- else
- setcc(SW_C0);
break;
- case TW_Empty:
+ case TAG_Empty:
setcc(SW_C0|SW_C2|SW_C3);
EXCEPTION(EX_StackUnder);
break;
- default:
- setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
- EXCEPTION(EX_INTERNAL|0x14);
- break;
}
}
-static void fxam(FPU_REG *st0_ptr)
+
+static void fxam(FPU_REG *st0_ptr, u_char st0tag)
{
- int c=0;
- switch (st0_ptr->tag)
+ int c = 0;
+ switch (st0tag)
{
- case TW_Empty:
+ case TAG_Empty:
c = SW_C3|SW_C0;
break;
- case TW_Zero:
+ case TAG_Zero:
c = SW_C3;
break;
- case TW_Valid:
- /* This will need to be changed if TW_Denormal is ever used. */
- if ( st0_ptr->exp <= EXP_UNDER )
- c = SW_C2|SW_C3; /* Denormal */
- else
- c = SW_C2;
- break;
- case TW_NaN:
- c = SW_C0;
- break;
- case TW_Infinity:
- c = SW_C2|SW_C0;
+ case TAG_Valid:
+ c = SW_C2;
break;
+ case TAG_Special:
+ switch ( FPU_Special(st0_ptr) )
+ {
+ case TW_Denormal:
+ c = SW_C2|SW_C3; /* Denormal */
+ break;
+ case TW_NaN:
+ /* We also use NaN for unsupported types. */
+ if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
+ c = SW_C0;
+ break;
+ case TW_Infinity:
+ c = SW_C2|SW_C0;
+ break;
+ }
}
- if (st0_ptr->sign == SIGN_NEG)
+ if ( getsign(st0_ptr) == SIGN_NEG )
c |= SW_C1;
setcc(c);
}
@@ -123,7 +137,7 @@ static FUNC_ST0 const fp_etc_table[] = {
ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
};
-void fp_etc()
+void FPU_etc()
{
- (fp_etc_table[FPU_rm])(&st(0));
+ (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
}
diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h
index d0e58ed0e..4fccf05fe 100644
--- a/arch/i386/math-emu/fpu_proto.h
+++ b/arch/i386/math-emu/fpu_proto.h
@@ -1,22 +1,26 @@
+#ifndef _FPU_PROTO_H
+#define _FPU_PROTO_H
+
/* errors.c */
extern void Un_impl(void);
extern void FPU_illegal(void);
-extern void emu_printall(void);
-extern void stack_overflow(void);
-extern void stack_underflow(void);
-extern void stack_underflow_i(int i);
-extern void stack_underflow_pop(int i);
-extern int set_precision_flag(int flags);
+extern void FPU_printall(void);
asmlinkage void FPU_exception(int n);
-asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest);
-asmlinkage int arith_invalid(FPU_REG *dest);
-asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
-asmlinkage void set_precision_flag_up(void);
-asmlinkage void set_precision_flag_down(void);
-asmlinkage int denormal_operand(void);
-asmlinkage int arith_overflow(FPU_REG *dest);
-asmlinkage int arith_underflow(FPU_REG *dest);
-
+extern int real_1op_NaN(FPU_REG *a);
+extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
+ FPU_REG const *defaultNaN);
+extern int arith_invalid(int deststnr);
+extern int FPU_divide_by_zero(int deststnr, u_char sign);
+extern int set_precision_flag(int flags);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern int arith_overflow(FPU_REG *dest);
+extern int arith_underflow(FPU_REG *dest);
+extern void FPU_stack_overflow(void);
+extern void FPU_stack_underflow(void);
+extern void FPU_stack_underflow_i(int i);
+extern void FPU_stack_underflow_pop(int i);
/* fpu_arith.c */
extern void fadd__(void);
extern void fmul__(void);
@@ -36,7 +40,6 @@ extern void fsubrp(void);
extern void fsubp_(void);
extern void fdivrp(void);
extern void fdivp_(void);
-
/* fpu_aux.c */
extern void fclex(void);
extern void finit(void);
@@ -49,89 +52,92 @@ extern void ffree_(void);
extern void ffreep(void);
extern void fst_i_(void);
extern void fstp_i(void);
-
/* fpu_entry.c */
-asmlinkage void math_emulate(long arg);
+extern void math_emulate(long arg);
extern void math_abort(struct info *info, unsigned int signal);
-
/* fpu_etc.c */
-extern void fp_etc(void);
-
+extern void FPU_etc(void);
+/* fpu_tags.c */
+extern int FPU_gettag0(void);
+extern int FPU_gettagi(int stnr);
+extern int FPU_gettag(int regnr);
+extern void FPU_settag0(int tag);
+extern void FPU_settagi(int stnr, int tag);
+extern void FPU_settag(int regnr, int tag);
+extern int FPU_Special(FPU_REG const *ptr);
+extern int isNaN(FPU_REG const *ptr);
+extern void FPU_pop(void);
+extern int FPU_empty_i(int stnr);
+extern int FPU_stackoverflow(FPU_REG **st_new_ptr);
+extern void FPU_sync_tags(void);
+extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
+extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
+extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
/* fpu_trig.c */
-extern void convert_l2reg(long const *arg, FPU_REG *dest);
-extern void trig_a(void);
-extern void trig_b(void);
-
+extern void FPU_triga(void);
+extern void FPU_trigb(void);
/* get_address.c */
-extern void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
- struct address *addr,
- fpu_addr_modes);
-extern void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
- struct address *addr,
- fpu_addr_modes);
-
+extern void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
+ struct address *addr, fpu_addr_modes addr_modes);
+extern void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
+ struct address *addr, fpu_addr_modes addr_modes);
/* load_store.c */
-extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
- void *address);
-
+extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
+ void *data_address);
/* poly_2xm1.c */
-extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
-
+extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result);
/* poly_atan.c */
-extern void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result);
-
+extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr,
+ u_char st1_tag);
/* poly_l2.c */
-extern void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result);
-extern int poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result);
-
+extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign);
+extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1,
+ FPU_REG *d);
/* poly_sin.c */
-extern void poly_sine(FPU_REG const *arg, FPU_REG *result);
-extern void poly_cos(FPU_REG const *arg, FPU_REG *result);
-
+extern void poly_sine(FPU_REG *st0_ptr);
+extern void poly_cos(FPU_REG *st0_ptr);
/* poly_tan.c */
-extern void poly_tan(FPU_REG const *arg, FPU_REG *result);
-
+extern void poly_tan(FPU_REG *st0_ptr);
/* reg_add_sub.c */
-extern int reg_add(FPU_REG const *a, FPU_REG const *b,
- FPU_REG *dest, int control_w);
-extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
- FPU_REG *dest, int control_w);
-
+extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w);
+extern int FPU_sub(int flags, int rm, int control_w);
/* reg_compare.c */
-extern int compare(FPU_REG const *b);
-extern int compare_st_data(FPU_REG const *b);
+extern int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag);
extern void fcom_st(void);
extern void fcompst(void);
extern void fcompp(void);
extern void fucom_(void);
extern void fucomp(void);
extern void fucompp(void);
-
/* reg_constant.c */
extern void fconst(void);
-
/* reg_ld_str.c */
-extern int reg_load_extended(long double *addr, FPU_REG *loaded_data);
-extern int reg_load_double(double *dfloat, FPU_REG *loaded_data);
-extern int reg_load_single(float *single, FPU_REG *loaded_data);
-extern void reg_load_int64(long long *_s, FPU_REG *loaded_data);
-extern void reg_load_int32(long *_s, FPU_REG *loaded_data);
-extern void reg_load_int16(short *_s, FPU_REG *loaded_data);
-extern void reg_load_bcd(char *s, FPU_REG *loaded_data);
-extern int reg_store_extended(long double *d, FPU_REG *st0_ptr);
-extern int reg_store_double(double *dfloat, FPU_REG *st0_ptr);
-extern int reg_store_single(float *single, FPU_REG *st0_ptr);
-extern int reg_store_int64(long long *d, FPU_REG *st0_ptr);
-extern int reg_store_int32(long *d, FPU_REG *st0_ptr);
-extern int reg_store_int16(short *d, FPU_REG *st0_ptr);
-extern int reg_store_bcd(char *d, FPU_REG *st0_ptr);
-extern int round_to_int(FPU_REG *r);
-extern char *fldenv(fpu_addr_modes addr_modes, char *address);
-extern void frstor(fpu_addr_modes addr_modes, char *address);
-extern unsigned short tag_word(void);
-extern char *fstenv(fpu_addr_modes addr_modes, char *address);
-extern void fsave(fpu_addr_modes addr_modes, char *address);
-
+extern int FPU_load_extended(long double *s, int stnr);
+extern int FPU_load_double(double *dfloat, FPU_REG *loaded_data);
+extern int FPU_load_single(float *single, FPU_REG *loaded_data);
+extern int FPU_load_int64(long long *_s);
+extern int FPU_load_int32(long *_s, FPU_REG *loaded_data);
+extern int FPU_load_int16(short *_s, FPU_REG *loaded_data);
+extern int FPU_load_bcd(u_char *s);
+extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
+ long double *d);
+extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat);
+extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single);
+extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d);
+extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d);
+extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d);
+extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d);
+extern int FPU_round_to_int(FPU_REG *r, u_char tag);
+extern u_char *fldenv(fpu_addr_modes addr_modes, u_char *s);
+extern void frstor(fpu_addr_modes addr_modes, u_char *data_address);
+extern u_char *fstenv(fpu_addr_modes addr_modes, u_char *d);
+extern void fsave(fpu_addr_modes addr_modes, u_char *data_address);
+extern int FPU_tagof(FPU_REG *ptr);
/* reg_mul.c */
-extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
- FPU_REG *dest, unsigned int control_w);
+extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
+
+extern int FPU_div(int flags, int regrm, int control_w);
+/* reg_convert.c */
+extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x);
+#endif /* _FPU_PROTO_H */
+
diff --git a/arch/i386/math-emu/fpu_system.h b/arch/i386/math-emu/fpu_system.h
index d2c3fa716..42303f679 100644
--- a/arch/i386/math-emu/fpu_system.h
+++ b/arch/i386/math-emu/fpu_system.h
@@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------+
| fpu_system.h |
| |
- | Copyright (C) 1992,1994 |
+ | Copyright (C) 1992,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
+---------------------------------------------------------------------------*/
@@ -18,19 +18,19 @@
/* This sets the pointer FPU_info to point to the argument part
of the stack frame of math_emulate() */
-#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg
-
-#define LDT_DESCRIPTOR(s) (current->ldt[(s) >> 3])
-#define SEG_D_SIZE(x) ((x).b & (3 << 21))
-#define SEG_G_BIT(x) ((x).b & (1 << 23))
-#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1)
-#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23)))
-#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \
+#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg
+
+#define LDT_DESCRIPTOR(s) (current->ldt[(s) >> 3])
+#define SEG_D_SIZE(x) ((x).b & (3 << 21))
+#define SEG_G_BIT(x) ((x).b & (1 << 23))
+#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1)
+#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23)))
+#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \
| (((s).b & 0xff) << 16) | ((s).a >> 16))
-#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff))
-#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11))
-#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9))
-#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
+#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff))
+#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11))
+#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9))
+#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
== (1 << 10))
#define I387 (current->tss.i387)
@@ -48,23 +48,24 @@
/* nz if ip_offset and cs_selector are not to be set for the current
instruction. */
-#define no_ip_update (((char *)&(I387.soft.twd))[0])
-#define FPU_rm (((unsigned char *)&(I387.soft.twd))[1])
+#define no_ip_update (*(u_char *)&(I387.soft.no_update))
+#define FPU_rm (*(u_char *)&(I387.soft.rm))
/* Number of bytes of data which can be legally accessed by the current
instruction. This only needs to hold a number <= 108, so a byte will do. */
-#define access_limit (((unsigned char *)&(I387.soft.twd))[2])
+#define access_limit (*(u_char *)&(I387.soft.alimit))
-#define partial_status (I387.soft.swd)
+#define partial_status (I387.soft.swd)
#define control_word (I387.soft.cwd)
-#define regs (I387.soft.regs)
-#define top (I387.soft.top)
+#define fpu_tag_word (I387.soft.twd)
+#define registers (I387.soft.st_space)
+#define top (I387.soft.ftop)
-#define instruction_address (*(struct address *)&I387.soft.fip)
-#define operand_address (*(struct address *)&I387.soft.foo)
+#define instruction_address (*(struct address *)&I387.soft.fip)
+#define operand_address (*(struct address *)&I387.soft.foo)
-#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
- math_abort(FPU_info,SIGSEGV)
+#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
+ math_abort(FPU_info,SIGSEGV)
#undef FPU_IGNORE_CODE_SEGV
#ifdef FPU_IGNORE_CODE_SEGV
@@ -80,4 +81,7 @@
#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
#endif
+#define FPU_get_user(x,y) get_user((x),(y))
+#define FPU_put_user(x,y) put_user((x),(y))
+
#endif
diff --git a/arch/i386/math-emu/fpu_tags.c b/arch/i386/math-emu/fpu_tags.c
new file mode 100644
index 000000000..cb436fe20
--- /dev/null
+++ b/arch/i386/math-emu/fpu_tags.c
@@ -0,0 +1,127 @@
+/*---------------------------------------------------------------------------+
+ | fpu_tags.c |
+ | |
+ | Set FPU register tags. |
+ | |
+ | Copyright (C) 1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+
+
+void FPU_pop(void)
+{
+ fpu_tag_word |= 3 << ((top & 7)*2);
+ top++;
+}
+
+
+int FPU_gettag0(void)
+{
+ return (fpu_tag_word >> ((top & 7)*2)) & 3;
+}
+
+
+int FPU_gettagi(int stnr)
+{
+ return (fpu_tag_word >> (((top+stnr) & 7)*2)) & 3;
+}
+
+
+int FPU_gettag(int regnr)
+{
+ return (fpu_tag_word >> ((regnr & 7)*2)) & 3;
+}
+
+
+void FPU_settag0(int tag)
+{
+ int regnr = top;
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settagi(int stnr, int tag)
+{
+ int regnr = stnr+top;
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+void FPU_settag(int regnr, int tag)
+{
+ regnr &= 7;
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
+
+
+int FPU_Special(FPU_REG const *ptr)
+{
+ int exp = exponent(ptr);
+
+ if ( exp == EXP_BIAS+EXP_UNDER )
+ return TW_Denormal;
+ else if ( exp != EXP_BIAS+EXP_OVER )
+ return TW_NaN;
+ else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) )
+ return TW_Infinity;
+ return TW_NaN;
+}
+
+
+int isNaN(FPU_REG const *ptr)
+{
+ return ( (exponent(ptr) == EXP_BIAS+EXP_OVER)
+ && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) );
+}
+
+
+int FPU_empty_i(int stnr)
+{
+ int regnr = (top+stnr) & 7;
+
+ return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty;
+}
+
+
+int FPU_stackoverflow(FPU_REG **st_new_ptr)
+{
+ *st_new_ptr = &st(-1);
+
+ return ((fpu_tag_word >> (((top - 1) & 7)*2)) & 3) != TAG_Empty;
+}
+
+
+void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
+{
+ reg_copy(r, &st(stnr));
+ FPU_settagi(stnr, tag);
+}
+
+void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
+{
+ reg_copy(r, &st(1));
+ FPU_settagi(1, tag);
+}
+
+void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
+{
+ int regnr = top;
+ regnr &= 7;
+
+ reg_copy(r, &st(0));
+
+ fpu_tag_word &= ~(3 << (regnr*2));
+ fpu_tag_word |= (tag & 3) << (regnr*2);
+}
diff --git a/arch/i386/math-emu/fpu_trig.c b/arch/i386/math-emu/fpu_trig.c
index 05241f700..57a902162 100644
--- a/arch/i386/math-emu/fpu_trig.c
+++ b/arch/i386/math-emu/fpu_trig.c
@@ -3,9 +3,9 @@
| |
| Implementation of the FPU "transcendental" functions. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -17,7 +17,6 @@
#include "control_w.h"
#include "reg_constant.h"
-
static void rem_kernel(unsigned long long st0, unsigned long long *y,
unsigned long long st1,
unsigned long long q, int n);
@@ -25,9 +24,6 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
#define BETTER_THAN_486
#define FCOS 4
-/* Not needed now with new code
-#define FPTAN 1
- */
/* Used only by fptan, fsin, fcos, and fsincos. */
/* This routine produces very accurate results, similar to
@@ -35,13 +31,15 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
/* Limited measurements show no results worse than 64 bit precision
except for the results for arguments close to 2^63, where the
precision of the result sometimes degrades to about 63.9 bits */
-static int trig_arg(FPU_REG *X, int even)
+static int trig_arg(FPU_REG *st0_ptr, int even)
{
FPU_REG tmp;
+ u_char tmptag;
unsigned long long q;
int old_cw = control_word, saved_status = partial_status;
+ int tag, st0_tag = TAG_Valid;
- if ( X->exp >= EXP_BIAS + 63 )
+ if ( exponent(st0_ptr) >= 63 )
{
partial_status |= SW_C2; /* Reduction incomplete. */
return -1;
@@ -50,58 +48,52 @@ static int trig_arg(FPU_REG *X, int even)
control_word &= ~CW_RC;
control_word |= RC_CHOP;
- reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
- round_to_int(&tmp); /* Fortunately, this can't overflow
- to 2^64 */
+ setpositive(st0_ptr);
+ tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
+ SIGN_POS);
+
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow
+ to 2^64 */
q = significand(&tmp);
if ( q )
{
- rem_kernel(significand(X),
+ rem_kernel(significand(st0_ptr),
&significand(&tmp),
significand(&CONST_PI2),
- q, X->exp - CONST_PI2.exp);
- tmp.exp = CONST_PI2.exp;
- normalize(&tmp);
- reg_move(&tmp, X);
- }
-
-#ifdef FPTAN
- if ( even == FPTAN )
- {
- if ( ((X->exp >= EXP_BIAS) ||
- ((X->exp == EXP_BIAS-1)
- && (X->sigh >= 0xc90fdaa2))) ^ (q & 1) )
- even = FCOS;
- else
- even = 0;
+ q, exponent(st0_ptr) - exponent(&CONST_PI2));
+ setexponent16(&tmp, exponent(&CONST_PI2));
+ st0_tag = FPU_normalize(&tmp);
+ FPU_copy_to_reg0(&tmp, st0_tag);
}
-#endif FPTAN
if ( (even && !(q & 1)) || (!even && (q & 1)) )
{
- reg_sub(&CONST_PI2, X, X, FULL_PRECISION);
+ st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, FULL_PRECISION);
+
#ifdef BETTER_THAN_486
/* So far, the results are exact but based upon a 64 bit
precision approximation to pi/2. The technique used
now is equivalent to using an approximation to pi/2 which
is accurate to about 128 bits. */
- if ( (X->exp <= CONST_PI2extra.exp + 64) || (q > 1) )
+ if ( (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) || (q > 1) )
{
- /* This code gives the effect of having p/2 to better than
+ /* This code gives the effect of having pi/2 to better than
128 bits precision. */
+
significand(&tmp) = q + 1;
- tmp.exp = EXP_BIAS + 63;
- tmp.tag = TW_Valid;
- normalize(&tmp);
- reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
- reg_add(X, &tmp, X, FULL_PRECISION);
- if ( X->sign == SIGN_NEG )
+ setexponent16(&tmp, 63);
+ FPU_normalize(&tmp);
+ tmptag =
+ FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS,
+ exponent16(&CONST_PI2extra) + exponent16(&tmp));
+ st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
+ if ( signnegative(st0_ptr) )
{
/* CONST_PI2extra is negative, so the result of the addition
can be negative. This means that the argument is actually
in a different quadrant. The correction is always < pi/2,
so it can't overflow into yet another quadrant. */
- X->sign = SIGN_POS;
+ setpositive(st0_ptr);
q++;
}
}
@@ -114,33 +106,39 @@ static int trig_arg(FPU_REG *X, int even)
precision approximation to pi/2. The technique used
now is equivalent to using an approximation to pi/2 which
is accurate to about 128 bits. */
- if ( ((q > 0) && (X->exp <= CONST_PI2extra.exp + 64)) || (q > 1) )
+ if ( ((q > 0) && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
+ || (q > 1) )
{
/* This code gives the effect of having p/2 to better than
128 bits precision. */
+
significand(&tmp) = q;
- tmp.exp = EXP_BIAS + 63;
- tmp.tag = TW_Valid;
- normalize(&tmp);
- reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
- reg_sub(X, &tmp, X, FULL_PRECISION);
- if ( (X->exp == CONST_PI2.exp) &&
- ((X->sigh > CONST_PI2.sigh)
- || ((X->sigh == CONST_PI2.sigh)
- && (X->sigl > CONST_PI2.sigl))) )
+ setexponent16(&tmp, 63);
+ FPU_normalize(&tmp); /* This must return TAG_Valid */
+ tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION,
+ SIGN_POS,
+ exponent16(&CONST_PI2extra) + exponent16(&tmp));
+ st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), (int)&tmp,
+ FULL_PRECISION);
+ if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) &&
+ ((st0_ptr->sigh > CONST_PI2.sigh)
+ || ((st0_ptr->sigh == CONST_PI2.sigh)
+ && (st0_ptr->sigl > CONST_PI2.sigl))) )
{
/* CONST_PI2extra is negative, so the result of the
subtraction can be larger than pi/2. This means
that the argument is actually in a different quadrant.
The correction is always < pi/2, so it can't overflow
into yet another quadrant. */
- reg_sub(&CONST_PI, X, X, FULL_PRECISION);
+ st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2,
+ FULL_PRECISION);
q++;
}
}
}
#endif BETTER_THAN_486
+ FPU_settag0(st0_tag);
control_word = old_cw;
partial_status = saved_status & ~SW_C2; /* Reduction complete. */
@@ -149,57 +147,56 @@ static int trig_arg(FPU_REG *X, int even)
/* Convert a long to register */
-void convert_l2reg(long const *arg, FPU_REG *dest)
+static void convert_l2reg(long const *arg, int deststnr)
{
+ int tag;
long num = *arg;
+ u_char sign;
+ FPU_REG *dest = &st(deststnr);
if (num == 0)
- { reg_move(&CONST_Z, dest); return; }
+ {
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ return;
+ }
if (num > 0)
- dest->sign = SIGN_POS;
+ { sign = SIGN_POS; }
else
- { num = -num; dest->sign = SIGN_NEG; }
+ { num = -num; sign = SIGN_NEG; }
dest->sigh = num;
dest->sigl = 0;
- dest->exp = EXP_BIAS + 31;
- dest->tag = TW_Valid;
- normalize(dest);
+ setexponent16(dest, 31);
+ tag = FPU_normalize(dest);
+ FPU_settagi(deststnr, tag);
+ setsign(dest, sign);
+ return;
}
-static void single_arg_error(FPU_REG *st0_ptr)
+static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
{
- switch ( st0_ptr->tag )
- {
- case TW_NaN:
- if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */
- {
- EXCEPTION(EX_Invalid);
- if ( control_word & CW_Invalid )
- st0_ptr->sigh |= 0x40000000; /* Convert to a QNaN */
- }
- break; /* return with a NaN in st(0) */
- case TW_Empty:
- stack_underflow(); /* Puts a QNaN in st(0) */
- break;
+ if ( st0_tag == TAG_Empty )
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
+ else if ( st0_tag == TW_NaN )
+ real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */
#ifdef PARANOID
- default:
- EXCEPTION(EX_INTERNAL|0x0112);
+ else
+ EXCEPTION(EX_INTERNAL|0x0112);
#endif PARANOID
- }
}
-static void single_arg_2_error(FPU_REG *st0_ptr)
+static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
{
- FPU_REG *st_new_ptr;
+ int isNaN;
- switch ( st0_ptr->tag )
+ switch ( st0_tag )
{
case TW_NaN:
- if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */
+ isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000);
+ if ( isNaN && !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */
{
EXCEPTION(EX_Invalid);
if ( control_word & CW_Invalid )
@@ -207,17 +204,27 @@ static void single_arg_2_error(FPU_REG *st0_ptr)
/* The masked response */
/* Convert to a QNaN */
st0_ptr->sigh |= 0x40000000;
- st_new_ptr = &st(-1);
push();
- reg_move(&st(1), st_new_ptr);
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
}
}
- else
+ else if ( isNaN )
{
/* A QNaN */
- st_new_ptr = &st(-1);
push();
- reg_move(&st(1), st_new_ptr);
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
+ }
+ else
+ {
+ /* pseudoNaN or other unsupported */
+ EXCEPTION(EX_Invalid);
+ if ( control_word & CW_Invalid )
+ {
+ /* The masked response */
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ push();
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
+ }
}
break; /* return with a NaN in st(0) */
#ifdef PARANOID
@@ -230,92 +237,88 @@ static void single_arg_2_error(FPU_REG *st0_ptr)
/*---------------------------------------------------------------------------*/
-static void f2xm1(FPU_REG *st0_ptr)
+static void f2xm1(FPU_REG *st0_ptr, u_char tag)
{
+ FPU_REG a;
+
clear_C1();
- switch ( st0_ptr->tag )
- {
- case TW_Valid:
- {
- if ( st0_ptr->exp >= 0 )
- {
- /* For an 80486 FPU, the result is undefined. */
- }
-#ifdef DENORM_OPERAND
- else if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
- else
- {
- /* poly_2xm1(x) requires 0 < x < 1. */
- poly_2xm1(st0_ptr, st0_ptr);
- }
- if ( st0_ptr->exp <= EXP_UNDER )
- {
- /* A denormal result has been produced.
- Precision must have been lost, this is always
- an underflow. */
- arith_underflow(st0_ptr);
- }
- set_precision_flag_up(); /* 80486 appears to always do this */
- return;
- }
- case TW_Zero:
+
+ if ( tag == TAG_Valid )
+ {
+ /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
+ if ( exponent(st0_ptr) < 0 )
+ {
+ denormal_arg:
+
+ FPU_to_exp16(st0_ptr, &a);
+
+ /* poly_2xm1(x) requires 0 < st(0) < 1. */
+ poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
+ }
+ set_precision_flag_up(); /* 80486 appears to always do this */
return;
+ }
+
+ if ( tag == TAG_Zero )
+ return;
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ switch ( tag )
+ {
+ case TW_Denormal:
+ if ( denormal_operand() < 0 )
+ return;
+ goto denormal_arg;
case TW_Infinity:
- if ( st0_ptr->sign == SIGN_NEG )
+ if ( signnegative(st0_ptr) )
{
/* -infinity gives -1 (p16-10) */
- reg_move(&CONST_1, st0_ptr);
- st0_ptr->sign = SIGN_NEG;
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ setnegative(st0_ptr);
}
return;
default:
- single_arg_error(st0_ptr);
+ single_arg_error(st0_ptr, tag);
}
}
-static void fptan(FPU_REG *st0_ptr)
+static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st_new_ptr;
int q;
- char arg_sign = st0_ptr->sign;
+ u_char arg_sign = getsign(st0_ptr);
/* Stack underflow has higher priority */
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
- stack_underflow(); /* Puts a QNaN in st(0) */
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
if ( control_word & CW_Invalid )
{
st_new_ptr = &st(-1);
push();
- stack_underflow(); /* Puts a QNaN in the new st(0) */
+ FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
}
return;
}
if ( STACK_OVERFLOW )
- { stack_overflow(); return; }
+ { FPU_stack_overflow(); return; }
- switch ( st0_tag )
+ if ( st0_tag == TAG_Valid )
{
- case TW_Valid:
- if ( st0_ptr->exp > EXP_BIAS - 40 )
+ if ( exponent(st0_ptr) > -40 )
{
- st0_ptr->sign = SIGN_POS;
- if ( (q = trig_arg(st0_ptr, 0)) != -1 )
- {
- poly_tan(st0_ptr, st0_ptr);
- st0_ptr->sign = (q & 1) ^ arg_sign;
- }
- else
+ if ( (q = trig_arg(st0_ptr, 0)) == -1 )
{
/* Operand is out of range */
- st0_ptr->sign = arg_sign; /* restore st(0) */
return;
}
+
+ poly_tan(st0_ptr);
+ setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
set_precision_flag_up(); /* We do not really know if up or down */
}
else
@@ -323,106 +326,134 @@ static void fptan(FPU_REG *st0_ptr)
/* For a small arg, the result == the argument */
/* Underflow may happen */
- if ( st0_ptr->exp <= EXP_UNDER )
- {
-#ifdef DENORM_OPERAND
- if ( denormal_operand() )
- return;
-#endif DENORM_OPERAND
- /* A denormal result has been produced.
- Precision must have been lost, this is always
- an underflow. */
- if ( arith_underflow(st0_ptr) )
- return;
- }
- set_precision_flag_down(); /* Must be down. */
+ denormal_arg:
+
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+ FPU_settag0(st0_tag);
}
push();
- reg_move(&CONST_1, st_new_ptr);
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
return;
- break;
- case TW_Infinity:
+ }
+
+ if ( st0_tag == TAG_Zero )
+ {
+ push();
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ setcc(0);
+ return;
+ }
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto denormal_arg;
+ }
+
+ if ( st0_tag == TW_Infinity )
+ {
/* The 80486 treats infinity as an invalid operand */
- arith_invalid(st0_ptr);
- if ( control_word & CW_Invalid )
+ if ( arith_invalid(0) >= 0 )
{
st_new_ptr = &st(-1);
push();
- arith_invalid(st_new_ptr);
+ arith_invalid(0);
}
return;
- case TW_Zero:
- push();
- reg_move(&CONST_1, st_new_ptr);
- setcc(0);
- break;
- default:
- single_arg_2_error(st0_ptr);
- break;
}
+
+ single_arg_2_error(st0_ptr, st0_tag);
}
-static void fxtract(FPU_REG *st0_ptr)
+static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st_new_ptr;
+ u_char sign;
register FPU_REG *st1_ptr = st0_ptr; /* anticipate */
if ( STACK_OVERFLOW )
- { stack_overflow(); return; }
+ { FPU_stack_overflow(); return; }
+
clear_C1();
- if ( !(st0_tag ^ TW_Valid) )
+
+ if ( st0_tag == TAG_Valid )
{
long e;
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
-
push();
- reg_move(st1_ptr, st_new_ptr);
- st_new_ptr->exp = EXP_BIAS;
- e = st1_ptr->exp - EXP_BIAS;
- convert_l2reg(&e, st1_ptr);
+ sign = getsign(st1_ptr);
+ reg_copy(st1_ptr, st_new_ptr);
+ setexponent16(st_new_ptr, exponent(st_new_ptr));
+
+ denormal_arg:
+
+ e = exponent16(st_new_ptr);
+ convert_l2reg(&e, 1);
+ setexponentpos(st_new_ptr, 0);
+ setsign(st_new_ptr, sign);
+ FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */
return;
}
- else if ( st0_tag == TW_Zero )
+ else if ( st0_tag == TAG_Zero )
{
- char sign = st0_ptr->sign;
- if ( divide_by_zero(SIGN_NEG, st0_ptr) )
+ sign = getsign(st0_ptr);
+
+ if ( FPU_divide_by_zero(0, SIGN_NEG) < 0 )
return;
+
push();
- reg_move(&CONST_Z, st_new_ptr);
- st_new_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(st_new_ptr, sign);
return;
}
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if (denormal_operand() < 0 )
+ return;
+
+ push();
+ sign = getsign(st1_ptr);
+ FPU_to_exp16(st1_ptr, st_new_ptr);
+ goto denormal_arg;
+ }
else if ( st0_tag == TW_Infinity )
{
- char sign = st0_ptr->sign;
- st0_ptr->sign = SIGN_POS;
+ sign = getsign(st0_ptr);
+ setpositive(st0_ptr);
push();
- reg_move(&CONST_INF, st_new_ptr);
- st_new_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
+ setsign(st_new_ptr, sign);
return;
}
else if ( st0_tag == TW_NaN )
{
- if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) )
+ if ( real_1op_NaN(st0_ptr) < 0 )
return;
+
push();
- reg_move(st1_ptr, st_new_ptr);
+ FPU_copy_to_reg0(st0_ptr, TAG_Special);
return;
}
- else if ( st0_tag == TW_Empty )
+ else if ( st0_tag == TAG_Empty )
{
/* Is this the correct behaviour? */
if ( control_word & EX_Invalid )
{
- stack_underflow();
+ FPU_stack_underflow();
push();
- stack_underflow();
+ FPU_stack_underflow();
}
else
EXCEPTION(EX_StackUnder);
@@ -434,193 +465,233 @@ static void fxtract(FPU_REG *st0_ptr)
}
-static void fdecstp(FPU_REG *st0_ptr)
+static void fdecstp(void)
{
clear_C1();
- top--; /* st0_ptr will be fixed in math_emulate() before the next instr */
+ top--;
}
-static void fincstp(FPU_REG *st0_ptr)
+static void fincstp(void)
{
clear_C1();
- top++; /* st0_ptr will be fixed in math_emulate() before the next instr */
+ top++;
}
-static void fsqrt_(FPU_REG *st0_ptr)
+static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
+ int expon;
clear_C1();
- if ( !(st0_tag ^ TW_Valid) )
+
+ if ( st0_tag == TAG_Valid )
{
- int expon;
+ u_char tag;
- if (st0_ptr->sign == SIGN_NEG)
+ if (signnegative(st0_ptr))
{
- arith_invalid(st0_ptr); /* sqrt(negative) is invalid */
+ arith_invalid(0); /* sqrt(negative) is invalid */
return;
}
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ /* make st(0) in [1.0 .. 4.0) */
+ expon = exponent(st0_ptr);
- expon = st0_ptr->exp - EXP_BIAS;
- st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */
-
- wm_sqrt(st0_ptr, control_word); /* Do the computation */
-
- st0_ptr->exp += expon >> 1;
- st0_ptr->sign = SIGN_POS;
+ denormal_arg:
+
+ setexponent16(st0_ptr, (expon & 1));
+
+ /* Do the computation, the sign of the result will be positive. */
+ tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
+ addexponent(st0_ptr, expon >> 1);
+ FPU_settag0(tag);
+ return;
}
- else if ( st0_tag == TW_Zero )
+
+ if ( st0_tag == TAG_Zero )
return;
- else if ( st0_tag == TW_Infinity )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Infinity )
{
- if ( st0_ptr->sign == SIGN_NEG )
- arith_invalid(st0_ptr); /* sqrt(-Infinity) is invalid */
+ if ( signnegative(st0_ptr) )
+ arith_invalid(0); /* sqrt(-Infinity) is invalid */
return;
}
- else
- { single_arg_error(st0_ptr); return; }
+ else if ( st0_tag == TW_Denormal )
+ {
+ if (signnegative(st0_ptr))
+ {
+ arith_invalid(0); /* sqrt(negative) is invalid */
+ return;
+ }
+
+ if ( denormal_operand() < 0 )
+ return;
+
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ expon = exponent16(st0_ptr);
+
+ goto denormal_arg;
+ }
+
+ single_arg_error(st0_ptr, st0_tag);
}
-static void frndint_(FPU_REG *st0_ptr)
+static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
- int flags;
+ int flags, tag;
- if ( !(st0_tag ^ TW_Valid) )
+ if ( st0_tag == TAG_Valid )
{
- if (st0_ptr->exp > EXP_BIAS+63)
- return;
+ u_char sign;
+
+ denormal_arg:
+
+ sign = getsign(st0_ptr);
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ if (exponent(st0_ptr) > 63)
return;
-#endif DENORM_OPERAND
+
+ if ( st0_tag == TW_Denormal )
+ {
+ if (denormal_operand() < 0 )
+ return;
+ }
/* Fortunately, this can't overflow to 2^64 */
- if ( (flags = round_to_int(st0_ptr)) )
+ if ( (flags = FPU_round_to_int(st0_ptr, st0_tag)) )
set_precision_flag(flags);
- st0_ptr->exp = EXP_BIAS + 63;
- normalize(st0_ptr);
+ setexponent16(st0_ptr, 63);
+ tag = FPU_normalize(st0_ptr);
+ setsign(st0_ptr, sign);
+ FPU_settag0(tag);
return;
}
- else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) )
+
+ if ( st0_tag == TAG_Zero )
+ return;
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( st0_tag == TW_Denormal )
+ goto denormal_arg;
+ else if ( st0_tag == TW_Infinity )
return;
else
- single_arg_error(st0_ptr);
+ single_arg_error(st0_ptr, st0_tag);
}
-static void fsin(FPU_REG *st0_ptr)
+static int fsin(FPU_REG *st0_ptr, u_char tag)
{
- char st0_tag = st0_ptr->tag;
- char arg_sign = st0_ptr->sign;
+ u_char arg_sign = getsign(st0_ptr);
- if ( st0_tag == TW_Valid )
+ if ( tag == TAG_Valid )
{
- FPU_REG rv;
int q;
- if ( st0_ptr->exp > EXP_BIAS - 40 )
+ if ( exponent(st0_ptr) > -40 )
{
- st0_ptr->sign = SIGN_POS;
- if ( (q = trig_arg(st0_ptr, 0)) != -1 )
+ if ( (q = trig_arg(st0_ptr, 0)) == -1 )
{
+ /* Operand is out of range */
+ return 1;
+ }
- poly_sine(st0_ptr, &rv);
+ poly_sine(st0_ptr);
+
+ if (q & 2)
+ changesign(st0_ptr);
- if (q & 2)
- rv.sign ^= SIGN_POS ^ SIGN_NEG;
- rv.sign ^= arg_sign;
- reg_move(&rv, st0_ptr);
+ setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
- /* We do not really know if up or down */
- set_precision_flag_up();
- return;
- }
- else
- {
- /* Operand is out of range */
- st0_ptr->sign = arg_sign; /* restore st(0) */
- return;
- }
+ /* We do not really know if up or down */
+ set_precision_flag_up();
+ return 0;
}
else
{
/* For a small arg, the result == the argument */
- /* Underflow may happen */
-
- if ( st0_ptr->exp <= EXP_UNDER )
- {
-#ifdef DENORM_OPERAND
- if ( denormal_operand() )
- return;
-#endif DENORM_OPERAND
- /* A denormal result has been produced.
- Precision must have been lost, this is always
- an underflow. */
- arith_underflow(st0_ptr);
- return;
- }
-
set_precision_flag_up(); /* Must be up. */
+ return 0;
}
}
- else if ( st0_tag == TW_Zero )
+
+ if ( tag == TAG_Zero )
{
setcc(0);
- return;
+ return 0;
}
- else if ( st0_tag == TW_Infinity )
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ if ( tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return 1;
+
+ /* For a small arg, the result == the argument */
+ /* Underflow may happen */
+ FPU_to_exp16(st0_ptr, st0_ptr);
+
+ tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
+
+ FPU_settag0(tag);
+
+ return 0;
+ }
+ else if ( tag == TW_Infinity )
{
/* The 80486 treats infinity as an invalid operand */
- arith_invalid(st0_ptr);
- return;
+ arith_invalid(0);
+ return 1;
}
else
- single_arg_error(st0_ptr);
+ {
+ single_arg_error(st0_ptr, tag);
+ return 1;
+ }
}
-static int f_cos(FPU_REG *arg)
+static int f_cos(FPU_REG *st0_ptr, u_char tag)
{
- char arg_sign = arg->sign;
+ u_char st0_sign;
+
+ st0_sign = getsign(st0_ptr);
- if ( arg->tag == TW_Valid )
+ if ( tag == TAG_Valid )
{
- FPU_REG rv;
int q;
- if ( arg->exp > EXP_BIAS - 40 )
+ if ( exponent(st0_ptr) > -40 )
{
- arg->sign = SIGN_POS;
- if ( (arg->exp < EXP_BIAS)
- || ((arg->exp == EXP_BIAS)
- && (significand(arg) <= 0xc90fdaa22168c234LL)) )
+ if ( (exponent(st0_ptr) < 0)
+ || ((exponent(st0_ptr) == 0)
+ && (significand(st0_ptr) <= 0xc90fdaa22168c234LL)) )
{
- poly_cos(arg, &rv);
- reg_move(&rv, arg);
+ poly_cos(st0_ptr);
/* We do not really know if up or down */
set_precision_flag_down();
return 0;
}
- else if ( (q = trig_arg(arg, FCOS)) != -1 )
+ else if ( (q = trig_arg(st0_ptr, FCOS)) != -1 )
{
- poly_sine(arg, &rv);
+ poly_sine(st0_ptr);
if ((q+1) & 2)
- rv.sign ^= SIGN_POS ^ SIGN_NEG;
- reg_move(&rv, arg);
+ changesign(st0_ptr);
/* We do not really know if up or down */
set_precision_flag_down();
@@ -630,19 +701,15 @@ static int f_cos(FPU_REG *arg)
else
{
/* Operand is out of range */
- arg->sign = arg_sign; /* restore st(0) */
return 1;
}
}
else
{
-#ifdef DENORM_OPERAND
- if ( (arg->exp <= EXP_UNDER) && (denormal_operand()) )
- return 1;
-#endif DENORM_OPERAND
+ denormal_arg:
setcc(0);
- reg_move(&CONST_1, arg);
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
#ifdef PECULIAR_486
set_precision_flag_down(); /* 80486 appears to do this. */
#else
@@ -651,79 +718,99 @@ static int f_cos(FPU_REG *arg)
return 0;
}
}
- else if ( arg->tag == TW_Zero )
+ else if ( tag == TAG_Zero )
{
- reg_move(&CONST_1, arg);
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
setcc(0);
return 0;
}
- else if ( arg->tag == TW_Infinity )
+
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+
+ if ( tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return 1;
+
+ goto denormal_arg;
+ }
+ else if ( tag == TW_Infinity )
{
/* The 80486 treats infinity as an invalid operand */
- arith_invalid(arg);
+ arith_invalid(0);
return 1;
}
else
{
- single_arg_error(arg); /* requires arg == &st(0) */
+ single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
return 1;
}
}
-static void fcos(FPU_REG *st0_ptr)
+static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
{
- f_cos(st0_ptr);
+ f_cos(st0_ptr, st0_tag);
}
-static void fsincos(FPU_REG *st0_ptr)
+static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st_new_ptr;
FPU_REG arg;
+ u_char tag;
/* Stack underflow has higher priority */
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
- stack_underflow(); /* Puts a QNaN in st(0) */
+ FPU_stack_underflow(); /* Puts a QNaN in st(0) */
if ( control_word & CW_Invalid )
{
st_new_ptr = &st(-1);
push();
- stack_underflow(); /* Puts a QNaN in the new st(0) */
+ FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
}
return;
}
if ( STACK_OVERFLOW )
- { stack_overflow(); return; }
+ { FPU_stack_overflow(); return; }
+
+ if ( st0_tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+ else
+ tag = st0_tag;
- if ( st0_tag == TW_NaN )
+ if ( tag == TW_NaN )
{
- single_arg_2_error(st0_ptr);
+ single_arg_2_error(st0_ptr, TW_NaN);
return;
}
- else if ( st0_tag == TW_Infinity )
+ else if ( tag == TW_Infinity )
{
/* The 80486 treats infinity as an invalid operand */
- if ( !arith_invalid(st0_ptr) )
+ if ( arith_invalid(0) >= 0 )
{
- /* unmasked response */
+ /* Masked response */
push();
- arith_invalid(st_new_ptr);
+ arith_invalid(0);
}
return;
}
- reg_move(st0_ptr,&arg);
- if ( !f_cos(&arg) )
+ reg_copy(st0_ptr, &arg);
+ if ( !fsin(st0_ptr, st0_tag) )
{
- fsin(st0_ptr);
push();
- reg_move(&arg,st_new_ptr);
+ FPU_copy_to_reg0(&arg, st0_tag);
+ f_cos(&st(0), st0_tag);
+ }
+ else
+ {
+ /* An error, so restore st(0) */
+ FPU_copy_to_reg0(&arg, st0_tag);
}
-
}
@@ -760,79 +847,86 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
/* Remainder of st(0) / st(1) */
/* This routine produces exact results, i.e. there is never any
rounding or truncation, etc of the result. */
-static void do_fprem(FPU_REG *st0_ptr, int round)
+static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
{
FPU_REG *st1_ptr = &st(1);
- char st1_tag = st1_ptr->tag;
- char st0_tag = st0_ptr->tag;
- char sign = st0_ptr->sign;
+ u_char st1_tag = FPU_gettagi(1);
- if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
{
- FPU_REG tmp;
- int old_cw = control_word;
- int expdif = st0_ptr->exp - st1_ptr->exp;
+ FPU_REG tmp, st0, st1;
+ u_char st0_sign, st1_sign;
+ u_char tmptag;
+ int tag;
+ int old_cw;
+ int expdif;
long long q;
unsigned short saved_status;
- int cc = 0;
+ int cc;
+
+ fprem_valid:
+ /* Convert registers for internal use. */
+ st0_sign = FPU_to_exp16(st0_ptr, &st0);
+ st1_sign = FPU_to_exp16(st1_ptr, &st1);
+ expdif = exponent16(&st0) - exponent16(&st1);
+
+ old_cw = control_word;
+ cc = 0;
-#ifdef DENORM_OPERAND
- if ( ((st0_ptr->exp <= EXP_UNDER) ||
- (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
-
/* We want the status following the denorm tests, but don't want
the status changed by the arithmetic operations. */
saved_status = partial_status;
control_word &= ~CW_RC;
control_word |= RC_CHOP;
- if (expdif < 64)
+ if ( expdif < 64 )
{
/* This should be the most common case */
if ( expdif > -2 )
{
- reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
+ u_char sign = st0_sign ^ st1_sign;
+ tag = FPU_u_div(&st0, &st1, &tmp,
+ PR_64_BITS | RC_CHOP | 0x3f,
+ sign);
+ setsign(&tmp, sign);
- if ( tmp.exp >= EXP_BIAS )
+ if ( exponent(&tmp) >= 0 )
{
- round_to_int(&tmp); /* Fortunately, this can't overflow
- to 2^64 */
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
+ overflow to 2^64 */
q = significand(&tmp);
- rem_kernel(significand(st0_ptr),
+ rem_kernel(significand(&st0),
&significand(&tmp),
- significand(st1_ptr),
+ significand(&st1),
q, expdif);
- tmp.exp = st1_ptr->exp;
+ setexponent16(&tmp, exponent16(&st1));
}
else
{
- reg_move(st0_ptr, &tmp);
+ reg_copy(&st0, &tmp);
q = 0;
}
- tmp.sign = sign;
if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) )
{
/* We may need to subtract st(1) once more,
to get a result <= 1/2 of st(1). */
unsigned long long x;
- expdif = st1_ptr->exp - tmp.exp;
+ expdif = exponent16(&st1) - exponent16(&tmp);
if ( expdif <= 1 )
{
if ( expdif == 0 )
- x = significand(st1_ptr) - significand(&tmp);
+ x = significand(&st1) - significand(&tmp);
else /* expdif is 1 */
- x = (significand(st1_ptr) << 1) - significand(&tmp);
+ x = (significand(&st1) << 1) - significand(&tmp);
if ( (x < significand(&tmp)) ||
/* or equi-distant (from 0 & st(1)) and q is odd */
((x == significand(&tmp)) && (q & 1) ) )
{
- tmp.sign ^= (SIGN_POS^SIGN_NEG);
+ st0_sign = ! st0_sign;
significand(&tmp) = x;
q++;
}
@@ -855,28 +949,35 @@ static void do_fprem(FPU_REG *st0_ptr, int round)
/* There is a large exponent difference ( >= 64 ) */
/* To make much sense, the code in this section should
be done at high precision. */
- int exp_1;
+ int exp_1, N;
+ u_char sign;
/* prevent overflow here */
/* N is 'a number between 32 and 63' (p26-113) */
- reg_move(st0_ptr, &tmp);
- tmp.exp = EXP_BIAS + 56;
- exp_1 = st1_ptr->exp; st1_ptr->exp = EXP_BIAS;
- expdif -= 56;
-
- reg_div(&tmp, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
- st1_ptr->exp = exp_1;
-
- round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */
-
- rem_kernel(significand(st0_ptr),
+ reg_copy(&st0, &tmp);
+ tmptag = st0_tag;
+ N = (expdif & 0x0000001f) + 32; /* This choice gives results
+ identical to an AMD 486 */
+ setexponent16(&tmp, N);
+ exp_1 = exponent16(&st1);
+ setexponent16(&st1, 0);
+ expdif -= N;
+
+ sign = getsign(&tmp) ^ st1_sign;
+ tag = FPU_u_div(&tmp, &st1, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
+ sign);
+ setsign(&tmp, sign);
+
+ FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
+ overflow to 2^64 */
+
+ rem_kernel(significand(&st0),
&significand(&tmp),
- significand(st1_ptr),
+ significand(&st1),
significand(&tmp),
- tmp.exp - EXP_BIAS
+ exponent(&tmp)
);
- tmp.exp = exp_1 + expdif;
- tmp.sign = sign;
+ setexponent16(&tmp, exp_1 + expdif);
/* It is possible for the operation to be complete here.
What does the IEEE standard say? The Intel 80486 manual
@@ -888,8 +989,8 @@ static void do_fprem(FPU_REG *st0_ptr, int round)
/* The result is zero */
control_word = old_cw;
partial_status = saved_status;
- reg_move(&CONST_Z, st0_ptr);
- st0_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(&st0, st0_sign);
#ifdef PECULIAR_486
setcc(SW_C2);
#else
@@ -902,52 +1003,82 @@ static void do_fprem(FPU_REG *st0_ptr, int round)
control_word = old_cw;
partial_status = saved_status;
- normalize_nuo(&tmp);
- reg_move(&tmp, st0_ptr);
- setcc(cc);
+ tag = FPU_normalize_nuo(&tmp);
+ reg_copy(&tmp, st0_ptr);
/* The only condition to be looked for is underflow,
and it can occur here only if underflow is unmasked. */
- if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero)
+ if ( (exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
&& !(control_word & CW_Underflow) )
- arith_underflow(st0_ptr);
+ {
+ setcc(cc);
+ tag = arith_underflow(st0_ptr);
+ setsign(st0_ptr, st0_sign);
+ FPU_settag0(tag);
+ return;
+ }
+ else if ( (exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero) )
+ {
+ stdexp(st0_ptr);
+ setsign(st0_ptr, st0_sign);
+ }
+ else
+ {
+ tag = FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
+ }
+ FPU_settag0(tag);
+ setcc(cc);
return;
}
- else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+ goto fprem_valid;
+ }
+ else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
{
- stack_underflow();
+ FPU_stack_underflow();
return;
}
- else if ( st0_tag == TW_Zero )
+ else if ( st0_tag == TAG_Zero )
{
- if ( st1_tag == TW_Valid )
+ if ( st1_tag == TAG_Valid )
{
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ setcc(0); return;
+ }
+ else if ( st1_tag == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
return;
-#endif DENORM_OPERAND
-
setcc(0); return;
}
- else if ( st1_tag == TW_Zero )
- { arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */
+ else if ( st1_tag == TAG_Zero )
+ { arith_invalid(0); return; } /* fprem(?,0) always invalid */
else if ( st1_tag == TW_Infinity )
{ setcc(0); return; }
}
- else if ( st0_tag == TW_Valid )
+ else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
{
- if ( st1_tag == TW_Zero )
+ if ( st1_tag == TAG_Zero )
{
- arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */
+ arith_invalid(0); /* fprem(Valid,Zero) is invalid */
return;
}
else if ( st1_tag != TW_NaN )
{
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ if ( ((st0_tag == TW_Denormal) || (st1_tag == TW_Denormal))
+ && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
if ( st1_tag == TW_Infinity )
{
@@ -960,729 +1091,710 @@ static void do_fprem(FPU_REG *st0_ptr, int round)
{
if ( st1_tag != TW_NaN )
{
- arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */
+ arith_invalid(0); /* fprem(Infinity,?) is invalid */
return;
}
}
- /* One of the registers must contain a NaN is we got here. */
+ /* One of the registers must contain a NaN if we got here. */
#ifdef PARANOID
if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
EXCEPTION(EX_INTERNAL | 0x118);
#endif PARANOID
- real_2op_NaN(st1_ptr, st0_ptr, st0_ptr);
+ real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
}
/* ST(1) <- ST(1) * log ST; pop ST */
-static void fyl2x(FPU_REG *st0_ptr)
+static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st1_ptr = &st(1), exponent;
- char st1_tag = st1_ptr->tag;
- int e;
+ u_char st1_tag = FPU_gettagi(1);
+ u_char sign;
+ int e, tag;
clear_C1();
- if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+
+ if ( (st0_tag == TAG_Valid) && (st1_tag == TAG_Valid) )
{
- if ( st0_ptr->sign == SIGN_POS )
+ both_valid:
+ /* Both regs are Valid or Denormal */
+ if ( signpositive(st0_ptr) )
{
-#ifdef DENORM_OPERAND
- if ( ((st0_ptr->exp <= EXP_UNDER) ||
- (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ if ( st0_tag == TW_Denormal )
+ FPU_to_exp16(st0_ptr, st0_ptr);
+ else
+ /* Convert st(0) for internal use. */
+ setexponent16(st0_ptr, exponent(st0_ptr));
if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) )
{
/* Special case. The result can be precise. */
- e = st0_ptr->exp - EXP_BIAS;
- if ( e > 0 )
+ u_char esign;
+ e = exponent16(st0_ptr);
+ if ( e >= 0 )
{
exponent.sigh = e;
- exponent.sign = SIGN_POS;
+ esign = SIGN_POS;
}
else
{
exponent.sigh = -e;
- exponent.sign = SIGN_NEG;
+ esign = SIGN_NEG;
}
exponent.sigl = 0;
- exponent.exp = EXP_BIAS + 31;
- exponent.tag = TW_Valid;
- normalize_nuo(&exponent);
- reg_mul(&exponent, st1_ptr, st1_ptr, FULL_PRECISION);
+ setexponent16(&exponent, 31);
+ tag = FPU_normalize_nuo(&exponent);
+ stdexp(&exponent);
+ setsign(&exponent, esign);
+ tag = FPU_mul(&exponent, tag, 1, FULL_PRECISION);
+ if ( tag >= 0 )
+ FPU_settagi(1, tag);
}
else
{
/* The usual case */
- poly_l2(st0_ptr, st1_ptr, st1_ptr);
- if ( st1_ptr->exp <= EXP_UNDER )
- {
- /* A denormal result has been produced.
- Precision must have been lost, this is always
- an underflow. */
- arith_underflow(st1_ptr);
- }
+ sign = getsign(st1_ptr);
+ if ( st1_tag == TW_Denormal )
+ FPU_to_exp16(st1_ptr, st1_ptr);
else
- set_precision_flag_up(); /* 80486 appears to always do this */
+ /* Convert st(1) for internal use. */
+ setexponent16(st1_ptr, exponent(st1_ptr));
+ poly_l2(st0_ptr, st1_ptr, sign);
}
- pop();
- return;
}
else
{
/* negative */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
+ if ( arith_invalid(1) < 0 )
+ return;
}
- }
- else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
- {
- stack_underflow_pop(1);
+
+ FPU_pop();
+
return;
}
- else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
{
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
+ FPU_stack_underflow_pop(1);
return;
}
- else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
+ else if ( (st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal) )
{
- /* one of the args is zero, the other valid, or both zero */
- if ( st0_tag == TW_Zero )
+ if ( st0_tag == TAG_Zero )
{
- if ( st1_tag == TW_Zero )
+ if ( st1_tag == TAG_Zero )
{
/* Both args zero is invalid */
- if ( !arith_invalid(st1_ptr) )
- pop();
- }
-#ifdef PECULIAR_486
- /* This case is not specifically covered in the manual,
- but divide-by-zero would seem to be the best response.
- However, a real 80486 does it this way... */
- else if ( st0_ptr->tag == TW_Infinity )
- {
- reg_move(&CONST_INF, st1_ptr);
- pop();
+ if ( arith_invalid(1) < 0 )
+ return;
}
-#endif PECULIAR_486
else
{
- if ( !divide_by_zero(st1_ptr->sign^SIGN_NEG^SIGN_POS, st1_ptr) )
- pop();
+ u_char sign;
+ sign = getsign(st1_ptr)^SIGN_NEG;
+ if ( FPU_divide_by_zero(1, sign) < 0 )
+ return;
+
+ setsign(st1_ptr, sign);
}
- return;
}
- else
+ else if ( st1_tag == TAG_Zero )
{
/* st(1) contains zero, st(0) valid <> 0 */
/* Zero is the valid answer */
- char sign = st1_ptr->sign;
-
- if ( st0_ptr->sign == SIGN_NEG )
+ sign = getsign(st1_ptr);
+
+ if ( signnegative(st0_ptr) )
{
/* log(negative) */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
+ if ( arith_invalid(1) < 0 )
+ return;
}
-
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
+ else
+ {
+ if ( exponent(st0_ptr) < 0 )
+ sign ^= SIGN_NEG;
- if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
- pop(); st0_ptr = &st(0);
- reg_move(&CONST_Z, st0_ptr);
- st0_ptr->sign = sign;
- return;
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ setsign(st1_ptr, sign);
+ }
}
+ else
+ {
+ /* One or both operands are denormals. */
+ if ( denormal_operand() < 0 )
+ return;
+ goto both_valid;
+ }
+ }
+ else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+ {
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
}
/* One or both arg must be an infinity */
else if ( st0_tag == TW_Infinity )
{
- if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
+ if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) )
{
/* log(-infinity) or 0*log(infinity) */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
+ if ( arith_invalid(1) < 0 )
+ return;
}
else
{
- char sign = st1_ptr->sign;
+ u_char sign = getsign(st1_ptr);
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- pop(); st0_ptr = &st(0);
- reg_move(&CONST_INF, st0_ptr);
- st0_ptr->sign = sign;
- return;
+ FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+ setsign(st1_ptr, sign);
}
}
/* st(1) must be infinity here */
- else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) )
+ else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
+ && ( signpositive(st0_ptr) ) )
{
- if ( st0_ptr->exp >= EXP_BIAS )
+ if ( exponent(st0_ptr) >= 0 )
{
- if ( (st0_ptr->exp == EXP_BIAS) &&
+ if ( (exponent(st0_ptr) == 0) &&
(st0_ptr->sigh == 0x80000000) &&
(st0_ptr->sigl == 0) )
{
/* st(0) holds 1.0 */
/* infinity*log(1) */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
+ if ( arith_invalid(1) < 0 )
+ return;
}
- /* st(0) is positive and > 1.0 */
- pop();
+ /* else st(0) is positive and > 1.0 */
}
else
{
/* st(0) is positive and < 1.0 */
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- st1_ptr->sign ^= SIGN_NEG;
- pop();
+ changesign(st1_ptr);
}
- return;
}
else
{
/* st(0) must be zero or negative */
- if ( st0_ptr->tag == TW_Zero )
+ if ( st0_tag == TAG_Zero )
{
/* This should be invalid, but a real 80486 is happy with it. */
+
#ifndef PECULIAR_486
- if ( !divide_by_zero(st1_ptr->sign, st1_ptr) )
+ sign = getsign(st1_ptr);
+ if ( FPU_divide_by_zero(1, sign) < 0 )
+ return;
#endif PECULIAR_486
- {
- st1_ptr->sign ^= SIGN_NEG^SIGN_POS;
- pop();
- }
- }
- else
- {
- /* log(negative) */
- if ( !arith_invalid(st1_ptr) )
- pop();
+
+ changesign(st1_ptr);
}
- return;
+ else if ( arith_invalid(1) < 0 ) /* log(negative) */
+ return;
}
+
+ FPU_pop();
}
-static void fpatan(FPU_REG *st0_ptr)
+static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st1_ptr = &st(1);
- char st1_tag = st1_ptr->tag;
+ u_char st1_tag = FPU_gettagi(1);
+ int tag;
clear_C1();
- if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
{
-#ifdef DENORM_OPERAND
- if ( ((st0_ptr->exp <= EXP_UNDER) ||
- (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ valid_atan:
- poly_atan(st0_ptr, st1_ptr, st1_ptr);
+ poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
- if ( st1_ptr->exp <= EXP_UNDER )
- {
- /* A denormal result has been produced.
- Precision must have been lost.
- This is by definition an underflow. */
- arith_underflow(st1_ptr);
- pop();
- return;
- }
+ FPU_pop();
+
+ return;
}
- else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
{
- stack_underflow_pop(1);
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto valid_atan;
+ }
+ else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
+ {
+ FPU_stack_underflow_pop(1);
return;
}
else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
{
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 )
+ FPU_pop();
return;
}
else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
{
- char sign = st1_ptr->sign;
+ u_char sign = getsign(st1_ptr);
if ( st0_tag == TW_Infinity )
{
if ( st1_tag == TW_Infinity )
{
- if ( st0_ptr->sign == SIGN_POS )
- { reg_move(&CONST_PI4, st1_ptr); }
+ if ( signpositive(st0_ptr) )
+ {
+ FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
+ }
else
- reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
+ {
+ setpositive(st1_ptr);
+ tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr,
+ FULL_PRECISION, SIGN_POS,
+ exponent(&CONST_PI4), exponent(&CONST_PI2));
+ if ( tag >= 0 )
+ FPU_settagi(1, tag);
+ }
}
else
{
-#ifdef DENORM_OPERAND
- if ( st1_tag != TW_Zero )
- {
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
- }
-#endif DENORM_OPERAND
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
- if ( st0_ptr->sign == SIGN_POS )
+ if ( signpositive(st0_ptr) )
{
- reg_move(&CONST_Z, st1_ptr);
- st1_ptr->sign = sign; /* An 80486 preserves the sign */
- pop();
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ setsign(st1_ptr, sign); /* An 80486 preserves the sign */
+ FPU_pop();
return;
}
else
- reg_move(&CONST_PI, st1_ptr);
+ {
+ FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+ }
}
}
else
{
/* st(1) is infinity, st(0) not infinity */
-#ifdef DENORM_OPERAND
- if ( st0_tag != TW_Zero )
- {
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
- }
-#endif DENORM_OPERAND
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
- reg_move(&CONST_PI2, st1_ptr);
+ FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
}
- st1_ptr->sign = sign;
+ setsign(st1_ptr, sign);
}
- else if ( st1_tag == TW_Zero )
+ else if ( st1_tag == TAG_Zero )
{
/* st(0) must be valid or zero */
- char sign = st1_ptr->sign;
+ u_char sign = getsign(st1_ptr);
+
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
-#ifdef DENORM_OPERAND
- if ( st0_tag != TW_Zero )
+ if ( signpositive(st0_ptr) )
{
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
+ /* An 80486 preserves the sign */
+ FPU_pop();
+ return;
}
-#endif DENORM_OPERAND
- if ( st0_ptr->sign == SIGN_POS )
- { /* An 80486 preserves the sign */ pop(); return; }
- else
- reg_move(&CONST_PI, st1_ptr);
- st1_ptr->sign = sign;
+ FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
+ setsign(st1_ptr, sign);
}
- else if ( st0_tag == TW_Zero )
+ else if ( st0_tag == TAG_Zero )
{
- /* st(1) must be TW_Valid here */
- char sign = st1_ptr->sign;
+ /* st(1) must be TAG_Valid here */
+ u_char sign = getsign(st1_ptr);
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- reg_move(&CONST_PI2, st1_ptr);
- st1_ptr->sign = sign;
+ FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
+ setsign(st1_ptr, sign);
}
#ifdef PARANOID
else
EXCEPTION(EX_INTERNAL | 0x125);
#endif PARANOID
- pop();
+ FPU_pop();
set_precision_flag_up(); /* We do not really know if up or down */
}
-static void fprem(FPU_REG *st0_ptr)
+static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
{
- do_fprem(st0_ptr, RC_CHOP);
+ do_fprem(st0_ptr, st0_tag, RC_CHOP);
}
-static void fprem1(FPU_REG *st0_ptr)
+static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
{
- do_fprem(st0_ptr, RC_RND);
+ do_fprem(st0_ptr, st0_tag, RC_RND);
}
-static void fyl2xp1(FPU_REG *st0_ptr)
+static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag, sign;
- FPU_REG *st1_ptr = &st(1);
- char st1_tag = st1_ptr->tag;
+ u_char sign, sign1;
+ FPU_REG *st1_ptr = &st(1), a, b;
+ u_char st1_tag = FPU_gettagi(1);
clear_C1();
- if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
{
-#ifdef DENORM_OPERAND
- if ( ((st0_ptr->exp <= EXP_UNDER) ||
- (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
+ valid_yl2xp1:
+
+ sign = getsign(st0_ptr);
+ sign1 = getsign(st1_ptr);
+
+ FPU_to_exp16(st0_ptr, &a);
+ FPU_to_exp16(st1_ptr, &b);
+
+ if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) )
return;
-#endif DENORM_OPERAND
- if ( poly_l2p1(st0_ptr, st1_ptr, st1_ptr) )
- {
-#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
- st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
-#else
- if ( arith_invalid(st1_ptr) ) /* poly_l2p1() returned invalid */
- return;
-#endif PECULIAR_486
- }
- if ( st1_ptr->exp <= EXP_UNDER )
- {
- /* A denormal result has been produced.
- Precision must have been lost, this is always
- an underflow. */
- sign = st1_ptr->sign;
- arith_underflow(st1_ptr);
- st1_ptr->sign = sign;
- }
- else
- set_precision_flag_up(); /* 80486 appears to always do this */
- pop();
+ FPU_pop();
return;
}
- else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
+ || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return;
+
+ goto valid_yl2xp1;
+ }
+ else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
{
- stack_underflow_pop(1);
+ FPU_stack_underflow_pop(1);
return;
}
- else if ( st0_tag == TW_Zero )
+ else if ( st0_tag == TAG_Zero )
{
- if ( st1_tag <= TW_Zero )
+ switch ( st1_tag )
{
-#ifdef DENORM_OPERAND
- if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
- (denormal_operand()) )
+ case TW_Denormal:
+ if ( denormal_operand() < 0 )
return;
-#endif DENORM_OPERAND
-
- st0_ptr->sign ^= st1_ptr->sign;
- reg_move(st0_ptr, st1_ptr);
- }
- else if ( st1_tag == TW_Infinity )
- {
+
+ case TAG_Zero:
+ case TAG_Valid:
+ setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
+ FPU_copy_to_reg1(st0_ptr, st0_tag);
+ break;
+
+ case TW_Infinity:
/* Infinity*log(1) */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
- }
- else if ( st1_tag == TW_NaN )
- {
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
- return;
- }
+ if ( arith_invalid(1) < 0 )
+ return;
+ break;
+
+ case TW_NaN:
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
+ break;
+
+ default:
#ifdef PARANOID
- else
- {
EXCEPTION(EX_INTERNAL | 0x116);
return;
- }
#endif PARANOID
- pop(); return;
+ }
}
- else if ( st0_tag == TW_Valid )
+ else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
{
- if ( st1_tag == TW_Zero )
+ switch ( st1_tag )
{
- if ( st0_ptr->sign == SIGN_NEG )
+ case TAG_Zero:
+ if ( signnegative(st0_ptr) )
{
- if ( st0_ptr->exp >= EXP_BIAS )
+ if ( exponent(st0_ptr) >= 0 )
{
/* st(0) holds <= -1.0 */
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
- st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
+ changesign(st1_ptr);
#else
- if ( arith_invalid(st1_ptr) ) return;
+ if ( arith_invalid(1) < 0 )
+ return;
#endif PECULIAR_486
- pop(); return;
}
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
- pop(); return;
+ else
+ changesign(st1_ptr);
}
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- pop(); return;
- }
- if ( st1_tag == TW_Infinity )
- {
- if ( st0_ptr->sign == SIGN_NEG )
+ break;
+
+ case TW_Infinity:
+ if ( signnegative(st0_ptr) )
{
- if ( (st0_ptr->exp >= EXP_BIAS) &&
+ if ( (exponent(st0_ptr) >= 0) &&
!((st0_ptr->sigh == 0x80000000) &&
(st0_ptr->sigl == 0)) )
{
/* st(0) holds < -1.0 */
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
- st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
+ changesign(st1_ptr);
#else
- if ( arith_invalid(st1_ptr) ) return;
+ if ( arith_invalid(1) < 0 ) return;
#endif PECULIAR_486
- pop(); return;
}
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
- pop(); return;
+ else
+ changesign(st1_ptr);
}
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
+ break;
+
+ case TW_NaN:
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
return;
-#endif DENORM_OPERAND
- pop(); return;
- }
- if ( st1_tag == TW_NaN )
- {
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
- return;
}
+
}
else if ( st0_tag == TW_NaN )
{
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
- return;
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
}
else if ( st0_tag == TW_Infinity )
{
if ( st1_tag == TW_NaN )
{
- if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
- pop();
- return;
+ if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
+ return;
}
- else if ( st0_ptr->sign == SIGN_NEG )
+ else if ( signnegative(st0_ptr) )
{
- int exponent = st1_ptr->exp;
#ifndef PECULIAR_486
/* This should have higher priority than denormals, but... */
- if ( arith_invalid(st1_ptr) ) /* log(-infinity) */
+ if ( arith_invalid(1) < 0 ) /* log(-infinity) */
return;
#endif PECULIAR_486
-#ifdef DENORM_OPERAND
- if ( st1_tag != TW_Zero )
- {
- if ( (exponent <= EXP_UNDER) && (denormal_operand()) )
- return;
- }
-#endif DENORM_OPERAND
+ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
+ return;
#ifdef PECULIAR_486
/* Denormal operands actually get higher priority */
- if ( arith_invalid(st1_ptr) ) /* log(-infinity) */
+ if ( arith_invalid(1) < 0 ) /* log(-infinity) */
return;
#endif PECULIAR_486
- pop();
- return;
}
- else if ( st1_tag == TW_Zero )
+ else if ( st1_tag == TAG_Zero )
{
/* log(infinity) */
- if ( !arith_invalid(st1_ptr) )
- pop();
- return;
+ if ( arith_invalid(1) < 0 )
+ return;
}
/* st(1) must be valid here. */
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
/* The Manual says that log(Infinity) is invalid, but a real
80486 sensibly says that it is o.k. */
- { char sign = st1_ptr->sign;
- reg_move(&CONST_INF, st1_ptr);
- st1_ptr->sign = sign;
- }
- pop();
- return;
+ else
+ {
+ u_char sign = getsign(st1_ptr);
+ FPU_copy_to_reg1(&CONST_INF, TAG_Special);
+ setsign(st1_ptr, sign);
+ }
}
#ifdef PARANOID
else
{
EXCEPTION(EX_INTERNAL | 0x117);
+ return;
}
#endif PARANOID
+
+ FPU_pop();
+ return;
+
}
-static void fscale(FPU_REG *st0_ptr)
+static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
{
- char st0_tag = st0_ptr->tag;
FPU_REG *st1_ptr = &st(1);
- char st1_tag = st1_ptr->tag;
+ u_char st1_tag = FPU_gettagi(1);
int old_cw = control_word;
- char sign = st0_ptr->sign;
+ u_char sign = getsign(st0_ptr);
clear_C1();
- if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+ if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) )
{
long scale;
FPU_REG tmp;
-#ifdef DENORM_OPERAND
- if ( ((st0_ptr->exp <= EXP_UNDER) ||
- (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ /* Convert register for internal use. */
+ setexponent16(st0_ptr, exponent(st0_ptr));
+
+ valid_scale:
- if ( st1_ptr->exp > EXP_BIAS + 30 )
+ if ( exponent(st1_ptr) > 30 )
{
/* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
- char sign;
- if ( st1_ptr->sign == SIGN_POS )
+ if ( signpositive(st1_ptr) )
{
EXCEPTION(EX_Overflow);
- sign = st0_ptr->sign;
- reg_move(&CONST_INF, st0_ptr);
- st0_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
}
else
{
EXCEPTION(EX_Underflow);
- sign = st0_ptr->sign;
- reg_move(&CONST_Z, st0_ptr);
- st0_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
}
+ setsign(st0_ptr, sign);
return;
}
control_word &= ~CW_RC;
control_word |= RC_CHOP;
- reg_move(st1_ptr, &tmp);
- round_to_int(&tmp); /* This can never overflow here */
+ reg_copy(st1_ptr, &tmp);
+ FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
control_word = old_cw;
- scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
- scale += st0_ptr->exp;
- st0_ptr->exp = scale;
+ scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
+ scale += exponent16(st0_ptr);
- /* Use round_reg() to properly detect under/overflow etc */
- round_reg(st0_ptr, 0, control_word);
+ setexponent16(st0_ptr, scale);
+
+ /* Use FPU_round() to properly detect under/overflow etc */
+ FPU_round(st0_ptr, 0, 0, control_word, sign);
return;
}
- else if ( st0_tag == TW_Valid )
+
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st1_tag == TAG_Special )
+ st1_tag = FPU_Special(st1_ptr);
+
+ if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
{
- if ( st1_tag == TW_Zero )
+ switch ( st1_tag )
{
-
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+ case TAG_Valid:
+ /* st(0) must be a denormal */
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
+ FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
+ goto valid_scale;
+
+ case TAG_Zero:
+ if ( st0_tag == TW_Denormal )
+ denormal_operand();
return;
- }
- if ( st1_tag == TW_Infinity )
- {
-#ifdef DENORM_OPERAND
- if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+
+ case TW_Denormal:
+ denormal_operand();
+ return;
+
+ case TW_Infinity:
+ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
return;
-#endif DENORM_OPERAND
- if ( st1_ptr->sign == SIGN_POS )
- { reg_move(&CONST_INF, st0_ptr); }
+ if ( signpositive(st1_ptr) )
+ FPU_copy_to_reg0(&CONST_INF, TAG_Special);
else
- reg_move(&CONST_Z, st0_ptr);
- st0_ptr->sign = sign;
+ FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
+ setsign(st0_ptr, sign);
+ return;
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
- if ( st1_tag == TW_NaN )
- { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
}
- else if ( st0_tag == TW_Zero )
+ else if ( st0_tag == TAG_Zero )
{
- if ( st1_tag == TW_Valid )
+ switch ( st1_tag )
{
+ case TAG_Valid:
+ case TAG_Zero:
+ return;
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ case TW_Denormal:
+ denormal_operand();
+ return;
+ case TW_Infinity:
+ if ( signpositive(st1_ptr) )
+ arith_invalid(0); /* Zero scaled by +Infinity */
+ return;
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
- else if ( st1_tag == TW_Zero ) { return; }
- else if ( st1_tag == TW_Infinity )
- {
- if ( st1_ptr->sign == SIGN_NEG )
- return;
- else
- {
- arith_invalid(st0_ptr); /* Zero scaled by +Infinity */
- return;
- }
- }
- else if ( st1_tag == TW_NaN )
- { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
}
else if ( st0_tag == TW_Infinity )
{
- if ( st1_tag == TW_Valid )
+ switch ( st1_tag )
{
+ case TAG_Valid:
+ case TAG_Zero:
+ return;
-#ifdef DENORM_OPERAND
- if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
- return;
-#endif DENORM_OPERAND
+ case TW_Denormal:
+ denormal_operand();
+ return;
+ case TW_Infinity:
+ if ( signnegative(st1_ptr) )
+ arith_invalid(0); /* Infinity scaled by -Infinity */
return;
- }
- if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
- || (st1_tag == TW_Zero) )
- return;
- else if ( st1_tag == TW_Infinity )
- {
- arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */
+
+ case TW_NaN:
+ real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
- else if ( st1_tag == TW_NaN )
- { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
}
else if ( st0_tag == TW_NaN )
{
- if ( st1_tag != TW_Empty )
- { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
+ if ( st1_tag != TAG_Empty )
+ { real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; }
}
#ifdef PARANOID
- if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
+ if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) )
{
EXCEPTION(EX_INTERNAL | 0x115);
return;
@@ -1690,7 +1802,7 @@ static void fscale(FPU_REG *st0_ptr)
#endif
/* At least one of st(0), st(1) must be empty */
- stack_underflow();
+ FPU_stack_underflow();
}
@@ -1698,21 +1810,22 @@ static void fscale(FPU_REG *st0_ptr)
/*---------------------------------------------------------------------------*/
static FUNC_ST0 const trig_table_a[] = {
- f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
+ f2xm1, fyl2x, fptan, fpatan,
+ fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp
};
-void trig_a(void)
+void FPU_triga(void)
{
- (trig_table_a[FPU_rm])(&st(0));
+ (trig_table_a[FPU_rm])(&st(0), FPU_gettag0());
}
static FUNC_ST0 const trig_table_b[] =
{
- fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
+ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos
};
-void trig_b(void)
+void FPU_trigb(void)
{
- (trig_table_b[FPU_rm])(&st(0));
+ (trig_table_b[FPU_rm])(&st(0), FPU_gettag0());
}
diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c
index 0749cdc70..799bc1c41 100644
--- a/arch/i386/math-emu/get_address.c
+++ b/arch/i386/math-emu/get_address.c
@@ -3,9 +3,9 @@
| |
| Get the effective address from an FPU instruction. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -41,7 +41,7 @@ static int reg_offset[] = {
offsetof(struct info,___edi)
};
-#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
+#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
static int reg_offset_vm86[] = {
offsetof(struct info,___cs),
@@ -54,7 +54,7 @@ static int reg_offset_vm86[] = {
};
#define VM86_REG_(x) (*(unsigned short *) \
- (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
+ (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
/* These are dummy, fs and gs are not saved on the stack. */
#define ___FS ___ds
@@ -71,18 +71,18 @@ static int reg_offset_pm[] = {
};
#define PM_REG_(x) (*(unsigned short *) \
- (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
+ (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
/* Decode the SIB byte. This function assumes mod != 0 */
static int sib(int mod, unsigned long *fpu_eip)
{
- unsigned char ss,index,base;
+ u_char ss,index,base;
long offset;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(base, (unsigned char *) (*fpu_eip)); /* The SIB byte */
+ FPU_get_user(base, (u_char *) (*fpu_eip)); /* The SIB byte */
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
ss = base >> 6;
@@ -112,7 +112,7 @@ static int sib(int mod, unsigned long *fpu_eip)
long displacement;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(displacement, (signed char *) (*fpu_eip));
+ FPU_get_user(displacement, (signed char *) (*fpu_eip));
offset += displacement;
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
@@ -123,7 +123,7 @@ static int sib(int mod, unsigned long *fpu_eip)
long displacement;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- get_user(displacement, (signed long *) (*fpu_eip));
+ FPU_get_user(displacement, (long *) (*fpu_eip));
offset += displacement;
RE_ENTRANT_CHECK_ON;
(*fpu_eip) += 4;
@@ -133,7 +133,7 @@ static int sib(int mod, unsigned long *fpu_eip)
}
-static unsigned long vm86_segment(unsigned char segment,
+static unsigned long vm86_segment(u_char segment,
unsigned short *selector)
{
segment--;
@@ -150,7 +150,7 @@ static unsigned long vm86_segment(unsigned char segment,
/* This should work for 16 and 32 bit protected mode. */
-static long pm_address(unsigned char FPU_modrm, unsigned char segment,
+static long pm_address(u_char FPU_modrm, u_char segment,
unsigned short *selector, long offset)
{
struct desc_struct descriptor;
@@ -233,12 +233,11 @@ static long pm_address(unsigned char FPU_modrm, unsigned char segment,
*/
-void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
struct address *addr,
-/* unsigned short *selector, unsigned long *offset, */
fpu_addr_modes addr_modes)
{
- unsigned char mod;
+ u_char mod;
unsigned rm = FPU_modrm & 7;
long *cpu_reg_ptr;
int address = 0; /* Initialized just to stop compiler warnings. */
@@ -270,7 +269,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- get_user(address, (unsigned long *) (*fpu_eip));
+ FPU_get_user(address, (unsigned long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
addr->offset = address;
@@ -287,7 +286,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(address, (signed char *) (*fpu_eip));
+ FPU_get_user(address, (signed char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
break;
@@ -295,7 +294,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- get_user(address, (long *) (*fpu_eip));
+ FPU_get_user(address, (long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
break;
@@ -329,12 +328,11 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
}
-void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
struct address *addr,
-/* unsigned short *selector, unsigned long *offset, */
fpu_addr_modes addr_modes)
{
- unsigned char mod;
+ u_char mod;
unsigned rm = FPU_modrm & 7;
int address = 0; /* Default used for mod == 0 */
@@ -358,7 +356,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* Special case: disp16 */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2);
- get_user(address, (unsigned short *) (*fpu_eip));
+ FPU_get_user(address, (unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
goto add_segment;
@@ -368,7 +366,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- get_user(address, (signed char *) (*fpu_eip));
+ FPU_get_user(address, (signed char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
break;
@@ -376,7 +374,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 16 bit displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2);
- get_user(address, (unsigned short *) (*fpu_eip));
+ FPU_get_user(address, (unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
break;
diff --git a/arch/i386/math-emu/load_store.c b/arch/i386/math-emu/load_store.c
index cc288a9ab..4ed4bb7a6 100644
--- a/arch/i386/math-emu/load_store.c
+++ b/arch/i386/math-emu/load_store.c
@@ -4,9 +4,9 @@
| This file contains most of the code to interpret the FPU instructions |
| which load and store from user memory. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -32,10 +32,10 @@
#define _PUSH_ 3 /* Need to check for space to push onto stack */
#define _null_ 4 /* Function illegal or not implemented */
-#define pop_0() { st0_ptr->tag = TW_Empty; top++; }
+#define pop_0() { FPU_settag0(TAG_Empty); top++; }
-static unsigned char const type_table[32] = {
+static u_char const type_table[32] = {
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
_null_, _null_, _null_, _null_,
_REG0_, _REG0_, _REG0_, _REG0_,
@@ -46,25 +46,27 @@ static unsigned char const type_table[32] = {
_NONE_, _REG0_, _NONE_, _REG0_
};
-unsigned char const data_sizes_16[32] = {
+u_char const data_sizes_16[32] = {
4, 4, 8, 2, 0, 0, 0, 0,
4, 4, 8, 2, 4, 4, 8, 2,
14, 0, 94, 10, 2, 10, 0, 8,
14, 0, 94, 10, 2, 10, 2, 8
};
-unsigned char const data_sizes_32[32] = {
+u_char const data_sizes_32[32] = {
4, 4, 8, 2, 0, 0, 0, 0,
4, 4, 8, 2, 4, 4, 8, 2,
28, 0,108, 10, 2, 10, 0, 8,
28, 0,108, 10, 2, 10, 2, 8
};
-int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
+int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
void *data_address)
{
FPU_REG loaded_data;
FPU_REG *st0_ptr;
+ u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
+ u_char loaded_tag;
st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
@@ -93,13 +95,14 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
case _REG0_:
st0_ptr = &st(0); /* Some of these instructions pop after
storing */
+ st0_tag = FPU_gettag0();
break;
case _PUSH_:
{
- st0_ptr = &st(-1);
- if ( st0_ptr->tag != TW_Empty )
- { stack_overflow(); return 0; }
+ if ( FPU_gettagi(-1) != TAG_Empty )
+ { FPU_stack_overflow(); return 0; }
top--;
+ st0_ptr = &st(0);
}
break;
case _null_:
@@ -116,92 +119,97 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
{
case 000: /* fld m32real */
clear_C1();
- reg_load_single((float *)data_address, &loaded_data);
- if ( (loaded_data.tag == TW_NaN) &&
- real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+ loaded_tag = FPU_load_single((float *)data_address, &loaded_data);
+ if ( (loaded_tag == TAG_Special)
+ && isNaN(&loaded_data)
+ && (real_1op_NaN(&loaded_data) < 0) )
{
top++;
break;
}
- reg_move(&loaded_data, st0_ptr);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
break;
case 001: /* fild m32int */
clear_C1();
- reg_load_int32((long *)data_address, st0_ptr);
+ loaded_tag = FPU_load_int32((long *)data_address, &loaded_data);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
break;
case 002: /* fld m64real */
clear_C1();
- reg_load_double((double *)data_address, &loaded_data);
- if ( (loaded_data.tag == TW_NaN) &&
- real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+ loaded_tag = FPU_load_double((double *)data_address, &loaded_data);
+ if ( (loaded_tag == TAG_Special)
+ && isNaN(&loaded_data)
+ && (real_1op_NaN(&loaded_data) < 0) )
{
top++;
break;
}
- reg_move(&loaded_data, st0_ptr);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
break;
case 003: /* fild m16int */
clear_C1();
- reg_load_int16((short *)data_address, st0_ptr);
+ loaded_tag = FPU_load_int16((short *)data_address, &loaded_data);
+ FPU_copy_to_reg0(&loaded_data, loaded_tag);
break;
case 010: /* fst m32real */
clear_C1();
- reg_store_single((float *)data_address, st0_ptr);
+ FPU_store_single(st0_ptr, st0_tag, (float *)data_address);
break;
case 011: /* fist m32int */
clear_C1();
- reg_store_int32((long *)data_address, st0_ptr);
+ FPU_store_int32(st0_ptr, st0_tag, (long *)data_address);
break;
case 012: /* fst m64real */
clear_C1();
- reg_store_double((double *)data_address, st0_ptr);
+ FPU_store_double(st0_ptr, st0_tag, (double *)data_address);
break;
case 013: /* fist m16int */
clear_C1();
- reg_store_int16((short *)data_address, st0_ptr);
+ FPU_store_int16(st0_ptr, st0_tag, (short *)data_address);
break;
case 014: /* fstp m32real */
clear_C1();
- if ( reg_store_single((float *)data_address, st0_ptr) )
+ if ( FPU_store_single(st0_ptr, st0_tag, (float *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 015: /* fistp m32int */
clear_C1();
- if ( reg_store_int32((long *)data_address, st0_ptr) )
+ if ( FPU_store_int32(st0_ptr, st0_tag, (long *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 016: /* fstp m64real */
clear_C1();
- if ( reg_store_double((double *)data_address, st0_ptr) )
+ if ( FPU_store_double(st0_ptr, st0_tag, (double *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 017: /* fistp m16int */
clear_C1();
- if ( reg_store_int16((short *)data_address, st0_ptr) )
+ if ( FPU_store_int16(st0_ptr, st0_tag, (short *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 020: /* fldenv m14/28byte */
- fldenv(addr_modes, (char *)data_address);
+ fldenv(addr_modes, (u_char *)data_address);
/* Ensure that the values just loaded are not changed by
fix-up operations. */
return 1;
case 022: /* frstor m94/108byte */
- frstor(addr_modes, (char *)data_address);
+ frstor(addr_modes, (u_char *)data_address);
/* Ensure that the values just loaded are not changed by
fix-up operations. */
return 1;
case 023: /* fbld m80dec */
clear_C1();
- reg_load_bcd((char *)data_address, st0_ptr);
+ loaded_tag = FPU_load_bcd((u_char *)data_address);
+ FPU_settag0(loaded_tag);
break;
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, data_address, 2);
- get_user(control_word, (unsigned short *) data_address);
+ FPU_get_user(control_word, (unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
if ( partial_status & ~control_word & CW_Exceptions )
partial_status |= (SW_Summary | SW_Backward);
@@ -213,45 +221,47 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
return 1;
case 025: /* fld m80real */
clear_C1();
- reg_load_extended((long double *)data_address, st0_ptr);
+ loaded_tag = FPU_load_extended((long double *)data_address, 0);
+ FPU_settag0(loaded_tag);
break;
case 027: /* fild m64int */
clear_C1();
- reg_load_int64((long long *)data_address, st0_ptr);
+ loaded_tag = FPU_load_int64((long long *)data_address);
+ FPU_settag0(loaded_tag);
break;
case 030: /* fstenv m14/28byte */
- fstenv(addr_modes, (char *)data_address);
+ fstenv(addr_modes, (u_char *)data_address);
return 1;
case 032: /* fsave */
- fsave(addr_modes, (char *)data_address);
+ fsave(addr_modes, (u_char *)data_address);
return 1;
case 033: /* fbstp m80dec */
clear_C1();
- if ( reg_store_bcd((char *)data_address, st0_ptr) )
+ if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,data_address,2);
- put_user(control_word, (unsigned short *) data_address);
+ FPU_put_user(control_word, (unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
case 035: /* fstp m80real */
clear_C1();
- if ( reg_store_extended((long double *)data_address, st0_ptr) )
+ if ( FPU_store_extended(st0_ptr, st0_tag, (long double *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
case 036: /* fstsw m2byte */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,data_address,2);
- put_user(status_word(),(unsigned short *) data_address);
+ FPU_put_user(status_word(),(unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
case 037: /* fistp m64int */
clear_C1();
- if ( reg_store_int64((long long *)data_address, st0_ptr) )
+ if ( FPU_store_int64(st0_ptr, st0_tag, (long long *)data_address) )
pop_0(); /* pop only if the number was actually stored
(see the 80486 manual p16-28) */
break;
diff --git a/arch/i386/math-emu/poly_2xm1.c b/arch/i386/math-emu/poly_2xm1.c
index f7c585d60..51fb4481c 100644
--- a/arch/i386/math-emu/poly_2xm1.c
+++ b/arch/i386/math-emu/poly_2xm1.c
@@ -3,9 +3,9 @@
| |
| Function to compute 2^x-1 by a polynomial approximation. |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
+#include "fpu_system.h"
#include "control_w.h"
#include "poly.h"
@@ -48,20 +49,19 @@ static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1,
/*--- poly_2xm1() -----------------------------------------------------------+
- | Requires an argument which is TW_Valid and < 1. |
+ | Requires st(0) which is TAG_Valid and < 1. |
+---------------------------------------------------------------------------*/
-int poly_2xm1(FPU_REG const *arg, FPU_REG *result)
+int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
{
- long int exponent, shift;
- unsigned long long Xll;
- Xsig accumulator, Denom, argSignif;
+ long int exponent, shift;
+ unsigned long long Xll;
+ Xsig accumulator, Denom, argSignif;
+ u_char tag;
-
- exponent = arg->exp - EXP_BIAS;
+ exponent = exponent16(arg);
#ifdef PARANOID
- if ( (exponent >= 0) /* Don't want a |number| >= 1.0 */
- || (arg->tag != TW_Valid) )
+ if ( exponent >= 0 ) /* Don't want a |number| >= 1.0 */
{
/* Number negative, too large, or not Valid. */
EXCEPTION(EX_INTERNAL|0x127);
@@ -94,7 +94,7 @@ int poly_2xm1(FPU_REG const *arg, FPU_REG *result)
if ( exponent < -2 )
{
/* Shift the argument right by the required places. */
- if ( shrx(&Xll, -2-exponent) >= 0x80000000U )
+ if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
Xll++; /* round up */
}
@@ -118,7 +118,7 @@ int poly_2xm1(FPU_REG const *arg, FPU_REG *result)
exponent = 1;
}
- if ( arg->sign != SIGN_POS )
+ if ( sign != SIGN_POS )
{
/* The argument is negative, use the identity:
f(-x) = -f(x) / (1 + f(x))
@@ -142,10 +142,14 @@ int poly_2xm1(FPU_REG const *arg, FPU_REG *result)
/* Convert to 64 bit signed-compatible */
exponent += round_Xsig(&accumulator);
+ result = &st(0);
significand(result) = XSIG_LL(accumulator);
- result->tag = TW_Valid;
- result->exp = exponent + EXP_BIAS;
- result->sign = arg->sign;
+ setexponent16(result, exponent);
+
+ tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
+
+ setsign(result, sign);
+ FPU_settag0(tag);
return 0;
diff --git a/arch/i386/math-emu/poly_atan.c b/arch/i386/math-emu/poly_atan.c
index 6edca625f..a5d5af882 100644
--- a/arch/i386/math-emu/poly_atan.c
+++ b/arch/i386/math-emu/poly_atan.c
@@ -3,9 +3,9 @@
| |
| Compute the arctan of a FPU_REG, using a polynomial approximation. |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
+#include "fpu_system.h"
#include "status_w.h"
#include "control_w.h"
#include "poly.h"
@@ -51,31 +52,57 @@ static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b);
/*--- poly_atan() -----------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
-void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result)
+void poly_atan(FPU_REG *st0_ptr, u_char st0_tag,
+ FPU_REG *st1_ptr, u_char st1_tag)
{
- char transformed, inverted,
- sign1 = arg1->sign, sign2 = arg2->sign;
- long int exponent, dummy_exp;
- Xsig accumulator, Numer, Denom, accumulatore, argSignif,
- argSq, argSqSq;
+ u_char transformed, inverted,
+ sign1, sign2;
+ int exponent;
+ long int dummy_exp;
+ Xsig accumulator, Numer, Denom, accumulatore, argSignif,
+ argSq, argSqSq;
+ u_char tag;
+ sign1 = getsign(st0_ptr);
+ sign2 = getsign(st1_ptr);
+ if ( st0_tag == TAG_Valid )
+ {
+ exponent = exponent(st0_ptr);
+ }
+ else
+ {
+ /* This gives non-compatible stack contents... */
+ FPU_to_exp16(st0_ptr, st0_ptr);
+ exponent = exponent16(st0_ptr);
+ }
+ if ( st1_tag == TAG_Valid )
+ {
+ exponent -= exponent(st1_ptr);
+ }
+ else
+ {
+ /* This gives non-compatible stack contents... */
+ FPU_to_exp16(st1_ptr, st1_ptr);
+ exponent -= exponent16(st1_ptr);
+ }
- arg1->sign = arg2->sign = SIGN_POS;
- if ( (compare(arg2) & ~COMP_Denormal) == COMP_A_lt_B )
+ if ( (exponent < 0) || ((exponent == 0) &&
+ ((st0_ptr->sigh < st1_ptr->sigh) ||
+ ((st0_ptr->sigh == st1_ptr->sigh) &&
+ (st0_ptr->sigl < st1_ptr->sigl))) ) )
{
inverted = 1;
- exponent = arg1->exp - arg2->exp;
Numer.lsw = Denom.lsw = 0;
- XSIG_LL(Numer) = significand(arg1);
- XSIG_LL(Denom) = significand(arg2);
+ XSIG_LL(Numer) = significand(st0_ptr);
+ XSIG_LL(Denom) = significand(st1_ptr);
}
else
{
inverted = 0;
- exponent = arg2->exp - arg1->exp;
+ exponent = -exponent;
Numer.lsw = Denom.lsw = 0;
- XSIG_LL(Numer) = significand(arg2);
- XSIG_LL(Denom) = significand(arg1);
+ XSIG_LL(Numer) = significand(st1_ptr);
+ XSIG_LL(Denom) = significand(st0_ptr);
}
div_Xsig(&Numer, &Denom, &argSignif);
exponent += norm_Xsig(&argSignif);
@@ -189,9 +216,14 @@ void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result)
}
exponent += round_Xsig(&accumulator);
- significand(result) = XSIG_LL(accumulator);
- result->exp = exponent + EXP_BIAS;
- result->tag = TW_Valid;
- result->sign = sign2;
+
+ significand(st1_ptr) = XSIG_LL(accumulator);
+ setexponent16(st1_ptr, exponent);
+
+ tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
+ FPU_settagi(1, tag);
+
+ set_precision_flag_up(); /* We do not really know if up or down,
+ use this as the default. */
}
diff --git a/arch/i386/math-emu/poly_l2.c b/arch/i386/math-emu/poly_l2.c
index 1677f4aff..07b2da4b9 100644
--- a/arch/i386/math-emu/poly_l2.c
+++ b/arch/i386/math-emu/poly_l2.c
@@ -3,9 +3,9 @@
| |
| Compute the base 2 log of a FPU_REG, using a polynomial approximation. |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -14,96 +14,101 @@
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
+#include "fpu_system.h"
#include "control_w.h"
#include "poly.h"
-
-static void log2_kernel(FPU_REG const *arg,
+static void log2_kernel(FPU_REG const *arg, u_char argsign,
Xsig *accum_result, long int *expon);
/*--- poly_l2() -------------------------------------------------------------+
| Base 2 logarithm by a polynomial approximation. |
+---------------------------------------------------------------------------*/
-void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
+void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
{
long int exponent, expon, expon_expon;
Xsig accumulator, expon_accum, yaccum;
- char sign;
+ u_char sign, argsign;
FPU_REG x;
+ int tag;
+ exponent = exponent16(st0_ptr);
- exponent = arg->exp - EXP_BIAS;
-
- /* From arg, make a number > sqrt(2)/2 and < sqrt(2) */
- if ( arg->sigh > (unsigned)0xb504f334 )
+ /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
+ if ( st0_ptr->sigh > (unsigned)0xb504f334 )
{
- /* Treat as sqrt(2)/2 < arg < 1 */
- significand(&x) = - significand(arg);
- x.sign = SIGN_NEG;
- x.tag = TW_Valid;
- x.exp = EXP_BIAS-1;
+ /* Treat as sqrt(2)/2 < st0_ptr < 1 */
+ significand(&x) = - significand(st0_ptr);
+ setexponent16(&x, -1);
exponent++;
- normalize(&x);
+ argsign = SIGN_NEG;
}
else
{
- /* Treat as 1 <= arg < sqrt(2) */
- x.sigh = arg->sigh - 0x80000000;
- x.sigl = arg->sigl;
- x.sign = SIGN_POS;
- x.tag = TW_Valid;
- x.exp = EXP_BIAS;
- normalize(&x);
+ /* Treat as 1 <= st0_ptr < sqrt(2) */
+ x.sigh = st0_ptr->sigh - 0x80000000;
+ x.sigl = st0_ptr->sigl;
+ setexponent16(&x, 0);
+ argsign = SIGN_POS;
}
+ tag = FPU_normalize_nuo(&x);
- if ( x.tag == TW_Zero )
+ if ( tag == TAG_Zero )
{
expon = 0;
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
}
else
{
- log2_kernel(&x, &accumulator, &expon);
+ log2_kernel(&x, argsign, &accumulator, &expon);
}
- sign = exponent < 0;
- if ( sign ) exponent = -exponent;
+ if ( exponent < 0 )
+ {
+ sign = SIGN_NEG;
+ exponent = -exponent;
+ }
+ else
+ sign = SIGN_POS;
expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
if ( exponent )
{
expon_expon = 31 + norm_Xsig(&expon_accum);
shr_Xsig(&accumulator, expon_expon - expon);
- if ( sign ^ (x.sign == SIGN_NEG) )
+ if ( sign ^ argsign )
negate_Xsig(&accumulator);
add_Xsig_Xsig(&accumulator, &expon_accum);
}
else
{
expon_expon = expon;
- sign = x.sign;
+ sign = argsign;
}
- yaccum.lsw = 0; XSIG_LL(yaccum) = significand(y);
+ yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr);
mul_Xsig_Xsig(&accumulator, &yaccum);
expon_expon += round_Xsig(&accumulator);
if ( accumulator.msw == 0 )
{
- reg_move(&CONST_Z, y);
- }
- else
- {
- result->exp = expon_expon + y->exp + 1;
- significand(result) = XSIG_LL(accumulator);
- result->tag = TW_Valid; /* set the tags to Valid */
- result->sign = sign ^ y->sign;
+ FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
+ return;
}
+ significand(st1_ptr) = XSIG_LL(accumulator);
+ setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
+
+ tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
+ FPU_settagi(1, tag);
+
+ set_precision_flag_up(); /* 80486 appears to always do this */
+
return;
+
}
@@ -111,47 +116,62 @@ void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
| Base 2 logarithm by a polynomial approximation. |
| log2(x+1) |
+---------------------------------------------------------------------------*/
-int poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
+int poly_l2p1(u_char sign0, u_char sign1,
+ FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest)
{
- char sign;
- long int exponent;
- Xsig accumulator, yaccum;
+ u_char tag;
+ long int exponent;
+ Xsig accumulator, yaccum;
-
- sign = arg->sign;
-
- if ( arg->exp < EXP_BIAS )
+ if ( exponent16(st0_ptr) < 0 )
{
- log2_kernel(arg, &accumulator, &exponent);
+ log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
yaccum.lsw = 0;
- XSIG_LL(yaccum) = significand(y);
+ XSIG_LL(yaccum) = significand(st1_ptr);
mul_Xsig_Xsig(&accumulator, &yaccum);
exponent += round_Xsig(&accumulator);
- result->exp = exponent + y->exp + 1;
- significand(result) = XSIG_LL(accumulator);
- result->tag = TW_Valid; /* set the tags to Valid */
- result->sign = sign ^ y->sign;
+ exponent += exponent16(st1_ptr) + 1;
+ if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER;
+
+ significand(dest) = XSIG_LL(accumulator);
+ setexponent16(dest, exponent);
- return 0;
+ tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
+ FPU_settagi(1, tag);
+
+ if ( tag == TAG_Valid )
+ set_precision_flag_up(); /* 80486 appears to always do this */
}
else
{
- /* The magnitude of arg is far too large. */
- reg_move(y, result);
- if ( sign != SIGN_POS )
+ /* The magnitude of st0_ptr is far too large. */
+
+ if ( sign0 != SIGN_POS )
{
/* Trying to get the log of a negative number. */
- return 1;
+#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
+ changesign(st1_ptr);
+#else
+ if ( arith_invalid(1) < 0 )
+ return 1;
+#endif PECULIAR_486
}
+
+ /* 80486 appears to do this */
+ if ( sign0 == SIGN_NEG )
+ set_precision_flag_down();
else
- {
- return 0;
- }
+ set_precision_flag_up();
}
+ if ( exponent(dest) <= EXP_UNDER )
+ EXCEPTION(EX_Underflow);
+
+ return 0;
+
}
@@ -180,20 +200,17 @@ static const unsigned long leadterm = 0xb8000000;
| Base 2 logarithm by a polynomial approximation. |
| log2(x+1) |
+---------------------------------------------------------------------------*/
-static void log2_kernel(FPU_REG const *arg, Xsig *accum_result,
+static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result,
long int *expon)
{
- char sign;
long int exponent, adj;
unsigned long long Xsq;
Xsig accumulator, Numer, Denom, argSignif, arg_signif;
- sign = arg->sign;
-
- exponent = arg->exp - EXP_BIAS;
+ exponent = exponent16(arg);
Numer.lsw = Denom.lsw = 0;
XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
- if ( sign == SIGN_POS )
+ if ( argsign == SIGN_POS )
{
shr_Xsig(&Denom, 2 - (1 + exponent));
Denom.msw |= 0x80000000;
diff --git a/arch/i386/math-emu/poly_sin.c b/arch/i386/math-emu/poly_sin.c
index 03db5b6aa..f03df4c00 100644
--- a/arch/i386/math-emu/poly_sin.c
+++ b/arch/i386/math-emu/poly_sin.c
@@ -4,9 +4,9 @@
| Computation of an approximation of the sin function and the cosine |
| function by a polynomial. |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -15,6 +15,7 @@
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
+#include "fpu_system.h"
#include "control_w.h"
#include "poly.h"
@@ -62,35 +63,26 @@ static const unsigned long long neg_terms_h[N_COEFF_NH] =
/*--- poly_sine() -----------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
-void poly_sine(FPU_REG const *arg, FPU_REG *result)
+void poly_sine(FPU_REG *st0_ptr)
{
int exponent, echange;
Xsig accumulator, argSqrd, argTo4;
unsigned long fix_up, adj;
unsigned long long fixed_arg;
+ FPU_REG result;
-
-#ifdef PARANOID
- if ( arg->tag == TW_Zero )
- {
- /* Return 0.0 */
- reg_move(&CONST_Z, result);
- return;
- }
-#endif PARANOID
-
- exponent = arg->exp - EXP_BIAS;
+ exponent = exponent(st0_ptr);
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
/* Split into two ranges, for arguments below and above 1.0 */
/* The boundary between upper and lower is approx 0.88309101259 */
- if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xe21240aa)) )
+ if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) )
{
/* The argument is <= 0.88309101259 */
- argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0;
- mul64_Xsig(&argSqrd, &significand(arg));
+ argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &significand(st0_ptr));
shr_Xsig(&argSqrd, 2*(-1-exponent));
argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
argTo4.lsw = argSqrd.lsw;
@@ -107,29 +99,29 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
shr_Xsig(&accumulator, 2); /* Divide by four */
accumulator.msw |= 0x80000000; /* Add 1.0 */
- mul64_Xsig(&accumulator, &significand(arg));
- mul64_Xsig(&accumulator, &significand(arg));
- mul64_Xsig(&accumulator, &significand(arg));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
/* Divide by four, FPU_REG compatible, etc */
- exponent = 3*exponent + EXP_BIAS;
+ exponent = 3*exponent;
/* The minimum exponent difference is 3 */
- shr_Xsig(&accumulator, arg->exp - exponent);
+ shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
negate_Xsig(&accumulator);
- XSIG_LL(accumulator) += significand(arg);
+ XSIG_LL(accumulator) += significand(st0_ptr);
echange = round_Xsig(&accumulator);
- result->exp = arg->exp + echange;
+ setexponentpos(&result, exponent(st0_ptr) + echange);
}
else
{
/* The argument is > 0.88309101259 */
- /* We use sin(arg) = cos(pi/2-arg) */
+ /* We use sin(st(0)) = cos(pi/2-st(0)) */
- fixed_arg = significand(arg);
+ fixed_arg = significand(st0_ptr);
if ( exponent == 0 )
{
@@ -192,16 +184,16 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
echange = round_Xsig(&accumulator);
- result->exp = EXP_BIAS - 1 + echange;
+ setexponentpos(&result, echange - 1);
}
- significand(result) = XSIG_LL(accumulator);
- result->tag = TW_Valid;
- result->sign = arg->sign;
+ significand(&result) = XSIG_LL(accumulator);
+ setsign(&result, getsign(st0_ptr));
+ FPU_copy_to_reg0(&result, TAG_Valid);
#ifdef PARANOID
- if ( (result->exp >= EXP_BIAS)
- && (significand(result) > 0x8000000000000000LL) )
+ if ( (exponent(&result) >= 0)
+ && (significand(&result) > 0x8000000000000000LL) )
{
EXCEPTION(EX_INTERNAL|0x150);
}
@@ -214,42 +206,36 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
/*--- poly_cos() ------------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
-void poly_cos(FPU_REG const *arg, FPU_REG *result)
+void poly_cos(FPU_REG *st0_ptr)
{
+ FPU_REG result;
long int exponent, exp2, echange;
Xsig accumulator, argSqrd, fix_up, argTo4;
unsigned long adj;
unsigned long long fixed_arg;
-
#ifdef PARANOID
- if ( arg->tag == TW_Zero )
- {
- /* Return 1.0 */
- reg_move(&CONST_1, result);
- return;
- }
-
- if ( (arg->exp > EXP_BIAS)
- || ((arg->exp == EXP_BIAS)
- && (significand(arg) > 0xc90fdaa22168c234LL)) )
+ if ( (exponent(st0_ptr) > 0)
+ || ((exponent(st0_ptr) == 0)
+ && (significand(st0_ptr) > 0xc90fdaa22168c234LL)) )
{
EXCEPTION(EX_Invalid);
- reg_move(&CONST_QNaN, result);
+ FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
return;
}
#endif PARANOID
- exponent = arg->exp - EXP_BIAS;
+ exponent = exponent(st0_ptr);
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
- if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xb00d6f54)) )
+ if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
{
/* arg is < 0.687705 */
- argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0;
- mul64_Xsig(&argSqrd, &significand(arg));
+ argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
+ argSqrd.lsw = 0;
+ mul64_Xsig(&argSqrd, &significand(st0_ptr));
if ( exponent < -1 )
{
@@ -270,8 +256,8 @@ void poly_cos(FPU_REG const *arg, FPU_REG *result)
N_COEFF_PH-1);
negate_Xsig(&accumulator);
- mul64_Xsig(&accumulator, &significand(arg));
- mul64_Xsig(&accumulator, &significand(arg));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
+ mul64_Xsig(&accumulator, &significand(st0_ptr));
shr_Xsig(&accumulator, -2*(1+exponent));
shr_Xsig(&accumulator, 3);
@@ -290,20 +276,20 @@ void poly_cos(FPU_REG const *arg, FPU_REG *result)
if ( accumulator.msw == 0 )
{
/* The result is 1.0 */
- reg_move(&CONST_1, result);
+ FPU_copy_to_reg0(&CONST_1, TAG_Valid);
+ return;
}
else
{
- significand(result) = XSIG_LL(accumulator);
+ significand(&result) = XSIG_LL(accumulator);
/* will be a valid positive nr with expon = -1 */
- *(short *)&(result->sign) = 0;
- result->exp = EXP_BIAS - 1;
+ setexponentpos(&result, -1);
}
}
else
{
- fixed_arg = significand(arg);
+ fixed_arg = significand(st0_ptr);
if ( exponent == 0 )
{
@@ -392,14 +378,15 @@ void poly_cos(FPU_REG const *arg, FPU_REG *result)
echange = round_Xsig(&accumulator);
- result->exp = exp2 + EXP_BIAS + echange;
- *(short *)&(result->sign) = 0; /* Is a valid positive nr */
- significand(result) = XSIG_LL(accumulator);
+ setexponentpos(&result, exp2 + echange);
+ significand(&result) = XSIG_LL(accumulator);
}
+ FPU_copy_to_reg0(&result, TAG_Valid);
+
#ifdef PARANOID
- if ( (result->exp >= EXP_BIAS)
- && (significand(result) > 0x8000000000000000LL) )
+ if ( (exponent(&result) >= 0)
+ && (significand(&result) > 0x8000000000000000LL) )
{
EXCEPTION(EX_INTERNAL|0x151);
}
diff --git a/arch/i386/math-emu/poly_tan.c b/arch/i386/math-emu/poly_tan.c
index d9b09e438..1743d6f0f 100644
--- a/arch/i386/math-emu/poly_tan.c
+++ b/arch/i386/math-emu/poly_tan.c
@@ -3,9 +3,9 @@
| |
| Compute the tan of a FPU_REG, using a polynomial approximation. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -13,6 +13,7 @@
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
+#include "fpu_system.h"
#include "control_w.h"
#include "poly.h"
@@ -52,7 +53,7 @@ static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL;
/*--- poly_tan() ------------------------------------------------------------+
| |
+---------------------------------------------------------------------------*/
-void poly_tan(FPU_REG const *arg, FPU_REG *result)
+void poly_tan(FPU_REG *st0_ptr)
{
long int exponent;
int invert;
@@ -60,20 +61,20 @@ void poly_tan(FPU_REG const *arg, FPU_REG *result)
argSignif, fix_up;
unsigned long adj;
- exponent = arg->exp - EXP_BIAS;
+ exponent = exponent(st0_ptr);
#ifdef PARANOID
- if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */
- { arith_invalid(result); return; } /* Need a positive number */
+ if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */
+ { arith_invalid(0); return; } /* Need a positive number */
#endif PARANOID
/* Split the problem into two domains, smaller and larger than pi/4 */
- if ( (exponent == 0) || ((exponent == -1) && (arg->sigh > 0xc90fdaa2)) )
+ if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
{
/* The argument is greater than (approx) pi/4 */
invert = 1;
accum.lsw = 0;
- XSIG_LL(accum) = significand(arg);
+ XSIG_LL(accum) = significand(st0_ptr);
if ( exponent == 0 )
{
@@ -92,12 +93,12 @@ void poly_tan(FPU_REG const *arg, FPU_REG *result)
{
invert = 0;
argSignif.lsw = 0;
- XSIG_LL(accum) = XSIG_LL(argSignif) = significand(arg);
+ XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
if ( exponent < -1 )
{
/* shift the argument right by the required places */
- if ( shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
+ if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
XSIG_LL(accum) ++; /* round up */
}
}
@@ -206,8 +207,8 @@ void poly_tan(FPU_REG const *arg, FPU_REG *result)
/* Transfer the result */
round_Xsig(&accum);
- *(short *)&(result->sign) = 0;
- significand(result) = XSIG_LL(accum);
- result->exp = EXP_BIAS + exponent;
+ FPU_settag0(TAG_Valid);
+ significand(st0_ptr) = XSIG_LL(accum);
+ setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
}
diff --git a/arch/i386/math-emu/reg_add_sub.c b/arch/i386/math-emu/reg_add_sub.c
index d70889b40..05e86d624 100644
--- a/arch/i386/math-emu/reg_add_sub.c
+++ b/arch/i386/math-emu/reg_add_sub.c
@@ -3,16 +3,19 @@
| |
| Functions to add or subtract two registers and put the result in a third. |
| |
- | Copyright (C) 1992,1993 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
- | For each function, the destination may be any FPU_REG, including one of |
+ | For each function, the destination may be any FPU_REG, including one of |
| the source FPU_REGs. |
+ | Each function returns 0 if the answer is o.k., otherwise a non-zero |
+ | value is returned, indicating either an exception condition or an |
+ | internal error. |
+---------------------------------------------------------------------------*/
#include "exception.h"
@@ -21,156 +24,164 @@
#include "control_w.h"
#include "fpu_system.h"
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+ FPU_REG const *b, u_char tagb, u_char signb,
+ FPU_REG *dest, int deststnr, int control_w);
-int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
+/*
+ Operates on st(0) and st(n), or on st(0) and temporary data.
+ The destination must be one of the source st(x).
+ */
+int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
{
- char saved_sign = dest->sign;
- int diff;
+ FPU_REG *a = &st(0);
+ FPU_REG *dest = &st(deststnr);
+ u_char signb = getsign(b);
+ u_char taga = FPU_gettag0();
+ u_char signa = getsign(a);
+ u_char saved_sign = getsign(dest);
+ int diff, tag, expa, expb;
- if ( !(a->tag | b->tag) )
+ if ( !(taga | tagb) )
{
+ expa = exponent(a);
+ expb = exponent(b);
+
+ valid_add:
/* Both registers are valid */
- if (!(a->sign ^ b->sign))
+ if (!(signa ^ signb))
{
/* signs are the same */
- dest->sign = a->sign;
- if ( reg_u_add(a, b, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
- return 0;
+ tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb);
}
-
- /* The signs are different, so do a subtraction */
- diff = a->exp - b->exp;
- if (!diff)
+ else
{
- diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
+ /* The signs are different, so do a subtraction */
+ diff = expa - expb;
if (!diff)
{
- diff = a->sigl > b->sigl;
+ diff = a->sigh - b->sigh; /* This works only if the ms bits
+ are identical. */
if (!diff)
- diff = -(a->sigl < b->sigl);
- }
- }
-
- if (diff > 0)
- {
- dest->sign = a->sign;
- if ( reg_u_sub(a, b, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
- }
- else if ( diff == 0 )
- {
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(&CONST_Z, dest);
- /* sign depends upon rounding mode */
- dest->sign = ((control_w & CW_RC) != RC_DOWN)
- ? SIGN_POS : SIGN_NEG;
- }
- else
- {
- dest->sign = b->sign;
- if ( reg_u_sub(b, a, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
- }
- return 0;
- }
- else
- {
- if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
- { return real_2op_NaN(a, b, dest); }
- else if (a->tag == TW_Zero)
- {
- if (b->tag == TW_Zero)
- {
- char different_signs = a->sign ^ b->sign;
- /* Both are zero, result will be zero. */
- reg_move(a, dest);
- if (different_signs)
{
- /* Signs are different. */
- /* Sign of answer depends upon rounding mode. */
- dest->sign = ((control_w & CW_RC) != RC_DOWN)
- ? SIGN_POS : SIGN_NEG;
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
}
}
- else
+
+ if (diff > 0)
{
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(b, dest);
+ tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
}
- return 0;
- }
- else if (b->tag == TW_Zero)
- {
-#ifdef DENORM_OPERAND
- if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(a, dest); return 0;
- }
- else if (a->tag == TW_Infinity)
- {
- if (b->tag != TW_Infinity)
+ else if ( diff < 0 )
{
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(a, dest); return 0;
+ tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
}
- if (a->sign == b->sign)
+ else
{
- /* They are both + or - infinity */
- reg_move(a, dest); return 0;
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ /* sign depends upon rounding mode */
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
+ return TAG_Zero;
}
- return arith_invalid(dest); /* Infinity-Infinity is undefined. */
}
- else if (b->tag == TW_Infinity)
+
+ if ( tag < 0 )
{
-#ifdef DENORM_OPERAND
- if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(b, dest); return 0;
+ setsign(dest, saved_sign);
+ return tag;
}
+ FPU_settagi(deststnr, tag);
+ return tag;
}
-#ifdef PARANOID
- EXCEPTION(EX_INTERNAL|0x101);
-#endif
- return 1;
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ FPU_REG x, y;
+
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ a = &x;
+ b = &y;
+ expa = exponent16(a);
+ expb = exponent16(b);
+ goto valid_add;
+ }
+
+ if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ if ( deststnr == 0 )
+ return real_2op_NaN(b, tagb, deststnr, a);
+ else
+ return real_2op_NaN(a, taga, deststnr, a);
+ }
+
+ return add_sub_specials(a, taga, signa, b, tagb, signb,
+ dest, deststnr, control_w);
}
/* Subtract b from a. (a-b) -> dest */
-int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
+int FPU_sub(int flags, int rm, int control_w)
{
- char saved_sign = dest->sign;
- int diff;
+ FPU_REG const *a, *b;
+ FPU_REG *dest;
+ u_char taga, tagb, signa, signb, saved_sign, sign;
+ int diff, tag, expa, expb, deststnr;
+
+ a = &st(0);
+ taga = FPU_gettag0();
+
+ deststnr = 0;
+ if ( flags & LOADED )
+ {
+ b = (FPU_REG *)rm;
+ tagb = flags & 0x0f;
+ }
+ else
+ {
+ b = &st(rm);
+ tagb = FPU_gettagi(rm);
+
+ if ( flags & DEST_RM )
+ deststnr = rm;
+ }
+
+ signa = getsign(a);
+ signb = getsign(b);
+
+ if ( flags & REV )
+ {
+ signa ^= SIGN_NEG;
+ signb ^= SIGN_NEG;
+ }
- if ( !(a->tag | b->tag) )
+ dest = &st(deststnr);
+ saved_sign = getsign(dest);
+
+ if ( !(taga | tagb) )
{
+ expa = exponent(a);
+ expb = exponent(b);
+
+ valid_subtract:
/* Both registers are valid */
- diff = a->exp - b->exp;
+
+ diff = expa - expb;
+
if (!diff)
{
diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
@@ -182,137 +193,182 @@ int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w)
}
}
- switch (a->sign*2 + b->sign)
+ switch ( (((int)signa)*2 + signb) / SIGN_NEG )
{
case 0: /* P - P */
case 3: /* N - N */
if (diff > 0)
{
/* |a| > |b| */
- dest->sign = a->sign;
- if ( reg_u_sub(a, b, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
- return 0;
+ tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
}
else if ( diff == 0 )
{
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(&CONST_Z, dest);
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+
/* sign depends upon rounding mode */
- dest->sign = ((control_w & CW_RC) != RC_DOWN)
- ? SIGN_POS : SIGN_NEG;
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
+ return TAG_Zero;
}
else
{
- dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
- if ( reg_u_sub(b, a, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
+ sign = signa ^ SIGN_NEG;
+ tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa);
}
break;
case 1: /* P - N */
- dest->sign = SIGN_POS;
- if ( reg_u_add(a, b, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
+ tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb);
break;
case 2: /* N - P */
- dest->sign = SIGN_NEG;
- if ( reg_u_add(a, b, dest, control_w) )
- {
- dest->sign = saved_sign;
- return 1;
- }
+ tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb);
break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL|0x111);
+ return -1;
+#endif
+ }
+ if ( tag < 0 )
+ {
+ setsign(dest, saved_sign);
+ return tag;
}
- return 0;
+ FPU_settagi(deststnr, tag);
+ return tag;
}
- else
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
{
- if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
- { return real_2op_NaN(b, a, dest); }
- else if (b->tag == TW_Zero)
- {
- if (a->tag == TW_Zero)
- {
- char same_signs = !(a->sign ^ b->sign);
- /* Both are zero, result will be zero. */
- reg_move(a, dest); /* Answer for different signs. */
- if (same_signs)
- {
- /* Sign depends upon rounding mode */
- dest->sign = ((control_w & CW_RC) != RC_DOWN)
- ? SIGN_POS : SIGN_NEG;
- }
- }
- else
- {
-#ifdef DENORM_OPERAND
- if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(a, dest);
- }
- return 0;
+ FPU_REG x, y;
+
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ a = &x;
+ b = &y;
+ expa = exponent16(a);
+ expb = exponent16(b);
+
+ goto valid_subtract;
+ }
+
+ if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ FPU_REG const *d1, *d2;
+ if ( flags & REV )
+ {
+ d1 = b;
+ d2 = a;
}
- else if (a->tag == TW_Zero)
+ else
{
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(b, dest);
- dest->sign ^= SIGN_POS^SIGN_NEG;
- return 0;
+ d1 = a;
+ d2 = b;
}
- else if (a->tag == TW_Infinity)
+ if ( flags & LOADED )
+ return real_2op_NaN(b, tagb, deststnr, d1);
+ if ( flags & DEST_RM )
+ return real_2op_NaN(a, taga, deststnr, d2);
+ else
+ return real_2op_NaN(b, tagb, deststnr, d2);
+ }
+
+ return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
+ dest, deststnr, control_w);
+}
+
+
+static
+int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
+ FPU_REG const *b, u_char tagb, u_char signb,
+ FPU_REG *dest, int deststnr, int control_w)
+{
+ if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+ && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ if (taga == TAG_Zero)
+ {
+ if (tagb == TAG_Zero)
{
- if (b->tag != TW_Infinity)
+ /* Both are zero, result will be zero. */
+ u_char different_signs = signa ^ signb;
+
+ FPU_copy_to_regi(a, TAG_Zero, deststnr);
+ if ( different_signs )
{
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(a, dest); return 0;
+ /* Signs are different. */
+ /* Sign of answer depends upon rounding mode. */
+ setsign(dest, ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG);
}
- /* Both args are Infinity */
- if (a->sign == b->sign)
+ else
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ return TAG_Zero;
+ }
+ else
+ {
+ reg_copy(b, dest);
+ if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
{
- /* Infinity-Infinity is undefined. */
- return arith_invalid(dest);
+ /* A pseudoDenormal, convert it. */
+ addexponent(dest, 1);
+ tagb = TAG_Valid;
}
- reg_move(a, dest);
- return 0;
+ else if ( tagb > TAG_Empty )
+ tagb = TAG_Special;
+ setsign(dest, signb); /* signb may differ from the sign of b. */
+ FPU_settagi(deststnr, tagb);
+ return tagb;
}
- else if (b->tag == TW_Infinity)
+ }
+ else if (tagb == TAG_Zero)
+ {
+ reg_copy(a, dest);
+ if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
{
-#ifdef DENORM_OPERAND
- if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(b, dest);
- dest->sign ^= SIGN_POS^SIGN_NEG;
- return 0;
+ /* A pseudoDenormal */
+ addexponent(dest, 1);
+ taga = TAG_Valid;
}
+ else if ( taga > TAG_Empty )
+ taga = TAG_Special;
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ FPU_settagi(deststnr, taga);
+ return taga;
}
+ else if (taga == TW_Infinity)
+ {
+ if ( (tagb != TW_Infinity) || (signa == signb) )
+ {
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, signa); /* signa may differ from the sign of a. */
+ return taga;
+ }
+ /* Infinity-Infinity is undefined. */
+ return arith_invalid(deststnr);
+ }
+ else if (tagb == TW_Infinity)
+ {
+ FPU_copy_to_regi(b, TAG_Special, deststnr);
+ setsign(dest, signb); /* signb may differ from the sign of b. */
+ return tagb;
+ }
+
#ifdef PARANOID
- EXCEPTION(EX_INTERNAL|0x110);
+ EXCEPTION(EX_INTERNAL|0x101);
#endif
- return 1;
+
+ return FPU_Exception;
}
diff --git a/arch/i386/math-emu/reg_compare.c b/arch/i386/math-emu/reg_compare.c
index eb4a1fa99..20023977f 100644
--- a/arch/i386/math-emu/reg_compare.c
+++ b/arch/i386/math-emu/reg_compare.c
@@ -3,9 +3,9 @@
| |
| Compare two floating point registers |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -21,86 +21,87 @@
#include "status_w.h"
-int compare(FPU_REG const *b)
+static int compare(FPU_REG const *b, int tagb)
{
- int diff;
- char st0_tag;
- FPU_REG *st0_ptr;
+ int diff, exp0, expb;
+ u_char st0_tag;
+ FPU_REG *st0_ptr;
+ FPU_REG x, y;
+ u_char st0_sign, signb = getsign(b);
st0_ptr = &st(0);
- st0_tag = st0_ptr->tag;
+ st0_tag = FPU_gettag0();
+ st0_sign = getsign(st0_ptr);
- if ( st0_tag | b->tag )
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+ if ( st0_tag == TAG_Special )
+ st0_tag = FPU_Special(st0_ptr);
+
+ if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
+ || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
{
- if ( st0_tag == TW_Zero )
+ if ( st0_tag == TAG_Zero )
{
- if ( b->tag == TW_Zero ) return COMP_A_eq_B;
- if ( b->tag == TW_Valid )
- {
- return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- | ((b->exp <= EXP_UNDER) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
+ if ( tagb == TAG_Zero ) return COMP_A_eq_B;
+ if ( tagb == TAG_Valid )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( tagb == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
}
- else if ( b->tag == TW_Zero )
+ else if ( tagb == TAG_Zero )
{
- if ( st0_tag == TW_Valid )
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
- : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- | ((st0_ptr->exp <= EXP_UNDER )
- ? COMP_Denormal : 0 )
-#endif DENORM_OPERAND
- ;
- }
+ if ( st0_tag == TAG_Valid )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
}
if ( st0_tag == TW_Infinity )
{
- if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
- : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0 )
-#endif DENORM_OPERAND
-;
- }
- else if ( b->tag == TW_Infinity )
+ if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ else if ( tagb == TW_Denormal )
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | COMP_Denormal;
+ else if ( tagb == TW_Infinity )
{
/* The 80486 book says that infinities can be equal! */
- return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
- ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ return (st0_sign == signb) ? COMP_A_eq_B :
+ ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
}
/* Fall through to the NaN code */
}
- else if ( b->tag == TW_Infinity )
+ else if ( tagb == TW_Infinity )
{
- if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
- {
- return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- | (((st0_tag == TW_Valid)
- && (st0_ptr->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
+ if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
+ if ( st0_tag == TW_Denormal )
+ return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | COMP_Denormal;
/* Fall through to the NaN code */
}
/* The only possibility now should be that one of the arguments
is a NaN */
- if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
+ if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
{
- if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
- || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
- /* At least one arg is a signaling NaN */
+ int signalling = 0, unsupported = 0;
+ if ( st0_tag == TW_NaN )
+ {
+ signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
+ unsupported = !((exponent(st0_ptr) == EXP_OVER)
+ && (st0_ptr->sigh & 0x80000000));
+ }
+ if ( tagb == TW_NaN )
+ {
+ signalling |= (b->sigh & 0xc0000000) == 0x80000000;
+ unsupported |= !((exponent(b) == EXP_OVER)
+ && (b->sigh & 0x80000000));
+ }
+ if ( signalling || unsupported )
return COMP_No_Comp | COMP_SNaN | COMP_NaN;
else
/* Neither is a signaling NaN */
@@ -110,24 +111,34 @@ int compare(FPU_REG const *b)
EXCEPTION(EX_Invalid);
}
+ if (st0_sign != signb)
+ {
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
+ }
+
+ if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
+ {
+ FPU_to_exp16(st0_ptr, &x);
+ FPU_to_exp16(b, &y);
+ st0_ptr = &x;
+ b = &y;
+ exp0 = exponent16(st0_ptr);
+ expb = exponent16(b);
+ }
+ else
+ {
+ exp0 = exponent(st0_ptr);
+ expb = exponent(b);
+ }
+
#ifdef PARANOID
if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
#endif PARANOID
-
- if (st0_ptr->sign != b->sign)
- {
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
- }
-
- diff = st0_ptr->exp - b->exp;
+ diff = exp0 - expb;
if ( diff == 0 )
{
diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
@@ -142,42 +153,30 @@ int compare(FPU_REG const *b)
if ( diff > 0 )
{
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
if ( diff < 0 )
{
- return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
return COMP_A_eq_B
-#ifdef DENORM_OPERAND
- |
- ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
- COMP_Denormal : 0)
-#endif DENORM_OPERAND
- ;
+ | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
+ COMP_Denormal : 0);
}
/* This function requires that st(0) is not empty */
-int compare_st_data(FPU_REG const *loaded_data)
+int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
{
int f, c;
- c = compare(loaded_data);
+ c = compare(loaded_data, loaded_tag);
if (c & COMP_NaN)
{
@@ -209,7 +208,7 @@ int compare_st_data(FPU_REG const *loaded_data)
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -218,6 +217,7 @@ int compare_st_data(FPU_REG const *loaded_data)
static int compare_st_st(int nr)
{
int f, c;
+ FPU_REG *st_ptr;
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
{
@@ -227,7 +227,8 @@ static int compare_st_st(int nr)
return !(control_word & CW_Invalid);
}
- c = compare(&st(nr));
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
if (c & COMP_NaN)
{
setcc(SW_C3 | SW_C2 | SW_C0);
@@ -259,7 +260,7 @@ static int compare_st_st(int nr)
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -268,6 +269,7 @@ static int compare_st_st(int nr)
static int compare_u_st_st(int nr)
{
int f, c;
+ FPU_REG *st_ptr;
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
{
@@ -277,7 +279,8 @@ static int compare_u_st_st(int nr)
return !(control_word & CW_Invalid);
}
- c = compare(&st(nr));
+ st_ptr = &st(nr);
+ c = compare(st_ptr, FPU_gettagi(nr));
if (c & COMP_NaN)
{
setcc(SW_C3 | SW_C2 | SW_C0);
@@ -314,7 +317,7 @@ static int compare_u_st_st(int nr)
setcc(f);
if (c & COMP_Denormal)
{
- return denormal_operand();
+ return denormal_operand() < 0;
}
return 0;
}
@@ -332,7 +335,7 @@ void fcompst()
{
/* fcomp st(i) */
if ( !compare_st_st(FPU_rm) )
- pop();
+ FPU_pop();
}
@@ -361,7 +364,7 @@ void fucomp()
{
/* fucomp st(i) */
if ( !compare_u_st_st(FPU_rm) )
- pop();
+ FPU_pop();
}
diff --git a/arch/i386/math-emu/reg_constant.c b/arch/i386/math-emu/reg_constant.c
index 1b2458eea..ffbfebd51 100644
--- a/arch/i386/math-emu/reg_constant.c
+++ b/arch/i386/math-emu/reg_constant.c
@@ -3,9 +3,9 @@
| |
| All of the constant FPU_REGs |
| |
- | Copyright (C) 1992,1993,1994,1996 |
+ | Copyright (C) 1992,1993,1994,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -17,59 +17,52 @@
#include "control_w.h"
-FPU_REG const CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
- 0x00000000, 0x80000000 };
-FPU_REG const CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1,
- 0x00000000, 0x80000000 };
-FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
- 0x00000000, 0x80000000 };
-FPU_REG const CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1,
- 0xcd1b8afe, 0xd49a784b };
-FPU_REG const CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS,
- 0x5c17f0bc, 0xb8aa3b29 };
-FPU_REG const CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1,
- 0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS,
- 0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
- 0x2168c235, 0xc90fdaa2 };
-FPU_REG const CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2,
- 0xfbcff799, 0x9a209a84 };
-FPU_REG const CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
- 0xd1cf79ac, 0xb17217f7 };
+#define MAKE_REG(s,e,l,h) { l, h, \
+ ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+
+FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
+FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
+FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
+FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
+FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
+FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
+FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
+FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
/* Extra bits to take pi/2 to more than 128 bits precision. */
-FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66,
- 0xfc8f8cbb, 0xece675d1 };
+FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
+ 0xfc8f8cbb, 0xece675d1);
/* Only the sign (and tag) is used in internal zeroes */
-FPU_REG const CONST_Z = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 };
+FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
/* Only the sign and significand (and tag) are used in internal NaNs */
/* The 80486 never generates one of these
-FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
*/
/* This is the real indefinite QNaN */
-FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
+FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
/* Only the sign (and tag) is used in internal infinities */
-FPU_REG const CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
-
+FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
-static void fld_const(FPU_REG const *c, int adj)
+static void fld_const(FPU_REG const *c, int adj, u_char tag)
{
FPU_REG *st_new_ptr;
if ( STACK_OVERFLOW )
{
- stack_overflow();
+ FPU_stack_overflow();
return;
}
push();
- reg_move(c, st_new_ptr);
+ reg_copy(c, st_new_ptr);
st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
borrow or carry. */
+ FPU_settag0(tag);
clear_C1();
}
@@ -80,37 +73,37 @@ static void fld_const(FPU_REG const *c, int adj)
static void fld1(int rc)
{
- fld_const(&CONST_1, 0);
+ fld_const(&CONST_1, 0, TAG_Valid);
}
static void fldl2t(int rc)
{
- fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0);
+ fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
}
static void fldl2e(int rc)
{
- fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0);
+ fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
}
static void fldpi(int rc)
{
- fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0);
+ fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
}
static void fldlg2(int rc)
{
- fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0);
+ fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
}
static void fldln2(int rc)
{
- fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0);
+ fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
}
static void fldz(int rc)
{
- fld_const(&CONST_Z, 0);
+ fld_const(&CONST_Z, 0, TAG_Zero);
}
typedef void (*FUNC_RC)(int);
diff --git a/arch/i386/math-emu/reg_convert.c b/arch/i386/math-emu/reg_convert.c
new file mode 100644
index 000000000..45a258752
--- /dev/null
+++ b/arch/i386/math-emu/reg_convert.c
@@ -0,0 +1,53 @@
+/*---------------------------------------------------------------------------+
+ | reg_convert.c |
+ | |
+ | Convert register representation. |
+ | |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
+ | |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_emu.h"
+
+
+int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
+{
+ int sign = getsign(a);
+
+ *(long long *)&(x->sigl) = *(const long long *)&(a->sigl);
+
+ /* Set up the exponent as a 16 bit quantity. */
+ setexponent16(x, exponent(a));
+
+ if ( exponent16(x) == EXP_UNDER )
+ {
+ /* The number is a de-normal or pseudodenormal. */
+ /* We only deal with the significand and exponent. */
+
+ if (x->sigh & 0x80000000)
+ {
+ /* Is a pseudodenormal. */
+ /* This is non-80486 behaviour because the number
+ loses its 'denormal' identity. */
+ addexponent(x, 1);
+ }
+ else
+ {
+ /* Is a denormal. */
+ addexponent(x, 1);
+ FPU_normalize_nuo(x);
+ }
+ }
+
+ if ( !(x->sigh & 0x80000000) )
+ {
+ EXCEPTION(EX_INTERNAL | 0x180);
+ }
+
+ return sign;
+}
+
diff --git a/arch/i386/math-emu/reg_div.S b/arch/i386/math-emu/reg_div.S
deleted file mode 100644
index 24d44ac6c..000000000
--- a/arch/i386/math-emu/reg_div.S
+++ /dev/null
@@ -1,248 +0,0 @@
- .file "reg_div.S"
-/*---------------------------------------------------------------------------+
- | reg_div.S |
- | |
- | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
- | |
- | Copyright (C) 1992,1993,1994,1995 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
- | |
- | Call from C as: |
- | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
- | unsigned int control_word) |
- | |
- +---------------------------------------------------------------------------*/
-
-#include "exception.h"
-#include "fpu_emu.h"
-
-
-.text
-ENTRY(reg_div)
- pushl %ebp
- movl %esp,%ebp
-#ifndef NON_REENTRANT_FPU
- subl $28,%esp /* Needed by divide_kernel */
-#endif NON_REENTRANT_FPU
-
- pushl %esi
- pushl %edi
- pushl %ebx
-
- movl PARAM1,%esi
- movl PARAM2,%ebx
- movl PARAM3,%edi
-
- movb TAG(%esi),%al
- orb TAG(%ebx),%al
-
- jne L_div_special /* Not (both numbers TW_Valid) */
-
-#ifdef DENORM_OPERAND
-/* Check for denormals */
- cmpl EXP_UNDER,EXP(%esi)
- jg xL_arg1_not_denormal
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xL_arg1_not_denormal:
- cmpl EXP_UNDER,EXP(%ebx)
- jg xL_arg2_not_denormal
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xL_arg2_not_denormal:
-#endif DENORM_OPERAND
-
-/* Both arguments are TW_Valid */
- movb TW_Valid,TAG(%edi)
-
- movb SIGN(%esi),%cl
- cmpb %cl,SIGN(%ebx)
- setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
-
- movl EXP(%esi),%edx
- movl EXP(%ebx),%eax
- subl %eax,%edx
- addl EXP_BIAS,%edx
- movl %edx,EXP(%edi)
-
- jmp SYMBOL_NAME(divide_kernel)
-
-
-/*-----------------------------------------------------------------------*/
-L_div_special:
- cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
- je L_arg1_NaN
-
- cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
- jne L_no_NaN_arg
-
-/* Operations on NaNs */
-L_arg1_NaN:
-L_arg2_NaN:
- pushl %edi /* Destination */
- pushl %esi
- pushl %ebx /* Ordering is important here */
- call SYMBOL_NAME(real_2op_NaN)
- jmp LDiv_exit
-
-/* Invalid operations */
-L_zero_zero:
-L_inf_inf:
- pushl %edi /* Destination */
- call SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */
- jmp LDiv_exit
-
-L_no_NaN_arg:
- cmpb TW_Infinity,TAG(%esi)
- jne L_arg1_not_inf
-
- cmpb TW_Infinity,TAG(%ebx)
- je L_inf_inf /* invalid operation */
-
- cmpb TW_Valid,TAG(%ebx)
- je L_inf_valid
-
-#ifdef PARANOID
- /* arg2 must be zero or valid */
- cmpb TW_Zero,TAG(%ebx)
- ja L_unknown_tags
-#endif PARANOID
-
- /* Note that p16-9 says that infinity/0 returns infinity */
- jmp L_copy_arg1 /* Answer is Inf */
-
-L_inf_valid:
-#ifdef DENORM_OPERAND
- cmpl EXP_UNDER,EXP(%ebx)
- jg L_copy_arg1 /* Answer is Inf */
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-#endif DENORM_OPERAND
-
- jmp L_copy_arg1 /* Answer is Inf */
-
-L_arg1_not_inf:
- cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
- jne L_arg2_not_zero
-
- cmpb TW_Zero,TAG(%esi)
- je L_zero_zero /* invalid operation */
-
-#ifdef PARANOID
- /* arg1 must be valid */
- cmpb TW_Valid,TAG(%esi)
- ja L_unknown_tags
-#endif PARANOID
-
-/* Division by zero error */
- pushl %edi /* destination */
- movb SIGN(%esi),%al
- xorb SIGN(%ebx),%al
- pushl %eax /* lower 8 bits have the sign */
- call SYMBOL_NAME(divide_by_zero)
- jmp LDiv_exit
-
-L_arg2_not_zero:
- cmpb TW_Infinity,TAG(%ebx)
- jne L_arg2_not_inf
-
-#ifdef DENORM_OPERAND
- cmpb TW_Valid,TAG(%esi)
- jne L_return_zero
-
- cmpl EXP_UNDER,EXP(%esi)
- jg L_return_zero /* Answer is zero */
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-#endif DENORM_OPERAND
-
- jmp L_return_zero /* Answer is zero */
-
-L_arg2_not_inf:
-
-#ifdef PARANOID
- cmpb TW_Zero,TAG(%esi)
- jne L_unknown_tags
-#endif PARANOID
-
- /* arg1 is zero, arg2 is not Infinity or a NaN */
-
-#ifdef DENORM_OPERAND
- cmpl EXP_UNDER,EXP(%ebx)
- jg L_copy_arg1 /* Answer is zero */
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-#endif DENORM_OPERAND
-
-L_copy_arg1:
- movb TAG(%esi),%ax
- movb %ax,TAG(%edi)
- movl EXP(%esi),%eax
- movl %eax,EXP(%edi)
- movl SIGL(%esi),%eax
- movl %eax,SIGL(%edi)
- movl SIGH(%esi),%eax
- movl %eax,SIGH(%edi)
-
-LDiv_set_result_sign:
- movb SIGN(%esi),%cl
- cmpb %cl,SIGN(%ebx)
- jne LDiv_negative_result
-
- movb SIGN_POS,SIGN(%edi)
- xorl %eax,%eax /* Valid result */
- jmp LDiv_exit
-
-LDiv_negative_result:
- movb SIGN_NEG,SIGN(%edi)
- xorl %eax,%eax /* Valid result */
-
-LDiv_exit:
-#ifndef NON_REENTRANT_FPU
- leal -40(%ebp),%esp
-#else
- leal -12(%ebp),%esp
-#endif NON_REENTRANT_FPU
-
- popl %ebx
- popl %edi
- popl %esi
- leave
- ret
-
-
-L_return_zero:
- xorl %eax,%eax
- movl %eax,SIGH(%edi)
- movl %eax,SIGL(%edi)
- movl EXP_UNDER,EXP(%edi)
- movb TW_Zero,TAG(%edi)
- jmp LDiv_set_result_sign
-
-#ifdef PARANOID
-L_unknown_tags:
- pushl EX_INTERNAL | 0x208
- call EXCEPTION
-
- /* Generate a NaN for unknown tags */
- movl SYMBOL_NAME(CONST_QNaN),%eax
- movl %eax,(%edi)
- movl SYMBOL_NAME(CONST_QNaN)+4,%eax
- movl %eax,SIGL(%edi)
- movl SYMBOL_NAME(CONST_QNaN)+8,%eax
- movl %eax,SIGH(%edi)
- jmp LDiv_exit /* %eax is nz */
-#endif PARANOID
diff --git a/arch/i386/math-emu/reg_divide.c b/arch/i386/math-emu/reg_divide.c
new file mode 100644
index 000000000..266775aca
--- /dev/null
+++ b/arch/i386/math-emu/reg_divide.c
@@ -0,0 +1,206 @@
+/*---------------------------------------------------------------------------+
+ | reg_divide.c |
+ | |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ | |
+ | Copyright (C) 1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+
+/*
+ Divide one register by another and put the result into a third register.
+ */
+int FPU_div(int flags, int rm, int control_w)
+{
+ FPU_REG x, y;
+ FPU_REG const *a, *b, *st0_ptr, *st_ptr;
+ FPU_REG *dest;
+ u_char taga, tagb, signa, signb, sign, saved_sign;
+ int tag, deststnr;
+
+ if ( flags & DEST_RM )
+ deststnr = rm;
+ else
+ deststnr = 0;
+
+ if ( flags & REV )
+ {
+ b = &st(0);
+ st0_ptr = b;
+ tagb = FPU_gettag0();
+ if ( flags & LOADED )
+ {
+ a = (FPU_REG *)rm;
+ taga = flags & 0x0f;
+ }
+ else
+ {
+ a = &st(rm);
+ st_ptr = a;
+ taga = FPU_gettagi(rm);
+ }
+ }
+ else
+ {
+ a = &st(0);
+ st0_ptr = a;
+ taga = FPU_gettag0();
+ if ( flags & LOADED )
+ {
+ b = (FPU_REG *)rm;
+ tagb = flags & 0x0f;
+ }
+ else
+ {
+ b = &st(rm);
+ st_ptr = b;
+ tagb = FPU_gettagi(rm);
+ }
+ }
+
+ signa = getsign(a);
+ signb = getsign(b);
+
+ sign = signa ^ signb;
+
+ dest = &st(deststnr);
+ saved_sign = getsign(dest);
+
+ if ( !(taga | tagb) )
+ {
+ /* Both regs Valid, this should be the most common case. */
+ reg_copy(a, &x);
+ reg_copy(b, &y);
+ setpositive(&x);
+ setpositive(&y);
+ tag = FPU_u_div(&x, &y, dest, control_w, sign);
+
+ if ( tag < 0 )
+ return tag;
+
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
+ {
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ tag = FPU_u_div(&x, &y, dest, control_w, sign);
+ if ( tag < 0 )
+ return tag;
+
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+ else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+ {
+ if ( tagb != TAG_Zero )
+ {
+ /* Want to find Zero/Valid */
+ if ( tagb == TW_Denormal )
+ {
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+ }
+
+ /* The result is zero. */
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ setsign(dest, sign);
+ return TAG_Zero;
+ }
+ /* We have an exception condition, either 0/0 or Valid/Zero. */
+ if ( taga == TAG_Zero )
+ {
+ /* 0/0 */
+ return arith_invalid(deststnr);
+ }
+ /* Valid/Zero */
+ return FPU_divide_by_zero(deststnr, sign);
+ }
+ /* Must have infinities, NaNs, etc */
+ else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ if ( flags & LOADED )
+ return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
+
+ if ( flags & DEST_RM )
+ {
+ int tag;
+ tag = FPU_gettag0();
+ if ( tag == TAG_Special )
+ tag = FPU_Special(st0_ptr);
+ return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm));
+ }
+ else
+ {
+ int tag;
+ tag = FPU_gettagi(rm);
+ if ( tag == TAG_Special )
+ tag = FPU_Special(&st(rm));
+ return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm));
+ }
+ }
+ else if (taga == TW_Infinity)
+ {
+ if (tagb == TW_Infinity)
+ {
+ /* infinity/infinity */
+ return arith_invalid(deststnr);
+ }
+ else
+ {
+ /* tagb must be Valid or Zero */
+ if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ /* Infinity divided by Zero or Valid does
+ not raise and exception, but returns Infinity */
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return taga;
+ }
+ }
+ else if (tagb == TW_Infinity)
+ {
+ if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
+ return FPU_Exception;
+
+ /* The result is zero. */
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
+ setsign(dest, sign);
+ return TAG_Zero;
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x102);
+ return FPU_Exception;
+ }
+#endif PARANOID
+
+}
diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c
index 3e258a0c6..468e51cc8 100644
--- a/arch/i386/math-emu/reg_ld_str.c
+++ b/arch/i386/math-emu/reg_ld_str.c
@@ -3,9 +3,9 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
- | Copyright (C) 1992,1993,1994,1996 |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- | E-mail billm@jacobi.maths.monash.edu.au |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -17,19 +17,17 @@
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
+#include "fpu_emu.h"
+
#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
#include "reg_constant.h"
-#include "fpu_emu.h"
#include "control_w.h"
#include "status_w.h"
-#define EXTENDED_Ebias 0x3fff
-#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
-
#define DOUBLE_Emax 1023 /* largest valid exponent */
#define DOUBLE_Ebias 1023
#define DOUBLE_Emin (-1022) /* smallest valid exponent */
@@ -38,123 +36,85 @@
#define SINGLE_Ebias 127
#define SINGLE_Emin (-126) /* smallest valid exponent */
-static void write_to_extended(FPU_REG *rp, char *d);
-
-/* Get a long double from user memory */
-int reg_load_extended(long double *s, FPU_REG *loaded_data)
+static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
{
- unsigned long sigl, sigh, exp;
+ u_char tag;
- RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_READ, s, 10);
- get_user(sigl, (unsigned long *) s);
- get_user(sigh, 1 + (unsigned long *) s);
- get_user(exp, 4 + (unsigned short *) s);
- RE_ENTRANT_CHECK_ON;
+ setexponent16(r, exp);
- loaded_data->tag = TW_Valid; /* Default */
- loaded_data->sigl = sigl;
- loaded_data->sigh = sigh;
- if (exp & 0x8000)
- loaded_data->sign = SIGN_NEG;
- else
- loaded_data->sign = SIGN_POS;
- exp &= 0x7fff;
- loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS;
+ tag = FPU_normalize_nuo(r);
+ stdexp(r);
+ if ( sign )
+ setnegative(r);
+
+ return tag;
+}
+
+
+int FPU_tagof(FPU_REG *ptr)
+{
+ int exp;
+ exp = exponent16(ptr) & 0x7fff;
if ( exp == 0 )
{
- if ( !(sigh | sigl) )
+ if ( !(ptr->sigh | ptr->sigl) )
{
- loaded_data->tag = TW_Zero;
- return 0;
+ return TAG_Zero;
}
/* The number is a de-normal or pseudodenormal. */
- if (sigh & 0x80000000)
- {
- /* Is a pseudodenormal. */
- /* Convert it for internal use. */
- /* This is non-80486 behaviour because the number
- loses its 'denormal' identity. */
- loaded_data->exp++;
- return 1;
- }
- else
- {
- /* Is a denormal. */
- /* Convert it for internal use. */
- loaded_data->exp++;
- normalize_nuo(loaded_data);
- return 0;
- }
+ return TAG_Special;
}
- else if ( exp == 0x7fff )
- {
- if ( !((sigh ^ 0x80000000) | sigl) )
- {
- /* Matches the bit pattern for Infinity. */
- loaded_data->exp = EXP_Infinity;
- loaded_data->tag = TW_Infinity;
- return 0;
- }
- loaded_data->exp = EXP_NaN;
- loaded_data->tag = TW_NaN;
- if ( !(sigh & 0x80000000) )
- {
- /* NaNs have the ms bit set to 1. */
- /* This is therefore an Unsupported NaN data type. */
- /* This is non 80486 behaviour */
- /* This should generate an Invalid Operand exception
- later, so we convert it to a SNaN */
- loaded_data->sigh = 0x80000000;
- loaded_data->sigl = 0x00000001;
- loaded_data->sign = SIGN_NEG;
- return 1;
- }
- return 0;
+ if ( exp == 0x7fff )
+ {
+ /* Is an Infinity, a NaN, or an unsupported data type. */
+ return TAG_Special;
}
- if ( !(sigh & 0x80000000) )
+ if ( !(ptr->sigh & 0x80000000) )
{
/* Unsupported data type. */
/* Valid numbers have the ms bit set to 1. */
/* Unnormal. */
- /* Convert it for internal use. */
- /* This is non-80486 behaviour */
- /* This should generate an Invalid Operand exception
- later, so we convert it to a SNaN */
- loaded_data->sigh = 0x80000000;
- loaded_data->sigl = 0x00000001;
- loaded_data->sign = SIGN_NEG;
- loaded_data->exp = EXP_NaN;
- loaded_data->tag = TW_NaN;
- return 1;
+ return TAG_Special;
}
- return 0;
+
+ return TAG_Valid;
+}
+
+
+/* Get a long double from user memory */
+int FPU_load_extended(long double *s, int stnr)
+{
+ FPU_REG *sti_ptr = &st(stnr);
+
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 10);
+ __copy_from_user(sti_ptr, s, 10);
+ RE_ENTRANT_CHECK_ON;
+
+ return FPU_tagof(sti_ptr);
}
/* Get a double from user memory */
-int reg_load_double(double *dfloat, FPU_REG *loaded_data)
+int FPU_load_double(double *dfloat, FPU_REG *loaded_data)
{
- int exp;
+ int exp, tag, negative;
unsigned m64, l64;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, dfloat, 8);
- get_user(m64, 1 + (unsigned long *) dfloat);
- get_user(l64, (unsigned long *) dfloat);
+ FPU_get_user(m64, 1 + (unsigned long *) dfloat);
+ FPU_get_user(l64, (unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON;
- if (m64 & 0x80000000)
- loaded_data->sign = SIGN_NEG;
- else
- loaded_data->sign = SIGN_POS;
- exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
+ negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+ exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
m64 &= 0xfffff;
- if (exp > DOUBLE_Emax)
+ if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
{
/* Infinity or NaN */
if ((m64 == 0) && (l64 == 0))
@@ -162,93 +122,87 @@ int reg_load_double(double *dfloat, FPU_REG *loaded_data)
/* +- infinity */
loaded_data->sigh = 0x80000000;
loaded_data->sigl = 0x00000000;
- loaded_data->exp = EXP_Infinity;
- loaded_data->tag = TW_Infinity;
- return 0;
+ exp = EXP_Infinity + EXTENDED_Ebias;
+ tag = TAG_Special;
}
else
{
/* Must be a signaling or quiet NaN */
- loaded_data->exp = EXP_NaN;
- loaded_data->tag = TW_NaN;
+ exp = EXP_NaN + EXTENDED_Ebias;
loaded_data->sigh = (m64 << 11) | 0x80000000;
loaded_data->sigh |= l64 >> 21;
loaded_data->sigl = l64 << 11;
- return 0; /* The calling function must look for NaNs */
+ tag = TAG_Special; /* The calling function must look for NaNs */
}
}
- else if ( exp < DOUBLE_Emin )
+ else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
{
/* Zero or de-normal */
if ((m64 == 0) && (l64 == 0))
{
/* Zero */
- int c = loaded_data->sign;
- reg_move(&CONST_Z, loaded_data);
- loaded_data->sign = c;
- return 0;
+ reg_copy(&CONST_Z, loaded_data);
+ exp = 0;
+ tag = TAG_Zero;
}
else
{
/* De-normal */
- loaded_data->exp = DOUBLE_Emin + EXP_BIAS;
- loaded_data->tag = TW_Valid;
loaded_data->sigh = m64 << 11;
loaded_data->sigh |= l64 >> 21;
loaded_data->sigl = l64 << 11;
- normalize_nuo(loaded_data);
- return denormal_operand();
+
+ return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
+ | (denormal_operand() < 0 ? FPU_Exception : 0);
}
}
else
{
- loaded_data->exp = exp + EXP_BIAS;
- loaded_data->tag = TW_Valid;
loaded_data->sigh = (m64 << 11) | 0x80000000;
loaded_data->sigh |= l64 >> 21;
loaded_data->sigl = l64 << 11;
- return 0;
+ tag = TAG_Valid;
}
+
+ setexponent16(loaded_data, exp | negative);
+
+ return tag;
}
/* Get a float from user memory */
-int reg_load_single(float *single, FPU_REG *loaded_data)
+int FPU_load_single(float *single, FPU_REG *loaded_data)
{
unsigned m32;
- int exp;
+ int exp, tag, negative;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, single, 4);
- get_user(m32, (unsigned long *) single);
+ FPU_get_user(m32, (unsigned long *) single);
RE_ENTRANT_CHECK_ON;
- if (m32 & 0x80000000)
- loaded_data->sign = SIGN_NEG;
- else
- loaded_data->sign = SIGN_POS;
+ negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
+
if (!(m32 & 0x7fffffff))
{
/* Zero */
- int c = loaded_data->sign;
- reg_move(&CONST_Z, loaded_data);
- loaded_data->sign = c;
- return 0;
+ reg_copy(&CONST_Z, loaded_data);
+ addexponent(loaded_data, negative);
+ return TAG_Zero;
}
- exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
+ exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
m32 = (m32 & 0x7fffff) << 8;
- if ( exp < SINGLE_Emin )
+ if ( exp < SINGLE_Emin + EXTENDED_Ebias )
{
/* De-normals */
- loaded_data->exp = SINGLE_Emin + EXP_BIAS;
- loaded_data->tag = TW_Valid;
loaded_data->sigh = m32;
loaded_data->sigl = 0;
- normalize_nuo(loaded_data);
- return denormal_operand();
+
+ return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
+ | (denormal_operand() < 0 ? FPU_Exception : 0);
}
- else if ( exp > SINGLE_Emax )
+ else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
{
/* Infinity or NaN */
if ( m32 == 0 )
@@ -256,36 +210,37 @@ int reg_load_single(float *single, FPU_REG *loaded_data)
/* +- infinity */
loaded_data->sigh = 0x80000000;
loaded_data->sigl = 0x00000000;
- loaded_data->exp = EXP_Infinity;
- loaded_data->tag = TW_Infinity;
- return 0;
+ exp = EXP_Infinity + EXTENDED_Ebias;
+ tag = TAG_Special;
}
else
{
/* Must be a signaling or quiet NaN */
- loaded_data->exp = EXP_NaN;
- loaded_data->tag = TW_NaN;
+ exp = EXP_NaN + EXTENDED_Ebias;
loaded_data->sigh = m32 | 0x80000000;
loaded_data->sigl = 0;
- return 0; /* The calling function must look for NaNs */
+ tag = TAG_Special; /* The calling function must look for NaNs */
}
}
else
{
- loaded_data->exp = exp + EXP_BIAS;
loaded_data->sigh = m32 | 0x80000000;
loaded_data->sigl = 0;
- loaded_data->tag = TW_Valid;
- return 0;
+ tag = TAG_Valid;
}
+
+ setexponent16(loaded_data, exp | negative); /* Set the sign. */
+
+ return tag;
}
/* Get a long long from user memory */
-void reg_load_int64(long long *_s, FPU_REG *loaded_data)
+int FPU_load_int64(long long *_s)
{
- int e;
long long s;
+ int sign;
+ FPU_REG *st0_ptr = &st(0);
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 8);
@@ -293,93 +248,91 @@ void reg_load_int64(long long *_s, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_ON;
if (s == 0)
- { reg_move(&CONST_Z, loaded_data); return; }
+ {
+ reg_copy(&CONST_Z, st0_ptr);
+ return TAG_Zero;
+ }
if (s > 0)
- loaded_data->sign = SIGN_POS;
+ sign = SIGN_Positive;
else
{
s = -s;
- loaded_data->sign = SIGN_NEG;
+ sign = SIGN_Negative;
}
- e = EXP_BIAS + 63;
- significand(loaded_data) = s;
- loaded_data->exp = e;
- loaded_data->tag = TW_Valid;
- normalize_nuo(loaded_data);
+ significand(st0_ptr) = s;
+
+ return normalize_no_excep(st0_ptr, 63, sign);
}
/* Get a long from user memory */
-void reg_load_int32(long *_s, FPU_REG *loaded_data)
+int FPU_load_int32(long *_s, FPU_REG *loaded_data)
{
long s;
- int e;
+ int negative;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 4);
- get_user(s, _s);
+ FPU_get_user(s, _s);
RE_ENTRANT_CHECK_ON;
if (s == 0)
- { reg_move(&CONST_Z, loaded_data); return; }
+ { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
if (s > 0)
- loaded_data->sign = SIGN_POS;
+ negative = SIGN_Positive;
else
- {
- s = -s;
- loaded_data->sign = SIGN_NEG;
- }
+ {
+ s = -s;
+ negative = SIGN_Negative;
+ }
- e = EXP_BIAS + 31;
loaded_data->sigh = s;
loaded_data->sigl = 0;
- loaded_data->exp = e;
- loaded_data->tag = TW_Valid;
- normalize_nuo(loaded_data);
+
+ return normalize_no_excep(loaded_data, 31, negative);
}
/* Get a short from user memory */
-void reg_load_int16(short *_s, FPU_REG *loaded_data)
+int FPU_load_int16(short *_s, FPU_REG *loaded_data)
{
- int s, e;
+ int s, negative;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 2);
/* Cast as short to get the sign extended. */
- get_user(s, _s);
+ FPU_get_user(s, _s);
RE_ENTRANT_CHECK_ON;
if (s == 0)
- { reg_move(&CONST_Z, loaded_data); return; }
+ { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
if (s > 0)
- loaded_data->sign = SIGN_POS;
+ negative = SIGN_Positive;
else
- {
- s = -s;
- loaded_data->sign = SIGN_NEG;
- }
+ {
+ s = -s;
+ negative = SIGN_Negative;
+ }
- e = EXP_BIAS + 15;
loaded_data->sigh = s << 16;
-
loaded_data->sigl = 0;
- loaded_data->exp = e;
- loaded_data->tag = TW_Valid;
- normalize_nuo(loaded_data);
+
+ return normalize_no_excep(loaded_data, 15, negative);
}
/* Get a packed bcd array from user memory */
-void reg_load_bcd(char *s, FPU_REG *loaded_data)
+int FPU_load_bcd(u_char *s)
{
+ FPU_REG *st0_ptr = &st(0);
int pos;
- unsigned char bcd;
+ u_char bcd;
long long l=0;
+ int sign;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 10);
@@ -388,7 +341,7 @@ void reg_load_bcd(char *s, FPU_REG *loaded_data)
{
l *= 10;
RE_ENTRANT_CHECK_OFF;
- get_user(bcd, (unsigned char *) s+pos);
+ FPU_get_user(bcd, (u_char *) s+pos);
RE_ENTRANT_CHECK_ON;
l += bcd >> 4;
l *= 10;
@@ -396,32 +349,27 @@ void reg_load_bcd(char *s, FPU_REG *loaded_data)
}
RE_ENTRANT_CHECK_OFF;
- {
- unsigned char sign;
- get_user(sign, (unsigned char *) s+9);
- loaded_data->sign = (sign & 0x80) ? SIGN_NEG : SIGN_POS;
- }
+ FPU_get_user(sign, (u_char *) s+9);
+ sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
RE_ENTRANT_CHECK_ON;
- if (l == 0)
+ if ( l == 0 )
{
- char sign = loaded_data->sign;
- reg_move(&CONST_Z, loaded_data);
- loaded_data->sign = sign;
+ reg_copy(&CONST_Z, st0_ptr);
+ addexponent(st0_ptr, sign); /* Set the sign. */
+ return TAG_Zero;
}
else
{
- significand(loaded_data) = l;
- loaded_data->exp = EXP_BIAS + 63;
- loaded_data->tag = TW_Valid;
- normalize_nuo(loaded_data);
+ significand(st0_ptr) = l;
+ return normalize_no_excep(st0_ptr, 63, sign);
}
}
/*===========================================================================*/
/* Put a long double into user memory */
-int reg_store_extended(long double *d, FPU_REG *st0_ptr)
+int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d)
{
/*
The only exception raised by an attempt to store to an
@@ -429,12 +377,16 @@ int reg_store_extended(long double *d, FPU_REG *st0_ptr)
attempting to store from an empty register.
*/
- if ( st0_ptr->tag != TW_Empty )
+ if ( st0_tag != TAG_Empty )
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE, d, 10);
+
+ FPU_put_user(st0_ptr->sigl, (unsigned long *) d);
+ FPU_put_user(st0_ptr->sigh, (unsigned long *) ((u_char *)d + 4));
+ FPU_put_user(exponent16(st0_ptr), (unsigned short *) ((u_char *)d + 8));
RE_ENTRANT_CHECK_ON;
- write_to_extended(st0_ptr, (char *) d);
+
return 1;
}
@@ -446,9 +398,9 @@ int reg_store_extended(long double *d, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
- put_user(0, (unsigned long *) d);
- put_user(0xc0000000, 1 + (unsigned long *) d);
- put_user(0xffff, 4 + (short *) d);
+ FPU_put_user(0, (unsigned long *) d);
+ FPU_put_user(0xc0000000, 1 + (unsigned long *) d);
+ FPU_put_user(0xffff, 4 + (short *) d);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -459,38 +411,26 @@ int reg_store_extended(long double *d, FPU_REG *st0_ptr)
/* Put a double into user memory */
-int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
+int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat)
{
unsigned long l[2];
unsigned long increment = 0; /* avoid gcc warnings */
- char st0_tag = st0_ptr->tag;
+ int precision_loss;
+ int exp;
+ FPU_REG tmp;
- if (st0_tag == TW_Valid)
+ if ( st0_tag == TAG_Valid )
{
- int precision_loss;
- int exp;
- FPU_REG tmp;
-
- reg_move(st0_ptr, &tmp);
- exp = tmp.exp - EXP_BIAS;
+ reg_copy(st0_ptr, &tmp);
+ exp = exponent(&tmp);
if ( exp < DOUBLE_Emin ) /* It may be a denormal */
{
- /* A denormal will always underflow. */
-#ifndef PECULIAR_486
- /* An 80486 is supposed to be able to generate
- a denormal exception here, but... */
- if ( st0_ptr->exp <= EXP_UNDER )
- {
- /* Underflow has priority. */
- if ( control_word & CW_Underflow )
- denormal_operand();
- }
-#endif PECULIAR_486
+ addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
- tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
+ denormal_arg:
- if ( (precision_loss = round_to_int(&tmp)) )
+ if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
{
#ifdef PECULIAR_486
/* Did it round to a non-denormal ? */
@@ -527,10 +467,10 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
break;
case RC_DOWN: /* towards -infinity */
- increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
+ increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
break;
case RC_UP: /* towards +infinity */
- increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
+ increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
break;
case RC_CHOP:
increment = 0;
@@ -601,33 +541,64 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
}
}
}
- else if (st0_tag == TW_Zero)
+ else if (st0_tag == TAG_Zero)
{
/* Number is zero */
l[0] = 0;
l[1] = 0;
}
- else if (st0_tag == TW_Infinity)
- {
- l[0] = 0;
- l[1] = 0x7ff00000;
- }
- else if (st0_tag == TW_NaN)
+ else if ( st0_tag == TAG_Special )
{
- /* See if we can get a valid NaN from the FPU_REG */
- l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
- l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
- if ( !(st0_ptr->sigh & 0x40000000) )
+ st0_tag = FPU_Special(st0_ptr);
+ if ( st0_tag == TW_Denormal )
{
- /* It is a signalling NaN */
- EXCEPTION(EX_Invalid);
- if ( !(control_word & CW_Invalid) )
- return 0;
- l[1] |= (0x40000000 >> 11);
+ /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+ /* An 80486 is supposed to be able to generate
+ a denormal exception here, but... */
+ /* Underflow has priority. */
+ if ( control_word & CW_Underflow )
+ denormal_operand();
+#endif PECULIAR_486
+ reg_copy(st0_ptr, &tmp);
+ goto denormal_arg;
+ }
+ else if (st0_tag == TW_Infinity)
+ {
+ l[0] = 0;
+ l[1] = 0x7ff00000;
+ }
+ else if (st0_tag == TW_NaN)
+ {
+ /* Is it really a NaN ? */
+ if ( (exponent(st0_ptr) == EXP_OVER)
+ && (st0_ptr->sigh & 0x80000000) )
+ {
+ /* See if we can get a valid NaN from the FPU_REG */
+ l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
+ l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
+ if ( !(st0_ptr->sigh & 0x40000000) )
+ {
+ /* It is a signalling NaN */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ l[1] |= (0x40000000 >> 11);
+ }
+ l[1] |= 0x7ff00000;
+ }
+ else
+ {
+ /* It is an unsupported data type */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ l[0] = 0;
+ l[1] = 0xfff80000;
+ }
}
- l[1] |= 0x7ff00000;
}
- else if ( st0_tag == TW_Empty )
+ else if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
@@ -637,21 +608,21 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
- put_user(0, (unsigned long *) dfloat);
- put_user(0xfff80000, 1 + (unsigned long *) dfloat);
+ FPU_put_user(0, (unsigned long *) dfloat);
+ FPU_put_user(0xfff80000, 1 + (unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON;
return 1;
}
else
return 0;
}
- if ( st0_ptr->sign )
+ if ( getsign(st0_ptr) )
l[1] |= 0x80000000;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
- put_user(l[0], (unsigned long *)dfloat);
- put_user(l[1], 1 + (unsigned long *)dfloat);
+ FPU_put_user(l[0], (unsigned long *)dfloat);
+ FPU_put_user(l[1], 1 + (unsigned long *)dfloat);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -659,38 +630,27 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
/* Put a float into user memory */
-int reg_store_single(float *single, FPU_REG *st0_ptr)
+int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
{
long templ;
unsigned long increment = 0; /* avoid gcc warnings */
- char st0_tag = st0_ptr->tag;
+ int precision_loss;
+ int exp;
+ FPU_REG tmp;
- if (st0_tag == TW_Valid)
+ if ( st0_tag == TAG_Valid )
{
- int precision_loss;
- int exp;
- FPU_REG tmp;
- reg_move(st0_ptr, &tmp);
- exp = tmp.exp - EXP_BIAS;
+ reg_copy(st0_ptr, &tmp);
+ exp = exponent(&tmp);
if ( exp < SINGLE_Emin )
{
- /* A denormal will always underflow. */
-#ifndef PECULIAR_486
- /* An 80486 is supposed to be able to generate
- a denormal exception here, but... */
- if ( st0_ptr->exp <= EXP_UNDER )
- {
- /* Underflow has priority. */
- if ( control_word & CW_Underflow )
- denormal_operand();
- }
-#endif PECULIAR_486
+ addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
- tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
+ denormal_arg:
- if ( (precision_loss = round_to_int(&tmp)) )
+ if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
{
#ifdef PECULIAR_486
/* Did it round to a non-denormal ? */
@@ -704,15 +664,15 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
EXCEPTION(EX_Underflow);
/* This is a special case: see sec 16.2.5.1 of
the 80486 book */
- if ( !(control_word & EX_Underflow) )
+ if ( !(control_word & CW_Underflow) )
return 0;
}
EXCEPTION(precision_loss);
- if ( !(control_word & EX_Precision) )
+ if ( !(control_word & CW_Precision) )
return 0;
}
templ = tmp.sigl;
- }
+ }
else
{
if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
@@ -726,15 +686,15 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
case RC_RND:
increment = ((sigh & 0xff) > 0x80) /* more than half */
|| (((sigh & 0xff) == 0x80) && sigl) /* more than half */
- || ((sigh & 0x180) == 0x180); /* round to even */
+ || ((sigh & 0x180) == 0x180); /* round to even */
break;
case RC_DOWN: /* towards -infinity */
- increment = (tmp.sign == SIGN_POS)
- ? 0 : (sigl | (sigh & 0xff));
+ increment = signpositive(&tmp)
+ ? 0 : (sigl | (sigh & 0xff));
break;
case RC_UP: /* towards +infinity */
- increment = (tmp.sign == SIGN_POS)
- ? (sigl | (sigh & 0xff)) : 0;
+ increment = signpositive(&tmp)
+ ? (sigl | (sigh & 0xff)) : 0;
break;
case RC_CHOP:
increment = 0;
@@ -767,7 +727,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
}
else
precision_loss = 0;
-
+
templ = (tmp.sigh >> 8) & 0x007fffff;
if ( exp > SINGLE_Emax )
@@ -798,29 +758,66 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
}
}
}
- else if (st0_tag == TW_Zero)
+ else if (st0_tag == TAG_Zero)
{
templ = 0;
}
- else if (st0_tag == TW_Infinity)
+ else if ( st0_tag == TAG_Special )
{
- templ = 0x7f800000;
- }
- else if (st0_tag == TW_NaN)
- {
- /* See if we can get a valid NaN from the FPU_REG */
- templ = st0_ptr->sigh >> 8;
- if ( !(st0_ptr->sigh & 0x40000000) )
+ st0_tag = FPU_Special(st0_ptr);
+ if (st0_tag == TW_Denormal)
{
- /* It is a signalling NaN */
- EXCEPTION(EX_Invalid);
- if ( !(control_word & CW_Invalid) )
- return 0;
- templ |= (0x40000000 >> 8);
+ reg_copy(st0_ptr, &tmp);
+
+ /* A denormal will always underflow. */
+#ifndef PECULIAR_486
+ /* An 80486 is supposed to be able to generate
+ a denormal exception here, but... */
+ /* Underflow has priority. */
+ if ( control_word & CW_Underflow )
+ denormal_operand();
+#endif PECULIAR_486
+ goto denormal_arg;
+ }
+ else if (st0_tag == TW_Infinity)
+ {
+ templ = 0x7f800000;
}
- templ |= 0x7f800000;
+ else if (st0_tag == TW_NaN)
+ {
+ /* Is it really a NaN ? */
+ if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
+ {
+ /* See if we can get a valid NaN from the FPU_REG */
+ templ = st0_ptr->sigh >> 8;
+ if ( !(st0_ptr->sigh & 0x40000000) )
+ {
+ /* It is a signalling NaN */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ templ |= (0x40000000 >> 8);
+ }
+ templ |= 0x7f800000;
+ }
+ else
+ {
+ /* It is an unsupported data type */
+ EXCEPTION(EX_Invalid);
+ if ( !(control_word & CW_Invalid) )
+ return 0;
+ templ = 0xffc00000;
+ }
+ }
+#ifdef PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x164);
+ return 0;
+ }
+#endif
}
- else if ( st0_tag == TW_Empty )
+ else if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
@@ -830,7 +827,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
- put_user(0xffc00000, (unsigned long *) single);
+ FPU_put_user(0xffc00000, (unsigned long *) single);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -844,12 +841,12 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
return 0;
}
#endif
- if (st0_ptr->sign)
+ if ( getsign(st0_ptr) )
templ |= 0x80000000;
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
- put_user(templ,(unsigned long *) single);
+ FPU_put_user(templ,(unsigned long *) single);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -857,34 +854,37 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
/* Put a long long into user memory */
-int reg_store_int64(long long *d, FPU_REG *st0_ptr)
+int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d)
{
FPU_REG t;
long long tll;
int precision_loss;
- char st0_tag = st0_ptr->tag;
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
goto invalid_operand;
}
- else if ( (st0_tag == TW_Infinity) ||
- (st0_tag == TW_NaN) )
+ else if ( st0_tag == TAG_Special )
{
- EXCEPTION(EX_Invalid);
- goto invalid_operand;
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
}
- reg_move(st0_ptr, &t);
- precision_loss = round_to_int(&t);
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
((long *)&tll)[0] = t.sigl;
((long *)&tll)[1] = t.sigh;
if ( (precision_loss == 1) ||
((t.sigh & 0x80000000) &&
!((t.sigh == 0x80000000) && (t.sigl == 0) &&
- (t.sign == SIGN_NEG))) )
+ signnegative(&t))) )
{
EXCEPTION(EX_Invalid);
/* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -901,7 +901,7 @@ int reg_store_int64(long long *d, FPU_REG *st0_ptr)
{
if ( precision_loss )
set_precision_flag(precision_loss);
- if ( t.sign )
+ if ( signnegative(&t) )
tll = - tll;
}
@@ -915,30 +915,33 @@ int reg_store_int64(long long *d, FPU_REG *st0_ptr)
/* Put a long into user memory */
-int reg_store_int32(long *d, FPU_REG *st0_ptr)
+int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d)
{
FPU_REG t;
int precision_loss;
- char st0_tag = st0_ptr->tag;
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
goto invalid_operand;
}
- else if ( (st0_tag == TW_Infinity) ||
- (st0_tag == TW_NaN) )
+ else if ( st0_tag == TAG_Special )
{
- EXCEPTION(EX_Invalid);
- goto invalid_operand;
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
}
- reg_move(st0_ptr, &t);
- precision_loss = round_to_int(&t);
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
if (t.sigh ||
((t.sigl & 0x80000000) &&
- !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
+ !((t.sigl == 0x80000000) && signnegative(&t))) )
{
EXCEPTION(EX_Invalid);
/* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -955,13 +958,13 @@ int reg_store_int32(long *d, FPU_REG *st0_ptr)
{
if ( precision_loss )
set_precision_flag(precision_loss);
- if ( t.sign )
+ if ( signnegative(&t) )
t.sigl = -(long)t.sigl;
}
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,4);
- put_user(t.sigl, (unsigned long *) d);
+ FPU_put_user(t.sigl, (unsigned long *) d);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -969,30 +972,33 @@ int reg_store_int32(long *d, FPU_REG *st0_ptr)
/* Put a short into user memory */
-int reg_store_int16(short *d, FPU_REG *st0_ptr)
+int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d)
{
FPU_REG t;
int precision_loss;
- char st0_tag = st0_ptr->tag;
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
goto invalid_operand;
}
- else if ( (st0_tag == TW_Infinity) ||
- (st0_tag == TW_NaN) )
+ else if ( st0_tag == TAG_Special )
{
- EXCEPTION(EX_Invalid);
- goto invalid_operand;
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
}
- reg_move(st0_ptr, &t);
- precision_loss = round_to_int(&t);
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
if (t.sigh ||
((t.sigl & 0xffff8000) &&
- !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
+ !((t.sigl == 0x8000) && signnegative(&t))) )
{
EXCEPTION(EX_Invalid);
/* This is a special case: see sec 16.2.5.1 of the 80486 book */
@@ -1009,13 +1015,13 @@ int reg_store_int16(short *d, FPU_REG *st0_ptr)
{
if ( precision_loss )
set_precision_flag(precision_loss);
- if ( t.sign )
+ if ( signnegative(&t) )
t.sigl = -t.sigl;
}
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,2);
- put_user((short)t.sigl,(short *) d);
+ FPU_put_user((short)t.sigl,(short *) d);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -1023,24 +1029,33 @@ int reg_store_int16(short *d, FPU_REG *st0_ptr)
/* Put a packed bcd array into user memory */
-int reg_store_bcd(char *d, FPU_REG *st0_ptr)
+int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d)
{
FPU_REG t;
unsigned long long ll;
- unsigned char b;
+ u_char b;
int i, precision_loss;
- unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
- char st0_tag = st0_ptr->tag;
+ u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
- if ( st0_tag == TW_Empty )
+ if ( st0_tag == TAG_Empty )
{
/* Empty register (stack underflow) */
EXCEPTION(EX_StackUnder);
goto invalid_operand;
}
+ else if ( st0_tag == TAG_Special )
+ {
+ st0_tag = FPU_Special(st0_ptr);
+ if ( (st0_tag == TW_Infinity) ||
+ (st0_tag == TW_NaN) )
+ {
+ EXCEPTION(EX_Invalid);
+ goto invalid_operand;
+ }
+ }
- reg_move(st0_ptr, &t);
- precision_loss = round_to_int(&t);
+ reg_copy(st0_ptr, &t);
+ precision_loss = FPU_round_to_int(&t, st0_tag);
ll = significand(&t);
/* Check for overflow, by comparing with 999999999999999999 decimal. */
@@ -1056,10 +1071,10 @@ int reg_store_bcd(char *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
for ( i = 0; i < 7; i++)
- put_user(0, (unsigned char *) d+i); /* These bytes "undefined" */
- put_user(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
- put_user(0xff, (unsigned char *) d+8);
- put_user(0xff, (unsigned char *) d+9);
+ FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */
+ FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */
+ FPU_put_user(0xff, (u_char *) d+8);
+ FPU_put_user(0xff, (u_char *) d+9);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -1077,14 +1092,14 @@ int reg_store_bcd(char *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 9; i++)
{
- b = div_small(&ll, 10);
- b |= (div_small(&ll, 10)) << 4;
+ b = FPU_div_small(&ll, 10);
+ b |= (FPU_div_small(&ll, 10)) << 4;
RE_ENTRANT_CHECK_OFF;
- put_user(b,(unsigned char *) d+i);
+ FPU_put_user(b,(u_char *) d+i);
RE_ENTRANT_CHECK_ON;
}
RE_ENTRANT_CHECK_OFF;
- put_user(sign,(unsigned char *) d+9);
+ FPU_put_user(sign,(u_char *) d+9);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -1100,25 +1115,25 @@ int reg_store_bcd(char *d, FPU_REG *st0_ptr)
/* Overflow is signalled by a non-zero return value (in eax).
In the case of overflow, the returned significand always has the
largest possible value */
-int round_to_int(FPU_REG *r)
+int FPU_round_to_int(FPU_REG *r, u_char tag)
{
- char very_big;
+ u_char very_big;
unsigned eax;
- if (r->tag == TW_Zero)
+ if (tag == TAG_Zero)
{
/* Make sure that zero is returned */
significand(r) = 0;
return 0; /* o.k. */
}
-
- if (r->exp > EXP_BIAS + 63)
+
+ if (exponent(r) > 63)
{
r->sigl = r->sigh = ~0; /* The largest representable number */
return 1; /* overflow */
}
- eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+ eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
#define half_or_more (eax & 0x80000000)
#define frac_part (eax)
@@ -1135,7 +1150,7 @@ int round_to_int(FPU_REG *r)
}
break;
case RC_DOWN:
- if (frac_part && r->sign)
+ if (frac_part && getsign(r))
{
if ( very_big ) return 1; /* overflow */
significand(r) ++;
@@ -1143,7 +1158,7 @@ int round_to_int(FPU_REG *r)
}
break;
case RC_UP:
- if (frac_part && !r->sign)
+ if (frac_part && !getsign(r))
{
if ( very_big ) return 1; /* overflow */
significand(r) ++;
@@ -1160,10 +1175,10 @@ int round_to_int(FPU_REG *r)
/*===========================================================================*/
-char *fldenv(fpu_addr_modes addr_modes, char *s)
+u_char *fldenv(fpu_addr_modes addr_modes, u_char *s)
{
unsigned short tag_word = 0;
- unsigned char tag;
+ u_char tag;
int i;
if ( (addr_modes.default_mode == VM86) ||
@@ -1172,13 +1187,13 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x0e);
- get_user(control_word, (unsigned short *) s);
- get_user(partial_status, (unsigned short *) (s+2));
- get_user(tag_word, (unsigned short *) (s+4));
- get_user(instruction_address.offset, (unsigned short *) (s+6));
- get_user(instruction_address.selector, (unsigned short *) (s+8));
- get_user(operand_address.offset, (unsigned short *) (s+0x0a));
- get_user(operand_address.selector, (unsigned short *) (s+0x0c));
+ FPU_get_user(control_word, (unsigned short *) s);
+ FPU_get_user(partial_status, (unsigned short *) (s+2));
+ FPU_get_user(tag_word, (unsigned short *) (s+4));
+ FPU_get_user(instruction_address.offset, (unsigned short *) (s+6));
+ FPU_get_user(instruction_address.selector, (unsigned short *) (s+8));
+ FPU_get_user(operand_address.offset, (unsigned short *) (s+0x0a));
+ FPU_get_user(operand_address.selector, (unsigned short *) (s+0x0c));
RE_ENTRANT_CHECK_ON;
s += 0x0e;
if ( addr_modes.default_mode == VM86 )
@@ -1192,14 +1207,14 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x1c);
- get_user(control_word, (unsigned short *) s);
- get_user(partial_status, (unsigned short *) (s+4));
- get_user(tag_word, (unsigned short *) (s+8));
- get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
- get_user(instruction_address.selector, (unsigned short *) (s+0x10));
- get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
- get_user(operand_address.offset, (unsigned long *) (s+0x14));
- get_user(operand_address.selector, (unsigned long *) (s+0x18));
+ FPU_get_user(control_word, (unsigned short *) s);
+ FPU_get_user(partial_status, (unsigned short *) (s+4));
+ FPU_get_user(tag_word, (unsigned short *) (s+8));
+ FPU_get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
+ FPU_get_user(instruction_address.selector, (unsigned short *) (s+0x10));
+ FPU_get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
+ FPU_get_user(operand_address.offset, (unsigned long *) (s+0x14));
+ FPU_get_user(operand_address.selector, (unsigned long *) (s+0x18));
RE_ENTRANT_CHECK_ON;
s += 0x1c;
}
@@ -1220,29 +1235,28 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
tag = tag_word & 3;
tag_word >>= 2;
- if ( tag == 3 )
+ if ( tag == TAG_Empty )
/* New tag is empty. Accept it */
- regs[i].tag = TW_Empty;
- else if ( regs[i].tag == TW_Empty )
+ FPU_settag(i, TAG_Empty);
+ else if ( FPU_gettag(i) == TAG_Empty )
{
/* Old tag is empty and new tag is not empty. New tag is determined
by old reg contents */
- if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias )
+ if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
{
- if ( !(regs[i].sigl | regs[i].sigh) )
- regs[i].tag = TW_Zero;
+ if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
+ FPU_settag(i, TAG_Zero);
else
- regs[i].tag = TW_Valid;
+ FPU_settag(i, TAG_Special);
}
- else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias )
+ else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
{
- if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) )
- regs[i].tag = TW_Infinity;
- else
- regs[i].tag = TW_NaN;
+ FPU_settag(i, TAG_Special);
}
+ else if ( fpu_register(i).sigh & 0x80000000 )
+ FPU_settag(i, TAG_Valid);
else
- regs[i].tag = TW_Valid;
+ FPU_settag(i, TAG_Special); /* An Un-normal */
}
/* Else old tag is not empty and new tag is not empty. Old tag
remains correct */
@@ -1252,56 +1266,32 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
}
-void frstor(fpu_addr_modes addr_modes, char *data_address)
+void frstor(fpu_addr_modes addr_modes, u_char *data_address)
{
- int i, stnr;
- unsigned char tag;
- char *s = fldenv(addr_modes, data_address);
+ int i, regnr;
+ u_char *s = fldenv(addr_modes, data_address);
+ int offset = (top & 7) * 10, other = 80 - offset;
+
+ /* Copy all registers in stack order. */
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ,s,80);
+ __copy_from_user(register_base+offset, s, other);
+ if ( offset )
+ __copy_from_user(register_base, s+other, offset);
+ RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 8; i++ )
{
- /* Load each register. */
- stnr = (i+top) & 7;
- tag = regs[stnr].tag; /* Derived from the fldenv() loaded tag word. */
- reg_load_extended((long double *)(s+i*10), &regs[stnr]);
- if ( tag == TW_Empty ) /* The loaded data over-rides all other cases. */
- regs[stnr].tag = tag;
+ regnr = (i+top) & 7;
+ if ( FPU_gettag(regnr) != TAG_Empty )
+ /* The loaded data over-rides all other cases. */
+ FPU_settag(regnr, FPU_tagof(&st(i)));
}
}
-unsigned short tag_word(void)
-{
- unsigned short word = 0;
- unsigned char tag;
- int i;
-
- for ( i = 7; i >= 0; i-- )
- {
- switch ( tag = regs[i].tag )
- {
- case TW_Valid:
- if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) )
- tag = 2;
- break;
- case TW_Infinity:
- case TW_NaN:
- tag = 2;
- break;
- case TW_Empty:
- tag = 3;
- break;
- /* TW_Zero already has the correct value */
- }
- word <<= 2;
- word |= tag;
- }
- return word;
-}
-
-
-char *fstenv(fpu_addr_modes addr_modes, char *d)
+u_char *fstenv(fpu_addr_modes addr_modes, u_char *d)
{
if ( (addr_modes.default_mode == VM86) ||
((addr_modes.default_mode == PM16)
@@ -1310,25 +1300,25 @@ char *fstenv(fpu_addr_modes addr_modes, char *d)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,14);
#ifdef PECULIAR_486
- put_user(control_word & ~0xe080, (unsigned long *) d);
+ FPU_put_user(control_word & ~0xe080, (unsigned long *) d);
#else
- put_user(control_word, (unsigned short *) d);
+ FPU_put_user(control_word, (unsigned short *) d);
#endif PECULIAR_486
- put_user(status_word(), (unsigned short *) (d+2));
- put_user(tag_word(), (unsigned short *) (d+4));
- put_user(instruction_address.offset, (unsigned short *) (d+6));
- put_user(operand_address.offset, (unsigned short *) (d+0x0a));
+ FPU_put_user(status_word(), (unsigned short *) (d+2));
+ FPU_put_user(fpu_tag_word, (unsigned short *) (d+4));
+ FPU_put_user(instruction_address.offset, (unsigned short *) (d+6));
+ FPU_put_user(operand_address.offset, (unsigned short *) (d+0x0a));
if ( addr_modes.default_mode == VM86 )
{
- put_user((instruction_address.offset & 0xf0000) >> 4,
+ FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
(unsigned short *) (d+8));
- put_user((operand_address.offset & 0xf0000) >> 4,
+ FPU_put_user((operand_address.offset & 0xf0000) >> 4,
(unsigned short *) (d+0x0c));
}
else
{
- put_user(instruction_address.selector, (unsigned short *) (d+8));
- put_user(operand_address.selector, (unsigned short *) (d+0x0c));
+ FPU_put_user(instruction_address.selector, (unsigned short *) (d+8));
+ FPU_put_user(operand_address.selector, (unsigned short *) (d+0x0c));
}
RE_ENTRANT_CHECK_ON;
d += 0x0e;
@@ -1336,28 +1326,17 @@ char *fstenv(fpu_addr_modes addr_modes, char *d)
else
{
RE_ENTRANT_CHECK_OFF;
- FPU_verify_area(VERIFY_WRITE,d,28);
+ FPU_verify_area(VERIFY_WRITE, d, 7*4);
#ifdef PECULIAR_486
+ control_word &= ~0xe080;
/* An 80486 sets all the reserved bits to 1. */
- put_user(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
- put_user(0xffff0000 | status_word(), (unsigned long *) (d+4));
- put_user(0xffff0000 | tag_word(), (unsigned long *) (d+8));
-#else
- put_user(control_word, (unsigned short *) d);
- put_user(status_word(), (unsigned short *) (d+4));
- put_user(tag_word(), (unsigned short *) (d+8));
-#endif PECULIAR_486
- put_user(instruction_address.offset, (unsigned long *) (d+0x0c));
- put_user(instruction_address.selector, (unsigned short *) (d+0x10));
- put_user(instruction_address.opcode, (unsigned short *) (d+0x12));
- put_user(operand_address.offset, (unsigned long *) (d+0x14));
-#ifdef PECULIAR_486
- /* An 80486 sets all the reserved bits to 1. */
- put_user(operand_address.selector, (unsigned short *) (d+0x18));
- put_user(0xffff, (unsigned short *) (d+0x1a));
-#else
- put_user(operand_address.selector, (unsigned long *) (d+0x18));
+ control_word |= 0xffff0000;
+ partial_status = status_word() | 0xffff0000;
+ fpu_tag_word |= 0xffff0000;
+ I387.soft.fcs |= 0xf8000000;
+ I387.soft.fos |= 0xffff0000;
#endif PECULIAR_486
+ __copy_to_user(d, &control_word, 7*4);
RE_ENTRANT_CHECK_ON;
d += 0x1c;
}
@@ -1369,84 +1348,23 @@ char *fstenv(fpu_addr_modes addr_modes, char *d)
}
-void fsave(fpu_addr_modes addr_modes, char *data_address)
+void fsave(fpu_addr_modes addr_modes, u_char *data_address)
{
- char *d;
- int i;
+ u_char *d;
+ int offset = (top & 7) * 10, other = 80 - offset;
d = fstenv(addr_modes, data_address);
+
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,80);
+
+ /* Copy all registers in stack order. */
+ __copy_to_user(d, register_base+offset, other);
+ if ( offset )
+ __copy_to_user(d+other, register_base, offset);
RE_ENTRANT_CHECK_ON;
- for ( i = 0; i < 8; i++ )
- write_to_extended(&regs[(top + i) & 7], d + 10 * i);
finit();
-
}
/*===========================================================================*/
-
-/*
- A call to this function must be preceded by a call to
- FPU_verify_area() to verify access to the 10 bytes at d
- */
-static void write_to_extended(FPU_REG *rp, char *d)
-{
- long e;
- FPU_REG tmp;
-
- e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
-
-#ifdef PARANOID
- switch ( rp->tag )
- {
- case TW_Zero:
- if ( rp->sigh | rp->sigl | e )
- EXCEPTION(EX_INTERNAL | 0x160);
- break;
- case TW_Infinity:
- case TW_NaN:
- if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) )
- EXCEPTION(EX_INTERNAL | 0x161);
- break;
- default:
- if (e > 0x7fff || e < -63)
- EXCEPTION(EX_INTERNAL | 0x162);
- }
-#endif PARANOID
-
- /*
- All numbers except denormals are stored internally in a
- format which is compatible with the extended real number
- format.
- */
- if ( e > 0 )
- {
- /* just copy the reg */
- RE_ENTRANT_CHECK_OFF;
- put_user(rp->sigl, (unsigned long *) d);
- put_user(rp->sigh, (unsigned long *) (d + 4));
- RE_ENTRANT_CHECK_ON;
- }
- else
- {
- /*
- The number is a de-normal stored as a normal using our
- extra exponent range, or is Zero.
- Convert it back to a de-normal, or leave it as Zero.
- */
- reg_move(rp, &tmp);
- tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 63 */
- round_to_int(&tmp);
- e = 0;
- RE_ENTRANT_CHECK_OFF;
- put_user(tmp.sigl, (unsigned long *) d);
- put_user(tmp.sigh, (unsigned long *) (d + 4));
- RE_ENTRANT_CHECK_ON;
- }
- e |= rp->sign == SIGN_POS ? 0 : 0x8000;
- RE_ENTRANT_CHECK_OFF;
- put_user(e, (unsigned short *) (d + 8));
- RE_ENTRANT_CHECK_ON;
-}
diff --git a/arch/i386/math-emu/reg_mul.c b/arch/i386/math-emu/reg_mul.c
index 75246187b..1ea92d48e 100644
--- a/arch/i386/math-emu/reg_mul.c
+++ b/arch/i386/math-emu/reg_mul.c
@@ -3,10 +3,11 @@
| |
| Multiply one FPU_REG by another, put the result in a destination FPU_REG. |
| |
- | Copyright (C) 1992,1993 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
+ | Returns the tag of the result if no exceptions or errors occured. |
| |
+---------------------------------------------------------------------------*/
@@ -14,92 +15,117 @@
| The destination may be any FPU_REG, including one of the source FPU_REGs. |
+---------------------------------------------------------------------------*/
+#include "fpu_emu.h"
#include "exception.h"
#include "reg_constant.h"
-#include "fpu_emu.h"
#include "fpu_system.h"
+/*
+ Multiply two registers to give a register result.
+ The sources are st(deststnr) and (b,tagb,signb).
+ The destination is st(deststnr).
+ */
/* This routine must be called with non-empty source registers */
-int reg_mul(FPU_REG const *a, FPU_REG const *b,
- FPU_REG *dest, unsigned int control_w)
+int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
{
- char saved_sign = dest->sign;
- char sign = (a->sign ^ b->sign);
+ FPU_REG *a = &st(deststnr);
+ FPU_REG *dest = a;
+ u_char taga = FPU_gettagi(deststnr);
+ u_char saved_sign = getsign(dest);
+ u_char sign = (getsign(a) ^ getsign(b));
+ int tag;
+
- if (!(a->tag | b->tag))
+ if ( !(taga | tagb) )
{
/* Both regs Valid, this should be the most common case. */
- dest->sign = sign;
- if ( reg_u_mul(a, b, dest, control_w) )
+
+ tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b));
+ if ( tag < 0 )
{
- dest->sign = saved_sign;
- return 1;
+ setsign(dest, saved_sign);
+ return tag;
}
- return 0;
+ FPU_settagi(deststnr, tag);
+ return tag;
}
- else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
+
+ if ( taga == TAG_Special )
+ taga = FPU_Special(a);
+ if ( tagb == TAG_Special )
+ tagb = FPU_Special(b);
+
+ if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
+ || ((taga == TW_Denormal) && (tagb == TAG_Valid))
+ || ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
{
-#ifdef DENORM_OPERAND
- if ( ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
- ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER)) )
+ FPU_REG x, y;
+ if ( denormal_operand() < 0 )
+ return FPU_Exception;
+
+ FPU_to_exp16(a, &x);
+ FPU_to_exp16(b, &y);
+ tag = FPU_u_mul(&x, &y, dest, control_w, sign,
+ exponent16(&x) + exponent16(&y));
+ if ( tag < 0 )
{
- if ( denormal_operand() ) return 1;
+ setsign(dest, saved_sign);
+ return tag;
}
-#endif DENORM_OPERAND
+ FPU_settagi(deststnr, tag);
+ return tag;
+ }
+ else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
+ {
+ if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
+ && (denormal_operand() < 0) )
+ return FPU_Exception;
+
/* Must have either both arguments == zero, or
one valid and the other zero.
The result is therefore zero. */
- reg_move(&CONST_Z, dest);
+ FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
/* The 80486 book says that the answer is +0, but a real
80486 behaves this way.
IEEE-754 apparently says it should be this way. */
- dest->sign = sign;
- return 0;
+ setsign(dest, sign);
+ return TAG_Zero;
}
- else
- {
/* Must have infinities, NaNs, etc */
- if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
- { return real_2op_NaN(a, b, dest); }
- else if (a->tag == TW_Infinity)
- {
- if (b->tag == TW_Zero)
- { return arith_invalid(dest); } /* Zero*Infinity is invalid */
- else
- {
-#ifdef DENORM_OPERAND
- if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(a, dest);
- dest->sign = sign;
- }
- return 0;
- }
- else if (b->tag == TW_Infinity)
- {
- if (a->tag == TW_Zero)
- { return arith_invalid(dest); } /* Zero*Infinity is invalid */
- else
- {
-#ifdef DENORM_OPERAND
- if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
- denormal_operand() )
- return 1;
-#endif DENORM_OPERAND
- reg_move(b, dest);
- dest->sign = sign;
- }
- return 0;
- }
+ else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
+ {
+ return real_2op_NaN(b, tagb, deststnr, &st(0));
+ }
+ else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
+ || ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
+ {
+ return arith_invalid(deststnr); /* Zero*Infinity is invalid */
+ }
+ else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
+ && (denormal_operand() < 0) )
+ {
+ return FPU_Exception;
+ }
+ else if (taga == TW_Infinity)
+ {
+ FPU_copy_to_regi(a, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return TAG_Special;
+ }
+ else if (tagb == TW_Infinity)
+ {
+ FPU_copy_to_regi(b, TAG_Special, deststnr);
+ setsign(dest, sign);
+ return TAG_Special;
+ }
+
#ifdef PARANOID
- else
- {
- EXCEPTION(EX_INTERNAL|0x102);
- return 1;
- }
-#endif PARANOID
+ else
+ {
+ EXCEPTION(EX_INTERNAL|0x102);
+ return FPU_Exception;
}
+#endif PARANOID
+
}
diff --git a/arch/i386/math-emu/reg_norm.S b/arch/i386/math-emu/reg_norm.S
index 781a2d466..f63a87755 100644
--- a/arch/i386/math-emu/reg_norm.S
+++ b/arch/i386/math-emu/reg_norm.S
@@ -1,16 +1,19 @@
/*---------------------------------------------------------------------------+
| reg_norm.S |
| |
- | Copyright (C) 1992,1993,1994,1995 |
+ | Copyright (C) 1992,1993,1994,1995,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| Normalize the value in a FPU_REG. |
| |
| Call from C as: |
- | void normalize(FPU_REG *n) |
+ | int FPU_normalize(FPU_REG *n) |
| |
- | void normalize_nuo(FPU_REG *n) |
+ | int FPU_normalize_nuo(FPU_REG *n) |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
| |
+---------------------------------------------------------------------------*/
@@ -18,24 +21,13 @@
.text
-ENTRY(normalize)
+ENTRY(FPU_normalize)
pushl %ebp
movl %esp,%ebp
pushl %ebx
movl PARAM1,%ebx
-#ifdef PARANOID
- cmpb TW_Valid,TAG(%ebx)
- je L_ok
-
- pushl $0x220
- call SYMBOL_NAME(FPU_exception)
- addl $4,%esp
-
-L_ok:
-#endif PARANOID
-
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
@@ -48,7 +40,7 @@ L_ok:
movl %eax,%edx
xorl %eax,%eax
- subl $32,EXP(%ebx) /* This can cause an underflow */
+ subw $32,EXP(%ebx) /* This can cause an underflow */
/* We need to shift left by 1 - 31 bits */
L_shift_1:
@@ -57,18 +49,25 @@ L_shift_1:
negl %ecx
shld %cl,%eax,%edx
shl %cl,%eax
- subl %ecx,EXP(%ebx) /* This can cause an underflow */
+ subw %cx,EXP(%ebx) /* This can cause an underflow */
movl %edx,SIGH(%ebx)
movl %eax,SIGL(%ebx)
L_done:
- cmpl EXP_OVER,EXP(%ebx)
+ cmpw EXP_OVER,EXP(%ebx)
jge L_overflow
- cmpl EXP_UNDER,EXP(%ebx)
+ cmpw EXP_UNDER,EXP(%ebx)
jle L_underflow
+L_exit_valid:
+ movl TAG_Valid,%eax
+
+ /* Convert the exponent to 80x87 form. */
+ addw EXTENDED_Ebias,EXP(%ebx)
+ andw $0x7fff,EXP(%ebx)
+
L_exit:
popl %ebx
leave
@@ -76,17 +75,21 @@ L_exit:
L_zero:
- movl EXP_UNDER,EXP(%ebx)
- movb TW_Zero,TAG(%ebx)
+ movw $0,EXP(%ebx)
+ movl TAG_Zero,%eax
jmp L_exit
L_underflow:
+ /* Convert the exponent to 80x87 form. */
+ addw EXTENDED_Ebias,EXP(%ebx)
push %ebx
call SYMBOL_NAME(arith_underflow)
pop %ebx
jmp L_exit
L_overflow:
+ /* Convert the exponent to 80x87 form. */
+ addw EXTENDED_Ebias,EXP(%ebx)
push %ebx
call SYMBOL_NAME(arith_overflow)
pop %ebx
@@ -95,37 +98,26 @@ L_overflow:
/* Normalise without reporting underflow or overflow */
-ENTRY(normalize_nuo)
+ENTRY(FPU_normalize_nuo)
pushl %ebp
movl %esp,%ebp
pushl %ebx
movl PARAM1,%ebx
-#ifdef PARANOID
- cmpb TW_Valid,TAG(%ebx)
- je L_ok_nuo
-
- pushl $0x221
- call SYMBOL_NAME(FPU_exception)
- addl $4,%esp
-
-L_ok_nuo:
-#endif PARANOID
-
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
orl %edx,%edx /* ms bits */
- js L_exit /* Already normalized */
+ js L_exit_nuo_valid /* Already normalized */
jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
orl %eax,%eax
- jz L_zero /* The contents are zero */
+ jz L_exit_nuo_zero /* The contents are zero */
movl %eax,%edx
xorl %eax,%eax
- subl $32,EXP(%ebx) /* This can cause an underflow */
+ subw $32,EXP(%ebx) /* This can cause an underflow */
/* We need to shift left by 1 - 31 bits */
L_nuo_shift_1:
@@ -134,10 +126,22 @@ L_nuo_shift_1:
negl %ecx
shld %cl,%eax,%edx
shl %cl,%eax
- subl %ecx,EXP(%ebx) /* This can cause an underflow */
+ subw %cx,EXP(%ebx) /* This can cause an underflow */
movl %edx,SIGH(%ebx)
movl %eax,SIGL(%ebx)
- jmp L_exit
+L_exit_nuo_valid:
+ movl TAG_Valid,%eax
+
+ popl %ebx
+ leave
+ ret
+L_exit_nuo_zero:
+ movl TAG_Zero,%eax
+ movw EXP_UNDER,EXP(%ebx)
+
+ popl %ebx
+ leave
+ ret
diff --git a/arch/i386/math-emu/reg_round.S b/arch/i386/math-emu/reg_round.S
index 4aac507a1..9ab32e999 100644
--- a/arch/i386/math-emu/reg_round.S
+++ b/arch/i386/math-emu/reg_round.S
@@ -4,17 +4,20 @@
| |
| Rounding/truncation/etc for FPU basic arithmetic functions. |
| |
- | Copyright (C) 1993,1995 |
+ | Copyright (C) 1993,1995,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| This code has four possible entry points. |
| The following must be entered by a jmp instruction: |
| fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. |
| |
- | The _round_reg entry point is intended to be used by C code. |
+ | The FPU_round entry point is intended to be used by C code. |
| From C, call as: |
- | void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
+ | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
| |
| For correct "up" and "down" rounding, the argument must have the correct |
| sign. |
@@ -106,7 +109,7 @@ FPU_denormal:
.globl fpu_Arith_exit
/* Entry point when called from C */
-ENTRY(round_reg)
+ENTRY(FPU_round)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -117,14 +120,10 @@ ENTRY(round_reg)
movl SIGH(%edi),%eax
movl SIGL(%edi),%ebx
movl PARAM2,%edx
- movl PARAM3,%ecx
- jmp fpu_reg_round_sqrt
fpu_reg_round: /* Normal entry point */
movl PARAM4,%ecx
-fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */
-
#ifndef NON_REENTRANT_FPU
pushl %ebx /* adjust the stack pointer */
#endif NON_REENTRANT_FPU
@@ -135,12 +134,12 @@ fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */
/* jns L_entry_bugged */
#endif PARANOID
- cmpl EXP_UNDER,EXP(%edi)
- jle xMake_denorm /* The number is a de-normal */
+ cmpw EXP_UNDER,EXP(%edi)
+ jle L_Make_denorm /* The number is a de-normal */
movb $0,FPU_denormal /* 0 -> not a de-normal */
-xDenorm_done:
+Denorm_done:
movb $0,FPU_bits_lost /* No bits yet lost in rounding */
movl %ecx,%esi
@@ -190,13 +189,13 @@ LRound_To_24:
#endif PARANOID
LUp_24:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
jne LCheck_truncate_24 /* If negative then up==truncate */
jmp LCheck_24_round_up
LDown_24:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
je LCheck_truncate_24 /* If positive then down==truncate */
LCheck_24_round_up:
@@ -205,7 +204,7 @@ LCheck_24_round_up:
orl %ebx,%ecx
orl %edx,%ecx
jnz LDo_24_round_up
- jmp LRe_normalise
+ jmp L_Re_normalise
LRound_nearest_24:
/* Do rounding of the 24th bit if needed (nearest or even) */
@@ -240,13 +239,13 @@ LCheck_truncate_24:
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
- jz LRe_normalise /* No truncation needed */
+ jz L_Re_normalise /* No truncation needed */
LDo_truncate_24:
andl $0xffffff00,%eax /* Truncate to 24 bits */
xorl %ebx,%ebx
movb LOST_DOWN,FPU_bits_lost
- jmp LRe_normalise
+ jmp L_Re_normalise
/* Round etc to 53 bit precision */
@@ -270,13 +269,13 @@ LRound_To_53:
#endif PARANOID
LUp_53:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
jne LCheck_truncate_53 /* If negative then up==truncate */
jmp LCheck_53_round_up
LDown_53:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
je LCheck_truncate_53 /* If positive then down==truncate */
LCheck_53_round_up:
@@ -284,7 +283,7 @@ LCheck_53_round_up:
andl $0x000007ff,%ecx
orl %edx,%ecx
jnz LDo_53_round_up
- jmp LRe_normalise
+ jmp L_Re_normalise
LRound_nearest_53:
/* Do rounding of the 53rd bit if needed (nearest or even) */
@@ -315,12 +314,12 @@ LCheck_truncate_53:
movl %ebx,%ecx
andl $0x000007ff,%ecx
orl %edx,%ecx
- jz LRe_normalise
+ jz L_Re_normalise
LTruncate_53:
movb LOST_DOWN,FPU_bits_lost
andl $0xfffff800,%ebx /* Truncate to 53 bits */
- jmp LRe_normalise
+ jmp L_Re_normalise
/* Round etc to 64 bit precision */
@@ -344,20 +343,20 @@ LRound_To_64:
#endif PARANOID
LUp_64:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
jne LCheck_truncate_64 /* If negative then up==truncate */
orl %edx,%edx
jnz LDo_64_round_up
- jmp LRe_normalise
+ jmp L_Re_normalise
LDown_64:
- cmpb SIGN_POS,SIGN(%edi)
+ cmpb SIGN_POS,PARAM5
je LCheck_truncate_64 /* If positive then down==truncate */
orl %edx,%edx
jnz LDo_64_round_up
- jmp LRe_normalise
+ jmp L_Re_normalise
LRound_nearest_64:
cmpl $0x80000000,%edx
@@ -375,46 +374,60 @@ LDo_64_round_up:
adcl $0,%eax
LCheck_Round_Overflow:
- jnc LRe_normalise
+ jnc L_Re_normalise
/* Overflow, adjust the result (significand to 1.0) */
rcrl $1,%eax
rcrl $1,%ebx
- incl EXP(%edi)
- jmp LRe_normalise
+ incw EXP(%edi)
+ jmp L_Re_normalise
LCheck_truncate_64:
orl %edx,%edx
- jz LRe_normalise
+ jz L_Re_normalise
LTruncate_64:
movb LOST_DOWN,FPU_bits_lost
-LRe_normalise:
+L_Re_normalise:
testb $0xff,FPU_denormal
- jnz xNormalise_result
+ jnz Normalise_result
+
+L_Normalised:
+ movl TAG_Valid,%edx
-xL_Normalised:
+L_deNormalised:
cmpb LOST_UP,FPU_bits_lost
- je xL_precision_lost_up
+ je L_precision_lost_up
cmpb LOST_DOWN,FPU_bits_lost
- je xL_precision_lost_down
+ je L_precision_lost_down
-xL_no_precision_loss:
+L_no_precision_loss:
/* store the result */
- movb TW_Valid,TAG(%edi)
-xL_Store_significand:
+L_Store_significand:
movl %eax,SIGH(%edi)
movl %ebx,SIGL(%edi)
- xorl %eax,%eax /* No errors detected. */
-
- cmpl EXP_OVER,EXP(%edi)
+ cmpw EXP_OVER,EXP(%edi)
jge L_overflow
-fpu_reg_round_exit:
+ movl %edx,%eax
+
+ /* Convert the exponent to 80x87 form. */
+ addw EXTENDED_Ebias,EXP(%edi)
+ andw $0x7fff,EXP(%edi)
+
+fpu_reg_round_signed_special_exit:
+
+ cmpb SIGN_POS,PARAM5
+ je fpu_reg_round_special_exit
+
+ orw $0x8000,EXP(%edi) /* Negative sign for the result. */
+
+fpu_reg_round_special_exit:
+
#ifndef NON_REENTRANT_FPU
popl %ebx /* adjust the stack pointer */
#endif NON_REENTRANT_FPU
@@ -431,21 +444,25 @@ fpu_Arith_exit:
* Set the FPU status flags to represent precision loss due to
* round-up.
*/
-xL_precision_lost_up:
+L_precision_lost_up:
+ push %edx
push %eax
call SYMBOL_NAME(set_precision_flag_up)
popl %eax
- jmp xL_no_precision_loss
+ popl %edx
+ jmp L_no_precision_loss
/*
* Set the FPU status flags to represent precision loss due to
* truncation.
*/
-xL_precision_lost_down:
+L_precision_lost_down:
+ push %edx
push %eax
call SYMBOL_NAME(set_precision_flag_down)
popl %eax
- jmp xL_no_precision_loss
+ popl %edx
+ jmp L_no_precision_loss
/*
@@ -453,30 +470,30 @@ xL_precision_lost_down:
* Shift the number right the required number of bits, which will
* have to be undone later...
*/
-xMake_denorm:
+L_Make_denorm:
/* The action to be taken depends upon whether the underflow
exception is masked */
testb CW_Underflow,%cl /* Underflow mask. */
- jz xUnmasked_underflow /* Do not make a denormal. */
+ jz Unmasked_underflow /* Do not make a denormal. */
movb DENORMAL,FPU_denormal
pushl %ecx /* Save */
- movl EXP_UNDER+1,%ecx
- subl EXP(%edi),%ecx
+ movw EXP_UNDER+1,%cx
+ subw EXP(%edi),%cx
- cmpl $64,%ecx /* shrd only works for 0..31 bits */
- jnc xDenorm_shift_more_than_63
+ cmpw $64,%cx /* shrd only works for 0..31 bits */
+ jnc Denorm_shift_more_than_63
- cmpl $32,%ecx /* shrd only works for 0..31 bits */
- jnc xDenorm_shift_more_than_32
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc Denorm_shift_more_than_32
/*
* We got here without jumps by assuming that the most common requirement
* is for a small de-normalising shift.
* Shift by [1..31] bits
*/
- addl %ecx,EXP(%edi)
+ addw %cx,EXP(%edi)
orl %edx,%edx /* extension */
setne %ch /* Save whether %edx is non-zero */
xorl %edx,%edx
@@ -485,11 +502,11 @@ xMake_denorm:
shr %cl,%eax
orb %ch,%dl
popl %ecx
- jmp xDenorm_done
+ jmp Denorm_done
/* Shift by [32..63] bits */
-xDenorm_shift_more_than_32:
- addl %ecx,EXP(%edi)
+Denorm_shift_more_than_32:
+ addw %cx,EXP(%edi)
subb $32,%cl
orl %edx,%edx
setne %ch
@@ -506,15 +523,15 @@ xDenorm_shift_more_than_32:
movl %eax,%ebx
xorl %eax,%eax
popl %ecx
- jmp xDenorm_done
+ jmp Denorm_done
/* Shift by [64..) bits */
-xDenorm_shift_more_than_63:
- cmpl $64,%ecx
- jne xDenorm_shift_more_than_64
+Denorm_shift_more_than_63:
+ cmpw $64,%cx
+ jne Denorm_shift_more_than_64
/* Exactly 64 bit shift */
- addl %ecx,EXP(%edi)
+ addw %cx,EXP(%edi)
xorl %ecx,%ecx
orl %edx,%edx
setne %cl
@@ -526,32 +543,32 @@ xDenorm_shift_more_than_63:
xorl %eax,%eax
xorl %ebx,%ebx
popl %ecx
- jmp xDenorm_done
+ jmp Denorm_done
-xDenorm_shift_more_than_64:
- movl EXP_UNDER+1,EXP(%edi)
+Denorm_shift_more_than_64:
+ movw EXP_UNDER+1,EXP(%edi)
/* This is easy, %eax must be non-zero, so.. */
movl $1,%edx
xorl %eax,%eax
xorl %ebx,%ebx
popl %ecx
- jmp xDenorm_done
+ jmp Denorm_done
-xUnmasked_underflow:
+Unmasked_underflow:
movb UNMASKED_UNDERFLOW,FPU_denormal
- jmp xDenorm_done
+ jmp Denorm_done
/* Undo the de-normalisation. */
-xNormalise_result:
+Normalise_result:
cmpb UNMASKED_UNDERFLOW,FPU_denormal
- je xSignal_underflow
+ je Signal_underflow
/* The number must be a denormal if we got here. */
#ifdef PARANOID
/* But check it... just in case. */
- cmpl EXP_UNDER+1,EXP(%edi)
+ cmpw EXP_UNDER+1,EXP(%edi)
jne L_norm_bugged
#endif PARANOID
@@ -565,41 +582,33 @@ xNormalise_result:
* Actual 80486 behaviour differs from this in some circumstances.
*/
orl %eax,%eax /* ms bits */
- js LNormalise_shift_done /* Will be masked underflow */
-#endif PECULIAR_486
-
+ js LPseudoDenormal /* Will be masked underflow */
+#else
orl %eax,%eax /* ms bits */
- js xL_Normalised /* No longer a denormal */
+ js L_Normalised /* No longer a denormal */
+#endif PECULIAR_486
- jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits */
+ jnz LDenormal_adj_exponent
orl %ebx,%ebx
jz L_underflow_to_zero /* The contents are zero */
-/* Shift left 32 - 63 bits */
- movl %ebx,%eax
- xorl %ebx,%ebx
- subl $32,EXP(%edi)
-
-LNormalise_shift_up_to_31:
- bsrl %eax,%ecx /* get the required shift in %ecx */
- subl $31,%ecx
- negl %ecx
- shld %cl,%ebx,%eax
- shl %cl,%ebx
- subl %ecx,EXP(%edi)
+LDenormal_adj_exponent:
+ decw EXP(%edi)
-LNormalise_shift_done:
+LPseudoDenormal:
testb $0xff,FPU_bits_lost /* bits lost == underflow */
- jz xL_Normalised
+ movl TAG_Special,%edx
+ jz L_deNormalised
/* There must be a masked underflow */
push %eax
pushl EX_Underflow
- call SYMBOL_NAME(FPU_exception)
+ call EXCEPTION
popl %eax
popl %eax
- jmp xL_Normalised
+ movl TAG_Special,%edx
+ jmp L_deNormalised
/*
@@ -613,41 +622,42 @@ L_underflow_to_zero:
push %eax
pushl EX_Underflow
- call SYMBOL_NAME(FPU_exception)
+ call EXCEPTION
popl %eax
popl %eax
/* Reduce the exponent to EXP_UNDER */
- movl EXP_UNDER,EXP(%edi)
- movb TW_Zero,TAG(%edi)
- jmp xL_Store_significand
+ movw EXP_UNDER,EXP(%edi)
+ movl TAG_Zero,%edx
+ jmp L_Store_significand
/* The operations resulted in a number too large to represent. */
L_overflow:
+ addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */
push %edi
call SYMBOL_NAME(arith_overflow)
pop %edi
- jmp fpu_reg_round_exit
+ jmp fpu_reg_round_signed_special_exit
-xSignal_underflow:
+Signal_underflow:
/* The number may have been changed to a non-denormal */
/* by the rounding operations. */
- cmpl EXP_UNDER,EXP(%edi)
- jle xDo_unmasked_underflow
+ cmpw EXP_UNDER,EXP(%edi)
+ jle Do_unmasked_underflow
- jmp xL_Normalised
+ jmp L_Normalised
-xDo_unmasked_underflow:
+Do_unmasked_underflow:
/* Increase the exponent by the magic number */
- addl $(3*(1<<13)),EXP(%edi)
+ addw $(3*(1<<13)),EXP(%edi)
push %eax
pushl EX_Underflow
call EXCEPTION
popl %eax
popl %eax
- jmp xL_Normalised
+ jmp L_Normalised
#ifdef PARANOID
@@ -694,6 +704,6 @@ L_entry_bugged:
call EXCEPTION
popl %ebx
L_exception_exit:
- mov $1,%eax
- jmp fpu_reg_round_exit
+ mov $-1,%eax
+ jmp fpu_reg_round_special_exit
#endif PARANOID
diff --git a/arch/i386/math-emu/reg_u_add.S b/arch/i386/math-emu/reg_u_add.S
index 1dc0d41df..c6664a49e 100644
--- a/arch/i386/math-emu/reg_u_add.S
+++ b/arch/i386/math-emu/reg_u_add.S
@@ -2,24 +2,26 @@
/*---------------------------------------------------------------------------+
| reg_u_add.S |
| |
- | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the |
+ | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the |
| result in a destination FPU_REG. |
| |
- | Copyright (C) 1992,1993,1995 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| Call from C as: |
- | void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
+ | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
| int control_w) |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
| |
+---------------------------------------------------------------------------*/
/*
- | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
- | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
| treated as unsigned numbers,
- | and returns their sum as a TW_Valid or TW_S f.p. number.
+ | and returns their sum as a TAG_Valid or TAG_Special f.p. number.
| The returned number is normalized.
| Basic checks are performed if PARANOID is defined.
*/
@@ -29,7 +31,7 @@
#include "control_w.h"
.text
-ENTRY(reg_u_add)
+ENTRY(FPU_u_add)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -39,27 +41,9 @@ ENTRY(reg_u_add)
movl PARAM1,%esi /* source 1 */
movl PARAM2,%edi /* source 2 */
-#ifdef DENORM_OPERAND
- cmpl EXP_UNDER,EXP(%esi)
- jg xOp1_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp1_not_denorm:
- cmpl EXP_UNDER,EXP(%edi)
- jg xOp2_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
- movl EXP(%esi),%ecx
- subl EXP(%edi),%ecx /* exp1 - exp2 */
+ movl PARAM6,%ecx
+ movl %ecx,%edx
+ subl PARAM7,%ecx /* exp1 - exp2 */
jge L_arg1_larger
/* num1 is smaller */
@@ -67,6 +51,7 @@ xOp2_not_denorm:
movl SIGH(%esi),%eax
movl %edi,%esi
+ movl PARAM7,%edx
negw %cx
jmp L_accum_loaded
@@ -77,12 +62,7 @@ L_arg1_larger:
L_accum_loaded:
movl PARAM3,%edi /* destination */
-/* movb SIGN(%esi),%dl
- movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
-
-
- movl EXP(%esi),%edx
- movl %edx,EXP(%edi) /* Copy exponent to destination */
+ movw %dx,EXP(%edi) /* Copy exponent to destination */
xorl %edx,%edx /* clear the extension */
@@ -162,7 +142,7 @@ L_shift_done:
orl $1,%edx
L_no_bit_lost:
- incl EXP(%edi)
+ incw EXP(%edi)
L_round_the_result:
jmp fpu_reg_round /* Round the result */
@@ -175,9 +155,8 @@ L_bugged:
pushl EX_INTERNAL|0x201
call EXCEPTION
pop %ebx
+ movl $-1,%eax
jmp L_exit
-#endif PARANOID
-
L_exit:
popl %ebx
@@ -185,3 +164,4 @@ L_exit:
popl %esi
leave
ret
+#endif PARANOID
diff --git a/arch/i386/math-emu/reg_u_div.S b/arch/i386/math-emu/reg_u_div.S
index 5bba98dd8..36630de7d 100644
--- a/arch/i386/math-emu/reg_u_div.S
+++ b/arch/i386/math-emu/reg_u_div.S
@@ -2,22 +2,24 @@
/*---------------------------------------------------------------------------+
| reg_u_div.S |
| |
- | Core division routines |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
| |
- | Copyright (C) 1992,1993,1995 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
- | Kernel for the division routines. |
- | |
- | void reg_u_div(FPU_REG *a, FPU_REG *a, |
- | FPU_REG *dest, unsigned int control_word) |
+ | Call from C as: |
+ | int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
+ | unsigned int control_word, char *sign) |
| |
| Does not compute the destination exponent, but does adjust it. |
+ | |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
+---------------------------------------------------------------------------*/
#include "exception.h"
@@ -67,9 +69,12 @@ FPU_ovfl_flag:
.byte 0
#endif NON_REENTRANT_FPU
+#define REGA PARAM1
+#define REGB PARAM2
+#define DEST PARAM3
.text
-ENTRY(reg_u_div)
+ENTRY(FPU_u_div)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
@@ -80,32 +85,28 @@ ENTRY(reg_u_div)
pushl %edi
pushl %ebx
- movl PARAM1,%esi /* pointer to num */
- movl PARAM2,%ebx /* pointer to denom */
- movl PARAM3,%edi /* pointer to answer */
+ movl REGA,%esi
+ movl REGB,%ebx
+ movl DEST,%edi
-#ifdef DENORM_OPERAND
- movl EXP(%esi),%eax
- cmpl EXP_UNDER,%eax
- jg xOp1_not_denorm
+ movw EXP(%esi),%dx
+ movw EXP(%ebx),%ax
+ .byte 0x0f,0xbf,0xc0 /* movsx %ax,%eax */
+ .byte 0x0f,0xbf,0xd2 /* movsx %dx,%edx */
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
+ /* A denormal and a large number can cause an exponent underflow */
+ cmpl EXP_WAY_UNDER,%edx
+ jg xExp_not_underflow
-xOp1_not_denorm:
- movl EXP(%ebx),%eax
- cmpl EXP_UNDER,%eax
- jg xOp2_not_denorm
+ /* Set to a really low value allow correct handling */
+ movl EXP_WAY_UNDER,%edx
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
+xExp_not_underflow:
-xOp2_not_denorm:
-#endif DENORM_OPERAND
+ movw %dx,EXP(%edi)
-ENTRY(divide_kernel)
#ifdef PARANOID
/* testl $0x80000000, SIGH(%esi) // Dividend */
/* je L_bugged */
@@ -147,7 +148,7 @@ L_no_adjust:
/* Do the shifting here */
/* increase the exponent */
- incl EXP(%edi)
+ incw EXP(%edi)
/* shift the mantissa right one bit */
stc /* To set the ms bit */
@@ -423,7 +424,7 @@ LRound_ovfl:
testb $255,FPU_ovfl_flag /* was the num > denom ? */
je LRound_precision
- incl EXP(%edi)
+ incw EXP(%edi)
/* shift the mantissa right one bit */
stc /* Will set the ms bit */
@@ -433,7 +434,7 @@ LRound_ovfl:
/* Round the result as required */
LRound_precision:
- decl EXP(%edi) /* binary point between 1st & 2nd bits */
+ decw EXP(%edi) /* binary point between 1st & 2nd bits */
movl %eax,%edx
movl FPU_result_1,%ebx
@@ -462,6 +463,7 @@ L_bugged_2:
jmp L_exit
L_exit:
+ movl $-1,%eax
popl %ebx
popl %edi
popl %esi
diff --git a/arch/i386/math-emu/reg_u_mul.S b/arch/i386/math-emu/reg_u_mul.S
index 682fbec15..b9396598d 100644
--- a/arch/i386/math-emu/reg_u_mul.S
+++ b/arch/i386/math-emu/reg_u_mul.S
@@ -4,9 +4,9 @@
| |
| Core multiplication routine |
| |
- | Copyright (C) 1992,1993,1995 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
@@ -15,7 +15,7 @@
| Basic multiplication routine. |
| Does not check the resulting exponent for overflow/underflow |
| |
- | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
+ | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
| |
| Internal working is at approx 128 bits. |
| Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
@@ -44,7 +44,7 @@ FPU_accum_1:
.text
-ENTRY(reg_u_mul)
+ENTRY(FPU_u_mul)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
@@ -65,27 +65,6 @@ ENTRY(reg_u_mul)
jz L_bugged
#endif PARANOID
-#ifdef DENORM_OPERAND
- movl EXP(%esi),%eax
- cmpl EXP_UNDER,%eax
- jg xOp1_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp1_not_denorm:
- movl EXP(%edi),%eax
- cmpl EXP_UNDER,%eax
- jg xOp2_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
xorl %ecx,%ecx
xorl %ebx,%ebx
@@ -111,13 +90,22 @@ xOp2_not_denorm:
addl %eax,%ebx
adcl %edx,%ecx
- movl EXP(%esi),%eax /* Compute the exponent */
- addl EXP(%edi),%eax
+ /* Get the sum of the exponents. */
+ movl PARAM6,%eax
subl EXP_BIAS-1,%eax
+ /* Two denormals can cause an exponent underflow */
+ cmpl EXP_WAY_UNDER,%eax
+ jg Exp_not_underflow
+
+ /* Set to a really low value allow correct handling */
+ movl EXP_WAY_UNDER,%eax
+
+Exp_not_underflow:
+
/* Have now finished with the sources */
movl PARAM3,%edi /* Point to the destination */
- movl %eax,EXP(%edi)
+ movw %ax,EXP(%edi)
/* Now make sure that the result is normalized */
testl $0x80000000,%ecx
@@ -128,7 +116,7 @@ xOp2_not_denorm:
rcll $1,FPU_accum_1
rcll $1,%ebx
rcll $1,%ecx
- decl EXP(%edi)
+ decw EXP(%edi)
LResult_Normalised:
movl FPU_accum_0,%eax
diff --git a/arch/i386/math-emu/reg_u_sub.S b/arch/i386/math-emu/reg_u_sub.S
index 891670260..092f956c0 100644
--- a/arch/i386/math-emu/reg_u_sub.S
+++ b/arch/i386/math-emu/reg_u_sub.S
@@ -4,21 +4,23 @@
| |
| Core floating point subtraction routine. |
| |
- | Copyright (C) 1992,1993,1995 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Copyright (C) 1992,1993,1995,1997 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@suburbia.net |
| |
| Call from C as: |
- | void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
+ | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
| int control_w) |
+ | Return value is the tag of the answer, or-ed with FPU_Exception if |
+ | one was raised, or -1 on internal error. |
| |
+---------------------------------------------------------------------------*/
/*
- | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
- | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TAG_Valid), which are
| treated as unsigned numbers,
- | and returns their difference as a TW_Valid or TW_Zero f.p.
+ | and returns their difference as a TAG_Valid or TAG_Zero f.p.
| number.
| The first number (arg1) must be the larger.
| The returned number is normalized.
@@ -30,7 +32,7 @@
#include "control_w.h"
.text
-ENTRY(reg_u_sub)
+ENTRY(FPU_u_sub)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -39,28 +41,9 @@ ENTRY(reg_u_sub)
movl PARAM1,%esi /* source 1 */
movl PARAM2,%edi /* source 2 */
-
-#ifdef DENORM_OPERAND
- cmpl EXP_UNDER,EXP(%esi)
- jg xOp1_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp1_not_denorm:
- cmpl EXP_UNDER,EXP(%edi)
- jg xOp2_not_denorm
-
- call SYMBOL_NAME(denormal_operand)
- orl %eax,%eax
- jnz fpu_Arith_exit
-
-xOp2_not_denorm:
-#endif DENORM_OPERAND
-
- movl EXP(%esi),%ecx
- subl EXP(%edi),%ecx /* exp1 - exp2 */
+
+ movl PARAM6,%ecx
+ subl PARAM7,%ecx /* exp1 - exp2 */
#ifdef PARANOID
/* source 2 is always smaller than source 1 */
@@ -81,10 +64,8 @@ xOp2_not_denorm:
movl SIGL(%edi),%ebx /* register ls word */
movl PARAM3,%edi /* destination */
- movl EXP(%esi),%edx
- movl %edx,EXP(%edi) /* Copy exponent to destination */
-/* movb SIGN(%esi),%dl
- movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
+ movl PARAM6,%edx
+ movw %dx,EXP(%edi) /* Copy exponent to destination */
xorl %edx,%edx /* register extension */
@@ -93,8 +74,8 @@ xOp2_not_denorm:
| right the required number of |
| places. |
+--------------------------------------*/
-L_shift_r:
- cmpl $32,%ecx /* shrd only works for 0..31 bits */
+
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
jnc L_more_than_31
/* less than 32 bits */
@@ -104,7 +85,7 @@ L_shift_r:
jmp L_shift_done
L_more_than_31:
- cmpl $64,%ecx
+ cmpw $64,%cx
jnc L_more_than_63
subb $32,%cl
@@ -210,7 +191,7 @@ L_subtr:
jnz L_must_be_zero
/* Shift left 64 bits */
- subl $64,EXP(%edi)
+ subw $64,EXP(%edi)
xchg %edx,%eax
jmp fpu_reg_round
@@ -221,17 +202,17 @@ L_must_be_zero:
#endif PARANOID
/* The result is zero */
- movb TW_Zero,TAG(%edi)
- movl $0,EXP(%edi) /* exponent */
+ movw $0,EXP(%edi) /* exponent */
movl $0,SIGL(%edi)
movl $0,SIGH(%edi)
- jmp L_exit /* %eax contains zero */
+ movl TAG_Zero,%eax
+ jmp L_exit
L_shift_32:
movl %ebx,%eax
movl %edx,%ebx
movl $0,%edx
- subl $32,EXP(%edi) /* Can get underflow here */
+ subw $32,EXP(%edi) /* Can get underflow here */
/* We need to shift left by 1 - 31 bits */
L_shift_1:
@@ -241,7 +222,7 @@ L_shift_1:
shld %cl,%ebx,%eax
shld %cl,%edx,%ebx
shl %cl,%edx
- subl %ecx,EXP(%edi) /* Can get underflow here */
+ subw %cx,EXP(%edi) /* Can get underflow here */
L_round:
jmp fpu_reg_round /* Round the result */
@@ -277,11 +258,12 @@ L_bugged:
call EXCEPTION
pop %ebx
jmp L_error_exit
-#endif PARANOID
-
L_error_exit:
- movl $1,%eax
+ movl $-1,%eax
+
+#endif PARANOID
+
L_exit:
popl %ebx
popl %edi
diff --git a/arch/i386/math-emu/version.h b/arch/i386/math-emu/version.h
index d966ab193..2f819087d 100644
--- a/arch/i386/math-emu/version.h
+++ b/arch/i386/math-emu/version.h
@@ -2,11 +2,11 @@
| version.h |
| |
| |
- | Copyright (C) 1992,1993,1994,1996 |
+ | Copyright (C) 1992,1993,1994,1996,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- | E-mail billm@jacobi.maths.monash.edu.au |
+ | E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version 1.22"
+#define FPU_VERSION "wm-FPU-emu version 2.00"
diff --git a/arch/i386/math-emu/wm_shrx.S b/arch/i386/math-emu/wm_shrx.S
index 1ea7ff7da..518428317 100644
--- a/arch/i386/math-emu/wm_shrx.S
+++ b/arch/i386/math-emu/wm_shrx.S
@@ -9,9 +9,9 @@
| Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
- | unsigned shrx(void *arg1, unsigned arg2) |
+ | unsigned FPU_shrx(void *arg1, unsigned arg2) |
| and |
- | unsigned shrxs(void *arg1, unsigned arg2) |
+ | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
| |
+---------------------------------------------------------------------------*/
@@ -19,7 +19,7 @@
.text
/*---------------------------------------------------------------------------+
- | unsigned shrx(void *arg1, unsigned arg2) |
+ | unsigned FPU_shrx(void *arg1, unsigned arg2) |
| |
| Extended shift right function. |
| Fastest for small shifts. |
@@ -32,7 +32,7 @@
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
-ENTRY(shrx)
+ENTRY(FPU_shrx)
push %ebp
movl %esp,%ebp
pushl %esi
@@ -95,7 +95,7 @@ L_more_than_95:
/*---------------------------------------------------------------------------+
- | unsigned shrxs(void *arg1, unsigned arg2) |
+ | unsigned FPU_shrxs(void *arg1, unsigned arg2) |
| |
| Extended shift right function (optimized for small floating point |
| integers). |
@@ -110,7 +110,7 @@ L_more_than_95:
| part which has been shifted out of the arg. |
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
-ENTRY(shrxs)
+ENTRY(FPU_shrxs)
push %ebp
movl %esp,%ebp
pushl %esi
diff --git a/arch/i386/math-emu/wm_sqrt.S b/arch/i386/math-emu/wm_sqrt.S
index 848796188..acc6dbbb2 100644
--- a/arch/i386/math-emu/wm_sqrt.S
+++ b/arch/i386/math-emu/wm_sqrt.S
@@ -4,12 +4,12 @@
| |
| Fixed point arithmetic square root evaluation. |
| |
- | Copyright (C) 1992,1993,1995 |
+ | Copyright (C) 1992,1993,1995,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| Call from C as: |
- | void wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | int wm_sqrt(FPU_REG *n, unsigned int control_word) |
| |
+---------------------------------------------------------------------------*/
@@ -92,7 +92,7 @@ ENTRY(wm_sqrt)
/* We use a rough linear estimate for the first guess.. */
- cmpl EXP_BIAS,EXP(%esi)
+ cmpw EXP_BIAS,EXP(%esi)
jnz sqrt_arg_ge_2
shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
@@ -347,9 +347,8 @@ sqrt_round_result:
movl %esi,%eax
movl %edi,%ebx
movl PARAM1,%edi
- movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */
- movl PARAM2,%ecx
- jmp fpu_reg_round_sqrt
+ movw EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */
+ jmp fpu_reg_round
sqrt_near_exact_x:
diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c
deleted file mode 100644
index eb72970d7..000000000
--- a/arch/m68k/amiga/amifb.c
+++ /dev/null
@@ -1,3633 +0,0 @@
-/*
- * linux/arch/m68k/amiga/amifb.c -- Low level implementation of the Amiga frame
- * buffer device
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- * with work by Roman Zippel
- *
- *
- * This file is based on the Atari frame buffer device (atafb.c):
- *
- * Copyright (C) 1994 Martin Schaller
- * Roman Hodek
- *
- * with work by Andreas Schwab
- * Guenther Kelleter
- *
- * and on the original Amiga console driver (amicon.c):
- *
- * Copyright (C) 1993 Hamish Macdonald
- * Greg Harp
- * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- * with work by William Rucklidge (wjr@cs.cornell.edu)
- * Geert Uytterhoeven
- * Jes Sorensen (jds@kom.auc.dk)
- *
- *
- * History:
- *
- * - 24 Jul 96: Copper generates now vblank interrupt and
- * VESA Power Saving Protocol is fully implemented
- * - 14 Jul 96: Rework and hopefully last ECS bugs fixed
- * - 7 Mar 96: Hardware sprite support by Roman Zippel
- * - 18 Feb 96: OCS and ECS support by Roman Zippel
- * Hardware functions completely rewritten
- * - 2 Dec 95: AGA version by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-#define DEBUG
-
-#if !defined(CONFIG_AMIFB_OCS) && !defined(CONFIG_AMIFB_ECS) && !defined(CONFIG_AMIFB_AGA)
-#define CONFIG_AMIFB_OCS /* define at least one fb driver, this will change later */
-#endif
-
-#if !defined(CONFIG_AMIFB_OCS)
-# define IS_OCS (0)
-#elif defined(CONFIG_AMIFB_ECS) || defined(CONFIG_AMIFB_AGA)
-# define IS_OCS (chipset == TAG_OCS)
-#else
-# define CONFIG_AMIFB_OCS_ONLY
-# define IS_OCS (1)
-#endif
-
-#if !defined(CONFIG_AMIFB_ECS)
-# define IS_ECS (0)
-#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_AGA)
-# define IS_ECS (chipset == TAG_ECS)
-#else
-# define CONFIG_AMIFB_ECS_ONLY
-# define IS_ECS (1)
-#endif
-
-#if !defined(CONFIG_AMIFB_AGA)
-# define IS_AGA (0)
-#elif defined(CONFIG_AMIFB_OCS) || defined(CONFIG_AMIFB_ECS)
-# define IS_AGA (chipset == TAG_AGA)
-#else
-# define CONFIG_AMIFB_AGA_ONLY
-# define IS_AGA (1)
-#endif
-
-/*******************************************************************************
-
-
- Generic video timings
- ---------------------
-
- Timings used by the frame buffer interface:
-
- +----------+---------------------------------------------+----------+-------+
- | | ^ | | |
- | | |upper_margin | | |
- | | ¥ | | |
- +----------###############################################----------+-------+
- | # ^ # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | left # | # right | hsync |
- | margin # | xres # margin | len |
- |<-------->#<---------------+--------------------------->#<-------->|<----->|
- | # | # | |
- | # | # | |
- | # | # | |
- | # |yres # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # ¥ # | |
- +----------###############################################----------+-------+
- | | ^ | | |
- | | |lower_margin | | |
- | | ¥ | | |
- +----------+---------------------------------------------+----------+-------+
- | | ^ | | |
- | | |vsync_len | | |
- | | ¥ | | |
- +----------+---------------------------------------------+----------+-------+
-
-
- Amiga video timings
- -------------------
-
- The Amiga native chipsets uses another timing scheme:
-
- - hsstrt: Start of horizontal synchronization pulse
- - hsstop: End of horizontal synchronization pulse
- - htotal: Last value on the line (i.e. line length = htotal+1)
- - vsstrt: Start of vertical synchronization pulse
- - vsstop: End of vertical synchronization pulse
- - vtotal: Last line value (i.e. number of lines = vtotal+1)
- - hcenter: Start of vertical retrace for interlace
-
- You can specify the blanking timings independently. Currently I just set
- them equal to the respective synchronization values:
-
- - hbstrt: Start of horizontal blank
- - hbstop: End of horizontal blank
- - vbstrt: Start of vertical blank
- - vbstop: End of vertical blank
-
- Horizontal values are in color clock cycles (280 ns), vertical values are in
- scanlines.
-
- (0, 0) is somewhere in the upper-left corner :-)
-
-
- Amiga visible window definitions
- --------------------------------
-
- Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to
- make corrections and/or additions.
-
- Within the above synchronization specifications, the visible window is
- defined by the following parameters (actual register resolutions may be
- different; all horizontal values are normalized with respect to the pixel
- clock):
-
- - diwstrt_h: Horizontal start of the visible window
- - diwstop_h: Horizontal stop+1(*) of the visible window
- - diwstrt_v: Vertical start of the visible window
- - diwstop_v: Vertical stop of the visible window
- - ddfstrt: Horizontal start of display DMA
- - ddfstop: Horizontal stop of display DMA
- - hscroll: Horizontal display output delay
-
- Sprite positioning:
-
- - sprstrt_h: Horizontal start-4 of sprite
- - sprstrt_v: Vertical start of sprite
-
- (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
-
- Horizontal values are in dotclock cycles (35 ns), vertical values are in
- scanlines.
-
- (0, 0) is somewhere in the upper-left corner :-)
-
-
- Dependencies (AGA, SHRES (35 ns dotclock))
- -------------------------------------------
-
- Since there are much more parameters for the Amiga display than for the
- frame buffer interface, there must be some dependencies among the Amiga
- display parameters. Here's what I found out:
-
- - ddfstrt and ddfstop are best aligned to 64 pixels.
- - the chipset needs 64+4 horizontal pixels after the DMA start before the
- first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
- display the first pixel on the line too. Increase diwstrt_h for virtual
- screen panning.
- - the display DMA always fetches 64 pixels at a time (fmode = 3).
- - ddfstop is ddfstrt+#pixels-64.
- - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
- more than htotal.
- - hscroll simply adds a delay to the display output. Smooth horizontal
- panning needs an extra 64 pixels on the left to prefetch the pixels that
- `fall off' on the left.
- - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
- DMA, so it's best to make the DMA start as late as possible.
- - you really don't want to make ddfstrt < 128, since this will steal DMA
- cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
- - I make diwstop_h and diwstop_v as large as possible.
-
- General dependencies
- --------------------
-
- - all values are SHRES pixel (35ns)
-
- table 1:fetchstart table 2:prefetch table 3:fetchsize
- ------------------ ---------------- -----------------
- Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
- -------------#------+-----+------#------+-----+------#------+-----+------
- Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64
- Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128
- Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256
-
- - chipset needs 4 pixels before the first pixel is output
- - ddfstrt must be aligned to fetchstart (table 1)
- - chipset needs also prefetch (table 2) to get first pixel data, so
- ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
- - for horizontal panning decrease diwstrt_h
- - the length of a fetchline must be aligned to fetchsize (table 3)
- - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
- moved to optimize use of dma (usefull for OCS/ECS overscan displays)
- - ddfstop is ddfstrt+ddfsize-fetchsize
- - If C= didn't change anything for AGA, then at following positions the
- dma bus is allready used:
- ddfstrt < 48 -> memory refresh
- < 96 -> disk dma
- < 160 -> audio dma
- < 192 -> sprite 0 dma
- < 416 -> sprite dma (32 per sprite)
- - in accordance with the hardware reference manual a hardware stop is at
- 192, but AGA (ECS?) can go below this.
-
- DMA priorities
- --------------
-
- Since there are limits on the earliest start value for display DMA and the
- display of sprites, I use the following policy on horizontal panning and
- the hardware cursor:
-
- - if you want to start display DMA too early, you loose the ability to
- do smooth horizontal panning (xpanstep 1 -> 64).
- - if you want to go even further, you loose the hardware cursor too.
-
- IMHO a hardware cursor is more important for X than horizontal scrolling,
- so that's my motivation.
-
-
- Implementation
- --------------
-
- ami_decode_var() converts the frame buffer values to the Amiga values. It's
- just a `straightforward' implementation of the above rules.
-
-
- Standard VGA timings
- --------------------
-
- xres yres left right upper lower hsync vsync
- ---- ---- ---- ----- ----- ----- ----- -----
- 80x25 720 400 27 45 35 12 108 2
- 80x30 720 480 27 45 30 9 108 2
-
- These were taken from a XFree86 configuration file, recalculated for a 28 MHz
- dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer
- generic timings.
-
- As a comparison, graphics/monitor.h suggests the following:
-
- xres yres left right upper lower hsync vsync
- ---- ---- ---- ----- ----- ----- ----- -----
-
- VGA 640 480 52 112 24 19 112 - 2 +
- VGA70 640 400 52 112 27 21 112 - 2 -
-
-
- Sync polarities
- ---------------
-
- VSYNC HSYNC Vertical size Vertical total
- ----- ----- ------------- --------------
- + + Reserved Reserved
- + - 400 414
- - + 350 362
- - - 480 496
-
- Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
-
-
- Broadcast video timings
- -----------------------
-
- According to the CCIR and RETMA specifications, we have the following values:
-
- CCIR -> PAL
- -----------
-
- - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
- 736 visible 70 ns pixels per line.
- - we have 625 scanlines, of which 575 are visible (interlaced); after
- rounding this becomes 576.
-
- RETMA -> NTSC
- -------------
-
- - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
- 736 visible 70 ns pixels per line.
- - we have 525 scanlines, of which 485 are visible (interlaced); after
- rounding this becomes 484.
-
- Thus if you want a PAL compatible display, you have to do the following:
-
- - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
- timings are to be used.
- - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
- interlaced, 312 for a non-interlaced and 156 for a doublescanned
- display.
- - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
- 908 for a HIRES and 454 for a LORES display.
- - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
- left_margin+2*hsync_len must be greater or equal.
- - the upper visible part begins at 48 (interlaced; non-interlaced:24,
- doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
- - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
- of 4 scanlines
-
- The settings for a NTSC compatible display are straightforward.
-
- Note that in a strict sense the PAL and NTSC standards only define the
- encoding of the color part (chrominance) of the video signal and don't say
- anything about horizontal/vertical synchronization nor refresh rates.
-
-
- -- Geert --
-
-*******************************************************************************/
-
-
- /*
- * Custom Chipset Definitions
- */
-
-#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld)
-
- /*
- * BPLCON0 -- Bitplane Control Register 0
- */
-
-#define BPC0_HIRES (0x8000)
-#define BPC0_BPU2 (0x4000) /* Bit plane used count */
-#define BPC0_BPU1 (0x2000)
-#define BPC0_BPU0 (0x1000)
-#define BPC0_HAM (0x0800) /* HAM mode */
-#define BPC0_DPF (0x0400) /* Double playfield */
-#define BPC0_COLOR (0x0200) /* Enable colorburst */
-#define BPC0_GAUD (0x0100) /* Genlock audio enable */
-#define BPC0_UHRES (0x0080) /* Ultrahi res enable */
-#define BPC0_SHRES (0x0040) /* Super hi res mode */
-#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */
-#define BPC0_BPU3 (0x0010) /* AGA */
-#define BPC0_LPEN (0x0008) /* Light pen enable */
-#define BPC0_LACE (0x0004) /* Interlace */
-#define BPC0_ERSY (0x0002) /* External resync */
-#define BPC0_ECSENA (0x0001) /* ECS enable */
-
- /*
- * BPLCON2 -- Bitplane Control Register 2
- */
-
-#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */
-#define BPC2_ZDBPSEL1 (0x2000)
-#define BPC2_ZDBPSEL0 (0x1000)
-#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */
-#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */
-#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */
-#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */
-#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */
-#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */
-#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */
-#define BPC2_PF2P1 (0x0010)
-#define BPC2_PF2P0 (0x0008)
-#define BPC2_PF1P2 (0x0004) /* ditto PF1 */
-#define BPC2_PF1P1 (0x0002)
-#define BPC2_PF1P0 (0x0001)
-
- /*
- * BPLCON3 -- Bitplane Control Register 3 (AGA)
- */
-
-#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */
-#define BPC3_BANK1 (0x4000)
-#define BPC3_BANK0 (0x2000)
-#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */
-#define BPC3_PF2OF1 (0x0800)
-#define BPC3_PF2OF0 (0x0400)
-#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */
-#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */
-#define BPC3_SPRES0 (0x0040)
-#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */
-#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */
-#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */
-#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */
-#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */
-
- /*
- * BPLCON4 -- Bitplane Control Register 4 (AGA)
- */
-
-#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */
-#define BPC4_BPLAM6 (0x4000)
-#define BPC4_BPLAM5 (0x2000)
-#define BPC4_BPLAM4 (0x1000)
-#define BPC4_BPLAM3 (0x0800)
-#define BPC4_BPLAM2 (0x0400)
-#define BPC4_BPLAM1 (0x0200)
-#define BPC4_BPLAM0 (0x0100)
-#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */
-#define BPC4_ESPRM6 (0x0040)
-#define BPC4_ESPRM5 (0x0020)
-#define BPC4_ESPRM4 (0x0010)
-#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */
-#define BPC4_OSPRM6 (0x0004)
-#define BPC4_OSPRM5 (0x0002)
-#define BPC4_OSPRM4 (0x0001)
-
- /*
- * BEAMCON0 -- Beam Control Register
- */
-
-#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */
-#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */
-#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */
-#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */
-#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */
-#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */
-#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */
-#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */
-#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */
-#define BMC0_PAL (0x0020) /* Set decodes for PAL */
-#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */
-#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */
-#define BMC0_CSYTRUE (0x0004) /* CSY polarity */
-#define BMC0_VSYTRUE (0x0002) /* VSY polarity */
-#define BMC0_HSYTRUE (0x0001) /* HSY polarity */
-
-
- /*
- * FMODE -- Fetch Mode Control Register (AGA)
- */
-
-#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */
-#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */
-#define FMODE_SPAGEM (0x0008) /* Sprite page mode */
-#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */
-#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */
-#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */
-
- /*
- * Tags used to indicate a specific Pixel Clock
- *
- * clk_shift is the shift value to get the timings in 35 ns units
- */
-
-enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
-
- /*
- * Tags used to indicate the specific chipset
- */
-
-enum { TAG_OCS, TAG_ECS, TAG_AGA };
-
- /*
- * Tags used to indicate the memory bandwidth
- */
-
-enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 };
-
-
- /*
- * Clock Definitions, Maximum Display Depth
- *
- * These depend on the E-Clock or the Chipset, so they are filled in
- * dynamically
- */
-
-static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */
-static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */
-static u_short maxfmode, chipset;
-
-
- /*
- * Broadcast Video Timings
- *
- * Horizontal values are in 35 ns (SHRES) units
- * Vertical values are in interlaced scanlines
- */
-
-#define PAL_DIWSTRT_H (360) /* PAL Window Limits */
-#define PAL_DIWSTRT_V (48)
-#define PAL_HTOTAL (1816)
-#define PAL_VTOTAL (625)
-
-#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */
-#define NTSC_DIWSTRT_V (40)
-#define NTSC_HTOTAL (1816)
-#define NTSC_VTOTAL (525)
-
-
- /*
- * Monitor Specifications
- *
- * These are typical for a `generic' Amiga monitor (e.g. A1960)
- */
-
-static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000;
-
-
- /*
- * Various macros
- */
-
-#define up2(v) (((v)+1) & -2)
-#define down2(v) ((v) & -2)
-#define div2(v) ((v)>>1)
-#define mod2(v) ((v) & 1)
-
-#define up4(v) (((v)+3) & -4)
-#define down4(v) ((v) & -4)
-#define mul4(v) ((v)<<2)
-#define div4(v) ((v)>>2)
-#define mod4(v) ((v) & 3)
-
-#define up8(v) (((v)+7) & -8)
-#define down8(v) ((v) & -8)
-#define div8(v) ((v)>>3)
-#define mod8(v) ((v) & 7)
-
-#define up16(v) (((v)+15) & -16)
-#define down16(v) ((v) & -16)
-#define div16(v) ((v)>>4)
-#define mod16(v) ((v) & 15)
-
-#define up32(v) (((v)+31) & -32)
-#define down32(v) ((v) & -32)
-#define div32(v) ((v)>>5)
-#define mod32(v) ((v) & 31)
-
-#define up64(v) (((v)+63) & -64)
-#define down64(v) ((v) & -64)
-#define div64(v) ((v)>>6)
-#define mod64(v) ((v) & 63)
-
-#define upx(x,v) (((v)+(x)-1) & -(x))
-#define downx(x,v) ((v) & -(x))
-#define modx(x,v) ((v) & ((x)-1))
-
-/* if x1 is not a constant, this macro won't make real sense :-) */
-#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
- "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#define max(a, b) ((a) > (b) ? (a) : (b))
-
-#define highw(x) ((u_long)(x)>>16 & 0xffff)
-#define loww(x) ((u_long)(x) & 0xffff)
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
-#define VBlankOff() custom.intena = IF_COPER
-
-
- /*
- * Chip RAM we reserve for the Frame Buffer
- *
- * This defines the Maximum Virtual Screen Size
- * (Setable per kernel options?)
- */
-
-#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */
-#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */
-#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */
-#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */
-#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */
-
-#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */
-#define DUMMYSPRITEMEMSIZE (8)
-
-#define CHIPRAM_SAFETY_LIMIT (16384)
-
-static u_long videomemory, spritememory;
-static u_long videomemorysize;
-
- /*
- * This is the earliest allowed start of fetching display data.
- * Only if you really want no hardware cursor and audio,
- * set this to 128, but let it better at 192
- */
-
-static u_long min_fstrt = 192;
-
-#define assignchunk(name, type, ptr, size) \
-{ \
- (name) = (type)(ptr); \
- ptr += size; \
-}
-
-
- /*
- * Copper Instructions
- */
-
-#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val))
-#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val))
-#define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
-#define CEND (0xfffffffe)
-
-
-typedef union {
- u_long l;
- u_short w[2];
-} copins;
-
-static struct copdisplay {
- copins *init;
- copins *wait;
- copins *list[2][2];
- copins *rebuild[2];
-} copdisplay;
-
-static u_short currentcop = 0;
-
- /*
- * Hardware Cursor
- */
-
-static int cursorrate = 20; /* Number of frames/flash toggle */
-static u_short cursorstate = -1;
-static u_short cursormode = FB_CURSOR_OFF;
-
-static u_short *lofsprite, *shfsprite, *dummysprite;
-
- /*
- * Current Video Mode
- */
-
-static struct amiga_fb_par {
-
- /* General Values */
-
- int xres; /* vmode */
- int yres; /* vmode */
- int vxres; /* vmode */
- int vyres; /* vmode */
- int xoffset; /* vmode */
- int yoffset; /* vmode */
- u_short bpp; /* vmode */
- u_short clk_shift; /* vmode */
- u_short line_shift; /* vmode */
- int vmode; /* vmode */
- u_short diwstrt_h; /* vmode */
- u_short diwstop_h; /* vmode */
- u_short diwstrt_v; /* vmode */
- u_short diwstop_v; /* vmode */
- u_long next_line; /* modulo for next line */
- u_long next_plane; /* modulo for next plane */
-
- /* Cursor Values */
-
- struct {
- short crsr_x; /* movecursor */
- short crsr_y; /* movecursor */
- short spot_x;
- short spot_y;
- u_short height;
- u_short width;
- u_short fmode;
- } crsr;
-
- /* OCS Hardware Registers */
-
- u_long bplpt0; /* vmode, pan (Note: physical address) */
- u_long bplpt0wrap; /* vmode, pan (Note: physical address) */
- u_short ddfstrt;
- u_short ddfstop;
- u_short bpl1mod;
- u_short bpl2mod;
- u_short bplcon0; /* vmode */
- u_short bplcon1; /* vmode */
- u_short htotal; /* vmode */
- u_short vtotal; /* vmode */
-
- /* Additional ECS Hardware Registers */
-
- u_short bplcon3; /* vmode */
- u_short beamcon0; /* vmode */
- u_short hsstrt; /* vmode */
- u_short hsstop; /* vmode */
- u_short hbstrt; /* vmode */
- u_short hbstop; /* vmode */
- u_short vsstrt; /* vmode */
- u_short vsstop; /* vmode */
- u_short vbstrt; /* vmode */
- u_short vbstop; /* vmode */
- u_short hcenter; /* vmode */
-
- /* Additional AGA Hardware Registers */
-
- u_short fmode; /* vmode */
-} currentpar;
-
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node; /* node of the /dev/fb?current file */
-
- /*
- * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern volatile u_short amiga_audio_min_period;
-
- /*
- * Since we can't read the palette on OCS/ECS, and since reading one
- * single color palette entry require 5 expensive custom chip bus accesses
- * on AGA, we keep a copy of the current palette.
- */
-
-#if defined(CONFIG_AMIFB_AGA)
-static struct { u_char red, green, blue, pad; } palette[256];
-#else
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif
-
-#if defined(CONFIG_AMIFB_ECS)
-static u_short ecs_palette[32];
-#endif
-
- /*
- * Latches for Display Changes during VBlank
- */
-
-static u_short do_vmode_full = 0; /* Change the Video Mode */
-static u_short do_vmode_pan = 0; /* Update the Video Mode */
-static short do_blank = 0; /* (Un)Blank the Screen (±1) */
-static u_short do_cursor = 0; /* Move the Cursor */
-
-
- /*
- * Various Flags
- */
-
-static u_short is_blanked = 0; /* Screen is Blanked */
-static u_short is_lace = 0; /* Screen is laced */
-
- /*
- * Frame Buffer Name
- *
- * The rest of the name is filled in during initialization
- */
-
-static char amiga_fb_name[16] = "Amiga ";
-
- /*
- * Predefined Video Mode Names
- *
- * The a2024-?? modes don't work yet because there's no A2024 driver.
- */
-
-static char *amiga_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * AmigaOS Video Modes
- */
-
- "ntsc", /* 640x200, 15 kHz, 60 Hz (NTSC) */
- "ntsc-lace", /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
- "pal", /* 640x256, 15 kHz, 50 Hz (PAL) */
- "pal-lace", /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
- "multiscan", /* 640x480, 29 kHz, 57 Hz */
- "multiscan-lace", /* 640x960, 29 kHz, 57 Hz interlaced */
- "a2024-10", /* 1024x800, 10 Hz (Not yet supported) */
- "a2024-15", /* 1024x800, 15 Hz (Not yet supported) */
- "euro36", /* 640x200, 15 kHz, 72 Hz */
- "euro36-lace", /* 640x400, 15 kHz, 72 Hz interlaced */
- "euro72", /* 640x400, 29 kHz, 68 Hz */
- "euro72-lace", /* 640x800, 29 kHz, 68 Hz interlaced */
- "super72", /* 800x300, 23 kHz, 70 Hz */
- "super72-lace", /* 800x600, 23 kHz, 70 Hz interlaced */
- "dblntsc", /* 640x200, 27 kHz, 57 Hz doublescan */
- "dblntsc-ff", /* 640x400, 27 kHz, 57 Hz */
- "dblntsc-lace", /* 640x800, 27 kHz, 57 Hz interlaced */
- "dblpal", /* 640x256, 27 kHz, 47 Hz doublescan */
- "dblpal-ff", /* 640x512, 27 kHz, 47 Hz */
- "dblpal-lace", /* 640x1024, 27 kHz, 47 Hz interlaced */
-
- /*
- * VGA Video Modes
- */
-
- "vga", /* 640x480, 31 kHz, 60 Hz (VGA) */
- "vga70", /* 640x400, 31 kHz, 70 Hz (VGA) */
-
- /*
- * User Defined Video Modes: to be set after boot up using e.g. fbset
- */
-
- "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
-static struct fb_var_screeninfo amiga_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * AmigaOS Video Modes
- */
-
- {
- /* ntsc */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 44, 16, 76, 2,
- FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* ntsc-lace */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 88, 33, 76, 4,
- FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* pal */
- 640, 256, 640, 256, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 40, 14, 76, 2,
- FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* pal-lace */
- 640, 512, 640, 512, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 80, 29, 76, 4,
- FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* multiscan */
- 640, 480, 640, 480, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 29, 8, 72, 8,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-
- }, {
- /* multiscan-lace */
- 640, 960, 640, 960, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 58, 16, 72, 16,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* a2024-10 (Not yet supported) */
- 1024, 800, 1024, 800, 0, 0, 2, 0,
- {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* a2024-15 (Not yet supported) */
- 1024, 800, 1024, 800, 0, 0, 2, 0,
- {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro36 */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro36-lace */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro72 */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* euro72-lace */
- 640, 800, 640, 800, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* super72 */
- 800, 300, 800, 300, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* super72-lace */
- 800, 600, 800, 600, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblntsc */
- 640, 200, 640, 200, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4,
- 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
- }, {
- /* dblntsc-ff */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblntsc-lace */
- 640, 800, 640, 800, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblpal */
- 640, 256, 640, 256, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4,
- 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
- }, {
- /* dblpal-ff */
- 640, 512, 640, 512, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* dblpal-lace */
- 640, 1024, 640, 1024, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14,
- 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
- },
-
- /*
- * VGA Video Modes
- */
-
- {
- /* vga */
- 640, 480, 640, 480, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2,
- 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- }, {
- /* vga70 */
- 640, 400, 640, 400, 0, 0, 4, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2,
- FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
- },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-#define NUM_USER_MODES (8)
-#define NUM_TOTAL_MODES arraysize(amiga_fb_predefined)
-#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES)
-
-static int amifb_ilbm = 0; /* interleaved or normal bitplanes */
-
-static int amifb_inverse = 0;
-static int amifb_usermode = 0;
-
- /*
- * Some default modes
- */
-
-#define DEFMODE_PAL "pal" /* for PAL OCS/ECS */
-#define DEFMODE_NTSC "ntsc" /* for NTSC OCS/ECS */
-#define DEFMODE_AMBER_PAL "pal-lace" /* for flicker fixed PAL (A3000) */
-#define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */
-#define DEFMODE_AGA "vga70" /* for AGA */
-
- /*
- * Macros for the conversion from real world values to hardware register
- * values
- *
- * This helps us to keep our attention on the real stuff...
- *
- * Hardware limits for AGA:
- *
- * parameter min max step
- * --------- --- ---- ----
- * diwstrt_h 0 2047 1
- * diwstrt_v 0 2047 1
- * diwstop_h 0 4095 1
- * diwstop_v 0 4095 1
- *
- * ddfstrt 0 2032 16
- * ddfstop 0 2032 16
- *
- * htotal 8 2048 8
- * hsstrt 0 2040 8
- * hsstop 0 2040 8
- * vtotal 1 4096 1
- * vsstrt 0 4095 1
- * vsstop 0 4095 1
- * hcenter 0 2040 8
- *
- * hbstrt 0 2047 1
- * hbstop 0 2047 1
- * vbstrt 0 4095 1
- * vbstop 0 4095 1
- *
- * Horizontal values are in 35 ns (SHRES) pixels
- * Vertical values are in half scanlines
- */
-
-/* bplcon1 (smooth scrolling) */
-
-#define hscroll2hw(hscroll) \
- (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
- ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
-
-/* diwstrt/diwstop/diwhigh (visible display window) */
-
-#define diwstrt2hw(diwstrt_h, diwstrt_v) \
- (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
-#define diwstop2hw(diwstop_h, diwstop_v) \
- (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
-#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
- (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
- ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
- ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
-
-/* ddfstrt/ddfstop (display DMA) */
-
-#define ddfstrt2hw(ddfstrt) div8(ddfstrt)
-#define ddfstop2hw(ddfstop) div8(ddfstop)
-
-/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */
-
-#define hsstrt2hw(hsstrt) (div8(hsstrt))
-#define hsstop2hw(hsstop) (div8(hsstop))
-#define htotal2hw(htotal) (div8(htotal)-1)
-#define vsstrt2hw(vsstrt) (div2(vsstrt))
-#define vsstop2hw(vsstop) (div2(vsstop))
-#define vtotal2hw(vtotal) (div2(vtotal)-1)
-#define hcenter2hw(htotal) (div8(htotal))
-
-/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
-
-#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
-#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
-#define vbstrt2hw(vbstrt) (div2(vbstrt))
-#define vbstop2hw(vbstop) (div2(vbstop))
-
-/* colour */
-
-#define rgb2hw8_high(red, green, blue) \
- (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f))
-#define rgb2hw8_low(red, green, blue) \
- (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
-#define rgb2hw4(red, green, blue) \
- (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f))
-#define rgb2hw2(red, green, blue) \
- (((red)<<10 & 0xc00) | ((green)<<6 & 0x0c0) | ((blue)<<2 & 0x00c))
-
-/* sprpos/sprctl (sprite positioning) */
-
-#define spr2hw_pos(start_v, start_h) \
- (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
-#define spr2hw_ctl(start_v, start_h, stop_v) \
- (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
- ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
- ((start_h)>>2&0x0001))
-
-/* get current vertical position of beam */
-#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
-
- /*
- * Copper Initialisation List
- */
-
-#define COPINITSIZE (sizeof(copins)*40)
-
-enum {
- cip_bplcon0
-};
-
- /*
- * Long Frame/Short Frame Copper List
- * Don't change the order, build_copper()/rebuild_copper() rely on this
- */
-
-#define COPLISTSIZE (sizeof(copins)*64)
-
-enum {
- cop_wait, cop_bplcon0,
- cop_spr0ptrh, cop_spr0ptrl,
- cop_diwstrt, cop_diwstop,
- cop_diwhigh,
-};
-
- /*
- * Pixel modes for Bitplanes and Sprites
- */
-
-static u_short bplpixmode[3] = {
- BPC0_SHRES, /* 35 ns */
- BPC0_HIRES, /* 70 ns */
- 0 /* 140 ns */
-};
-
-static u_short sprpixmode[3] = {
- BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */
- BPC3_SPRES1, /* 70 ns */
- BPC3_SPRES0 /* 140 ns */
-};
-
- /*
- * Fetch modes for Bitplanes and Sprites
- */
-
-static u_short bplfetchmode[3] = {
- 0, /* 1x */
- FMODE_BPL32, /* 2x */
- FMODE_BPAGEM | FMODE_BPL32 /* 4x */
-};
-
-static u_short sprfetchmode[3] = {
- 0, /* 1x */
- FMODE_SPR32, /* 2x */
- FMODE_SPAGEM | FMODE_SPR32 /* 4x */
-};
-
- /*
- * Default Colormaps
- */
-
-static u_short red2[] =
- { 0x0000, 0xc000 };
-static u_short green2[] =
- { 0x0000, 0xc000 };
-static u_short blue2[] =
- { 0x0000, 0xc000 };
-
-static u_short red4[] =
- { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short green4[] =
- { 0x0000, 0xc000, 0x8000, 0xffff };
-static u_short blue4[] =
- { 0x0000, 0xc000, 0x8000, 0xffff };
-
-static u_short red8[] =
- { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000 };
-static u_short green8[] =
- { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000 };
-static u_short blue8[] =
- { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000 };
-
-static u_short red16[] =
- { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static u_short green16[] =
- { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static u_short blue16[] =
- { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
- 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_2_colors =
- { 0, 2, red2, green2, blue2, NULL };
-static struct fb_cmap default_8_colors =
- { 0, 8, red8, green8, blue8, NULL };
-static struct fb_cmap default_4_colors =
- { 0, 4, red4, green4, blue4, NULL };
-static struct fb_cmap default_16_colors =
- { 0, 16, red16, green16, blue16, NULL };
-
- /*
- * Interface used by the world
- */
-
-void amiga_video_setup(char *options, int *ints);
-
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con);
-
- /*
- * Interface to the low level console driver
- */
-
-struct fb_info *amiga_fb_init(long *mem_start);
-static int amifbcon_switch(int con);
-static int amifbcon_updatevar(int con);
-static void amifbcon_blank(int blank);
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con);
-
- /*
- * Internal routines
- */
-
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static int flash_cursor(void);
-static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
-static void get_video_mode(const char *name);
-static void check_default_mode(void);
-static u_long chipalloc(u_long size);
-static char *strtoke(char *s,const char *ct);
-
- /*
- * Hardware routines
- */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amiga_fb_par *par);
-static int ami_decode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par);
-static int ami_encode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par);
-static void ami_get_par(struct amiga_fb_par *par);
-static void ami_set_var(struct fb_var_screeninfo *var);
-#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par);
-#endif
-static void ami_pan_var(struct fb_var_screeninfo *var);
-static int ami_update_par(void);
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
-static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
-static void ami_update_display(void);
-static void ami_init_display(void);
-static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
-static void ami_set_sprite(void);
-static void ami_init_copper(void);
-static void ami_reinit_copper(void);
-static void ami_build_copper(void);
-static void ami_rebuild_copper(void);
-
-
- /*
- * External references
- */
-
-extern unsigned short ami_intena_vals[];
-
- /*
- * Support for Graphics Boards
- */
-
-#ifdef CONFIG_FB_CYBER /* Cybervision */
-extern int Cyber_probe(void);
-extern void Cyber_video_setup(char *options, int *ints);
-extern struct fb_info *Cyber_fb_init(long *mem_start);
-
-static int amifb_Cyber = 0;
-#endif
-
-#ifdef CONFIG_FB_RETINAZ3 /* RetinaZ3 */
-extern int retz3_probe(void);
-extern void retz3_video_setup(char *options, int *ints);
-extern struct fb_info *retz3_fb_init(long *mem_start);
-
-static int amifb_retz3 = 0;
-#endif
-
-#ifdef CONFIG_GSP_RESOLVER /* DMI Resolver */
-extern int resolver_probe(void);
-extern void resolver_video_setup(char *options, int *ints);
-extern struct fb_info *resolver_fb_init(long *mem_start);
-
-static int amifb_resolver = 0;
-#endif
-
-static struct fb_ops amiga_fb_ops = {
- amiga_fb_get_fix, amiga_fb_get_var, amiga_fb_set_var, amiga_fb_get_cmap,
- amiga_fb_set_cmap, amiga_fb_pan_display, amiga_fb_ioctl
-};
-
-void amiga_video_setup(char *options, int *ints)
-{
- char *this_opt;
- int i;
- char mcap_spec[80];
-
- /*
- * Check for a Graphics Board
- */
-
-#ifdef CONFIG_FB_CYBER
- if (options && *options)
- if (!strncmp(options, "cyber", 5) && Cyber_probe()) {
- amifb_Cyber = 1;
- Cyber_video_setup(options, ints);
- return;
- }
-#endif
-#ifdef CONFIG_FB_RETINAZ3
- if (options && *options)
- if (!strncmp(options, "retz3", 5) && retz3_probe()) {
- amifb_retz3 = 1;
- retz3_video_setup(options, ints);
- return;
- }
-#endif
-#ifdef CONFIG_GSP_RESOLVER
- if (options && *options)
- if (!strncmp(options, "resolver", 5) && resolver_probe()) {
- amifb_resolver = 1;
- resolver_video_setup(options, ints);
- return;
- }
-#endif
-
- mcap_spec[0] = '\0';
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
- char *p;
-
- if (!strcmp(this_opt, "inverse")) {
- amifb_inverse = 1;
- for (i = 0; i < 16; i++) {
- red16[i] = ~red16[i];
- green16[i] = ~green16[i];
- blue16[i] = ~blue16[i];
- }
- for (i = 0; i < 8; i++) {
- red8[i] = ~red8[i];
- green8[i] = ~green8[i];
- blue8[i] = ~blue8[i];
- }
- for (i = 0; i < 4; i++) {
- red4[i] = ~red4[i];
- green4[i] = ~green4[i];
- blue4[i] = ~blue4[i];
- }
- for (i = 0; i < 2; i++) {
- red2[i] = ~red2[i];
- green2[i] = ~green2[i];
- blue2[i] = ~blue2[i];
- }
- } else if (!strcmp(this_opt, "ilbm"))
- amifb_ilbm = 1;
- else if (!strncmp(this_opt, "monitorcap:", 11))
- strcpy(mcap_spec, this_opt+11);
- else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else if (!strncmp(this_opt, "fstart:", 7))
- min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
- else if (!strncmp(this_opt, "depth:", 6))
- amiga_fb_predefined[0].bits_per_pixel =
- simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "size:", 5)) {
- p = this_opt + 5;
- if (*p != ';')
- amiga_fb_predefined[0].xres =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p != ';')
- amiga_fb_predefined[0].yres =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p != ';')
- amiga_fb_predefined[0].xres_virtual =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p != ';')
- amiga_fb_predefined[0].yres_virtual =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p)
- amiga_fb_predefined[0].bits_per_pixel =
- simple_strtoul(p, NULL, 0);
- } else if (!strncmp(this_opt, "timing:", 7)) {
- p = this_opt + 7;
- if (*p != ';')
- amiga_fb_predefined[0].left_margin =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p != ';')
- amiga_fb_predefined[0].right_margin =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p != ';')
- amiga_fb_predefined[0].upper_margin =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p)
- amiga_fb_predefined[0].lower_margin =
- simple_strtoul(p, NULL, 0);
- } else if (!strncmp(this_opt, "sync:", 5)) {
- p = this_opt + 5;
- if (*p != ';')
- amiga_fb_predefined[0].hsync_len =
- simple_strtoul(p, NULL, 0);
- if (!(p = strchr(p, ';')))
- continue;
- if (*++p)
- amiga_fb_predefined[0].vsync_len =
- simple_strtoul(p, NULL, 0);
- } else
- get_video_mode(this_opt);
- }
-
- if (min_fstrt < 48)
- min_fstrt = 48;
-
- if (*mcap_spec) {
- char *p;
- int vmin, vmax, hmin, hmax;
-
- /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
- * <V*> vertical freq. in Hz
- * <H*> horizontal freq. in kHz
- */
-
- if (!(p = strtoke(mcap_spec, ";")) || !*p)
- goto cap_invalid;
- vmin = simple_strtoul(p, NULL, 10);
- if (vmin <= 0)
- goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
- goto cap_invalid;
- vmax = simple_strtoul(p, NULL, 10);
- if (vmax <= 0 || vmax <= vmin)
- goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
- goto cap_invalid;
- hmin = 1000 * simple_strtoul(p, NULL, 10);
- if (hmin <= 0)
- goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p)
- goto cap_invalid;
- hmax = 1000 * simple_strtoul(p, NULL, 10);
- if (hmax <= 0 || hmax <= hmin)
- goto cap_invalid;
-
- vfmin = vmin;
- vfmax = vmax;
- hfmin = hmin;
- hfmax = hmax;
-cap_invalid:
- ;
- }
-}
-
- /*
- * Get the Fixed Part of the Display
- */
-
-static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct amiga_fb_par par;
-
- if (con == -1)
- ami_get_par(&par);
- else {
- int err;
-
- if ((err = ami_decode_var(&disp[con].var, &par)))
- return err;
- }
- return ami_encode_fix(fix, &par);
-}
-
- /*
- * Get the User Defined Part of the Display
- */
-
-static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- int err = 0;
-
- if (con == -1) {
- struct amiga_fb_par par;
-
- ami_get_par(&par);
- err = ami_encode_var(var, &par);
- } else
- *var = disp[con].var;
- return err;
-}
-
- /*
- * Set the User Defined Part of the Display
- */
-
-static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err, activate = var->activate;
- int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
- struct amiga_fb_par par;
-
-
- /*
- * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
- * as FB_VMODE_SMOOTH_XPAN is only used internally
- */
-
- if (var->vmode & FB_VMODE_CONUPDATE) {
- var->vmode |= FB_VMODE_YWRAP;
- var->xoffset = disp[con].var.xoffset;
- var->yoffset = disp[con].var.yoffset;
- }
- if ((err = ami_decode_var(var, &par)))
- return err;
- ami_encode_var(var, &par);
- if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = disp[con].var.xres;
- oldyres = disp[con].var.yres;
- oldvxres = disp[con].var.xres_virtual;
- oldvyres = disp[con].var.yres_virtual;
- oldbpp = disp[con].var.bits_per_pixel;
- disp[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- struct fb_fix_screeninfo fix;
-
- ami_encode_fix(&fix, &par);
- disp[con].screen_base = (u_char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].line_length = fix.line_length;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = amifb_inverse;
- if (fb_info.changevar)
- (*fb_info.changevar)(con);
- }
- if (oldbpp != var->bits_per_pixel) {
- if ((err = alloc_cmap(&disp[con].cmap, 0, 0)))
- return err;
- do_install_cmap(con);
- }
- if (con == currcon)
- ami_set_var(&disp[con].var);
- }
- return 0;
-}
-
- /*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- if (var->vmode & FB_VMODE_YWRAP) {
- if (var->yoffset<0 || var->yoffset >= disp[con].var.yres_virtual || var->xoffset)
- return -EINVAL;
- } else {
- /*
- * TODO: There will be problems when xpan!=1, so some columns
- * on the right side will never be seen
- */
- if (var->xoffset+disp[con].var.xres > upx(16<<maxfmode, disp[con].var.xres_virtual) ||
- var->yoffset+disp[con].var.yres > disp[con].var.yres_virtual)
- return -EINVAL;
- }
- if (con == currcon)
- ami_pan_var(var);
- disp[con].var.xoffset = var->xoffset;
- disp[con].var.yoffset = var->yoffset;
- if (var->vmode & FB_VMODE_YWRAP)
- disp[con].var.vmode |= FB_VMODE_YWRAP;
- else
- disp[con].var.vmode &= ~FB_VMODE_YWRAP;
- return 0;
-}
-
- /*
- * Get the Colormap
- */
-
-static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console? */
- return do_fb_get_cmap(cmap, &disp[con].var, kspc);
- else if (disp[con].cmap.len) /* non default colormap? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
- /*
- * Set the Colormap
- */
-
-static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
-
- if (!disp[con].cmap.len) { /* no colormap allocated? */
- if ((err = alloc_cmap(&disp[con].cmap,
- 1<<disp[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console? */
- return do_fb_set_cmap(cmap, &disp[con].var, kspc);
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
- /*
- * Amiga Frame Buffer Specific ioctls
- */
-
-static int amiga_fb_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg, int con)
-{
- int i;
-
- switch (cmd) {
- case FBIOGET_FCURSORINFO : {
- struct fb_fix_cursorinfo crsrfix;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
- if (!i) {
- i = amiga_fb_get_fix_cursorinfo(&crsrfix, con);
- copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
- }
- return i;
- }
- case FBIOGET_VCURSORINFO : {
- struct fb_var_cursorinfo crsrvar;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
- if (!i) {
- i = amiga_fb_get_var_cursorinfo(&crsrvar,
- ((struct fb_var_cursorinfo *)arg)->data, con);
- copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
- }
- return i;
- }
- case FBIOPUT_VCURSORINFO : {
- struct fb_var_cursorinfo crsrvar;
-
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
- if (!i) {
- copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
- i = amiga_fb_set_var_cursorinfo(&crsrvar,
- ((struct fb_var_cursorinfo *)arg)->data, con);
- }
- return i;
- }
- case FBIOGET_CURSORSTATE : {
- struct fb_cursorstate crsrstate;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
- if (!i) {
- i = amiga_fb_get_cursorstate(&crsrstate, con);
- copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
- }
- return i;
- }
- case FBIOPUT_CURSORSTATE : {
- struct fb_cursorstate crsrstate;
-
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
- if (!i) {
- copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
- i = amiga_fb_set_cursorstate(&crsrstate, con);
- }
- return i;
- }
-#ifdef DEBUG
- case FBCMD_GET_CURRENTPAR : {
- struct amiga_fb_par par;
-
- i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amiga_fb_par));
- if (!i) {
- ami_get_par(&par);
- copy_to_user((void *)arg, &par, sizeof(struct amiga_fb_par));
- }
- return i;
- }
- case FBCMD_SET_CURRENTPAR : {
- struct amiga_fb_par par;
-
- i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amiga_fb_par));
- if (!i) {
- copy_from_user(&par, (void *)arg, sizeof(struct amiga_fb_par));
- ami_set_par(&par);
- }
- return i;
- }
-#endif */ DEBUG */
- }
- return -EINVAL;
-}
-
- /*
- * Hardware Cursor
- */
-
-static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
-{
- return ami_get_fix_cursorinfo(fix, con);
-}
-
-static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
- return ami_get_var_cursorinfo(var, data, con);
-}
-
-static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
- return ami_set_var_cursorinfo(var, data, con);
-}
-
-static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con)
-{
- return ami_get_cursorstate(state, con);
-}
-
-static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con)
-{
- return ami_set_cursorstate(state, con);
-}
-
- /*
- * Initialisation
- */
-
-__initfunc(struct fb_info *amiga_fb_init(long *mem_start))
-{
- int err, tag, i;
- u_long chipptr;
-
- /*
- * Check for a Graphics Board
- */
-
-#ifdef CONFIG_FB_CYBER
- if (amifb_Cyber)
- return Cyber_fb_init(mem_start);
-#endif
-#ifdef CONFIG_FB_RETINAZ3
- if (amifb_retz3){
- custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
- DMAF_BLITTER | DMAF_SPRITE;
- return retz3_fb_init(mem_start);
- }
-#endif
-#ifdef CONFIG_GSP_RESOLVER
- if (amifb_resolver){
- custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
- DMAF_BLITTER | DMAF_SPRITE;
- return NULL;
- }
-#endif
-
- /*
- * Use the Builtin Chipset
- */
-
- if (!AMIGAHW_PRESENT(AMI_VIDEO))
- return NULL;
-
- custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
- switch (amiga_chipset) {
-#ifdef CONFIG_AMIFB_OCS
- case CS_OCS:
- strcat(amiga_fb_name, "OCS");
-default_chipset:
- chipset = TAG_OCS;
- maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */
- maxdepth[TAG_HIRES] = 4;
- maxdepth[TAG_LORES] = 6;
- maxfmode = TAG_FMODE_1;
- if (!amifb_usermode) /* Set the Default Video Mode */
- get_video_mode(amiga_vblank == 50 ?
- DEFMODE_PAL : DEFMODE_NTSC);
- videomemorysize = VIDEOMEMSIZE_OCS;
- break;
-#endif /* CONFIG_AMIFB_OCS */
-
-#ifdef CONFIG_AMIFB_ECS
- case CS_ECS:
- strcat(amiga_fb_name, "ECS");
- chipset = TAG_ECS;
- maxdepth[TAG_SHRES] = 2;
- maxdepth[TAG_HIRES] = 4;
- maxdepth[TAG_LORES] = 6;
- maxfmode = TAG_FMODE_1;
- if (!amifb_usermode) { /* Set the Default Video Mode */
- if (AMIGAHW_PRESENT(AMBER_FF))
- get_video_mode(amiga_vblank == 50 ?
- DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC);
- else
- get_video_mode(amiga_vblank == 50 ?
- DEFMODE_PAL : DEFMODE_NTSC);
- }
- if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
- VIDEOMEMSIZE_ECS_1M)
- videomemorysize = VIDEOMEMSIZE_ECS_2M;
- else
- videomemorysize = VIDEOMEMSIZE_ECS_1M;
- break;
-#endif /* CONFIG_AMIFB_ECS */
-
-#ifdef CONFIG_AMIFB_AGA
- case CS_AGA:
- strcat(amiga_fb_name, "AGA");
- chipset = TAG_AGA;
- maxdepth[TAG_SHRES] = 8;
- maxdepth[TAG_HIRES] = 8;
- maxdepth[TAG_LORES] = 8;
- maxfmode = TAG_FMODE_4;
- if (!amifb_usermode) /* Set the Default Video Mode */
- get_video_mode(DEFMODE_AGA);
- if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
- VIDEOMEMSIZE_AGA_1M)
- videomemorysize = VIDEOMEMSIZE_AGA_2M;
- else
- videomemorysize = VIDEOMEMSIZE_AGA_1M;
- break;
-#endif /* CONFIG_AMIFB_AGA */
-
- default:
-#ifdef CONFIG_AMIFB_OCS
- printk("Unknown graphics chipset, defaulting to OCS\n");
- strcat(amiga_fb_name, "Unknown");
- goto default_chipset;
-#else /* CONFIG_AMIFB_OCS */
- panic("Unknown graphics chipset, no default driver");
-#endif /* CONFIG_AMIFB_OCS */
- break;
- }
-
- /*
- * Calculate the Pixel Clock Values for this Machine
- */
-
- pixclock[TAG_SHRES] = DIVUL(25E9, amiga_eclock); /* SHRES: 35 ns / 28 MHz */
- pixclock[TAG_HIRES] = DIVUL(50E9, amiga_eclock); /* HIRES: 70 ns / 14 MHz */
- pixclock[TAG_LORES] = DIVUL(100E9, amiga_eclock); /* LORES: 140 ns / 7 MHz */
-
- /*
- * Replace the Tag Values with the Real Pixel Clock Values
- */
-
- for (i = 0; i < NUM_PREDEF_MODES; i++) {
- tag = amiga_fb_predefined[i].pixclock;
- if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
- amiga_fb_predefined[i].pixclock = pixclock[tag];
- if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag])
- amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag];
- }
- }
-
- err = register_framebuffer(amiga_fb_name, &node, &amiga_fb_ops,
- NUM_TOTAL_MODES, amiga_fb_predefined);
- if (err < 0)
- panic("Cannot register frame buffer");
-
- chipptr = chipalloc(videomemorysize+
- SPRITEMEMSIZE+
- DUMMYSPRITEMEMSIZE+
- COPINITSIZE+
- 4*COPLISTSIZE);
-
- assignchunk(videomemory, u_long, chipptr, videomemorysize);
- assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
- assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
- assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
- assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
- assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
- assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
- assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
-
- memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
-
- /*
- * Enable Display DMA
- */
-
- custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
- DMAF_BLITTER | DMAF_SPRITE;
-
- /*
- * Make sure the Copper has something to do
- */
-
- ami_init_copper();
-
- check_default_mode();
-
- if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, IRQ_FLG_LOCK,
- "fb vertb handler", NULL))
- panic("Couldn't add vblank interrupt\n");
- ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
- ami_intena_vals[IRQ_AMIGA_COPPER] = 0;
- custom.intena = IF_VERTB;
- custom.intena = IF_SETCLR | IF_COPER;
-
- strcpy(fb_info.modename, amiga_fb_name);
- fb_info.changevar = NULL;
- fb_info.disp = disp;
- fb_info.switch_con = &amifbcon_switch;
- fb_info.updatevar = &amifbcon_updatevar;
- fb_info.blank = &amifbcon_blank;
- fb_info.setcmap = &amifbcon_setcmap;
-
- amiga_fb_set_var(&amiga_fb_predefined[0], 0);
-
- return &fb_info;
-}
-
-static int amifbcon_switch(int con)
-{
- /* Do we have to save the colormap? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
- currcon = con;
- ami_set_var(&disp[con].var);
- /* Install new colormap */
- do_install_cmap(con);
- return 0;
-}
-
- /*
- * Update the `var' structure (called by amicon.c)
- */
-
-static int amifbcon_updatevar(int con)
-{
- ami_pan_var(&disp[con].var);
- return 0;
-}
-
- /*
- * Blank the display.
- */
-
-static void amifbcon_blank(int blank)
-{
- do_blank = blank ? blank : -1;
-}
-
- /*
- * Set the colormap
- */
-
-static int amifbcon_setcmap(struct fb_cmap *cmap, int con)
-{
- return(amiga_fb_set_cmap(cmap, 1, con));
-}
-
-/* ---------------------------- Generic routines ---------------------------- */
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
- switch (bpp) {
- case 1:
- return &default_2_colors;
- break;
- case 2:
- return &default_4_colors;
- break;
- case 3:
- return &default_8_colors;
- break;
- default:
- return &default_16_colors;
- break;
- }
-}
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
- ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- u_short *red, *green, *blue, *transp;
- u_int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (ami_getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return 0;
- hred = CNVT_FROMHW(hred, var->red.length);
- hgreen = CNVT_FROMHW(hgreen, var->green.length);
- hblue = CNVT_FROMHW(hblue, var->blue.length);
- htransp = CNVT_FROMHW(htransp, var->transp.length);
- if (kspc) {
- *red = hred;
- *green = hgreen;
- *blue = hblue;
- if (transp)
- *transp = htransp;
- } else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp)
- put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- }
- return 0;
-}
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- u_short *red, *green, *blue, *transp;
- u_int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (kspc) {
- hred = *red;
- hgreen = *green;
- hblue = *blue;
- htransp = transp ? *transp : 0;
- } else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred = CNVT_TOHW(hred, var->red.length);
- hgreen = CNVT_TOHW(hgreen, var->green.length);
- hblue = CNVT_TOHW(hblue, var->blue.length);
- htransp = CNVT_TOHW(htransp, var->transp.length);
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- if (ami_setcolreg(start++, hred, hgreen, hblue, htransp))
- return 0;
- }
- return 0;
-}
-
-static void do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
- else
- do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- &disp[con].var, 1);
-}
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
-}
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff = 0, fromoff = 0;
-
- if (to->start > from->start)
- fromoff = to->start-from->start;
- else
- tooff = from->start-to->start;
- size = to->len-tooff;
- if (size > from->len-fromoff)
- size = from->len-fromoff;
- if (size < 0)
- return;
- size *= sizeof(u_short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
- int size = len*sizeof(u_short);
-
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return -1;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return 0;
-}
-
-static int flash_cursor(void)
-{
- static int cursorcount = 1;
-
- if (cursormode == FB_CURSOR_FLASH) {
- if (!--cursorcount) {
- cursorstate = -cursorstate;
- cursorcount = cursorrate;
- if (!is_blanked)
- return 1;
- }
- }
- return 0;
-}
-
- /*
- * VBlank Display Interrupt
- */
-
-static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
-{
- u_short ints = custom.intreqr & custom.intenar;
- static struct irq_server server = {0, 0};
- unsigned long flags;
-
- if (ints & IF_BLIT) {
- custom.intreq = IF_BLIT;
- amiga_do_irq(IRQ_AMIGA_BLIT, fp);
- }
-
- if (ints & IF_COPER) {
- custom.intreq = IF_COPER;
- if (do_vmode_pan || do_vmode_full)
- ami_update_display();
-
- if (do_vmode_full)
- ami_init_display();
-
- if (do_vmode_pan) {
- flash_cursor();
- ami_rebuild_copper();
- do_cursor = do_vmode_pan = 0;
- } else if (do_cursor) {
- flash_cursor();
- ami_set_sprite();
- do_cursor = 0;
- } else {
- if (flash_cursor())
- ami_set_sprite();
- }
-
- save_flags(flags);
- cli();
- if (get_vbpos() < down2(currentpar.diwstrt_v - 6))
- custom.copjmp2 = 0;
- restore_flags(flags);
-
- if (do_blank) {
- ami_do_blank();
- do_blank = 0;
- }
-
- if (do_vmode_full) {
- ami_reinit_copper();
- do_vmode_full = 0;
- }
- amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server);
- }
-
- if (ints & IF_VERTB) {
- printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__);
- custom.intena = IF_VERTB;
- }
-}
-
- /*
- * Get a Video Mode
- */
-
-static void get_video_mode(const char *name)
-{
- int i;
-
- for (i = 1; i < NUM_PREDEF_MODES; i++) {
- if (!strcmp(name, amiga_fb_modenames[i])) {
- amiga_fb_predefined[0] = amiga_fb_predefined[i];
- amifb_usermode = i;
- return;
- }
- }
-}
-
- /*
- * Probe the Video Modes
- */
-
-static void check_default_mode(void)
-{
- struct amiga_fb_par par;
- int mode;
-
- for (mode = 0; mode < NUM_PREDEF_MODES; mode++) {
- if (!ami_decode_var(&amiga_fb_predefined[mode], &par)) {
- if (mode)
- amiga_fb_predefined[0] = amiga_fb_predefined[mode];
- return;
- }
- if (!mode)
- printk("Can't use default video mode. Probing video modes...\n");
- }
- panic("Can't find any usable video mode");
-}
-
- /*
- * Allocate, Clear and Align a Block of Chip Memory
- */
-
-static u_long chipalloc(u_long size)
-{
- u_long ptr;
-
- size += PAGE_SIZE-1;
- if (!(ptr = (u_long)amiga_chip_alloc(size)))
- panic("No Chip RAM for frame buffer");
- memset((void *)ptr, 0, size);
- ptr = PAGE_ALIGN(ptr);
-
- return ptr;
-}
-
- /*
- * A strtok which returns empty strings, too
- */
-
-static char *strtoke(char *s,const char *ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin)
- return NULL;
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
-/* --------------------------- Hardware routines --------------------------- */
-
- /*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
- struct amiga_fb_par *par)
-{
- int i;
-
- strcpy(fix->id, amiga_fb_name);
- fix->smem_start = videomemory;
- fix->smem_len = videomemorysize;
-
- if (amifb_ilbm) {
- fix->type = FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux = par->next_line;
- } else {
- fix->type = FB_TYPE_PLANES;
- fix->type_aux = 0;
- }
- fix->line_length = div8(upx(16<<maxfmode, par->vxres));
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
- if (par->vmode & FB_VMODE_YWRAP) {
- fix->ywrapstep = 1;
- fix->xpanstep = fix->ypanstep = 0;
- } else {
- fix->ywrapstep = 0;
- if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
- fix->xpanstep = 1;
- else
- fix->xpanstep = 16<<maxfmode;
- fix->ypanstep = 1;
- }
-
- for (i = 0; i < arraysize(fix->reserved); i++)
- fix->reserved[i] = 0;
-
- return 0;
-}
-
- /*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int ami_decode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par)
-{
- u_short clk_shift, line_shift;
- u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
- u_long hrate = 0, vrate = 0;
-
- /*
- * Find a matching Pixel Clock
- */
-
- for (clk_shift = TAG_SHRES; clk_shift < TAG_LORES; clk_shift++)
- if (var->pixclock <= pixclock[clk_shift])
- break;
- if (clk_shift >= TAG_LORES)
- return -EINVAL;
- par->clk_shift = clk_shift;
-
- /*
- * Check the Geometry Values
- */
-
- if ((par->xres = var->xres) < 64)
- return -EINVAL;
- if ((par->yres = var->yres) < 64)
- return -EINVAL;
- if ((par->vxres = var->xres_virtual) < 64)
- return -EINVAL;
- if ((par->vyres = var->yres_virtual) < 64)
- return -EINVAL;
-
- par->bpp = var->bits_per_pixel;
- if (!var->nonstd) {
- if (par->bpp <= 0 || par->bpp > maxdepth[clk_shift])
- return -EINVAL;
- } else if (var->nonstd == FB_NONSTD_HAM) {
- if (par->bpp != 6)
- if (par->bpp != 8 || !IS_AGA)
- return -EINVAL;
- } else
- return -EINVAL;
-
- /*
- * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
- * checks failed and smooth scrolling is not possible
- */
-
- par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
- switch (par->vmode & FB_VMODE_MASK) {
- case FB_VMODE_INTERLACED:
- line_shift = 0;
- break;
- case FB_VMODE_NONINTERLACED:
- line_shift = 1;
- break;
- case FB_VMODE_DOUBLE:
- if (!IS_AGA)
- return -EINVAL;
- line_shift = 2;
- break;
- default:
- return -EINVAL;
- break;
- }
- par->line_shift = line_shift;
-
- /*
- * Vertical and Horizontal Timings
- */
-
- xres_n = par->xres<<clk_shift;
- yres_n = par->yres<<line_shift;
- par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
- par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
-
- if (IS_AGA)
- par->bplcon3 = sprpixmode[clk_shift];
- else
- par->bplcon3 = 0;
- if (var->sync & FB_SYNC_BROADCAST) {
- par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
- if (IS_AGA)
- par->diwstop_h += mod4(var->hsync_len);
- else
- par->diwstop_h = down4(par->diwstop_h);
- par->diwstrt_h = par->diwstop_h - xres_n;
- par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
- par->diwstrt_v = par->diwstop_v - yres_n;
- if (par->diwstop_h >= par->htotal+8 || par->diwstop_v > par->vtotal)
- return -EINVAL;
- if (!IS_OCS) {
- /* Initialize sync with some reasonable values for pwrsave */
- par->hsstrt = 160;
- par->hsstop = 320;
- par->vsstrt = 30;
- par->vsstop = 34;
- } else {
- par->hsstrt = 0;
- par->hsstop = 0;
- par->vsstrt = 0;
- par->vsstop = 0;
- }
- if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
- /* PAL video mode */
- if (par->htotal != PAL_HTOTAL)
- return -EINVAL;
- if (par->diwstrt_h < PAL_DIWSTRT_H)
- return -EINVAL;
- if (par->diwstrt_v < PAL_DIWSTRT_V)
- return -EINVAL;
- hrate = 15625;
- vrate = 50;
- if (!IS_OCS) {
- par->beamcon0 = BMC0_PAL;
- par->bplcon3 |= BPC3_BRDRBLNK;
- } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
- AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
- par->beamcon0 = BMC0_PAL;
- par->hsstop = 1;
- } else if (amiga_vblank != 50)
- return -EINVAL;
- } else {
- /* NTSC video mode
- * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
- * and NTSC activated, so than better let diwstop_h <= 1812
- */
- if (par->htotal != NTSC_HTOTAL)
- return -EINVAL;
- if (par->diwstrt_h < NTSC_DIWSTRT_H)
- return -EINVAL;
- if (par->diwstrt_v < NTSC_DIWSTRT_V)
- return -EINVAL;
- hrate = 15750;
- vrate = 60;
- if (!IS_OCS) {
- par->beamcon0 = 0;
- par->bplcon3 |= BPC3_BRDRBLNK;
- } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
- AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
- par->beamcon0 = 0;
- par->hsstop = 1;
- } else if (amiga_vblank != 60)
- return -EINVAL;
- }
- if (IS_OCS) {
- if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
- par->diwstrt_v >= 512 || par->diwstop_v < 256)
- return -EINVAL;
- }
- } else if (!IS_OCS) {
- /* Programmable video mode */
- par->hsstrt = var->right_margin<<clk_shift;
- par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
- par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
- if (!IS_AGA)
- par->diwstop_h = down4(par->diwstop_h) - 16;
- par->diwstrt_h = par->diwstop_h - xres_n;
- par->hbstop = par->diwstrt_h + 4;
- par->hbstrt = par->diwstop_h + 4;
- if (par->hbstrt >= par->htotal + 8)
- par->hbstrt -= par->htotal;
- par->hcenter = par->hsstrt + (par->htotal >> 1);
- par->vsstrt = var->lower_margin<<line_shift;
- par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
- par->diwstop_v = par->vtotal;
- if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
- par->diwstop_v -= 2;
- par->diwstrt_v = par->diwstop_v - yres_n;
- par->vbstop = par->diwstrt_v - 2;
- par->vbstrt = par->diwstop_v - 2;
- if (par->vtotal > 2048 || par->htotal > 2048)
- return -EINVAL;
- par->bplcon3 |= BPC3_EXTBLKEN;
- par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
- BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
- BMC0_PAL | BMC0_VARCSYEN;
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- par->beamcon0 |= BMC0_HSYTRUE;
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- par->beamcon0 |= BMC0_VSYTRUE;
- if (var->sync & FB_SYNC_COMP_HIGH_ACT)
- par->beamcon0 |= BMC0_CSYTRUE;
- hrate = (amiga_masterclock+par->htotal/2)/par->htotal;
- vrate = div2(par->vtotal) * par->htotal;
- vrate = (amiga_masterclock+vrate/2)/vrate;
- } else
- return -EINVAL;
-
- /*
- * Checking the DMA timing
- */
-
- fconst = 16<<maxfmode<<clk_shift;
-
- /*
- * smallest window start value without turn off other dma cycles
- * than sprite1-7, unless you change min_fstrt
- */
-
-
- fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
- fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
- if (fstrt < min_fstrt)
- return -EINVAL;
-
- /*
- * smallest window start value where smooth scrolling is possible
- */
-
- fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
- if (fstrt < min_fstrt)
- par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
- maxfetchstop = down16(par->htotal - 80);
-
- fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
- fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
- if (fstrt + fsize > maxfetchstop)
- par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
- fsize = upx(fconst, xres_n);
- if (fstrt + fsize > maxfetchstop)
- return -EINVAL;
-
- if (maxfmode + clk_shift <= 1) {
- fsize = up64(xres_n + fconst - 1);
- if (min_fstrt + fsize - 64 > maxfetchstop)
- par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
-
- fsize = up64(xres_n);
- if (min_fstrt + fsize - 64 > maxfetchstop)
- return -EINVAL;
-
- fsize -= 64;
- } else
- fsize -= fconst;
-
- /*
- * Check if there is enough time to update the bitplane pointers for ywrap
- */
-
- if (par->htotal-fsize-64 < par->bpp*64)
- par->vmode &= ~FB_VMODE_YWRAP;
-
- /*
- * Bitplane calculations and check the Memory Requirements
- */
-
- if (amifb_ilbm) {
- par->next_plane = div8(upx(16<<maxfmode, par->vxres));
- par->next_line = par->bpp*par->next_plane;
- if (par->next_line * par->vyres > videomemorysize)
- return -EINVAL;
- } else {
- par->next_line = div8(upx(16<<maxfmode, par->vxres));
- par->next_plane = par->vyres*par->next_line;
- if (par->next_plane * par->bpp > videomemorysize)
- return -EINVAL;
- }
-
- /*
- * Hardware Register Values
- */
-
- par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
- if (!IS_OCS)
- par->bplcon0 |= BPC0_ECSENA;
- if (par->bpp == 8)
- par->bplcon0 |= BPC0_BPU3;
- else
- par->bplcon0 |= par->bpp<<12;
- if (var->nonstd == FB_NONSTD_HAM)
- par->bplcon0 |= BPC0_HAM;
- if (var->sync & FB_SYNC_EXT)
- par->bplcon0 |= BPC0_ERSY;
-
- if (IS_AGA)
- par->fmode = bplfetchmode[maxfmode];
-
- switch (par->vmode & FB_VMODE_MASK) {
- case FB_VMODE_INTERLACED:
- par->bplcon0 |= BPC0_LACE;
- break;
- case FB_VMODE_DOUBLE:
- if (IS_AGA)
- par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
- break;
- }
-
- if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
- par->xoffset = var->xoffset;
- par->yoffset = var->yoffset;
- if (par->vmode & FB_VMODE_YWRAP) {
- if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
- par->xoffset = par->yoffset = 0;
- } else {
- if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
- par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
- par->xoffset = par->yoffset = 0;
- }
- } else
- par->xoffset = par->yoffset = 0;
-
- par->crsr.crsr_x = par->crsr.crsr_y = 0;
- par->crsr.spot_x = par->crsr.spot_y = 0;
- par->crsr.height = par->crsr.width = 0;
-
- if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax)
- return -EINVAL;
-
- return 0;
-}
-
- /*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int ami_encode_var(struct fb_var_screeninfo *var,
- struct amiga_fb_par *par)
-{
- u_short clk_shift, line_shift;
- int i;
-
- clk_shift = par->clk_shift;
- line_shift = par->line_shift;
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->vxres;
- var->yres_virtual = par->vyres;
- var->xoffset = par->xoffset;
- var->yoffset = par->yoffset;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- if (IS_AGA) {
- var->red.offset = 0;
- var->red.length = 8;
- var->red.msb_right = 0;
- } else {
- if (clk_shift == TAG_SHRES) {
- var->red.offset = 0;
- var->red.length = 2;
- var->red.msb_right = 0;
- } else {
- var->red.offset = 0;
- var->red.length = 4;
- var->red.msb_right = 0;
- }
- }
- var->blue = var->green = var->red;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->transp.msb_right = 0;
-
- if (par->bplcon0 & BPC0_HAM)
- var->nonstd = FB_NONSTD_HAM;
- else
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
- var->accel = 0;
-
- var->pixclock = pixclock[clk_shift];
-
- if (IS_AGA && par->fmode & FMODE_BSCAN2)
- var->vmode = FB_VMODE_DOUBLE;
- else if (par->bplcon0 & BPC0_LACE)
- var->vmode = FB_VMODE_INTERLACED;
- else
- var->vmode = FB_VMODE_NONINTERLACED;
-
- if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
- var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
- var->right_margin = par->hsstrt>>clk_shift;
- var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
- var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
- var->lower_margin = par->vsstrt>>line_shift;
- var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
- var->sync = 0;
- if (par->beamcon0 & BMC0_HSYTRUE)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (par->beamcon0 & BMC0_VSYTRUE)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
- if (par->beamcon0 & BMC0_CSYTRUE)
- var->sync |= FB_SYNC_COMP_HIGH_ACT;
- } else {
- var->sync = FB_SYNC_BROADCAST;
- var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
- var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
- var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
- var->vsync_len = 4>>line_shift;
- var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
- var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
- var->lower_margin - var->vsync_len;
- }
-
- if (par->bplcon0 & BPC0_ERSY)
- var->sync |= FB_SYNC_EXT;
- if (par->vmode & FB_VMODE_YWRAP)
- var->vmode |= FB_VMODE_YWRAP;
-
- for (i = 0; i < arraysize(var->reserved); i++)
- var->reserved[i] = 0;
-
- return 0;
-}
-
- /*
- * Get current hardware setting
- */
-
-static void ami_get_par(struct amiga_fb_par *par)
-{
- *par = currentpar;
-}
-
- /*
- * Set new videomode
- */
-
-static void ami_set_var(struct fb_var_screeninfo *var)
-{
- do_vmode_pan = 0;
- do_vmode_full = 0;
- ami_decode_var(var, &currentpar);
- ami_build_copper();
- do_vmode_full = 1;
-}
-
-#ifdef DEBUG
-static void ami_set_par(struct amiga_fb_par *par)
-{
- do_vmode_pan = 0;
- do_vmode_full = 0;
- currentpar = *par;
- ami_build_copper();
- do_vmode_full = 1;
-}
-#endif
-
- /*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- * in `var'.
- */
-
-static void ami_pan_var(struct fb_var_screeninfo *var)
-{
- struct amiga_fb_par *par = &currentpar;
-
- par->xoffset = var->xoffset;
- par->yoffset = var->yoffset;
- if (var->vmode & FB_VMODE_YWRAP)
- par->vmode |= FB_VMODE_YWRAP;
- else
- par->vmode &= ~FB_VMODE_YWRAP;
-
- do_vmode_pan = 0;
- ami_update_par();
- do_vmode_pan = 1;
-}
-
- /*
- * Update hardware
- */
-
-static int ami_update_par(void)
-{
- struct amiga_fb_par *par = &currentpar;
- short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod;
-
- clk_shift = par->clk_shift;
-
- if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
- par->xoffset = upx(16<<maxfmode, par->xoffset);
-
- fconst = 16<<maxfmode<<clk_shift;
- vshift = modx(16<<maxfmode, par->xoffset);
- fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
- fsize = (par->xres+vshift)<<clk_shift;
- shift = modx(fconst, fstrt);
- move = downx(2<<maxfmode, div8(par->xoffset));
- if (maxfmode + clk_shift > 1) {
- fstrt = downx(fconst, fstrt) - 64;
- fsize = upx(fconst, fsize);
- fstop = fstrt + fsize - fconst;
- } else {
- mod = fstrt = downx(fconst, fstrt) - fconst;
- fstop = fstrt + upx(fconst, fsize) - 64;
- fsize = up64(fsize);
- fstrt = fstop - fsize + 64;
- if (fstrt < min_fstrt) {
- fstop += min_fstrt - fstrt;
- fstrt = min_fstrt;
- }
- move = move - div8((mod-fstrt)>>clk_shift);
- }
- mod = par->next_line - div8(fsize>>clk_shift);
- par->ddfstrt = fstrt;
- par->ddfstop = fstop;
- par->bplcon1 = hscroll2hw(shift);
- par->bpl2mod = mod;
- if (par->bplcon0 & BPC0_LACE)
- par->bpl2mod += par->next_line;
- if (IS_AGA && (par->fmode & FMODE_BSCAN2))
- par->bpl1mod = -div8(fsize>>clk_shift);
- else
- par->bpl1mod = par->bpl2mod;
-
- if (par->yoffset) {
- par->bplpt0 = ZTWO_PADDR((u_long)videomemory + par->next_line*par->yoffset + move);
- if (par->vmode & FB_VMODE_YWRAP) {
- if (par->yoffset > par->vyres-par->yres) {
- par->bplpt0wrap = ZTWO_PADDR((u_long)videomemory + move);
- if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
- par->bplpt0wrap += par->next_line;
- }
- }
- } else
- par->bplpt0 = ZTWO_PADDR((u_long)videomemory + move);
-
- if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
- par->bplpt0 += par->next_line;
-
- return 0;
-}
-
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
-{
- if (IS_AGA) {
- if (regno > 255)
- return 1;
- } else {
- if (regno > 31)
- return 1;
- }
-
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
- return 0;
-}
-
-
- /*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
-{
-#if defined(CONFIG_AMIFB_AGA)
- u_short bplcon3 = currentpar.bplcon3;
-
- if (IS_AGA) {
- if (regno > 255)
- return 1;
- } else
-#endif
- if (regno > 31)
- return 1;
-
- /*
- * Update the corresponding Hardware Color Register, unless it's Color
- * Register 0 and the screen is blanked.
- *
- * VBlank is switched off to protect bplcon3 or ecs_palette[] from
- * being changed by ami_do_blank() during the VBlank.
- */
-
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
-
- if (regno || !is_blanked) {
-#if defined(CONFIG_AMIFB_AGA)
- if (IS_AGA) {
- VBlankOff();
- custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
- custom.color[regno&31] = rgb2hw8_high(red, green, blue);
- custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
- custom.color[regno&31] = rgb2hw8_low(red, green, blue);
- custom.bplcon3 = bplcon3;
- VBlankOn();
- } else
-#endif
- {
-#if defined(CONFIG_AMIFB_ECS)
- if (currentpar.bplcon0 & BPC0_SHRES) {
- u_short color, mask;
- int i;
-
- mask = 0x3333;
- color = rgb2hw2(red, green, blue);
- VBlankOff();
- for (i = regno+12; i >= (int)regno; i -= 4)
- custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
- mask <<=2; color >>= 2;
- regno = down16(regno)+mul4(mod4(regno));
- for (i = regno+3; i >= (int)regno; i--)
- custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
- VBlankOn();
- } else
-#endif
- custom.color[regno] = rgb2hw4(red, green, blue);
- }
- }
- return 0;
-}
-
-static void ami_update_display(void)
-{
- struct amiga_fb_par *par = &currentpar;
-
- custom.bplcon1 = par->bplcon1;
- custom.bpl1mod = par->bpl1mod;
- custom.bpl2mod = par->bpl2mod;
- custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
- custom.ddfstop = ddfstop2hw(par->ddfstop);
-}
-
- /*
- * Change the video mode (called by VBlank interrupt)
- */
-
-static void ami_init_display(void)
-{
- struct amiga_fb_par *par = &currentpar;
-
- custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
- custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
- if (!IS_OCS) {
- custom.bplcon3 = par->bplcon3;
- if (IS_AGA)
- custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
- if (par->beamcon0 & BMC0_VARBEAMEN) {
- custom.htotal = htotal2hw(par->htotal);
- custom.hbstrt = hbstrt2hw(par->hbstrt);
- custom.hbstop = hbstop2hw(par->hbstop);
- custom.hsstrt = hsstrt2hw(par->hsstrt);
- custom.hsstop = hsstop2hw(par->hsstop);
- custom.hcenter = hcenter2hw(par->hcenter);
- custom.vtotal = vtotal2hw(par->vtotal);
- custom.vbstrt = vbstrt2hw(par->vbstrt);
- custom.vbstop = vbstop2hw(par->vbstop);
- custom.vsstrt = vsstrt2hw(par->vsstrt);
- custom.vsstop = vsstop2hw(par->vsstop);
- }
- }
- if (!IS_OCS || par->hsstop)
- custom.beamcon0 = par->beamcon0;
- if (IS_AGA)
- custom.fmode = par->fmode;
-
- /*
- * The minimum period for audio depends on htotal
- */
-
- amiga_audio_min_period = div16(par->htotal);
-
- is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
-#if 1
- if (is_lace) {
- if (custom.vposr & 0x8000)
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
- else
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
- } else {
- custom.vposw = custom.vposr | 0x8000;
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
- }
-#else
- custom.vposw = custom.vposr | 0x8000;
- custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-#endif
-}
-
- /*
- * (Un)Blank the screen (called by VBlank interrupt)
- */
-
-static void ami_do_blank(void)
-{
- struct amiga_fb_par *par = &currentpar;
-#if defined(CONFIG_AMIFB_AGA)
- u_short bplcon3 = par->bplcon3;
-#endif
- u_char red, green, blue;
-
- if (do_blank > 0) {
- custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
- red = green = blue = 0;
- if (!IS_OCS && do_blank > 1) {
- switch (do_blank) {
- case 2 : /* suspend vsync */
- custom.hsstrt = hsstrt2hw(par->hsstrt);
- custom.hsstop = hsstop2hw(par->hsstop);
- custom.vsstrt = vsstrt2hw(par->vtotal+4);
- custom.vsstop = vsstop2hw(par->vtotal+4);
- break;
- case 3 : /* suspend hsync */
- custom.hsstrt = hsstrt2hw(par->htotal+16);
- custom.hsstop = hsstop2hw(par->htotal+16);
- custom.vsstrt = vsstrt2hw(par->vsstrt);
- custom.vsstop = vsstrt2hw(par->vsstop);
- break;
- case 4 : /* powerdown */
- custom.hsstrt = hsstrt2hw(par->htotal+16);
- custom.hsstop = hsstop2hw(par->htotal+16);
- custom.vsstrt = vsstrt2hw(par->vtotal+4);
- custom.vsstop = vsstop2hw(par->vtotal+4);
- break;
- }
- if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
- custom.htotal = htotal2hw(par->htotal);
- custom.vtotal = vtotal2hw(par->vtotal);
- custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
- BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
- }
- }
- } else {
- custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
- red = palette[0].red;
- green = palette[0].green;
- blue = palette[0].blue;
- if (!IS_OCS) {
- custom.hsstrt = hsstrt2hw(par->hsstrt);
- custom.hsstop = hsstop2hw(par->hsstop);
- custom.vsstrt = vsstrt2hw(par->vsstrt);
- custom.vsstop = vsstop2hw(par->vsstop);
- custom.beamcon0 = par->beamcon0;
- }
- }
-#if defined(CONFIG_AMIFB_AGA)
- if (IS_AGA) {
- custom.bplcon3 = bplcon3;
- custom.color[0] = rgb2hw8_high(red, green, blue);
- custom.bplcon3 = bplcon3 | BPC3_LOCT;
- custom.color[0] = rgb2hw8_low(red, green, blue);
- custom.bplcon3 = bplcon3;
- } else
-#endif
- {
-#if defined(CONFIG_AMIFB_ECS)
- if (par->bplcon0 & BPC0_SHRES) {
- u_short color, mask;
- int i;
-
- mask = 0x3333;
- color = rgb2hw2(red, green, blue);
- for (i = 12; i >= 0; i -= 4)
- custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
- mask <<=2; color >>= 2;
- for (i = 3; i >= 0; i--)
- custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
- } else
-#endif
- custom.color[0] = rgb2hw4(red, green, blue);
- }
- is_blanked = do_blank > 0 ? do_blank : 0;
-}
-
- /*
- * Flash the cursor (called by VBlank interrupt)
- */
-
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
-{
- struct amiga_fb_par *par = &currentpar;
-
- fix->crsr_width = fix->crsr_xsize = par->crsr.width;
- fix->crsr_height = fix->crsr_ysize = par->crsr.height;
- fix->crsr_color1 = 17;
- fix->crsr_color2 = 18;
- return 0;
-}
-
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
- struct amiga_fb_par *par = &currentpar;
- register u_short *lspr, *sspr;
- register u_long datawords asm ("d2");
- register short delta;
- register u_char color;
- short height, width, bits, words;
- int i, size, alloc;
-
- size = par->crsr.height*par->crsr.width;
- alloc = var->height*var->width;
- var->height = par->crsr.height;
- var->width = par->crsr.width;
- var->xspot = par->crsr.spot_x;
- var->yspot = par->crsr.spot_y;
- if (size > var->height*var->width)
- return -ENAMETOOLONG;
- if ((i = verify_area(VERIFY_WRITE, (void *)data, size)))
- return i;
- delta = 1<<par->crsr.fmode;
- lspr = lofsprite + (delta<<1);
- if (par->bplcon0 & BPC0_LACE)
- sspr = shfsprite + (delta<<1);
- else
- sspr = 0;
- for (height = (short)var->height-1; height >= 0; height--) {
- bits = 0; words = delta; datawords = 0;
- for (width = (short)var->width-1; width >= 0; width--) {
- if (bits == 0) {
- bits = 16; --words;
- asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
- : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
- }
- --bits;
- asm volatile (
- "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
- "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
- : "=d" (color), "=d" (datawords) : "1" (datawords));
- put_user(color, data++);
- }
- if (bits > 0) {
- --words; ++lspr;
- }
- while (--words >= 0)
- ++lspr;
- asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
- : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
- }
- return 0;
-}
-
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
-{
- struct amiga_fb_par *par = &currentpar;
- register u_short *lspr, *sspr;
- register u_long datawords asm ("d2");
- register short delta;
- u_short fmode;
- short height, width, bits, words;
- int i;
-
- if (!var->width)
- return -EINVAL;
- else if (var->width <= 16)
- fmode = TAG_FMODE_1;
- else if (var->width <= 32)
- fmode = TAG_FMODE_2;
- else if (var->width <= 64)
- fmode = TAG_FMODE_4;
- else
- return -EINVAL;
- if (fmode > maxfmode)
- return -EINVAL;
- if (!var->height)
- return -EINVAL;
- if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height)))
- return i;
- delta = 1<<fmode;
- lofsprite = shfsprite = (u_short *)spritememory;
- lspr = lofsprite + (delta<<1);
- if (par->bplcon0 & BPC0_LACE) {
- if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
- return -EINVAL;
- memset(lspr, 0, (var->height+4)<<fmode<<2);
- shfsprite += ((var->height+5)&-2)<<fmode;
- sspr = shfsprite + (delta<<1);
- } else {
- if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
- return -EINVAL;
- memset(lspr, 0, (var->height+2)<<fmode<<2);
- sspr = 0;
- }
- for (height = (short)var->height-1; height >= 0; height--) {
- bits = 16; words = delta; datawords = 0;
- for (width = (short)var->width-1; width >= 0; width--) {
- unsigned long tdata = 0;
- get_user(tdata, (char *)data);
- data++;
- asm volatile (
- "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
- "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
- : "=d" (datawords)
- : "0" (datawords), "d" (tdata));
- if (--bits == 0) {
- bits = 16; --words;
- asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
- : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
- }
- }
- if (bits < 16) {
- --words;
- asm volatile (
- "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
- "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
- : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
- }
- while (--words >= 0)
- asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
- : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
- asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
- : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
- }
- par->crsr.height = var->height;
- par->crsr.width = var->width;
- par->crsr.spot_x = var->xspot;
- par->crsr.spot_y = var->yspot;
- par->crsr.fmode = fmode;
- if (IS_AGA) {
- par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
- par->fmode |= sprfetchmode[fmode];
- custom.fmode = par->fmode;
- }
- return 0;
-}
-
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
-{
- struct amiga_fb_par *par = &currentpar;
-
- state->xoffset = par->crsr.crsr_x;
- state->yoffset = par->crsr.crsr_y;
- state->mode = cursormode;
- return 0;
-}
-
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
-{
- struct amiga_fb_par *par = &currentpar;
-
- par->crsr.crsr_x = state->xoffset;
- par->crsr.crsr_y = state->yoffset;
- if ((cursormode = state->mode) == FB_CURSOR_OFF)
- cursorstate = -1;
- do_cursor = 1;
- return 0;
-}
-
-static void ami_set_sprite(void)
-{
- struct amiga_fb_par *par = &currentpar;
- copins *copl, *cops;
- u_short hs, vs, ve;
- u_long pl, ps, pt;
- short mx, my;
-
- cops = copdisplay.list[currentcop][0];
- copl = copdisplay.list[currentcop][1];
- ps = pl = ZTWO_PADDR(dummysprite);
- mx = par->crsr.crsr_x-par->crsr.spot_x;
- my = par->crsr.crsr_y-par->crsr.spot_y;
- if (!(par->vmode & FB_VMODE_YWRAP)) {
- mx -= par->xoffset;
- my -= par->yoffset;
- }
- if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
- mx > -(short)par->crsr.width && mx < par->xres &&
- my > -(short)par->crsr.height && my < par->yres) {
- pl = ZTWO_PADDR(lofsprite);
- hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
- vs = par->diwstrt_v + (my<<par->line_shift);
- ve = vs + (par->crsr.height<<par->line_shift);
- if (par->bplcon0 & BPC0_LACE) {
- ps = ZTWO_PADDR(shfsprite);
- lofsprite[0] = spr2hw_pos(vs, hs);
- shfsprite[0] = spr2hw_pos(vs+1, hs);
- if (mod2(vs)) {
- lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
- shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
- pt = pl; pl = ps; ps = pt;
- } else {
- lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
- shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
- }
- } else {
- lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
- lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
- }
- }
- copl[cop_spr0ptrh].w[1] = highw(pl);
- copl[cop_spr0ptrl].w[1] = loww(pl);
- if (par->bplcon0 & BPC0_LACE) {
- cops[cop_spr0ptrh].w[1] = highw(ps);
- cops[cop_spr0ptrl].w[1] = loww(ps);
- }
-}
-
- /*
- * Initialise the Copper Initialisation List
- */
-
-static void ami_init_copper(void)
-{
- copins *cop = copdisplay.init;
- u_long p;
- int i;
-
- if (!IS_OCS) {
- (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
- (cop++)->l = CMOVE(0x0181, diwstrt);
- (cop++)->l = CMOVE(0x0281, diwstop);
- (cop++)->l = CMOVE(0x0000, diwhigh);
- } else
- (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
- p = ZTWO_PADDR(dummysprite);
- for (i = 0; i < 8; i++) {
- (cop++)->l = CMOVE(0, spr[i].pos);
- (cop++)->l = CMOVE(highw(p), sprpt[i]);
- (cop++)->l = CMOVE2(loww(p), sprpt[i]);
- }
-
- (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
- copdisplay.wait = cop;
- (cop++)->l = CEND;
- (cop++)->l = CMOVE(0, copjmp2);
- cop->l = CEND;
-
- custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
- custom.copjmp1 = 0;
-}
-
-static void ami_reinit_copper(void)
-{
- struct amiga_fb_par *par = &currentpar;
-
- copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
- copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
-}
-
- /*
- * Build the Copper List
- */
-
-static void ami_build_copper(void)
-{
- struct amiga_fb_par *par = &currentpar;
- copins *copl, *cops;
- u_long p;
-
- currentcop = 1 - currentcop;
-
- copl = copdisplay.list[currentcop][1];
-
- (copl++)->l = CWAIT(0, 10);
- (copl++)->l = CMOVE(par->bplcon0, bplcon0);
- (copl++)->l = CMOVE(0, sprpt[0]);
- (copl++)->l = CMOVE2(0, sprpt[0]);
-
- if (par->bplcon0 & BPC0_LACE) {
- cops = copdisplay.list[currentcop][0];
-
- (cops++)->l = CWAIT(0, 10);
- (cops++)->l = CMOVE(par->bplcon0, bplcon0);
- (cops++)->l = CMOVE(0, sprpt[0]);
- (cops++)->l = CMOVE2(0, sprpt[0]);
-
- (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
- (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
- (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
- (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
- if (!IS_OCS) {
- (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
- par->diwstop_h, par->diwstop_v+1), diwhigh);
- (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
- par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
- if (par->beamcon0 & BMC0_VARBEAMEN) {
- (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
- (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
- (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
- (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
- (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
- (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
- }
-#endif
- }
- p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
- (copl++)->l = CMOVE(highw(p), cop2lc);
- (copl++)->l = CMOVE2(loww(p), cop2lc);
- p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
- (cops++)->l = CMOVE(highw(p), cop2lc);
- (cops++)->l = CMOVE2(loww(p), cop2lc);
- copdisplay.rebuild[0] = cops;
- } else {
- (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
- (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
- if (!IS_OCS) {
- (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
- par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
- if (par->beamcon0 & BMC0_VARBEAMEN) {
- (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
- (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
- (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
- }
-#endif
- }
- }
- copdisplay.rebuild[1] = copl;
-
- ami_update_par();
- ami_rebuild_copper();
-}
-
- /*
- * Rebuild the Copper List
- *
- * We only change the things that are not static
- */
-
-static void ami_rebuild_copper(void)
-{
- struct amiga_fb_par *par = &currentpar;
- copins *copl, *cops;
- u_short line, h_end1, h_end2;
- short i;
- u_long p;
-
- if (IS_AGA && maxfmode + par->clk_shift == 0)
- h_end1 = par->diwstrt_h-64;
- else
- h_end1 = par->htotal-32;
- h_end2 = par->ddfstop+64;
-
- ami_set_sprite();
-
- copl = copdisplay.rebuild[1];
- p = par->bplpt0;
- if (par->vmode & FB_VMODE_YWRAP) {
- if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
- if (par->yoffset > par->vyres-par->yres) {
- for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
- (copl++)->l = CMOVE(highw(p), bplpt[i]);
- (copl++)->l = CMOVE2(loww(p), bplpt[i]);
- }
- line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
- while (line >= 512) {
- (copl++)->l = CWAIT(h_end1, 510);
- line -= 512;
- }
- if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
- (copl++)->l = CWAIT(h_end1, line);
- else
- (copl++)->l = CWAIT(h_end2, line);
- p = par->bplpt0wrap;
- }
- } else p = par->bplpt0wrap;
- }
- for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
- (copl++)->l = CMOVE(highw(p), bplpt[i]);
- (copl++)->l = CMOVE2(loww(p), bplpt[i]);
- }
- copl->l = CEND;
-
- if (par->bplcon0 & BPC0_LACE) {
- cops = copdisplay.rebuild[0];
- p = par->bplpt0;
- if (mod2(par->diwstrt_v))
- p -= par->next_line;
- else
- p += par->next_line;
- if (par->vmode & FB_VMODE_YWRAP) {
- if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
- if (par->yoffset > par->vyres-par->yres+1) {
- for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
- (cops++)->l = CMOVE(highw(p), bplpt[i]);
- (cops++)->l = CMOVE2(loww(p), bplpt[i]);
- }
- line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
- while (line >= 512) {
- (cops++)->l = CWAIT(h_end1, 510);
- line -= 512;
- }
- if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
- (cops++)->l = CWAIT(h_end1, line);
- else
- (cops++)->l = CWAIT(h_end2, line);
- p = par->bplpt0wrap;
- if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
- p -= par->next_line;
- else
- p += par->next_line;
- }
- } else p = par->bplpt0wrap - par->next_line;
- }
- for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
- (cops++)->l = CMOVE(highw(p), bplpt[i]);
- (cops++)->l = CMOVE2(loww(p), bplpt[i]);
- }
- cops->l = CEND;
- }
-}
diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c
deleted file mode 100644
index 5a102a12c..000000000
--- a/arch/m68k/amiga/amikeyb.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * linux/arch/m68k/amiga/amikeyb.c
- *
- * Amiga Keyboard driver for Linux/m68k
- *
- * 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.
- */
-
-/*
- * Amiga support by Hamish Macdonald
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/keyboard.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/kd.h>
-#include <linux/random.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-
-#define AMIKEY_CAPS (0x62)
-#define BREAK_MASK (0x80)
-#define RESET_WARNING (0xf0) /* before rotation */
-
-static u_short amiplain_map[NR_KEYS] __initdata = {
- 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
- 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
- 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
- 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
- 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
- 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
- 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
- 0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_map[NR_KEYS] = {
- 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
- 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
- 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
- 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
- 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
- 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
- 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
- 0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialtgr_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
- 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
- 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
- 0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_map[NR_KEYS] = {
- 0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
- 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
- 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
- 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
- 0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
- 0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
- 0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
- 0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_ctrl_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
- 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialt_map[NR_KEYS] = {
- 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
- 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
- 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
- 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
- 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
- 0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
- 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
- 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
- 0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
- 0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_alt_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
- 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
- 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-#define DEFAULT_KEYB_REP_DELAY (HZ/4)
-#define DEFAULT_KEYB_REP_RATE (HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static void amikeyb_rep(unsigned long ignore);
-static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
-
-static void amikeyb_rep(unsigned long ignore)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
-
- kbd_pt_regs = NULL;
-
- amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
- amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
- add_timer(&amikeyb_rep_timer);
- handle_scancode(rep_scancode);
-
- restore_flags(flags);
-}
-
-static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
- unsigned char scancode, break_flag, keycode;
- static int reset_warning = 0;
-
- /* save frame for register dump */
- kbd_pt_regs = fp;
-
- /* get and invert scancode (keyboard is active low) */
- scancode = ~ciaa.sdr;
-
- /* switch SP pin to output for handshake */
- ciaa.cra |= 0x40;
-
-#if 0 // No longer used
- /*
- * On receipt of the second RESET_WARNING, we must not pull KDAT high
- * again to delay the hard reset as long as possible.
- *
- * Note that not all keyboards send reset warnings...
- */
- if (reset_warning)
- if (scancode == RESET_WARNING) {
- printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
- "The system will be reset within 10 seconds!!\n");
- /* Panic doesn't sync from within an interrupt, so we do nothing */
- return;
- } else
- /* Probably a mistake, cancel the alert */
- reset_warning = 0;
-#endif
-
- /* wait until 85 us have expired */
- udelay(85);
- /* switch CIA serial port to input mode */
- ciaa.cra &= ~0x40;
-
- mark_bh(KEYBOARD_BH);
-
- /* rotate scan code to get up/down bit in proper position */
- __asm__ __volatile__ ("rorb #1,%0" : "=g" (scancode) : "0" (scancode));
-
- /*
- * Check make/break first
- */
- break_flag = scancode & BREAK_MASK;
- keycode = scancode & (unsigned char)~BREAK_MASK;
-
- if (keycode == AMIKEY_CAPS) {
- /* if the key is CAPS, fake a press/release. */
- handle_scancode(AMIKEY_CAPS);
- handle_scancode(BREAK_MASK | AMIKEY_CAPS);
- } else if (keycode < 0x78) {
- /* handle repeat */
- if (break_flag) {
- del_timer(&amikeyb_rep_timer);
- rep_scancode = 0;
- } else {
- del_timer(&amikeyb_rep_timer);
- rep_scancode = keycode;
- amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
- amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
- add_timer(&amikeyb_rep_timer);
- }
- handle_scancode(scancode);
- } else
- switch (keycode) {
- case 0x78:
- reset_warning = 1;
- break;
- case 0x79:
- printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
- break;
- case 0x7a:
- printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
- break;
-#if 0 /* obsolete according to the HRM */
- case 0x7b:
- printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
- break;
-#endif
- case 0x7c:
- printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
- break;
- case 0x7d:
- printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
- break;
- case 0x7e:
- printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
- break;
-#if 0 /* obsolete according to the HRM */
- case 0x7f:
- printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
- break;
-#endif
- default:
- printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
- scancode);
- break;
- }
-}
-
-__initfunc(int amiga_keyb_init(void))
-{
- if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
- return -EIO;
-
- /* setup key map */
- memcpy(plain_map, amiplain_map, sizeof(plain_map));
- key_maps[1] = amishift_map;
- key_maps[2] = amialtgr_map;
- key_maps[4] = amictrl_map;
- key_maps[5] = amishift_ctrl_map;
- key_maps[8] = amialt_map;
- key_maps[12] = amictrl_alt_map;
-
- /*
- * Initialize serial data direction.
- */
- ciaa.cra &= ~0x41; /* serial data in, turn off TA */
-
- /*
- * arrange for processing of keyboard interrupt
- */
- request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
-
- return 0;
-}
-
-int amiga_kbdrate( struct kbd_repeat *k )
-{
- if (k->delay > 0) {
- /* convert from msec to jiffies */
- key_repeat_delay = (k->delay * HZ + 500) / 1000;
- if (key_repeat_delay < 1)
- key_repeat_delay = 1;
- }
- if (k->rate > 0) {
- key_repeat_rate = (k->rate * HZ + 500) / 1000;
- if (key_repeat_rate < 1)
- key_repeat_rate = 1;
- }
-
- k->delay = key_repeat_delay * 1000 / HZ;
- k->rate = key_repeat_rate * 1000 / HZ;
-
- return( 0 );
-}
diff --git a/arch/m68k/amiga/cyberfb.c b/arch/m68k/amiga/cyberfb.c
deleted file mode 100644
index b7802a67c..000000000
--- a/arch/m68k/amiga/cyberfb.c
+++ /dev/null
@@ -1,1253 +0,0 @@
-/*
- * linux/arch/m68k/amiga/cyberfb.c -- Low level implementation of the
- * Cybervision frame buffer device
- *
- * Copyright (C) 1996 Martin Apel
- * Geert Uytterhoeven
- *
- *
- * This file is based on the Amiga frame buffer device (amifb.c):
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * History:
- * - 22 Dec 95: Original version by Martin Apel
- * - 05 Jan 96: Geert: integration into the current source tree
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/zorro.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include "s3blit.h"
-
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-struct Cyber_fb_par {
- int xres;
- int yres;
- int bpp;
-};
-
-static struct Cyber_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node; /* node of the /dev/fb?current file */
-
-
- /*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
-
- int (*init)(void);
-
- /* Display Control */
-
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct Cyber_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par);
- int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
- int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
- void (*blank)(int blank);
-} *fbhw;
-
-
- /*
- * Frame Buffer Name
- */
-
-static char Cyber_fb_name[16] = "Cybervision";
-
-
- /*
- * Cybervision Graphics Board
- */
-
-#define CYBER8_WIDTH 1152
-#define CYBER8_HEIGHT 886
-#define CYBER8_PIXCLOCK 12500 /* ++Geert: Just a guess */
-
-#define CYBER16_WIDTH 800
-#define CYBER16_HEIGHT 600
-#define CYBER16_PIXCLOCK 25000 /* ++Geert: Just a guess */
-
-
-static int CyberKey = 0;
-static u_char Cyber_colour_table [256][4];
-static unsigned long CyberMem;
-static unsigned long CyberSize;
-static volatile char *CyberRegs;
-
-static long *memstart;
-
-
- /*
- * Predefined Video Mode Names
- */
-
-static char *Cyber_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "cyber8", /* Cybervision 8 bpp */
- "cyber16", /* Cybervision 16 bpp */
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7"
-};
-
-
- /*
- * Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo Cyber_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- {
- /* Cybervision 8 bpp */
- CYBER8_WIDTH, CYBER8_HEIGHT, CYBER8_WIDTH, CYBER8_HEIGHT, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }, {
- /* Cybervision 16 bpp */
- CYBER16_WIDTH, CYBER16_HEIGHT, CYBER16_WIDTH, CYBER16_HEIGHT, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
-
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES arraysize(Cyber_fb_predefined)
-#define NUM_PREDEF_MODES (3)
-
-
-static int Cyberfb_inverse = 0;
-static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */
-static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */
-static int Cyberfb_mode = 0;
-
-
- /*
- * Some default modes
- */
-
-#define CYBER8_DEFMODE (1)
-#define CYBER16_DEFMODE (2)
-
-
- /*
- * Interface used by the world
- */
-
-int Cyber_probe(void);
-void Cyber_video_setup(char *options, int *ints);
-
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, int con);
-
-
- /*
- * Interface to the low level console driver
- */
-
-struct fb_info *Cyber_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int Cyberfb_switch(int con);
-static int Cyberfb_updatevar(int con);
-static void Cyberfb_blank(int blank);
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con);
-
-
- /*
- * Accelerated Functions used by the low level console driver
- */
-
-void Cyber_WaitQueue(u_short fifo);
-void Cyber_WaitBlit(void);
-void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short mode);
-void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color);
-void Cyber_MoveCursor(u_short x, u_short y);
-
-
- /*
- * Hardware Specific Routines
- */
-
-static int Cyber_init(void);
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct Cyber_fb_par *par);
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par);
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par);
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp);
-static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp);
-static void Cyber_blank(int blank);
-
-
- /*
- * Internal routines
- */
-
-static void Cyber_fb_get_par(struct Cyber_fb_par *par);
-static void Cyber_fb_set_par(struct Cyber_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void Cyber_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-
- /*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int Cyber_init(void)
-{
-int i;
-char size;
-volatile u_long *CursorBase;
-unsigned long board_addr;
-struct ConfigDev *cd;
-
-if (Cyberfb_mode == -1)
- {
- if (Cyberfb_Cyber8)
- Cyberfb_mode = CYBER8_DEFMODE;
- else
- Cyberfb_mode = CYBER16_DEFMODE;
- }
-
-cd = zorro_get_board (CyberKey);
-zorro_config_board (CyberKey, 0);
-board_addr = (unsigned long)cd->cd_BoardAddr;
-
-for (i = 0; i < 256; i++)
-
-for (i = 0; i < 256; i++)
- {
- Cyber_colour_table [i][0] = i;
- Cyber_colour_table [i][1] = i;
- Cyber_colour_table [i][2] = i;
- Cyber_colour_table [i][3] = 0;
- }
-
-*memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-/* This includes the video memory as well as the S3 register set */
-CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000,
- KERNELMAP_NOCACHE_SER, memstart);
-
-if (Cyberfb_Cyber8)
- memset ((char*)CyberMem, 0, CYBER8_WIDTH * CYBER8_HEIGHT);
-else
- memset ((char*)CyberMem, 0, CYBER16_WIDTH * CYBER16_HEIGHT);
-
-CyberRegs = (char*) (CyberMem + 0x00c00000);
-
-/* Disable hardware cursor */
-*(CyberRegs + S3_CRTC_ADR) = S3_REG_LOCK2;
-*(CyberRegs + S3_CRTC_DATA) = 0xa0;
-*(CyberRegs + S3_CRTC_ADR) = S3_HGC_MODE;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DX;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DY;
-*(CyberRegs + S3_CRTC_DATA) = 0x00;
-
-/* Set clipping rectangle to current screen size */
-*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x1000;
-*((u_short volatile *)(CyberRegs + 0xbee8)) = 0x2000;
-if (Cyberfb_Cyber8)
- {
- *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (CYBER8_HEIGHT - 1);
- *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (CYBER8_WIDTH - 1);
- }
-else
- {
- *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (CYBER16_HEIGHT - 1);
- *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (CYBER16_WIDTH - 1);
- }
-
-/* Get memory size (if not 2MB it is 4MB) */
-*(CyberRegs + S3_CRTC_ADR) = S3_LAW_CTL;
-size = *(CyberRegs + S3_CRTC_DATA);
-if ((size & 0x03) == 0x02)
- CyberSize = 0x00200000; /* 2 MB */
-else
- CyberSize = 0x00400000; /* 4 MB */
-
-/* Initialize hardware cursor */
-CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
-for (i=0; i < 8; i++)
- {
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-for (i=8; i < 64; i++)
- {
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-
-Cyber_setcolreg (255, 56, 100, 160, 0);
-Cyber_setcolreg (254, 0, 0, 0, 0);
-
-return (0);
-}
-
-
- /*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct Cyber_fb_par *par)
-{
- int i;
-
- strcpy(fix->id, Cyber_fb_name);
- fix->smem_start = CyberMem;
-#if 0
- fix->smem_len = CyberSize;
-#else
- fix->smem_len = 0x01000000;
-#endif
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_DIRECTCOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
-
- for (i = 0; i < arraysize(fix->reserved); i++)
- fix->reserved[i] = 0;
-
- return(0);
-}
-
-
- /*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par)
-{
- if (Cyberfb_Cyber8) {
- par->xres = CYBER8_WIDTH;
- par->yres = CYBER8_HEIGHT;
- par->bpp = 8;
- } else {
- par->xres = CYBER16_WIDTH;
- par->yres = CYBER16_HEIGHT;
- par->bpp = 16;
- }
- return(0);
-}
-
-
- /*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct Cyber_fb_par *par)
-{
- int i;
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres;
- var->yres_virtual = par->yres;
- var->xoffset = 0;
- var->yoffset = 0;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- if (par->bpp == 8) {
- var->red.offset = 0;
- var->red.length = 8;
- var->red.msb_right = 0;
- var->blue = var->green = var->red;
- } else {
- var->red.offset = 11;
- var->red.length = 5;
- var->red.msb_right = 0;
- var->green.offset = 5;
- var->green.length = 6;
- var->green.msb_right = 0;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->blue.msb_right = 0;
- }
- var->transp.offset = 0;
- var->transp.length = 0;
- var->transp.msb_right = 0;
-
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
- var->accel = FB_ACCEL_CYBERVISION;
- var->vmode = FB_VMODE_NONINTERLACED;
-
- /* Dummy values */
-
- if (par->bpp == 8)
- var->pixclock = CYBER8_PIXCLOCK;
- else
- var->pixclock = CYBER16_PIXCLOCK;
- var->sync = 0;
- var->left_margin = 64;
- var->right_margin = 96;
- var->upper_margin = 35;
- var->lower_margin = 12;
- var->hsync_len = 112;
- var->vsync_len = 2;
-
- for (i = 0; i < arraysize(var->reserved); i++)
- var->reserved[i] = 0;
-
- return(0);
-}
-
-
- /*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp)
-{
-if (regno > 255)
- return (1);
-
-*(CyberRegs + 0x3c8) = (char)regno;
-Cyber_colour_table [regno][0] = red & 0xff;
-Cyber_colour_table [regno][1] = green & 0xff;
-Cyber_colour_table [regno][2] = blue & 0xff;
-Cyber_colour_table [regno][3] = transp;
-
-*(CyberRegs + 0x3c9) = (red & 0xff) >> 2;
-*(CyberRegs + 0x3c9) = (green & 0xff) >> 2;
-*(CyberRegs + 0x3c9) = (blue & 0xff) >> 2;
-
-return (0);
-}
-
-
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp)
-{
-if (regno >= 256)
- return (1);
-*red = Cyber_colour_table [regno][0];
-*green = Cyber_colour_table [regno][1];
-*blue = Cyber_colour_table [regno][2];
-*transp = Cyber_colour_table [regno][3];
-return (0);
-}
-
-
- /*
- * (Un)Blank the screen
- */
-
-void Cyber_blank(int blank)
-{
-int i;
-
-if (blank)
- for (i = 0; i < 256; i++)
- {
- *(CyberRegs + 0x3c8) = i;
- *(CyberRegs + 0x3c9) = 0;
- *(CyberRegs + 0x3c9) = 0;
- *(CyberRegs + 0x3c9) = 0;
- }
-else
- for (i = 0; i < 256; i++)
- {
- *(CyberRegs + 0x3c8) = i;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][0] >> 2;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][1] >> 2;
- *(CyberRegs + 0x3c9) = Cyber_colour_table [i][2] >> 2;
- }
-}
-
-
-/**************************************************************
- * We are waiting for "fifo" FIFO-slots empty
- */
-void Cyber_WaitQueue (u_short fifo)
-{
-u_short status;
-
-do
- {
- status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- }
-while (status & fifo);
-}
-
-/**************************************************************
- * We are waiting for Hardware (Graphics Engine) not busy
- */
-void Cyber_WaitBlit (void)
-{
-u_short status;
-
-do
- {
- status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- }
-while (status & S3_HDW_BUSY);
-}
-
-/**************************************************************
- * BitBLT - Through the Plane
- */
-void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short mode)
-{
-u_short blitcmd = S3_BITBLT;
-
-/* Set drawing direction */
-/* -Y, X maj, -X (default) */
-if (curx > destx)
- blitcmd |= 0x0020; /* Drawing direction +X */
-else
- {
- curx += (width - 1);
- destx += (width - 1);
- }
-
-if (cury > desty)
- blitcmd |= 0x0080; /* Drawing direction +Y */
-else
- {
- cury += (height - 1);
- desty += (height - 1);
- }
-
-Cyber_WaitQueue (0x8000);
-
-*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0060 | mode);
-
-*((u_short volatile *)(CyberRegs + S3_CUR_X)) = curx;
-*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = cury;
-
-*((u_short volatile *)(CyberRegs + S3_DESTX_DIASTP)) = destx;
-*((u_short volatile *)(CyberRegs + S3_DESTY_AXSTP)) = desty;
-
-*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1;
-
-*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
-}
-
-/**************************************************************
- * Rectangle Fill Solid
- */
-void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short fcolor)
-{
-u_short blitcmd = S3_FILLEDRECT;
-
-Cyber_WaitQueue (0x8000);
-
-*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0020 | mode);
-
-*((u_short volatile *)(CyberRegs + S3_MULT_MISC)) = 0xe000;
-*((u_short volatile *)(CyberRegs + S3_FRGD_COLOR)) = color;
-
-*((u_short volatile *)(CyberRegs + S3_CUR_X)) = x;
-*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = y;
-
-*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1;
-
-*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
-}
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void Cyber_MoveCursor (u_short x, u_short y)
-{
-*(CyberRegs + S3_CRTC_ADR) = 0x39;
-*(CyberRegs + S3_CRTC_DATA) = 0xa0;
-
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
-*(CyberRegs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
-*(CyberRegs + S3_CRTC_DATA) = (char)(x & 0x00ff);
-
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
-*(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
-*(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
-*(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff);
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch Cyber_switch = {
- Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
- Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
- /*
- * Fill the hardware's `par' structure.
- */
-
-static void Cyber_fb_get_par(struct Cyber_fb_par *par)
-{
- if (current_par_valid)
- *par = current_par;
- else
- fbhw->decode_var(&Cyber_fb_predefined[Cyberfb_mode], par);
-}
-
-
-static void Cyber_fb_set_par(struct Cyber_fb_par *par)
-{
- current_par = *par;
- current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct Cyber_fb_par par;
-
- if ((err = fbhw->decode_var(var, &par)))
- return(err);
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- Cyber_fb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate = activate;
- return(0);
-}
-
-
- /*
- * Default Colormaps
- */
-
-static u_short red16[] =
- { 0xc000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0x0000,
- 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff};
-static u_short green16[] =
- { 0xc000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0x0000,
- 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff};
-static u_short blue16[] =
- { 0xc000, 0x0000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0x0000,
- 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff};
-
-
-static struct fb_cmap default_16_colors =
- { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
- return(&default_16_colors);
-}
-
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
- ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- u_short *red, *green, *blue, *transp;
- u_int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
- if (start < 0)
- return(-EINVAL);
- for (i = 0; i < cmap->len; i++) {
- if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return(0);
- hred = CNVT_FROMHW(hred, var->red.length);
- hgreen = CNVT_FROMHW(hgreen, var->green.length);
- hblue = CNVT_FROMHW(hblue, var->blue.length);
- htransp = CNVT_FROMHW(htransp, var->transp.length);
- if (kspc) {
- *red = hred;
- *green = hgreen;
- *blue = hblue;
- if (transp)
- *transp = htransp;
- } else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp)
- put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- }
- return(0);
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- u_short *red, *green, *blue, *transp;
- u_int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return(-EINVAL);
- for (i = 0; i < cmap->len; i++) {
- if (kspc) {
- hred = *red;
- hgreen = *green;
- hblue = *blue;
- htransp = transp ? *transp : 0;
- } else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred = CNVT_TOHW(hred, var->red.length);
- hgreen = CNVT_TOHW(hgreen, var->green.length);
- hblue = CNVT_TOHW(hblue, var->blue.length);
- htransp = CNVT_TOHW(htransp, var->transp.length);
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
- return(0);
- }
- return(0);
-}
-
-
-static void do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
- else
- do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff = 0, fromoff = 0;
-
- if (to->start > from->start)
- fromoff = to->start-from->start;
- else
- tooff = from->start-to->start;
- size = to->len-tooff;
- if (size > from->len-fromoff)
- size = from->len-fromoff;
- if (size < 0)
- return;
- size *= sizeof(u_short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
- int size = len*sizeof(u_short);
-
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return(0);
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- return(-1);
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- return(-1);
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return(-1);
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return(-1);
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return(0);
-}
-
-
- /*
- * Get the Fixed Part of the Display
- */
-
-static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct Cyber_fb_par par;
- int error = 0;
-
- if (con == -1)
- Cyber_fb_get_par(&par);
- else
- error = fbhw->decode_var(&disp[con].var, &par);
- return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
- /*
- * Get the User Defined Part of the Display
- */
-
-static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- struct Cyber_fb_par par;
- int error = 0;
-
- if (con == -1) {
- Cyber_fb_get_par(&par);
- error = fbhw->encode_var(var, &par);
- } else
- *var = disp[con].var;
- return(error);
-}
-
-
-static void Cyber_fb_set_disp(int con)
-{
- struct fb_fix_screeninfo fix;
-
- Cyber_fb_get_fix(&fix, con);
- if (con == -1)
- con = 0;
- disp[con].screen_base = (u_char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = Cyberfb_inverse;
-}
-
-
- /*
- * Set the User Defined Part of the Display
- */
-
-static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
- if ((err = do_fb_set_var(var, con == currcon)))
- return(err);
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = disp[con].var.xres;
- oldyres = disp[con].var.yres;
- oldvxres = disp[con].var.xres_virtual;
- oldvyres = disp[con].var.yres_virtual;
- oldbpp = disp[con].var.bits_per_pixel;
- disp[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- Cyber_fb_set_disp(con);
- (*fb_info.changevar)(con);
- alloc_cmap(&disp[con].cmap, 0, 0);
- do_install_cmap(con);
- }
- }
- var->activate = 0;
- return(0);
-}
-
-
- /*
- * Get the Colormap
- */
-
-static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console? */
- return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
- else if (disp[con].cmap.len) /* non default colormap? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), cmap,
- kspc ? 0 : 2);
- return(0);
-}
-
-
- /*
- * Set the Colormap
- */
-
-static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
-
- if (!disp[con].cmap.len) { /* no colormap allocated? */
- if ((err = alloc_cmap(&disp[con].cmap, 1<<disp[con].var.bits_per_pixel,
- 0)))
- return(err);
- }
- if (con == currcon) /* current console? */
- return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return(0);
-}
-
-
- /*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- return(-EINVAL);
-}
-
-
- /*
- * Cybervision Frame Buffer Specific ioctls
- */
-
-static int Cyber_fb_ioctl(struct inode *inode, struct file *file,
- u_int cmd, u_long arg, int con)
-{
- return(-EINVAL);
-}
-
-
-static struct fb_ops Cyber_fb_ops = {
- Cyber_fb_get_fix, Cyber_fb_get_var, Cyber_fb_set_var, Cyber_fb_get_cmap,
- Cyber_fb_set_cmap, Cyber_fb_pan_display, Cyber_fb_ioctl
-};
-
-
-int Cyber_probe(void)
-{
- CyberKey = zorro_find(MANUF_PHASE5, PROD_CYBERVISION, 0, 0);
- return(CyberKey);
-}
-
-
-void Cyber_video_setup(char *options, int *ints)
-{
- char *this_opt;
- int i;
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
- if (!strcmp(this_opt, "inverse")) {
- Cyberfb_inverse = 1;
- for (i = 0; i < 16; i++) {
- red16[i] = ~red16[i];
- green16[i] = ~green16[i];
- blue16[i] = ~blue16[i];
- }
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else if (!strcmp (this_opt, "cyber8"))
- Cyberfb_Cyber8 = 1;
- else if (!strcmp (this_opt, "cyber16"))
- Cyberfb_Cyber16 = 1;
- else
- Cyberfb_mode = get_video_mode(this_opt);
-}
-
-
- /*
- * Initialization
- */
-
-__initfunc(struct fb_info *Cyber_fb_init(long *mem_start))
-{
- int err;
- struct Cyber_fb_par par;
-
- memstart = mem_start;
-
- fbhw = &Cyber_switch;
-
- err = register_framebuffer(Cyber_fb_name, &node, &Cyber_fb_ops,
- NUM_TOTAL_MODES, Cyber_fb_predefined);
- if (err < 0)
- panic("Cannot register frame buffer\n");
-
- fbhw->init();
- fbhw->decode_var(&Cyber_fb_predefined[Cyberfb_mode], &par);
- fbhw->encode_var(&Cyber_fb_predefined[0], &par);
-
- strcpy(fb_info.modename, Cyber_fb_name);
- fb_info.disp = disp;
- fb_info.switch_con = &Cyberfb_switch;
- fb_info.updatevar = &Cyberfb_updatevar;
- fb_info.blank = &Cyberfb_blank;
- fb_info.setcmap = &Cyberfb_setcmap;
-
- do_fb_set_var(&Cyber_fb_predefined[0], 1);
- Cyber_fb_get_var(&disp[0].var, -1);
- Cyber_fb_set_disp(-1);
- do_install_cmap(0);
- return(&fb_info);
-}
-
-
-static int Cyberfb_switch(int con)
-{
- /* Do we have to save the colormap? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
- do_fb_set_var(&disp[con].var, 1);
- currcon = con;
- /* Install new colormap */
- do_install_cmap(con);
- return(0);
-}
-
-
- /*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int Cyberfb_updatevar(int con)
-{
- return(0);
-}
-
-
- /*
- * Blank the display.
- */
-
-static void Cyberfb_blank(int blank)
-{
- fbhw->blank(blank);
-}
-
-
- /*
- * Set the colormap
- */
-
-static int Cyberfb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(Cyber_fb_set_cmap(cmap, 1, con));
-}
-
-
- /*
- * Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
- int i;
-
- for (i = 1; i < NUM_PREDEF_MODES; i++)
- if (!strcmp(name, Cyber_fb_modenames[i]))
- return(i);
- return(0);
-}
diff --git a/arch/m68k/amiga/retz3fb.c b/arch/m68k/amiga/retz3fb.c
deleted file mode 100644
index 49a0853bc..000000000
--- a/arch/m68k/amiga/retz3fb.c
+++ /dev/null
@@ -1,1754 +0,0 @@
-/*
- * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- * Geert Uytterhoeven
- * clgen.c: Copyright (C) 1996 Frank Neumann
- *
- * History:
- * - 22 Jan 97: Initial work
- * - 14 Feb 97: Screen initialization works somewhat, still only
- * 8-bit packed pixel is supported.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/zorro.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-struct retz3_fb_par {
- int xres;
- int yres;
- int xres_vir;
- int yres_vir;
- int xoffset;
- int yoffset;
- int bpp;
-
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
-
- int pixclock;
- int left_margin; /* time from sync to picture */
- int right_margin; /* time from picture to sync */
- int upper_margin; /* time from sync to picture */
- int lower_margin;
- int hsync_len; /* length of horizontal sync */
- int vsync_len; /* length of vertical sync */
- int vmode;
-};
-
-struct display_data {
- long h_total; /* Horizontal Total */
- long h_sstart; /* Horizontal Sync Start */
- long h_sstop; /* Horizontal Sync Stop */
- long h_bstart; /* Horizontal Blank Start */
- long h_bstop; /* Horizontal Blank Stop */
- long h_dispend; /* Horizontal Display End */
- long v_total; /* Vertical Total */
- long v_sstart; /* Vertical Sync Start */
- long v_sstop; /* Vertical Sync Stop */
- long v_bstart; /* Vertical Blank Start */
- long v_bstop; /* Vertical Blank Stop */
- long v_dispend; /* Horizontal Display End */
-};
-
-static struct retz3_fb_par current_par;
-
-static int current_par_valid = 0;
-static int currcon = 0;
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-
-static int node; /* node of the /dev/fb?current file */
-
-
-/*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
-
- int (*init)(void);
-
- /* Display Control */
-
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par);
- int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned
- int *green, unsigned int *blue, unsigned int *transp);
- int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int
- green, unsigned int blue, unsigned int transp);
- void (*blank)(int blank);
-} *fbhw;
-
-
-/*
- * Frame Buffer Name
- */
-
-static char retz3_fb_name[16] = "RetinaZ3";
-
-
-static int z3_key = 0;
-static unsigned char retz3_color_table [256][4];
-static unsigned long z3_mem;
-static unsigned long z3_fbmem;
-static unsigned long z3_size;
-static volatile unsigned char *z3_regs;
-
-static long *memstart;
-
-
-/*
- * Predefined Video Mode Names
- */
-
-static char *retz3_fb_modenames[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- "default",
-
- /*
- * Predefined Video Modes
- */
-
- "640x480", /* RetinaZ3 8 bpp */
- "800x600", /* RetinaZ3 8 bpp */
- "1024x768i",
- "640x480-16", /* RetinaZ3 16 bpp */
- "640x480-24", /* RetinaZ3 24 bpp */
-
- /*
- * Dummy Video Modes
- */
-
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
- "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
-
- /*
- * User Defined Video Modes
- *
- * This doesn't work yet!!
- */
-
- "user0", "user1", "user2", "user3",
- "user4", "user5", "user6", "user7"
-};
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600" 50 800 856 976 1040 600 637 643 666
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
-
-The fields in the fb_var_screeninfo structure are:
- unsigned long pixclock; * pixel clock in ps (pico seconds) *
- unsigned long left_margin; * time from sync to picture *
- unsigned long right_margin; * time from picture to sync *
- unsigned long upper_margin; * time from sync to picture *
- unsigned long lower_margin;
- unsigned long hsync_len; * length of horizontal sync *
- unsigned long vsync_len; * length of vertical sync *
-
-1) Pixelclock:
- xfree: in MHz
- fb: In Picoseconds (ps)
-
- pixclock = 1000000 / DCF
-
-2) horizontal timings:
- left_margin = HFL - SH2
- right_margin = SH1 - HR
- hsync_len = SH2 - SH1
-
-3) vertical timings:
- upper_margin = VFL - SV2
- lower_margin = SV1 - VR
- vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- * Predefined Video Mode Definitions
- */
-
-static struct fb_var_screeninfo retz3_fb_predefined[] = {
-
- /*
- * Autodetect (Default) Video Mode
- */
-
- { 0, },
-
- /*
- * Predefined Video Modes
- */
-
- /*
- * NB: it is very important to adjust the pixel-clock to the color-depth.
- */
-
- {
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 800 x 600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- /*
- ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- /* 1024 x 768, 8 bpp, interlaced */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
- {
- 640, 480, 640, 480, 0, 0, 24, 0,
- {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- },
-
- /*
- * Dummy Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, },
- { 0, }, { 0, },
-
- /*
- * User Defined Video Modes
- */
-
- { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }
-};
-
-
-#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined)
-#define NUM_PREDEF_MODES (5)
-
-
-static int z3fb_inverse = 0;
-static int z3fb_mode = 0;
-
-
-/*
- * Interface used by the world
- */
-
-int retz3_probe(void);
-void retz3_video_setup(char *options, int *ints);
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con);
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con);
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con);
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con);
-
-
-/*
- * Interface to the low level console driver
- */
-
-struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */
-static int z3fb_switch(int con);
-static int z3fb_updatevar(int con);
-static void z3fb_blank(int blank);
-static int z3fb_setcmap(struct fb_cmap *cmap, int con);
-
-
-/*
- * Accelerated Functions used by the low level console driver
- */
-
-void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short curx, unsigned short cury, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-void retz3_fill(unsigned short x, unsigned short y, unsigned short
- width, unsigned short height, unsigned short mode,
- unsigned short color);
-
-/*
- * Hardware Specific Routines
- */
-
-static int retz3_init(void);
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp);
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp);
-static void retz3_blank(int blank);
-
-
-/*
- * Internal routines
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par);
-static void retz3_fb_set_par(struct retz3_fb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static struct fb_cmap *get_default_colormap(int bpp);
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc);
-static void do_install_cmap(int con);
-static void memcpy_fs(int fsfromto, void *to, void *from, int len);
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto);
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp);
-static void retz3_fb_set_disp(int con);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines -------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
- unsigned long f;
- long tmp;
- long prev = 0x7fffffff;
- long n2, n1 = 3;
- unsigned long m;
- unsigned short res = 0;
-
- if (freq <= 31250000)
- n2 = 3;
- else if (freq <= 62500000)
- n2 = 2;
- else if (freq <= 125000000)
- n2 = 1;
- else if (freq <= 250000000)
- n2 = 0;
- else
- return(0);
-
-
- do {
- f = freq >> (10 - n2);
-
- m = (f * n1) / (14318180/1024);
-
- if (m > 129)
- break;
-
- tmp = (((m * 14318180) >> n2) / n1) - freq;
- if (tmp < 0)
- tmp = -tmp;
-
- if (tmp < prev) {
- prev = tmp;
- res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
- }
-
- } while ( (++n1) <= 21);
-
- return res;
-}
-
-
-static int retz3_set_video(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- float freq_f;
- long freq;
-
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- unsigned char tmp;
- unsigned short best_freq;
- struct display_data data;
-
- short clocksel = 0; /* Apparantly this is always zero */
-
- int bpp = var->bits_per_pixel;
-
- /*
- * XXX
- */
- if (bpp == 24)
- return 0;
-
- if ((bpp != 8) && (bpp != 16) && (bpp != 24))
- return -EFAULT;
-
- par->xoffset = 0;
- par->yoffset = 0;
-
- xres = var->xres * bpp / 4;
- hfront = var->right_margin * bpp / 4;
- hsync = var->hsync_len * bpp / 4;
- hback = var->left_margin * bpp / 4;
-
- if (var->vmode & FB_VMODE_DOUBLE)
- {
- yres = var->yres * 2;
- vfront = var->lower_margin * 2;
- vsync = var->vsync_len * 2;
- vback = var->upper_margin * 2;
- }
- else if (var->vmode & FB_VMODE_INTERLACED)
- {
- yres = (var->yres + 1) / 2;
- vfront = (var->lower_margin + 1) / 2;
- vsync = (var->vsync_len + 1) / 2;
- vback = (var->upper_margin + 1) / 2;
- }
- else
- {
- yres = var->yres; /* -1 ? */
- vfront = var->lower_margin;
- vsync = var->vsync_len;
- vback = var->upper_margin;
- }
-
- data.h_total = (hback / 8) + (xres / 8)
- + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
- data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
- data.h_bstart = xres / 8 /* + 1 */;
-
- data.h_bstop = data.h_total+1 + 2 + 1;
- data.h_sstart = (xres / 8) + (hfront / 8) + 1;
- data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
- data.v_total = yres + vfront + vsync + vback - 1;
-
- data.v_dispend = yres - 1;
- data.v_bstart = yres;
-
- data.v_bstop = data.v_total;
- data.v_sstart = yres + vfront - 1 - 2;
- data.v_sstop = yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
- printk("HBS: %i\n", data.h_bstart);
- printk("HSS: %i\n", data.h_sstart);
- printk("HSE: %i\n", data.h_sstop);
- printk("HBE: %i\n", data.h_bstop);
- printk("HT: %i\n", data.h_total);
-
- printk("hsync: %i\n", hsync);
- printk("hfront: %i\n", hfront);
- printk("hback: %i\n", hback);
-
- printk("VBS: %i\n", data.v_bstart);
- printk("VSS: %i\n", data.v_sstart);
- printk("VSE: %i\n", data.v_sstop);
- printk("VBE: %i\n", data.v_bstop);
- printk("VT: %i\n", data.v_total);
-
- printk("vsync: %i\n", vsync);
- printk("vfront: %i\n", vfront);
- printk("vback: %i\n", vback);
-#endif
-
- if (data.v_total >= 1024)
- printk("MAYDAY: v_total >= 1024; bailing out!\n");
-
- reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
- reg_w(GREG_FEATURE_CONTROL_W, 0x00);
-
- seq_w(SEQ_RESET, 0x00);
- seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */
-
- /*
- * CLOCKING_MODE bits:
- * 2: This one is only set for certain text-modes, wonder if
- * it may be for EGA-lines? (it was referred to as CLKDIV2)
- * (The CL drivers sets it to 0x21 with the comment:
- * FullBandwidth (video off) and 8/9 dot clock)
- */
- seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
- seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
- seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
- seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
- seq_w(SEQ_RESET, 0x01);
- seq_w(SEQ_RESET, 0x03);
-
- seq_w(SEQ_EXTENDED_ENABLE, 0x05);
-
- seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(SEQ_LINEAR_0, 0x4a);
- seq_w(SEQ_LINEAR_1, 0x00);
-
- seq_w(SEQ_SEC_HOST_OFF_HI, 0x00);
- seq_w(SEQ_SEC_HOST_OFF_LO, 0x00);
- seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
- /*
- * The lower 4 bits (0-3) are used to set the font-width for
- * text-mode - DON'T try to set this for gfx-mode.
- */
- seq_w(SEQ_EXT_CLOCK_MODE, 0x10);
- seq_w(SEQ_EXT_VIDEO_ADDR, 0x03);
-
- /*
- * Extended Pixel Control:
- * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
- * bit 1: (Packed/Nibble Pixel Format ?)
- * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
- */
- seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
- seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04);
- seq_w(SEQ_COLOR_EXP_WFG, 0x01);
- seq_w(SEQ_COLOR_EXP_WBG, 0x00);
- seq_w(SEQ_EXT_RW_CONTROL, 0x00);
- seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
- seq_w(SEQ_COLOR_KEY_CNTL, 0x40);
- seq_w(SEQ_COLOR_KEY_MATCH0, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH1, 0x00);
- seq_w(SEQ_COLOR_KEY_MATCH2, 0x00);
- seq_w(SEQ_CRC_CONTROL, 0x00);
- seq_w(SEQ_PERF_SELECT, 0x10);
- seq_w(SEQ_ACM_APERTURE_1, 0x00);
- seq_w(SEQ_ACM_APERTURE_2, 0x30);
- seq_w(SEQ_ACM_APERTURE_3, 0x00);
- seq_w(SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
- /* unlock register CRT0..CRT7 */
- crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
- /* Zuerst zu schreibende Werte nur per printk ausgeben */
- DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
- crt_w(CRT_HOR_TOTAL, data.h_total & 0xff);
-
- DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
- crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
- DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
- crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
- DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
- crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
-
- DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
- crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
- tmp = (data.h_sstop & 0x1f);
- if (data.h_bstop & 0x20)
- tmp |= 0x80;
- DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
- crt_w(CRT_END_HOR_RETR, tmp);
-
- DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
- crt_w(CRT_VER_TOTAL, (data.v_total & 0xff));
-
- tmp = 0x10; /* LineCompare bit #9 */
- if (data.v_total & 256)
- tmp |= 0x01;
- if (data.v_dispend & 256)
- tmp |= 0x02;
- if (data.v_sstart & 256)
- tmp |= 0x04;
- if (data.v_bstart & 256)
- tmp |= 0x08;
- if (data.v_total & 512)
- tmp |= 0x20;
- if (data.v_dispend & 512)
- tmp |= 0x40;
- if (data.v_sstart & 512)
- tmp |= 0x80;
- DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
- crt_w(CRT_OVERFLOW, tmp);
-
- crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
- tmp = 0x40; /* LineCompare bit #8 */
- if (data.v_bstart & 512)
- tmp |= 0x20;
- if (var->vmode & FB_VMODE_DOUBLE)
- tmp |= 0x80;
- DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
- crt_w(CRT_MAX_SCAN_LINE, tmp);
-
- crt_w(CRT_CURSOR_START, 0x00);
- crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
- crt_w(CRT_START_ADDR_HIGH, 0x00);
- crt_w(CRT_START_ADDR_LOW, 0x00);
-
- crt_w(CRT_CURSOR_LOC_HIGH, 0x00);
- crt_w(CRT_CURSOR_LOC_LOW, 0x00);
-
- DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
- crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
- /* 5 refresh cycles per scanline */
- DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
- DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
- crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
- DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
- crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
- DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
- crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
- DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
- crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
- DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
- crt_w(CRT_MODE_CONTROL, 0xe3);
-
- DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
- crt_w(CRT_LINE_COMPARE, 0xff);
-
- tmp = (var->xres_virtual / 8) * (bpp / 8);
- crt_w(CRT_OFFSET, tmp);
-
- crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
- tmp = 0x20; /* Enable extended end bits */
- if (data.h_total & 0x100)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x100)
- tmp |= 0x02;
- if (data.h_bstart & 0x100)
- tmp |= 0x04;
- if (data.h_sstart & 0x100)
- tmp |= 0x08;
- if (var->vmode & FB_VMODE_INTERLACED)
- tmp |= 0x10;
- DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
- crt_w(CRT_EXT_HOR_TIMING1, tmp);
-
- tmp = 0x00;
- if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
- tmp |= 0x10;
- crt_w(CRT_EXT_START_ADDR, tmp);
-
- tmp = 0x00;
- if (data.h_total & 0x200)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x200)
- tmp |= 0x02;
- if (data.h_bstart & 0x200)
- tmp |= 0x04;
- if (data.h_sstart & 0x200)
- tmp |= 0x08;
- tmp |= ((data.h_bstop & 0xc0) >> 2);
- tmp |= ((data.h_sstop & 0x60) << 1);
- crt_w(CRT_EXT_HOR_TIMING2, tmp);
- DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
- tmp = 0x10; /* Line compare bit 10 */
- if (data.v_total & 0x400)
- tmp |= 0x01;
- if ((data.v_dispend) & 0x400)
- tmp |= 0x02;
- if (data.v_bstart & 0x400)
- tmp |= 0x04;
- if (data.v_sstart & 0x400)
- tmp |= 0x08;
- tmp |= ((data.v_bstop & 0x300) >> 3);
- if (data.v_sstop & 0x10)
- tmp |= 0x80;
- crt_w(CRT_EXT_VER_TIMING, tmp);
- DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
- crt_w(CRT_MONITOR_POWER, 0x00);
-
- /*
- * Convert from ps to Hz.
- */
- freq_f = (1.0/(float)var->pixclock) * 1000000000;
- freq = ((long)freq_f) * 1000;
-
- best_freq = find_fq(freq);
- pll_w(0x02, best_freq);
- best_freq = find_fq(61000000);
- pll_w(0x0a, best_freq);
- pll_w(0x0e, 0x22);
-
- gfx_w(GFX_SET_RESET, 0x00);
- gfx_w(GFX_ENABLE_SET_RESET, 0x00);
- gfx_w(GFX_COLOR_COMPARE, 0x00);
- gfx_w(GFX_DATA_ROTATE, 0x00);
- gfx_w(GFX_READ_MAP_SELECT, 0x00);
- gfx_w(GFX_GRAPHICS_MODE, 0x00);
- gfx_w(GFX_MISC, 0x05);
- gfx_w(GFX_COLOR_XCARE, 0x0f);
- gfx_w(GFX_BITMASK, 0xff);
-
- reg_r(ACT_ADDRESS_RESET);
- attr_w(ACT_PALETTE0 , 0x00);
- attr_w(ACT_PALETTE1 , 0x01);
- attr_w(ACT_PALETTE2 , 0x02);
- attr_w(ACT_PALETTE3 , 0x03);
- attr_w(ACT_PALETTE4 , 0x04);
- attr_w(ACT_PALETTE5 , 0x05);
- attr_w(ACT_PALETTE6 , 0x06);
- attr_w(ACT_PALETTE7 , 0x07);
- attr_w(ACT_PALETTE8 , 0x08);
- attr_w(ACT_PALETTE9 , 0x09);
- attr_w(ACT_PALETTE10, 0x0a);
- attr_w(ACT_PALETTE11, 0x0b);
- attr_w(ACT_PALETTE12, 0x0c);
- attr_w(ACT_PALETTE13, 0x0d);
- attr_w(ACT_PALETTE14, 0x0e);
- attr_w(ACT_PALETTE15, 0x0f);
- reg_r(ACT_ADDRESS_RESET);
-
- attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
- attr_w(ACT_OVERSCAN_COLOR, 0x00);
- attr_w(ACT_COLOR_PLANE_ENA, 0x0f);
- attr_w(ACT_HOR_PEL_PANNING, 0x00);
- attr_w(ACT_COLOR_SELECT, 0x00);
-
- reg_r(ACT_ADDRESS_RESET);
- reg_w(ACT_DATA, 0x20);
-
- reg_w(VDAC_MASK, 0xff);
-
- /*
- * Extended palette adressing ???
- */
- switch (bpp){
- case 8:
- reg_w(0x83c6, 0x00);
- break;
- case 16:
- reg_w(0x83c6, 0x60);
- break;
- case 24:
- reg_w(0x83c6, 0xe0);
- break;
- default:
- printk("Illegal color-depth: %i\n", bpp);
- }
-
- reg_w(VDAC_ADDRESS, 0x00);
-
- seq_w(SEQ_MAP_MASK, 0x0f );
-
- return 0;
-}
-
-/*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int retz3_init(void)
-{
- int i;
-#if 0
- volatile unsigned long *CursorBase;
-#endif
- unsigned long board_addr, board_size;
- struct ConfigDev *cd;
-
- cd = zorro_get_board (z3_key);
- zorro_config_board (z3_key, 0);
- board_addr = (unsigned long)cd->cd_BoardAddr;
- board_size = (unsigned long)cd->cd_BoardSize;
-
- for (i = 0; i < 256; i++){
- for (i = 0; i < 256; i++){
- retz3_color_table [i][0] = i;
- retz3_color_table [i][1] = i;
- retz3_color_table [i][2] = i;
- retz3_color_table [i][3] = 0;
- }
- }
-
- *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- z3_mem = kernel_map (board_addr, board_size,
- KERNELMAP_NOCACHE_SER, memstart);
-
- z3_regs = (char*) z3_mem;
- z3_fbmem = z3_mem + VIDEO_MEM_OFFSET;
-
- /* Get memory size - for now we asume its a 4MB board */
-
- z3_size = 0x00400000; /* 4 MB */
-
- memset ((char*)z3_fbmem, 0, z3_size);
-
- /* Disable hardware cursor */
-
- seq_w(SEQ_CURSOR_Y_INDEX, 0x00);
-
-
-#if 0
- /* Initialize hardware cursor */
- CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400);
- for (i=0; i < 8; i++){
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i=8; i < 64; i++){
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-#endif
-
- retz3_setcolreg (255, 56, 100, 160, 0);
- retz3_setcolreg (254, 0, 0, 0, 0);
-
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_fix_screeninfo *fix,
- struct retz3_fb_par *par)
-{
- int i;
-
- strcpy(fix->id, retz3_fb_name);
- fix->smem_start = z3_fbmem;
- fix->smem_len = z3_size;
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_DIRECTCOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
-
- for (i = 0; i < arraysize(fix->reserved); i++)
- fix->reserved[i] = 0;
-
- return 0;
-}
-
-
-/*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- par->xres = var->xres;
- par->yres = var->yres;
- par->xres_vir = var->xres_virtual;
- par->yres_vir = var->yres_virtual;
- par->bpp = var->bits_per_pixel;
- par->pixclock = var->pixclock;
- par->vmode = var->vmode;
-
- par->red = var->red;
- par->green = var->green;
- par->blue = var->blue;
- par->transp = var->transp;
-
- par->left_margin = var->left_margin;
- par->right_margin = var->right_margin;
- par->upper_margin = var->upper_margin;
- par->lower_margin = var->lower_margin;
- par->hsync_len = var->hsync_len;
- par->vsync_len = var->vsync_len;
-
- return 0;
-}
-
-
-/*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3_fb_par *par)
-{
- int i;
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres_vir;
- var->yres_virtual = par->yres_vir;
- var->xoffset = 0;
- var->yoffset = 0;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- var->red = par->red;
- var->green = par->green;
- var->blue = par->blue;
- var->transp = par->transp;
-
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
-
- var->accel = FB_ACCEL_RETINAZ3;
-
- var->pixclock = par->pixclock;
-
- var->sync = 0; /* ??? */
- var->left_margin = par->left_margin;
- var->right_margin = par->right_margin;
- var->upper_margin = par->upper_margin;
- var->lower_margin = par->lower_margin;
- var->hsync_len = par->hsync_len;
- var->vsync_len = par->vsync_len;
-
- for (i = 0; i < arraysize(var->reserved); i++)
- var->reserved[i] = 0;
-
- var->vmode = par->vmode;
- return 0;
-}
-
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int retz3_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp)
-{
- /* We'll get to this */
-
- if (regno > 255)
- return 1;
-
- retz3_color_table [regno][0] = red & 0xff;
- retz3_color_table [regno][1] = green & 0xff;
- retz3_color_table [regno][2] = blue & 0xff;
- retz3_color_table [regno][3] = transp;
-
- reg_w(VDAC_ADDRESS_W, regno);
- reg_w(VDAC_DATA, (red & 0xff) >> 2);
- reg_w(VDAC_DATA, (green & 0xff) >> 2);
- reg_w(VDAC_DATA, (blue & 0xff) >> 2);
-
- return 0;
-}
-
-
-/*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp)
-{
- if (regno > 255)
- return 1;
- *red = retz3_color_table [regno][0];
- *green = retz3_color_table [regno][1];
- *blue = retz3_color_table [regno][2];
- *transp = retz3_color_table [regno][3];
- return 0;
-}
-
-
-/*
- * (Un)Blank the screen
- */
-
-void retz3_blank(int blank)
-{
- int i;
-
- if (blank)
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- reg_w(VDAC_DATA, 0);
- }
- else
- for (i = 0; i < 256; i++){
- reg_w(VDAC_ADDRESS_W, i);
- reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2);
- reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2);
- }
-}
-
-
-void retz3_bitblt (struct fb_var_screeninfo *var,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask)
-{
-
- volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET);
- unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF);
-
- unsigned short mod;
- unsigned long tmp;
- unsigned long pat, src, dst;
- unsigned char blt_status;
-
- int i, xres_virtual = var->xres_virtual;
- short bpp = (var->bits_per_pixel & 0xff);
-
- if (bpp < 8)
- bpp = 8;
-
- tmp = mask | (mask << 16);
-
-#if 0
- /*
- * Check for blitter finished before we start messing with the
- * pattern.
- */
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }while ((blt_status & 1) == 0);
-#endif
-
- i = 0;
- do{
- *pattern++ = tmp;
- }while(i++ < bpp/4);
-
- tmp = cmd << 8;
- *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
- mod = 0xc0c2;
-
- pat = 8 * PAT_MEM_OFF;
- dst = bpp * (destx + desty * xres_virtual);
-
- /*
- * Source is not set for clear.
- */
- if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
- src = bpp * (srcx + srcy * xres_virtual);
-
- if (destx > srcx) {
- mod &= ~0x8000;
- src += bpp * (width - 1);
- dst += bpp * (width - 1);
- pat += bpp * 2;
- }
- if (desty > srcy) {
- mod &= ~0x4000;
- src += bpp * (height - 1) * xres_virtual;
- dst += bpp * (height - 1) * xres_virtual;
- pat += bpp * 4;
- }
-
- *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
- }
-
- *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
- *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
- tmp = mod << 16;
- *(acm + ACM_CONTROL/4) = tmp;
-
- tmp = width | (height << 16);
-
- *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
- /*
- * No reason to wait for the blitter to finish, it is better
- * just to check if it has finished before we use it again.
- */
-#if 1
-#if 0
- while ((*(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2)) & 1) == 0);
-#else
- do{
- blt_status = *(((volatile unsigned char *)acm) +
- (ACM_START_STATUS + 2));
- }
- while ((blt_status & 1) == 0);
-#endif
-#endif
-}
-
-#if 0
-void retz3_fill (unsigned short x, unsigned short y, unsigned
- short width, unsigned short height,
- unsigned short mode, unsigned short color)
-{
-
-}
-#endif
-
-
-/**************************************************************
- * Move cursor to x, y
- */
-void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
- /* Guess we gotta deal with the cursor at some point */
-}
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch retz3_switch = {
- retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var,
- retz3_getcolreg, retz3_setcolreg, retz3_blank
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void retz3_fb_get_par(struct retz3_fb_par *par)
-{
- if (current_par_valid)
- *par = current_par;
- else
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par);
-}
-
-
-static void retz3_fb_set_par(struct retz3_fb_par *par)
-{
- current_par = *par;
- current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct retz3_fb_par par;
-
- if ((err = fbhw->decode_var(var, &par)))
- return err;
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3_fb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate = activate;
-
-#if 1
- retz3_set_video(var, &current_par);
-#endif
- return 0;
-}
-
-
-/*
- * Default Colormaps
- */
-
-static unsigned short red16[] =
- { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff };
-static unsigned short green16[] =
- { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000,
- 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff };
-static unsigned short blue16[] =
- { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,
- 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff };
-
-
-static struct fb_cmap default_16_colors =
- { 0, 16, red16, green16, blue16, NULL };
-
-
-static struct fb_cmap *get_default_colormap(int bpp)
-{
- return &default_16_colors;
-}
-
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16)
-#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \
- ((1<<(width))-1)) : 0))
-
-static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return 0;
- hred = CNVT_FROMHW(hred, var->red.length);
- hgreen = CNVT_FROMHW(hgreen, var->green.length);
- hblue = CNVT_FROMHW(hblue, var->blue.length);
- htransp = CNVT_FROMHW(htransp, var->transp.length);
- if (kspc) {
- *red = hred;
- *green = hgreen;
- *blue = hblue;
- if (transp)
- *transp = htransp;
- } else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp)
- put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- }
- return 0;
-}
-
-
-static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var,
- int kspc)
-{
- int i, start;
- unsigned short *red, *green, *blue, *transp;
- unsigned int hred, hgreen, hblue, htransp;
-
- red = cmap->red;
- green = cmap->green;
- blue = cmap->blue;
- transp = cmap->transp;
- start = cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i = 0; i < cmap->len; i++) {
- if (kspc) {
- hred = *red;
- hgreen = *green;
- hblue = *blue;
- htransp = transp ? *transp : 0;
- } else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred = CNVT_TOHW(hred, var->red.length);
- hgreen = CNVT_TOHW(hgreen, var->green.length);
- hblue = CNVT_TOHW(hblue, var->blue.length);
- htransp = CNVT_TOHW(htransp, var->transp.length);
- red++;
- green++;
- blue++;
- if (transp)
- transp++;
- if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
- return 0;
- }
- return 0;
-}
-
-
-static void do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1);
- else
- do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- &disp[con].var, 1);
-}
-
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to, from, len);
- return;
- case 1:
- copy_from_user(to, from, len);
- return;
- case 2:
- copy_to_user(to, from, len);
- return;
- }
-}
-
-
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff = 0, fromoff = 0;
-
- if (to->start > from->start)
- fromoff = to->start-from->start;
- else
- tooff = from->start-to->start;
- size = to->len-tooff;
- if (size > from->len-fromoff)
- size = from->len-fromoff;
- if (size < 0)
- return;
- size *= sizeof(unsigned short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff,
- from->transp+fromoff, size);
-}
-
-
-static int alloc_cmap(struct fb_cmap *cmap, int len, int transp)
-{
- int size = len*sizeof(unsigned short);
-
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
- cmap->len = 0;
- if (!len)
- return 0;
- if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
- if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
- return -1;
- } else
- cmap->transp = NULL;
- }
- cmap->start = 0;
- cmap->len = len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return 0;
-}
-
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1)
- retz3_fb_get_par(&par);
- else
- error = fbhw->decode_var(&disp[con].var, &par);
- return(error ? error : fbhw->encode_fix(fix, &par));
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- struct retz3_fb_par par;
- int error = 0;
-
- if (con == -1) {
- retz3_fb_get_par(&par);
- error = fbhw->encode_var(var, &par);
- } else
- *var = disp[con].var;
- return error;
-}
-
-
-static void retz3_fb_set_disp(int con)
-{
- struct fb_fix_screeninfo fix;
-
- retz3_fb_get_fix(&fix, con);
- if (con == -1)
- con = 0;
- disp[con].screen_base = (unsigned char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].can_soft_blank = 1;
- disp[con].inverse = z3fb_inverse;
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-
- if ((err = do_fb_set_var(var, con == currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = disp[con].var.xres;
- oldyres = disp[con].var.yres;
- oldvxres = disp[con].var.xres_virtual;
- oldvyres = disp[con].var.yres_virtual;
- oldbpp = disp[con].var.bits_per_pixel;
- disp[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
- retz3_fb_set_disp(con);
- (*fb_info.changevar)(con);
- alloc_cmap(&disp[con].cmap, 0, 0);
- do_install_cmap(con);
- }
- }
- var->activate = 0;
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console? */
- return(do_fb_get_cmap(cmap, &disp[con].var, kspc));
- else if (disp[con].cmap.len) /* non default colormap? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
-
-/*
- * Set the Colormap
- */
-
-static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
-
- if (!disp[con].cmap.len) { /* no colormap allocated? */
- if ((err = alloc_cmap(&disp[con].cmap,
- 1<<disp[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console? */
- return(do_fb_set_cmap(cmap, &disp[con].var, kspc));
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-
-/*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- return -EINVAL;
-}
-
-
-/*
- * RetinaZ3 Frame Buffer Specific ioctls
- */
-
-static int retz3_fb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con)
-{
- return -EINVAL;
-}
-
-
-static struct fb_ops retz3_fb_ops = {
- retz3_fb_get_fix, retz3_fb_get_var, retz3_fb_set_var, retz3_fb_get_cmap,
- retz3_fb_set_cmap, retz3_fb_pan_display, retz3_fb_ioctl
-};
-
-
-int retz3_probe(void)
-{
- z3_key = zorro_find(MANUF_MACROSYSTEMS2, PROD_RETINA_Z3, 0, 0);
- return(z3_key);
-}
-
-
-void retz3_video_setup(char *options, int *ints)
-{
- char *this_opt;
- int i;
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")){
- if (!strcmp(this_opt, "inverse")) {
- z3fb_inverse = 1;
- for (i = 0; i < 16; i++) {
- red16[i] = ~red16[i];
- green16[i] = ~green16[i];
- blue16[i] = ~blue16[i];
- }
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else
- z3fb_mode = get_video_mode(this_opt);
- }
-}
-
-
-/*
- * Initialization
- */
-
-__initfunc(struct fb_info *retz3_fb_init(long *mem_start))
-{
- int err;
- struct retz3_fb_par par;
-
- memstart = mem_start;
-
- fbhw = &retz3_switch;
-
- err = register_framebuffer(retz3_fb_name, &node, &retz3_fb_ops,
- NUM_TOTAL_MODES, retz3_fb_predefined);
- if (err < 0)
- panic("Cannot register frame buffer\n");
-
- fbhw->init();
-
- if (z3fb_mode == -1)
- z3fb_mode = 1;
-
- fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par);
- fbhw->encode_var(&retz3_fb_predefined[0], &par);
-
- strcpy(fb_info.modename, retz3_fb_name);
- fb_info.disp = disp;
- fb_info.switch_con = &z3fb_switch;
- fb_info.updatevar = &z3fb_updatevar;
- fb_info.blank = &z3fb_blank;
- fb_info.setcmap = &z3fb_setcmap;
-
- do_fb_set_var(&retz3_fb_predefined[0], 0);
- retz3_fb_get_var(&disp[0].var, -1);
- retz3_fb_set_disp(-1);
- do_install_cmap(0);
-
- return &fb_info;
-}
-
-
-static int z3fb_switch(int con)
-{
- /* Do we have to save the colormap? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1);
-
- do_fb_set_var(&disp[con].var, 1);
- currcon = con;
- /* Install new colormap */
- do_install_cmap(con);
- return 0;
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con)
-{
- return 0;
-}
-
-
-/*
- * Blank the display.
- */
-
-static void z3fb_blank(int blank)
-{
- fbhw->blank(blank);
-}
-
-
-/*
- * Set the colormap
- */
-
-static int z3fb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(retz3_fb_set_cmap(cmap, 1, con));
-}
-
-
-/*
- * Get a Video Mode
- */
-
-static int get_video_mode(const char *name)
-{
- int i;
-
- for (i = 1; i <= NUM_PREDEF_MODES; i++)
- if (!strcmp(name, retz3_fb_modenames[i])){
- retz3_fb_predefined[0] = retz3_fb_predefined[i];
- return i;
- }
- return -1;
-}
diff --git a/arch/m68k/amiga/retz3fb.h b/arch/m68k/amiga/retz3fb.h
deleted file mode 100644
index 0cb03c324..000000000
--- a/arch/m68k/amiga/retz3fb.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the
- * RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * History:
- * - 22 Jan 97: Initial work
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(reg,dat) (*(z3_regs + reg) = dat)
-#define reg_r(reg) (*(z3_regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(sreg,sdat) \
- do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(creg,cdat) \
- do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(greg,gdat) \
- do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(areg,adat) \
- do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(preg,pdat) \
- do{ reg_w(PLL_IDX, preg); \
- reg_w(PLL_DATA, (pdat & 0xff)); \
- reg_w(PLL_DATA, (pdat >> 8));\
- } while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET 0x00c00000
-#define ACM_OFFSET 0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET 0x00
-#define ACM_SECONDARY_OFFSET 0x04
-#define ACM_MODE_CONTROL 0x08
-#define ACM_CURSOR_POSITION 0x0c
-#define ACM_START_STATUS 0x30
-#define ACM_CONTROL 0x34
-#define ACM_RASTEROP_ROTATION 0x38
-#define ACM_BITMAP_DIMENSION 0x3c
-#define ACM_DESTINATION 0x40
-#define ACM_SOURCE 0x44
-#define ACM_PATTERN 0x48
-#define ACM_FOREGROUND 0x4c
-#define ACM_BACKGROUND 0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX 0x03c4 /* Sequencer Index */
-#define SEQ_DATA 0x03c5
-#define SEQ_RESET 0x00
-#define SEQ_CLOCKING_MODE 0x01
-#define SEQ_MAP_MASK 0x02
-#define SEQ_CHAR_MAP_SELECT 0x03
-#define SEQ_MEMORY_MODE 0x04
-#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */
-#define SEQ_UNKNOWN1 0x06
-#define SEQ_UNKNOWN2 0x07
-#define SEQ_CHIP_ID 0x08
-#define SEQ_UNKNOWN3 0x09
-#define SEQ_CURSOR_COLOR1 0x0a
-#define SEQ_CURSOR_COLOR0 0x0b
-#define SEQ_CURSOR_CONTROL 0x0c
-#define SEQ_CURSOR_X_LOC_HI 0x0d
-#define SEQ_CURSOR_X_LOC_LO 0x0e
-#define SEQ_CURSOR_Y_LOC_HI 0x0f
-#define SEQ_CURSOR_Y_LOC_LO 0x10
-#define SEQ_CURSOR_X_INDEX 0x11
-#define SEQ_CURSOR_Y_INDEX 0x12
-#define SEQ_CURSOR_STORE_HI 0x13
-#define SEQ_CURSOR_STORE_LO 0x14
-#define SEQ_CURSOR_ST_OFF_HI 0x15
-#define SEQ_CURSOR_ST_OFF_LO 0x16
-#define SEQ_CURSOR_PIXELMASK 0x17
-#define SEQ_PRIM_HOST_OFF_HI 0x18
-#define SEQ_PRIM_HOST_OFF_LO 0x19
-#define SEQ_LINEAR_0 0x1a
-#define SEQ_LINEAR_1 0x1b
-#define SEQ_SEC_HOST_OFF_HI 0x1c
-#define SEQ_SEC_HOST_OFF_LO 0x1d
-#define SEQ_EXTENDED_MEM_ENA 0x1e
-#define SEQ_EXT_CLOCK_MODE 0x1f
-#define SEQ_EXT_VIDEO_ADDR 0x20
-#define SEQ_EXT_PIXEL_CNTL 0x21
-#define SEQ_BUS_WIDTH_FEEDB 0x22
-#define SEQ_PERF_SELECT 0x23
-#define SEQ_COLOR_EXP_WFG 0x24
-#define SEQ_COLOR_EXP_WBG 0x25
-#define SEQ_EXT_RW_CONTROL 0x26
-#define SEQ_MISC_FEATURE_SEL 0x27
-#define SEQ_COLOR_KEY_CNTL 0x28
-#define SEQ_COLOR_KEY_MATCH0 0x29
-#define SEQ_COLOR_KEY_MATCH1 0x2a
-#define SEQ_COLOR_KEY_MATCH2 0x2b
-#define SEQ_UNKNOWN6 0x2c
-#define SEQ_CRC_CONTROL 0x2d
-#define SEQ_CRC_DATA_LOW 0x2e
-#define SEQ_CRC_DATA_HIGH 0x2f
-#define SEQ_MEMORY_MAP_CNTL 0x30
-#define SEQ_ACM_APERTURE_1 0x31
-#define SEQ_ACM_APERTURE_2 0x32
-#define SEQ_ACM_APERTURE_3 0x33
-#define SEQ_BIOS_UTILITY_0 0x3e
-#define SEQ_BIOS_UTILITY_1 0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX 0x03ce
-#define GFX_DATA 0x03cf
-#define GFX_SET_RESET 0x00
-#define GFX_ENABLE_SET_RESET 0x01
-#define GFX_COLOR_COMPARE 0x02
-#define GFX_DATA_ROTATE 0x03
-#define GFX_READ_MAP_SELECT 0x04
-#define GFX_GRAPHICS_MODE 0x05
-#define GFX_MISC 0x06
-#define GFX_COLOR_XCARE 0x07
-#define GFX_BITMASK 0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX 0x03d4
-#define CRT_DATA 0x03d5
-#define CRT_HOR_TOTAL 0x00
-#define CRT_HOR_DISP_ENA_END 0x01
-#define CRT_START_HOR_BLANK 0x02
-#define CRT_END_HOR_BLANK 0x03
-#define CRT_START_HOR_RETR 0x04
-#define CRT_END_HOR_RETR 0x05
-#define CRT_VER_TOTAL 0x06
-#define CRT_OVERFLOW 0x07
-#define CRT_PRESET_ROW_SCAN 0x08
-#define CRT_MAX_SCAN_LINE 0x09
-#define CRT_CURSOR_START 0x0a
-#define CRT_CURSOR_END 0x0b
-#define CRT_START_ADDR_HIGH 0x0c
-#define CRT_START_ADDR_LOW 0x0d
-#define CRT_CURSOR_LOC_HIGH 0x0e
-#define CRT_CURSOR_LOC_LOW 0x0f
-#define CRT_START_VER_RETR 0x10
-#define CRT_END_VER_RETR 0x11
-#define CRT_VER_DISP_ENA_END 0x12
-#define CRT_OFFSET 0x13
-#define CRT_UNDERLINE_LOC 0x14
-#define CRT_START_VER_BLANK 0x15
-#define CRT_END_VER_BLANK 0x16
-#define CRT_MODE_CONTROL 0x17
-#define CRT_LINE_COMPARE 0x18
-#define CRT_UNKNOWN1 0x19
-#define CRT_UNKNOWN2 0x1a
-#define CRT_UNKNOWN3 0x1b
-#define CRT_UNKNOWN4 0x1c
-#define CRT_UNKNOWN5 0x1d
-#define CRT_UNKNOWN6 0x1e
-#define CRT_UNKNOWN7 0x1f
-#define CRT_UNKNOWN8 0x20
-#define CRT_UNKNOWN9 0x21
-#define CRT_UNKNOWN10 0x22
-#define CRT_UNKNOWN11 0x23
-#define CRT_UNKNOWN12 0x24
-#define CRT_UNKNOWN13 0x25
-#define CRT_UNKNOWN14 0x26
-#define CRT_UNKNOWN15 0x27
-#define CRT_UNKNOWN16 0x28
-#define CRT_UNKNOWN17 0x29
-#define CRT_UNKNOWN18 0x2a
-#define CRT_UNKNOWN19 0x2b
-#define CRT_UNKNOWN20 0x2c
-#define CRT_UNKNOWN21 0x2d
-#define CRT_UNKNOWN22 0x2e
-#define CRT_UNKNOWN23 0x2f
-#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */
-#define CRT_EXT_START_ADDR 0x31
-#define CRT_EXT_HOR_TIMING2 0x32
-#define CRT_EXT_VER_TIMING 0x33
-#define CRT_MONITOR_POWER 0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R 0x03c2
-#define GREG_STATUS1_R 0x03da
-#define GREG_MISC_OUTPUT_R 0x03cc
-#define GREG_MISC_OUTPUT_W 0x03c2
-#define GREG_FEATURE_CONTROL_R 0x03ca
-#define GREG_FEATURE_CONTROL_W 0x03da
-#define GREG_POS 0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX 0x03C0
-#define ACT_ADDRESS_R 0x03C0
-#define ACT_DATA 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_PALETTE0 0x00
-#define ACT_PALETTE1 0x01
-#define ACT_PALETTE2 0x02
-#define ACT_PALETTE3 0x03
-#define ACT_PALETTE4 0x04
-#define ACT_PALETTE5 0x05
-#define ACT_PALETTE6 0x06
-#define ACT_PALETTE7 0x07
-#define ACT_PALETTE8 0x08
-#define ACT_PALETTE9 0x09
-#define ACT_PALETTE10 0x0A
-#define ACT_PALETTE11 0x0B
-#define ACT_PALETTE12 0x0C
-#define ACT_PALETTE13 0x0D
-#define ACT_PALETTE14 0x0E
-#define ACT_PALETTE15 0x0F
-#define ACT_ATTR_MODE_CNTL 0x10
-#define ACT_OVERSCAN_COLOR 0x11
-#define ACT_COLOR_PLANE_ENA 0x12
-#define ACT_HOR_PEL_PANNING 0x13
-#define ACT_COLOR_SELECT 0x14
-
-/*
- * PLL
- */
-#define PLL_IDX 0x83c8
-#define PLL_DATA 0x83c9
-
-/*
- * Blitter operations
- */
-#define Z3BLTclear 0x00 /* 0 */
-#define Z3BLTand 0x80 /* src AND dst */
-#define Z3BLTandReverse 0x40 /* src AND NOT dst */
-#define Z3BLTcopy 0xc0 /* src */
-#define Z3BLTandInverted 0x20 /* NOT src AND dst */
-#define Z3BLTnoop 0xa0 /* dst */
-#define Z3BLTxor 0x60 /* src XOR dst */
-#define Z3BLTor 0xe0 /* src OR dst */
-#define Z3BLTnor 0x10 /* NOT src AND NOT dst */
-#define Z3BLTequiv 0x90 /* NOT src XOR dst */
-#define Z3BLTinvert 0x50 /* NOT dst */
-#define Z3BLTorReverse 0xd0 /* src OR NOT dst */
-#define Z3BLTcopyInverted 0x30 /* NOT src */
-#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
-#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
-#define Z3BLTset 0xf0 /* 1 */
diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c
deleted file mode 100644
index efa6fc8b8..000000000
--- a/arch/m68k/atari/atafb.c
+++ /dev/null
@@ -1,3292 +0,0 @@
-/*
- * atari/atafb.c -- Low level implementation of Atari frame buffer device
- *
- * Copyright (C) 1994 Martin Schaller & Roman Hodek
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * History:
- * - 03 Jan 95: Original version by Martin Schaller: The TT driver and
- * all the device independent stuff
- * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
- * and wrote the Falcon, ST(E), and External drivers
- * based on the original TT driver.
- * - 07 May 95: Martin: Added colormap operations for the external driver
- * - 21 May 95: Martin: Added support for overscan
- * Andreas: some bug fixes for this
- * - Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
- * Programmable Falcon video modes
- * (thanks to Christian Cartus for documentation
- * of VIDEL registers).
- * - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]"
- * on minor 24...31. "user0" may be set on commandline by
- * "R<x>;<y>;<depth>". (Makes sense only on Falcon)
- * Video mode switch on Falcon now done at next VBL interrupt
- * to avoid the annoying right shift of the screen.
- *
- *
- * To do:
- * - For the Falcon it is not possible to set random video modes on
- * SM124 and SC/TV, only the bootup resolution is supported.
- *
- */
-
-#define ATAFB_TT
-#define ATAFB_STE
-#define ATAFB_EXT
-#define ATAFB_FALCON
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-
-#include <linux/fb.h>
-#include <asm/atarikb.h>
-
-#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
-#define SWITCH_SND6 0x40
-#define SWITCH_SND7 0x80
-#define SWITCH_NONE 0x00
-
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
-
-
-static int default_par=0; /* default resolution (0=none) */
-
-static int node; /* node of the /dev/fb?current file */
-
-static unsigned long default_mem_req=0;
-
-static int hwscroll=-1;
-
-static int use_hwscroll = 1;
-
-static int sttt_xres=640,st_yres=400,tt_yres=480;
-static int sttt_xres_virtual=640,sttt_yres_virtual=400;
-static int ovsc_offset=0, ovsc_addlen=0;
-int ovsc_switchmode=0;
-
-static struct atari_fb_par {
- unsigned long screen_base;
- int yres_virtual;
- union {
- struct {
- int mode;
- int sync;
- } tt, st;
- struct falcon_hw {
- /* Here are fields for storing a video mode, as direct
- * parameters for the hardware.
- */
- short sync;
- short line_width;
- short line_offset;
- short st_shift;
- short f_shift;
- short vid_control;
- short vid_mode;
- short xoffset;
- short hht, hbb, hbe, hdb, hde, hss;
- short vft, vbb, vbe, vdb, vde, vss;
- /* auxiliary information */
- short mono;
- short ste_mode;
- short bpp;
- } falcon;
- /* Nothing needed for external mode */
- } hw;
-} current_par;
-
-/* Don't calculate an own resolution, and thus don't change the one found when
- * booting (currently used for the Falcon to keep settings for internal video
- * hardware extensions (e.g. ScreenBlaster) */
-static int DontCalcRes = 0;
-
-#define HHT hw.falcon.hht
-#define HBB hw.falcon.hbb
-#define HBE hw.falcon.hbe
-#define HDB hw.falcon.hdb
-#define HDE hw.falcon.hde
-#define HSS hw.falcon.hss
-#define VFT hw.falcon.vft
-#define VBB hw.falcon.vbb
-#define VBE hw.falcon.vbe
-#define VDB hw.falcon.vdb
-#define VDE hw.falcon.vde
-#define VSS hw.falcon.vss
-#define VCO_CLOCK25 0x04
-#define VCO_CSYPOS 0x10
-#define VCO_VSYPOS 0x20
-#define VCO_HSYPOS 0x40
-#define VCO_SHORTOFFS 0x100
-#define VMO_DOUBLE 0x01
-#define VMO_INTER 0x02
-#define VMO_PREMASK 0x0c
-
-static struct fb_info fb_info;
-
-static unsigned long screen_base; /* base address of screen */
-static unsigned long real_screen_base; /* (only for Overscan) */
-
-static int screen_len;
-
-static int current_par_valid=0;
-
-static int currcon=0;
-
-static int mono_moni=0;
-
-static struct display disp[MAX_NR_CONSOLES];
-
-
-#ifdef ATAFB_EXT
-/* external video handling */
-
-static unsigned external_xres;
-static unsigned external_yres;
-static unsigned external_depth;
-static int external_pmode;
-static unsigned long external_addr = 0;
-static unsigned long external_len;
-static unsigned long external_vgaiobase = 0;
-static unsigned int external_bitspercol = 6;
-
-/*
-++JOE <joe@amber.dinoco.de>:
-added card type for external driver, is only needed for
-colormap handling.
-*/
-
-enum cardtype { IS_VGA, IS_MV300 };
-static enum cardtype external_card_type = IS_VGA;
-
-/*
-The MV300 mixes the color registers. So we need an array of munged
-indices in order to acces the correct reg.
-*/
-static int MV300_reg_1bit[2]={0,1};
-static int MV300_reg_4bit[16]={
-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-static int MV300_reg_8bit[256]={
-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 };
-
-static int *MV300_reg = MV300_reg_8bit;
-
-/*
-And on the MV300 it's difficult to read out the hardware palette. So we
-just keep track of the set colors in our own array here, and use that!
-*/
-
-static struct { unsigned char red,green,blue,pad; } MV300_color[256];
-#endif /* ATAFB_EXT */
-
-
-static int inverse=0;
-
-extern int fontheight_8x8;
-extern int fontwidth_8x8;
-extern unsigned char fontdata_8x8[];
-
-extern int fontheight_8x16;
-extern int fontwidth_8x16;
-extern unsigned char fontdata_8x16[];
-
-/* import first 16 colors from fbcon.c */
-extern unsigned short packed16_cmap[16];
-
-
-/* ++roman: This structure abstracts from the underlying hardware (ST(e),
- * TT, or Falcon.
- *
- * int (*detect)( void )
- * This function should detect the current video mode settings and
- * store them in atari_fb_predefined[0] for later reference by the
- * user. Return the index+1 of an equivalent predefined mode or 0
- * if there is no such.
- *
- * int (*encode_fix)( struct fb_fix_screeninfo *fix,
- * struct atari_fb_par *par )
- * This function should fill in the 'fix' structure based on the
- * values in the 'par' structure.
- *
- * int (*decode_var)( struct fb_var_screeninfo *var,
- * struct atari_fb_par *par )
- * Get the video params out of 'var'. If a value doesn't fit, round
- * it up, if it's too big, return EINVAL.
- * Round up in the following order: bits_per_pixel, xres, yres,
- * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
- * horizontal timing, vertical timing.
- *
- * int (*encode_var)( struct fb_var_screeninfo *var,
- * struct atari_fb_par *par );
- * Fill the 'var' structure based on the values in 'par' and maybe
- * other values read out of the hardware.
- *
- * void (*get_par)( struct atari_fb_par *par )
- * Fill the hardware's 'par' structure.
- *
- * void (*set_par)( struct atari_fb_par *par )
- * Set the hardware according to 'par'.
- *
- * int (*setcolreg)( unsigned regno, unsigned red,
- * unsigned green, unsigned blue,
- * unsigned transp )
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- *
- * int (*getcolreg)( unsigned regno, unsigned *red,
- * unsigned *green, unsigned *blue,
- * unsigned *transp )
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- *
- * void (*set_screen_base)( unsigned long s_base )
- * Set the base address of the displayed frame buffer. Only called
- * if yres_virtual > yres or xres_virtual > xres.
- *
- * int (*blank)( int blank_mode )
- * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
- * the caller blanks by setting the CLUT to all black. Return 0 if blanking
- * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
- * doesn't support it. Implements VESA suspend and powerdown modes on
- * hardware that supports disabling hsync/vsync:
- * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
- */
-
-static struct fb_hwswitch {
- int (*detect)( void );
- int (*encode_fix)( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par );
- int (*decode_var)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par );
- int (*encode_var)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par );
- void (*get_par)( struct atari_fb_par *par );
- void (*set_par)( struct atari_fb_par *par );
- int (*getcolreg)( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp );
- int (*setcolreg)( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp );
- void (*set_screen_base)( unsigned long s_base );
- int (*blank)( int blank_mode );
- int (*pan_display)( struct fb_var_screeninfo *var,
- struct atari_fb_par *par);
-} *fbhw;
-
-static char *autodetect_names[] = {"autodetect", NULL};
-static char *stlow_names[] = {"stlow", NULL};
-static char *stmid_names[] = {"stmid", "default5", NULL};
-static char *sthigh_names[] = {"sthigh", "default4", NULL};
-static char *ttlow_names[] = {"ttlow", NULL};
-static char *ttmid_names[]= {"ttmid", "default1", NULL};
-static char *tthigh_names[]= {"tthigh", "default2", NULL};
-static char *vga2_names[] = {"vga2", NULL};
-static char *vga4_names[] = {"vga4", NULL};
-static char *vga16_names[] = {"vga16", "default3", NULL};
-static char *vga256_names[] = {"vga256", NULL};
-static char *falh2_names[] = {"falh2", NULL};
-static char *falh16_names[] = {"falh16", NULL};
-static char *user0_names[] = {"user0", NULL};
-static char *user1_names[] = {"user1", NULL};
-static char *user2_names[] = {"user2", NULL};
-static char *user3_names[] = {"user3", NULL};
-static char *user4_names[] = {"user4", NULL};
-static char *user5_names[] = {"user5", NULL};
-static char *user6_names[] = {"user6", NULL};
-static char *user7_names[] = {"user7", NULL};
-static char *dummy_names[] = {"dummy", NULL};
-
-static char **fb_var_names[] = {
- /* Writing the name arrays directly in this array (via "(char *[]){...}")
- * crashes gcc 2.5.8 (sigsegv) if the inner array
- * contains more than two items. I've also seen that all elements
- * were identical to the last (my cross-gcc) :-(*/
- autodetect_names,
- stlow_names,
- stmid_names,
- sthigh_names,
- ttlow_names,
- ttmid_names,
- tthigh_names,
- vga2_names,
- vga4_names,
- vga16_names,
- vga256_names,
- falh2_names,
- falh16_names,
- dummy_names, dummy_names, dummy_names, dummy_names,
- dummy_names, dummy_names, dummy_names, dummy_names,
- dummy_names, dummy_names,
- user0_names,
- user1_names,
- user2_names,
- user3_names,
- user4_names,
- user5_names,
- user6_names,
- user7_names,
- NULL
- /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
-};
-
-static struct fb_var_screeninfo atari_fb_predefined[] = {
- /*
- * yres_virtual==0 means use hw-scrolling if possible, else yres
- */
- { /* autodetect */
- 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
- {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* st low */
- 320, 200, 320, 0, 0, 0, 4, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* st mid */
- 640, 200, 640, 0, 0, 0, 2, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* st high */
- 640, 400, 640, 0, 0, 0, 1, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* tt low */
- 320, 480, 320, 0, 0, 0, 8, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* tt mid */
- 640, 480, 640, 0, 0, 0, 4, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* tt high */
- 1280, 960, 1280, 0, 0, 0, 1, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* vga2 */
- 640, 480, 640, 0, 0, 0, 1, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* vga4 */
- 640, 480, 640, 0, 0, 0, 2, 0,
- {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* vga16 */
- 640, 480, 640, 0, 0, 0, 4, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* vga256 */
- 640, 480, 640, 0, 0, 0, 8, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* falh2 */
- 896, 608, 896, 0, 0, 0, 1, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* falh16 */
- 896, 608, 896, 0, 0, 0, 4, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- /* Minor 14..23 free for more standard video modes */
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- { 0, },
- /* Minor 24..31 reserved for user defined video modes */
- { /* user0, initialized to Rx;y;d from commandline, if supplied */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user1 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user2 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user3 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user4 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user5 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user6 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* user7 */
- 0, 0, 0, 0, 0, 0, 0, 0,
- {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-static int num_atari_fb_predefined=arraysize(atari_fb_predefined);
-
-
-static int
-get_video_mode(char *vname)
-{
- char ***name_list;
- char **name;
- int i;
- name_list=fb_var_names;
- for (i = 0 ; i < num_atari_fb_predefined ; i++) {
- name=*(name_list++);
- if (! name || ! *name)
- break;
- while (*name) {
- if (! strcmp(vname, *name))
- return i+1;
- name++;
- }
- }
- return 0;
-}
-
-
-
-/* ------------------- TT specific functions ---------------------- */
-
-#ifdef ATAFB_TT
-
-static int tt_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
-
-{
- int mode, i;
-
- strcpy(fix->id,"Atari Builtin");
- fix->smem_start=real_screen_base;
- fix->smem_len = screen_len;
- fix->type=FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux=2;
- fix->visual=FB_VISUAL_PSEUDOCOLOR;
- mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
- if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->type_aux=0;
- if (mode == TT_SHIFTER_TTHIGH)
- fix->visual=FB_VISUAL_MONO01;
- }
- fix->xpanstep=0;
- fix->ypanstep=1;
- fix->ywrapstep=0;
- fix->line_length = 0;
- for (i=0; i<arraysize(fix->reserved); i++)
- fix->reserved[i]=0;
- return 0;
-}
-
-
-static int tt_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int xres=var->xres;
- int yres=var->yres;
- int bpp=var->bits_per_pixel;
- int linelen;
- int yres_virtual = var->yres_virtual;
-
- if (mono_moni) {
- if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
- return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_TTHIGH;
- xres=sttt_xres*2;
- yres=tt_yres*2;
- bpp=1;
- } else {
- if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
- return -EINVAL;
- if (bpp > 4) {
- if (xres > sttt_xres/2 || yres > tt_yres)
- return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_TTLOW;
- xres=sttt_xres/2;
- yres=tt_yres;
- bpp=8;
- }
- else if (bpp > 2) {
- if (xres > sttt_xres || yres > tt_yres)
- return -EINVAL;
- if (xres > sttt_xres/2 || yres > st_yres/2) {
- par->hw.tt.mode=TT_SHIFTER_TTMID;
- xres=sttt_xres;
- yres=tt_yres;
- bpp=4;
- }
- else {
- par->hw.tt.mode=TT_SHIFTER_STLOW;
- xres=sttt_xres/2;
- yres=st_yres/2;
- bpp=4;
- }
- }
- else if (bpp > 1) {
- if (xres > sttt_xres || yres > st_yres/2)
- return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_STMID;
- xres=sttt_xres;
- yres=st_yres/2;
- bpp=2;
- }
- else if (var->xres > sttt_xres || var->yres > st_yres) {
- return -EINVAL;
- }
- else {
- par->hw.tt.mode=TT_SHIFTER_STHIGH;
- xres=sttt_xres;
- yres=st_yres;
- bpp=1;
- }
- }
- if (yres_virtual <= 0)
- yres_virtual = 0;
- else if (yres_virtual < yres)
- yres_virtual = yres;
- if (var->sync & FB_SYNC_EXT)
- par->hw.tt.sync=0;
- else
- par->hw.tt.sync=1;
- linelen=xres*bpp/8;
- if (yres_virtual * linelen > screen_len && screen_len)
- return -EINVAL;
- if (yres * linelen > screen_len && screen_len)
- return -EINVAL;
- if (var->yoffset + yres > yres_virtual && yres_virtual)
- return -EINVAL;
- par->yres_virtual = yres_virtual;
- par->screen_base = screen_base + var->yoffset * linelen;
- return 0;
-}
-
-static int tt_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int linelen, i;
- var->red.offset=0;
- var->red.length=4;
- var->red.msb_right=0;
- var->grayscale=0;
-
- var->pixclock=31041;
- var->left_margin=120; /* these may be incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
-
- var->height=-1;
- var->width=-1;
-
- if (par->hw.tt.sync & 1)
- var->sync=0;
- else
- var->sync=FB_SYNC_EXT;
-
- switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
- case TT_SHIFTER_STLOW:
- var->xres=sttt_xres/2;
- var->xres_virtual=sttt_xres_virtual/2;
- var->yres=st_yres/2;
- var->bits_per_pixel=4;
- break;
- case TT_SHIFTER_STMID:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=st_yres/2;
- var->bits_per_pixel=2;
- break;
- case TT_SHIFTER_STHIGH:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=st_yres;
- var->bits_per_pixel=1;
- break;
- case TT_SHIFTER_TTLOW:
- var->xres=sttt_xres/2;
- var->xres_virtual=sttt_xres_virtual/2;
- var->yres=tt_yres;
- var->bits_per_pixel=8;
- break;
- case TT_SHIFTER_TTMID:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=tt_yres;
- var->bits_per_pixel=4;
- break;
- case TT_SHIFTER_TTHIGH:
- var->red.length=0;
- var->xres=sttt_xres*2;
- var->xres_virtual=sttt_xres_virtual*2;
- var->yres=tt_yres*2;
- var->bits_per_pixel=1;
- break;
- }
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- linelen=var->xres_virtual * var->bits_per_pixel / 8;
- if (! use_hwscroll)
- var->yres_virtual=var->yres;
- else if (screen_len)
- if (par->yres_virtual)
- var->yres_virtual = par->yres_virtual;
- else
- /* yres_virtual==0 means use maximum */
- var->yres_virtual = screen_len / linelen;
- else {
- if (hwscroll < 0)
- var->yres_virtual = 2 * var->yres;
- else
- var->yres_virtual=var->yres+hwscroll * 16;
- }
- var->xoffset=0;
- if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
- else
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
- for (i=0; i<arraysize(var->reserved); i++)
- var->reserved[i]=0;
- return 0;
-}
-
-
-static void tt_get_par( struct atari_fb_par *par )
-{
- unsigned long addr;
- par->hw.tt.mode=shifter_tt.tt_shiftmode;
- par->hw.tt.sync=shifter.syncmode;
- addr = ((shifter.bas_hi & 0xff) << 16) |
- ((shifter.bas_md & 0xff) << 8) |
- ((shifter.bas_lo & 0xff));
- par->screen_base = PTOV(addr);
-}
-
-static void tt_set_par( struct atari_fb_par *par )
-{
- shifter_tt.tt_shiftmode=par->hw.tt.mode;
- shifter.syncmode=par->hw.tt.sync;
- /* only set screen_base if really necessary */
- if (current_par.screen_base != par->screen_base)
- fbhw->set_screen_base(par->screen_base);
-}
-
-
-static int tt_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp )
-{
- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
- regno += 254;
- if (regno > 255)
- return 1;
- *blue = tt_palette[regno];
- *green = (*blue >> 4) & 0xf;
- *red = (*blue >> 8) & 0xf;
- *blue &= 0xf;
- *transp = 0;
- return 0;
-}
-
-
-static int tt_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp )
-{
- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
- regno += 254;
- if (regno > 255)
- return 1;
- tt_palette[regno] = (red << 8) | (green << 4) | blue;
- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
- TT_SHIFTER_STHIGH && regno == 254)
- tt_palette[0] = 0;
- return 0;
-}
-
-
-static int tt_detect( void )
-
-{ struct atari_fb_par par;
-
- /* Determine the connected monitor: The DMA sound must be
- * disabled before reading the MFP GPIP, because the Sound
- * Done Signal and the Monochrome Detect are XORed together!
- *
- * Even on a TT, we should look if there is a DMA sound. It was
- * announced that the Eagle is TT compatible, but only the PCM is
- * missing...
- */
- if (ATARIHW_PRESENT(PCM_8BIT)) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- udelay(20); /* wait a while for things to settle down */
- }
- mono_moni = (mfp.par_dt_reg & 0x80) == 0;
-
- tt_get_par(&par);
- tt_encode_var(&atari_fb_predefined[0], &par);
-
- return 1;
-}
-
-#endif /* ATAFB_TT */
-
-/* ------------------- Falcon specific functions ---------------------- */
-
-#ifdef ATAFB_FALCON
-
-static int mon_type; /* Falcon connected monitor */
-static int f030_bus_width; /* Falcon ram bus width (for vid_control) */
-#define F_MON_SM 0
-#define F_MON_SC 1
-#define F_MON_VGA 2
-#define F_MON_TV 3
-
-/* Multisync monitor capabilities */
-/* Atari-TOS defaults if no boot option present */
-static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000;
-
-static struct pixel_clock {
- unsigned long f; /* f/[Hz] */
- unsigned long t; /* t/[ps] (=1/f) */
- int right, hsync, left; /* standard timing in clock cycles, not pixel */
- /* hsync initialized in falcon_detect() */
- int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
- int control_mask; /* ditto, for hw.falcon.vid_control */
-}
-f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
-f32 = {32000000, 31250, 18, 0, 42, 0x0, 0},
-fext = { 0, 0, 18, 0, 42, 0x1, 0};
-
-/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
-
-/* Default hsync timing [mon_type] in picoseconds */
-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
-
-
-static inline int hxx_prescale(struct falcon_hw *hw)
-{
- return hw->ste_mode ? 16 :
- vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
-}
-
-static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
-{
- int i;
-
- strcpy(fix->id, "Atari Builtin");
- fix->smem_start = real_screen_base;
- fix->smem_len = screen_len;
- fix->type = FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux = 2;
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- fix->xpanstep = 1;
- fix->ypanstep = 1;
- fix->ywrapstep = 0;
- if (par->hw.falcon.mono) {
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- /* no smooth scrolling with longword aligned video mem */
- fix->xpanstep = 32;
- }
- else if (par->hw.falcon.f_shift & 0x100) {
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- /* Is this ok or should it be DIRECTCOLOR? */
- fix->visual = FB_VISUAL_TRUECOLOR;
- fix->xpanstep = 2;
- }
- fix->line_length = 0;
- for (i=0; i<arraysize(fix->reserved); i++)
- fix->reserved[i]=0;
- return 0;
-}
-
-
-static int falcon_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int bpp = var->bits_per_pixel;
- int xres = var->xres;
- int yres = var->yres;
- int xres_virtual = var->xres_virtual;
- int yres_virtual = var->yres_virtual;
- int left_margin, right_margin, hsync_len;
- int upper_margin, lower_margin, vsync_len;
- int linelen;
- int interlace = 0, doubleline = 0;
- struct pixel_clock *pclock;
- int plen; /* width of pixel in clock cycles */
- int xstretch;
- int prescale;
- int longoffset = 0;
- int hfreq, vfreq;
-
-/*
- Get the video params out of 'var'. If a value doesn't fit, round
- it up, if it's too big, return EINVAL.
- Round up in the following order: bits_per_pixel, xres, yres,
- xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
- horizontal timing, vertical timing.
-
- There is a maximum of screen resolution determined by pixelclock
- and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
- In interlace mode this is " * " *vfmin <= pixelclock.
- Additional constraints: hfreq.
- Frequency range for multisync monitors is given via command line.
- For TV and SM124 both frequencies are fixed.
-
- X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
- Y % 16 == 0 to fit 8x16 font
- Y % 8 == 0 if Y<400
-
- Currently interlace and doubleline mode in var are ignored.
- On SM124 and TV only the standard resolutions can be used.
-*/
-
- /* Reject uninitialized mode */
- if (!xres || !yres || !bpp)
- return -EINVAL;
-
- if (mon_type == F_MON_SM && bpp != 1) {
- return -EINVAL;
- }
- else if (bpp <= 1) {
- bpp = 1;
- par->hw.falcon.f_shift = 0x400;
- par->hw.falcon.st_shift = 0x200;
- }
- else if (bpp <= 2) {
- bpp = 2;
- par->hw.falcon.f_shift = 0x000;
- par->hw.falcon.st_shift = 0x100;
- }
- else if (bpp <= 4) {
- bpp = 4;
- par->hw.falcon.f_shift = 0x000;
- par->hw.falcon.st_shift = 0x000;
- }
- else if (bpp <= 8) {
- bpp = 8;
- par->hw.falcon.f_shift = 0x010;
- }
- else if (bpp <= 16) {
- bpp = 16; /* packed pixel mode */
- par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
- }
- else
- return -EINVAL;
- par->hw.falcon.bpp = bpp;
-
- if (mon_type == F_MON_SM || DontCalcRes) {
- /* Skip all calculations. VGA/TV/SC1224 only supported. */
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-
- if (bpp > myvar->bits_per_pixel ||
- var->xres > myvar->xres ||
- var->yres > myvar->yres)
- return -EINVAL;
- fbhw->get_par(par); /* Current par will be new par */
- goto set_screen_base; /* Don't forget this */
- }
-
- /* Only some fixed resolutions < 640x400 */
- if (xres <= 320)
- xres = 320;
- else if (xres <= 640 && bpp != 16)
- xres = 640;
- if (yres <= 200)
- yres = 200;
- else if (yres <= 240)
- yres = 240;
- else if (yres <= 400)
- yres = 400;
-
- /* 2 planes must use STE compatibility mode */
- par->hw.falcon.ste_mode = bpp==2;
- par->hw.falcon.mono = bpp==1;
-
- /* Total and visible scanline length must be a multiple of one longword,
- * this and the console fontwidth yields the alignment for xres and
- * xres_virtual.
- * TODO: this way "odd" fontheights are not supported
- *
- * Special case in STE mode: blank and graphic positions don't align,
- * avoid trash at right margin
- */
- if (par->hw.falcon.ste_mode)
- xres = (xres + 63) & ~63;
- else if (bpp == 1)
- xres = (xres + 31) & ~31;
- else
- xres = (xres + 15) & ~15;
- if (yres >= 400)
- yres = (yres + 15) & ~15;
- else
- yres = (yres + 7) & ~7;
-
- if (xres_virtual < xres)
- xres_virtual = xres;
- else if (bpp == 1)
- xres_virtual = (xres_virtual + 31) & ~31;
- else
- xres_virtual = (xres_virtual + 15) & ~15;
-
- if (yres_virtual <= 0)
- yres_virtual = 0;
- else if (yres_virtual < yres)
- yres_virtual = yres;
-
- /* backward bug-compatibility */
- if (var->pixclock > 1)
- var->pixclock -= 1;
-
- par->hw.falcon.line_width = bpp * xres / 16;
- par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
-
- /* single or double pixel width */
- xstretch = (xres < 640) ? 2 : 1;
-
-#if 0 /* SM124 supports only 640x400, this is rejected above */
- if (mon_type == F_MON_SM) {
- if (xres != 640 && yres != 400)
- return -EINVAL;
- plen = 1;
- pclock = &f32;
- /* SM124-mode is special */
- par->hw.falcon.ste_mode = 1;
- par->hw.falcon.f_shift = 0x000;
- par->hw.falcon.st_shift = 0x200;
- left_margin = hsync_len = 128 / plen;
- right_margin = 0;
- /* TODO set all margins */
- }
- else
-#endif
- if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
- plen = 2 * xstretch;
- if (var->pixclock > f32.t * plen)
- return -EINVAL;
- pclock = &f32;
- if (yres > 240)
- interlace = 1;
- if (var->pixclock == 0) {
- /* set some minimal margins which center the screen */
- left_margin = 32;
- right_margin = 18;
- hsync_len = pclock->hsync / plen;
- upper_margin = 31;
- lower_margin = 14;
- vsync_len = interlace ? 3 : 4;
- } else {
- left_margin = var->left_margin;
- right_margin = var->right_margin;
- hsync_len = var->hsync_len;
- upper_margin = var->upper_margin;
- lower_margin = var->lower_margin;
- vsync_len = var->vsync_len;
- if (var->vmode & FB_VMODE_INTERLACED) {
- upper_margin = (upper_margin + 1) / 2;
- lower_margin = (lower_margin + 1) / 2;
- vsync_len = (vsync_len + 1) / 2;
- } else if (var->vmode & FB_VMODE_DOUBLE) {
- upper_margin *= 2;
- lower_margin *= 2;
- vsync_len *= 2;
- }
- }
- }
- else
- { /* F_MON_VGA */
- if (bpp == 16)
- xstretch = 2; /* Double pixel width only for hicolor */
- /* Default values are used for vert./hor. timing if no pixelclock given. */
- if (var->pixclock == 0) {
- int linesize;
-
- /* Choose master pixelclock depending on hor. timing */
- plen = 1 * xstretch;
- if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f)
- pclock = &f25;
- else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f)
- pclock = &f32;
- else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f
- && fext.f)
- pclock = &fext;
- else
- return -EINVAL;
-
- left_margin = pclock->left / plen;
- right_margin = pclock->right / plen;
- hsync_len = pclock->hsync / plen;
- linesize = left_margin + xres + right_margin + hsync_len;
- upper_margin = 31;
- lower_margin = 11;
- vsync_len = 3;
- }
- else {
- /* Choose largest pixelclock <= wanted clock */
- int i;
- unsigned long pcl = ULONG_MAX;
- pclock = 0;
- for (i=1; i <= 4; i *= 2) {
- if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
- pcl = f25.t * i;
- pclock = &f25;
- }
- if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
- pcl = f32.t * i;
- pclock = &f32;
- }
- if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
- pcl = fext.t * i;
- pclock = &fext;
- }
- }
- if (!pclock)
- return -EINVAL;
- plen = pcl / pclock->t;
-
- left_margin = var->left_margin;
- right_margin = var->right_margin;
- hsync_len = var->hsync_len;
- upper_margin = var->upper_margin;
- lower_margin = var->lower_margin;
- vsync_len = var->vsync_len;
- /* Internal unit is [single lines per (half-)frame] */
- if (var->vmode & FB_VMODE_INTERLACED) {
- /* # lines in half frame */
- /* External unit is [lines per full frame] */
- upper_margin = (upper_margin + 1) / 2;
- lower_margin = (lower_margin + 1) / 2;
- vsync_len = (vsync_len + 1) / 2;
- }
- else if (var->vmode & FB_VMODE_DOUBLE) {
- /* External unit is [double lines per frame] */
- upper_margin *= 2;
- lower_margin *= 2;
- vsync_len *= 2;
- }
- }
- if (pclock == &fext)
- longoffset = 1; /* VIDEL doesn't synchronize on short offset */
- }
- /* Is video bus bandwidth (32MB/s) too low for this resolution? */
- /* this is definitely wrong if bus clock != 32MHz */
- if (pclock->f / plen / 8 * bpp > 32000000L)
- return -EINVAL;
-
- if (vsync_len < 1)
- vsync_len = 1;
-
- /* include sync lengths in right/lower margin for all calculations */
- right_margin += hsync_len;
- lower_margin += vsync_len;
-
- /* ! In all calculations of margins we use # of lines in half frame
- * (which is a full frame in non-interlace mode), so we can switch
- * between interlace and non-interlace without messing around
- * with these.
- */
- again:
- /* Set base_offset 128 and video bus width */
- par->hw.falcon.vid_control = mon_type | f030_bus_width;
- if (!longoffset)
- par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- par->hw.falcon.vid_control |= VCO_HSYPOS;
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- par->hw.falcon.vid_control |= VCO_VSYPOS;
- /* Pixelclock */
- par->hw.falcon.vid_control |= pclock->control_mask;
- /* External or internal clock */
- par->hw.falcon.sync = pclock->sync_mask | 0x2;
- /* Pixellength and prescale */
- par->hw.falcon.vid_mode = (2/plen) << 2;
- if (doubleline)
- par->hw.falcon.vid_mode |= VMO_DOUBLE;
- if (interlace)
- par->hw.falcon.vid_mode |= VMO_INTER;
-
- /*********************
- Horizontal timing: unit = [master clock cycles]
- unit of hxx-registers: [master clock cycles * prescale]
- Hxx-registers are 9 bit wide
-
- 1 line = ((hht + 2) * 2 * prescale) clock cycles
-
- graphic output = hdb & 0x200 ?
- ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
- ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
- (this must be a multiple of plen*128/bpp, on VGA pixels
- to the right may be cut off with a bigger right margin)
-
- start of graphics relative to start of 1st halfline = hdb & 0x200 ?
- (hdb - hht - 2) * prescale + hdboff :
- hdb * prescale + hdboff
-
- end of graphics relative to start of 1st halfline =
- (hde + hht + 2) * prescale + hdeoff
- *********************/
- /* Calculate VIDEL registers */
- {
- int hdb_off, hde_off, base_off;
- int gstart, gend1, gend2, align;
-
- prescale = hxx_prescale(&par->hw.falcon);
- base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
-
- /* Offsets depend on video mode */
- /* Offsets are in clock cycles, divide by prescale to
- * calculate hd[be]-registers
- */
- if (par->hw.falcon.f_shift & 0x100) {
- align = 1;
- hde_off = 0;
- hdb_off = (base_off + 16 * plen) + prescale;
- }
- else {
- align = 128 / bpp;
- hde_off = ((128 / bpp + 2) * plen);
- if (par->hw.falcon.ste_mode)
- hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
- else
- hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
- }
-
- gstart = (prescale/2 + plen * left_margin) / prescale;
- /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
- gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
- /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
- gend2 = gstart + xres * plen / prescale;
- par->HHT = plen * (left_margin + xres + right_margin) /
- (2 * prescale) - 2;
-/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
-
- par->HDB = gstart - hdb_off/prescale;
- par->HBE = gstart;
- if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
- par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
- par->HBB = gend2 - par->HHT - 2;
-#if 0
- /* One more Videl constraint: data fetch of two lines must not overlap */
- if (par->HDB & 0x200 && par->HDB & ~0x200 - par->HDE <= 5) {
- /* if this happens increase margins, decrease hfreq. */
- }
-#endif
- if (hde_off % prescale)
- par->HBB++; /* compensate for non matching hde and hbb */
- par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
- if (par->HSS < par->HBB)
- par->HSS = par->HBB;
- }
-
- /* check hor. frequency */
- hfreq = pclock->f / ((par->HHT+2)*prescale*2);
- if (hfreq > hfmax && mon_type!=F_MON_VGA) {
- /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
- /* Too high -> enlarge margin */
- left_margin += 1;
- right_margin += 1;
- goto again;
- }
- if (hfreq > hfmax || hfreq < hfmin)
- return -EINVAL;
-
- /* Vxx-registers */
- /* All Vxx must be odd in non-interlace, since frame starts in the middle
- * of the first displayed line!
- * One frame consists of VFT+1 half lines. VFT+1 must be even in
- * non-interlace, odd in interlace mode for synchronisation.
- * Vxx-registers are 11 bit wide
- */
- par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
- par->VDB = par->VBE;
- par->VDE = yres;
- if (!interlace) par->VDE <<= 1;
- if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */
- par->VDE += par->VDB;
- par->VBB = par->VDE;
- par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
- par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
- /* vbb,vss,vft must be even in interlace mode */
- if (interlace) {
- par->VBB++;
- par->VSS++;
- par->VFT++;
- }
-
- /* V-frequency check, hope I didn't create any loop here. */
- /* Interlace and doubleline are mutually exclusive. */
- vfreq = (hfreq * 2) / (par->VFT + 1);
- if (vfreq > vfmax && !doubleline && !interlace) {
- /* Too high -> try again with doubleline */
- doubleline = 1;
- goto again;
- }
- else if (vfreq < vfmin && !interlace && !doubleline) {
- /* Too low -> try again with interlace */
- interlace = 1;
- goto again;
- }
- else if (vfreq < vfmin && doubleline) {
- /* Doubleline too low -> clear doubleline and enlarge margins */
- int lines;
- doubleline = 0;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>vfmax; lines++)
- ;
- upper_margin += lines;
- lower_margin += lines;
- goto again;
- }
- else if (vfreq > vfmax && doubleline) {
- /* Doubleline too high -> enlarge margins */
- int lines;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines+=2)
- ;
- upper_margin += lines;
- lower_margin += lines;
- goto again;
- }
- else if (vfreq > vfmax && interlace) {
- /* Interlace, too high -> enlarge margins */
- int lines;
- for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++)
- ;
- upper_margin += lines;
- lower_margin += lines;
- goto again;
- }
- else if (vfreq < vfmin || vfreq > vfmax)
- return -EINVAL;
-
- set_screen_base:
- linelen = xres_virtual * bpp / 8;
- if (yres_virtual * linelen > screen_len && screen_len)
- return -EINVAL;
- if (yres * linelen > screen_len && screen_len)
- return -EINVAL;
- if (var->yoffset + yres > yres_virtual && yres_virtual)
- return -EINVAL;
- par->yres_virtual = yres_virtual;
- par->screen_base = screen_base + var->yoffset * linelen;
- par->hw.falcon.xoffset = 0;
-
- return 0;
-}
-
-static int falcon_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
-/* !!! only for VGA !!! */
- int linelen, i;
- int prescale, plen;
- int hdb_off, hde_off, base_off;
- struct falcon_hw *hw = &par->hw.falcon;
-
- /* possible frequencies: 25.175 or 32MHz */
- var->pixclock = hw->sync & 0x1 ? fext.t :
- hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
-
- var->height=-1;
- var->width=-1;
-
- var->sync=0;
- if (hw->vid_control & VCO_HSYPOS)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (hw->vid_control & VCO_VSYPOS)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
-
- var->vmode = FB_VMODE_NONINTERLACED;
- if (hw->vid_mode & VMO_INTER)
- var->vmode |= FB_VMODE_INTERLACED;
- if (hw->vid_mode & VMO_DOUBLE)
- var->vmode |= FB_VMODE_DOUBLE;
-
- /* visible y resolution:
- * Graphics display starts at line VDB and ends at line
- * VDE. If interlace mode off unit of VC-registers is
- * half lines, else lines.
- */
- var->yres = hw->vde - hw->vdb;
- if (!(var->vmode & FB_VMODE_INTERLACED))
- var->yres >>= 1;
- if (var->vmode & FB_VMODE_DOUBLE)
- var->yres >>= 1;
-
- /* to get bpp, we must examine f_shift and st_shift.
- * f_shift is valid if any of bits no. 10, 8 or 4
- * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
- * if bit 10 set then bit 8 and bit 4 don't care...
- * If all these bits are 0 get display depth from st_shift
- * (as for ST and STE)
- */
- if (hw->f_shift & 0x400) /* 2 colors */
- var->bits_per_pixel = 1;
- else if (hw->f_shift & 0x100) /* hicolor */
- var->bits_per_pixel = 16;
- else if (hw->f_shift & 0x010) /* 8 bitplanes */
- var->bits_per_pixel = 8;
- else if (hw->st_shift == 0)
- var->bits_per_pixel = 4;
- else if (hw->st_shift == 0x100)
- var->bits_per_pixel = 2;
- else /* if (hw->st_shift == 0x200) */
- var->bits_per_pixel = 1;
-
- var->xres = hw->line_width * 16 / var->bits_per_pixel;
- var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
- if (hw->xoffset)
- var->xres_virtual += 16;
-
- if (var->bits_per_pixel == 16) {
- var->red.offset=11;
- var->red.length=5;
- var->red.msb_right=0;
- var->green.offset=5;
- var->green.length=6;
- var->green.msb_right=0;
- var->blue.offset=0;
- var->blue.length=5;
- var->blue.msb_right=0;
- }
- else {
- var->red.offset=0;
- var->red.length = hw->ste_mode ? 4 : 6;
- var->red.msb_right=0;
- var->grayscale=0;
- var->blue=var->green=var->red;
- }
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
-
- linelen = var->xres_virtual * var->bits_per_pixel / 8;
- if (screen_len)
- if (par->yres_virtual)
- var->yres_virtual = par->yres_virtual;
- else
- /* yres_virtual==0 means use maximum */
- var->yres_virtual = screen_len / linelen;
- else {
- if (hwscroll < 0)
- var->yres_virtual = 2 * var->yres;
- else
- var->yres_virtual=var->yres+hwscroll * 16;
- }
- var->xoffset=0; /* TODO change this */
-
- /* hdX-offsets */
- prescale = hxx_prescale(hw);
- plen = 4 >> (hw->vid_mode >> 2 & 0x3);
- base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
- if (hw->f_shift & 0x100) {
- hde_off = 0;
- hdb_off = (base_off + 16 * plen) + prescale;
- }
- else {
- hde_off = ((128 / var->bits_per_pixel + 2) * plen);
- if (hw->ste_mode)
- hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
- + prescale;
- else
- hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
- + prescale;
- }
-
- /* Right margin includes hsync */
- var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
- (hw->hdb & 0x200 ? 2+hw->hht : 0));
- if (hw->ste_mode || mon_type!=F_MON_VGA)
- var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
- else
- /* can't use this in ste_mode, because hbb is +1 off */
- var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
- var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
-
- /* Lower margin includes vsync */
- var->upper_margin = hw->vdb / 2 ; /* round down to full lines */
- var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
- var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
- if (var->vmode & FB_VMODE_INTERLACED) {
- var->upper_margin *= 2;
- var->lower_margin *= 2;
- var->vsync_len *= 2;
- }
- else if (var->vmode & FB_VMODE_DOUBLE) {
- var->upper_margin = (var->upper_margin + 1) / 2;
- var->lower_margin = (var->lower_margin + 1) / 2;
- var->vsync_len = (var->vsync_len + 1) / 2;
- }
-
- var->pixclock *= plen;
- var->left_margin /= plen;
- var->right_margin /= plen;
- var->hsync_len /= plen;
-
- var->right_margin -= var->hsync_len;
- var->lower_margin -= var->vsync_len;
-
- if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
- else
- var->yoffset=0;
- var->nonstd=0; /* what is this for? */
- var->activate=0;
- for (i=0; i<arraysize(var->reserved); i++)
- var->reserved[i]=0;
- return 0;
-}
-
-
-static int f_change_mode = 0;
-static struct falcon_hw f_new_mode;
-static int f_pan_display = 0;
-
-static void falcon_get_par( struct atari_fb_par *par )
-{
- unsigned long addr;
- struct falcon_hw *hw = &par->hw.falcon;
-
- hw->line_width = shifter_f030.scn_width;
- hw->line_offset = shifter_f030.off_next;
- hw->st_shift = videl.st_shift & 0x300;
- hw->f_shift = videl.f_shift;
- hw->vid_control = videl.control;
- hw->vid_mode = videl.mode;
- hw->sync = shifter.syncmode & 0x1;
- hw->xoffset = videl.xoffset & 0xf;
- hw->hht = videl.hht;
- hw->hbb = videl.hbb;
- hw->hbe = videl.hbe;
- hw->hdb = videl.hdb;
- hw->hde = videl.hde;
- hw->hss = videl.hss;
- hw->vft = videl.vft;
- hw->vbb = videl.vbb;
- hw->vbe = videl.vbe;
- hw->vdb = videl.vdb;
- hw->vde = videl.vde;
- hw->vss = videl.vss;
-
- addr = (shifter.bas_hi & 0xff) << 16 |
- (shifter.bas_md & 0xff) << 8 |
- (shifter.bas_lo & 0xff);
- par->screen_base = PTOV(addr);
-
- /* derived parameters */
- hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
- hw->mono = (hw->f_shift & 0x400) ||
- ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
-}
-
-static void falcon_set_par( struct atari_fb_par *par )
-{
- f_change_mode = 0;
-
- /* only set screen_base if really necessary */
- if (current_par.screen_base != par->screen_base)
- fbhw->set_screen_base(par->screen_base);
-
- /* Don't touch any other registers if we keep the default resolution */
- if (DontCalcRes)
- return;
-
- /* Tell vbl-handler to change video mode.
- * We change modes only on next VBL, to avoid desynchronisation
- * (a shift to the right and wrap around by a random number of pixels
- * in all monochrome modes).
- * This seems to work on my Falcon.
- */
- f_new_mode = par->hw.falcon;
- f_change_mode = 1;
-}
-
-
-static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
-{
- struct falcon_hw *hw = &f_new_mode;
-
- if (f_change_mode) {
- f_change_mode = 0;
-
- if (hw->sync & 0x1) {
- /* Enable external pixelclock. This code only for ScreenWonder */
- *(volatile unsigned short*)0xffff9202 = 0xffbf;
- }
- else {
- /* Turn off external clocks. Read sets all output bits to 1. */
- *(volatile unsigned short*)0xffff9202;
- }
- shifter.syncmode = hw->sync;
-
- videl.hht = hw->hht;
- videl.hbb = hw->hbb;
- videl.hbe = hw->hbe;
- videl.hdb = hw->hdb;
- videl.hde = hw->hde;
- videl.hss = hw->hss;
- videl.vft = hw->vft;
- videl.vbb = hw->vbb;
- videl.vbe = hw->vbe;
- videl.vdb = hw->vdb;
- videl.vde = hw->vde;
- videl.vss = hw->vss;
-
- videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
- if (hw->ste_mode) {
- videl.st_shift = hw->st_shift; /* write enables STE palette */
- }
- else {
- /* IMPORTANT:
- * set st_shift 0, so we can tell the screen-depth if f_shift==0.
- * Writing 0 to f_shift enables 4 plane Falcon mode but
- * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
- * with Falcon palette.
- */
- videl.st_shift = 0;
- /* now back to Falcon palette mode */
- videl.f_shift = hw->f_shift;
- }
- /* writing to st_shift changed scn_width and vid_mode */
- videl.xoffset = hw->xoffset;
- shifter_f030.scn_width = hw->line_width;
- shifter_f030.off_next = hw->line_offset;
- videl.control = hw->vid_control;
- videl.mode = hw->vid_mode;
- }
- if (f_pan_display) {
- f_pan_display = 0;
- videl.xoffset = current_par.hw.falcon.xoffset;
- shifter_f030.off_next = current_par.hw.falcon.line_offset;
- }
-}
-
-
-static int falcon_pan_display( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int xoffset;
- int bpp = disp[currcon].var.bits_per_pixel;
-
- if (bpp == 1)
- var->xoffset = up(var->xoffset, 32);
- if (bpp != 16)
- par->hw.falcon.xoffset = var->xoffset & 15;
- else {
- par->hw.falcon.xoffset = 0;
- var->xoffset = up(var->xoffset, 2);
- }
- par->hw.falcon.line_offset = bpp *
- (disp[currcon].var.xres_virtual - disp[currcon].var.xres) / 16;
- if (par->hw.falcon.xoffset)
- par->hw.falcon.line_offset -= bpp;
- xoffset = var->xoffset - par->hw.falcon.xoffset;
-
- par->screen_base = screen_base +
- (var->yoffset * disp[currcon].var.xres_virtual + xoffset) * bpp / 8;
- if (fbhw->set_screen_base)
- fbhw->set_screen_base (par->screen_base);
- else
- return -EINVAL; /* shouldn't happen */
- f_pan_display = 1;
- return 0;
-}
-
-
-static int falcon_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp )
-{ unsigned long col;
-
- if (regno > 255)
- return 1;
- /* This works in STE-mode (with 4bit/color) since f030_col-registers
- * hold up to 6bit/color.
- * Even with hicolor r/g/b=5/6/5 bit!
- */
- col = f030_col[regno];
- *red = (col >> 26) & 0x3f;
- *green = (col >> 18) & 0x3f;
- *blue = (col >> 2) & 0x3f;
- *transp = 0;
- return 0;
-}
-
-
-static int falcon_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp )
-{
- if (regno > 255)
- return 1;
- f030_col[regno] = (red << 26) | (green << 18) | (blue << 2);
- if (regno < 16) {
- shifter_tt.color_reg[regno] =
- (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
- (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
- ((blue & 0xe) >> 1) | ((blue & 1) << 3);
- packed16_cmap[regno] = (red << 11) | (green << 5) | blue;
- }
- return 0;
-}
-
-
-static int falcon_blank( int blank_mode )
-{
-/* ++guenther: we can switch off graphics by changing VDB and VDE,
- * so VIDEL doesn't hog the bus while saving.
- * (this may affect usleep()).
- */
- int vdb, vss, hbe, hss;
-
- if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
- return 1;
-
- vdb = current_par.VDB;
- vss = current_par.VSS;
- hbe = current_par.HBE;
- hss = current_par.HSS;
-
- if (blank_mode >= 1) {
- /* disable graphics output (this speeds up the CPU) ... */
- vdb = current_par.VFT + 1;
- /* ... and blank all lines */
- hbe = current_par.HHT + 2;
- }
- /* use VESA suspend modes on VGA monitors */
- if (mon_type == F_MON_VGA) {
- if (blank_mode == 2 || blank_mode == 4)
- vss = current_par.VFT + 1;
- if (blank_mode == 3 || blank_mode == 4)
- hss = current_par.HHT + 2;
- }
-
- videl.vdb = vdb;
- videl.vss = vss;
- videl.hbe = hbe;
- videl.hss = hss;
-
- return 0;
-}
-
-
-static int falcon_detect( void )
-{
- struct atari_fb_par par;
- unsigned char fhw;
-
- /* Determine connected monitor and set monitor parameters */
- fhw = *(unsigned char*)0xffff8006;
- mon_type = fhw >> 6 & 0x3;
- /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
- f030_bus_width = fhw << 6 & 0x80;
- switch (mon_type) {
- case F_MON_SM:
- vfmin = 70;
- vfmax = 72;
- hfmin = 35713;
- hfmax = 35715;
- break;
- case F_MON_SC:
- case F_MON_TV:
- /* PAL...NTSC */
- vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
- vfmax = 60;
- hfmin = 15620;
- hfmax = 15755;
- break;
- }
- /* initialize hsync-len */
- f25.hsync = h_syncs[mon_type] / f25.t;
- f32.hsync = h_syncs[mon_type] / f32.t;
- if (fext.t)
- fext.hsync = h_syncs[mon_type] / fext.t;
-
- falcon_get_par(&par);
- falcon_encode_var(&atari_fb_predefined[0], &par);
-
- /* Detected mode is always the "autodetect" slot */
- return 1;
-}
-
-#endif /* ATAFB_FALCON */
-
-/* ------------------- ST(E) specific functions ---------------------- */
-
-#ifdef ATAFB_STE
-
-static int stste_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
-
-{
- int mode, i;
-
- strcpy(fix->id,"Atari Builtin");
- fix->smem_start=real_screen_base;
- fix->smem_len=screen_len;
- fix->type=FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux=2;
- fix->visual=FB_VISUAL_PSEUDOCOLOR;
- mode = par->hw.st.mode & 3;
- if (mode == ST_HIGH) {
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->type_aux=0;
- fix->visual=FB_VISUAL_MONO10;
- }
- if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
- fix->xpanstep = 16;
- fix->ypanstep = 1;
- } else {
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- }
- fix->ywrapstep = 0;
- fix->line_length = 0;
- for (i=0; i<arraysize(fix->reserved); i++)
- fix->reserved[i]=0;
- return 0;
-}
-
-
-static int stste_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int xres=var->xres;
- int yres=var->yres;
- int bpp=var->bits_per_pixel;
- int linelen;
- int yres_virtual = var->yres_virtual;
-
- if (mono_moni) {
- if (bpp > 1 || xres > sttt_xres || yres > st_yres)
- return -EINVAL;
- par->hw.st.mode=ST_HIGH;
- xres=sttt_xres;
- yres=st_yres;
- bpp=1;
- } else {
- if (bpp > 4 || xres > sttt_xres || yres > st_yres)
- return -EINVAL;
- if (bpp > 2) {
- if (xres > sttt_xres/2 || yres > st_yres/2)
- return -EINVAL;
- par->hw.st.mode=ST_LOW;
- xres=sttt_xres/2;
- yres=st_yres/2;
- bpp=4;
- }
- else if (bpp > 1) {
- if (xres > sttt_xres || yres > st_yres/2)
- return -EINVAL;
- par->hw.st.mode=ST_MID;
- xres=sttt_xres;
- yres=st_yres/2;
- bpp=2;
- }
- else
- return -EINVAL;
- }
- if (yres_virtual <= 0)
- yres_virtual = 0;
- else if (yres_virtual < yres)
- yres_virtual = yres;
- if (var->sync & FB_SYNC_EXT)
- par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
- else
- par->hw.st.sync=(par->hw.st.sync & ~1);
- linelen=xres*bpp/8;
- if (yres_virtual * linelen > screen_len && screen_len)
- return -EINVAL;
- if (yres * linelen > screen_len && screen_len)
- return -EINVAL;
- if (var->yoffset + yres > yres_virtual && yres_virtual)
- return -EINVAL;
- par->yres_virtual = yres_virtual;
- par->screen_base=screen_base+ var->yoffset*linelen;
- return 0;
-}
-
-static int stste_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int linelen, i;
- var->red.offset=0;
- var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
- var->red.msb_right=0;
- var->grayscale=0;
-
- var->pixclock=31041;
- var->left_margin=120; /* these are incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
-
- var->height=-1;
- var->width=-1;
-
- if (!(par->hw.st.sync & 1))
- var->sync=0;
- else
- var->sync=FB_SYNC_EXT;
-
- switch (par->hw.st.mode & 3) {
- case ST_LOW:
- var->xres=sttt_xres/2;
- var->yres=st_yres/2;
- var->bits_per_pixel=4;
- break;
- case ST_MID:
- var->xres=sttt_xres;
- var->yres=st_yres/2;
- var->bits_per_pixel=2;
- break;
- case ST_HIGH:
- var->xres=sttt_xres;
- var->yres=st_yres;
- var->bits_per_pixel=1;
- break;
- }
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- var->xres_virtual=sttt_xres_virtual;
- linelen=var->xres_virtual * var->bits_per_pixel / 8;
- ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
-
- if (! use_hwscroll)
- var->yres_virtual=var->yres;
- else if (screen_len)
- if (par->yres_virtual)
- var->yres_virtual = par->yres_virtual;
- else
- /* yres_virtual==0 means use maximum */
- var->yres_virtual = screen_len / linelen;
- else {
- if (hwscroll < 0)
- var->yres_virtual = 2 * var->yres;
- else
- var->yres_virtual=var->yres+hwscroll * 16;
- }
- var->xoffset=0;
- if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
- else
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
- for (i=0; i<arraysize(var->reserved); i++)
- var->reserved[i]=0;
- return 0;
-}
-
-
-static void stste_get_par( struct atari_fb_par *par )
-{
- unsigned long addr;
- par->hw.st.mode=shifter_tt.st_shiftmode;
- par->hw.st.sync=shifter.syncmode;
- addr = ((shifter.bas_hi & 0xff) << 16) |
- ((shifter.bas_md & 0xff) << 8);
- if (ATARIHW_PRESENT(EXTD_SHIFTER))
- addr |= (shifter.bas_lo & 0xff);
- par->screen_base = PTOV(addr);
-}
-
-static void stste_set_par( struct atari_fb_par *par )
-{
- shifter_tt.st_shiftmode=par->hw.st.mode;
- shifter.syncmode=par->hw.st.sync;
- /* only set screen_base if really necessary */
- if (current_par.screen_base != par->screen_base)
- fbhw->set_screen_base(par->screen_base);
-}
-
-
-static int stste_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp )
-{ unsigned col;
-
- if (regno > 15)
- return 1;
- col = shifter_tt.color_reg[regno];
- if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
- *red = ((col >> 7) & 0xe) | ((col >> 11) & 1);
- *green = ((col >> 3) & 0xe) | ((col >> 7) & 1);
- *blue = ((col << 1) & 0xe) | ((col >> 3) & 1);
- }
- else {
- *red = (col >> 8) & 0x7;
- *green = (col >> 4) & 0x7;
- *blue = col & 0x7;
- }
- *transp = 0;
- return 0;
-}
-
-
-static int stste_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp )
-{
- if (regno > 15)
- return 1;
- if (ATARIHW_PRESENT(EXTD_SHIFTER))
- shifter_tt.color_reg[regno] =
- (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) |
- (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) |
- ((blue & 0xe) >> 1) | ((blue & 1) << 3);
- else
- shifter_tt.color_reg[regno] =
- ((red & 0x7) << 8) |
- ((green & 0x7) << 4) |
- (blue & 0x7);
- return 0;
-}
-
-
-static int stste_detect( void )
-
-{ struct atari_fb_par par;
-
- /* Determine the connected monitor: The DMA sound must be
- * disabled before reading the MFP GPIP, because the Sound
- * Done Signal and the Monochrome Detect are XORed together!
- */
- if (ATARIHW_PRESENT(PCM_8BIT)) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- udelay(20); /* wait a while for things to settle down */
- }
- mono_moni = (mfp.par_dt_reg & 0x80) == 0;
-
- stste_get_par(&par);
- stste_encode_var(&atari_fb_predefined[0], &par);
-
- if (!ATARIHW_PRESENT(EXTD_SHIFTER))
- use_hwscroll = 0;
- return 1;
-}
-
-static void stste_set_screen_base(unsigned long s_base)
-{
- unsigned long addr;
- addr= VTOP(s_base);
- /* Setup Screen Memory */
- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
- if (ATARIHW_PRESENT(EXTD_SHIFTER))
- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
-}
-
-#endif /* ATAFB_STE */
-
-/* Switching the screen size should be done during vsync, otherwise
- * the margins may get messed up. This is a well known problem of
- * the ST's video system.
- *
- * Unfortunately there is hardly any way to find the vsync, as the
- * vertical blank interrupt is no longer in time on machines with
- * overscan type modifications.
- *
- * We can, however, use Timer B to safely detect the black shoulder,
- * but then we've got to guess an appropriate delay to find the vsync.
- * This might not work on every machine.
- *
- * martin_rogge @ ki.maus.de, 8th Aug 1995
- */
-
-#define LINE_DELAY (mono_moni ? 30 : 70)
-#define SYNC_DELAY (mono_moni ? 1500 : 2000)
-
-/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
-static void st_ovsc_switch(int switchmode)
-{
- unsigned long flags;
- register unsigned char old, new;
-
- if ((switchmode & (SWITCH_ACIA | SWITCH_SND6 | SWITCH_SND7)) == 0)
- return;
- save_flags(flags);
- cli();
-
- mfp.tim_ct_b = 0x10;
- mfp.active_edge |= 8;
- mfp.tim_ct_b = 0;
- mfp.tim_dt_b = 0xf0;
- mfp.tim_ct_b = 8;
- while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
- ;
- new = mfp.tim_dt_b;
- do {
- udelay(LINE_DELAY);
- old = new;
- new = mfp.tim_dt_b;
- } while (old != new);
- mfp.tim_ct_b = 0x10;
- udelay(SYNC_DELAY);
-
- if (switchmode == SWITCH_ACIA)
- acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE);
- else {
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | switchmode;
- }
- restore_flags(flags);
-}
-
-/* ------------------- External Video ---------------------- */
-
-#ifdef ATAFB_EXT
-
-static int ext_encode_fix( struct fb_fix_screeninfo *fix,
- struct atari_fb_par *par )
-
-{
- int i;
-
- strcpy(fix->id,"Unknown Extern");
- fix->smem_start=external_addr;
- fix->smem_len=(external_len + PAGE_SIZE -1) & PAGE_MASK;
- if (external_depth == 1) {
- fix->type = FB_TYPE_PACKED_PIXELS;
- /* The letters 'n' and 'i' in the "atavideo=external:" stand
- * for "normal" and "inverted", rsp., in the monochrome case */
- fix->visual =
- (external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
- external_pmode == FB_TYPE_PACKED_PIXELS) ?
- FB_VISUAL_MONO10 :
- FB_VISUAL_MONO01;
- }
- else {
- switch (external_pmode) {
- /* All visuals are STATIC, because we don't know how to change
- * colors :-(
- */
- case -1: /* truecolor */
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->visual=FB_VISUAL_TRUECOLOR;
- break;
- case FB_TYPE_PACKED_PIXELS:
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
- break;
- case FB_TYPE_PLANES:
- fix->type=FB_TYPE_PLANES;
- fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
- break;
- case FB_TYPE_INTERLEAVED_PLANES:
- fix->type=FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux=2;
- fix->visual=FB_VISUAL_STATIC_PSEUDOCOLOR;
- break;
- }
- }
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
- for (i=0; i<arraysize(fix->reserved); i++)
- fix->reserved[i]=0;
- return 0;
-}
-
-
-static int ext_decode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-
- if (var->bits_per_pixel > myvar->bits_per_pixel ||
- var->xres > myvar->xres ||
- var->yres > myvar->yres ||
- var->xoffset > 0 ||
- var->yoffset > 0)
- return -EINVAL;
- return 0;
-}
-
-
-static int ext_encode_var( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- int i;
-
- var->red.offset=0;
- var->red.length=(external_pmode == -1) ? external_depth/3 :
- (external_vgaiobase ? external_bitspercol : 0);
- var->red.msb_right=0;
- var->grayscale=0;
-
- var->pixclock=31041;
- var->left_margin=120; /* these are surely incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
-
- var->height=-1;
- var->width=-1;
-
- var->sync=0;
-
- var->xres = external_xres;
- var->yres = external_yres;
- var->bits_per_pixel = external_depth;
-
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- var->xres_virtual=var->xres;
- var->yres_virtual=var->yres;
- var->xoffset=0;
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
- for (i=0; i<arraysize(var->reserved); i++)
- var->reserved[i]=0;
- return 0;
-}
-
-
-static void ext_get_par( struct atari_fb_par *par )
-{
- par->screen_base = external_addr;
-}
-
-static void ext_set_par( struct atari_fb_par *par )
-{
-}
-
-#define OUTB(port,val) \
- *((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
-#define INB(port) \
- (*((unsigned volatile char *) ((port)+external_vgaiobase)))
-#define DACDelay \
- do { \
- unsigned char tmp=INB(0x3da); \
- tmp=INB(0x3da); \
- } while (0)
-
-static int ext_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp )
-
-{ unsigned char colmask = (1 << external_bitspercol) - 1;
-
- if (! external_vgaiobase)
- return 1;
-
- switch (external_card_type) {
- case IS_VGA:
- OUTB(0x3c7, regno);
- DACDelay;
- *red=INB(0x3c9) & colmask;
- DACDelay;
- *green=INB(0x3c9) & colmask;
- DACDelay;
- *blue=INB(0x3c9) & colmask;
- DACDelay;
- return 0;
-
- case IS_MV300:
- *red = MV300_color[regno].red;
- *green = MV300_color[regno].green;
- *blue = MV300_color[regno].blue;
- *transp=0;
- return 0;
-
- default:
- return 1;
- }
-}
-
-static int ext_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp )
-
-{ unsigned char colmask = (1 << external_bitspercol) - 1;
-
- if (! external_vgaiobase)
- return 1;
-
- switch (external_card_type) {
- case IS_VGA:
- OUTB(0x3c8, regno);
- DACDelay;
- OUTB(0x3c9, red & colmask);
- DACDelay;
- OUTB(0x3c9, green & colmask);
- DACDelay;
- OUTB(0x3c9, blue & colmask);
- DACDelay;
- return 0;
-
- case IS_MV300:
- MV300_color[regno].red = red;
- MV300_color[regno].green = green;
- MV300_color[regno].blue = blue;
- OUTB((MV300_reg[regno] << 2)+1, red);
- OUTB((MV300_reg[regno] << 2)+1, green);
- OUTB((MV300_reg[regno] << 2)+1, blue);
- return 0;
-
- default:
- return 1;
- }
-}
-
-
-static int ext_detect( void )
-
-{
- struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
- struct atari_fb_par dummy_par;
-
- myvar->xres = external_xres;
- myvar->yres = external_yres;
- myvar->bits_per_pixel = external_depth;
- ext_encode_var(myvar, &dummy_par);
- return 1;
-}
-
-#endif /* ATAFB_EXT */
-
-/* ------ This is the same for most hardware types -------- */
-
-static void set_screen_base(unsigned long s_base)
-{
- unsigned long addr;
- addr= VTOP(s_base);
- /* Setup Screen Memory */
- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
-}
-
-
-static int pan_display( struct fb_var_screeninfo *var,
- struct atari_fb_par *par )
-{
- if (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)
- return -EINVAL;
- else
- var->xoffset = up(var->xoffset, 16);
- par->screen_base = screen_base +
- (var->yoffset * disp[currcon].var.xres_virtual + var->xoffset)
- * disp[currcon].var.bits_per_pixel / 8;
- if (fbhw->set_screen_base)
- fbhw->set_screen_base (par->screen_base);
- else
- return -EINVAL;
- return 0;
-}
-
-
-/* ------------ Interfaces to hardware functions ------------ */
-
-
-#ifdef ATAFB_TT
-static struct fb_hwswitch tt_switch = {
- tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
- tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg,
- set_screen_base, NULL, pan_display
-};
-#endif
-
-#ifdef ATAFB_FALCON
-static struct fb_hwswitch falcon_switch = {
- falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
- falcon_get_par, falcon_set_par, falcon_getcolreg,
- falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display
-};
-#endif
-
-#ifdef ATAFB_STE
-static struct fb_hwswitch st_switch = {
- stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
- stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg,
- stste_set_screen_base, NULL, pan_display
-};
-#endif
-
-#ifdef ATAFB_EXT
-static struct fb_hwswitch ext_switch = {
- ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
- ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL
-};
-#endif
-
-
-
-static void atari_fb_get_par( struct atari_fb_par *par )
-{
- if (current_par_valid) {
- *par=current_par;
- }
- else
- fbhw->get_par(par);
-}
-
-
-static void atari_fb_set_par( struct atari_fb_par *par )
-{
- fbhw->set_par(par);
- current_par=*par;
- current_par_valid=1;
-}
-
-
-
-/* =========================================================== */
-/* ============== Hardware Independent Functions ============= */
-/* =========================================================== */
-
-
-/* used for hardware scrolling */
-
-static int
-fb_update_var(int con)
-{
- int off=disp[con].var.yoffset*disp[con].var.xres_virtual*
- disp[con].var.bits_per_pixel>>3;
-
- current_par.screen_base=screen_base + off;
-
- if (fbhw->set_screen_base)
- fbhw->set_screen_base(current_par.screen_base);
- return 0;
-}
-
-static int
-do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err,activate;
- struct atari_fb_par par;
- if ((err=fbhw->decode_var(var, &par)))
- return err;
- activate=var->activate;
- if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
- atari_fb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate=activate;
- return 0;
-}
-
-/* Functions for handling colormap */
-
-/* there seems to be a bug in gcc 2.5.8 which inhibits using an other solution */
-/* I always get a sigsegv */
-
-static short red16[]=
- { 0x0000,0x0000,0x0000,0x0000,0xc000,0xc000,0xc000,0xc000,
- 0x8000,0x0000,0x0000,0x0000,0xffff,0xffff,0xffff,0xffff};
-static short green16[]=
- { 0x0000,0x0000,0xc000,0xc000,0x0000,0x0000,0xc000,0xc000,
- 0x8000,0x0000,0xffff,0xffff,0x0000,0x0000,0xffff,0xffff};
-static short blue16[]=
- { 0x0000,0xc000,0x0000,0xc000,0x0000,0xc000,0x0000,0xc000,
- 0x8000,0xffff,0x0000,0xffff,0x0000,0xffff,0x0000,0xffff};
-
-static short red4[]=
- { 0x0000,0xc000,0x8000,0xffff};
-static short green4[]=
- { 0x0000,0xc000,0x8000,0xffff};
-static short blue4[]=
- { 0x0000,0xc000,0x8000,0xffff};
-
-static short red2[]=
- { 0x0000,0xffff};
-static short green2[]=
- { 0x0000,0xffff};
-static short blue2[]=
- { 0x0000,0xffff};
-
-static struct fb_cmap default_16_colors = {
- 0, 16, red16, green16, blue16, NULL
-};
-static struct fb_cmap default_4_colors = {
- 0, 4, red4, green4, blue4, NULL
-};
-static struct fb_cmap default_2_colors = {
- 0, 2, red2, green2, blue2, NULL
-};
-
-static struct fb_cmap *
-get_default_colormap(int bpp)
-{
- if (bpp == 1)
- return &default_2_colors;
- if (bpp == 2)
- return &default_4_colors;
- return &default_16_colors;
-}
-
-#define CNVT_TOHW(val,width) (((val) << (width)) + 0x7fff - (val)) >> 16
-#define CNVT_FROMHW(val,width) ((width)?((((val) << 16) - (val)) / ((1<<(width))-1)):0)
-
-
-static int
-do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc)
-{
- int i,start;
- unsigned short *red,*green,*blue,*transp;
- unsigned int hred,hgreen,hblue,htransp;
-
- red=cmap->red;
- green=cmap->green;
- blue=cmap->blue;
- transp=cmap->transp;
- start=cmap->start;
- if (start < 0)
- return EINVAL;
- for (i=0 ; i < cmap->len ; i++) {
- if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp))
- return 0;
- hred=CNVT_FROMHW(hred,var->red.length);
- hgreen=CNVT_FROMHW(hgreen,var->green.length);
- hblue=CNVT_FROMHW(hblue,var->blue.length);
- htransp=CNVT_FROMHW(htransp,var->transp.length);
- if (kspc) {
- *red=hred;
- *green=hgreen;
- *blue=hblue;
- if (transp) *transp=htransp;
- }
- else {
- put_user(hred, red);
- put_user(hgreen, green);
- put_user(hblue, blue);
- if (transp) put_user(htransp, transp);
- }
- red++;
- green++;
- blue++;
- if (transp) transp++;
- }
- return 0;
-}
-
-static int
-do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc)
-{
- int i,start;
- unsigned short *red,*green,*blue,*transp;
- unsigned int hred,hgreen,hblue,htransp;
-
- red=cmap->red;
- green=cmap->green;
- blue=cmap->blue;
- transp=cmap->transp;
- start=cmap->start;
-
- if (start < 0)
- return -EINVAL;
- for (i=0 ; i < cmap->len ; i++) {
- if (kspc) {
- hred=*red;
- hgreen=*green;
- hblue=*blue;
- htransp=(transp) ? *transp : 0;
- }
- else {
- get_user(hred, red);
- get_user(hgreen, green);
- get_user(hblue, blue);
- if (transp)
- get_user(htransp, transp);
- else
- htransp = 0;
- }
- hred=CNVT_TOHW(hred,var->red.length);
- hgreen=CNVT_TOHW(hgreen,var->green.length);
- hblue=CNVT_TOHW(hblue,var->blue.length);
- htransp=CNVT_TOHW(htransp,var->transp.length);
- red++;
- green++;
- blue++;
- if (transp) transp++;
- if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp))
- return 0;
- }
- return 0;
-}
-
-static void
-do_install_cmap(int con)
-{
- if (con != currcon)
- return;
- if (disp[con].cmap.len)
- do_fb_set_cmap(&disp[con].cmap, &(disp[con].var), 1);
- else
- do_fb_set_cmap(get_default_colormap(
- disp[con].var.bits_per_pixel), &(disp[con].var), 1);
-}
-
-static void
-memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
- switch (fsfromto) {
- case 0:
- memcpy(to,from,len);
- return;
- case 1:
- copy_from_user(to,from,len);
- return;
- case 2:
- copy_to_user(to,from,len);
- return;
- }
-}
-
-static void
-copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
-{
- int size;
- int tooff=0, fromoff=0;
-
- if (to->start > from->start)
- fromoff=to->start-from->start;
- else
- tooff=from->start-to->start;
- size=to->len-tooff;
- if (size > from->len-fromoff)
- size=from->len-fromoff;
- if (size < 0)
- return;
- size*=sizeof(unsigned short);
- memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
- memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
- memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
- if (from->transp && to->transp)
- memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
-}
-
-static int
-alloc_cmap(struct fb_cmap *cmap,int len,int transp)
-{
- int size=len*sizeof(unsigned short);
- if (cmap->len != len) {
- if (cmap->red)
- kfree(cmap->red);
- if (cmap->green)
- kfree(cmap->green);
- if (cmap->blue)
- kfree(cmap->blue);
- if (cmap->transp)
- kfree(cmap->transp);
- cmap->red=cmap->green=cmap->blue=cmap->transp=NULL;
- cmap->len=0;
- if (! len)
- return 0;
- if (! (cmap->red=kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (! (cmap->green=kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (! (cmap->blue=kmalloc(size, GFP_ATOMIC)))
- return -1;
- if (transp) {
- if (! (cmap->transp=kmalloc(size, GFP_ATOMIC)))
- return -1;
- }
- else
- cmap->transp=NULL;
- }
- cmap->start=0;
- cmap->len=len;
- copy_cmap(get_default_colormap(len), cmap, 0);
- return 0;
-}
-
-static int
-atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con)
-{
- struct atari_fb_par par;
- if (con == -1)
- atari_fb_get_par(&par);
- else
- fbhw->decode_var(&disp[con].var,&par);
- return fbhw->encode_fix(fix, &par);
-}
-
-static int
-atari_fb_get_var(struct fb_var_screeninfo *var, int con)
-{
- struct atari_fb_par par;
- if (con == -1) {
- atari_fb_get_par(&par);
- fbhw->encode_var(var, &par);
- }
- else
- *var=disp[con].var;
- return 0;
-}
-
-static void
-atari_fb_set_disp(int con)
-{
- struct fb_fix_screeninfo fix;
-
- atari_fb_get_fix(&fix, con);
- if (con == -1)
- con=0;
- disp[con].screen_base = (u_char *)fix.smem_start;
- disp[con].visual = fix.visual;
- disp[con].type = fix.type;
- disp[con].type_aux = fix.type_aux;
- disp[con].ypanstep = fix.ypanstep;
- disp[con].ywrapstep = fix.ywrapstep;
- disp[con].line_length = fix.line_length;
- if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
- fix.visual != FB_VISUAL_DIRECTCOLOR)
- disp[con].can_soft_blank = 0;
- else
- disp[con].can_soft_blank = 1;
- disp[con].inverse =
- (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
-}
-
-static int
-atari_fb_set_var(struct fb_var_screeninfo *var, int con)
-{
- int err,oldxres,oldyres,oldbpp,oldxres_virtual,
- oldyres_virtual,oldyoffset;
- if ((err=do_fb_set_var(var, con==currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres=disp[con].var.xres;
- oldyres=disp[con].var.yres;
- oldxres_virtual=disp[con].var.xres_virtual;
- oldyres_virtual=disp[con].var.yres_virtual;
- oldbpp=disp[con].var.bits_per_pixel;
- oldyoffset=disp[con].var.yoffset;
- disp[con].var=*var;
- if (oldxres != var->xres || oldyres != var->yres
- || oldxres_virtual != var->xres_virtual
- || oldyres_virtual != var->yres_virtual
- || oldbpp != var->bits_per_pixel
- || oldyoffset != var->yoffset) {
- atari_fb_set_disp(con);
- (*fb_info.changevar)(con);
- alloc_cmap(&disp[con].cmap, 0, 0);
- do_install_cmap(con);
- }
- }
- var->activate=0;
- return 0;
-}
-
-
-
-static int
-atari_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- if (con == currcon) /* current console ? */
- return do_fb_get_cmap(cmap, &(disp[con].var), kspc);
- else
- if (disp[con].cmap.len) /* non default colormap ? */
- copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2);
- else
- copy_cmap(get_default_colormap(
- disp[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
- return 0;
-}
-
-static int
-atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con)
-{
- int err;
- if (! disp[con].cmap.len) { /* no colormap allocated ? */
- if ((err = alloc_cmap(&disp[con].cmap,
- 1 << disp[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == currcon) /* current console ? */
- return do_fb_set_cmap(cmap, &(disp[con].var), kspc);
- else
- copy_cmap(cmap, &disp[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-static int
-atari_fb_pan_display(struct fb_var_screeninfo *var, int con)
-{
- int xoffset = var->xoffset;
- int yoffset = var->yoffset;
- int err;
-
- if ( xoffset < 0 || xoffset + disp[con].var.xres > disp[con].var.xres_virtual
- || yoffset < 0 || yoffset + disp[con].var.yres > disp[con].var.yres_virtual)
- return -EINVAL;
-
- if (con == currcon) {
- if (fbhw->pan_display) {
- if ((err = fbhw->pan_display(var, &current_par)))
- return err;
- }
- else
- return -EINVAL;
- }
- disp[con].var.xoffset = var->xoffset;
- disp[con].var.yoffset = var->yoffset;
- return 0;
-}
-
-static int
-atari_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg, int con)
-{
- switch (cmd) {
-#ifdef FBCMD_GET_CURRENTPAR
- case FBCMD_GET_CURRENTPAR:
- if (copy_to_user((void *)arg, (void *)&current_par,
- sizeof(struct atari_fb_par)))
- return -EFAULT;
- return 0;
-#endif
-#ifdef FBCMD_SET_CURRENTPAR
- case FBCMD_SET_CURRENTPAR:
- if (copy_from_user((void *)&current_par, (void *)arg,
- sizeof(struct atari_fb_par)))
- return -EFAULT;
- atari_fb_set_par(&current_par);
- return 0;
-#endif
- }
- return -EINVAL;
-}
-
-static struct fb_ops atari_fb_ops = {
- atari_fb_get_fix, atari_fb_get_var, atari_fb_set_var, atari_fb_get_cmap,
- atari_fb_set_cmap, atari_fb_pan_display, atari_fb_ioctl
-};
-
-static void
-check_default_par( int detected_mode )
-{
- char default_name[10];
- int i;
- struct fb_var_screeninfo var;
- unsigned long min_mem;
-
- /* First try the user supplied mode */
- if (default_par) {
- var=atari_fb_predefined[default_par-1];
- var.activate = FB_ACTIVATE_TEST;
- if (do_fb_set_var(&var,1))
- default_par=0; /* failed */
- }
- /* Next is the autodetected one */
- if (! default_par) {
- var=atari_fb_predefined[detected_mode-1]; /* autodetect */
- var.activate = FB_ACTIVATE_TEST;
- if (!do_fb_set_var(&var,1))
- default_par=detected_mode;
- }
- /* If that also failed, try some default modes... */
- if (! default_par) {
- /* try default1, default2... */
- for (i=1 ; i < 10 ; i++) {
- sprintf(default_name,"default%d",i);
- default_par=get_video_mode(default_name);
- if (! default_par)
- panic("can't set default video mode\n");
- var=atari_fb_predefined[default_par-1];
- var.activate = FB_ACTIVATE_TEST;
- if (! do_fb_set_var(&var,1))
- break; /* ok */
- }
- }
- min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
- if (default_mem_req < min_mem)
- default_mem_req=min_mem;
-}
-
-static int
-atafb_switch(int con)
-{
- /* Do we have to save the colormap ? */
- if (disp[currcon].cmap.len)
- do_fb_get_cmap(&disp[currcon].cmap, &(disp[currcon].var), 1);
- do_fb_set_var(&disp[con].var,1);
- currcon=con;
- /* Install new colormap */
- do_install_cmap(con);
- return 0;
-}
-
-/* (un)blank/poweroff
- * 0 = unblank
- * 1 = blank
- * 2 = suspend vsync
- * 3 = suspend hsync
- * 4 = off
- */
-static void
-atafb_blank(int blank)
-{
- unsigned short black[16];
- struct fb_cmap cmap;
- if (fbhw->blank && !fbhw->blank(blank))
- return;
- if (blank) {
- memset(black, 0, 16*sizeof(unsigned short));
- cmap.red=black;
- cmap.green=black;
- cmap.blue=black;
- cmap.transp=NULL;
- cmap.start=0;
- cmap.len=16;
- do_fb_set_cmap(&cmap, &(disp[currcon].var), 1);
- }
- else
- do_install_cmap(currcon);
-}
-
-static int
-atafb_setcmap(struct fb_cmap *cmap, int con)
-{
- return(atari_fb_set_cmap(cmap, 1, con));
-}
-
-__initfunc(struct fb_info *
-atari_fb_init(long *mem_start))
-{
- int err;
- int pad;
- int detected_mode;
- unsigned long mem_req;
- struct fb_var_screeninfo *var;
-
- err=register_framebuffer("Atari Builtin", &node, &atari_fb_ops,
- num_atari_fb_predefined, atari_fb_predefined);
- if (err < 0)
- panic ("Cannot register frame buffer\n");
- do {
-#ifdef ATAFB_EXT
- if (external_addr) {
- fbhw = &ext_switch;
- break;
- }
-#endif
-#ifdef ATAFB_TT
- if (ATARIHW_PRESENT(TT_SHIFTER)) {
- fbhw = &tt_switch;
- break;
- }
-#endif
-#ifdef ATAFB_FALCON
- if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
- fbhw = &falcon_switch;
- request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
- "framebuffer/modeswitch", falcon_vbl_switcher);
- break;
- }
-#endif
-#ifdef ATAFB_STE
- if (ATARIHW_PRESENT(STND_SHIFTER) ||
- ATARIHW_PRESENT(EXTD_SHIFTER)) {
- fbhw = &st_switch;
- break;
- }
- fbhw = &st_switch;
- printk("Cannot determine video hardware; defaulting to ST(e)\n");
-#else /* ATAFB_STE */
- /* no default driver included */
- /* Nobody will ever see this message :-) */
- panic("Cannot initialize video hardware\n");
-#endif
- } while (0);
- detected_mode = fbhw->detect();
- check_default_par(detected_mode);
-#ifdef ATAFB_EXT
- if (!external_addr) {
-#endif /* ATAFB_EXT */
- mem_req = default_mem_req + ovsc_offset +
- ovsc_addlen;
- mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE;
- screen_base = (unsigned long) atari_stram_alloc(mem_req, mem_start);
- memset((char *) screen_base, 0, mem_req);
- pad = ((screen_base + PAGE_SIZE-1) & PAGE_MASK) - screen_base;
- screen_base+=pad;
- real_screen_base=screen_base+ovsc_offset;
- screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
- st_ovsc_switch(ovsc_switchmode);
- if (CPU_IS_040_OR_060) {
- /* On a '040+, the cache mode of video RAM must be set to
- * write-through also for internal video hardware! */
- cache_push( VTOP(screen_base), screen_len );
- kernel_set_cachemode( screen_base, screen_len,
- KERNELMAP_NO_COPYBACK );
- }
-#ifdef ATAFB_EXT
- }
- else {
- /* Map the video memory (physical address given) to somewhere
- * in the kernel address space.
- */
- *mem_start = (*mem_start+PAGE_SIZE-1) & ~(PAGE_SIZE-1);
- external_addr = kernel_map(external_addr, external_len,
- KERNELMAP_NO_COPYBACK, mem_start);
- if (external_vgaiobase)
- external_vgaiobase = kernel_map(external_vgaiobase,
- 0x10000, KERNELMAP_NOCACHE_SER, mem_start);
- screen_base =
- real_screen_base = external_addr;
- screen_len = external_len & PAGE_MASK;
- memset ((char *) screen_base, 0, external_len);
- }
-#endif /* ATAFB_EXT */
-
- strcpy(fb_info.modename, "Atari Builtin ");
- fb_info.disp=disp;
- fb_info.switch_con=&atafb_switch;
- fb_info.updatevar=&fb_update_var;
- fb_info.blank=&atafb_blank;
- fb_info.setcmap=&atafb_setcmap;
- var=atari_fb_predefined+default_par-1;
- do_fb_set_var(var,1);
- strcat(fb_info.modename,fb_var_names[default_par-1][0]);
-
- atari_fb_get_var(&disp[0].var, -1);
- atari_fb_set_disp(-1);
- printk("Determined %dx%d, depth %d\n",
- disp[0].var.xres, disp[0].var.yres, disp[0].var.bits_per_pixel );
- do_install_cmap(0);
- return &fb_info;
-}
-
-/* a strtok which returns empty strings, too */
-
-static char * strtoke(char * s,const char * ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin) {
- return NULL;
- }
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
-void atari_video_setup( char *options, int *ints )
-{
- char *this_opt;
- int temp;
- char ext_str[80], int_str[100];
- char mcap_spec[80];
- char user_mode[80];
-
- ext_str[0] =
- int_str[0] =
- mcap_spec[0] =
- user_mode[0] =
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options)
- return;
-
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
- if (!*this_opt) continue;
- if ((temp=get_video_mode(this_opt)))
- default_par=temp;
- else if (! strcmp(this_opt, "inverse"))
- inverse=1;
- else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else if (! strncmp(this_opt, "hwscroll_",9)) {
- hwscroll=simple_strtoul(this_opt+9, NULL, 10);
- if (hwscroll < 0)
- hwscroll = 0;
- if (hwscroll > 200)
- hwscroll = 200;
- }
- else if (! strncmp(this_opt, "sw_",3)) {
- if (! strcmp(this_opt+3, "acia"))
- ovsc_switchmode = SWITCH_ACIA;
- else if (! strcmp(this_opt+3, "snd6"))
- ovsc_switchmode = SWITCH_SND6;
- else if (! strcmp(this_opt+3, "snd7"))
- ovsc_switchmode = SWITCH_SND7;
- else ovsc_switchmode = SWITCH_NONE;
- }
-#ifdef ATAFB_EXT
- else if (!strcmp(this_opt,"mv300")) {
- external_bitspercol = 8;
- external_card_type = IS_MV300;
- }
- else if (!strncmp(this_opt,"external:",9))
- strcpy(ext_str, this_opt+9);
-#endif
- else if (!strncmp(this_opt,"internal:",9))
- strcpy(int_str, this_opt+9);
-#ifdef ATAFB_FALCON
- else if (!strncmp(this_opt, "eclock:", 7)) {
- fext.f = simple_strtoul(this_opt+7, NULL, 10);
- /* external pixelclock in kHz --> ps */
- fext.t = 1000000000/fext.f;
- fext.f *= 1000;
- }
- else if (!strncmp(this_opt, "monitorcap:", 11))
- strcpy(mcap_spec, this_opt+11);
-#endif
- else if (!strcmp(this_opt, "keep"))
- DontCalcRes = 1;
- else if (!strncmp(this_opt, "R", 1))
- strcpy(user_mode, this_opt+1);
- }
-
- if (*int_str) {
- /* Format to config extended internal video hardware like OverScan:
- "<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
- Explanation:
- <switch-type> type to switch on higher resolution
- sw_acia : via keyboard ACIA
- sw_snd6 : via bit 6 of the soundchip port
- sw_snd7 : via bit 7 of the soundchip port
- <xres>: x-resolution
- <yres>: y-resolution
- The following are only needed if you have an overscan which
- needs a black border:
- <xres_max>: max. length of a line in pixels your OverScan hardware would allow
- <yres_max>: max. number of lines your OverScan hardware would allow
- <offset>: Offset from physical beginning to visible beginning
- of screen in bytes
- */
- int xres;
- char *p;
-
- if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
- xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
- sttt_xres=xres;
- tt_yres=st_yres=simple_strtoul(p, NULL, 10);
- if ((p=strtoke(NULL, ";")) && *p) {
- sttt_xres_virtual=simple_strtoul(p, NULL, 10);
- }
- if ((p=strtoke(NULL, ";")) && *p) {
- sttt_yres_virtual=simple_strtoul(p, NULL, 0);
- }
- if ((p=strtoke(NULL, ";")) && *p) {
- ovsc_offset=simple_strtoul(p, NULL, 0);
- }
-
- if (ovsc_offset || (sttt_yres_virtual != st_yres))
- use_hwscroll=0;
- }
- else
- int_invalid: ovsc_switchmode = SWITCH_NONE;
-
-#ifdef ATAFB_EXT
- if (*ext_str) {
- int xres, yres, depth, planes;
- unsigned long addr, len;
- char *p;
-
- /* Format is: <xres>;<yres>;<depth>;<plane organ.>;
- * <screen mem addr>
- * [;<screen mem length>[;<vgaiobase>[;<colorreg-type>]]]
- */
- if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
- xres = simple_strtoul(p, NULL, 10);
- if (xres <= 0) goto ext_invalid;
-
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
- yres = simple_strtoul(p, NULL, 10);
- if (yres <= 0) goto ext_invalid;
-
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
- depth = simple_strtoul(p, NULL, 10);
- if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
- depth != 16 && depth != 24) goto ext_invalid;
-
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
- if (*p == 'i')
- planes = FB_TYPE_INTERLEAVED_PLANES;
- else if (*p == 'p')
- planes = FB_TYPE_PACKED_PIXELS;
- else if (*p == 'n')
- planes = FB_TYPE_PLANES;
- else if (*p == 't')
- planes = -1; /* true color */
- else
- goto ext_invalid;
-
-
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
- addr = simple_strtoul(p, NULL, 0);
-
- if (!(p = strtoke(NULL, ";")) ||!*p)
- len = xres*yres*depth/8;
- else
- len = simple_strtoul(p, NULL, 0);
-
- if ((p = strtoke(NULL, ";")) && *p)
- external_vgaiobase=simple_strtoul(p, NULL, 0);
-
- if ((p = strtoke(NULL, ";")) && *p) {
- external_bitspercol = simple_strtoul(p, NULL, 0);
- if (external_bitspercol > 8)
- external_bitspercol = 8;
- else if (external_bitspercol < 1)
- external_bitspercol = 1;
- }
-
- if ((p = strtoke(NULL, ";")) && *p) {
- if (!strcmp(this_opt, "vga"))
- external_card_type = IS_VGA;
- if (!strcmp(this_opt, "mv300"))
- external_card_type = IS_MV300;
- }
-
- external_xres = xres;
- external_yres = yres;
- external_depth = depth;
- external_pmode = planes;
- external_addr = addr;
- external_len = len;
-
- if (external_card_type == IS_MV300)
- switch (external_depth) {
- case 1:
- MV300_reg = MV300_reg_1bit;
- break;
- case 4:
- MV300_reg = MV300_reg_4bit;
- break;
- case 8:
- MV300_reg = MV300_reg_8bit;
- break;
- }
-
- ext_invalid:
- ;
- }
-#endif /* ATAFB_EXT */
-
-#ifdef ATAFB_FALCON
- if (*mcap_spec) {
- char *p;
- int vmin, vmax, hmin, hmax;
-
- /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
- * <V*> vertical freq. in Hz
- * <H*> horizontal freq. in kHz
- */
- if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
- vmin = simple_strtoul(p, NULL, 10);
- if (vmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
- vmax = simple_strtoul(p, NULL, 10);
- if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
- hmin = 1000 * simple_strtoul(p, NULL, 10);
- if (hmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
- hmax = 1000 * simple_strtoul(p, NULL, 10);
- if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
-
- vfmin = vmin;
- vfmax = vmax;
- hfmin = hmin;
- hfmax = hmax;
- cap_invalid:
- ;
- }
-#endif
-
- if (*user_mode) {
- /* Format of user defined video mode is: <xres>;<yres>;<depth>
- */
- char *p;
- int xres, yres, depth, temp;
-
- if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
- xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
- yres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
- depth = simple_strtoul(p, NULL, 10);
- if ((temp=get_video_mode("user0"))) {
- default_par=temp;
- atari_fb_predefined[default_par-1].xres = xres;
- atari_fb_predefined[default_par-1].yres = yres;
- atari_fb_predefined[default_par-1].bits_per_pixel = depth;
- }
-
- user_invalid:
- ;
- }
-}
diff --git a/arch/m68k/atari/atafb.h b/arch/m68k/atari/atafb.h
deleted file mode 100644
index 2bacb7027..000000000
--- a/arch/m68k/atari/atafb.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <linux/fb.h>
-#include <linux/console.h>
-
-
-struct display
-{
- int bytes_per_row; /* offset to one line below */
-
- int cursor_x; /* current cursor position */
- int cursor_y;
-
- int fgcol; /* text colors */
- int bgcol;
-
- struct fb_var_screeninfo var; /* variable infos */
- struct fb_cmap cmap; /* colormap */
-
- /* the following three are copies from fb_fix_screeninfo */
- int visual;
- int type;
- int type_aux;
-
- u_char *bitplane; /* pointer to top of physical screen */
-
- u_char *screen_base; /* pointer to top of virtual screen */
-
- u_char *fontdata; /* Font associated to this display */
- int fontheight;
- int fontwidth;
-
- int inverse; /* != 0 text black on white as default */
- struct vc_data *conp; /* pointer to console data */
- struct display_switch *dispsw; /* pointers to depth specific functions */
-};
-
-struct fb_info
-{
- char modename[40]; /* name of the at boottime detected video mode */
- struct display *disp; /* pointer to display variables */
- int (*changevar)(int); /* tell the console var has changed */
- int (*switch_con)(int); /* tell the framebuffer to switch consoles */
- int (*updatevar)(int); /* tell the framebuffer to update the vars */
- void (*blank)(int); /* tell the framebuffer to (un)blank the screen */
-};
-
-struct fb_info *atafb_init(long *);
-
-
diff --git a/arch/m68k/console/Makefile b/arch/m68k/console/Makefile
deleted file mode 100644
index 6c2126a1d..000000000
--- a/arch/m68k/console/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Makefile for Linux arch/m68k/console 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).
-#
-
-GSPA = gspa
-GSPH2C = gspahextoc
-
-L_TARGET = console.a
-L_OBJS = fbcon.o fonts.o font_8x16.o font_8x8.o pearl_8x8.o
-M_OBJS =
-
-ifdef CONFIG_AMIGA_GSP
-L_OBJS := $(L_OBJS) gspcon.o gspcore.o
-endif
-
-include $(TOPDIR)/Rules.make
-
-gspcore.c: gspcore.gsp
- $(GSPA) $< > $*.hex
- $(GSPH2C) $*.hex > gspcore.c
diff --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c
deleted file mode 100644
index 5065e5769..000000000
--- a/arch/m68k/console/fbcon.c
+++ /dev/null
@@ -1,4126 +0,0 @@
-/*
- * linux/arch/m68k/console/fbcon.c -- Low level frame buffer based console
- * driver
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * This file is based on the original Amiga console driver (amicon.c):
- *
- * Copyright (C) 1993 Hamish Macdonald
- * Greg Harp
- * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
- *
- * with work by William Rucklidge (wjr@cs.cornell.edu)
- * Geert Uytterhoeven
- * Jes Sorensen (jds@kom.auc.dk)
- * Martin Apel
- *
- * and on the original Atari console driver (atacon.c):
- *
- * Copyright (C) 1993 Bjoern Brauel
- * Roman Hodek
- *
- * with work by Guenther Kelleter
- * Martin Schaller
- * Andreas Schwab
- *
- *
- * 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.
- */
-
-/*
- * To do:
- * - Implement 16 plane mode.
- * - Add support for 16/24/32 bit packed pixels
- * - Hardware cursor
- */
-
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
-#include <asm/atariints.h>
-#endif
-#ifdef CONFIG_FB_CYBER
-#include "../amiga/s3blit.h"
-#endif
-#include <linux/fb.h>
-#include <asm/font.h>
-#include <asm/machdep.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/vt_kern.h>
-#include <linux/console_struct.h>
-
-/* Import console_blanked from console.c */
-
-extern int console_blanked;
-
-
- /*
- * The following symbols select what modes are supported. They should
- * be settable by the user ("make config") later.
- */
-
-/* Clear all definitions */
-
-#undef CONFIG_FBCON_MONO
-#undef CONFIG_FBCON_ILBM
-#undef CONFIG_FBCON_PLANES
-#undef CONFIG_FBCON_2PLANE
-#undef CONFIG_FBCON_4PLANE
-#undef CONFIG_FBCON_8PLANE
-#undef CONFIG_FBCON_8PACKED
-#undef CONFIG_FBCON_16PACKED
-#undef CONFIG_FBCON_24PACKED
-#undef CONFIG_FBCON_32PACKED
-#undef CONFIG_FBCON_CYBER
-#undef CONFIG_FBCON_RETINAZ3
-
-/* Monochrome is default */
-
-#define CONFIG_FBCON_MONO
-
-/* Amiga support */
-
-#ifdef CONFIG_AMIGA
-#ifndef CONFIG_FBCON_ILBM
-#define CONFIG_FBCON_ILBM
-#endif
-#ifndef CONFIG_FBCON_PLANES
-#define CONFIG_FBCON_PLANES
-#endif
-
-/* Cybervision Graphics Board */
-
-#ifdef CONFIG_FB_CYBER
-#ifndef CONFIG_FBCON_CYBER
-#define CONFIG_FBCON_CYBER
-#endif
-#endif
-
-/* RetinaZ3 Graphics Board */
-
-#ifdef CONFIG_FB_RETINAZ3
-#ifndef CONFIG_FBCON_RETINAZ3
-#define CONFIG_FBCON_RETINAZ3
-#endif
-#ifndef CONFIG_FBCON_8PACKED
-#define CONFIG_FBCON_8PACKED
-#endif
-#endif
-
-#endif /* CONFIG_AMIGA */
-
-/* Atari support */
-
-#ifdef CONFIG_ATARI
-#ifndef CONFIG_FBCON_2PLANE
-#define CONFIG_FBCON_2PLANE
-#endif
-#ifndef CONFIG_FBCON_4PLANE
-#define CONFIG_FBCON_4PLANE
-#endif
-#ifndef CONFIG_FBCON_8PLANE
-#define CONFIG_FBCON_8PLANE
-#endif
-#ifndef CONFIG_FBCON_8PACKED
-#define CONFIG_FBCON_8PACKED
-#endif
-#ifndef CONFIG_FBCON_16PACKED
-#define CONFIG_FBCON_16PACKED
-#endif
-#endif /* CONFIG_ATARI */
-
-
-/* Extra definitions to make the code more readable */
-
-#if defined(CONFIG_FBCON_2PLANE) || defined(CONFIG_FBCON_4PLANE) || \
- defined(CONFIG_FBCON_8PLANE)
-#define CONFIG_FBCON_IPLAN2
-#else
-#undef CONFIG_FBCON_IPLAN2
-#endif
-
-#if defined(CONFIG_FBCON_CYBER) || defined(CONFIG_FBCON_RETINAZ3) || \
- defined(CONFIG_FBCON_8PACKED) || defined(CONFIG_FBCON_16PACKED) || \
- defined(CONFIG_FBCON_24PACKED) || defined(CONFIG_FBCON_32PACKED)
-#define CONFIG_FBCON_PACKED
-#else
-#undef CONFIG_FBCON_PACKED
-#endif
-
-
-static struct fb_info *fb_info;
-static struct display *disp;
-
-
-/* ++Geert: Sorry, no hardware cursor support at the moment;
- use Atari alike software cursor */
-
-static int cursor_drawn = 0;
-
-#define CURSOR_DRAW_DELAY (2)
-
-/* # VBL ints between cursor state changes */
-#define AMIGA_CURSOR_BLINK_RATE (20)
-#define ATARI_CURSOR_BLINK_RATE (42)
-
-static int vbl_cursor_cnt = 0;
-static int cursor_on = 0;
-static int cursor_blink_rate;
-
-static __inline__ int CURSOR_UNDRAWN(void)
-{
- int cursor_was_drawn;
- vbl_cursor_cnt = 0;
- cursor_was_drawn = cursor_drawn;
- cursor_drawn = 0;
- return(cursor_was_drawn);
-}
-
- /*
- * Attribute Decoding
- */
-
-/* Color */
-#define attr_fgcol(p,conp) \
- (((conp)->vc_attr >> ((p)->inverse ? 4 : 0)) & 0x0f)
-#define attr_bgcol(p,conp) \
- (((conp)->vc_attr >> ((p)->inverse ? 0 : 4)) & 0x0f)
-#define attr_bgcol_ec(p,conp) \
- (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
-
-/* Monochrome */
-#define attr_bold(p,conp) \
- (((conp)->vc_attr & 3) == 2)
-#define attr_reverse(p,conp) \
- (((conp)->vc_attr & 8) ^ ((p)->inverse ? 8 : 0))
-#define attr_underline(p,conp) \
- (((conp)->vc_attr) & 4)
-
-
- /*
- * Scroll Method
- */
-
-#define SCROLL_YWRAP (0)
-#define SCROLL_YPAN (1)
-#define SCROLL_YMOVE (2)
-
-#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
-
-
- /*
- * Interface used by the world
- */
-
-static u_long fbcon_startup(u_long kmem_start, const char **display_desc);
-static void fbcon_init(struct vc_data *conp);
-static int fbcon_deinit(struct vc_data *conp);
-static int fbcon_changevar(int con);
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width);
-static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx);
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy,
- int xx);
-static int fbcon_cursor(struct vc_data *conp, int mode);
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width);
-static int fbcon_switch(struct vc_data *conp);
-static int fbcon_blank(int blank);
-static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
-static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
-static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
-
-
- /*
- * Internal routines
- */
-
-static void fbcon_setup(int con, int setcol, int init);
-static __inline__ void *mymemclear_small(void *s, size_t count);
-static __inline__ void *mymemclear(void *s, size_t count);
-static __inline__ void *mymemset(void *s, size_t count);
-static __inline__ void *mymemmove(void *d, void *s, size_t count);
-static __inline__ void fast_memmove(char *dst, char *src, size_t size);
-static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr);
-static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
- u_long val2);
-static __inline__ void memmove_4p_col(void *d, void *s, int h, int bpr);
-static __inline__ u_long expand4l(u_char c);
-static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2);
-static __inline__ u_long dup4l(u_char c);
-static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
- u_long val2, int bpr);
-static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
- u_long val2, u_long val3, u_long val4);
-static __inline__ void memmove_8p_col(void *d, void *s, int h, int bpr);
-static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2);
-static __inline__ void memclear_2p_col(void *d, size_t h, u_short val,
- int bpr);
-static __inline__ void memset_even_2p(void *d, size_t count, u_long val);
-static __inline__ void memmove_2p_col(void *d, void *s, int h, int bpr);
-static __inline__ u_short expand2w(u_char c);
-static __inline__ u_long expand2l(u_char c);
-static __inline__ u_short dup2w(u_char c);
-static __inline__ int real_y(struct display *p, int yy);
-static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
-static __inline__ void updatescrollmode(struct display *p);
-static __inline__ void ywrap_up(int unit, struct display *p, int count);
-static __inline__ void ywrap_down(int unit, struct display *p, int count);
-static __inline__ void ypan_up(int unit, struct vc_data *conp,
- struct display *p, int count);
-static __inline__ void ypan_down(int unit, struct vc_data *conp,
- struct display *p, int count);
-static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width, u_int y_break);
-
-
- /*
- * Monochrome
- */
-
-#ifdef CONFIG_FBCON_MONO
-static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_mono(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_MONO */
-
-
- /*
- * Color Interleaved Planes
- */
-
-#ifdef CONFIG_FBCON_ILBM
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_ilbm(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_ILBM */
-
-
- /*
- * Color Planes
- */
-
-#ifdef CONFIG_FBCON_PLANES
-static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_plan(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_PLANES */
-
-
- /*
- * 2 Planes (2-bytes interleave)
- */
-
-#ifdef CONFIG_FBCON_2PLANE
-static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_2_plane(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_2_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_2_plane(struct display *display, int xx, int yy);
-#endif /* CONFIG_FBCON_2PLANE */
-
-
- /*
- * 4 Planes (2-bytes interleave)
- */
-
-#ifdef CONFIG_FBCON_4PLANE
-static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_4_plane(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_4_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_4_plane(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_4PLANE */
-
-
- /*
- * 8 Planes (2-bytes interleave)
- */
-
-#ifdef CONFIG_FBCON_8PLANE
-static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_8_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_8_plane(struct display *display, int xx, int yy);
-#endif /* CONFIG_FBCON_8PLANE */
-
-
- /*
- * 8 bpp Packed Pixels
- */
-
-#ifdef CONFIG_FBCON_8PACKED
-static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_8_packed(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_8_packed(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_8_packed(struct display *p, int xx, int yy);
-#endif /* CONFIG_FBCON_8PACKED */
-
-
- /*
- * 16 bpp Packed Pixels
- */
-
-#ifdef CONFIG_FBCON_16PACKED
-static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width);
-static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_16_packed(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx);
-static void rev_char_16_packed(struct display *p, int xx, int yy);
-#endif */ CONFIG_FBCON_8PACKED */
-
-
- /*
- * Cybervision (accelerated)
- */
-
-#ifdef CONFIG_FBCON_CYBER
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
- int xx);
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
-static void rev_char_cyber(struct display *p, int xx, int yy);
-
-extern void Cyber_WaitQueue(unsigned short fifo);
-extern void Cyber_WaitBlit(void);
-extern void Cyber_BitBLT(unsigned short curx, unsigned short cury,
- unsigned short destx, unsigned short desty,
- unsigned short width, unsigned short height,
- unsigned short mode);
-extern void Cyber_RectFill(unsigned short xx, unsigned short yy,
- unsigned short width, unsigned short
- height, unsigned short mode,
- unsigned short fcolor);
-extern void Cyber_MoveCursor(unsigned short xx, unsigned short yy);
-#endif /* CONFIG_FBCON_CYBER */
-
-#ifdef CONFIG_FBCON_RETINAZ3
-static void clear_retz3(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width);
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width);
-extern void retz3_bitblt(struct fb_var_screeninfo *scr,
- unsigned short srcx, unsigned short srcy, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-static void putc_retz3(struct vc_data *conp, struct display *p, int c,
- int yy, int xx);
-static void putcs_retz3(struct vc_data *conp, struct display *p, const
- char *s, int count, int yy, int xx);
-static void rev_char_retz3(struct display *p, int xx, int yy);
-#endif
-
- /*
- * `switch' for the Low Level Operations
- */
-
-struct display_switch {
- void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, int height,
- int width);
- void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width);
- void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, int xx);
- void (*putcs)(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx);
- void (*rev_char)(struct display *p, int xx, int yy);
-};
-
-
-#ifdef CONFIG_FBCON_MONO
-static struct display_switch dispsw_mono = {
- bmove_mono, clear_mono, putc_mono, putcs_mono, rev_char_mono
-};
-#endif /* CONFIG_FBCON_MONO */
-
-#ifdef CONFIG_FBCON_ILBM
-static struct display_switch dispsw_ilbm = {
- bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, rev_char_ilbm
-};
-#endif /* CONFIG_FBCON_ILBM */
-
-#ifdef CONFIG_FBCON_PLANES
-static struct display_switch dispsw_plan = {
- bmove_plan, clear_plan, putc_plan, putcs_plan, rev_char_plan
-};
-#endif /* CONFIG_FBCON_PLANES */
-
-#ifdef CONFIG_FBCON_2PLANE
-static struct display_switch dispsw_2_plane = {
- bmove_2_plane, clear_2_plane, putc_2_plane, putcs_2_plane, rev_char_2_plane
-};
-#endif /* CONFIG_FBCON_2PLANE */
-
-#ifdef CONFIG_FBCON_4PLANE
-static struct display_switch dispsw_4_plane = {
- bmove_4_plane, clear_4_plane, putc_4_plane, putcs_4_plane, rev_char_4_plane
-};
-#endif /* CONFIG_FBCON_4PLANE */
-
-#ifdef CONFIG_FBCON_8PLANE
-static struct display_switch dispsw_8_plane = {
- bmove_8_plane, clear_8_plane, putc_8_plane, putcs_8_plane, rev_char_8_plane
-};
-#endif /* CONFIG_FBCON_8PLANE */
-
-#ifdef CONFIG_FBCON_8PACKED
-static struct display_switch dispsw_8_packed = {
- bmove_8_packed, clear_8_packed, putc_8_packed, putcs_8_packed, rev_char_8_packed
-};
-#endif /* CONFIG_FBCON_8PACKED */
-
-#ifdef CONFIG_FBCON_16PACKED
-static struct display_switch dispsw_16_packed = {
- bmove_16_packed, clear_16_packed, putc_16_packed, putcs_16_packed,
- rev_char_16_packed
-};
-#endif /* CONFIG_FBCON_16PACKED */
-
-#ifdef CONFIG_FBCON_CYBER
-static struct display_switch dispsw_cyber = {
- bmove_cyber, clear_cyber, putc_cyber, putcs_cyber, rev_char_cyber
-};
-#endif /* CONFIG_FBCON_CYBER */
-
-#ifdef CONFIG_FBCON_RETINAZ3
-static struct display_switch dispsw_retz3 = {
- bmove_retz3, clear_retz3, putc_retz3,
- putcs_retz3, rev_char_retz3
-};
-#endif
-
-
-static u_long fbcon_startup(u_long kmem_start, const char **display_desc)
-{
- int irqres = 0;
-
- fb_info = mach_fb_init(&kmem_start);
- disp = fb_info->disp;
- *display_desc = fb_info->modename;
- fb_info->changevar = &fbcon_changevar;
-
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA) {
- cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE;
- irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0,
- "console/cursor", fbcon_vbl_handler);
- }
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI) {
- cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
- irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO,
- "console/cursor", fbcon_vbl_handler);
- }
-#endif /* CONFIG_ATARI */
-
- if (irqres)
- panic("fbcon_startup: Couldn't add vblank interrupt");
-
- return(kmem_start);
-}
-
-
-static void fbcon_init(struct vc_data *conp)
-{
- int unit = conp->vc_num;
-
- if (unit)
- disp[unit] = disp[0];
- disp[unit].conp = conp;
- fbcon_setup(unit, 1, 1);
-}
-
-
-static int fbcon_deinit(struct vc_data *conp)
-{
- disp[conp->vc_num].conp = 0;
- return(0);
-}
-
-
-static int fbcon_changevar(int con)
-{
- fbcon_setup(con, 1, 0);
- return(0);
-}
-
-
-static __inline__ void updatescrollmode(struct display *p)
-{
- if (divides(p->ywrapstep, p->fontheight) &&
- divides(p->fontheight, p->var.yres_virtual))
- p->scrollmode = SCROLL_YWRAP;
- else if (divides(p->ypanstep, p->fontheight) &&
- p->var.yres_virtual >= p->var.yres+p->fontheight)
- p->scrollmode = SCROLL_YPAN;
- else
- p->scrollmode = SCROLL_YMOVE;
-}
-
-
-static void fbcon_setup(int con, int setcol, int init)
-{
- struct display *p = &disp[con];
- struct vc_data *conp = p->conp;
- int nr_rows, nr_cols;
-
- p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
-
- if (!fb_info->fontname[0] ||
- !findsoftfont(fb_info->fontname, &p->fontwidth, &p->fontheight,
- &p->fontdata) || p->fontwidth != 8)
- getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
- &p->fontheight, &p->fontdata);
- if (p->fontwidth != 8) {
- /* ++Geert: changed from panic() to `correct and continue' */
- printk("fbcon_setup: No support for fontwidth != 8");
- p->fontwidth = 8;
- }
- updatescrollmode(p);
-
- nr_cols = p->var.xres/p->fontwidth;
- nr_rows = p->var.yres/p->fontheight;
- /* ++guenther: console.c:vc_allocate() relies on initializing vc_{cols,rows},
- * but we must not set those if we are only resizing the console.
- */
- if (init) {
- conp->vc_cols = nr_cols;
- conp->vc_rows = nr_rows;
- }
- p->vrows = p->var.yres_virtual/p->fontheight;
- conp->vc_can_do_color = p->var.bits_per_pixel != 1;
-
-#ifdef CONFIG_FBCON_MONO
- if (p->var.bits_per_pixel == 1) {
- if (p->line_length)
- p->next_line = p->line_length;
- else
- p->next_line = p->var.xres_virtual>>3;
- p->next_plane = 0;
- p->dispsw = &dispsw_mono;
- } else
-#endif /* CONFIG_FBCON_MONO */
-#ifdef CONFIG_FBCON_IPLAN2
- if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux == 2) {
- p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3;
- p->next_plane = 0;
-#ifdef CONFIG_FBCON_2PLANE
- if (p->var.bits_per_pixel == 2)
- p->dispsw = &dispsw_2_plane;
- else
-#endif /* CONFIG_FBCON_2PLANE */
-#ifdef CONFIG_FBCON_4PLANE
- if (p->var.bits_per_pixel == 4)
- p->dispsw = &dispsw_4_plane;
- else
-#endif /* CONFIG_FBCON_4PLANE */
-#ifdef CONFIG_FBCON_8PLANE
- if (p->var.bits_per_pixel == 8)
- p->dispsw = &dispsw_8_plane;
- else
-#endif /* CONFIG_FBCON_8PLANE */
- goto fail;
- } else
-#endif /* CONFIG_FBCON_IPLAN2 */
-#ifdef CONFIG_FBCON_ILBM
- if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) {
- if (p->line_length) {
- p->next_line = p->line_length*p->var.bits_per_pixel;
- p->next_plane = p->line_length
-;
- } else {
- p->next_line = p->type_aux;
- p->next_plane = p->type_aux/p->var.bits_per_pixel;
- }
- p->dispsw = &dispsw_ilbm;
- } else
-#endif /* CONFIG_FBCON_ILBM */
-#ifdef CONFIG_FBCON_PLANES
- if (p->type == FB_TYPE_PLANES) {
- if (p->line_length)
- p->next_line = p->line_length;
- else
- p->next_line = p->var.xres_virtual>>3;
- p->next_plane = p->var.yres_virtual*p->next_line;
- p->dispsw = &dispsw_plan;
- } else
-#endif /* CONFIG_FBCON_PLANES */
-#ifdef CONFIG_FBCON_PACKED
- if (p->type == FB_TYPE_PACKED_PIXELS) {
- p->next_line = (p->var.xres_virtual*p->var.bits_per_pixel)>>3;
- p->next_plane = 0;
-#ifdef CONFIG_FBCON_CYBER
- if (p->var.accel == FB_ACCEL_CYBERVISION)
- p->dispsw = &dispsw_cyber;
- else
-#endif
-#ifdef CONFIG_FBCON_RETINAZ3
- if (p->var.accel == FB_ACCEL_RETINAZ3)
- p->dispsw = &dispsw_retz3;
- else
-#endif
-#ifdef CONFIG_FBCON_8PACKED
- if (p->var.bits_per_pixel == 8)
- p->dispsw = &dispsw_8_packed;
- else
-#endif /* CONFIG_FBCON_8PACKED */
-#ifdef CONFIG_FBCON_16PACKED
- if (p->var.bits_per_pixel == 16)
- p->dispsw = &dispsw_16_packed;
- else
-#endif /* CONFIG_FBCON_16PACKED */
-#ifdef CONFIG_FBCON_24PACKED
- if (p->var.bits_per_pixel == 24)
- p->dispsw = &dispsw_24_packed;
- else
-#endif /* CONFIG_FBCON_24PACKED */
-#ifdef CONFIG_FBCON_32PACKED
- if (p->var.bits_per_pixel == 32)
- p->dispsw = &dispsw_32_packed;
- else
-#endif /* CONFIG_FBCON_32PACKED */
- goto fail;
- } else
-#endif /* CONFIG_FBCON_PACKED */
- {
-fail:
-#ifdef CONFIG_FBCON_MONO
- printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n",
- p->type, p->type_aux);
- if (p->line_length)
- p->next_line = p->line_length;
- else
- p->next_line = p->var.xres_virtual>>3;
- p->next_plane = 0;
- p->var.bits_per_pixel = 1;
- p->dispsw = &dispsw_mono;
-#else /* CONFIG_FBCON_MONO */
- panic("fbcon_setup: no default driver");
-#endif /* CONFIG_FBCON_MONO */
- }
-
- if (setcol) {
- p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
- p->bgcol = 0;
- }
-
- if (!init)
- vc_resize_con(nr_rows, nr_cols, con);
-}
-
-
-/* ================================================================= */
-/* Utility Assembler Functions */
-/* ================================================================= */
-
-
-/* ====================================================================== */
-
-/* Those of a delicate disposition might like to skip the next couple of
- * pages.
- *
- * These functions are drop in replacements for memmove and
- * memset(_, 0, _). However their five instances add at least a kilobyte
- * to the object file. You have been warned.
- *
- * Not a great fan of assembler for the sake of it, but I think
- * that these routines are at least 10 times faster than their C
- * equivalents for large blits, and that's important to the lowest level of
- * a graphics driver. Question is whether some scheme with the blitter
- * would be faster. I suspect not for simple text system - not much
- * asynchrony.
- *
- * Code is very simple, just gruesome expansion. Basic strategy is to
- * increase data moved/cleared at each step to 16 bytes to reduce
- * instruction per data move overhead. movem might be faster still
- * For more than 15 bytes, we try to align the write direction on a
- * longword boundary to get maximum speed. This is even more gruesome.
- * Unaligned read/write used requires 68020+ - think this is a problem?
- *
- * Sorry!
- */
-
-
-/* ++roman: I've optimized Robert's original versions in some minor
- * aspects, e.g. moveq instead of movel, let gcc choose the registers,
- * use movem in some places...
- * For other modes than 1 plane, lots of more such assembler functions
- * were needed (e.g. the ones using movep or expanding color values).
- */
-
-/* ++andreas: more optimizations:
- subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
- addal is faster than addaw
- movep is rather expensive compared to ordinary move's
- some functions rewritten in C for clarity, no speed loss */
-
-static __inline__ void *mymemclear_small(void *s, size_t count)
-{
- if (!count)
- return(0);
-
- __asm__ __volatile__(
- "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
- "1: subql #1,%1 ; jcs 3f\n\t"
- "2: moveml %2/%3/%4/%5,%0@-\n\t"
- "dbra %1,2b\n\t"
- "3:"
- : "=a" (s), "=d" (count)
- : "d" (0), "d" (0), "d" (0), "d" (0),
- "0" ((char *)s+count), "1" (count)
- );
-
- return(0);
-}
-
-
-static __inline__ void *mymemclear(void *s, size_t count)
-{
- if (!count)
- return(0);
-
- if (count < 16) {
- __asm__ __volatile__(
- "lsrl #1,%1 ; jcc 1f ; clrb %0@+\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; clrw %0@+\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t"
- "1:"
- : "=a" (s), "=d" (count)
- : "0" (s), "1" (count)
- );
- } else {
- long tmp;
- __asm__ __volatile__(
- "movel %1,%2\n\t"
- "lsrl #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t"
- "lsrl #1,%2 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/
- "clrw %0@+ ; subqw #2,%1 ; jra 2f\n\t"
- "1: lsrl #1,%2 ; jcc 2f\n\t"
- "clrw %0@+ ; subqw #2,%1\n\t"
- "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t"
- "lsrl #1,%1 ; jcc 3f ; clrl %0@+\n\t"
- "3: lsrl #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t"
- "4: subql #1,%1 ; jcs 6f\n\t"
- "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t"
- "dbra %1,5b ; clrw %1; subql #1,%1; jcc 5b\n\t"
- "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t"
- "7: ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t"
- "8:"
- : "=a" (s), "=d" (count), "=d" (tmp)
- : "0" (s), "1" (count)
- );
- }
-
- return(0);
-}
-
-
-static __inline__ void *mymemset(void *s, size_t count)
-{
- if (!count)
- return(0);
-
- __asm__ __volatile__(
- "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
- "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
- "1: subql #1,%1 ; jcs 3f\n\t"
- "2: moveml %2/%3/%4/%5,%0@-\n\t"
- "dbra %1,2b\n\t"
- "3:"
- : "=a" (s), "=d" (count)
- : "d" (-1), "d" (-1), "d" (-1), "d" (-1),
- "0" ((char *) s + count), "1" (count)
- );
-
- return(0);
-}
-
-
-static __inline__ void *mymemmove(void *d, void *s, size_t count)
-{
- if (d < s) {
- if (count < 16) {
- __asm__ __volatile__(
- "lsrl #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
- "1:"
- : "=a" (d), "=a" (s), "=d" (count)
- : "0" (d), "1" (s), "2" (count)
- );
- } else {
- long tmp;
- __asm__ __volatile__(
- "movel %0,%3\n\t"
- "lsrl #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t"
- "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/
- "movew %1@+,%0@+ ; subqw #2,%2 ; jra 2f\n\t"
- "1: lsrl #1,%3 ; jcc 2f\n\t"
- "movew %1@+,%0@+ ; subqw #2,%2\n\t"
- "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
- "lsrl #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t"
- "3: lsrl #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t"
- "4: subql #1,%2 ; jcs 6f\n\t"
- "5: movel %1@+,%0@+;movel %1@+,%0@+\n\t"
- "movel %1@+,%0@+;movel %1@+,%0@+\n\t"
- "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
- "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t"
- "7: ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t"
- "8:"
- : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
- : "0" (d), "1" (s), "2" (count)
- );
- }
- } else {
- if (count < 16) {
- __asm__ __volatile__(
- "lsrl #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t"
- "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
- "1:"
- : "=a" (d), "=a" (s), "=d" (count)
- : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
- );
- } else {
- long tmp;
- __asm__ __volatile__(
- "movel %0,%3\n\t"
- "lsrl #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t"
- "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/
- "movew %1@-,%0@- ; subqw #2,%2 ; jra 2f\n\t"
- "1: lsrl #1,%3 ; jcc 2f\n\t"
- "movew %1@-,%0@- ; subqw #2,%2\n\t"
- "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
- "lsrl #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t"
- "3: lsrl #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t"
- "4: subql #1,%2 ; jcs 6f\n\t"
- "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t"
- "movel %1@-,%0@-;movel %1@-,%0@-\n\t"
- "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
- "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t"
- "7: ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t"
- "8:"
- : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
- : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
- );
- }
- }
-
- return(0);
-}
-
-
-/* ++andreas: Simple and fast version of memmove, assumes size is
- divisible by 16, suitable for moving the whole screen bitplane */
-static __inline__ void fast_memmove(char *dst, char *src, size_t size)
-{
- if (!size)
- return;
- if (dst < src)
- __asm__ __volatile__
- ("1:"
- " moveml %0@+,%/d0/%/d1/%/a0/%/a1\n"
- " moveml %/d0/%/d1/%/a0/%/a1,%1@\n"
- " addql #8,%1; addql #8,%1\n"
- " dbra %2,1b\n"
- " clrw %2; subql #1,%2\n"
- " jcc 1b"
- : "=a" (src), "=a" (dst), "=d" (size)
- : "0" (src), "1" (dst), "2" (size / 16 - 1)
- : "d0", "d1", "a0", "a1", "memory");
- else
- __asm__ __volatile__
- ("1:"
- " subql #8,%0; subql #8,%0\n"
- " moveml %0@,%/d0/%/d1/%/a0/%/a1\n"
- " moveml %/d0/%/d1/%/a0/%/a1,%1@-\n"
- " dbra %2,1b\n"
- " clrw %2; subql #1,%2\n"
- " jcc 1b"
- : "=a" (src), "=a" (dst), "=d" (size)
- : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
- : "d0", "d1", "a0", "a1", "memory");
-}
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val for a 4 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- * *d = (color & 1) ? 0xff : 0;
- * *(d+2) = (color & 2) ? 0xff : 0;
- * *(d+4) = (color & 4) ? 0xff : 0;
- * *(d+6) = (color & 8) ? 0xff : 0;
- */
-
-static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr)
-{
- __asm__ __volatile__
- ("1: movepl %4,%0@(0)\n\t"
- "addal %5,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
- );
-}
-
-/* Sets a 4 plane region from 'd', length 'count' bytes, to the color
- * in val1/val2. 'd' has to be an even address and count must be divisible
- * by 8, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/8 times)
- * *d = *(d+1) = (color & 1) ? 0xff : 0;
- * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
- * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
- * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_4p(void *d, size_t count, u_long val1,
- u_long val2)
-{
- u_long *dd = d;
-
- count /= 8;
- while (count--)
- {
- *dd++ = val1;
- *dd++ = val2;
- }
-}
-
-/* Copies a 4 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
-{
- u_char *dd = d, *ss = s;
-
- while (h--)
- {
- dd[0] = ss[0];
- dd[2] = ss[2];
- dd[4] = ss[4];
- dd[6] = ss[6];
- dd += bpr;
- ss += bpr;
- }
-}
-
-
-/* This expands a 4 bit color into a long for movepl (4 plane) operations. */
-
-static __inline__ u_long expand4l(u_char c)
-{
- u_long rv;
-
- __asm__ __volatile__
- ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c)
- );
- return(rv);
-}
-
-/* This expands a 4 bit color into two longs for two movel operations
- * (4 planes).
- */
-
-static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2)
-{
- u_long rv1, rv2;
-
- __asm__ __volatile__
- ("lsrb #1,%3\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "swap %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "extw %1\n\t"
- "swap %1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "extw %1"
- : "=&d" (rv1), "=&d" (rv2), "=d" (c)
- : "2" (c)
- );
- *ret1 = rv1;
- *ret2 = rv2;
-}
-
-
-/* This duplicates a byte 4 times into a long. */
-
-static __inline__ u_long dup4l(u_char c)
-{
- ushort tmp;
- ulong rv;
-
- __asm__ __volatile__
- ("moveb %2,%0\n\t"
- "lslw #8,%0\n\t"
- "moveb %2,%0\n\t"
- "movew %0,%1\n\t"
- "swap %0\n\t"
- "movew %1,%0"
- : "=&d" (rv), "=d" (tmp)
- : "d" (c)
- );
-
- return(rv);
-}
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- * *d = (color & 1) ? 0xff : 0;
- * *(d+2) = (color & 2) ? 0xff : 0;
- * *(d+4) = (color & 4) ? 0xff : 0;
- * *(d+6) = (color & 8) ? 0xff : 0;
- * *(d+8) = (color & 16) ? 0xff : 0;
- * *(d+10) = (color & 32) ? 0xff : 0;
- * *(d+12) = (color & 64) ? 0xff : 0;
- * *(d+14) = (color & 128) ? 0xff : 0;
- */
-
-static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1,
- u_long val2, int bpr)
-{
- __asm__ __volatile__
- ("1: movepl %4,%0@(0)\n\t"
- "movepl %5,%0@(8)\n\t"
- "addal %6,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val1), "d" (val2), "r" (bpr)
- );
-}
-
-/* Sets a 8 plane region from 'd', length 'count' bytes, to the color
- * val1..val4. 'd' has to be an even address and count must be divisible
- * by 16, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/16 times)
- * *d = *(d+1) = (color & 1) ? 0xff : 0;
- * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
- * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
- * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
- * *(d+8) = *(d+9) = (color & 16) ? 0xff : 0;
- * *(d+10) = *(d+11) = (color & 32) ? 0xff : 0;
- * *(d+12) = *(d+13) = (color & 64) ? 0xff : 0;
- * *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_8p(void *d, size_t count, u_long val1,
- u_long val2, u_long val3, u_long val4)
-{
- u_long *dd = d;
-
- count /= 16;
- while (count--)
- {
- *dd++ = val1;
- *dd++ = val2;
- *dd++ = val3;
- *dd++ = val4;
- }
-}
-
-/* Copies a 8 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
-{
- u_char *dd = d, *ss = s;
-
- while (h--)
- {
- dd[0] = ss[0];
- dd[2] = ss[2];
- dd[4] = ss[4];
- dd[6] = ss[6];
- dd[8] = ss[8];
- dd[10] = ss[10];
- dd[12] = ss[12];
- dd[14] = ss[14];
- dd += bpr;
- ss += bpr;
- }
-}
-
-
-/* This expands a 8 bit color into two longs for two movepl (8 plane)
- * operations.
- */
-
-static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2)
-{
- u_long rv1, rv2;
-
- __asm__ __volatile__
- ("lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%3\n\t"
- "scs %0\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1\n\t"
- "lsll #8,%1\n\t"
- "lsrb #1,%3\n\t"
- "scs %1"
- : "=&d" (rv1), "=&d" (rv2),"=d" (c)
- : "2" (c)
- );
-
- *ret1 = rv1;
- *ret2 = rv2;
-}
-
-/* This expands a 8 bit color into four longs for four movel operations
- * (8 planes).
- */
-
-/* ++andreas: use macro to avoid taking address of return values */
-#define expand8ql(c, rv1, rv2, rv3, rv4) \
-do { u_char tmp = c; \
- __asm__ __volatile__ \
- ("lsrb #1,%5\n\t" \
- "scs %0\n\t" \
- "extw %0\n\t" \
- "swap %0\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %0\n\t" \
- "extw %0\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %1\n\t" \
- "extw %1\n\t" \
- "swap %1\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %1\n\t" \
- "extw %1\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %2\n\t" \
- "extw %2\n\t" \
- "swap %2\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %2\n\t" \
- "extw %2\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %3\n\t" \
- "extw %3\n\t" \
- "swap %3\n\t" \
- "lsrb #1,%5\n\t" \
- "scs %3\n\t" \
- "extw %3" \
- : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3), \
- "=&d" (rv4), "=d" (tmp) \
- : "4" (tmp) \
- ); \
-} while (0)
-
-
-/* Sets the bytes in the visible column at d, height h, to the value
- * val for a 2 plane screen. The the bis of the color in 'color' are
- * moved (8 times) to the respective bytes. This means:
- *
- * for(h times; d += bpr)
- * *d = (color & 1) ? 0xff : 0;
- * *(d+2) = (color & 2) ? 0xff : 0;
- */
-
-static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr)
-{
- __asm__ __volatile__
- ("1: movepw %4,%0@(0)\n\t"
- "addal %5,%0\n\t"
- "dbra %1,1b"
- : "=a" (d), "=d" (h)
- : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)
- );
-}
-
-/* Sets a 2 plane region from 'd', length 'count' bytes, to the color
- * in val1. 'd' has to be an even address and count must be divisible
- * by 8, because only whole words and all planes are accessed. I.e.:
- *
- * for(count/4 times)
- * *d = *(d+1) = (color & 1) ? 0xff : 0;
- * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
- */
-
-static __inline__ void memset_even_2p(void *d, size_t count, u_long val)
-{
- u_long *dd = d;
-
- count /= 4;
- while (count--)
- *dd++ = val;
-}
-
-/* Copies a 2 plane column from 's', height 'h', to 'd'. */
-
-static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
-{
- u_char *dd = d, *ss = s;
-
- while (h--)
- {
- dd[0] = ss[0];
- dd[2] = ss[2];
- dd += bpr;
- ss += bpr;
- }
-}
-
-
-/* This expands a 2 bit color into a short for movepw (2 plane) operations. */
-
-static __inline__ u_short expand2w(u_char c)
-{
- u_short rv;
-
- __asm__ __volatile__
- ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "lsll #8,%0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c)
- );
- return(rv);
-}
-
-/* This expands a 2 bit color into one long for a movel operation
- * (2 planes).
- */
-
-static __inline__ u_long expand2l(u_char c)
-{
- u_long rv;
-
- __asm__ __volatile__
- ("lsrb #1,%2\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- "swap %0\n\t"
- "lsrb #1,%2\n\t"
- "scs %0\n\t"
- "extw %0\n\t"
- : "=&d" (rv), "=d" (c)
- : "1" (c)
- );
-
- return rv;
-}
-
-
-/* This duplicates a byte 2 times into a short. */
-
-static __inline__ u_short dup2w(u_char c)
-{
- ushort rv;
-
- __asm__ __volatile__
- ( "moveb %1,%0\n\t"
- "lslw #8,%0\n\t"
- "moveb %1,%0\n\t"
- : "=&d" (rv)
- : "d" (c)
- );
-
- return( rv );
-}
-
-
-/* ====================================================================== */
-
-/* fbcon_XXX routines - interface used by the world
- *
- * This system is now divided into two levels because of complications
- * caused by hardware scrolling. Top level functions:
- *
- * fbcon_bmove(), fbcon_clear(), fbcon_putc()
- *
- * handles y values in range [0, scr_height-1] that correspond to real
- * screen positions. y_wrap shift means that first line of bitmap may be
- * anywhere on this display. These functions convert lineoffsets to
- * bitmap offsets and deal with the wrap-around case by splitting blits.
- *
- * fbcon_bmove_physical_8() -- These functions fast implementations
- * fbcon_clear_physical_8() -- of original fbcon_XXX fns.
- * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later
- *
- * WARNING:
- *
- * At the moment fbcon_putc() cannot blit across vertical wrap boundary
- * Implies should only really hardware scroll in rows. Only reason for
- * restriction is simplicity & efficiency at the moment.
- */
-
-static __inline__ int real_y(struct display *p, int yy)
-{
- int rows = p->vrows;
-
- yy += p->yscroll;
- return(yy < rows ? yy : yy-rows);
-}
-
-
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
- u_int y_break;
-
- if (!p->can_soft_blank && console_blanked)
- return(0);
-
- if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
- (sx <= p->cursor_x) && (p->cursor_x < sx+width))
- CURSOR_UNDRAWN();
-
- /* Split blits that cross physical y_wrap boundary */
-
- y_break = p->vrows-p->yscroll;
- if (sy < y_break && sy+height-1 >= y_break) {
- u_int b = y_break-sy;
- p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width);
- p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
- } else
- p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
-
- return(0);
-}
-
-
-static int fbcon_putc(struct vc_data *conp, int c, int yy, int xx)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
-
- if (!p->can_soft_blank && console_blanked)
- return(0);
-
- if ((p->cursor_x == xx) && (p->cursor_y == yy))
- CURSOR_UNDRAWN();
-
- p->dispsw->putc(conp, p, c, real_y(p, yy), xx);
-
- return(0);
-}
-
-
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int yy,
- int xx)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
-
- if (!p->can_soft_blank && console_blanked)
- return(0);
-
- if ((p->cursor_y == yy) && (xx <= p->cursor_x) && (p->cursor_x < xx+count))
- CURSOR_UNDRAWN();
-
- p->dispsw->putcs(conp, p, s, count, real_y(p, yy), xx);
-
- return(0);
-}
-
-
-static int fbcon_cursor(struct vc_data *conp, int mode)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
-
- /* Avoid flickering if there's no real change. */
- if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y &&
- (mode == CM_ERASE) == !cursor_on)
- return 0;
- if (CURSOR_UNDRAWN ())
- p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
- p->cursor_x = conp->vc_x;
- p->cursor_y = conp->vc_y;
-
- switch (mode) {
- case CM_ERASE:
- cursor_on = 0;
- break;
-
- case CM_MOVE:
- case CM_DRAW:
- vbl_cursor_cnt = CURSOR_DRAW_DELAY;
- cursor_on = 1;
- break;
- }
-
- return(0);
-}
-
-
-static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
-{
- struct display *p;
-
- if (!cursor_on)
- return;
-
- if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
- /* Here no check is possible for console changing. The console
- * switching code should set vbl_cursor_cnt to an appropriate value.
- */
- p = &disp[fg_console];
- p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
- cursor_drawn ^= 1;
- vbl_cursor_cnt = cursor_blink_rate;
- }
-}
-
-
-static __inline__ void ywrap_up(int unit, struct display *p, int count)
-{
- p->yscroll += count;
- if (p->yscroll >= p->vrows) /* Deal with wrap */
- p->yscroll -= p->vrows;
- p->var.xoffset = 0;
- p->var.yoffset = p->yscroll*p->fontheight;
- p->var.vmode |= FB_VMODE_YWRAP;
- fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ywrap_down(int unit, struct display *p, int count)
-{
- p->yscroll -= count;
- if (p->yscroll < 0) /* Deal with wrap */
- p->yscroll += p->vrows;
- p->var.xoffset = 0;
- p->var.yoffset = p->yscroll*p->fontheight;
- p->var.vmode |= FB_VMODE_YWRAP;
- fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ypan_up(int unit, struct vc_data *conp,
- struct display *p, int count)
-{
- p->yscroll += count;
- if (p->yscroll+conp->vc_rows > p->vrows) {
- p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count,
- conp->vc_cols);
- p->yscroll = 0;
- }
- p->var.xoffset = 0;
- p->var.yoffset = p->yscroll*p->fontheight;
- p->var.vmode &= ~FB_VMODE_YWRAP;
- fb_info->updatevar(unit);
-}
-
-
-static __inline__ void ypan_down(int unit, struct vc_data *conp,
- struct display *p, int count)
-{
- p->yscroll -= count;
- if (p->yscroll < 0) {
- p->yscroll = p->vrows-conp->vc_rows;
- p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, conp->vc_rows-count,
- conp->vc_cols);
- }
- p->var.xoffset = 0;
- p->var.yoffset = p->yscroll*p->fontheight;
- p->var.vmode &= ~FB_VMODE_YWRAP;
- fb_info->updatevar(unit);
-}
-
-
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
-
- if (!p->can_soft_blank && console_blanked)
- return(0);
-
- fbcon_cursor(conp, CM_ERASE);
-
- /*
- * ++Geert: Only use ywrap/ypan if the console is in text mode
- */
-
- switch (dir) {
- case SM_UP:
- if (count > conp->vc_rows) /* Maximum realistic size */
- count = conp->vc_rows;
- if (vt_cons[unit]->vc_mode == KD_TEXT)
- switch (p->scrollmode) {
- case SCROLL_YWRAP:
- if (b-t-count > 3*conp->vc_rows>>2) {
- if (t > 0)
- fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
- ywrap_up(unit, p, count);
- if (conp->vc_rows-b > 0)
- fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
- conp->vc_cols);
- } else
- fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
- conp->vc_cols);
- fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
- break;
-
- case SCROLL_YPAN:
- if (b-t-count > 3*conp->vc_rows>>2) {
- if (t > 0)
- fbcon_bmove(conp, 0, 0, count, 0, t, conp->vc_cols);
- ypan_up(unit, conp, p, count);
- if (conp->vc_rows-b > 0)
- fbcon_bmove(conp, b-count, 0, b, 0, conp->vc_rows-b,
- conp->vc_cols);
- } else
- fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
- conp->vc_cols);
- fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
- break;
-
- case SCROLL_YMOVE:
- p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
- conp->vc_cols);
- p->dispsw->clear(conp, p, b-count, 0, count, conp->vc_cols);
- break;
- }
- else {
- fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
- fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
- }
- break;
-
- case SM_DOWN:
- if (count > conp->vc_rows) /* Maximum realistic size */
- count = conp->vc_rows;
- if (vt_cons[unit]->vc_mode == KD_TEXT)
- switch (p->scrollmode) {
- case SCROLL_YWRAP:
- if (b-t-count > 3*conp->vc_rows>>2) {
- if (conp->vc_rows-b > 0)
- fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
- conp->vc_cols);
- ywrap_down(unit, p, count);
- if (t > 0)
- fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
- } else
- fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
- conp->vc_cols);
- fbcon_clear(conp, t, 0, count, conp->vc_cols);
- break;
-
- case SCROLL_YPAN:
- if (b-t-count > 3*conp->vc_rows>>2) {
- if (conp->vc_rows-b > 0)
- fbcon_bmove(conp, b, 0, b-count, 0, conp->vc_rows-b,
- conp->vc_cols);
- ypan_down(unit, conp, p, count);
- if (t > 0)
- fbcon_bmove(conp, count, 0, 0, 0, t, conp->vc_cols);
- } else
- fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
- conp->vc_cols);
- fbcon_clear(conp, t, 0, count, conp->vc_cols);
- break;
-
- case SCROLL_YMOVE:
- p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
- conp->vc_cols);
- p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
- break;
- }
- else {
- /*
- * Fixed bmove() should end Arno's frustration with copying?
- * Confucius says:
- * Man who copies in wrong direction, end up with trashed data
- */
- fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
- fbcon_clear(conp, t, 0, count, conp->vc_cols);
- }
- break;
-
- case SM_LEFT:
- fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count);
- fbcon_clear(conp, 0, b-count, conp->vc_rows, count);
- break;
-
- case SM_RIGHT:
- fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count);
- fbcon_clear(conp, 0, t, conp->vc_rows, count);
- break;
- }
-
- return(0);
-}
-
-
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
-
- if (!p->can_soft_blank && console_blanked)
- return(0);
-
- if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
- (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
- ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
- (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
- fbcon_cursor(conp, CM_ERASE);
-
- /* Split blits that cross physical y_wrap case.
- * Pathological case involves 4 blits, better to use recursive
- * code rather than unrolled case
- *
- * Recursive invocations don't need to erase the cursor over and
- * over again, so we use fbcon_bmove_rec()
- */
- fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
-
- return(0);
-}
-
-
-static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width, u_int y_break)
-{
- u_int b;
-
- if (sy < y_break && sy+height > y_break) {
- b = y_break-sy;
- if (dy < sy) { /* Avoid trashing self */
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- } else {
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- }
- return;
- }
-
- if (dy < y_break && dy+height > y_break) {
- b = y_break-dy;
- if (dy < sy) { /* Avoid trashing self */
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- } else {
- fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break);
- fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break);
- }
- return;
- }
- p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
-}
-
-
-static int fbcon_switch(struct vc_data *conp)
-{
- if (fb_info && fb_info->switch_con)
- (*fb_info->switch_con)(conp->vc_num);
- return(0);
-}
-
-
-static int fbcon_blank(int blank)
-{
- struct display *p = &disp[fg_console];
-
- fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
-
- if (!p->can_soft_blank)
- if (blank) {
- if (p->visual == FB_VISUAL_MONO01)
- mymemset(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- else
- mymemclear(p->screen_base, p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- return(0);
- } else {
- /* Tell console.c that it has to restore the screen itself */
- return(1);
- }
- (*fb_info->blank)(blank);
- return(0);
-}
-
-
-static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
- int i, j, size, alloc;
-
- size = (p->fontwidth+7)/8 * p->fontheight * 256;
- alloc = (*w+7)/8 * *h * 256;
- *w = p->fontwidth;
- *h = p->fontheight;
-
- if (alloc < size)
- /* allocation length not sufficient */
- return( -ENAMETOOLONG );
-
- for (i = 0; i < 256; i++)
- for (j = 0; j < p->fontheight; j++)
- data[i*32+j] = p->fontdata[i*p->fontheight+j];
- return( 0 );
-}
-
-
-#define REFCOUNT(fd) (((int *)(fd))[-1])
-
-static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
- int i, j, size, userspace = 1, resize;
- char *old_data = NULL, *new_data;
-
- if (w < 0)
- w = p->fontwidth;
- if (h < 0)
- h = p->fontheight;
-
- if (w == 0) {
- /* engage predefined font, name in 'data' */
- char name[MAX_FONT_NAME+1];
-
- if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME )))
- return i;
- copy_from_user( name, data, MAX_FONT_NAME );
- name[sizeof(name)-1] = 0;
-
- if (!findsoftfont( name, &w, &h, (u_char **)&data ))
- return( -ENOENT );
- userspace = 0;
- }
- else if (w == 1) {
- /* copy font from some other console in 'h'*/
- struct display *op;
-
- if (h < 0 || !vc_cons_allocated( h ))
- return( -ENOTTY );
- if (h == unit)
- return( 0 ); /* nothing to do */
- op = &disp[h];
- if (op->fontdata == p->fontdata)
- return( 0 ); /* already the same font... */
-
- resize = (op->fontwidth != p->fontwidth) ||
- (op->fontheight != p->fontheight);
- if (p->userfont)
- old_data = p->fontdata;
- p->fontdata = op->fontdata;
- w = p->fontwidth = op->fontwidth;
- h = p->fontheight = op->fontheight;
- if ((p->userfont = op->userfont))
- REFCOUNT(p->fontdata)++; /* increment usage counter */
- goto activate;
- }
-
- if (w != 8)
- /* Currently only fontwidth == 8 supported */
- return( -ENXIO );
-
- resize = (w != p->fontwidth) || (h != p->fontheight);
- size = (w+7)/8 * h * 256;
-
- if (p->userfont)
- old_data = p->fontdata;
-
- if (userspace) {
- if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER )))
- return( -ENOMEM );
- new_data += sizeof(int);
- REFCOUNT(new_data) = 1; /* usage counter */
-
- for (i = 0; i < 256; i++)
- for (j = 0; j < h; j++)
- new_data[i*h+j] = data[i*32+j];
-
- p->fontdata = new_data;
- p->userfont = 1;
- }
- else {
- p->fontdata = data;
- p->userfont = 0;
- }
- p->fontwidth = w;
- p->fontheight = h;
-
- activate:
- if (resize) {
- p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
- /* Adjust the virtual screen-size to fontheight*rows */
- p->var.yres_virtual = (p->var.yres/h)*h;
- p->vrows = p->var.yres_virtual/h;
- updatescrollmode(p);
- vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
- }
- else if (unit == fg_console)
- update_screen( unit );
-
- if (old_data) {
- if (--REFCOUNT(old_data) == 0) {
- kfree( old_data - sizeof(int) );
- }
- }
-
- return( 0 );
-}
-
-static unsigned short palette_red[16];
-static unsigned short palette_green[16];
-static unsigned short palette_blue[16];
-
-static struct fb_cmap palette_cmap = {
- 0, 16, palette_red, palette_green, palette_blue, NULL
-};
-
-static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
-{
- int unit = conp->vc_num;
- struct display *p = &disp[unit];
- int i, j, k;
- u_char val;
-
- if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
- return(-EINVAL);
- for (i = j = 0; i < 16; i++) {
- k = table[i];
- val = conp->vc_palette[j++];
- palette_red[k] = (val<<8)|val;
- val = conp->vc_palette[j++];
- palette_green[k] = (val<<8)|val;
- val = conp->vc_palette[j++];
- palette_blue[k] = (val<<8)|val;
- }
- palette_cmap.len = 1<<p->var.bits_per_pixel;
- if (palette_cmap.len > 16)
- palette_cmap.len = 16;
- return(fb_info->setcmap(&palette_cmap, unit));
-}
-
-
-/* ====================================================================== */
-
-/*
- * Low Level Operations for the various display memory organizations.
- *
- * Currently only the following organizations are supported here:
- *
- * - Monochrome
- * - Color Interleaved Planes à la Amiga
- * - Color Normal Planes
- * - Color Interleaved Planes à la Atari (2, 4 and 8 planes)
- * - Color Packed Pixels (8 and 16 bpp)
- * - Cybervision Color Packed Pixels (accelerated)
- */
-
-#ifdef CONFIG_FBCON_MONO
-
- /*
- * Monochrome
- */
-
-static void bmove_mono(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- u_char *src, *dest;
- u_int rows;
-
- if (sx == 0 && dx == 0 && width == p->next_line) {
- src = p->screen_base+sy*p->fontheight*width;
- dest = p->screen_base+dy*p->fontheight*width;
- mymemmove(dest, src, height*p->fontheight*width);
- } else if (dy <= sy) {
- src = p->screen_base+sy*p->fontheight*p->next_line+sx;
- dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
- for (rows = height*p->fontheight; rows--;) {
- mymemmove(dest, src, width);
- src += p->next_line;
- dest += p->next_line;
- }
- } else {
- src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
- dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
- for (rows = height*p->fontheight; rows--;) {
- mymemmove(dest, src, width);
- src -= p->next_line;
- dest -= p->next_line;
- }
- }
-}
-
-
-static void clear_mono(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
-{
- u_char *dest;
- u_int rows;
-
- dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
- if (sx == 0 && width == p->next_line)
- if (attr_reverse(p,conp))
- mymemset(dest, height*p->fontheight*width);
- else
- mymemclear(dest, height*p->fontheight*width);
- else
- for (rows = height*p->fontheight; rows--; dest += p->next_line)
- if (attr_reverse(p,conp))
- mymemset(dest, width);
- else
- mymemclear_small(dest, width);
-}
-
-
-static void putc_mono(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest, *cdat;
- u_int rows, bold, revs, underl;
- u_char d;
-
- c &= 0xff;
-
- dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
- cdat = p->fontdata+c*p->fontheight;
- bold = attr_bold(p,conp);
- revs = attr_reverse(p,conp);
- underl = attr_underline(p,conp);
-
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
- if (underl && !rows)
- d = 0xff;
- else if (bold)
- d |= d>>1;
- if (revs)
- d = ~d;
- *dest = d;
- }
-}
-
-
-static void putcs_mono(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
-{
- u_char *dest, *dest0, *cdat;
- u_int rows, bold, revs, underl;
- u_char c, d;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- bold = attr_bold(p,conp);
- revs = attr_reverse(p,conp);
- underl = attr_underline(p,conp);
-
- while (count--) {
- c = *s++;
- dest = dest0++;
- cdat = p->fontdata+c*p->fontheight;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
- if (underl && !rows)
- d = 0xff;
- else if (bold)
- d |= d>>1;
- if (revs)
- d = ~d;
- *dest = d;
- }
- }
-}
-
-
-static void rev_char_mono(struct display *p, int xx, int yy)
-{
- u_char *dest;
- u_int rows;
-
- dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
- for (rows = p->fontheight; rows--; dest += p->next_line)
- *dest = ~*dest;
-}
-
-#endif /* CONFIG_FBCON_MONO */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_ILBM
-
- /*
- * Color Interleaved Planes
- *
- * This code heavily relies on the fact that
- *
- * next_line == interleave == next_plane*bits_per_pixel
- *
- * But maybe it can be merged with the code for normal bitplanes without
- * much performance loss?
- */
-
-static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- if (sx == 0 && dx == 0 && width == p->next_plane)
- mymemmove(p->screen_base+dy*p->fontheight*p->next_line,
- p->screen_base+sy*p->fontheight*p->next_line,
- height*p->fontheight*p->next_line);
- else {
- u_char *src, *dest;
- u_int i;
-
- if (dy <= sy) {
- src = p->screen_base+sy*p->fontheight*p->next_line+sx;
- dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
- mymemmove(dest, src, width);
- src += p->next_plane;
- dest += p->next_plane;
- }
- } else {
- src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
- dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) {
- src -= p->next_plane;
- dest -= p->next_plane;
- mymemmove(dest, src, width);
- }
- }
- }
-}
-
-
-static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
-{
- u_char *dest;
- u_int i, rows;
- int bg, bg0;
-
- dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
- bg0 = attr_bgcol_ec(p,conp);
- for (rows = height*p->fontheight; rows--;) {
- bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
- mymemset(dest, width);
- else
- mymemclear(dest, width);
- bg >>= 1;
- }
- }
-}
-
-
-static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest, *cdat;
- u_int rows, i;
- u_char d;
- int fg0, bg0, fg, bg;
-
- c &= 0xff;
-
- dest = p->screen_base + yy*p->fontheight*p->next_line + xx;
- cdat = p->fontdata+c*p->fontheight;
- fg0 = attr_fgcol(p,conp);
- bg0 = attr_bgcol(p,conp);
-
- for (rows = p->fontheight; rows--;) {
- d = *cdat++;
- fg = fg0;
- bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- bg >>= 1;
- fg >>= 1;
- }
- }
-}
-
-
-/*
- * I split the console character loop in two parts:
- *
- * - slow version: this blits one character at a time
- *
- * - fast version: this blits 4 characters at a time at a longword aligned
- * address, to reduce the number of expensive Chip RAM
- * accesses.
- *
- * Experiments on my A4000/040 revealed that this makes a console
- * switch on a 640x400 screen with 256 colors about 3 times faster.
- *
- * Geert
- */
-
-static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
-{
- u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
- u_int rows, i;
- u_char c1, c2, c3, c4;
- u_long d;
- int fg0, bg0, fg, bg;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- fg0 = attr_fgcol(p,conp);
- bg0 = attr_bgcol(p,conp);
-
- while (count--)
- if (xx & 3 || count < 3) { /* Slow version */
- c1 = *s++;
- dest = dest0++;
- xx++;
-
- cdat1 = p->fontdata+c1*p->fontheight;
- for (rows = p->fontheight; rows--;) {
- d = *cdat1++;
- fg = fg0;
- bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- bg >>= 1;
- fg >>= 1;
- }
- }
- } else { /* Fast version */
- c1 = s[0];
- c2 = s[1];
- c3 = s[2];
- c4 = s[3];
-
- dest = dest0;
- cdat1 = p->fontdata+c1*p->fontheight;
- cdat2 = p->fontdata+c2*p->fontheight;
- cdat3 = p->fontdata+c3*p->fontheight;
- cdat4 = p->fontdata+c4*p->fontheight;
- for (rows = p->fontheight; rows--;) {
- d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
- fg = fg0;
- bg = bg0;
- for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
- if (bg & 1)
- if (fg & 1)
- *(u_long *)dest = 0xffffffff;
- else
- *(u_long *)dest = ~d;
- else
- if (fg & 1)
- *(u_long *)dest = d;
- else
- *(u_long *)dest = 0x00000000;
- bg >>= 1;
- fg >>= 1;
- }
- }
- s += 4;
- dest0 += 4;
- xx += 4;
- count -= 3;
- }
-}
-
-
-static void rev_char_ilbm(struct display *p, int xx, int yy)
-{
- u_char *dest, *dest0;
- u_int rows, i;
- int mask;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- mask = p->fgcol ^ p->bgcol;
-
- /*
- * This should really obey the individual character's
- * background and foreground colors instead of simply
- * inverting.
- */
-
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
- if (mask & 1) {
- dest = dest0;
- for (rows = p->fontheight; rows--; dest += p->next_line)
- *dest = ~*dest;
- }
- mask >>= 1;
- }
-}
-
-#endif /* CONFIG_FBCON_ILBM */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_PLANES
-
- /*
- * Color Planes
- */
-
-static void bmove_plan(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- u_char *src, *dest, *src0, *dest0;
- u_int i, rows;
-
- if (sx == 0 && dx == 0 && width == p->next_line) {
- src = p->screen_base+sy*p->fontheight*width;
- dest = p->screen_base+dy*p->fontheight*width;
- for (i = p->var.bits_per_pixel; i--;) {
- mymemmove(dest, src, height*p->fontheight*width);
- src += p->next_plane;
- dest += p->next_plane;
- }
- } else if (dy <= sy) {
- src0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
- dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel; i--;) {
- src = src0;
- dest = dest0;
- for (rows = height*p->fontheight; rows--;) {
- mymemmove(dest, src, width);
- src += p->next_line;
- dest += p->next_line;
- }
- src0 += p->next_plane;
- dest0 += p->next_plane;
- }
- } else {
- src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx;
- dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx;
- for (i = p->var.bits_per_pixel; i--;) {
- src = src0;
- dest = dest0;
- for (rows = height*p->fontheight; rows--;) {
- src -= p->next_line;
- dest -= p->next_line;
- mymemmove(dest, src, width);
- }
- src0 += p->next_plane;
- dest0 += p->next_plane;
- }
- }
-}
-
-
-static void clear_plan(struct vc_data *conp, struct display *p, int sy, int sx,
- int height, int width)
-{
- u_char *dest, *dest0;
- u_int i, rows;
- int bg;
-
- dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx;
-
- bg = attr_bgcol_ec(p,conp);
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
- dest = dest0;
- for (rows = height*p->fontheight; rows--; dest += p->next_line)
- if (bg & 1)
- mymemset(dest, width);
- else
- mymemclear(dest, width);
- bg >>= 1;
- }
-}
-
-
-static void putc_plan(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest, *dest0, *cdat, *cdat0;
- u_int rows, i;
- u_char d;
- int fg, bg;
-
- c &= 0xff;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- cdat0 = p->fontdata+c*p->fontheight;
- fg = attr_fgcol(p,conp);
- bg = attr_bgcol(p,conp);
-
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
- dest = dest0;
- cdat = cdat0;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- }
- bg >>= 1;
- fg >>= 1;
- }
-}
-
-
-/*
- * I split the console character loop in two parts
- * (cfr. fbcon_putcs_ilbm())
- */
-
-static void putcs_plan(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
-{
- u_char *dest, *dest0, *dest1;
- u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
- u_int rows, i;
- u_char c1, c2, c3, c4;
- u_long d;
- int fg0, bg0, fg, bg;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- fg0 = attr_fgcol(p,conp);
- bg0 = attr_bgcol(p,conp);
-
- while (count--)
- if (xx & 3 || count < 3) { /* Slow version */
- c1 = *s++;
- dest1 = dest0++;
- xx++;
-
- cdat10 = p->fontdata+c1*p->fontheight;
- fg = fg0;
- bg = bg0;
-
- for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
- dest = dest1;
- cdat1 = cdat10;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat1++;
- if (bg & 1)
- if (fg & 1)
- *dest = 0xff;
- else
- *dest = ~d;
- else
- if (fg & 1)
- *dest = d;
- else
- *dest = 0x00;
- }
- bg >>= 1;
- fg >>= 1;
- }
- } else { /* Fast version */
- c1 = s[0];
- c2 = s[1];
- c3 = s[2];
- c4 = s[3];
-
- dest1 = dest0;
- cdat10 = p->fontdata+c1*p->fontheight;
- cdat20 = p->fontdata+c2*p->fontheight;
- cdat30 = p->fontdata+c3*p->fontheight;
- cdat40 = p->fontdata+c4*p->fontheight;
- fg = fg0;
- bg = bg0;
-
- for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) {
- dest = dest1;
- cdat1 = cdat10;
- cdat2 = cdat20;
- cdat3 = cdat30;
- cdat4 = cdat40;
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
- if (bg & 1)
- if (fg & 1)
- *(u_long *)dest = 0xffffffff;
- else
- *(u_long *)dest = ~d;
- else
- if (fg & 1)
- *(u_long *)dest = d;
- else
- *(u_long *)dest = 0x00000000;
- }
- bg >>= 1;
- fg >>= 1;
- }
- s += 4;
- dest0 += 4;
- xx += 4;
- count -= 3;
- }
-}
-
-
-static void rev_char_plan(struct display *p, int xx, int yy)
-{
- u_char *dest, *dest0;
- u_int rows, i;
- int mask;
-
- dest0 = p->screen_base + yy*p->fontheight*p->next_line + xx;
- mask = p->fgcol ^ p->bgcol;
-
- /*
- * This should really obey the individual character's
- * background and foreground colors instead of simply
- * inverting.
- */
-
- for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) {
- if (mask & 1) {
- dest = dest0;
- for (rows = p->fontheight; rows--; dest += p->next_line)
- *dest = ~*dest;
- }
- mask >>= 1;
- }
-}
-
-#endif /* CONFIG_FBCON_PLANES */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_2PLANE
-
- /*
- * 2 Planes (2-bytes interleave)
- */
-
-/* Increment/decrement 2 plane addresses */
-
-#define INC_2P(p) do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
-#define DEC_2P(p) do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
-
-/* Convert a standard 4 bit color to our 2 bit color assignment:
- * If at least two RGB channels are active, the low bit is turned on;
- * The intensity bit (b3) is shifted into b1.
- */
-
-#define COLOR_2P(c) (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2)
-
-
-static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- /* bmove() has to distinguish two major cases: If both, source and
- * destination, start at even addresses or both are at odd
- * addresses, just the first odd and last even column (if present)
- * require special treatment (memmove_col()). The rest between
- * then can be copied by normal operations, because all adjacent
- * bytes are affected and are to be stored in the same order.
- * The pathological case is when the move should go from an odd
- * address to an even or vice versa. Since the bytes in the plane
- * words must be assembled in new order, it seems wisest to make
- * all movements by memmove_col().
- */
-
- if (sx == 0 && dx == 0 && width == p->next_line/2) {
- /* Special (but often used) case: Moving whole lines can be
- * done with memmove()
- */
- mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
- p->screen_base + sy * p->next_line * p->fontheight,
- p->next_line * height * p->fontheight);
- } else {
- int rows, cols;
- u_char *src;
- u_char *dst;
- int bytes = p->next_line;
- int linesize = bytes * p->fontheight;
- u_int colsize = height * p->fontheight;
- u_int upwards = (dy < sy) || (dy == sy && dx < sx);
-
- if ((sx & 1) == (dx & 1)) {
- /* odd->odd or even->even */
-
- if (upwards) {
-
- src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-
- if (sx & 1) {
- memmove_2p_col(dst, src, colsize, bytes);
- src += 3;
- dst += 3;
- --width;
- }
-
- if (width > 1) {
- for(rows = colsize; rows > 0; --rows) {
- mymemmove(dst, src, (width>>1)*4);
- src += bytes;
- dst += bytes;
- }
- }
-
- if (width & 1) {
- src -= colsize * bytes;
- dst -= colsize * bytes;
- memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
- colsize, bytes);
- }
- }
- else {
-
- if (!((sx+width-1) & 1)) {
- src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
- dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
- memmove_2p_col(dst, src, colsize, bytes);
- --width;
- }
-
- src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
-
- if (width > 1) {
- src += colsize * bytes + (sx & 1)*3;
- dst += colsize * bytes + (sx & 1)*3;
- for(rows = colsize; rows > 0; --rows) {
- src -= bytes;
- dst -= bytes;
- mymemmove(dst, src, (width>>1)*4);
- }
- }
-
- if (width & 1) {
- memmove_2p_col(dst-3, src-3, colsize, bytes);
- }
-
- }
- }
- else {
- /* odd->even or even->odd */
-
- if (upwards) {
- src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_2p_col(dst, src, colsize, bytes);
- INC_2P(src);
- INC_2P(dst);
- }
- }
- else {
- sx += width-1;
- dx += width-1;
- src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_2p_col(dst, src, colsize, bytes);
- DEC_2P(src);
- DEC_2P(dst);
- }
- }
- }
-
-
- }
-}
-
-
-static void clear_2_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- ulong offset;
- u_char *start;
- int rows;
- int bytes = p->next_line;
- int lines = height * p->fontheight;
- ulong size;
- u_long cval;
- u_short pcval;
-
- cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp)));
-
- if (sx == 0 && width == bytes/2) {
-
- offset = sy * bytes * p->fontheight;
- size = lines * bytes;
- memset_even_2p(p->screen_base+offset, size, cval);
-
- } else {
-
- offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1);
- start = p->screen_base + offset;
- pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp)));
-
- /* Clears are split if the region starts at an odd column or
- * end at an even column. These extra columns are spread
- * across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
- * the single plane words are affected.
- */
-
- if (sx & 1) {
- memclear_2p_col(start, lines, pcval, bytes);
- start += 3;
- width--;
- }
-
- if (width & 1) {
- memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
- width--;
- }
-
- if (width) {
- for(rows = lines; rows-- ; start += bytes)
- memset_even_2p(start, width*2, cval);
- }
- }
-}
-
-
-static void putc_2_plane(struct vc_data *conp, struct display *p, int
- c, int yy, int xx)
-{
- u_char *dest;
- u_char *cdat;
- int rows;
- int bytes = p->next_line;
- ulong eorx, fgx, bgx, fdx;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * bytes +
- (xx >> 1)*4 + (xx & 1);
- cdat = p->fontdata + (c * p->fontheight);
-
- fgx = expand2w(COLOR_2P(attr_fgcol(p,conp)));
- bgx = expand2w(COLOR_2P(attr_bgcol(p,conp)));
- eorx = fgx ^ bgx;
-
- for(rows = p->fontheight ; rows-- ; dest += bytes) {
- fdx = dup2w(*cdat++);
- __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
- }
-}
-
-
-static void putcs_2_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- u_char *dest, *dest0;
- u_char *cdat, c;
- int rows;
- int bytes;
- ulong eorx, fgx, bgx, fdx;
-
- bytes = p->next_line;
- dest0 = p->screen_base + yy * p->fontheight * bytes
- + (xx >> 1)*4 + (xx & 1);
- fgx = expand2w(COLOR_2P(attr_fgcol(p,conp)));
- bgx = expand2w(COLOR_2P(attr_bgcol(p,conp)));
- eorx = fgx ^ bgx;
-
- while (count--) {
-
- c = *s++;
- cdat = p->fontdata + (c * p->fontheight);
-
- for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- fdx = dup2w(*cdat++);
- __asm__ __volatile__ ("movepw %1,%0@(0)" : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
- }
- INC_2P(dest0);
- }
-}
-
-
-static void rev_char_2_plane(struct display *p, int xx, int yy)
-{
- u_char *dest;
- int j;
- int bytes;
-
- dest = p->screen_base + yy * p->fontheight * p->next_line +
- (xx >> 1)*4 + (xx & 1);
- j = p->fontheight;
- bytes = p->next_line;
- while (j--)
- {
- /* This should really obey the individual character's
- * background and foreground colors instead of simply
- * inverting.
- */
- dest[0] = ~dest[0];
- dest[2] = ~dest[2];
- dest += bytes;
- }
-}
-#endif /* CONFIG_FBCON_2PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_4PLANE
-
- /*
- * 4 Planes (2-bytes interleave)
- */
-
-/* Increment/decrement 4 plane addresses */
-
-#define INC_4P(p) do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
-#define DEC_4P(p) do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
-
-
-static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- /* bmove() has to distinguish two major cases: If both, source and
- * destination, start at even addresses or both are at odd
- * addresses, just the first odd and last even column (if present)
- * require special treatment (memmove_col()). The rest between
- * then can be copied by normal operations, because all adjacent
- * bytes are affected and are to be stored in the same order.
- * The pathological case is when the move should go from an odd
- * address to an even or vice versa. Since the bytes in the plane
- * words must be assembled in new order, it seems wisest to make
- * all movements by memmove_col().
- */
-
- if (sx == 0 && dx == 0 && width == p->next_line/4) {
- /* Special (but often used) case: Moving whole lines can be
- * done with memmove()
- */
- mymemmove(p->screen_base + dy * p->next_line * p->fontheight,
- p->screen_base + sy * p->next_line * p->fontheight,
- p->next_line * height * p->fontheight);
- } else {
- int rows, cols;
- u_char *src;
- u_char *dst;
- int bytes = p->next_line;
- int linesize = bytes * p->fontheight;
- u_int colsize = height * p->fontheight;
- u_int upwards = (dy < sy) || (dy == sy && dx < sx);
-
- if ((sx & 1) == (dx & 1)) {
- /* odd->odd or even->even */
-
- if (upwards) {
-
- src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-
- if (sx & 1) {
- memmove_4p_col(dst, src, colsize, bytes);
- src += 7;
- dst += 7;
- --width;
- }
-
- if (width > 1) {
- for(rows = colsize; rows > 0; --rows) {
- mymemmove(dst, src, (width>>1)*8);
- src += bytes;
- dst += bytes;
- }
- }
-
- if (width & 1) {
- src -= colsize * bytes;
- dst -= colsize * bytes;
- memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8,
- colsize, bytes);
- }
- }
- else {
-
- if (!((sx+width-1) & 1)) {
- src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
- dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
- memmove_4p_col(dst, src, colsize, bytes);
- --width;
- }
-
- src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
-
- if (width > 1) {
- src += colsize * bytes + (sx & 1)*7;
- dst += colsize * bytes + (sx & 1)*7;
- for(rows = colsize; rows > 0; --rows) {
- src -= bytes;
- dst -= bytes;
- mymemmove(dst, src, (width>>1)*8);
- }
- }
-
- if (width & 1) {
- memmove_4p_col(dst-7, src-7, colsize, bytes);
- }
-
- }
- }
- else {
- /* odd->even or even->odd */
-
- if (upwards) {
- src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_4p_col(dst, src, colsize, bytes);
- INC_4P(src);
- INC_4P(dst);
- }
- }
- else {
- sx += width-1;
- dx += width-1;
- src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_4p_col(dst, src, colsize, bytes);
- DEC_4P(src);
- DEC_4P(dst);
- }
- }
- }
-
-
- }
-}
-
-
-static void clear_4_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- ulong offset;
- u_char *start;
- int rows;
- int bytes = p->next_line;
- int lines = height * p->fontheight;
- ulong size;
- u_long cval1, cval2, pcval;
-
- expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2);
-
- if (sx == 0 && width == bytes/4) {
-
- offset = sy * bytes * p->fontheight;
- size = lines * bytes;
- memset_even_4p(p->screen_base+offset, size, cval1, cval2);
-
- } else {
-
- offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1);
- start = p->screen_base + offset;
- pcval = expand4l(attr_bgcol_ec(p,conp));
-
- /* Clears are split if the region starts at an odd column or
- * end at an even column. These extra columns are spread
- * across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
- * the single plane words are affected.
- */
-
- if (sx & 1) {
- memclear_4p_col(start, lines, pcval, bytes);
- start += 7;
- width--;
- }
-
- if (width & 1) {
- memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes);
- width--;
- }
-
- if (width) {
- for(rows = lines; rows-- ; start += bytes)
- memset_even_4p(start, width*4, cval1, cval2);
- }
- }
-}
-
-
-static void putc_4_plane(struct vc_data *conp, struct display *p, int
- c, int yy, int xx)
-{
- u_char *dest;
- u_char *cdat;
- int rows;
- int bytes = p->next_line;
- ulong eorx, fgx, bgx, fdx;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * bytes +
- (xx >> 1)*8 + (xx & 1);
- cdat = p->fontdata + (c * p->fontheight);
-
- fgx = expand4l(attr_fgcol(p,conp));
- bgx = expand4l(attr_bgcol(p,conp));
- eorx = fgx ^ bgx;
-
- for(rows = p->fontheight ; rows-- ; dest += bytes) {
- fdx = dup4l(*cdat++);
- __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
- }
-}
-
-
-static void putcs_4_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- u_char *dest, *dest0;
- u_char *cdat, c;
- int rows;
- int bytes;
- ulong eorx, fgx, bgx, fdx;
-
- bytes = p->next_line;
- dest0 = p->screen_base + yy * p->fontheight * bytes
- + (xx >> 1)*8 + (xx & 1);
- fgx = expand4l(attr_fgcol(p,conp));
- bgx = expand4l(attr_bgcol(p,conp));
- eorx = fgx ^ bgx;
-
- while (count--) {
-
- /* I think, unrolling the loops like in the 1 plane case isn't
- * practicable here, because the body is much longer for 4
- * planes (mostly the dup4l()). I guess, unrolling this would
- * need more than 256 bytes and so exceed the instruction
- * cache :-(
- */
-
- c = *s++;
- cdat = p->fontdata + (c * p->fontheight);
-
- for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- fdx = dup4l(*cdat++);
- __asm__ __volatile__ ("movepl %1,%0@(0)" : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx) ^ bgx));
- }
- INC_4P(dest0);
- }
-}
-
-
-static void rev_char_4_plane(struct display *p, int xx, int yy)
-{
- u_char *dest;
- int j;
- int bytes;
-
- dest = p->screen_base + yy * p->fontheight * p->next_line +
- (xx >> 1)*8 + (xx & 1);
- j = p->fontheight;
- bytes = p->next_line;
-
- while (j--)
- {
- /* This should really obey the individual character's
- * background and foreground colors instead of simply
- * inverting.
- */
- dest[0] = ~dest[0];
- dest[2] = ~dest[2];
- dest[4] = ~dest[4];
- dest[6] = ~dest[6];
- dest += bytes;
- }
-}
-#endif /* CONFIG_FBCON_4PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_8PLANE
-
- /*
- * 8 Planes (2-bytes interleave)
- */
-
-/* In 8 plane mode, 256 colors would be possible, but only the first
- * 16 are used by the console code (the upper 4 bits are
- * background/unused). For that, the following functions mask off the
- * higher 4 bits of each color.
- */
-
-/* Increment/decrement 8 plane addresses */
-
-#define INC_8P(p) do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
-#define DEC_8P(p) do { if ((long)(--(p)) & 1) (p) -= 14; } while(0)
-
-
-static void bmove_8_plane(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- /* bmove() has to distinguish two major cases: If both, source and
- * destination, start at even addresses or both are at odd
- * addresses, just the first odd and last even column (if present)
- * require special treatment (memmove_col()). The rest between
- * then can be copied by normal operations, because all adjacent
- * bytes are affected and are to be stored in the same order.
- * The pathological case is when the move should go from an odd
- * address to an even or vice versa. Since the bytes in the plane
- * words must be assembled in new order, it seems wisest to make
- * all movements by memmove_col().
- */
-
- if (sx == 0 && dx == 0 && width == p->next_line/8) {
- /* Special (but often used) case: Moving whole lines can be
- * done with memmove()
- */
- fast_memmove (p->screen_base + dy * p->next_line * p->fontheight,
- p->screen_base + sy * p->next_line * p->fontheight,
- p->next_line * height * p->fontheight);
- } else {
- int rows, cols;
- u_char *src;
- u_char *dst;
- int bytes = p->next_line;
- int linesize = bytes * p->fontheight;
- u_int colsize = height * p->fontheight;
- u_int upwards = (dy < sy) || (dy == sy && dx < sx);
-
- if ((sx & 1) == (dx & 1)) {
- /* odd->odd or even->even */
-
- if (upwards) {
-
- src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-
- if (sx & 1) {
- memmove_8p_col(dst, src, colsize, bytes);
- src += 15;
- dst += 15;
- --width;
- }
-
- if (width > 1) {
- for(rows = colsize; rows > 0; --rows) {
- fast_memmove (dst, src, (width >> 1) * 16);
- src += bytes;
- dst += bytes;
- }
- }
-
- if (width & 1) {
- src -= colsize * bytes;
- dst -= colsize * bytes;
- memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16,
- colsize, bytes);
- }
- }
- else {
-
- if (!((sx+width-1) & 1)) {
- src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
- dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
- memmove_8p_col(dst, src, colsize, bytes);
- --width;
- }
-
- src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
-
- if (width > 1) {
- src += colsize * bytes + (sx & 1)*15;
- dst += colsize * bytes + (sx & 1)*15;
- for(rows = colsize; rows > 0; --rows) {
- src -= bytes;
- dst -= bytes;
- fast_memmove (dst, src, (width>>1)*16);
- }
- }
-
- if (width & 1) {
- memmove_8p_col(dst-15, src-15, colsize, bytes);
- }
-
- }
- }
- else {
- /* odd->even or even->odd */
-
- if (upwards) {
- src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_8p_col(dst, src, colsize, bytes);
- INC_8P(src);
- INC_8P(dst);
- }
- }
- else {
- sx += width-1;
- dx += width-1;
- src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
- dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
- for(cols = width; cols > 0; --cols) {
- memmove_8p_col(dst, src, colsize, bytes);
- DEC_8P(src);
- DEC_8P(dst);
- }
- }
- }
-
-
- }
-}
-
-
-static void clear_8_plane(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- ulong offset;
- u_char *start;
- int rows;
- int bytes = p->next_line;
- int lines = height * p->fontheight;
- ulong size;
- u_long cval1, cval2, cval3, cval4, pcval1, pcval2;
-
- expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4);
-
- if (sx == 0 && width == bytes/8) {
-
- offset = sy * bytes * p->fontheight;
- size = lines * bytes;
- memset_even_8p(p->screen_base+offset, size, cval1,
- cval2, cval3, cval4);
-
- } else {
-
- offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1);
- start = p->screen_base + offset;
- expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2);
-
- /* Clears are split if the region starts at an odd column or
- * end at an even column. These extra columns are spread
- * across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
- * the single plane words are affected.
- */
-
- if (sx & 1) {
- memclear_8p_col(start, lines, pcval1, pcval2, bytes);
- start += 7;
- width--;
- }
-
- if (width & 1) {
- memclear_8p_col(start + (width>>1)*16, lines, pcval1,
- pcval2, bytes);
- width--;
- }
-
- if (width) {
- for(rows = lines; rows-- ; start += bytes)
- memset_even_8p(start, width*8, cval1, cval2, cval3, cval4);
- }
- }
-}
-
-
-static void putc_8_plane(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest;
- u_char *cdat;
- int rows;
- int bytes = p->next_line;
- ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * bytes +
- (xx >> 1)*16 + (xx & 1);
- cdat = p->fontdata + (c * p->fontheight);
-
- expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
- expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
- eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2;
-
- for(rows = p->fontheight ; rows-- ; dest += bytes) {
- fdx = dup4l(*cdat++);
- __asm__ __volatile__
- ("movepl %1,%0@(0)\n\t"
- "movepl %2,%0@(8)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
- "d" ((fdx & eorx2) ^ bgx2)
- );
- }
-}
-
-
-static void putcs_8_plane(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- u_char *dest, *dest0;
- u_char *cdat, c;
- int rows;
- int bytes;
- ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
-
- bytes = p->next_line;
- dest0 = p->screen_base + yy * p->fontheight * bytes
- + (xx >> 1)*16 + (xx & 1);
-
- expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2);
- expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2);
- eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2;
-
- while (count--) {
-
- /* I think, unrolling the loops like in the 1 plane case isn't
- * practicable here, because the body is much longer for 4
- * planes (mostly the dup4l()). I guess, unrolling this would
- * need more than 256 bytes and so exceed the instruction
- * cache :-(
- */
-
- c = *s++;
- cdat = p->fontdata + (c * p->fontheight);
-
- for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- fdx = dup4l(*cdat++);
- __asm__ __volatile__
- ("movepl %1,%0@(0)\n\t"
- "movepl %2,%0@(8)"
- : /* no outputs */
- : "a" (dest), "d" ((fdx & eorx1) ^ bgx1),
- "d" ((fdx & eorx2) ^ bgx2)
- );
- }
- INC_8P(dest0);
- }
-}
-
-
-static void rev_char_8_plane(struct display *p, int xx, int yy)
-{
- u_char *dest;
- int j;
- int bytes;
-
- dest = p->screen_base + yy * p->fontheight * p->next_line
- + (xx >> 1)*16 + (xx & 1);
- j = p->fontheight;
- bytes = p->next_line;
-
- while (j--)
- {
- /* This should really obey the individual character's
- * background and foreground colors instead of simply
- * inverting. For 8 plane mode, only the lower 4 bits of the
- * color are inverted, because only that color registers have
- * been set up.
- */
- dest[0] = ~dest[0];
- dest[2] = ~dest[2];
- dest[4] = ~dest[4];
- dest[6] = ~dest[6];
- dest += bytes;
- }
-}
-#endif /* CONFIG_FBCON_8PLANE */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_8PACKED
-
- /*
- * 8 bpp Packed Pixels
- */
-
-static u_long nibbletab_8_packed[]={
-0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
-0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
-0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
-0xffff0000,0xffff00ff,0xffffff00,0xffffffff};
-
-static void bmove_8_packed(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
- u_char *src,*dst;
-
- if (sx == 0 && dx == 0 && width * 8 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
- p->screen_base + sy * linesize,
- height * linesize);
- }
- else {
- if (dy < sy || (dy == sy && dx < sx)) {
- src = p->screen_base + sy * linesize + sx * 8;
- dst = p->screen_base + dy * linesize + dx * 8;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 8);
- src += bytes;
- dst += bytes;
- }
- }
- else {
- src = p->screen_base + (sy+height) * linesize + sx * 8
- - bytes;
- dst = p->screen_base + (dy+height) * linesize + dx * 8
- - bytes;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 8);
- src -= bytes;
- dst -= bytes;
- }
- }
- }
-}
-
-
-static void clear_8_packed(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- u_char *dest0,*dest;
- int bytes=p->next_line,lines=height * p->fontheight, rows, i;
- u_long bgx;
-
- dest = p->screen_base + sy * p->fontheight * bytes + sx * 8;
-
- bgx=attr_bgcol_ec(p,conp);
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
-
- if (sx == 0 && width * 8 == bytes) {
- for (i = 0 ; i < lines * width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- dest+=8;
- }
- } else {
- dest0=dest;
- for (rows = lines; rows-- ; dest0 += bytes) {
- dest=dest0;
- for (i = 0 ; i < width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- dest+=8;
- }
- }
- }
-}
-
-
-static void putc_8_packed(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
-{
- u_char *dest,*cdat;
- int bytes=p->next_line,rows;
- ulong eorx,fgx,bgx;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 8;
- cdat = p->fontdata + c * p->fontheight;
-
- fgx=attr_fgcol(p,conp);
- bgx=attr_bgcol(p,conp);
- fgx |= (fgx << 8);
- fgx |= (fgx << 16);
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]=
- (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
- ((u_long *)dest)[1]=
- (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
- }
-}
-
-
-static void putcs_8_packed(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- u_char *cdat, c, *dest, *dest0;
- int rows,bytes=p->next_line;
- u_long eorx, fgx, bgx;
-
- dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 8;
- fgx=attr_fgcol(p,conp);
- bgx=attr_bgcol(p,conp);
- fgx |= (fgx << 8);
- fgx |= (fgx << 16);
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
- while (count--) {
- c = *s++;
- cdat = p->fontdata + c * p->fontheight;
-
- for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]=
- (nibbletab_8_packed[*cdat >> 4] & eorx) ^ bgx;
- ((u_long *)dest)[1]=
- (nibbletab_8_packed[*cdat++ & 0xf] & eorx) ^ bgx;
- }
- dest0+=8;
- }
-}
-
-
-static void rev_char_8_packed(struct display *p, int xx, int yy)
-{
- u_char *dest;
- int bytes=p->next_line, rows;
-
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 8;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0] ^= 0x0f0f0f0f;
- ((u_long *)dest)[1] ^= 0x0f0f0f0f;
- }
-}
-
-#endif /* CONFIG_FBCON_8PACKED */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_16PACKED
-
- /*
- * 16 bpp Packed Pixels
- */
-
-u_short packed16_cmap[16];
-
-static u_long tab_16_packed[]={
-0x00000000,0x0000ffff,0xffff0000,0xffffffff};
-
-static void bmove_16_packed(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
- u_char *src,*dst;
-
- if (sx == 0 && dx == 0 && width * 16 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
- p->screen_base + sy * linesize,
- height * linesize);
- }
- else {
- if (dy < sy || (dy == sy && dx < sx)) {
- src = p->screen_base + sy * linesize + sx * 16;
- dst = p->screen_base + dy * linesize + dx * 16;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 16);
- src += bytes;
- dst += bytes;
- }
- }
- else {
- src = p->screen_base + (sy+height) * linesize + sx * 16
- - bytes;
- dst = p->screen_base + (dy+height) * linesize + dx * 16
- - bytes;
- for (rows = height * p->fontheight ; rows-- ;) {
- mymemmove(dst, src, width * 16);
- src -= bytes;
- dst -= bytes;
- }
- }
- }
-}
-
-
-static void clear_16_packed(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- u_char *dest0,*dest;
- int bytes=p->next_line,lines=height * p->fontheight, rows, i;
- u_long bgx;
-
- dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
-
- bgx = attr_bgcol_ec(p,conp);
- bgx = packed16_cmap[bgx];
- bgx |= (bgx << 16);
-
- if (sx == 0 && width * 16 == bytes) {
- for (i = 0 ; i < lines * width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- ((u_long *)dest)[2]=bgx;
- ((u_long *)dest)[3]=bgx;
- dest+=16;
- }
- } else {
- dest0=dest;
- for (rows = lines; rows-- ; dest0 += bytes) {
- dest=dest0;
- for (i = 0 ; i < width ; i++) {
- ((u_long *)dest)[0]=bgx;
- ((u_long *)dest)[1]=bgx;
- ((u_long *)dest)[2]=bgx;
- ((u_long *)dest)[3]=bgx;
- dest+=16;
- }
- }
- }
-}
-
-
-static void putc_16_packed(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
-{
- u_char *dest,*cdat;
- int bytes=p->next_line,rows;
- ulong eorx,fgx,bgx;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- cdat = p->fontdata + c * p->fontheight;
-
- fgx = attr_fgcol(p,conp);
- fgx = packed16_cmap[fgx];
- bgx = attr_bgcol(p,conp);
- bgx = packed16_cmap[bgx];
- fgx |= (fgx << 16);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
-
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]=
- (tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
- ((u_long *)dest)[1]=
- (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[2]=
- (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[3]=
- (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
- }
-}
-
-
-/* TODO */
-static void putcs_16_packed(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- u_char *cdat, c, *dest, *dest0;
- int rows,bytes=p->next_line;
- u_long eorx, fgx, bgx;
-
- dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- fgx = attr_fgcol(p,conp);
- fgx = packed16_cmap[fgx];
- bgx = attr_bgcol(p,conp);
- bgx = packed16_cmap[bgx];
- fgx |= (fgx << 16);
- bgx |= (bgx << 16);
- eorx = fgx ^ bgx;
- while (count--) {
- c = *s++;
- cdat = p->fontdata + c * p->fontheight;
-
- for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
- ((u_long *)dest)[0]=
- (tab_16_packed[*cdat >> 6] & eorx) ^ bgx;
- ((u_long *)dest)[1]=
- (tab_16_packed[*cdat >> 4 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[2]=
- (tab_16_packed[*cdat >> 2 & 0x3] & eorx) ^ bgx;
- ((u_long *)dest)[3]=
- (tab_16_packed[*cdat++ & 0x3] & eorx) ^ bgx;
- }
- dest0+=16;
- }
-}
-
-
-static void rev_char_16_packed(struct display *p, int xx, int yy)
-{
- u_char *dest;
- int bytes=p->next_line, rows;
-
- dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((u_long *)dest)[0] ^= 0xffffffff;
- ((u_long *)dest)[1] ^= 0xffffffff;
- ((u_long *)dest)[2] ^= 0xffffffff;
- ((u_long *)dest)[3] ^= 0xffffffff;
- }
-}
-
-#endif /* CONFIG_FBCON_16PACKED */
-
-
-/* ====================================================================== */
-
-#ifdef CONFIG_FBCON_CYBER
-
- /*
- * Cybervision (accelerated)
- */
-
-static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- sx *= 8; dx *= 8; width *= 8;
- Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx,
- (u_short)(dy*p->fontheight), (u_short)width,
- (u_short)(height*p->fontheight), (u_short)S3_NEW);
-}
-
-
-static void clear_cyber(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- Cyber_RectFill((u_short)sx,
- (u_short)(sy*p->fontheight),
- (u_short)width,
- (u_short)(height*p->fontheight),
- (u_short)S3_NEW,
- (u_short)bg);
-}
-
-
-static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- u_char *dest, *cdat;
- u_long tmp;
- u_int rows, revs, underl;
- u_char d;
- u_char fg, bg;
-
- c &= 0xff;
-
- dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
- cdat = p->fontdata+(c*p->fontheight);
- fg = disp->fgcol;
- bg = disp->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- Cyber_WaitBlit();
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((u_long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((u_long*) dest + 1) = tmp;
- }
-}
-
-
-static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s,
- int count, int yy, int xx)
-{
- u_char *dest, *dest0, *cdat;
- u_long tmp;
- u_int rows, revs, underl;
- u_char c, d;
- u_char fg, bg;
-
- dest0 = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
- fg = disp->fgcol;
- bg = disp->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- Cyber_WaitBlit();
- while (count--) {
- c = *s++;
- dest = dest0;
- dest0 += 8;
- cdat = p->fontdata+(c*p->fontheight);
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((u_long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((u_long*) dest + 1) = tmp;
- }
- }
-}
-
-
-static void rev_char_cyber(struct display *p, int xx, int yy)
-{
- unsigned char *dest;
- unsigned int rows;
- unsigned char fg, bg;
-
- fg = disp->fgcol;
- bg = disp->bgcol;
-
- dest = p->screen_base + yy * p->fontheight * p->next_line + 8 * xx;
- Cyber_WaitBlit();
- for (rows = p->fontheight; rows--; dest += p->next_line) {
- *dest = (*dest == fg) ? bg : fg;
- *(dest+1) = (*(dest + 1) == fg) ? bg : fg;
- *(dest+2) = (*(dest + 2) == fg) ? bg : fg;
- *(dest+3) = (*(dest + 3) == fg) ? bg : fg;
- *(dest+4) = (*(dest + 4) == fg) ? bg : fg;
- *(dest+5) = (*(dest + 5) == fg) ? bg : fg;
- *(dest+6) = (*(dest + 6) == fg) ? bg : fg;
- *(dest+7) = (*(dest + 7) == fg) ? bg : fg;
- }
-}
-
-#endif /* CONFIG_FBCON_CYBER */
-
-
-#ifdef CONFIG_FBCON_RETINAZ3
-
-/*
- * RetinaZ3 (accelerated)
- */
-
-#define Z3BLTcopy 0xc0
-#define Z3BLTset 0xf0
-
-static void clear_retz3(struct vc_data *conp, struct display *p, int
- sy, int sx, int height, int width)
-{
- unsigned short col;
- int fontwidth = p->fontwidth;
-
- sx *= fontwidth;
- width *= fontwidth;
-
- col = attr_bgcol_ec(p, conp);
- col &= 0xff;
- col |= (col << 8);
-
- retz3_bitblt(&p->var,
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)width,
- (unsigned short)(height*p->fontheight),
- Z3BLTset,
- col);
-}
-
-static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- int fontwidth = p->fontwidth;
-
- sx *= fontwidth;
- dx *= fontwidth;
- width *= fontwidth;
-
- retz3_bitblt(&p->var,
- (unsigned short)sx,
- (unsigned short)(sy*p->fontheight),
- (unsigned short)dx,
- (unsigned short)(dy*p->fontheight),
- (unsigned short)width,
- (unsigned short)(height*p->fontheight),
- Z3BLTcopy,
- 0xffff);
-}
-
-static void putc_retz3(struct vc_data *conp, struct display *p,
- int c, int yy, int xx)
-{
- unsigned char *dest, *cdat;
- unsigned long tmp;
- unsigned int rows, revs, underl, bytes;
- unsigned char d;
- unsigned char fg, bg;
-
- c &= 0xff;
-
- bytes = p->next_line;
-
- dest = p->screen_base + yy*p->fontheight*bytes
- + xx*p->var.bits_per_pixel;
- cdat = p->fontdata + c * p->fontheight;
-
- fg = disp->fgcol;
- bg = disp->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- for (rows = p->fontheight; rows--; dest += bytes) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((unsigned long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((unsigned long*) dest + 1) = tmp;
- }
-}
-
-
-static void putcs_retz3(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
-{
- unsigned char *dest, *dest0, *cdat;
- unsigned long tmp;
- unsigned int rows, revs, underl, bytes;
- unsigned char c, d;
- unsigned char fg, bg;
-
- bytes = p->next_line;
-
- dest0 = p->screen_base + yy*p->fontheight*bytes
- + xx * p->var.bits_per_pixel;
- fg = disp->fgcol;
- bg = disp->bgcol;
- revs = conp->vc_reverse;
- underl = conp->vc_underline;
-
- while (count--) {
- c = *s++;
- dest = dest0;
- dest0 += 8;
-
- cdat = p->fontdata + c * p->fontheight;
- for (rows = p->fontheight; rows--; dest += bytes) {
- d = *cdat++;
-
- if (underl && !rows)
- d = 0xff;
- if (revs)
- d = ~d;
-
- tmp = ((d & 0x80) ? fg : bg) << 24;
- tmp |= ((d & 0x40) ? fg : bg) << 16;
- tmp |= ((d & 0x20) ? fg : bg) << 8;
- tmp |= ((d & 0x10) ? fg : bg);
- *((unsigned long*) dest) = tmp;
- tmp = ((d & 0x8) ? fg : bg) << 24;
- tmp |= ((d & 0x4) ? fg : bg) << 16;
- tmp |= ((d & 0x2) ? fg : bg) << 8;
- tmp |= ((d & 0x1) ? fg : bg);
- *((unsigned long*) dest + 1) = tmp;
- }
- }
-}
-
-static void rev_char_retz3(struct display *p, int xx, int yy)
-{
- unsigned char *dest;
- int bytes=p->next_line, rows;
- unsigned int bpp, mask;
-
- bpp = p->var.bits_per_pixel;
-
- switch (bpp){
- case 8:
- mask = 0x0f0f0f0f;
- break;
- case 16:
- mask = 0xffffffff;
- break;
- case 24:
- mask = 0xffffffff; /* ??? */
- break;
- default:
- printk("illegal depth for rev_char_retz3(), bpp = %i\n", bpp);
- return;
- }
-
- dest = p->screen_base + yy * p->fontheight * bytes + xx * bpp;
-
- for (rows = p->fontheight ; rows-- ; dest += bytes) {
- ((unsigned long *)dest)[0] ^= mask;
- ((unsigned long *)dest)[1] ^= mask;
- }
-}
-
-#endif
-
-/* ====================================================================== */
-
- /*
- * The console `switch' structure for the frame buffer based console
- */
-
-struct consw fb_con = {
- fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
- fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
- fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette
-};
diff --git a/arch/m68k/console/font_8x16.c b/arch/m68k/console/font_8x16.c
deleted file mode 100644
index 59801b438..000000000
--- a/arch/m68k/console/font_8x16.c
+++ /dev/null
@@ -1,4625 +0,0 @@
-/**********************************************/
-/* */
-/* Font file generated by cpi2fnt */
-/* */
-/**********************************************/
-
-#define FONTDATAMAX 4096
-
-char fontname_8x16[] = "VGA8x16";
-
-int fontheight_8x16 = 16;
-int fontwidth_8x16 = 8;
-
-unsigned char fontdata_8x16[FONTDATAMAX] = {
-
- /* 0 0x00 '^@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 1 0x01 '^A' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x81, /* 10000001 */
- 0xa5, /* 10100101 */
- 0x81, /* 10000001 */
- 0x81, /* 10000001 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0x81, /* 10000001 */
- 0x81, /* 10000001 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 2 0x02 '^B' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xdb, /* 11011011 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 3 0x03 '^C' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 4 0x04 '^D' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 5 0x05 '^E' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 6 0x06 '^F' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 7 0x07 '^G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 8 0x08 '^H' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xe7, /* 11100111 */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 9 0x09 '^I' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x42, /* 01000010 */
- 0x42, /* 01000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 10 0x0a '^J' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0x99, /* 10011001 */
- 0xbd, /* 10111101 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0xc3, /* 11000011 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 11 0x0b '^K' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x0e, /* 00001110 */
- 0x1a, /* 00011010 */
- 0x32, /* 00110010 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 12 0x0c '^L' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 13 0x0d '^M' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x33, /* 00110011 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x70, /* 01110000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 14 0x0e '^N' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x67, /* 01100111 */
- 0xe7, /* 11100111 */
- 0xe6, /* 11100110 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 15 0x0f '^O' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xdb, /* 11011011 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0x3c, /* 00111100 */
- 0xdb, /* 11011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 16 0x10 '^P' */
- 0x00, /* 00000000 */
- 0x80, /* 10000000 */
- 0xc0, /* 11000000 */
- 0xe0, /* 11100000 */
- 0xf0, /* 11110000 */
- 0xf8, /* 11111000 */
- 0xfe, /* 11111110 */
- 0xf8, /* 11111000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
- 0xc0, /* 11000000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 17 0x11 '^Q' */
- 0x00, /* 00000000 */
- 0x02, /* 00000010 */
- 0x06, /* 00000110 */
- 0x0e, /* 00001110 */
- 0x1e, /* 00011110 */
- 0x3e, /* 00111110 */
- 0xfe, /* 11111110 */
- 0x3e, /* 00111110 */
- 0x1e, /* 00011110 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 18 0x12 '^R' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 19 0x13 '^S' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 20 0x14 '^T' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7f, /* 01111111 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7b, /* 01111011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 21 0x15 '^U' */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 22 0x16 '^V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 23 0x17 '^W' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 24 0x18 '^X' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 25 0x19 '^Y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 26 0x1a '^Z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 27 0x1b '^[' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 28 0x1c '^\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 29 0x1d '^]' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x28, /* 00101000 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x28, /* 00101000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 30 0x1e '^^' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 31 0x1f '^_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 32 0x20 ' ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 33 0x21 '!' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 34 0x22 '"' */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x24, /* 00100100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 35 0x23 '#' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 36 0x24 '$' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x86, /* 10000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 37 0x25 '%' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc2, /* 11000010 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0x86, /* 10000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 38 0x26 '&' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 39 0x27 ''' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 40 0x28 '(' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 41 0x29 ')' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 42 0x2a '*' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0xff, /* 11111111 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 43 0x2b '+' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 44 0x2c ',' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 45 0x2d '-' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 46 0x2e '.' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 47 0x2f '/' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x02, /* 00000010 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 48 0x30 '0' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 49 0x31 '1' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x38, /* 00111000 */
- 0x78, /* 01111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 50 0x32 '2' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 51 0x33 '3' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x3c, /* 00111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 52 0x34 '4' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x1c, /* 00011100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 53 0x35 '5' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 54 0x36 '6' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 55 0x37 '7' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 56 0x38 '8' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 57 0x39 '9' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 58 0x3a ':' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 59 0x3b ';' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 60 0x3c '<' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 61 0x3d '=' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 62 0x3e '>' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 63 0x3f '?' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 64 0x40 '@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xdc, /* 11011100 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 65 0x41 'A' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 66 0x42 'B' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 67 0x43 'C' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc2, /* 11000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 68 0x44 'D' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 69 0x45 'E' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x60, /* 01100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 70 0x46 'F' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 71 0x47 'G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xde, /* 11011110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x66, /* 01100110 */
- 0x3a, /* 00111010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 72 0x48 'H' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 73 0x49 'I' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 74 0x4a 'J' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 75 0x4b 'K' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe6, /* 11100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 76 0x4c 'L' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 77 0x4d 'M' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xee, /* 11101110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 78 0x4e 'N' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xfe, /* 11111110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 79 0x4f 'O' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 80 0x50 'P' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 81 0x51 'Q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xde, /* 11011110 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 82 0x52 'R' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 83 0x53 'S' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 84 0x54 'T' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x5a, /* 01011010 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 85 0x55 'U' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 86 0x56 'V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 87 0x57 'W' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0xee, /* 11101110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 88 0x58 'X' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 89 0x59 'Y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 90 0x5a 'Z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x86, /* 10000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc2, /* 11000010 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 91 0x5b '[' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 92 0x5c '\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x80, /* 10000000 */
- 0xc0, /* 11000000 */
- 0xe0, /* 11100000 */
- 0x70, /* 01110000 */
- 0x38, /* 00111000 */
- 0x1c, /* 00011100 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 93 0x5d ']' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 94 0x5e '^' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 95 0x5f '_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 96 0x60 '`' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 97 0x61 'a' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 98 0x62 'b' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 99 0x63 'c' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 100 0x64 'd' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 101 0x65 'e' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 102 0x66 'f' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x36, /* 00110110 */
- 0x32, /* 00110010 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 103 0x67 'g' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 104 0x68 'h' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x6c, /* 01101100 */
- 0x76, /* 01110110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 105 0x69 'i' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 106 0x6a 'j' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 107 0x6b 'k' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 108 0x6c 'l' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 109 0x6d 'm' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 110 0x6e 'n' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 111 0x6f 'o' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 112 0x70 'p' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 113 0x71 'q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
-
- /* 114 0x72 'r' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x66, /* 01100110 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 115 0x73 's' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 116 0x74 't' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0xfc, /* 11111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x36, /* 00110110 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 117 0x75 'u' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 118 0x76 'v' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 119 0x77 'w' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 120 0x78 'x' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 121 0x79 'y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
-
- /* 122 0x7a 'z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 123 0x7b '{' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 124 0x7c '|' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 125 0x7d '}' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 126 0x7e '~' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 127 0x7f '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 128 0x80 '€' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc2, /* 11000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 129 0x81 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 130 0x82 '‚' */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 131 0x83 'ƒ' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 132 0x84 '„' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 133 0x85 '…' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 134 0x86 '†' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 135 0x87 '‡' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 136 0x88 'ˆ' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 137 0x89 '‰' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 138 0x8a 'Š' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 139 0x8b '‹' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 140 0x8c 'Œ' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 141 0x8d '' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 142 0x8e 'Ž' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 143 0x8f '' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 144 0x90 '' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 145 0x91 '‘' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x6e, /* 01101110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 146 0x92 '’' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3e, /* 00111110 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 147 0x93 '“' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 148 0x94 '”' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 149 0x95 '•' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 150 0x96 '–' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 151 0x97 '—' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 152 0x98 '˜' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 153 0x99 '™' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 154 0x9a 'š' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 155 0x9b '›' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 156 0x9c 'œ' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x64, /* 01100100 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xe6, /* 11100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 157 0x9d '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 158 0x9e 'ž' */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xf8, /* 11111000 */
- 0xc4, /* 11000100 */
- 0xcc, /* 11001100 */
- 0xde, /* 11011110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 159 0x9f 'Ÿ' */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 160 0xa0 ' ' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 161 0xa1 '¡' */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 162 0xa2 '¢' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 163 0xa3 '£' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 164 0xa4 '¤' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 165 0xa5 '¥' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xfe, /* 11111110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 166 0xa6 '¦' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 167 0xa7 '§' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 168 0xa8 '¨' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 169 0xa9 '©' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 170 0xaa 'ª' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 171 0xab '«' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0xe0, /* 11100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xdc, /* 11011100 */
- 0x86, /* 10000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 172 0xac '¬' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0xe0, /* 11100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x66, /* 01100110 */
- 0xce, /* 11001110 */
- 0x9a, /* 10011010 */
- 0x3f, /* 00111111 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 173 0xad '­' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 174 0xae '®' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x36, /* 00110110 */
- 0x6c, /* 01101100 */
- 0xd8, /* 11011000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 175 0xaf '¯' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xd8, /* 11011000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x6c, /* 01101100 */
- 0xd8, /* 11011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 176 0xb0 '°' */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
-
- /* 177 0xb1 '±' */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
-
- /* 178 0xb2 '²' */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
-
- /* 179 0xb3 '³' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 180 0xb4 '´' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 181 0xb5 'µ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 182 0xb6 '¶' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 183 0xb7 '·' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 184 0xb8 '¸' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 185 0xb9 '¹' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 186 0xba 'º' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 187 0xbb '»' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 188 0xbc '¼' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 189 0xbd '½' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 190 0xbe '¾' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 191 0xbf '¿' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 192 0xc0 'À' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 193 0xc1 'Á' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 194 0xc2 'Â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 195 0xc3 'Ã' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 196 0xc4 'Ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 197 0xc5 'Å' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 198 0xc6 'Æ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 199 0xc7 'Ç' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 200 0xc8 'È' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 201 0xc9 'É' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 202 0xca 'Ê' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 203 0xcb 'Ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 204 0xcc 'Ì' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 205 0xcd 'Í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 206 0xce 'Î' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 207 0xcf 'Ï' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 208 0xd0 'Ð' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 209 0xd1 'Ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 210 0xd2 'Ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 211 0xd3 'Ó' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 212 0xd4 'Ô' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 213 0xd5 'Õ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 214 0xd6 'Ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 215 0xd7 '×' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 216 0xd8 'Ø' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 217 0xd9 'Ù' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 218 0xda 'Ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 219 0xdb 'Û' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 220 0xdc 'Ü' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 221 0xdd 'Ý' */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
-
- /* 222 0xde 'Þ' */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
-
- /* 223 0xdf 'ß' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 224 0xe0 'à' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 225 0xe1 'á' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 226 0xe2 'â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 227 0xe3 'ã' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 228 0xe4 'ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 229 0xe5 'å' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 230 0xe6 'æ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 231 0xe7 'ç' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 232 0xe8 'è' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 233 0xe9 'é' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 234 0xea 'ê' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xee, /* 11101110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 235 0xeb 'ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x3e, /* 00111110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 236 0xec 'ì' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 237 0xed 'í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x03, /* 00000011 */
- 0x06, /* 00000110 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xf3, /* 11110011 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 238 0xee 'î' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 239 0xef 'ï' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 240 0xf0 'ð' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 241 0xf1 'ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 242 0xf2 'ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 243 0xf3 'ó' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 244 0xf4 'ô' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 245 0xf5 'õ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 246 0xf6 'ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 247 0xf7 '÷' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 248 0xf8 'ø' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 249 0xf9 'ù' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 250 0xfa 'ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 251 0xfb 'û' */
- 0x00, /* 00000000 */
- 0x0f, /* 00001111 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xec, /* 11101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3c, /* 00111100 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 252 0xfc 'ü' */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 253 0xfd 'ý' */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x32, /* 00110010 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 254 0xfe 'þ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 255 0xff 'ÿ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
-};
-
diff --git a/arch/m68k/console/font_8x8.c b/arch/m68k/console/font_8x8.c
deleted file mode 100644
index 72a6c3f8f..000000000
--- a/arch/m68k/console/font_8x8.c
+++ /dev/null
@@ -1,2577 +0,0 @@
-/**********************************************/
-/* */
-/* Font file generated by cpi2fnt */
-/* */
-/**********************************************/
-
-#define FONTDATAMAX 2048
-
-char fontname_8x8[] = "VGA8x8";
-
-int fontheight_8x8 = 8;
-int fontwidth_8x8 = 8;
-
-unsigned char fontdata_8x8[FONTDATAMAX] = {
-
- /* 0 0x00 '^@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 1 0x01 '^A' */
- 0x7e, /* 01111110 */
- 0x81, /* 10000001 */
- 0xa5, /* 10100101 */
- 0x81, /* 10000001 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0x81, /* 10000001 */
- 0x7e, /* 01111110 */
-
- /* 2 0x02 '^B' */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xdb, /* 11011011 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
-
- /* 3 0x03 '^C' */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
-
- /* 4 0x04 '^D' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
-
- /* 5 0x05 '^E' */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
-
- /* 6 0x06 '^F' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
-
- /* 7 0x07 '^G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 8 0x08 '^H' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xe7, /* 11100111 */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 9 0x09 '^I' */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x42, /* 01000010 */
- 0x42, /* 01000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 10 0x0a '^J' */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0x99, /* 10011001 */
- 0xbd, /* 10111101 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0xc3, /* 11000011 */
- 0xff, /* 11111111 */
-
- /* 11 0x0b '^K' */
- 0x0f, /* 00001111 */
- 0x07, /* 00000111 */
- 0x0f, /* 00001111 */
- 0x7d, /* 01111101 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
-
- /* 12 0x0c '^L' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
-
- /* 13 0x0d '^M' */
- 0x3f, /* 00111111 */
- 0x33, /* 00110011 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x70, /* 01110000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
-
- /* 14 0x0e '^N' */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x67, /* 01100111 */
- 0xe6, /* 11100110 */
- 0xc0, /* 11000000 */
-
- /* 15 0x0f '^O' */
- 0x18, /* 00011000 */
- 0xdb, /* 11011011 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0x3c, /* 00111100 */
- 0xdb, /* 11011011 */
- 0x18, /* 00011000 */
-
- /* 16 0x10 '^P' */
- 0x80, /* 10000000 */
- 0xe0, /* 11100000 */
- 0xf8, /* 11111000 */
- 0xfe, /* 11111110 */
- 0xf8, /* 11111000 */
- 0xe0, /* 11100000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
-
- /* 17 0x11 '^Q' */
- 0x02, /* 00000010 */
- 0x0e, /* 00001110 */
- 0x3e, /* 00111110 */
- 0xfe, /* 11111110 */
- 0x3e, /* 00111110 */
- 0x0e, /* 00001110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
-
- /* 18 0x12 '^R' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
-
- /* 19 0x13 '^S' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
-
- /* 20 0x14 '^T' */
- 0x7f, /* 01111111 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7b, /* 01111011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x00, /* 00000000 */
-
- /* 21 0x15 '^U' */
- 0x3e, /* 00111110 */
- 0x61, /* 01100001 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x86, /* 10000110 */
- 0x7c, /* 01111100 */
-
- /* 22 0x16 '^V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 23 0x17 '^W' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
-
- /* 24 0x18 '^X' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 25 0x19 '^Y' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 26 0x1a '^Z' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 27 0x1b '^[' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 28 0x1c '^\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 29 0x1d '^]' */
- 0x00, /* 00000000 */
- 0x24, /* 00100100 */
- 0x66, /* 01100110 */
- 0xff, /* 11111111 */
- 0x66, /* 01100110 */
- 0x24, /* 00100100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 30 0x1e '^^' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 31 0x1f '^_' */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 32 0x20 ' ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 33 0x21 '!' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 34 0x22 '"' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x24, /* 00100100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 35 0x23 '#' */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 36 0x24 '$' */
- 0x18, /* 00011000 */
- 0x3e, /* 00111110 */
- 0x60, /* 01100000 */
- 0x3c, /* 00111100 */
- 0x06, /* 00000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 37 0x25 '%' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x66, /* 01100110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 38 0x26 '&' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 39 0x27 ''' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 40 0x28 '(' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
-
- /* 41 0x29 ')' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
-
- /* 42 0x2a '*' */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0xff, /* 11111111 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 43 0x2b '+' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 44 0x2c ',' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
-
- /* 45 0x2d '-' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 46 0x2e '.' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 47 0x2f '/' */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
-
- /* 48 0x30 '0' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 49 0x31 '1' */
- 0x18, /* 00011000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 50 0x32 '2' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x1c, /* 00011100 */
- 0x30, /* 00110000 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 51 0x33 '3' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x3c, /* 00111100 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 52 0x34 '4' */
- 0x1c, /* 00011100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
-
- /* 53 0x35 '5' */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 54 0x36 '6' */
- 0x38, /* 00111000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 55 0x37 '7' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
-
- /* 56 0x38 '8' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 57 0x39 '9' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 58 0x3a ':' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 59 0x3b ';' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
-
- /* 60 0x3c '<' */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
-
- /* 61 0x3d '=' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 62 0x3e '>' */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
-
- /* 63 0x3f '?' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 64 0x40 '@' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xc0, /* 11000000 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 65 0x41 'A' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 66 0x42 'B' */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 67 0x43 'C' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 68 0x44 'D' */
- 0xf8, /* 11111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
-
- /* 69 0x45 'E' */
- 0xfe, /* 11111110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x62, /* 01100010 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 70 0x46 'F' */
- 0xfe, /* 11111110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 71 0x47 'G' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xce, /* 11001110 */
- 0x66, /* 01100110 */
- 0x3a, /* 00111010 */
- 0x00, /* 00000000 */
-
- /* 72 0x48 'H' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 73 0x49 'I' */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 74 0x4a 'J' */
- 0x1e, /* 00011110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 75 0x4b 'K' */
- 0xe6, /* 11100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
-
- /* 76 0x4c 'L' */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 77 0x4d 'M' */
- 0xc6, /* 11000110 */
- 0xee, /* 11101110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 78 0x4e 'N' */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 79 0x4f 'O' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 80 0x50 'P' */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 81 0x51 'Q' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xce, /* 11001110 */
- 0x7c, /* 01111100 */
- 0x0e, /* 00001110 */
-
- /* 82 0x52 'R' */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
-
- /* 83 0x53 'S' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 84 0x54 'T' */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x5a, /* 01011010 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 85 0x55 'U' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 86 0x56 'V' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 87 0x57 'W' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 88 0x58 'X' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 89 0x59 'Y' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 90 0x5a 'Z' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x8c, /* 10001100 */
- 0x18, /* 00011000 */
- 0x32, /* 00110010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 91 0x5b '[' */
- 0x3c, /* 00111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 92 0x5c '\' */
- 0xc0, /* 11000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
-
- /* 93 0x5d ']' */
- 0x3c, /* 00111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 94 0x5e '^' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 95 0x5f '_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
-
- /* 96 0x60 '`' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 97 0x61 'a' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 98 0x62 'b' */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x7c, /* 01111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
-
- /* 99 0x63 'c' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 100 0x64 'd' */
- 0x1c, /* 00011100 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 101 0x65 'e' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 102 0x66 'f' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x60, /* 01100000 */
- 0xf8, /* 11111000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 103 0x67 'g' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0xf8, /* 11111000 */
-
- /* 104 0x68 'h' */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x6c, /* 01101100 */
- 0x76, /* 01110110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
-
- /* 105 0x69 'i' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 106 0x6a 'j' */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
-
- /* 107 0x6b 'k' */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
-
- /* 108 0x6c 'l' */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 109 0x6d 'm' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0x00, /* 00000000 */
-
- /* 110 0x6e 'n' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
-
- /* 111 0x6f 'o' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 112 0x70 'p' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
-
- /* 113 0x71 'q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
-
- /* 114 0x72 'r' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 115 0x73 's' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 116 0x74 't' */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0xfc, /* 11111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x36, /* 00110110 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
-
- /* 117 0x75 'u' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 118 0x76 'v' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 119 0x77 'w' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 120 0x78 'x' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 121 0x79 'y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0xfc, /* 11111100 */
-
- /* 122 0x7a 'z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x4c, /* 01001100 */
- 0x18, /* 00011000 */
- 0x32, /* 00110010 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 123 0x7b '{' */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
-
- /* 124 0x7c '|' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 125 0x7d '}' */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 126 0x7e '~' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 127 0x7f '' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 128 0x80 '€' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
-
- /* 129 0x81 '' */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 130 0x82 '‚' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 131 0x83 'ƒ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 132 0x84 '„' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 133 0x85 '…' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 134 0x86 '†' */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 135 0x87 '‡' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x7e, /* 01111110 */
- 0x0c, /* 00001100 */
- 0x38, /* 00111000 */
-
- /* 136 0x88 'ˆ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 137 0x89 '‰' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 138 0x8a 'Š' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 139 0x8b '‹' */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 140 0x8c 'Œ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 141 0x8d '' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 142 0x8e 'Ž' */
- 0xc6, /* 11000110 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 143 0x8f '' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 144 0x90 '' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xf8, /* 11111000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 145 0x91 '‘' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 146 0x92 '’' */
- 0x3e, /* 00111110 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
-
- /* 147 0x93 '“' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 148 0x94 '”' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 149 0x95 '•' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 150 0x96 '–' */
- 0x78, /* 01111000 */
- 0x84, /* 10000100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 151 0x97 '—' */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 152 0x98 '˜' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0xfc, /* 11111100 */
-
- /* 153 0x99 '™' */
- 0xc6, /* 11000110 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 154 0x9a 'š' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 155 0x9b '›' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 156 0x9c 'œ' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x64, /* 01100100 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x66, /* 01100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 157 0x9d '' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 158 0x9e 'ž' */
- 0xf8, /* 11111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xfa, /* 11111010 */
- 0xc6, /* 11000110 */
- 0xcf, /* 11001111 */
- 0xc6, /* 11000110 */
- 0xc7, /* 11000111 */
-
- /* 159 0x9f 'Ÿ' */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 160 0xa0 ' ' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 161 0xa1 '¡' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 162 0xa2 '¢' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 163 0xa3 '£' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 164 0xa4 '¤' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
-
- /* 165 0xa5 '¥' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
-
- /* 166 0xa6 '¦' */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 167 0xa7 '§' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 168 0xa8 '¨' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x63, /* 01100011 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
-
- /* 169 0xa9 '©' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 170 0xaa 'ª' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 171 0xab '«' */
- 0x63, /* 01100011 */
- 0xe6, /* 11100110 */
- 0x6c, /* 01101100 */
- 0x7e, /* 01111110 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x0f, /* 00001111 */
-
- /* 172 0xac '¬' */
- 0x63, /* 01100011 */
- 0xe6, /* 11100110 */
- 0x6c, /* 01101100 */
- 0x7a, /* 01111010 */
- 0x36, /* 00110110 */
- 0x6a, /* 01101010 */
- 0xdf, /* 11011111 */
- 0x06, /* 00000110 */
-
- /* 173 0xad '­' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 174 0xae '®' */
- 0x00, /* 00000000 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x66, /* 01100110 */
- 0x33, /* 00110011 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 175 0xaf '¯' */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x66, /* 01100110 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 176 0xb0 '°' */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
-
- /* 177 0xb1 '±' */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
-
- /* 178 0xb2 '²' */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
-
- /* 179 0xb3 '³' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 180 0xb4 '´' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 181 0xb5 'µ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 182 0xb6 '¶' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 183 0xb7 '·' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 184 0xb8 '¸' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 185 0xb9 '¹' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 186 0xba 'º' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 187 0xbb '»' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 188 0xbc '¼' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 189 0xbd '½' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 190 0xbe '¾' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 191 0xbf '¿' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 192 0xc0 'À' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 193 0xc1 'Á' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 194 0xc2 'Â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 195 0xc3 'Ã' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 196 0xc4 'Ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 197 0xc5 'Å' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 198 0xc6 'Æ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 199 0xc7 'Ç' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 200 0xc8 'È' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 201 0xc9 'É' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 202 0xca 'Ê' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 203 0xcb 'Ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 204 0xcc 'Ì' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 205 0xcd 'Í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 206 0xce 'Î' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 207 0xcf 'Ï' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 208 0xd0 'Ð' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 209 0xd1 'Ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 210 0xd2 'Ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 211 0xd3 'Ó' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 212 0xd4 'Ô' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 213 0xd5 'Õ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 214 0xd6 'Ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 215 0xd7 '×' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 216 0xd8 'Ø' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 217 0xd9 'Ù' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 218 0xda 'Ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 219 0xdb 'Û' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 220 0xdc 'Ü' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 221 0xdd 'Ý' */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
-
- /* 222 0xde 'Þ' */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
-
- /* 223 0xdf 'ß' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 224 0xe0 'à' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xc8, /* 11001000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 225 0xe1 'á' */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
-
- /* 226 0xe2 'â' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 227 0xe3 'ã' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 228 0xe4 'ä' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 229 0xe5 'å' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 230 0xe6 'æ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0xc0, /* 11000000 */
-
- /* 231 0xe7 'ç' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 232 0xe8 'è' */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
-
- /* 233 0xe9 'é' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 234 0xea 'ê' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xee, /* 11101110 */
- 0x00, /* 00000000 */
-
- /* 235 0xeb 'ë' */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x3e, /* 00111110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 236 0xec 'ì' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 237 0xed 'í' */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
-
- /* 238 0xee 'î' */
- 0x1e, /* 00011110 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
-
- /* 239 0xef 'ï' */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 240 0xf0 'ð' */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 241 0xf1 'ñ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 242 0xf2 'ò' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 243 0xf3 'ó' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 244 0xf4 'ô' */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 245 0xf5 'õ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
-
- /* 246 0xf6 'ö' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 247 0xf7 '÷' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 248 0xf8 'ø' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 249 0xf9 'ù' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 250 0xfa 'ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 251 0xfb 'û' */
- 0x0f, /* 00001111 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xec, /* 11101100 */
- 0x6c, /* 01101100 */
- 0x3c, /* 00111100 */
- 0x1c, /* 00011100 */
-
- /* 252 0xfc 'ü' */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 253 0xfd 'ý' */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 254 0xfe 'þ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 255 0xff 'ÿ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
-};
-
diff --git a/arch/m68k/console/fonts.c b/arch/m68k/console/fonts.c
deleted file mode 100644
index 934a0bc70..000000000
--- a/arch/m68k/console/fonts.c
+++ /dev/null
@@ -1,108 +0,0 @@
-
-/*
- * arch/m68k/console/fonts.c -- `Soft' font definitions
- *
- * Created 1995 by Geert Uytterhoeven
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <asm/setup.h>
-#include <asm/font.h>
-
-
- /*
- * External Font Definitions
- */
-
-/* VGA8x8 */
-extern char fontname_8x8[];
-extern int fontwidth_8x8, fontheight_8x8;
-extern u_char fontdata_8x8[];
-
-/* VGA8x16 */
-extern char fontname_8x16[];
-extern int fontwidth_8x16, fontheight_8x16;
-extern u_char fontdata_8x16[];
-
-/* PEARL8x8 */
-extern char fontname_pearl8x8[];
-extern int fontwidth_pearl8x8, fontheight_pearl8x8;
-extern u_char fontdata_pearl8x8[];
-
-
- /*
- * Font Descriptor Array
- */
-
-struct softfontdesc {
- char *name;
- int *width;
- int *height;
- u_char *data;
-};
-
-#define VGA8x8_IDX 0
-#define VGA8x16_IDX 1
-#define PEARL8x8_IDX 2
-
-static struct softfontdesc softfonts[] = {
- { fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 },
- { fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 },
- { fontname_pearl8x8, &fontwidth_pearl8x8, &fontheight_pearl8x8,
- fontdata_pearl8x8 },
-};
-
-static u_long numsoftfonts = sizeof(softfonts)/sizeof(*softfonts);
-
-
- /*
- * Find a font with a specific name
- */
-
-int findsoftfont(char *name, int *width, int *height, u_char *data[])
-{
- int i;
-
- for (i = 0; i < numsoftfonts; i++)
- if (!strcmp(softfonts[i].name, name)) {
- if (width)
- *width = *softfonts[i].width;
- if (height)
- *height = *softfonts[i].height;
- if (data)
- *data = softfonts[i].data;
- return(1);
- }
- return(0);
-}
-
-
- /*
- * Get the default font for a specific screen size
- */
-
-void getdefaultfont(int xres, int yres, char *name[], int *width, int *height,
- u_char *data[])
-{
- int i;
-
- if (yres < 400)
- i = MACH_IS_AMIGA ? PEARL8x8_IDX : VGA8x8_IDX;
- else
- i = VGA8x16_IDX;
-
- if (name)
- *name = softfonts[i].name;
- if (width)
- *width = *softfonts[i].width;
- if (height)
- *height = *softfonts[i].height;
- if (data)
- *data = softfonts[i].data;
-}
diff --git a/arch/m68k/console/pearl_8x8.c b/arch/m68k/console/pearl_8x8.c
deleted file mode 100644
index a48c702d2..000000000
--- a/arch/m68k/console/pearl_8x8.c
+++ /dev/null
@@ -1,2582 +0,0 @@
-/**********************************************/
-/* */
-/* Font file generated by cpi2fnt */
-/* ------------------------------ */
-/* Combined with the alpha-numeric */
-/* portion of Greg Harp's old PEARL */
-/* font (from earlier versions of */
-/* linux-m86k) by John Shifflett */
-/* */
-/**********************************************/
-
-#define FONTDATAMAX 2048
-
-char fontname_pearl8x8[] = "PEARL8x8";
-
-int fontheight_pearl8x8 = 8;
-int fontwidth_pearl8x8 = 8;
-
-unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
-
- /* 0 0x00 '^@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 1 0x01 '^A' */
- 0x7e, /* 01111110 */
- 0x81, /* 10000001 */
- 0xa5, /* 10100101 */
- 0x81, /* 10000001 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0x81, /* 10000001 */
- 0x7e, /* 01111110 */
-
- /* 2 0x02 '^B' */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xdb, /* 11011011 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
-
- /* 3 0x03 '^C' */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
-
- /* 4 0x04 '^D' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
-
- /* 5 0x05 '^E' */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
-
- /* 6 0x06 '^F' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
-
- /* 7 0x07 '^G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 8 0x08 '^H' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xe7, /* 11100111 */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 9 0x09 '^I' */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x42, /* 01000010 */
- 0x42, /* 01000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 10 0x0a '^J' */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0x99, /* 10011001 */
- 0xbd, /* 10111101 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0xc3, /* 11000011 */
- 0xff, /* 11111111 */
-
- /* 11 0x0b '^K' */
- 0x0f, /* 00001111 */
- 0x07, /* 00000111 */
- 0x0f, /* 00001111 */
- 0x7d, /* 01111101 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
-
- /* 12 0x0c '^L' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
-
- /* 13 0x0d '^M' */
- 0x3f, /* 00111111 */
- 0x33, /* 00110011 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x70, /* 01110000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
-
- /* 14 0x0e '^N' */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x67, /* 01100111 */
- 0xe6, /* 11100110 */
- 0xc0, /* 11000000 */
-
- /* 15 0x0f '^O' */
- 0x18, /* 00011000 */
- 0xdb, /* 11011011 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0x3c, /* 00111100 */
- 0xdb, /* 11011011 */
- 0x18, /* 00011000 */
-
- /* 16 0x10 '^P' */
- 0x80, /* 10000000 */
- 0xe0, /* 11100000 */
- 0xf8, /* 11111000 */
- 0xfe, /* 11111110 */
- 0xf8, /* 11111000 */
- 0xe0, /* 11100000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
-
- /* 17 0x11 '^Q' */
- 0x02, /* 00000010 */
- 0x0e, /* 00001110 */
- 0x3e, /* 00111110 */
- 0xfe, /* 11111110 */
- 0x3e, /* 00111110 */
- 0x0e, /* 00001110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
-
- /* 18 0x12 '^R' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
-
- /* 19 0x13 '^S' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
-
- /* 20 0x14 '^T' */
- 0x7f, /* 01111111 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7b, /* 01111011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x00, /* 00000000 */
-
- /* 21 0x15 '^U' */
- 0x3e, /* 00111110 */
- 0x61, /* 01100001 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x86, /* 10000110 */
- 0x7c, /* 01111100 */
-
- /* 22 0x16 '^V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 23 0x17 '^W' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
-
- /* 24 0x18 '^X' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 25 0x19 '^Y' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 26 0x1a '^Z' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 27 0x1b '^[' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 28 0x1c '^\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 29 0x1d '^]' */
- 0x00, /* 00000000 */
- 0x24, /* 00100100 */
- 0x66, /* 01100110 */
- 0xff, /* 11111111 */
- 0x66, /* 01100110 */
- 0x24, /* 00100100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 30 0x1e '^^' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 31 0x1f '^_' */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 32 0x20 ' ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 33 0x21 '!' */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 34 0x22 '"' */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 35 0x23 '#' */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 36 0x24 '$' */
- 0x18, /* 00011000 */
- 0x3e, /* 00111110 */
- 0x60, /* 01100000 */
- 0x3c, /* 00111100 */
- 0x06, /* 00000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 37 0x25 '%' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x66, /* 01100110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 38 0x26 '&' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x68, /* 01101000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 39 0x27 ''' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 40 0x28 '(' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
-
- /* 41 0x29 ')' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
-
- /* 42 0x2a '*' */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0xff, /* 11111111 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 43 0x2b '+' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 44 0x2c ',' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
-
- /* 45 0x2d '-' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 46 0x2e '.' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 47 0x2f '/' */
- 0x03, /* 00000011 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 48 0x30 '0' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xde, /* 11011110 */
- 0xfe, /* 11111110 */
- 0xf6, /* 11110110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 49 0x31 '1' */
- 0x18, /* 00011000 */
- 0x78, /* 01111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 50 0x32 '2' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 51 0x33 '3' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x1c, /* 00011100 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 52 0x34 '4' */
- 0x1c, /* 00011100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
-
- /* 53 0x35 '5' */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 54 0x36 '6' */
- 0x38, /* 00111000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 55 0x37 '7' */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
-
- /* 56 0x38 '8' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 57 0x39 '9' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 58 0x3a ':' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 59 0x3b ';' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
-
- /* 60 0x3c '<' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
-
- /* 61 0x3d '=' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 62 0x3e '>' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
-
- /* 63 0x3f '?' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 64 0x40 '@' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 65 0x41 'A' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 66 0x42 'B' */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 67 0x43 'C' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 68 0x44 'D' */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 69 0x45 'E' */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xf8, /* 11111000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 70 0x46 'F' */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xf8, /* 11111000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 71 0x47 'G' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 72 0x48 'H' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 73 0x49 'I' */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 74 0x4a 'J' */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 75 0x4b 'K' */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xf0, /* 11110000 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 76 0x4c 'L' */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 77 0x4d 'M' */
- 0x82, /* 10000010 */
- 0xc6, /* 11000110 */
- 0xee, /* 11101110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 78 0x4e 'N' */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 79 0x4f 'O' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 80 0x50 'P' */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 81 0x51 'Q' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xf6, /* 11110110 */
- 0xde, /* 11011110 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
-
- /* 82 0x52 'R' */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 83 0x53 'S' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 84 0x54 'T' */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 85 0x55 'U' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 86 0x56 'V' */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 87 0x57 'W' */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0xee, /* 11101110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 88 0x58 'X' */
- 0xc3, /* 11000011 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc3, /* 11000011 */
- 0x00, /* 00000000 */
-
- /* 89 0x59 'Y' */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 90 0x5a 'Z' */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 91 0x5b '[' */
- 0x3c, /* 00111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 92 0x5c '\' */
- 0xc0, /* 11000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x03, /* 00000011 */
- 0x00, /* 00000000 */
-
- /* 93 0x5d ']' */
- 0x3c, /* 00111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 94 0x5e '^' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 95 0x5f '_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
-
- /* 96 0x60 '`' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 97 0x61 'a' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
- 0x7e, /* 01111110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 98 0x62 'b' */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 99 0x63 'c' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 100 0x64 'd' */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x7e, /* 01111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 101 0x65 'e' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 102 0x66 'f' */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
-
- /* 103 0x67 'g' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x7c, /* 01111100 */
-
- /* 104 0x68 'h' */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 105 0x69 'i' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 106 0x6a 'j' */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
-
- /* 107 0x6b 'k' */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xf0, /* 11110000 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
-
- /* 108 0x6c 'l' */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 109 0x6d 'm' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 110 0x6e 'n' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 111 0x6f 'o' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 112 0x70 'p' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfc, /* 11111100 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
-
- /* 113 0x71 'q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
-
- /* 114 0x72 'r' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0xe6, /* 11100110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 115 0x73 's' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 116 0x74 't' */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x7c, /* 01111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x36, /* 00110110 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
-
- /* 117 0x75 'u' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 118 0x76 'v' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 119 0x77 'w' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 120 0x78 'x' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 121 0x79 'y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc3, /* 11000011 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
-
- /* 122 0x7a 'z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x38, /* 00111000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 123 0x7b '{' */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
-
- /* 124 0x7c '|' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 125 0x7d '}' */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 126 0x7e '~' */
- 0x72, /* 01110010 */
- 0x9c, /* 10011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 127 0x7f '' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 128 0x80 '€' */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
-
- /* 129 0x81 '' */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 130 0x82 '‚' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 131 0x83 'ƒ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 132 0x84 '„' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 133 0x85 '…' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 134 0x86 '†' */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 135 0x87 '‡' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x7e, /* 01111110 */
- 0x0c, /* 00001100 */
- 0x38, /* 00111000 */
-
- /* 136 0x88 'ˆ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 137 0x89 '‰' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 138 0x8a 'Š' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 139 0x8b '‹' */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 140 0x8c 'Œ' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 141 0x8d '' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 142 0x8e 'Ž' */
- 0xc6, /* 11000110 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 143 0x8f '' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 144 0x90 '' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xf8, /* 11111000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 145 0x91 '‘' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 146 0x92 '’' */
- 0x3e, /* 00111110 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
-
- /* 147 0x93 '“' */
- 0x7c, /* 01111100 */
- 0x82, /* 10000010 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 148 0x94 '”' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 149 0x95 '•' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 150 0x96 '–' */
- 0x78, /* 01111000 */
- 0x84, /* 10000100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 151 0x97 '—' */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 152 0x98 '˜' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0xfc, /* 11111100 */
-
- /* 153 0x99 '™' */
- 0xc6, /* 11000110 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 154 0x9a 'š' */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 155 0x9b '›' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 156 0x9c 'œ' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x64, /* 01100100 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x66, /* 01100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
-
- /* 157 0x9d '' */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 158 0x9e 'ž' */
- 0xf8, /* 11111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xfa, /* 11111010 */
- 0xc6, /* 11000110 */
- 0xcf, /* 11001111 */
- 0xc6, /* 11000110 */
- 0xc7, /* 11000111 */
-
- /* 159 0x9f 'Ÿ' */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 160 0xa0 ' ' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 161 0xa1 '¡' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 162 0xa2 '¢' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
-
- /* 163 0xa3 '£' */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 164 0xa4 '¤' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
-
- /* 165 0xa5 '¥' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
-
- /* 166 0xa6 '¦' */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 167 0xa7 '§' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 168 0xa8 '¨' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x63, /* 01100011 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
-
- /* 169 0xa9 '©' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 170 0xaa 'ª' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 171 0xab '«' */
- 0x63, /* 01100011 */
- 0xe6, /* 11100110 */
- 0x6c, /* 01101100 */
- 0x7e, /* 01111110 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x0f, /* 00001111 */
-
- /* 172 0xac '¬' */
- 0x63, /* 01100011 */
- 0xe6, /* 11100110 */
- 0x6c, /* 01101100 */
- 0x7a, /* 01111010 */
- 0x36, /* 00110110 */
- 0x6a, /* 01101010 */
- 0xdf, /* 11011111 */
- 0x06, /* 00000110 */
-
- /* 173 0xad '­' */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 174 0xae '®' */
- 0x00, /* 00000000 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x66, /* 01100110 */
- 0x33, /* 00110011 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 175 0xaf '¯' */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x66, /* 01100110 */
- 0x33, /* 00110011 */
- 0x66, /* 01100110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 176 0xb0 '°' */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
- 0x22, /* 00100010 */
- 0x88, /* 10001000 */
-
- /* 177 0xb1 '±' */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
-
- /* 178 0xb2 '²' */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
-
- /* 179 0xb3 '³' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 180 0xb4 '´' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 181 0xb5 'µ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 182 0xb6 '¶' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 183 0xb7 '·' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 184 0xb8 '¸' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 185 0xb9 '¹' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 186 0xba 'º' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 187 0xbb '»' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 188 0xbc '¼' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 189 0xbd '½' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 190 0xbe '¾' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 191 0xbf '¿' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 192 0xc0 'À' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 193 0xc1 'Á' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 194 0xc2 'Â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 195 0xc3 'Ã' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 196 0xc4 'Ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 197 0xc5 'Å' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 198 0xc6 'Æ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 199 0xc7 'Ç' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 200 0xc8 'È' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 201 0xc9 'É' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 202 0xca 'Ê' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 203 0xcb 'Ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 204 0xcc 'Ì' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 205 0xcd 'Í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 206 0xce 'Î' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 207 0xcf 'Ï' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 208 0xd0 'Ð' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 209 0xd1 'Ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 210 0xd2 'Ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 211 0xd3 'Ó' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 212 0xd4 'Ô' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 213 0xd5 'Õ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 214 0xd6 'Ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 215 0xd7 '×' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 216 0xd8 'Ø' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 217 0xd9 'Ù' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 218 0xda 'Ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 219 0xdb 'Û' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 220 0xdc 'Ü' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 221 0xdd 'Ý' */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
-
- /* 222 0xde 'Þ' */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
-
- /* 223 0xdf 'ß' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 224 0xe0 'à' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xc8, /* 11001000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
-
- /* 225 0xe1 'á' */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
-
- /* 226 0xe2 'â' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 227 0xe3 'ã' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
-
- /* 228 0xe4 'ä' */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
-
- /* 229 0xe5 'å' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
-
- /* 230 0xe6 'æ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0xc0, /* 11000000 */
-
- /* 231 0xe7 'ç' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
-
- /* 232 0xe8 'è' */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
-
- /* 233 0xe9 'é' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
-
- /* 234 0xea 'ê' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xee, /* 11101110 */
- 0x00, /* 00000000 */
-
- /* 235 0xeb 'ë' */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x3e, /* 00111110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 236 0xec 'ì' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 237 0xed 'í' */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
-
- /* 238 0xee 'î' */
- 0x1e, /* 00011110 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
-
- /* 239 0xef 'ï' */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
-
- /* 240 0xf0 'ð' */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 241 0xf1 'ñ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 242 0xf2 'ò' */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 243 0xf3 'ó' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
-
- /* 244 0xf4 'ô' */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 245 0xf5 'õ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
-
- /* 246 0xf6 'ö' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 247 0xf7 '÷' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 248 0xf8 'ø' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 249 0xf9 'ù' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 250 0xfa 'ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 251 0xfb 'û' */
- 0x0f, /* 00001111 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xec, /* 11101100 */
- 0x6c, /* 01101100 */
- 0x3c, /* 00111100 */
- 0x1c, /* 00011100 */
-
- /* 252 0xfc 'ü' */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 253 0xfd 'ý' */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 254 0xfe 'þ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 255 0xff 'ÿ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
-};
-
diff --git a/arch/m68k/console/txtcon.c b/arch/m68k/console/txtcon.c
deleted file mode 100644
index b85808558..000000000
--- a/arch/m68k/console/txtcon.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * linux/arch/m68k/console/txtcon.c -- Low level text mode based console driver
- *
- * Copyright (C) 1995 Geert Uytterhoeven
- *
- *
- * This file is currently only a skeleton, since all Amigas and Ataris have
- * bitmapped graphics.
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <linux/types.h>
-#include <linux/console.h>
-
-
- /*
- * Interface used by the world
- */
-
-static u_long txtcon_startup(u_long kmem_start, const char **display_desc);
-static void txtcon_init(struct vc_data *conp);
-static int txtcon_deinit(struct vc_data *conp);
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width);
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x);
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
- int x);
-static int txtcon_cursor(struct vc_data *conp, int mode);
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count);
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width);
-static int txtcon_switch(struct vc_data *conp);
-static int txtcon_blank(int blank);
-static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
-static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data);
-static int txtcon_set_palette(struct vc_data *conp, unsigned char *table);
-
-
-static u_long txtcon_startup(u_long kmem_start, const char **display_desc)
-{
- *display_desc = "Not yet implemented";
- return(kmem_start);
-}
-
-
-static void txtcon_init(struct vc_data *conp)
-{
-}
-
-
-static int txtcon_deinit(struct vc_data *conp)
-{
- return(0);
-}
-
-
-/* ====================================================================== */
-
-/* txtcon_XXX routines - interface used by the world */
-
-
-static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height,
- int width)
-{
- return(0);
-}
-
-
-static int txtcon_putc(struct vc_data *conp, int c, int y, int x)
-{
- return(0);
-}
-
-
-static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y,
- int x)
-{
- return(0);
-}
-
-
-static int txtcon_cursor(struct vc_data *conp, int mode)
-{
- return(0);
-}
-
-
-static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
-{
- return(0);
-}
-
-
-static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- int height, int width)
-{
- return(0);
-}
-
-
-static int txtcon_switch(struct vc_data *conp)
-{
- return(0);
-}
-
-
-static int txtcon_blank(int blank)
-{
- return(0);
-}
-
-
-static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data)
-{
- return(0);
-}
-
-
-static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data)
-{
- return(0);
-}
-
-
-static int txtcon_set_palette(struct vc_data *conp, unsigned char *table)
-{
- return(0);
-}
-
-
-/* ====================================================================== */
-
- /*
- * The console `switch' structure for the text mode based console
- */
-
-struct consw txt_con = {
- txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc,
- txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch,
- txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette
-};
-
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 220148670..b76e9af08 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -23,26 +23,28 @@ else
fi
if [ "$CONFIG_PCI" = "y" ]; then
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
- bool ' PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
- if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+ bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+ if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Tekram TRM290 DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
- bool ' OPTi 82C621 enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+ bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+ bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+ bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
fi
fi
fi
bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
comment 'Note: most of these also require special kernel boot parameters'
- bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
- bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
- bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
- bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+ bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+ bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+ bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+ bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+ bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
+ bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+ bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
fi
- bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
- bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
fi
fi
fi
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 50e9f6be6..f992a98a5 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -79,11 +79,17 @@ L_OBJS += hd.o
endif
ifeq ($(CONFIG_BLK_DEV_IDE),y)
-LX_OBJS += ide.o
-L_OBJS += ide-probe.o
+ LX_OBJS += ide.o
+ ifeq ($(CONFIG_PROC_FS),y)
+ L_OBJS += ide-proc.o
+ endif
+ L_OBJS += ide-probe.o
else
ifeq ($(CONFIG_BLK_DEV_IDE),m)
MX_OBJS += ide.o
+ ifeq ($(CONFIG_PROC_FS),y)
+ M_OBJS += ide-proc.o
+ endif
M_OBJS += ide-probe.o
endif
endif
@@ -96,6 +102,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD640),y)
L_OBJS += cmd640.o
endif
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+L_OBJS += ide-pci.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
L_OBJS += ide-dma.o
endif
@@ -137,6 +147,10 @@ ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
L_OBJS += opti621.o
endif
+ifeq ($(CONFIG_BLK_DEV_NS87415),y)
+L_OBJS += ns87415.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_IDEDISK),y)
L_OBJS += ide-disk.o
else
diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c
index 5f6c0f437..c0c7762d6 100644
--- a/drivers/block/ali14xx.c
+++ b/drivers/block/ali14xx.c
@@ -213,6 +213,7 @@ void init_ali14xx (void)
ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
/* initialize controller registers */
if (!initRegisters()) {
diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c
index e833a2bd0..5ffbefaf0 100644
--- a/drivers/block/cmd640.c
+++ b/drivers/block/cmd640.c
@@ -797,6 +797,7 @@ int ide_probe_for_cmd640x (void)
cmd_hwif1->chipset = ide_cmd640;
cmd_hwif0->mate = cmd_hwif1;
cmd_hwif1->mate = cmd_hwif0;
+ cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c
index 30988bd99..63b9143b6 100644
--- a/drivers/block/dtc2278.c
+++ b/drivers/block/dtc2278.c
@@ -127,4 +127,5 @@ void init_dtc2278 (void)
ide_hwifs[1].drives[1].no_unmask = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}
diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c
index 9d888cfc0..b739f39ee 100644
--- a/drivers/block/ht6560b.c
+++ b/drivers/block/ht6560b.c
@@ -155,7 +155,6 @@ static void ht6560b_selectproc (ide_drive_t *drive)
printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing);
#endif
}
- OUT_BYTE(drive->select.all,IDE_SELECT_REG);
}
/*
@@ -229,6 +228,7 @@ void init_ht6560b (void)
ide_hwifs[1].serialized = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
} else
printk("\nht6560b: not found\n");
}
diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c
index 02f97ec6f..3a8e48722 100644
--- a/drivers/block/ide-cd.c
+++ b/drivers/block/ide-cd.c
@@ -2,7 +2,7 @@
/*
* linux/drivers/block/ide-cd.c
* Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996, 1997 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
@@ -27,13 +27,6 @@
* unless you have a patch to fix it. I am working on it...)
* -Implement ide_cdrom_select_speed using the generic cdrom interface
* -Fix ide_cdrom_reset so that it works (it does nothing right now)
- * -When trying to mount a cdrom with the tray open, you get an billion
- * "tray open or drive not ready" messages until the tray gets closed.
- * This is because ide-cd does not properly return drive_status immediatly,
- * but instead waits for the drive to close first (bad, bad, bad)
- * and keeps on trying, and failing... This bug was revealed by the
- * recent changes to the Uniform CD-ROm driver, and I havn't had a
- * chance to fix it yet.
*
* MOSTLY DONE LIST:
* Query the drive to find what features are available
@@ -185,8 +178,13 @@
* Added identifier so new Sanyo CD-changer works
* Better detection if door locking isn't supported
*
+ * 4.06 Dec 17, 1997 -- fixed endless "tray open" messages -ml
+ * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open"
+ *
*************************************************************************/
+#define IDECD_VERSION "4.07"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -194,11 +192,8 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/malloc.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/cdrom.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -418,7 +413,8 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive)
(struct packet_command *)
pc->sense_data);
}
-
+ if (rq->cmd == READ && !rq->current_nr_sectors)
+ uptodate = 1;
ide_end_request (uptodate, HWGROUP(drive));
}
@@ -443,7 +439,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
sense_key = err >> 4;
if (rq == NULL)
- printk ("%s : missing request in cdrom_decode_status\n",
+ printk ("%s: missing request in cdrom_decode_status\n",
drive->name);
else {
cmd = rq->cmd;
@@ -477,16 +473,13 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
because workman constantly polls the drive
with this command, and we don't want
to uselessly fill up the syslog. */
- if (pc->c[0] != SCMD_READ_SUBCHANNEL) {
+ if (pc->c[0] != SCMD_READ_SUBCHANNEL)
printk ("%s: tray open or drive not ready\n",
drive->name);
- return 1;
- }
} else if (sense_key == UNIT_ATTENTION) {
/* Check for media change. */
cdrom_saw_media_change (drive);
- printk (" %s: media changed\n", drive->name);
- return 0;
+ printk ("%s: media changed\n", drive->name);
} else {
/* Otherwise, print an error. */
ide_dump_status (drive, "packet command error",
@@ -521,7 +514,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
cdrom_saw_media_change (drive);
/* Fail the request. */
- printk ("%s : tray open\n", drive->name);
+ printk ("%s: tray open\n", drive->name);
cdrom_end_request (0, drive);
} else if (sense_key == UNIT_ATTENTION) {
/* Media change. */
@@ -591,7 +584,6 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
if (info->dma)
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
ide_set_handler (drive, handler, WAIT_CMD);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
@@ -619,7 +611,8 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive,
int stat_dum;
/* Check for errors. */
- if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;
+ if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))
+ return 1;
} else {
/* Otherwise, we must wait for DRQ to get set. */
if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
@@ -746,12 +739,12 @@ static void cdrom_read_intr (ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive)))
+ if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
HWIF(drive)->dmaproc(ide_dma_off, drive);
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
}
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
if (dma) {
if (!dma_error) {
@@ -764,7 +757,6 @@ static void cdrom_read_intr (ide_drive_t *drive)
return;
}
-
/* Read the interrupt reason and the transfer length. */
ireason = IN_BYTE (IDE_NSECTOR_REG);
len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
@@ -779,7 +771,6 @@ static void cdrom_read_intr (ide_drive_t *drive)
cdrom_end_request (0, drive);
} else
cdrom_end_request (1, drive);
-
return;
}
@@ -990,7 +981,8 @@ static void cdrom_seek_intr (ide_drive_t *drive)
int stat;
static int retry = 10;
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
CDROM_CONFIG_FLAGS(drive)->seeking = 1;
if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
@@ -1088,7 +1080,8 @@ static void cdrom_pc_intr (ide_drive_t *drive)
struct packet_command *pc = (struct packet_command *)rq->buffer;
/* Check for errors. */
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
/* Read the interrupt reason and the transfer length. */
ireason = IN_BYTE (IDE_NSECTOR_REG);
@@ -1251,8 +1244,11 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
ide_init_drive_cmd (&req);
req.cmd = PACKET_COMMAND;
req.buffer = (char *)pc;
- (void) ide_do_drive_cmd (drive, &req, ide_wait);
-
+ if (ide_do_drive_cmd (drive, &req, ide_wait)) {
+ printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",
+ drive->name, req.buffer[0], req.buffer[1]);
+ /* FIXME: we should probably abort/retry or something */
+ }
if (pc->stat != 0) {
/* The request failed. Retry if it was due to a unit
attention status
@@ -2692,7 +2688,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
static
int ide_cdrom_probe_capabilities (ide_drive_t *drive)
{
- int stat, nslots;
+ int stat, nslots, attempts = 3;
struct {
char pad[8];
struct atapi_capabilities_page cap;
@@ -2703,14 +2699,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
if (CDROM_CONFIG_FLAGS (drive)->nec260)
return nslots;
- stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
- (char *)&buf, sizeof (buf), NULL);
- if (stat)
- return nslots;
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ if (attempts-- <= 0)
+ return 0;
+ stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
+ (char *)&buf, sizeof (buf), NULL);
+ } while (stat);
if (buf.cap.lock == 0)
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-
if (buf.cap.cd_r_write)
CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
if (buf.cap.cd_rw_write)
@@ -2737,11 +2734,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
}
}
- CDROM_STATE_FLAGS (drive)->curent_speed = ntohs(buf.cap.curspeed)/176;
- CDROM_CONFIG_FLAGS (drive)->max_speed = ntohs(buf.cap.maxspeed)/176;
+ if (drive->id && drive->id->model[0]) {
+ CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+ } else { /* no-name ACERs (AOpen) have it backwards */
+ CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+ }
- stat=0;
- printk ("%s: ATAPI %dx CDROM",
+ printk ("%s: ATAPI %dX CDROM",
drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed);
if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw)
printk (" CD%s%s",
@@ -2827,7 +2828,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
else if (strcmp (drive->id->model,
"NEC CD-ROM DRIVE:260") == 0 &&
- strcmp (drive->id->fw_rev, "1.01") == 0) {
+ strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
/* Old NEC260 (not R).
This drive was released before the 1.2 version
of the spec. */
@@ -2838,7 +2839,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
}
else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
- strcmp (drive->id->fw_rev, "A1.1") == 0) {
+ strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
/* Wearnes */
CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
@@ -2936,21 +2937,23 @@ static ide_module_t ide_cdrom_module = {
};
static ide_driver_t ide_cdrom_driver = {
+ "ide-cdrom", /* name */
+ IDECD_VERSION, /* version */
ide_cdrom, /* media */
0, /* busy */
1, /* supports_dma */
1, /* supports_dsc_overlap */
ide_cdrom_cleanup, /* cleanup */
ide_do_rw_cdrom, /* do_request */
- NULL, /* ??? or perhaps
- cdrom_end_request? */
+ NULL, /* ??? or perhaps cdrom_end_request? */
ide_cdrom_ioctl, /* ioctl */
ide_cdrom_open, /* open */
ide_cdrom_release, /* release */
ide_cdrom_check_media_change, /* media_change */
NULL, /* pre_reset */
NULL, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h
index afb3e5dbe..53e38e1b1 100644
--- a/drivers/block/ide-cd.h
+++ b/drivers/block/ide-cd.h
@@ -119,11 +119,11 @@ struct ide_cd_config_flags {
__u8 cd_rw : 1; /* Drive can write to CD-R/W media . */
__u8 supp_disc_present: 1; /* Changer can report exact contents
of slots. */
- __u8 max_speed : 4; /* Max speed of the drive */
__u8 seeking : 1; /* Seeking in progress */
__u8 reserved : 6;
+ byte max_speed; /* Max speed of the drive */
};
-#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_cyl))
+#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
/* State flags. These give information about the current state of the
@@ -133,10 +133,10 @@ struct ide_cd_state_flags {
__u8 toc_valid : 1; /* Saved TOC information is current. */
__u8 door_locked : 1; /* We think that the drive door is locked. */
__u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */
- __u8 curent_speed : 4; /* Current speed of the drive */
__u8 reserved : 3;
+ byte current_speed; /* Current speed of the drive */
};
-#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head))
+#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
struct atapi_request_sense {
@@ -385,6 +385,8 @@ struct cdrom_info {
/* Buffer to hold mechanism status and changer slot table. */
struct atapi_changer_info *changer_info;
+ struct ide_cd_config_flags config_flags;
+ struct ide_cd_state_flags state_flags;
/* Per-device info needed by cdrom.c generic driver. */
struct cdrom_device_info devinfo;
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index f75a1a5be..5e178b6cd 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -10,32 +10,6 @@
*
* This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
*
- * From hd.c:
- * |
- * | It traverses the request-list, using interrupts to jump between functions.
- * | As nearly all functions can be called within interrupts, we may not sleep.
- * | Special care is recommended. Have Fun!
- * |
- * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- * |
- * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- * | in the early extended-partition checks and added DM partitions.
- * |
- * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- * |
- * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- * | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
- * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2")
- * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
- *
- * This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
- * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
* Version 1.00 move disk only code from ide.c to ide-disk.c
* support optional byte-swapping of all data
* Version 1.01 fix previous byte-swapping code
@@ -43,6 +17,8 @@
* Verions 1.03 fix display of id->buf_size for big-endian
*/
+#define IDEDISK_VERSION "1.03"
+
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/config.h>
@@ -52,12 +28,9 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/delay.h>
@@ -319,7 +292,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl
OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
#ifdef CONFIG_BLK_DEV_PDC4030
if (IS_PDC4030_DRIVE) {
- if (hwif->is_pdc4030_2 || rq->cmd == READ) {
+ if (hwif->channel != 0 || rq->cmd == READ) {
use_pdc4030_io = 1;
}
}
@@ -494,6 +467,11 @@ static void idedisk_pre_reset (ide_drive_t *drive)
drive->special.b.set_multmode = 1;
}
+static ide_proc_entry_t idedisk_proc[] = {
+ { "geometry", proc_ide_read_geometry, NULL },
+ { NULL, NULL, NULL }
+};
+
int idedisk_init (void);
static ide_module_t idedisk_module = {
IDE_DRIVER_MODULE,
@@ -505,6 +483,8 @@ static ide_module_t idedisk_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idedisk_driver = {
+ "ide-disk", /* name */
+ IDEDISK_VERSION, /* version */
ide_disk, /* media */
0, /* busy */
1, /* supports_dma */
@@ -518,7 +498,8 @@ static ide_driver_t idedisk_driver = {
idedisk_media_change, /* media_change */
idedisk_pre_reset, /* pre_reset */
idedisk_capacity, /* capacity */
- idedisk_special /* special */
+ idedisk_special, /* special */
+ idedisk_proc /* proc */
};
static int idedisk_cleanup (ide_drive_t *drive)
@@ -526,20 +507,6 @@ static int idedisk_cleanup (ide_drive_t *drive)
return ide_unregister_subdriver(drive);
}
-static int idedisk_identify_device (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
-
- if (id == NULL)
- return 0;
-
- /* SunDisk drives: force one unit */
- if (id->model[0] == 'S' && id->model[1] == 'u' && (drive->select.all & (1<<4)))
- return 1;
-
- return 0;
-}
-
static void idedisk_setup (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -554,7 +521,7 @@ static void idedisk_setup (ide_drive_t *drive)
drive->removable = 1;
}
- /* SunDisk drives: treat as non-removable */
+ /* SunDisk drives: treat as non-removable; can mess up non-Sun systems! FIXME */
if (id->model[0] == 'S' && id->model[1] == 'u')
drive->removable = 0;
@@ -634,8 +601,12 @@ int idedisk_init (void)
MOD_INC_USE_COUNT;
while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) {
- if (idedisk_identify_device (drive))
+
+ /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */
+ struct hd_driveid *id = drive->id;
+ if (id && id->model[0] == 'S' && id->model[1] == 'u' && drive->select.b.unit)
continue;
+
if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
continue;
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index 6a2886f78..bba735580 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-dma.c Version 4.06 December 3, 1997
+ * linux/drivers/block/ide-dma.c Version 4.07 December 5, 1997
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -49,9 +49,8 @@
* available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
* (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
*
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for fixing the
- * problem with some (all?) ACER motherboards/BIOSs. Hopefully the fix
- * still works here (?).
+ * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
+ * fixing the problem with the BIOS on some Acer motherboards.
*
* Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
* "TX" chipset compatibility and for providing patches for the "TX" chipset.
@@ -69,16 +68,12 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/bios32.h>
-#include <linux/init.h>
#include <asm/io.h>
-#include <asm/dma.h>
+#include <asm/irq.h>
#include "ide.h"
@@ -110,23 +105,19 @@ const char *good_dma_drives[] = {"Micropolis 2112A",
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
-static int config_drive_for_dma (ide_drive_t *);
-
/*
* dma_intr() is the handler for disk read/write DMA interrupts
*/
-static void dma_intr (ide_drive_t *drive)
+void ide_dma_intr (ide_drive_t *drive)
{
- byte stat, dma_stat;
int i;
- struct request *rq = HWGROUP(drive)->rq;
- unsigned short dma_base = HWIF(drive)->dma_base;
+ byte stat, dma_stat;
- dma_stat = inb(dma_base+2); /* get DMA status */
- outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */
+ dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
- if ((dma_stat & 7) == 4) { /* verify good DMA status */
+ if (!dma_stat) {
+ struct request *rq = HWGROUP(drive)->rq;
rq = HWGROUP(drive)->rq;
for (i = rq->nr_sectors; i > 0;) {
i -= rq->current_nr_sectors;
@@ -134,7 +125,7 @@ static void dma_intr (ide_drive_t *drive)
}
return;
}
- printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat);
+ printk("%s: dma_intr: bad DMA status\n", drive->name);
}
sti();
ide_error(drive, "dma_intr", stat);
@@ -195,23 +186,46 @@ int ide_build_dmatable (ide_drive_t *drive)
unsigned long xcount, bcount = 0x10000 - (addr & 0xffff);
if (bcount > size)
bcount = size;
- *table++ = addr;
+ *table++ = cpu_to_le32(addr);
xcount = bcount & 0xffff;
if (is_trm290_chipset)
xcount = ((xcount >> 2) - 1) << 16;
- *table++ = xcount;
+ *table++ = cpu_to_le32(xcount);
addr += bcount;
size -= bcount;
}
}
} while (bh != NULL);
- if (count) {
- if (!is_trm290_chipset)
- *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */
- return count;
+ if (!count)
+ printk("%s: empty DMA table?\n", drive->name);
+ else if (!is_trm290_chipset)
+ *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */
+ return count;
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ const char **list;
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) {
+ /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+ if (id->field_valid & 4) /* UltraDMA */
+ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
+ return hwif->dmaproc(ide_dma_on, drive);
+ /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+ if (id->field_valid & 2) /* regular DMA */
+ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+ return hwif->dmaproc(ide_dma_on, drive);
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model))
+ return hwif->dmaproc(ide_dma_on, drive);
+ }
}
- printk("%s: empty DMA table?\n", drive->name);
- return 0;
+ return hwif->dmaproc(ide_dma_off_quietly, drive);
}
/*
@@ -233,7 +247,7 @@ int ide_build_dmatable (ide_drive_t *drive)
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned long dma_base = hwif->dma_base;
+ unsigned int dma_base = hwif->dma_base;
unsigned int count, reading = 0;
switch (func) {
@@ -243,21 +257,8 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_on:
drive->using_dma = (func == ide_dma_on);
return 0;
- case ide_dma_abort:
- outb(inb(dma_base)&~1, dma_base); /* stop DMA */
- return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
- case ide_dma_status_bad:
- return ((inb(dma_base+2) & 7) != 4); /* verify good DMA status */
- case ide_dma_transferred:
- return 0; /* NOT IMPLEMENTED: number of bytes actually transferred */
- case ide_dma_begin:
- outb(inb(dma_base)|1, dma_base); /* begin DMA */
- return 0;
- default:
- printk("ide_dmaproc: unsupported func: %d\n", func);
- return 1;
case ide_dma_read:
reading = 1 << 3;
case ide_dma_write:
@@ -268,50 +269,37 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
- outb(inb(dma_base)|1, dma_base); /* begin DMA */
+ case ide_dma_begin:
+ outb(inb(dma_base)|1, dma_base); /* start DMA */
return 0;
- }
-}
-
-static int config_drive_for_dma (ide_drive_t *drive)
-{
- const char **list;
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
-
- if (id && (id->capability & 1)) {
- /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
- if (id->field_valid & 4) /* UltraDMA */
- if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
- return hwif->dmaproc(ide_dma_on, drive);
- /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
- if (id->field_valid & 2) /* regular DMA */
- if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
- return hwif->dmaproc(ide_dma_on, drive);
- /* Consult the list of known "good" drives */
- list = good_dma_drives;
- while (*list) {
- if (!strcmp(*list++,id->model))
- return hwif->dmaproc(ide_dma_on, drive);
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ {
+ byte dma_stat = inb(dma_base+2);
+ int rc = (dma_stat & 7) != 4;
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA */
+ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
+ return rc; /* verify good DMA status */
}
+ default:
+ printk("ide_dmaproc: unsupported func: %d\n", func);
+ return 1;
}
- return hwif->dmaproc(ide_dma_off_quietly, drive);
}
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports)
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dma_base, unsigned int num_ports) /* __init */
{
static unsigned long dmatable = 0;
static unsigned leftover = 0;
- printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase + num_ports - 1);
- if (check_region(dmabase, num_ports)) {
+ printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dma_base, dma_base + num_ports - 1);
+ if (check_region(dma_base, num_ports)) {
printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
return;
}
- request_region(dmabase, num_ports, hwif->name);
- hwif->dma_base = dmabase;
+ request_region(dma_base, num_ports, hwif->name);
+ hwif->dma_base = dma_base;
if (leftover < (PRD_ENTRIES * PRD_BYTES)) {
/*
* The BM-DMA uses full 32bit addr, so we can
@@ -328,87 +316,18 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_p
dmatable += (PRD_ENTRIES * PRD_BYTES);
leftover -= (PRD_ENTRIES * PRD_BYTES);
hwif->dmaproc = &ide_dmaproc;
+
if (hwif->chipset != ide_trm290) {
- byte dma_stat = inb(dmabase+2);
- printk(", BIOS DMA settings: %s:%s %s:%s",
- hwif->drives[0].name, (dma_stat & 0x20) ? "yes" : "no ",
- hwif->drives[1].name, (dma_stat & 0x40) ? "yes" : "no");
+ byte dma_stat = inb(dma_base+2);
+ printk(", BIOS settings: %s:%s, %s:%s",
+ hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+ hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
}
printk("\n");
}
}
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(byte, byte, ide_hwif_t *);
-#define INIT_TRM290 (&ide_init_trm290)
-#else
-#define INIT_TRM290 (NULL)
-#endif /* CONFIG_BLK_DEV_TRM290 */
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(byte, byte, ide_hwif_t *);
-#define INIT_OPTI (&ide_init_opti621)
-#else
-#define INIT_OPTI (NULL)
-#endif /* CONFIG_BLK_DEV_OPTI621 */
-
-#define DEVID_PIIX (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371_1 <<16))
-#define DEVID_PIIX3 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371SB_1 <<16))
-#define DEVID_PIIX4 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371AB <<16))
-#define DEVID_VP_IDE (PCI_VENDOR_ID_VIA |(PCI_DEVICE_ID_VIA_82C586_1 <<16))
-#define DEVID_PDC20246 (PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246 <<16))
-#define DEVID_RZ1000 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1000 <<16))
-#define DEVID_RZ1001 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1001 <<16))
-#define DEVID_CMD640 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_640 <<16))
-#define DEVID_CMD646 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_646 <<16))
-#define DEVID_SIS5513 (PCI_VENDOR_ID_SI |(PCI_DEVICE_ID_SI_5513 <<16))
-#define DEVID_OPTI (PCI_VENDOR_ID_OPTI |(PCI_DEVICE_ID_OPTI_82C621 <<16))
-#define DEVID_OPTI2 (PCI_VENDOR_ID_OPTI |(0xd568 /* from datasheets */ <<16))
-#define DEVID_TRM290 (PCI_VENDOR_ID_TEKRAM |(PCI_DEVICE_ID_TEKRAM_DC290 <<16))
-#define DEVID_NS87410 (PCI_VENDOR_ID_NS |(PCI_DEVICE_ID_NS_87410 <<16))
-#define DEVID_HT6565 (PCI_VENDOR_ID_HOLTEK |(PCI_DEVICE_ID_HOLTEK_6565 <<16))
-
-typedef struct ide_pci_enablebit_s {
- byte reg; /* byte pci reg holding the enable-bit */
- byte mask; /* mask to isolate the enable-bit */
- byte val; /* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
- unsigned int id;
- const char *name;
- void (*init_hwif)(byte bus, byte fn, ide_hwif_t *hwif);
- ide_pci_enablebit_t enablebits[2];
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] = {
- {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
- {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
- {DEVID_RZ1000, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_RZ1001, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_CMD640, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_OPTI, "OPTI", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
- {DEVID_OPTI2, "OPTI2", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
- {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
- {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
- {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
- {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {0, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
-
-__initfunc(static ide_pci_device_t *lookup_devid(unsigned int devid))
-{
- ide_pci_device_t *d = ide_pci_chipsets;
- while (d->id && d->id != devid)
- ++d;
- return d;
-}
-
-/* The next two functions were stolen from cmd640.c, with
- a few modifications */
+/* The next two functions were stolen from cmd640.c, with a few modifications */
__initfunc(static void write_pcicfg_dword (byte fn, unsigned short reg, long val))
{
@@ -435,244 +354,50 @@ __initfunc(static long read_pcicfg_dword (byte fn, unsigned short reg))
}
/*
- * Search for an (apparently) unused block of I/O space
- * of "size" bytes in length.
- */
-__initfunc(static short find_free_region (unsigned short size))
-{
- unsigned short i, base = 0xe800;
- for (base = 0xe800; base > 0; base -= 0x800) {
- if (!check_region(base,size)) {
- for (i = 0; i < size; i++) {
- if (inb(base+i) != 0xff)
- goto next;
- }
- return base; /* success */
- }
- next:
- }
- return 0; /* failure */
-}
-
-/*
- * Fetch the Bus-Master I/O Base-Address (BMIBA) from PCI space:
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
*/
-__initfunc(static unsigned int ide_get_or_set_bmiba (byte bus, byte fn, const char *name))
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */
{
- unsigned int bmiba = 0;
- unsigned short base;
- int rc;
-
- if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba))) {
- printk("%s: failed to read BMIBA\n", name);
- } else if ((bmiba &= 0xfff0) == 0) {
- printk("%s: BMIBA is invalid (0x%04x, BIOS problem)\n", name, bmiba);
- base = find_free_region(16);
- if (base) {
- printk("%s: setting BMIBA to 0x%04x\n", name, base);
- pcibios_write_config_dword(bus, fn, 0x20, base | 1);
- pcibios_read_config_dword(bus, fn, 0x20, &bmiba);
- bmiba &= 0xfff0;
- if (bmiba != base) {
+ unsigned int new, dma_base = 0;
+ byte bus = hwif->pci_bus, fn = hwif->pci_fn;
+
+ if (hwif->mate && hwif->mate->dma_base) {
+ dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ } else if (pcibios_read_config_dword(bus, fn, 0x20, &dma_base)) {
+ printk("%s: failed to read dma_base\n", name);
+ dma_base = 0;
+ } else if ((dma_base &= ~0xf) == 0 || dma_base == ~0xf) {
+ printk("%s: dma_base is invalid (0x%04x, BIOS problem)\n", name, dma_base);
+ new = ide_find_free_region(16 + extra);
+ hwif->no_autodma = 1; /* default DMA off if we had to configure it here */
+ if (new) {
+ printk("%s: setting dma_base to 0x%04x\n", name, new);
+ new |= 1;
+ (void) pcibios_write_config_dword(bus, fn, 0x20, new);
+ (void) pcibios_read_config_dword(bus, fn, 0x20, &dma_base);
+ if (dma_base != new) {
if (bus == 0) {
printk("%s: operation failed, bypassing BIOS to try again\n", name);
- write_pcicfg_dword(fn, 0x20, base | 1);
- bmiba = read_pcicfg_dword(fn, 0x20) & 0xfff0;
+ write_pcicfg_dword(fn, 0x20, new);
+ dma_base = read_pcicfg_dword(fn, 0x20);
}
- if (bmiba != base) {
+ if (dma_base != new) {
printk("%s: operation failed, DMA disabled\n", name);
- bmiba = 0;
+ dma_base = 0;
}
}
+ dma_base &= ~0xf;
}
}
- return bmiba;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-__initfunc(ide_hwif_t *ide_match_hwif (unsigned int io_base))
-{
- int h;
- ide_hwif_t *hwif;
-
- /*
- * Look for a hwif with matching io_base specified using
- * parameters to ide_setup().
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
- if (hwif->chipset == ide_generic)
- return hwif; /* a perfect match */
- }
- }
- /*
- * Look for a hwif with matching io_base default value.
- * If chipset is "ide_unknown", then claim that hwif slot.
- * Otherwise, some other chipset has already claimed it.. :(
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
- if (hwif->chipset == ide_unknown)
- return hwif; /* match */
- return NULL; /* already claimed */
- }
- }
- /*
- * Okay, there is no hwif matching our io_base,
- * so we'll just claim an unassigned slot.
- * Give preference to claiming ide2/ide3 before ide0/ide1,
- * just in case there's another interface yet-to-be-scanned
- * which uses ports 1f0/170 (the ide0/ide1 defaults).
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
- hwif = &ide_hwifs[hwifs[h]];
- if (hwif->chipset == ide_unknown)
- return hwif; /* pick an unused entry */
- }
- return NULL;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them. This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits. For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int bmiba, ide_pci_device_t *d))
-{
- unsigned int port, at_least_one_hwif_enabled = 0;
- unsigned short base = 0, ctl = 0;
- byte tmp = 0;
- ide_hwif_t *hwif, *mate = NULL;
-
- for (port = 0; port <= 1; ++port) {
- ide_pci_enablebit_t *e = &(d->enablebits[port]);
- if (e->reg) {
- if (pcibios_read_config_byte(bus, fn, e->reg, &tmp)) {
- printk("%s: unable to read pci reg 0x%x\n", d->name, e->reg);
- } else if ((tmp & e->mask) != e->val)
- continue; /* port not enabled */
- }
- if (pcibios_read_config_word(bus, fn, 0x14+(port*8), &ctl))
- ctl = 0;
- if ((ctl &= 0xfffc) == 0)
- ctl = 0x3f4 ^ (port << 7);
- if (pcibios_read_config_word(bus, fn, 0x10+(port*8), &base))
- base = 0;
- if ((base &= 0xfff8) == 0)
- base = 0x1F0 ^ (port << 7);
- if ((hwif = ide_match_hwif(base)) == NULL) {
- printk("%s: no room in hwif table for port %d\n", d->name, port);
- continue;
- }
- hwif->chipset = ide_pci;
- hwif->pci_port = port;
- if (mate) {
- hwif->mate = mate;
- mate->mate = hwif;
- }
- mate = hwif; /* for next iteration */
- if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
- ide_init_hwif_ports(hwif->io_ports, base, NULL);
- hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
- }
- if (bmiba) {
- if ((inb(bmiba+2) & 0x80)) { /* simplex DMA only? */
- printk("%s: simplex device: DMA disabled\n", d->name);
- } else { /* supports simultaneous DMA on both channels */
- ide_setup_dma(hwif, bmiba + (8 * port), 8);
- }
- }
- if (d->id) { /* For "known" chipsets, allow other irqs during i/o */
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
- }
- if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
- d->init_hwif(bus, fn, hwif);
- at_least_one_hwif_enabled = 1;
- }
- if (!at_least_one_hwif_enabled)
- printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-/*
- * ide_scan_pci_device() examines all functions of a PCI device,
- * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
- */
-__initfunc(static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn))
-{
- unsigned int devid, ccode;
- unsigned short pcicmd, class;
- ide_pci_device_t *d;
- byte hedt, progif;
-
- if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
- hedt = 0;
- do {
- if (pcibios_read_config_dword(bus, fn, 0x00, &devid)
- || devid == 0xffffffff
- || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
- return;
- d = lookup_devid(devid);
- if (d->name == NULL) /* some chips (cmd640, rz1000) are handled elsewhere */
- continue;
- progif = (ccode >> 8) & 0xff;
- class = ccode >> 16;
- if (d->id || class == PCI_CLASS_STORAGE_IDE) {
- if (d->id)
- printk("%s: IDE device on PCI bus %d function %d\n", d->name, bus, fn);
- else
- printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
- d->name, bus, fn, devid & 0xffff, devid >> 16);
- /*
- * See if IDE ports are enabled
- */
- if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) {
- printk("%s: error accessing PCICMD\n", d->name);
- } else if ((pcicmd & 1) == 0) {
- printk("%s: device disabled (BIOS)\n", d->name);
- } else {
- unsigned int bmiba = 0;
- /*
- * Check for Bus-Master DMA capability
- */
- if (d->id == DEVID_PDC20246 || (class == PCI_CLASS_STORAGE_IDE && (progif & 0x80))) {
- if ((!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name)))) {
- printk("%s: Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, progif=0x%02x, bmiba=0x%04x\n", d->name, pcicmd, progif, bmiba);
- }
- }
- /*
- * Setup the IDE ports
- */
- ide_setup_pci_device(bus, fn, bmiba, d);
- }
- }
- } while (hedt == 0x80 && (++fn & 7));
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c
- */
-__initfunc(void ide_scan_pcibus (void))
-{
- unsigned int bus, dev;
-
- if (!pcibios_present())
- return;
- for (bus = 0; bus <= 255; ++bus) {
- for (dev = 0; dev <= 31; ++dev) {
- ide_scan_pci_device(bus, dev << 3);
+ if (dma_base) {
+ if (extra) /* PDC20246 */
+ request_region(dma_base+16, extra, name);
+ dma_base += hwif->channel ? 8 : 0;
+ if (inb(dma_base+2) & 0x80) {
+ printk("%s: simplex device: DMA disabled\n", name);
+ dma_base = 0;
}
}
+ return dma_base;
}
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index 2856f330f..5572a07ba 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-floppy.c Version 0.5 - ALPHA Feb 21, 1997
+ * linux/drivers/block/ide-floppy.c Version 0.8 Feb 21, 1997
*
* Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -21,8 +21,15 @@
* Use the minimum of the LBA and CHS capacities.
* Avoid hwgroup->rq == NULL on the last irq.
* Fix potential null dereferencing with DEBUG_LOG.
+ * Ver 0.8 Dec 7 97 Increase irq timeout from 10 to 50 seconds.
+ * Add media write-protect detection.
+ * Issue START command only if TEST UNIT READY fails.
+ * Add work-around for IOMEGA ZIP revision 21.D.
+ * Remove idefloppy_get_capabilities().
*/
+#define IDEFLOPPY_VERSION "0.8"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -31,12 +38,9 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
@@ -60,6 +64,11 @@
#define IDEFLOPPY_DEBUG_BUGS 1
/*
+ * Some drives require a longer irq timeout.
+ */
+#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD)
+
+/*
* After each failed packet command we issue a request sense command
* and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times.
*/
@@ -191,6 +200,7 @@ typedef struct {
int blocks, block_size, bs_factor; /* Current format */
idefloppy_capacity_descriptor_t capacity; /* Last format capacity */
idefloppy_flexible_disk_page_t flexible_disk_page; /* Copy of the flexible disk page */
+ int wp; /* Write protect */
unsigned int flags; /* Status/Action flags */
} idefloppy_floppy_t;
@@ -683,13 +693,12 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
+ if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
idefloppy_update_buffers (drive, pc);
}
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */
#if IDEFLOPPY_DEBUG_LOG
printk (KERN_INFO "ide-floppy: DMA finished\n");
#endif /* IDEFLOPPY_DEBUG_LOG */
@@ -728,8 +737,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
- printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
ide_do_reset (drive);
return;
}
@@ -755,7 +763,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
idefloppy_discard_data (drive,bcount.all);
- ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD);
+ ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
return;
}
#if IDEFLOPPY_DEBUG_LOG
@@ -777,7 +785,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD); /* And set the interrupt handler again */
+ ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */
}
static void idefloppy_transfer_pc (ide_drive_t *drive)
@@ -795,7 +803,7 @@ static void idefloppy_transfer_pc (ide_drive_t *drive)
ide_do_reset (drive);
return;
}
- ide_set_handler (drive, &idefloppy_pc_intr, WAIT_CMD); /* Set the interrupt routine */
+ ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */
atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
}
@@ -843,8 +851,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
- printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -864,7 +871,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
- ide_set_handler (drive, &idefloppy_transfer_pc, WAIT_CMD);
+ ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -934,6 +941,12 @@ static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
pc->c[4] = start;
}
+static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+}
+
static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
{
int block = sector / floppy->bs_factor;
@@ -1041,6 +1054,7 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
return 1;
}
header = (idefloppy_mode_parameter_header_t *) pc.buffer;
+ floppy->wp = header->wp;
page = (idefloppy_flexible_disk_page_t *) (header + 1);
page->transfer_rate = ntohs (page->transfer_rate);
@@ -1144,13 +1158,21 @@ static int idefloppy_open (struct inode *inode, struct file *filp, ide_drive_t *
MOD_INC_USE_COUNT;
if (drive->usage == 1) {
- idefloppy_create_start_stop_cmd (&pc, 1);
- (void) idefloppy_queue_pc_tail (drive, &pc);
+ idefloppy_create_test_unit_ready_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ idefloppy_create_start_stop_cmd (&pc, 1);
+ (void) idefloppy_queue_pc_tail (drive, &pc);
+ }
if (idefloppy_get_capacity (drive)) {
drive->usage--;
MOD_DEC_USE_COUNT;
return -EIO;
}
+ if (floppy->wp && (filp->f_mode & 2)) {
+ drive->usage--;
+ MOD_DEC_USE_COUNT;
+ return -EROFS;
+ }
set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
idefloppy_create_prevent_cmd (&pc, 1);
(void) idefloppy_queue_pc_tail (drive, &pc);
@@ -1243,9 +1265,9 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
default: sprintf (buffer, "Reserved");break;
}
printk (KERN_INFO "Command Packet Size: %s\n", buffer);
- printk (KERN_INFO "Model: %s\n",id->model);
- printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
- printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+ printk (KERN_INFO "Model: %.40s\n",id->model);
+ printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+ printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -1306,51 +1328,13 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
}
/*
- * idefloppy_get_capabilities asks the floppy about its various
- * parameters.
- */
-static void idefloppy_get_capabilities (ide_drive_t *drive)
-{
- idefloppy_pc_t pc;
- idefloppy_mode_parameter_header_t *header;
- idefloppy_capabilities_page_t *capabilities;
-
- idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE, MODE_SENSE_CURRENT);
- if (idefloppy_queue_pc_tail (drive,&pc)) {
- printk (KERN_ERR "ide-floppy: Can't get drive capabilities\n");
- return;
- }
- header = (idefloppy_mode_parameter_header_t *) pc.buffer;
- capabilities = (idefloppy_capabilities_page_t *) (header + 1);
-
- if (!capabilities->sflp)
- printk (KERN_INFO "%s: Warning - system floppy device bit is not set\n", drive->name);
-
-#if IDEFLOPPY_DEBUG_INFO
- printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
- printk (KERN_INFO "Mode Parameter Header:\n");
- printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
- printk (KERN_INFO "Medium Type - %d\n",header->medium_type);
- printk (KERN_INFO "WP - %d\n",header->wp);
-
- printk (KERN_INFO "Capabilities Page:\n");
- printk (KERN_INFO "Page code - %d\n",capabilities->page_code);
- printk (KERN_INFO "Page length - %d\n",capabilities->page_length);
- printk (KERN_INFO "PS - %d\n",capabilities->ps);
- printk (KERN_INFO "System Floppy Type device - %s\n",capabilities->sflp ? "Yes":"No");
- printk (KERN_INFO "Supports Reporting progress of Format - %s\n",capabilities->srfp ? "Yes":"No");
- printk (KERN_INFO "Non CD Optical device - %s\n",capabilities->ncd ? "Yes":"No");
- printk (KERN_INFO "Multiple LUN support - %s\n",capabilities->sml ? "Yes":"No");
- printk (KERN_INFO "Total LUN supported - %s\n",capabilities->tlun ? "Yes":"No");
-#endif /* IDEFLOPPY_DEBUG_INFO */
-}
-
-/*
* Driver initialization.
*/
static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
{
struct idefloppy_id_gcw gcw;
+ int major = HWIF(drive)->major, i;
+ int minor = drive->select.b.unit << PARTN_BITS;
*((unsigned short *) &gcw) = drive->id->config;
drive->driver_data = floppy;
@@ -1360,8 +1344,12 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
floppy->pc = floppy->pc_stack;
if (gcw.drq_type == 1)
set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+ if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 &&
+ strcmp(drive->id->fw_rev, "21.D") == 0) {
+ for (i = 0; i < 1 << PARTN_BITS; i++)
+ max_sectors[major][minor + i] = 64;
+ }
- idefloppy_get_capabilities (drive);
(void) idefloppy_get_capacity (drive);
}
@@ -1387,6 +1375,8 @@ static ide_module_t idefloppy_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idefloppy_driver = {
+ "ide-floppy", /* name */
+ IDEFLOPPY_VERSION, /* version */
ide_floppy, /* media */
0, /* busy */
1, /* supports_dma */
@@ -1400,7 +1390,8 @@ static ide_driver_t idefloppy_driver = {
idefloppy_media_change, /* media_change */
NULL, /* pre_reset */
idefloppy_capacity, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
/*
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
new file mode 100644
index 000000000..adcf99525
--- /dev/null
+++ b/drivers/block/ide-pci.c
@@ -0,0 +1,382 @@
+/*
+ * linux/drivers/block/ide-pci.c Version 1.00 December 8, 1997
+ *
+ * Copyright (c) 1995-1998 Mark Lord
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This modules provides support for automatic detection and
+ * configuration of all PCI IDE interfaces present in a system.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide.h"
+
+#define DEVID_PIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1})
+#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1})
+#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
+#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+#define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000})
+#define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640})
+#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646})
+#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513})
+#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621})
+#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558})
+#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, 0xd568}) /* from datasheets */
+#define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290})
+#define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410})
+#define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415})
+#define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565})
+
+#define IDE_IGNORE ((void *)-1)
+
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290 &ide_init_trm290
+#else
+#define INIT_TRM290 IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void ide_init_opti621(ide_hwif_t *);
+#define INIT_OPTI621 &ide_init_opti621
+#else
+#define INIT_OPTI621 NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_NS87415
+extern void ide_init_ns87415(ide_hwif_t *);
+#define INIT_NS87415 &ide_init_ns87415
+#else
+#define INIT_NS87415 IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_init_rz1000(ide_hwif_t *);
+#define INIT_RZ1000 &ide_init_rz1000
+#else
+#define INIT_RZ1000 IDE_IGNORE
+#endif
+
+typedef struct ide_pci_enablebit_s {
+ byte reg; /* byte pci reg holding the enable-bit */
+ byte mask; /* mask to isolate the enable-bit */
+ byte val; /* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+ ide_pci_devid_t devid;
+ const char *name;
+ void (*init_hwif)(ide_hwif_t *hwif);
+ ide_pci_enablebit_t enablebits[2];
+} ide_pci_device_t;
+
+static ide_pci_device_t ide_pci_chipsets[] __initdata = {
+ {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
+ {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
+ {DEVID_RZ1000, "RZ1000", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_RZ1001, "RZ1001", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_CMD640, "CMD640", IDE_IGNORE, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
+ {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
+ {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
+ {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_OPTI621, "OPTI621", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+ {DEVID_OPTI621X,"OPTI621X", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+ {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
+
+/*
+ * Search for an (apparently) unused block of I/O space
+ * of "size" bytes in length. Ideally we ought to do a pass
+ * through pcicfg space to eliminate ports already allocated
+ * by the BIOS, to avoid conflicts later in the init cycle,
+ * but we don't. FIXME
+ */
+unsigned int ide_find_free_region (unsigned short size) /* __init */
+{
+ static unsigned short base = 0x5800; /* it works for me */
+ unsigned short i;
+
+ for (; base > 0; base -= 0x200) {
+ if (!check_region(base,size)) {
+ for (i = 0; i < size; i++) {
+ if (inb(base+i) != 0xff)
+ goto next;
+ }
+ return base; /* success */
+ }
+ next:
+ }
+ return 0; /* failure */
+}
+
+/*
+ * Match a PCI IDE port against an entry in ide_hwifs[],
+ * based on io_base port if possible.
+ */
+__initfunc(static ide_hwif_t *ide_match_hwif (unsigned int io_base, const char *name))
+{
+ int h;
+ ide_hwif_t *hwif;
+
+ /*
+ * Look for a hwif with matching io_base specified using
+ * parameters to ide_setup().
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_generic)
+ return hwif; /* a perfect match */
+ }
+ }
+ /*
+ * Look for a hwif with matching io_base default value.
+ * If chipset is "ide_unknown", then claim that hwif slot.
+ * Otherwise, some other chipset has already claimed it.. :(
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* match */
+ printk("%s: port 0x%04x already claimed by %s\n", name, io_base, hwif->name);
+ return NULL; /* already claimed */
+ }
+ }
+ /*
+ * Okay, there is no hwif matching our io_base,
+ * so we'll just claim an unassigned slot.
+ * Give preference to claiming other slots before claiming ide0/ide1,
+ * just in case there's another interface yet-to-be-scanned
+ * which uses ports 1f0/170 (the ide0/ide1 defaults).
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
+ hwif = &ide_hwifs[hwifs[h]];
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+ }
+ printk("%s: too many IDE interfaces, no room in table\n", name);
+ return NULL;
+}
+
+__initfunc(static int ide_setup_pci_baseregs (byte bus, byte fn, const char *name))
+{
+ unsigned int base, readback;
+ byte reg, progif = 0;
+
+ /*
+ * Place both IDE interfaces into PCI "native" mode:
+ */
+ if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+ if ((progif & 0xa) != 0xa) {
+ printk("%s: device not capable of full native PCI mode\n", name);
+ return 1;
+ }
+ printk("%s: placing both ports into native PCI mode\n", name);
+ (void) pcibios_write_config_byte(bus, fn, 0x09, progif|5);
+ if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+ printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
+ return 1;
+ }
+ }
+ /*
+ * Setup base registers for IDE command/control spaces for each interface:
+ */
+ if (!(base = ide_find_free_region(32)))
+ return 1;
+ for (reg = 0x10; reg <= 0x1c; reg += 4, base += 8) {
+ (void) pcibios_write_config_dword(bus, fn, reg, base|1);
+ if (pcibios_read_config_dword(bus, fn, reg, &readback) || (readback &= ~1) != base) {
+ printk("%s: readback failed for basereg 0x%02x: wrote 0x%04x, read 0x%x04\n", name, reg, base, readback);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them. This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits. For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int ccode, ide_pci_device_t *d))
+{
+ unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0;
+ unsigned short pcicmd = 0;
+ byte tmp = 0, progif = 0, pciirq = 0;
+ ide_hwif_t *hwif, *mate = NULL;
+
+ if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+ || pcibios_read_config_byte(bus, fn, 0x09, &progif)
+ || pcibios_read_config_byte(bus, fn, 0x3c, &pciirq))
+ {
+ printk("%s: error accessing PCI regs\n", d->name);
+ return;
+ }
+ if (!(pcicmd & 1)) { /* is device disabled? */
+ /*
+ * PnP BIOS was *supposed* to have set this device up for us,
+ * but we can do it ourselves, so long as the BIOS has assigned an IRQ
+ * (or possibly the device is using a "legacy header" for IRQs).
+ * Maybe the user deliberately *disabled* the device,
+ * but we'll eventually ignore it again if no drives respond.
+ */
+ if (ide_setup_pci_baseregs(bus, fn, d->name)
+ || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1)
+ || pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+ || !(pcicmd & 1))
+ {
+ printk("%s: device disabled (BIOS)\n", d->name);
+ return;
+ }
+ no_autodma = 1; /* default DMA off if we had to configure it here */
+ printk("%s: device enabled (Linux)\n", d->name);
+ }
+ if (!pciirq || pciirq >= NR_IRQS) { /* is pciirq invalid? */
+ if (pciirq || (progif & 0x5)) /* don't complain if using "legacy" mode */
+ printk("%s: BIOS returned %d for IRQ (ignored)\n", d->name, pciirq);
+ pciirq = 0; /* probe for it instead */
+ }
+ /*
+ * Set up the IDE ports
+ */
+ for (port = 0; port <= 1; ++port) {
+ unsigned int base = 0, ctl = 0;
+ ide_pci_enablebit_t *e = &(d->enablebits[port]);
+ if (e->reg && (pcibios_read_config_byte(bus, fn, e->reg, &tmp) || (tmp & e->mask) != e->val))
+ continue; /* port not enabled */
+ if (pcibios_read_config_dword(bus, fn, 0x14+(port*8), &ctl) || (ctl &= ~3) == 0)
+ ctl = port ? 0x374 : 0x3f4; /* use default value */
+ if (pcibios_read_config_dword(bus, fn, 0x10+(port*8), &base) || (base &= ~7) == 0)
+ base = port ? 0x170 : 0x1f0; /* use default value */
+ if ((hwif = ide_match_hwif(base, d->name)) == NULL)
+ continue; /* no room in ide_hwifs[] */
+ if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+ ide_init_hwif_ports(hwif->io_ports, base, NULL);
+ hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
+ }
+ hwif->chipset = ide_pci;
+ hwif->pci_bus = bus;
+ hwif->pci_fn = fn;
+ hwif->pci_devid = d->devid;
+ hwif->channel = port;
+ hwif->irq = pciirq;
+ if (mate) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ }
+ if (no_autodma)
+ hwif->no_autodma = 1;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((ccode >> 16) == PCI_CLASS_STORAGE_IDE && (ccode & 0x8000))) {
+ unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0;
+ unsigned int dma_base = ide_get_or_set_dma_base(hwif, extra, d->name);
+ if (dma_base && !(pcicmd & 4)) {
+ /*
+ * Set up BM-DMA capability (PnP BIOS should have done this)
+ */
+ hwif->no_autodma = 1; /* default DMA off if we had to configure it here */
+ (void) pcibios_write_config_word(bus, fn, 0x04, (pcicmd|4));
+ if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd) || !(pcicmd & 4)) {
+ printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
+ dma_base = 0;
+ }
+ }
+ if (dma_base)
+ ide_setup_dma(hwif, dma_base, 8);
+ else
+ printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04x\n",
+ hwif->name, d->name, pcicmd, ccode, dma_base);
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
+ d->init_hwif(hwif);
+ mate = hwif;
+ at_least_one_hwif_enabled = 1;
+ }
+ if (!at_least_one_hwif_enabled)
+ printk("%s: neither IDE port enabled (BIOS)\n", d->name);
+}
+
+/*
+ * ide_scan_pci_device() examines all functions of a PCI device,
+ * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
+{
+ unsigned int ccode;
+ ide_pci_devid_t devid;
+ ide_pci_device_t *d;
+ byte hedt;
+
+ if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
+ hedt = 0;
+ do {
+ if (pcibios_read_config_word(bus, fn, 0x00, &devid.vid)
+ || devid.vid == 0xffff
+ || pcibios_read_config_word(bus, fn, 0x02, &devid.did)
+ || IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL)
+ || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
+ return;
+ for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+ if (d->init_hwif == IDE_IGNORE)
+ printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(fn & 1))
+ continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */
+ else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) {
+ if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
+ printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
+ d->name, bus, fn, devid.vid, devid.did);
+ else
+ printk("%s: PCI bus %d function %d\n", d->name, bus, fn);
+ ide_setup_pci_device(bus, fn, ccode, d);
+ }
+ } while (hedt == 0x80 && (++fn & 7));
+}
+
+/*
+ * ide_scan_pcibus() gets invoked at boot time from ide.c
+ *
+ * Loops over all PCI devices on all PCI buses, invoking ide_scan_pci_device().
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+void ide_scan_pcibus (void) /* __init */
+{
+ unsigned int bus, dev;
+
+ if (!pcibios_present())
+ return;
+ for (bus = 0; bus <= 255; ++bus) {
+ for (dev = 0; dev < 256; dev += 8) {
+ ide_scan_pci_device(bus, dev);
+ }
+ }
+}
+
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 9ae187b7e..8e9336037 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide-probe.c Version 1.02 Jul 29, 1997
+ * linux/drivers/block/ide-probe.c Version 1.03 Dec 5, 1997
*
- * Copyright (C) 1994-1996 Linus Torvalds & authors (see below)
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
/*
@@ -10,36 +10,11 @@
*
* This is the IDE probe module, as evolved from hd.c and ide.c.
*
- * From hd.c:
- * |
- * | It traverses the request-list, using interrupts to jump between functions.
- * | As nearly all functions can be called within interrupts, we may not sleep.
- * | Special care is recommended. Have Fun!
- * |
- * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- * |
- * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- * | in the early extended-partition checks and added DM partitions.
- * |
- * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- * |
- * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- * | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
- * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2")
- * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
- *
- * This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
- * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
* Version 1.00 move drive probing code from ide.c to ide-probe.c
* Version 1.01 fix compilation problem for m68k
* Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Version 1.03 fix for (hwif->chipset == ide_4drives)
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -51,12 +26,9 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/delay.h>
@@ -105,6 +77,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+ id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */
drive->present = 1;
printk("%s: %s, ", drive->name, id->model);
@@ -115,7 +88,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
byte type = (id->config >> 8) & 0x1f;
printk("ATAPI ");
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->is_pdc4030_2) {
+ if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
printk(" -- not supported on 2nd Promise port\n");
drive->present = 0;
return;
@@ -160,8 +133,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
*/
static void delay_50ms (void)
{
- unsigned long timer = jiffies + ((HZ + 19)/20) + 1;
- while (timer > jiffies);
+ unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
+ while (0 < (signed long)(timeout - jiffies));
}
/*
@@ -180,6 +153,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
ide_ioreg_t hd_status;
unsigned long timeout;
unsigned long irqs = 0;
+ byte s, a;
if (!HWIF(drive)->irq) { /* already got an IRQ? */
probe_irq_off(probe_irq_on()); /* clear dangling irqs */
@@ -188,9 +162,11 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
}
delay_50ms(); /* take a deep breath */
- if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) {
- printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name);
- hd_status = IDE_STATUS_REG; /* ancient Seagate drives */
+ a = IN_BYTE(IDE_ALTSTATUS_REG);
+ s = IN_BYTE(IDE_STATUS_REG);
+ if ((a ^ s) & ~INDEX_STAT) {
+ printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+ hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */
} else
hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */
@@ -208,7 +184,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
timeout += jiffies;
do {
- if (jiffies > timeout) {
+ if (0 < (signed long)(jiffies - timeout)) {
if (irqs)
(void) probe_irq_off(irqs);
return 1; /* drive timed-out */
@@ -285,9 +261,11 @@ static int do_probe (ide_drive_t *drive, byte cmd)
SELECT_DRIVE(hwif,drive);
delay_50ms();
if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
- OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */
- delay_50ms(); /* allow BUSY_STAT to assert & clear */
- return 3; /* no i/f present: avoid killing ethernet cards */
+ if (drive->select.b.unit != 0) {
+ SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */
+ delay_50ms(); /* allow BUSY_STAT to assert & clear */
+ }
+ return 3; /* no i/f present: mmm.. this should be a 4 -ml */
}
if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
@@ -302,7 +280,7 @@ static int do_probe (ide_drive_t *drive, byte cmd)
rc = 3; /* not present or maybe ATAPI */
}
if (drive->select.b.unit != 0) {
- OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */
+ SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */
delay_50ms();
(void) GET_STAT(); /* ensure drive irq is clear */
}
@@ -367,7 +345,7 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif)
int unit;
#ifdef CONFIG_BLK_DEV_PDC4030
- if (hwif->is_pdc4030_2)
+ if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
return;
#endif /* CONFIG_BLK_DEV_PDC4030 */
outb_p(0x12,0x70); /* specify CMOS address 0x12 */
@@ -400,12 +378,12 @@ static void probe_hwif (ide_hwif_t *hwif)
return;
if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
probe_cmos_for_drives (hwif);
+ if ((hwif->chipset != ide_4drives || !hwif->mate->present)
#if CONFIG_BLK_DEV_PDC4030
- if (!hwif->is_pdc4030_2 &&
- (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) {
-#else
- if (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)) {
+ && (hwif->chipset != ide_pdc4030 || hwif->channel == 0)
#endif /* CONFIG_BLK_DEV_PDC4030 */
+ && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)))
+ {
int msgout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
@@ -431,8 +409,10 @@ static void probe_hwif (ide_hwif_t *hwif)
(void) probe_for_drive (drive);
if (drive->present && !hwif->present) {
hwif->present = 1;
- ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
- ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+ if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+ ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+ ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+ }
}
}
if (hwif->reset) {
@@ -446,7 +426,8 @@ static void probe_hwif (ide_hwif_t *hwif)
do {
delay_50ms();
stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
- } while ((stat & BUSY_STAT) && jiffies < timeout);
+ } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+
}
restore_flags(flags);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -521,13 +502,11 @@ static int init_irq (ide_hwif_t *hwif)
save_match(hwif, h, &match);
}
if (hwif->serialized) {
- ide_hwif_t *mate = &ide_hwifs[hwif->index^1];
- if (index == mate->index || h->irq == mate->irq)
+ if (hwif->mate && hwif->mate->irq == h->irq)
save_match(hwif, h, &match);
}
if (h->serialized) {
- ide_hwif_t *mate = &ide_hwifs[h->index^1];
- if (hwif->irq == mate->irq)
+ if (h->mate && hwif->irq == h->mate->irq)
save_match(hwif, h, &match);
}
}
@@ -603,7 +582,7 @@ static void init_gendisk (ide_hwif_t *hwif)
{
struct gendisk *gd, **gdp;
unsigned int unit, units, minors;
- int *bs;
+ int *bs, *max_sect;
/* figure out maximum drive number on the interface */
for (units = MAX_DRIVES; units > 0; --units) {
@@ -615,13 +594,17 @@ static void init_gendisk (ide_hwif_t *hwif)
gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
bs = kmalloc (minors*sizeof(int), GFP_KERNEL);
+ max_sect = kmalloc (minors*sizeof(int), GFP_KERNEL);
memset(gd->part, 0, minors * sizeof(struct hd_struct));
/* cdroms and msdos f/s are examples of non-1024 blocksizes */
blksize_size[hwif->major] = bs;
- for (unit = 0; unit < minors; ++unit)
+ max_sectors[hwif->major] = max_sect;
+ for (unit = 0; unit < minors; ++unit) {
*bs++ = BLOCK_SIZE;
+ *max_sect++ = 244;
+ }
for (unit = 0; unit < units; ++unit)
hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
@@ -640,9 +623,8 @@ static void init_gendisk (ide_hwif_t *hwif)
hwif->gd = *gdp = gd; /* link onto tail of list */
}
-static int hwif_init (int h)
+static int hwif_init (ide_hwif_t *hwif)
{
- ide_hwif_t *hwif = &ide_hwifs[h];
void (*rfn)(void);
if (!hwif->present)
@@ -692,7 +674,6 @@ static int hwif_init (int h)
return hwif->present;
}
-int ideprobe_init (void);
static ide_module_t ideprobe_module = {
IDE_PROBE_MODULE,
ideprobe_init,
@@ -713,9 +694,11 @@ int ideprobe_init (void)
* Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
*/
for (index = 0; index < MAX_HWIFS; ++index)
- if (probe[index]) probe_hwif (&ide_hwifs[index]);
+ if (probe[index])
+ probe_hwif(&ide_hwifs[index]);
for (index = 0; index < MAX_HWIFS; ++index)
- if (probe[index]) hwif_init (index);
+ if (probe[index])
+ hwif_init(&ide_hwifs[index]);
ide_register_module(&ideprobe_module);
MOD_DEC_USE_COUNT;
return 0;
diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c
new file mode 100644
index 000000000..55ad22521
--- /dev/null
+++ b/drivers/block/ide-proc.c
@@ -0,0 +1,505 @@
+/*
+ * linux/drivers/block/proc_ide.c Version 1.01 December 12, 1997
+ *
+ * Copyright (C) 1997-1998 Mark Lord
+ */
+
+/*
+ * This is the /proc/ide/ filesystem implementation.
+ *
+ * The major reason this exists is to provide sufficient access
+ * to driver and config data, such that user-mode programs can
+ * be developed to handle chipset tuning for most PCI interfaces.
+ * This should provide better utilities, and less kernel bloat.
+ *
+ * The entire pci config space for a PCI interface chipset can be
+ * retrieved by just reading it. e.g. "cat /proc/ide3/pci"
+ *
+ * To modify registers, do something like:
+ * echo "40:88" >/proc/ide/ide3/pci
+ * That expression writes 0x88 to pci config register 0x40
+ * on the chip which controls ide3. Multiple tuples can be issued,
+ * and the writes will be completed as an atomic set:
+ * echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci
+ * All numbers must be pairs of ascii hex digits.
+ *
+ * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY
+ * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the
+ * returned data as 256 16-bit words. The "hdparm" utility will
+ * be updated someday soon to use this mechanism.
+ *
+ * Feel free to develop and distribute fancy GUI configuration
+ * utilities for you favorite PCI chipsets. I'll be working on
+ * one for the Promise 20246 someday soon. -ml
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/ctype.h>
+#include "ide.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{ \
+ len -= off; \
+ if (len < count) { \
+ *eof = 1; \
+ if (len <= 0) \
+ return 0; \
+ } else \
+ len = count; \
+ *start = page + off; \
+ return len; \
+}
+
+
+#ifdef CONFIG_PCI
+
+static int ide_getxdigit(char c)
+{
+ int digit;
+ if (isdigit(c))
+ digit = c - '0';
+ else if (isxdigit(c))
+ digit = tolower(c) - 'a' + 10;
+ else
+ digit = -1;
+ return digit;
+}
+
+
+static int xx_xx_parse_error (const char *start, unsigned long maxlen)
+{
+ char errbuf[7];
+ int i, len = MIN(6, maxlen);
+ for (i = 0; i < len; ++i) {
+ char c = start[i];
+ if (!c || c == '\n')
+ c = '\0';
+ else if (iscntrl(c))
+ c = '?';
+ errbuf[i] = c;
+ }
+ errbuf[i] = '\0';
+ printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf);
+ return -EINVAL;
+}
+
+static int proc_ide_write_pci
+ (struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)data;
+ int for_real = 0;
+ unsigned long n, flags;
+ const char *start;
+
+ if (!suser())
+ return -EACCES;
+ /*
+ * Skip over leading whitespace
+ */
+ while (count && isspace(*buffer)) {
+ --count;
+ ++buffer;
+ }
+ /*
+ * Do one full pass to verify all parameters,
+ * then do another to actually write the pci regs.
+ */
+ save_flags(flags);
+ do {
+ const char *p = buffer;
+ n = count;
+ if (for_real) {
+ unsigned long timeout = jiffies + (3 * HZ);
+ cli(); /* ensure all PCI writes are done together */
+ while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
+ sti();
+ if (0 < (signed long)(timeout - jiffies)) {
+ printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+ return -EBUSY;
+ }
+ cli();
+ }
+ }
+ while (n) {
+ int d1, d2, rc;
+ byte reg, val;
+ start = p;
+#if 0
+ printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p);
+#endif
+ if (n < 5)
+ goto parse_error;
+ if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ goto parse_error;
+ reg = (d1 << 4) | d2;
+ if (*p++ != ':')
+ goto parse_error;
+ if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ goto parse_error;
+ val = (d1 << 4) | d2;
+ if (n > 5 && !isspace(*p))
+ goto parse_error;
+ n -= 5;
+ while (n && isspace(*p)) {
+ --n;
+ ++p;
+ }
+ if (for_real) {
+#if 0
+ printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val);
+#endif
+ rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
+ if (rc) {
+ restore_flags(flags);
+ printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n",
+ hwif->pci_bus, hwif->pci_fn, reg, val);
+ printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc));
+ return -EIO;
+ }
+ }
+ }
+ } while (!for_real++);
+ restore_flags(flags);
+ return count;
+parse_error:
+ restore_flags(flags);
+ return xx_xx_parse_error(start, n);
+}
+
+static int proc_ide_read_pci
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)data;
+ char *out = page;
+ int len, reg = 0;
+
+ out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n",
+ hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+ do {
+ byte val;
+ int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val);
+ if (rc) {
+ printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n",
+ hwif->pci_bus, hwif->pci_fn, reg);
+ printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc));
+ return -EIO;
+ out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+ } else
+ out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+ } while (reg < 0x100);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_imodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+ const char *vids, *dids;
+
+ vids = pci_strvendor(hwif->pci_devid.vid);
+ dids = pci_strdev(hwif->pci_devid.vid, hwif->pci_devid.did);
+ len = sprintf(page,"%s: %s\n", vids ? vids : "(none)", dids ? dids : "(none)");
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif /* CONFIG_PCI */
+
+static int proc_ide_read_type
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+ const char *name;
+
+ switch (hwif->chipset) {
+ case ide_unknown: name = "(none)"; break;
+ case ide_generic: name = "generic"; break;
+ case ide_pci: name = "pci"; break;
+ case ide_cmd640: name = "cmd640"; break;
+ case ide_dtc2278: name = "dtc2278"; break;
+ case ide_ali14xx: name = "ali14xx"; break;
+ case ide_qd6580: name = "qd6580"; break;
+ case ide_umc8672: name = "umc8672"; break;
+ case ide_ht6560b: name = "ht6560b"; break;
+ case ide_pdc4030: name = "pdc4030"; break;
+ case ide_rz1000: name = "rz1000"; break;
+ case ide_trm290: name = "trm290"; break;
+ case ide_4drives: name = "4drives"; break;
+ default: name = "(unknown)"; break;
+ }
+ len = sprintf(page, "%s\n", name);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_mate
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ len = sprintf(page, "%s\n", hwif->mate->name);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_channel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ page[0] = hwif->channel ? '1' : '0';
+ page[1] = '\n';
+ len = 2;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_get_identify (ide_drive_t *drive, byte *buf)
+{
+ struct request rq;
+ byte *end;
+
+ ide_init_drive_cmd(&rq);
+ rq.buffer = buf;
+ *buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY;
+ *buf++ = 0;
+ *buf++ = 0;
+ *buf++ = 1;
+ end = buf + (SECTOR_WORDS * 4);
+ while (buf != end)
+ *buf++ = 0; /* pre-zero it, in case identify fails */
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
+ return 0;
+}
+
+static int proc_ide_read_identify
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *)data;
+ int len = 0, i = 0;
+
+ if (!proc_ide_get_identify(drive, page)) {
+ unsigned short *val = ((unsigned short *)page) + 2;
+ char *out = ((char *)val) + (SECTOR_WORDS * 4);
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < (SECTOR_WORDS * 2));
+ len = out - page;
+ }
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_settings
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ out += sprintf(out,"multcount %i\n", drive->mult_count);
+ out += sprintf(out,"io_32bit %i\n", drive->io_32bit);
+ out += sprintf(out,"unmaskirq %i\n", drive->unmask);
+ out += sprintf(out,"using_dma %i\n", drive->using_dma);
+ out += sprintf(out,"nowerr %i\n", drive->bad_wstat == BAD_R_STAT);
+ out += sprintf(out,"keepsettings %i\n", drive->keep_settings);
+ out += sprintf(out,"nice %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ int len;
+
+ len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_geometry
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ out += sprintf(out,"physical %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
+ out += sprintf(out,"logical %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_dmodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ struct hd_driveid *id = drive->id;
+ int len;
+
+ len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_driver
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ ide_driver_t *driver = (ide_driver_t *) drive->driver;
+ int len;
+
+ if (!driver)
+ len = sprintf(page, "(none)\n");
+ else
+ len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_media
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ const char *media;
+ int len;
+
+ switch (drive->media) {
+ case ide_disk: media = "disk\n";
+ break;
+ case ide_cdrom: media = "cdrom\n";
+ break;
+ case ide_tape: media = "tape\n";
+ break;
+ case ide_floppy:media = "floppy\n";
+ break;
+ default: media = "UNKNOWN\n";
+ break;
+ }
+ strcpy(page,media);
+ len = strlen(media);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+
+static ide_proc_entry_t generic_drive_entries[] = {
+ { "capacity", proc_ide_read_capacity, NULL },
+ { "driver", proc_ide_read_driver, NULL },
+ { "identify", proc_ide_read_identify, NULL },
+ { "media", proc_ide_read_media, NULL },
+ { "model", proc_ide_read_dmodel, NULL },
+ { "settings", proc_ide_read_settings, NULL },
+ { NULL, NULL, NULL }
+};
+
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+ struct proc_dir_entry *ent;
+
+ if (!drive->proc || !p)
+ return;
+ while (p->name != NULL) {
+ ent = create_proc_entry(p->name, 0, drive->proc);
+ if (!ent) return;
+ ent->data = drive;
+ ent->read_proc = p->read_proc;
+ ent->write_proc = p->write_proc;
+ p++;
+ }
+}
+
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+ if (!drive->proc || !p)
+ return;
+ while (p->name != NULL) {
+ remove_proc_entry(p->name, drive->proc);
+ p++;
+ }
+}
+
+static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent)
+{
+ int d;
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+
+ if (!drive->present)
+ continue;
+ drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+ if (drive->proc)
+ ide_add_proc_entries(drive, generic_drive_entries);
+ }
+}
+
+static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+{
+ int h;
+ struct proc_dir_entry *hwif_ent, *ent;
+
+ for (h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+
+ if (!hwif->present)
+ continue;
+ hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
+ if (!hwif_ent) return;
+#ifdef CONFIG_PCI
+ if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
+ ent = create_proc_entry("pci", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_pci;
+ ent->write_proc = proc_ide_write_pci;;
+
+ ent = create_proc_entry("model", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_imodel;
+ }
+#endif /* CONFIG_PCI */
+ ent = create_proc_entry("channel", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_channel;
+
+ if (hwif->mate && hwif->mate->present) {
+ ent = create_proc_entry("mate", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_mate;
+ }
+
+ ent = create_proc_entry("type", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_type;
+
+ create_proc_ide_drives(hwif, hwif_ent);
+ }
+}
+
+void proc_ide_init(void)
+{
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("ide", S_IFDIR, 0);
+ if (!ent) return;
+ create_proc_ide_interfaces(ent);
+}
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index e9d7f1433..a30fc9a58 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.11 - BETA Dec 2, 1996
+ * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997
*
* Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
*
@@ -206,6 +206,11 @@
* Use ide_stall_queue() for DSC overlap.
* Use the maximum speed rather than the current speed
* to compute the request service time.
+ * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data
+ * corruption, which could occur if the total number
+ * of bytes written to the tape was not an integral
+ * number of tape blocks.
+ * Add support for INTERRUPT DRQ devices.
*
* Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well:
@@ -315,6 +320,8 @@
* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
*/
+#define IDETAPE_VERSION "1.12"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -323,12 +330,9 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
@@ -692,6 +696,7 @@ typedef struct {
#define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */
#define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */
#define IDETAPE_FILEMARK 5 /* Currently on a filemark */
+#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */
/*
* Supported ATAPI tape drives packet commands
@@ -1152,11 +1157,6 @@ static void idetape_postpone_request (ide_drive_t *drive)
*/
static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
{
- unsigned int major = HWIF(drive)->major;
- struct blk_dev_struct *bdev = &blk_dev[major];
-
- bdev->current_request=HWGROUP (drive)->rq; /* Since we may have taken it out */
-
ide_init_drive_cmd (rq);
rq->buffer = (char *) pc;
rq->cmd = IDETAPE_PC_RQ1;
@@ -1542,16 +1542,12 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
ide_drive_t *drive = hwgroup->drive;
struct request *rq = hwgroup->rq;
idetape_tape_t *tape = drive->driver_data;
- unsigned int major = HWIF(drive)->major;
- struct blk_dev_struct *bdev = &blk_dev[major];
int error;
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "Reached idetape_end_request\n");
#endif /* IDETAPE_DEBUG_LOG */
- bdev->current_request=rq; /* Since we may have taken it out */
-
switch (uptodate) {
case 0: error = IDETAPE_ERROR_GENERAL; break;
case 1: error = 0; break;
@@ -1723,18 +1719,23 @@ static void idetape_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
- set_bit (PC_DMA_ERROR, &pc->flags);
+ if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
/*
- * We will currently correct the following in
- * idetape_analyze_error.
+ * A DMA error is sometimes expected. For example,
+ * if the tape is crossing a filemark during a
+ * READ command, it will issue an irq and position
+ * itself before the filemark, so that only a partial
+ * data transfer will occur (which causes the DMA
+ * error). In that case, we will later ask the tape
+ * how much bytes of the original request were
+ * actually transferred (we can't receive that
+ * information from the DMA engine on most chipsets).
*/
- pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive);
+ set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
idetape_update_buffers (pc);
}
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "ide-tape: DMA finished\n");
#endif /* IDETAPE_DEBUG_LOG */
@@ -1780,7 +1781,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
ide_do_reset (drive);
return;
}
@@ -1873,11 +1874,31 @@ static void idetape_pc_intr (ide_drive_t *drive)
* we will handle the next request.
*
*/
+
+static void idetape_transfer_pc(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = tape->pc;
+ idetape_ireason_reg_t ireason;
+
+ if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ return;
+ }
+ ireason.all=IN_BYTE (IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
+ ide_do_reset (drive);
+ return;
+ }
+ ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */
+ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
+}
+
static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
{
idetape_tape_t *tape = drive->driver_data;
idetape_bcount_reg_t bcount;
- idetape_ireason_reg_t ireason;
int dma_ok=0;
#if IDETAPE_DEBUG_BUGS
@@ -1918,7 +1939,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -1929,35 +1950,19 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-
- ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */
- OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG); /* Issue the packet command */
-
- if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { /* Wait for DRQ to be ready - Assuming Accelerated DRQ */
- /*
- * We currently only support tape drives which report
- * accelerated DRQ assertion. For this case, specs
- * allow up to 50us. We really shouldn't get here.
- *
- * ??? Still needs to think what to do if we reach
- * here anyway.
- */
- printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
- return;
- }
- ireason.all=IN_BYTE (IDE_IREASON_REG);
- if (!ireason.b.cod || ireason.b.io) {
- printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
- ide_do_reset (drive);
- return;
- }
- atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD);
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ } else {
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ idetape_transfer_pc(drive);
+ }
}
static void idetape_media_access_finished (ide_drive_t *drive)
@@ -2179,7 +2184,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc;
- struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
struct request *postponed_rq = tape->postponed_rq;
idetape_status_reg_t status;
@@ -2198,32 +2202,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
}
/*
- * This is an important point. We will try to remove our request
- * from the block device request queue while we service the
- * request. Note that the request must be returned to
- * bdev->current_request before the next call to
- * ide_end_drive_cmd or ide_do_drive_cmd to conform with the
- * normal behavior of the IDE driver, which leaves the active
- * request in bdev->current_request during I/O.
- *
- * This will eliminate fragmentation of disk/cdrom requests
- * around a tape request, now that we are using ide_next to
- * insert pending pipeline requests, since we have only one
- * ide-tape.c data request in the device request queue, and
- * thus once removed, ll_rw_blk.c will only see requests from
- * the other device.
- *
- * The potential fragmentation inefficiency was pointed to me
- * by Mark Lord.
- *
- * Uhuh.. the following "fix" is actually not entirely correct.
- * Some day we should probably move to a per device request
- * queue, rather than per interface.
- */
- if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev)
- bdev->current_request=rq->next;
-
- /*
* Retry a failed packet command
*/
if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2612,8 +2590,8 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
if (tape->merge_stage_size % tape->tape_block_size) {
blocks++;
i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
- memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i);
- tape->merge_stage->bh->b_count += i;
+ memset (tape->bh->b_data + tape->bh->b_count, 0, i);
+ tape->bh->b_count += i;
}
(void) idetape_add_chrdev_write_request (drive, blocks);
tape->merge_stage_size = 0;
@@ -3378,9 +3356,9 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
case 1: printk (KERN_INFO "16 bytes\n");break;
default: printk (KERN_INFO "Reserved\n");break;
}
- printk (KERN_INFO "Model: %s\n",id->model);
- printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
- printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+ printk (KERN_INFO "Model: %.40s\n",id->model);
+ printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+ printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512);
printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -3532,6 +3510,7 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
ide_hwif_t *hwif = HWIF(drive);
unsigned long t1, tmid, tn, t;
u16 speed;
+ struct idetape_id_gcw gcw;
drive->driver_data = tape;
drive->ready_stat = 0; /* An ATAPI device ignores DRDY */
@@ -3543,6 +3522,9 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->chrdev_direction = idetape_direction_none;
tape->pc = tape->pc_stack;
tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
+ *((unsigned short *) &gcw) = drive->id->config;
+ if (gcw.drq_type == 1)
+ set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
idetape_get_mode_sense_results (drive);
@@ -3635,6 +3617,8 @@ static ide_module_t idetape_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idetape_driver = {
+ "ide-tape", /* name */
+ IDETAPE_VERSION, /* version */
ide_tape, /* media */
1, /* busy */
1, /* supports_dma */
@@ -3648,7 +3632,8 @@ static ide_driver_t idetape_driver = {
NULL, /* media_change */
idetape_pre_reset, /* pre_reset */
NULL, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
/*
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 50af139cd..3b9a17283 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.05 November 30, 1997
+ * linux/drivers/block/ide.c Version 6.11 December 5, 1997
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -95,6 +95,9 @@
* added support for BIOS-enabled UltraDMA
* rename all "promise" things to "pdc4030"
* fix EZ-DRIVE handling on small disks
+ * Version 6.11 fix probe error in ide_scan_devices()
+ * fix ancient "jiffies" polling bugs
+ * mask all hwgroup interrupts on each irq entry
*
* Some additional driver compile-time options are in ide.h
*
@@ -111,18 +114,14 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -312,11 +311,12 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
+ unsigned long flags;
+ save_flags(flags);
cli();
do_vlb_sync(IDE_NSECTOR_REG);
insl(IDE_DATA_REG, buffer, wcount);
- if (drive->unmask)
- sti();
+ restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
insl(IDE_DATA_REG, buffer, wcount);
@@ -344,11 +344,12 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
+ unsigned long flags;
+ save_flags(flags);
cli();
do_vlb_sync(IDE_NSECTOR_REG);
outsl(IDE_DATA_REG, buffer, wcount);
- if (drive->unmask)
- sti();
+ restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
outsl(IDE_DATA_REG, buffer, wcount);
@@ -469,13 +470,13 @@ static void atapi_reset_pollfunc (ide_drive_t *drive)
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
- OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ SELECT_DRIVE(HWIF(drive),drive);
udelay (10);
if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
- if (jiffies < hwgroup->poll_timeout) {
+ if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
return; /* continue polling */
}
@@ -500,7 +501,7 @@ static void reset_pollfunc (ide_drive_t *drive)
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (jiffies < hwgroup->poll_timeout) {
+ if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &reset_pollfunc, HZ/20);
return; /* continue polling */
}
@@ -542,7 +543,7 @@ static void pre_reset (ide_drive_t *drive)
drive->unmask = 0;
drive->io_32bit = 0;
if (drive->using_dma)
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (drive->driver != NULL)
DRIVER(drive)->pre_reset(drive);
@@ -576,7 +577,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
pre_reset(drive);
- OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ SELECT_DRIVE(hwif,drive);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
@@ -808,7 +809,7 @@ static void drive_cmd_intr (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
byte *args = (byte *) rq->buffer;
- byte stat = GET_STAT();
+ byte test, stat = GET_STAT();
ide_sti();
if ((stat & DRQ_STAT) && args && args[3]) {
@@ -818,7 +819,10 @@ static void drive_cmd_intr (ide_drive_t *drive)
drive->io_32bit = io_32bit;
stat = GET_STAT();
}
- if (OK_STAT(stat,READY_STAT,BAD_STAT))
+ test = stat;
+ if (drive->media == ide_cdrom)
+ test = stat &~BUSY_STAT;
+ if (OK_STAT(test,READY_STAT,BAD_STAT))
ide_end_drive_cmd (drive, stat, GET_ERR());
else
ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
@@ -870,7 +874,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
ide_sti();
timeout += jiffies;
while ((stat = GET_STAT()) & BUSY_STAT) {
- if (jiffies > timeout) {
+ if (0 < (signed long)(jiffies - timeout)) {
restore_flags(flags);
ide_error(drive, "status timeout", stat);
return 1;
@@ -1007,7 +1011,7 @@ repeat:
do {
if (!drive->queue)
continue;
- if (drive->sleep && drive->sleep > jiffies)
+ if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies))
continue;
if (!best) {
best = drive;
@@ -1019,7 +1023,7 @@ repeat:
best = drive;
} while ((drive = drive->next) != hwgroup->drive);
if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) {
- long t = (signed) (WAKEUP(best) - jiffies);
+ long t = (signed) (WAKEUP(best) - jiffies); /* BUGGY? */
if (t >= WAIT_MIN_SLEEP) {
/*
* We *may* have some time to spare, but first let's see if
@@ -1029,7 +1033,7 @@ repeat:
do {
if (drive->sleep) /* this drive tried to be nice to us */
continue;
- if (WAKEUP(drive) > jiffies - best->service_time && WAKEUP(drive) < jiffies + t) {
+ if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) { /* BUGGY? */
ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
goto repeat;
}
@@ -1057,7 +1061,7 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup)
sleep = drive->sleep;
} while ((drive = drive->next) != hwgroup->drive);
if (sleep) {
- if (sleep < jiffies + WAIT_MIN_SLEEP)
+ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP;
hwgroup->timer.expires = sleep;
add_timer(&hwgroup->timer);
@@ -1189,7 +1193,7 @@ void ide_timer_expiry (unsigned long data)
handler(drive);
else { /* abort the operation */
if (hwgroup->hwif->dmaproc)
- (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
+ (void) hwgroup->hwif->dmaproc (ide_dma_end, drive);
ide_error(drive, "irq timeout", GET_STAT());
}
cli();
@@ -1229,7 +1233,6 @@ void ide_timer_expiry (unsigned long data)
static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
- unsigned int unit;
ide_hwif_t *hwif = hwgroup->hwif;
/*
@@ -1237,27 +1240,18 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
*/
do {
if (hwif->irq == irq) {
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
- if (!drive->present)
- continue;
- SELECT_DRIVE(hwif,drive);
- udelay(100); /* Ugly, but wait_stat() may not be safe here */
- if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
- /* Try to not flood the console with msgs */
- static unsigned long last_msgtime = 0;
- if ((last_msgtime + (HZ/2)) < jiffies) {
- last_msgtime = jiffies;
- (void) ide_dump_status(drive, "unexpected_intr", stat);
- }
+ stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+ /* Try to not flood the console with msgs */
+ static unsigned long last_msgtime = 0;
+ if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
+ last_msgtime = jiffies;
+ printk("%s%s: unexpected interrupt, status=0x%02x\n",
+ hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat);
}
- if ((stat & DRQ_STAT))
- try_to_flush_leftover_data(drive);
}
}
} while ((hwif = hwif->next) != hwgroup->hwif);
- SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
- udelay(100); /* Ugly, but wait_stat() may not be safe here */
}
/*
@@ -1266,14 +1260,28 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
{
ide_hwgroup_t *hwgroup = dev_id;
+ ide_hwif_t *hwif = hwgroup->hwif;
ide_handler_t *handler;
- if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET],
- hwgroup->hwif->io_ports[IDE_IRQ_OFFSET]))
+ if (!ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]))
return;
-
- if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
+ do {
+ if (hwif->irq != irq) disable_irq(hwif->irq);
+ } while ((hwif = hwif->next) != hwgroup->hwif);
+ if (irq == hwif->irq && (handler = hwgroup->handler) != NULL) {
ide_drive_t *drive = hwgroup->drive;
+#if 1 /* temporary, remove later -- FIXME */
+ {
+ struct request *rq = hwgroup->rq;
+ if (rq != NULL
+ &&( MAJOR(rq->rq_dev) != HWIF(drive)->major
+ || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit))
+ {
+ printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n");
+ return;
+ }
+ }
+#endif /* temporary */
hwgroup->handler = NULL;
del_timer(&(hwgroup->timer));
if (drive->unmask)
@@ -1289,6 +1297,10 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
unexpected_intr(irq, hwgroup);
}
cli();
+ hwif = hwgroup->hwif;
+ do {
+ if (hwif->irq != irq) enable_irq(hwif->irq);
+ } while ((hwif = hwif->next) != hwgroup->hwif);
}
/*
@@ -1627,6 +1639,7 @@ void ide_unregister (unsigned int index)
*/
unregister_blkdev(hwif->major, hwif->name);
kfree(blksize_size[hwif->major]);
+ kfree(max_sectors[hwif->major]);
blk_dev[hwif->major].request_fn = NULL;
blk_dev[hwif->major].data = NULL;
blk_dev[hwif->major].queue = NULL;
@@ -1686,13 +1699,15 @@ found:
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- int err;
+ int err, major, minor;
ide_drive_t *drive;
unsigned long flags;
struct request rq;
+ kdev_t dev;
- if (!inode || !(inode->i_rdev))
+ if (!inode || !(dev = inode->i_rdev))
return -EINVAL;
+ major = MAJOR(dev); minor = MINOR(dev);
if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENODEV;
ide_init_drive_cmd (&rq);
@@ -1726,6 +1741,23 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
+ case BLKFRASET:
+ if (!suser()) return -EACCES;
+ max_readahead[major][minor] = arg;
+ return 0;
+
+ case BLKFRAGET:
+ return put_user(max_readahead[major][minor], (long *) arg);
+
+ case BLKSECTSET:
+ if (!suser()) return -EACCES;
+ if (!arg || arg > 0xff) return -EINVAL;
+ max_sectors[major][minor] = arg;
+ return 0;
+
+ case BLKSECTGET:
+ return put_user(max_sectors[major][minor], (long *) arg);
+
case BLKRRPART: /* Re-read partition tables */
if (!suser()) return -EACCES;
return ide_revalidate_disk(inode->i_rdev);
@@ -2074,6 +2106,9 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
* This is the default for most chipsets,
* except the cmd640.
* "idex=serialize" : do not overlap operations on idex and ide(x^1)
+ * "idex=four" : four drives on idex and ide(x^1) share same ports
+ * "idex=reset" : reset interface before first use
+ * "idex=nodma" : do not enable DMA by default on either drive
*
* The following are valid ONLY on ide0,
* and the defaults for the base,ctl ports must not be altered.
@@ -2175,8 +2210,8 @@ __initfunc(void ide_setup (char *s))
/*
* Be VERY CAREFUL changing this: note hardcoded indexes below
*/
- const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "qd6580",
- "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "four", "reset", NULL};
+ const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "nodma", "four",
+ "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
i = match_parm(&s[4], ide_words, vals, 3);
@@ -2184,42 +2219,19 @@ __initfunc(void ide_setup (char *s))
/*
* Cryptic check to ensure chipset not already set for hwif:
*/
- if (i > 0 || (i <= -5 && i != -13)) {
+ if (i > 0 || i <= -7) { /* is parameter a chipset name? */
if (hwif->chipset != ide_unknown)
- goto bad_option;
- if (i <= -5) {
- if (ide_hwifs[1].chipset != ide_unknown)
- goto bad_option;
- /*
- * Interface keywords work only for ide0:
- */
- if (hw != 0)
- goto bad_hwif;
- printk("\n");
- }
+ goto bad_option; /* chipset already specified */
+ if (i != -7 && hw != 0)
+ goto bad_hwif; /* chipset drivers are for "ide0=" only */
+ if (ide_hwifs[hw^1].chipset != ide_unknown)
+ goto bad_option; /* chipset for 2nd port already specified */
+ printk("\n");
}
switch (i) {
- case -13: /* "reset" */
- hwif->reset = 1;
- goto done;
-#ifdef CONFIG_BLK_DEV_4DRIVES
- case -12: /* "four" drives on one set of ports */
- {
- ide_hwif_t *mate = &ide_hwifs[hw^1];
- mate->mate = hwif;
- hwif->mate = mate;
- hwif->chipset = mate->chipset = ide_4drives;
- hwif->serialized = mate->serialized = 1;
- mate->drives[0].select.all ^= 0x20;
- mate->drives[1].select.all ^= 0x20;
- memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
- mate->irq = hwif->irq;
- goto done;
- }
-#endif /* CONFIG_BLK_DEV_4DRIVES */
#ifdef CONFIG_BLK_DEV_PDC4030
- case -11: /* "dc4030" */
+ case -14: /* "dc4030" */
{
extern void setup_pdc4030(ide_hwif_t *);
setup_pdc4030(hwif);
@@ -2227,7 +2239,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_PDC4030 */
#ifdef CONFIG_BLK_DEV_ALI14XX
- case -10: /* "ali14xx" */
+ case -13: /* "ali14xx" */
{
extern void init_ali14xx (void);
init_ali14xx();
@@ -2235,7 +2247,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_ALI14XX */
#ifdef CONFIG_BLK_DEV_UMC8672
- case -9: /* "umc8672" */
+ case -12: /* "umc8672" */
{
extern void init_umc8672 (void);
init_umc8672();
@@ -2243,7 +2255,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_UMC8672 */
#ifdef CONFIG_BLK_DEV_DTC2278
- case -8: /* "dtc2278" */
+ case -11: /* "dtc2278" */
{
extern void init_dtc2278 (void);
init_dtc2278();
@@ -2251,7 +2263,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_DTC2278 */
#ifdef CONFIG_BLK_DEV_CMD640
- case -7: /* "cmd640_vlb" */
+ case -10: /* "cmd640_vlb" */
{
extern int cmd640_vlb; /* flag for cmd640.c */
cmd640_vlb = 1;
@@ -2259,7 +2271,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_CMD640 */
#ifdef CONFIG_BLK_DEV_HT6560B
- case -6: /* "ht6560b" */
+ case -9: /* "ht6560b" */
{
extern void init_ht6560b (void);
init_ht6560b();
@@ -2267,13 +2279,31 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_HT6560B */
#if CONFIG_BLK_DEV_QD6580
- case -5: /* "qd6580" (has secondary i/f) */
+ case -8: /* "qd6580" */
{
extern void init_qd6580 (void);
init_qd6580();
goto done;
}
#endif /* CONFIG_BLK_DEV_QD6580 */
+#ifdef CONFIG_BLK_DEV_4DRIVES
+ case -7: /* "four" drives on one set of ports */
+ {
+ ide_hwif_t *mate = &ide_hwifs[hw^1];
+ mate->drives[0].select.all ^= 0x20;
+ mate->drives[1].select.all ^= 0x20;
+ hwif->chipset = mate->chipset = ide_4drives;
+ mate->irq = hwif->irq;
+ memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
+ goto do_serialize;
+ }
+#endif /* CONFIG_BLK_DEV_4DRIVES */
+ case -6: /* nodma */
+ hwif->no_autodma = 1;
+ goto done;
+ case -5: /* "reset" */
+ hwif->reset = 1;
+ goto done;
case -4: /* "noautotune" */
hwif->drives[0].autotune = 2;
hwif->drives[1].autotune = 2;
@@ -2284,8 +2314,9 @@ __initfunc(void ide_setup (char *s))
goto done;
case -2: /* "serialize" */
do_serialize:
- ide_hwifs[hw].serialized = 1; /* serialize */
- ide_hwifs[hw^1].serialized = 1; /* with mate */
+ hwif->mate = &ide_hwifs[hw^1];
+ hwif->mate->mate = hwif;
+ hwif->serialized = hwif->mate->serialized = 1;
goto done;
case -1: /* "noprobe" */
@@ -2395,44 +2426,37 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
- *
- * This routine should ideally be using pcibios_find_class() to find all
- * PCI IDE interfaces, but that function causes some systems to "go weird".
*/
__initfunc(static void probe_for_hwifs (void))
{
#ifdef CONFIG_PCI
- /*
- * Find/initialize PCI IDE interfaces
- */
if (pcibios_present())
{
-#ifdef CONFIG_BLK_DEV_IDEDMA
- {
- extern void ide_scan_pcibus(void);
- ide_scan_pcibus();
- }
-#endif
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ ide_scan_pcibus();
+#else
#ifdef CONFIG_BLK_DEV_RZ1000
{
extern void ide_probe_for_rz100x(void);
ide_probe_for_rz100x();
}
-#endif
+#endif /* CONFIG_BLK_DEV_RZ1000 */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCI */
+
#ifdef CONFIG_BLK_DEV_CMD640
{
extern void ide_probe_for_cmd640x(void);
ide_probe_for_cmd640x();
}
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640 */
#ifdef CONFIG_BLK_DEV_PDC4030
{
extern int init_pdc4030(void);
(void) init_pdc4030();
}
-#endif
+#endif /* CONFIG_BLK_DEV_PDC4030 */
}
__initfunc(void ide_init_builtin_drivers (void))
@@ -2460,6 +2484,10 @@ __initfunc(void ide_init_builtin_drivers (void))
#endif /* __mc68000__ */
#endif /* CONFIG_BLK_DEV_IDE */
+#ifdef CONFIG_PROC_FS
+ proc_ide_init();
+#endif
+
/*
* Attempt to match drivers for the available drives
*/
@@ -2552,18 +2580,19 @@ static void setup_driver_defaults (ide_drive_t *drive)
ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
{
unsigned int unit, index, i;
- ide_drive_t *drive;
for (index = 0; index < MAX_HWIFS; ++index)
if (ide_hwifs[index].present) goto search;
ide_init_module(IDE_PROBE_MODULE);
search:
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &ide_hwifs[index].drives[unit];
- if (drive->present && drive->media == media &&
- drive->driver == driver && ++i > n)
- return drive;
+ ide_hwif_t *hwif = &ide_hwifs[index];
+ if (hwif->present) {
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+ return drive;
+ }
}
}
return NULL;
@@ -2590,6 +2619,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
drive->nice1 = 1;
}
drive->revalidate = 1;
+ ide_add_proc_entries(drive, driver->proc);
return 0;
}
@@ -2603,6 +2633,7 @@ int ide_unregister_subdriver (ide_drive_t *drive)
restore_flags(flags);
return 1;
}
+ ide_remove_proc_entries(drive, DRIVER(drive)->proc);
drive->driver = NULL;
restore_flags(flags);
return 0;
@@ -2694,6 +2725,9 @@ EXPORT_SYMBOL(ide_end_request);
EXPORT_SYMBOL(ide_revalidate_disk);
EXPORT_SYMBOL(ide_cmd);
EXPORT_SYMBOL(ide_stall_queue);
+EXPORT_SYMBOL(ide_add_proc_entries);
+EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(proc_ide_read_geometry);
EXPORT_SYMBOL(ide_register);
EXPORT_SYMBOL(ide_unregister);
diff --git a/drivers/block/ide.h b/drivers/block/ide.h
index dd3549ac9..dfcb80fa5 100644
--- a/drivers/block/ide.h
+++ b/drivers/block/ide.h
@@ -7,10 +7,15 @@
*/
#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
#include <asm/ide.h>
/*
- * This is the multiple IDE interface driver, as evolved from hd.c.
+ * This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
@@ -22,7 +27,7 @@
/******************************************************************************
* IDE driver configuration options (play with these as desired):
- *
+ *
* REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
*/
#undef REALLY_FAST_IO /* define if ide ports are perfect */
@@ -164,18 +169,13 @@ typedef unsigned char byte; /* used everywhere */
#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
#define SELECT_DRIVE(hwif,drive) \
{ \
if (hwif->selectproc) \
hwif->selectproc(drive); \
- else \
- OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+ OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
}
-#else
-#define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-#endif /* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PDC4030 */
-
+
/*
* Now for the data we need to maintain per-drive: ide_drive_t
*/
@@ -248,7 +248,7 @@ typedef struct ide_drive_s {
byte bios_sect __attribute__ ((aligned (8))); /* BIOS/fdisk/LILO sectors per track */
unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned short cyl; /* "real" number of cyls */
- unsigned int timing_data; /* for use by tuneproc()'s */
+ unsigned int drive_data; /* for use by tuneproc/selectproc as needed */
void *hwif; /* actually (ide_hwif_t *) */
struct wait_queue *wqueue; /* used to wait for drive in open() */
struct hd_driveid *id; /* drive model identification info */
@@ -256,6 +256,7 @@ typedef struct ide_drive_s {
char name[4]; /* drive name, such as "hda" */
void *driver; /* (ide_driver_t *) */
void *driver_data; /* extra driver data */
+ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
} ide_drive_t;
/*
@@ -269,12 +270,9 @@ typedef struct ide_drive_s {
* Returns 1 if DMA read/write could not be started, in which case the caller
* should either try again later, or revert to PIO for the current request.
*/
-typedef enum { ide_dma_read = 0, ide_dma_write = 1,
- ide_dma_abort = 2, ide_dma_check = 3,
- ide_dma_status_bad = 4, ide_dma_transferred = 5,
- ide_dma_begin = 6, ide_dma_on = 7,
- ide_dma_off = 8, ide_dma_off_quietly = 9 }
- ide_dma_action_t;
+typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end,
+ ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly
+ } ide_dma_action_t;
typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
@@ -293,7 +291,7 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
/*
- * This is used to provide HT6560B & PDC4030 & TRM290 interface support.
+ * This is used to provide support for strange interfaces
*/
typedef void (ide_selectproc_t) (ide_drive_t *);
@@ -305,8 +303,16 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_cmd640, ide_dtc2278, ide_ali14xx,
ide_qd6580, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290,
- ide_4drives }
- hwif_chipset_t;
+ ide_4drives
+ } hwif_chipset_t;
+
+typedef struct ide_pci_devid_s {
+ unsigned short vid;
+ unsigned short did;
+} ide_pci_devid_t;
+
+#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0})
+#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did)
typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
@@ -315,13 +321,14 @@ typedef struct hwif_s {
ide_drive_t drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
ide_selectproc_t *selectproc; /* tweaks hardware to select drive */
-#endif
ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */
unsigned long *dmatable; /* dma physical region descriptor table */
struct hwif_s *mate; /* other hwif from same PCI chip */
- unsigned short dma_base; /* base addr for dma ports (triton) */
+ unsigned int dma_base; /* base addr for dma ports */
+ unsigned int config_data; /* for use by chipset-specific code */
+ unsigned int select_data; /* for use by chipset-specific code */
+ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
int irq; /* our irq number */
byte major; /* our major number */
char name[6]; /* name of interface, eg. "ide0" */
@@ -331,11 +338,12 @@ typedef struct hwif_s {
unsigned present : 1; /* this interface exists */
unsigned serialized : 1; /* serialized operation with mate hwif */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
-#ifdef CONFIG_BLK_DEV_PDC4030
- unsigned is_pdc4030_2: 1;/* 2nd i/f on pdc4030 */
-#endif /* CONFIG_BLK_DEV_PDC4030 */
- unsigned reset : 1; /* reset after probe */
- unsigned pci_port : 1; /* for dual-port chips: 0=primary, 1=secondary */
+ unsigned reset : 1; /* reset after probe */
+ unsigned no_autodma : 1; /* don't automatically enable DMA at boot */
+ byte channel; /* for dual-port chips: 0=primary, 1=secondary */
+ byte pci_bus; /* for pci chipsets */
+ byte pci_fn; /* for pci chipsets */
+ ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
@@ -358,6 +366,20 @@ typedef struct hwgroup_s {
} ide_hwgroup_t;
/*
+ * /proc/ide interface
+ */
+typedef struct {
+ char *name;
+ read_proc_t *read_proc;
+ write_proc_t *write_proc;
+} ide_proc_entry_t;
+
+void proc_ide_init(void);
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_geometry;
+
+/*
* Subdrivers support.
*/
#define IDE_SUBDRIVER_VERSION 1
@@ -374,6 +396,8 @@ typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
typedef void (ide_special_proc)(ide_drive_t *);
typedef struct ide_driver_s {
+ const char *name;
+ const char *version;
byte media;
unsigned busy : 1;
unsigned supports_dma : 1;
@@ -388,6 +412,7 @@ typedef struct ide_driver_s {
ide_pre_reset_proc *pre_reset;
ide_capacity_proc *capacity;
ide_special_proc *special;
+ ide_proc_entry_t *proc;
} ide_driver_t;
#define DRIVER(drive) ((ide_driver_t *)((drive)->driver))
@@ -410,7 +435,7 @@ typedef struct ide_module_s {
/*
* ide_hwifs[] is the master data structure used to keep track
* of just about everything in ide.c. Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or
+ * should be using pointers to a drive (ide_drive_t *) or
* pointers to a hwif (ide_hwif_t *), rather than indexing this
* structure directly (the allocation/layout may change!).
*
@@ -533,7 +558,7 @@ typedef enum
* If action is ide_next, then the rq is queued immediately after
* the currently-being-processed-request (if any), and the function
* returns without waiting for the new rq to be completed. As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
+ * This is VERY DANGEROUS, and is intended for careful use by the
* ATAPI tape/cdrom driver code.
*
* If action is ide_end, then the rq is queued at the end of the
@@ -542,7 +567,7 @@ typedef enum
* use by the ATAPI tape/cdrom driver code.
*/
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
-
+
/*
* Clean up after success/failure of an explicit drive cmd.
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
@@ -617,10 +642,16 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n);
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
int ide_unregister_subdriver (ide_drive_t *drive);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+unsigned int ide_find_free_region (unsigned short size) __init;
+void ide_scan_pcibus (void) __init;
+#endif
#ifdef CONFIG_BLK_DEV_IDEDMA
int ide_build_dmatable (ide_drive_t *drive);
+void ide_dma_intr (ide_drive_t *drive);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports);
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dmabase, unsigned int num_ports) __init;
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
#endif
#ifdef CONFIG_BLK_DEV_IDE
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 925423581..d4a83f9a1 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -87,6 +87,18 @@ int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
*/
int * max_readahead[MAX_BLKDEV] = { NULL, NULL, };
+/*
+ * Max number of sectors per request
+ */
+int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
+
+static inline int get_max_sectors(kdev_t dev)
+{
+ if (!max_sectors[MAJOR(dev)])
+ return 244; /* 254? */
+ return max_sectors[MAJOR(dev)][MINOR(dev)];
+}
+
static inline struct request **get_queue(kdev_t dev)
{
int major = MAJOR(dev);
@@ -300,9 +312,7 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
sti();
}
-#define MAX_SECTORS 244
-
-static inline void attempt_merge (struct request *req)
+static inline void attempt_merge (struct request *req, int max_sectors)
{
struct request *next = req->next;
@@ -310,7 +320,7 @@ static inline void attempt_merge (struct request *req)
return;
if (req->sector + req->nr_sectors != next->sector)
return;
- if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors >= MAX_SECTORS)
+ if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
return;
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
@@ -324,7 +334,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
{
unsigned int sector, count;
struct request * req;
- int rw_ahead, max_req;
+ int rw_ahead, max_req, max_sectors;
count = bh->b_size >> 9;
sector = bh->b_rsector;
@@ -391,6 +401,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
/*
* Try to coalesce the new request with old requests
*/
+ max_sectors = get_max_sectors(bh->b_rdev);
cli();
req = *get_queue(bh->b_rdev);
if (!req) {
@@ -428,7 +439,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
continue;
if (req->cmd != rw)
continue;
- if (req->nr_sectors >= MAX_SECTORS)
+ if (req->nr_sectors + count > max_sectors)
continue;
if (req->rq_dev != bh->b_rdev)
continue;
@@ -438,7 +449,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
req->bhtail = bh;
req->nr_sectors += count;
/* Can we now merge this req with the next? */
- attempt_merge(req);
+ attempt_merge(req, max_sectors);
/* or to the beginning? */
} else if (req->sector - count == sector) {
bh->b_reqnext = req->bh;
@@ -684,6 +695,7 @@ __initfunc(int blk_dev_init(void))
}
memset(ro_bits,0,sizeof(ro_bits));
memset(max_readahead, 0, sizeof(max_readahead));
+ memset(max_sectors, 0, sizeof(max_sectors));
#ifdef CONFIG_AMIGA_Z2RAM
z2_init();
#endif
diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c
new file mode 100644
index 000000000..62ae86f61
--- /dev/null
+++ b/drivers/block/ns87415.c
@@ -0,0 +1,228 @@
+/*
+ * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
+ *
+ * Copyright (C) 1997-1998 Mark Lord
+ *
+ * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+#include "ide.h"
+
+
+#undef INCLUDE_OBSOLETE_NS87514_STUFF /* define this if you absolutely *need* the timings stuff */
+
+
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+/*
+ * This part adapted from code from David S. Miller (davem@caipfs.rutgers.edu)
+ * which was in turn adapted from code from Mark Lord.
+ *
+ * Here as a temporary measure only. Will be removed once /proc/ide/ is working.
+ */
+#include "ide_modes.h"
+
+static void ns87415_program_modes(ide_drive_t *drive, byte active_count, byte recovery_count)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ byte cfg_reg, regval;
+
+ cfg_reg = (0x44 + (8 * HWIF(drive)->channel) + (4 * drive->select.b.unit));
+
+ /* set identical PIO timings for read/write */
+ regval = (17 - active_count) | ((16 - recovery_count) << 4);
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg, regval);
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg + 1, regval);
+}
+
+static void set_ide_modes(ide_drive_t *drive, ide_pio_data_t *d, int bus_speed)
+{
+ int setup_time, active_time, cycle_time = d->cycle_time;
+ byte setup_count, active_count, pio_mode = d->pio_mode;
+ byte recovery_count, recovery_count2, cycle_count;
+ int recovery_time, clock_time;
+
+ if(pio_mode > 5)
+ pio_mode = 5;
+
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+ active_count = (active_time + clock_time - 1) / clock_time;
+
+ if(active_count < 2)
+ active_count = 2;
+
+ recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count2 = cycle_count - (setup_count + active_count);
+
+ if(recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if(recovery_count < 2)
+ recovery_count = 2;
+ if(recovery_count > 17) {
+ active_count += recovery_count - 17;
+ recovery_count = 17;
+ }
+
+ if(active_count > 16)
+ active_count = 16;
+ if(recovery_count > 16)
+ recovery_count = 16;
+
+ printk("active[%d CLKS] recovery[%d CLKS]\n", active_count, recovery_count);
+
+ ns87415_program_modes(drive, active_count, recovery_count);
+}
+
+/* Configure for best PIO mode. */
+static void ns87415_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_pio_data_t d;
+ int bus_speed = ide_system_bus_speed();
+
+ switch(mode_wanted) {
+ case 6:
+ case 7:
+ /* Changes to Fast-devsel are unsupported. */
+ return;
+
+ case 8:
+ case 9:
+ mode_wanted &= 1;
+ /* XXX set_prefetch_mode(index, mode_wanted); */
+ printk("%s: %sbled NS87415 prefetching...\n", drive->name, mode_wanted ? "en" : "dis");
+ return;
+ };
+
+ (void) ide_get_best_pio_mode(drive, mode_wanted, 5, &d);
+
+ printk("%s: selected NS87415 PIO mode%d (%dns)%s ",
+ drive->name, d.pio_mode, d.cycle_time,
+ d.overridden ? " (overriding vendor mode)" : "");
+
+ set_ide_modes(drive, &d, bus_speed);
+}
+#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = {0};
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int bit, new, *old = (unsigned int *) hwif->select_data;
+ unsigned int flags;
+
+ save_flags(flags);
+ cli();
+
+ new = *old;
+
+ /* adjust IRQ enable bit */
+ bit = 1 << (8 + hwif->channel);
+ new = drive->present ? (new | bit) : (new & ~bit);
+
+ /* select PIO or DMA */
+ bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
+ new = use_dma ? (new | bit) : (new & ~bit);
+
+ if (new != *old) {
+ *old = new;
+ (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, new);
+ }
+ restore_flags(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+ ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ switch (func) {
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ {
+ byte dma_stat = inb(hwif->dma_base+2);
+ int rc = (dma_stat & 7) != 4;
+ outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */
+ outb(dma_stat|6, hwif->dma_base+2); /* clear the INTR & ERROR bits */
+ return rc; /* verify good DMA status */
+ }
+ case ide_dma_write:
+ case ide_dma_read:
+ ns87415_prepare_drive(drive, 1); /* select DMA xfer */
+ if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */
+ return 0;
+ ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */
+ return 1;
+ default:
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+ }
+}
+
+__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif))
+{
+ unsigned int ctrl, progif, using_inta;
+
+ /*
+ * We cannot probe for IRQ: both ports share common IRQ on INTA.
+ * Also, leave IRQ masked during drive probing, to prevent infinite
+ * interrupts from a potentially floating INTA..
+ *
+ * IRQs get unmasked in selectproc when drive is first used.
+ */
+ (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &ctrl);
+ (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &progif);
+ /* is irq in "native" mode? */
+ using_inta = progif & (1 << (hwif->channel << 1));
+ if (!using_inta)
+ using_inta = ctrl & (1 << (4 + hwif->channel));
+ (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, ctrl);
+ if (hwif->mate) {
+ hwif->select_data = hwif->mate->select_data;
+ } else {
+ hwif->select_data = (unsigned int) &ns87415_control[ns87415_count++];
+ ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */
+ if (using_inta)
+ ctrl &= ~(1 << 6); /* unmask INTA */
+ *((unsigned int *)hwif->select_data) = ctrl;
+ /*
+ * Set prefetch size to 512 bytes for both ports,
+ * but don't turn on/off prefetching here.
+ */
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, 0x55, 0xee);
+ }
+ if (!using_inta)
+ hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+
+ hwif->dmaproc = &ns87415_dmaproc;
+ hwif->selectproc = &ns87415_selectproc;
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+ hwif->tuneproc = &ns87415_tuneproc;
+#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */
+}
diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c
index 0e0b23758..a4c94b0e6 100644
--- a/drivers/block/opti621.c
+++ b/drivers/block/opti621.c
@@ -110,7 +110,7 @@ int reg_base;
/* there are stored pio numbers from other calls of opti621_tune_drive */
static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->timing_data
+/* Store values into drive->drive_data
* second_contr - 0 for primary controller, 1 for secondary
* slave_drive - 0 -> pio is for master, 1 -> pio is for slave
* pio - PIO mode for selected drive (for other we don't know)
@@ -119,17 +119,17 @@ static void compute_pios(ide_drive_t *drive, byte pio)
int d;
ide_hwif_t *hwif = HWIF(drive);
- drive->timing_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
for (d = 0; d < 2; ++d) {
drive = &hwif->drives[d];
if (drive->present) {
- if (drive->timing_data == PIO_DONT_KNOW)
- drive->timing_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+ if (drive->drive_data == PIO_DONT_KNOW)
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
#ifdef OPTI621_DEBUG
- printk("%s: Selected PIO mode %d\n", drive->name, drive->timing_data);
+ printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
#endif
} else {
- drive->timing_data = PIO_NOT_EXIST;
+ drive->drive_data = PIO_NOT_EXIST;
}
}
}
@@ -192,7 +192,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks)
clks->address_time = cmpt_clk(adr_setup, bus_speed);
clks->data_time = cmpt_clk(data_pls, bus_speed);
clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
- -adr_setup-data_pls, bus_speed);
+ - adr_setup-data_pls, bus_speed);
if (clks->address_time<1) clks->address_time = 1;
if (clks->address_time>4) clks->address_time = 4;
if (clks->data_time<1) clks->data_time = 1;
@@ -220,10 +220,10 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
byte cycle1, cycle2, misc;
ide_hwif_t *hwif = HWIF(drive);
- /* set drive->timing_data for both drives */
+ /* set drive->drive_data for both drives */
compute_pios(drive, pio);
- pio1 = hwif->drives[0].timing_data;
- pio2 = hwif->drives[1].timing_data;
+ pio1 = hwif->drives[0].drive_data;
+ pio2 = hwif->drives[1].drive_data;
compute_clocks(pio1, &first);
compute_clocks(pio2, &second);
@@ -274,11 +274,11 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
}
/*
- * ide_init_opti621() is Called from idedma.c once for each hwif found at boot.
+ * ide_init_opti621() is called once for each hwif found at boot.
*/
-void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwif)
+void ide_init_opti621 (ide_hwif_t *hwif)
{
- hwif->drives[0].timing_data = PIO_DONT_KNOW;
- hwif->drives[1].timing_data = PIO_DONT_KNOW;
+ hwif->drives[0].drive_data = PIO_DONT_KNOW;
+ hwif->drives[1].drive_data = PIO_DONT_KNOW;
hwif->tuneproc = &opti621_tune_drive;
}
diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c
index c161e58b6..30baff570 100644
--- a/drivers/block/pdc4030.c
+++ b/drivers/block/pdc4030.c
@@ -72,9 +72,7 @@ static void promise_selectproc (ide_drive_t *drive)
{
unsigned int number;
- OUT_BYTE(drive->select.all,IDE_SELECT_REG);
- udelay(1); /* paranoia */
- number = ((HWIF(drive)->is_pdc4030_2)<<1) + drive->select.b.unit;
+ number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
OUT_BYTE(number,IDE_FEATURE_REG);
}
@@ -134,7 +132,7 @@ int init_pdc4030 (void)
drive = &hwif->drives[0];
second_hwif = &ide_hwifs[hwif->index+1];
- if(hwif->is_pdc4030_2) /* we've already been found ! */
+ if(hwif->chipset == ide_pdc4030) /* we've already been found ! */
return 1;
if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
@@ -172,6 +170,7 @@ int init_pdc4030 (void)
hwif->chipset = second_hwif->chipset = ide_pdc4030;
hwif->mate = second_hwif;
second_hwif->mate = hwif;
+ second_hwif->channel = 1;
hwif->selectproc = second_hwif->selectproc = &promise_selectproc;
/* Shift the remaining interfaces down by one */
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
@@ -182,7 +181,6 @@ int init_pdc4030 (void)
h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET];
h->noprobe = (h-1)->noprobe;
}
- second_hwif->is_pdc4030_2 = 1;
ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL);
second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET];
second_hwif->irq = hwif->irq;
diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c
index 296aef3a7..9c13bfea9 100644
--- a/drivers/block/qd6580.c
+++ b/drivers/block/qd6580.c
@@ -65,4 +65,5 @@ void init_qd6580 (void)
ide_hwifs[0].tuneproc = &tune_qd6580;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}
diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c
index b7270c559..670fe3e58 100644
--- a/drivers/block/rz1000.c
+++ b/drivers/block/rz1000.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/rz1000.c Version 0.03 Mar 20, 1996
+ * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
*
- * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
*/
/*
@@ -9,6 +9,8 @@
*
* This file provides support for disabling the buggy read-ahead
* mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ * Dunno if this fixes both ports, or only the primary port (?).
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -26,21 +28,40 @@
#include <linux/pci.h>
#include "ide.h"
-static void init_rz1000 (byte bus, byte fn, const char *name)
+#ifdef CONFIG_BLK_DEV_IDEPCI
+
+__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */
+{
+ unsigned short reg;
+
+ hwif->chipset = ide_rz1000;
+ if (!pcibios_read_config_word (hwif->pci_bus, hwif->pci_fn, 0x40, &reg)
+ && !pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, 0x40, reg & 0xdfff))
+ {
+ printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
+ } else {
+ hwif->serialized = 1;
+ hwif->drives[0].no_unmask = 1;
+ hwif->drives[1].no_unmask = 1;
+ printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
+ }
+}
+
+#else
+
+__initfunc(static void init_rz1000 (byte bus, byte fn, const char *name))
{
unsigned short reg, h;
- printk("%s: buggy IDE controller: ", name);
if (!pcibios_read_config_word (bus, fn, PCI_COMMAND, &reg) && !(reg & 1)) {
- printk("disabled (BIOS)\n");
+ printk("%s: buggy IDE controller disabled (BIOS)\n", name);
return;
}
if (!pcibios_read_config_word (bus, fn, 0x40, &reg)
&& !pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))
{
- printk("disabled read-ahead\n");
+ printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
} else {
- printk("\n");
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
@@ -50,13 +71,15 @@ static void init_rz1000 (byte bus, byte fn, const char *name)
hwif->serialized = 1;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
- printk(" %s: serialized, disabled unmasking\n", hwif->name);
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+ hwif->channel = 1;
+ printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
}
}
}
}
-void ide_probe_for_rz100x (void)
+__initfunc(void ide_probe_for_rz100x (void)) /* called from ide.c */
{
byte index, bus, fn;
@@ -65,3 +88,5 @@ void ide_probe_for_rz100x (void)
for (index = 0; !pcibios_find_device (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, index, &bus, &fn); ++index)
init_rz1000 (bus, fn, "RZ1001");
}
+
+#endif CONFIG_BLK_DEV_IDEPCI
diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c
index 7b8fb308c..f88f597d8 100644
--- a/drivers/block/trm290.c
+++ b/drivers/block/trm290.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/trm290.c Version 1.00 December 3, 1997
+ * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
*
* Copyright (c) 1997-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -34,18 +34,20 @@
* The configuration registers are addressed in normal I/O port space
* and are used as follows:
*
- * 0x3df2 when WRITTEN: chiptest register (byte, write-only)
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
* bit7 must always be written as "1"
* bits6-2 undefined
* bit1 1=legacy_compatible_mode, 0=native_pci_mode
* bit0 1=test_mode, 0=normal(default)
*
- * 0x3df2 when READ: status register (byte, read-only)
+ * trm290_base+2 when READ: status register (byte, read-only)
* bits7-2 undefined
* bit1 channel0 busmaster interrupt status 0=none, 1=asserted
* bit0 channel0 interrupt status 0=none, 1=asserted
*
- * 0x3df3 Interrupt mask register
+ * trm290_base+3 Interrupt mask register
* bits7-5 undefined
* bit4 legacy_header: 1=present, 0=absent
* bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
@@ -53,7 +55,7 @@
* bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
* bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
*
- * 0x3df1 "CPR" Config Pointer Register (byte)
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
* bit7 1=autoincrement CPR bits 2-0 after each access of CDR
* bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
* bit5 0=enabled master burst access (default), 1=disable (write only)
@@ -61,7 +63,7 @@
* bit3 0=primary IDE channel, 1=secondary IDE channel
* bits2-0 register index for accesses through CDR port
*
- * 0x3df0 "CDR" Config Data Register (word)
+ * trm290_base+0 "CDR" Config Data Register (word)
* two sets of seven config registers,
* selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
* each index defined below:
@@ -130,98 +132,137 @@
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+
#include <asm/io.h>
#include "ide.h"
-static void select_dma_or_pio(ide_hwif_t *hwif, int dma)
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- static int previous[2] = {-1,-1};
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int reg;
unsigned long flags;
- if (previous[hwif->pci_port] != dma) {
- unsigned short cfg1 = dma ? 0xa3 : 0x21;
- previous[hwif->pci_port] = dma;
- save_flags(flags);
- cli();
- outb(0x51|(hwif->pci_port<<3),0x3df1);
- outw(cfg1,0x3df0);
- restore_flags(flags);
+ /* select PIO or DMA */
+ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+ save_flags(flags);
+ cli();
+
+ if (reg != hwif->select_data) {
+ hwif->select_data = reg;
+ outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */
+ outw(reg & 0xff, hwif->config_data);
+ }
+
+ /* enable IRQ if not probing */
+ if (drive->present) {
+ reg = inw(hwif->config_data+3) & 0x13;
+ reg &= ~(1 << hwif->channel);
+ outw(reg, hwif->config_data+3);
}
+
+ restore_flags(flags);
}
-/*
- * trm290_dma_intr() is the handler for trm290 disk read/write DMA interrupts
- */
-static void trm290_dma_intr (ide_drive_t *drive)
+static void trm290_selectproc (ide_drive_t *drive)
{
- byte stat;
- int i;
- struct request *rq = HWGROUP(drive)->rq;
-
- stat = GET_STAT(); /* get drive status */
- if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
- unsigned short dma_stat = inw(HWIF(drive)->dma_base + 2);
- if (dma_stat == 0x00ff) {
- rq = HWGROUP(drive)->rq;
- for (i = rq->nr_sectors; i > 0;) {
- i -= rq->current_nr_sectors;
- ide_end_request(1, HWGROUP(drive));
- }
- return;
- }
- printk("%s: bad trm290 DMA status: 0x%04x\n", drive->name, dma_stat);
- }
- sti();
- ide_error(drive, "dma_intr", stat);
+ trm290_prepare_drive(drive, drive->using_dma);
}
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned int count, reading = 1 << 1;
+ unsigned int count, reading = 2, writing = 0;
- if (drive->media == ide_disk) {
- switch (func) {
- case ide_dma_write:
- reading = 0;
+ switch (func) {
+ case ide_dma_write:
+ reading = 0;
+ writing = 1;
#ifdef TRM290_NO_DMA_WRITES
- break; /* always use PIO for writes */
+ break; /* always use PIO for writes */
#endif
- case ide_dma_read:
- if (!(count = ide_build_dmatable(drive)))
- break; /* try PIO instead of DMA */
- select_dma_or_pio(hwif, 1); /* select DMA mode */
- outl_p(virt_to_bus(hwif->dmatable)|reading, hwif->dma_base);
- outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
- ide_set_handler(drive, &trm290_dma_intr, WAIT_CMD);
- OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ case ide_dma_read:
+ if (!(count = ide_build_dmatable(drive)))
+ break; /* try PIO instead of DMA */
+ trm290_prepare_drive(drive, 1); /* select DMA xfer */
+ outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base);
+ outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
+ if (drive->media != ide_disk)
return 0;
- default:
- return ide_dmaproc(func, drive);
- }
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ case ide_dma_begin:
+ return 0;
+ case ide_dma_end:
+ return (inw(hwif->dma_base+2) != 0x00ff);
+ default:
+ return ide_dmaproc(func, drive);
}
- select_dma_or_pio(hwif, 0); /* force PIO mode for this operation */
+ trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
-static void trm290_selectproc (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
-
- select_dma_or_pio(hwif, drive->using_dma);
- OUT_BYTE(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-}
-
/*
* Invoked from ide-dma.c at boot time.
*/
-__initfunc(void ide_init_trm290 (byte bus, byte fn, ide_hwif_t *hwif))
+__initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
{
+ unsigned int cfgbase = 0;
+ unsigned long flags;
+ byte reg, progif;
+
hwif->chipset = ide_trm290;
- hwif->selectproc = trm290_selectproc;
- hwif->drives[0].autotune = 2; /* play it safe */
- hwif->drives[1].autotune = 2; /* play it safe */
- ide_setup_dma(hwif, hwif->pci_port ? 0x3d74 : 0x3df4, 2);
+ if (!pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, 0x09, &progif) && (progif & 5)
+ && !pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x20, &cfgbase) && cfgbase)
+ {
+ hwif->config_data = cfgbase & ~1;
+ printk("TRM290: chip config base at 0x%04x\n", hwif->config_data);
+ } else {
+ hwif->config_data = 0x3df4;
+ printk("TRM290: using default config base at 0x%04x\n", hwif->config_data);
+ }
+
+ save_flags(flags);
+ cli();
+ /* put config reg into first byte of hwif->select_data */
+ outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+ hwif->select_data = 0x21; /* select PIO as default */
+ outb(hwif->select_data, hwif->config_data);
+ reg = inb(hwif->config_data+3); /* get IRQ info */
+ reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */
+ outb(reg, hwif->config_data+3);
+ restore_flags(flags);
+
+ if ((reg & 0x10))
+ hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
+ ide_setup_dma(hwif, (hwif->channel ? hwif->config_data ^ 0x0080 : hwif->config_data) + 4, 2);
hwif->dmaproc = &trm290_dmaproc;
+ hwif->selectproc = &trm290_selectproc;
+ hwif->no_autodma = 1; /* play it safe for now */
+#if 1
+ {
+ /*
+ * My trm290-based card doesn't seem to work with all possible values
+ * for the control basereg, so this kludge ensures that we use only
+ * values that are known to work. Ugh. -ml
+ */
+ unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+ static unsigned short next_offset = 0;
+
+ outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+ old = inw(hwif->config_data) & ~1;
+ if (old != compat && inb(old+2) == 0xff) {
+ compat += (next_offset += 0x400); /* leave lower 10 bits untouched */
+ hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; /* FIXME: should do a check_region */
+ outw(compat|1, hwif->config_data);
+ printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
+ }
+ }
+#endif
}
diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c
index 628e13bb5..8856dad35 100644
--- a/drivers/block/umc8672.c
+++ b/drivers/block/umc8672.c
@@ -153,4 +153,5 @@ void init_umc8672 (void) /* called from ide.c */
ide_hwifs[1].tuneproc = &tune_umc;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 849487b19..c17ae5e14 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -17,6 +17,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
+#include <linux/delay.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
@@ -205,16 +206,21 @@ static volatile unsigned char resend = 0;
/*
* Wait for keyboard controller input buffer is empty.
+ *
+ * Don't use 'jiffies' so that we don't depend on
+ * interrupts..
*/
static inline void kb_wait(void)
{
- unsigned long start = jiffies;
+ unsigned long timeout = KBC_TIMEOUT;
do {
if (! (kbd_read_status() & KBD_STAT_IBF))
return;
- } while (jiffies - start < KBC_TIMEOUT);
+ udelay(1000);
+ timeout--;
+ } while (timeout);
#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timed out\n");
#endif
@@ -544,30 +550,35 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* send_data sends a character to the keyboard and waits
* for an acknowledge, possibly retrying if asked to. Returns
* the success status.
+ *
+ * Don't use 'jiffies', so that we don't depend on interrupts
*/
static int send_data(unsigned char data)
{
int retries = 3;
- unsigned long start;
do {
+ unsigned long timeout = KBD_TIMEOUT;
+
kb_wait();
acknowledge = 0;
resend = 0;
reply_expected = 1;
kbd_write_output(data);
kbd_pause();
- start = jiffies;
- do {
+ for (;;) {
if (acknowledge)
return 1;
- if (jiffies - start >= KBD_TIMEOUT) {
+ if (resend)
+ break;
+ udelay(1000);
+ if (!--timeout) {
#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timeout\n");
#endif
return 0;
}
- } while (!resend);
+ }
} while (retries-- > 0);
#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index ffbfc49e2..a70763bf0 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -15,9 +15,9 @@
#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_INIT_TIMEOUT HZ /* Timeout for initializing the keyboard */
-#define KBC_TIMEOUT (HZ/4) /* Timeout for sending to keyboard controller */
-#define KBD_TIMEOUT (HZ/4) /* Timeout for keyboard command acknowledge */
+#define KBD_INIT_TIMEOUT HZ /* Timeout in jiffies for initializing the keyboard */
+#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 250 /* Timeout in ms for keyboard command acknowledge */
/*
* Internal variables of the driver
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 207fc4cf4..2226f9f3c 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -30,6 +30,7 @@
* code bits, and added compatibility to 2.1.x.
* 970912 Enabled board on open and disable on close.
* 971107 Took account of recent VFS changes (broke read).
+ * 971210 Disable board on initialisation in case board already ticking.
*/
#include <linux/module.h>
@@ -579,6 +580,12 @@ __initfunc(int pcwatchdog_init(void))
pcwd_showprevstate();
+ /* Disable the board */
+ if (revision == PCWD_REVISION_C) {
+ outb_p(0xA5, current_readport + 3);
+ outb_p(0xA5, current_readport + 3);
+ }
+
if (revision == PCWD_REVISION_A)
request_region(current_readport, 2, "PCWD Rev.A (Berkshire)");
else
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index ae1f06c99..d645ce165 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -323,7 +323,7 @@ inline static void adapter_reset(struct device *dev)
* never happen in theory, but seems to occur occasionally if the card gets
* prodded at the wrong time.
*/
-static inline void check_dma(struct device *dev)
+static inline void check_3c505_dma(struct device *dev)
{
elp_device *adapter = dev->priv;
if (adapter->dmaing && (jiffies > (adapter->current_dma.start_time + 10))) {
@@ -406,7 +406,7 @@ static int send_pcb(struct device *dev, pcb_struct * pcb)
int timeout;
elp_device *adapter = dev->priv;
- check_dma(dev);
+ check_3c505_dma(dev);
if (adapter->dmaing && adapter->current_dma.direction == 0)
return FALSE;
@@ -723,7 +723,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
}
} else {
/* has one timed out? */
- check_dma(dev);
+ check_3c505_dma(dev);
}
sti();
@@ -1088,7 +1088,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev)
return 1;
}
- check_dma(dev);
+ check_3c505_dma(dev);
/*
* if the transmitter is still busy, we have a transmit timeout...
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c2fa5b507..4202f8ef6 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1,31 +1,60 @@
-/* 3c59x.c: A 3Com 3c590/3c595 "Vortex" ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
/*
- Written 1995 by Donald Becker.
+ Written 1996-1997 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
- This driver is for the 3Com "Vortex" series ethercards. Members of
- the series include the 3c590 PCI EtherLink III and 3c595-Tx PCI Fast
- EtherLink.
+ This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
+ Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
+ and the EtherLink XL 3c900 and 3c905 cards.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
*/
-static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";
+static char *version =
+"3c59x.c:v0.46B 9/25/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-/* "Knobs" that turn on special features. */
-/* Enable the experimental automatic media selection code. */
+/* "Knobs" that adjust features and parameters. */
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ Setting to > 1512 effectively disables this feature. */
+static const rx_copybreak = 200;
+/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
+static const mtu = 1500;
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Enable the automatic media selection code -- usually set. */
#define AUTOMEDIA 1
-/* Allow the use of bus master transfers instead of programmed-I/O for the
- Tx process. Bus master transfers are always disabled by default, but
- iff this is set they may be turned on using 'options'. */
+/* Allow the use of fragment bus master transfers instead of only
+ programmed-I/O for Vortex cards. Full-bus-master transfers are always
+ enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined,
+ the feature may be turned on using 'options'. */
#define VORTEX_BUS_MASTER
+
+/* A few values that may be tweaked. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT ((400*HZ)/1000)
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+
#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -36,16 +65,10 @@ static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <linux/delay.h>
-
-#ifdef CONFIG_PCI
#include <linux/pci.h>
#include <linux/bios32.h>
-#endif
-
#include <linux/timer.h>
+#include <asm/irq.h> /* For NR_IRQS only. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -53,27 +76,60 @@ static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h> /* Redundant above, here for easy clean-up. */
+#endif
+#if LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x) /* What to put in timer->expires. */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#if defined(__alpha)
+#error "The Alpha architecture is only support with kernel version 2.0."
+#endif
+#define virt_to_bus(addr) ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+#else /* 1.3.0 and later */
#define RUN_AT(x) (jiffies + (x))
#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+#ifdef SA_SHIRQ
#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#else
+#define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
/* "Knobs" for adjusting internal parameters. */
/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 2
-
-/* Number of times to check to see if the Tx FIFO has space, used in some
- limited cases. */
-#define WAIT_TX_AVAIL 200
+#define VORTEX_DEBUG 1
+/* Some values here only for performance evaluation and path-coverage
+ debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
/* Operational parameter that usually are not changed. */
-#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */
-/* The total size is twice that of the original EtherLinkIII series: the
- runtime register window, window 1, is now always mapped in. */
+/* The Vortex size is twice that of the original EtherLinkIII series: the
+ runtime register window, window 1, is now always mapped in.
+ The Boomerang size is twice as large as the Vortex -- it has additional
+ bus master control registers. */
#define VORTEX_TOTAL_SIZE 0x20
+#define BOOMERANG_TOTAL_SIZE 0x40
#ifdef HAVE_DEVLIST
struct netdev_entry tc59x_drv =
@@ -86,27 +142,40 @@ static int vortex_debug = VORTEX_DEBUG;
static int vortex_debug = 1;
#endif
-#ifdef CONFIG_PCI
-static int product_ids[] __initdata = {0x5900, 0x5950, 0x5951, 0x5952, 0, 0};
-#endif
+/* Set iff a MII transceiver on any interface requires mdio preamble. */
+static char mii_preamble_required = 0;
+/* Caution! These entries must be consistent, with the EISA ones last. */
+static const int product_ids[] = {
+ 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0};
static const char *product_names[] = {
"3c590 Vortex 10Mbps",
"3c595 Vortex 100baseTX",
"3c595 Vortex 100baseT4",
"3c595 Vortex 100base-MII",
- "EISA Vortex 3c597",
+ "3c900 Boomerang 10baseT",
+ "3c900 Boomerang 10Mbps/Combo",
+ "3c905 Boomerang 100baseTx",
+ "3c905 Boomerang 100baseT4",
+ "3c592 EISA 10mbps Demon/Vortex",
+ "3c597 EISA Fast Demon/Vortex",
};
-#define DEMON_INDEX 5 /* Caution! Must be consistent with above! */
+#define DEMON10_INDEX 8
+#define DEMON100_INDEX 9
/*
Theory of Operation
I. Board Compatibility
-This device driver is designed for the 3Com FastEtherLink, 3Com's PCI to
-10/100baseT adapter. It also works with the 3c590, a similar product
-with only a 10Mbs interface.
+This device driver is designed for the 3Com FastEtherLink and FastEtherLink
+XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs
+versions of the FastEtherLink cards. The supported product IDs are
+ 3c590, 3c592, 3c595, 3c597, 3c900, 3c905
+
+The ISA 3c515 is supported with a seperate driver, 3c515.c, included with
+the kernel source or available from
+ cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
II. Board-specific settings
@@ -122,12 +191,33 @@ The 3c59x series use an interface that's very similar to the previous 3c5x9
series. The primary interface is two programmed-I/O FIFOs, with an
alternate single-contiguous-region bus-master transfer (see next).
+The 3c900 "Boomerang" series uses a full-bus-master interface with seperate
+lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
+DEC Tulip and Intel Speedo3. The first chip version retains a compatible
+programmed-I/O interface that will be removed in the 'B' and subsequent
+revisions.
+
One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters. Unfortunately this capability is only for
-a single contiguous region making it less useful than the list of transfer
-regions available with the DEC Tulip or AMD PCnet. Given the significant
-performance impact of taking an extra interrupt for each transfer, using
-DMA transfers is a win only with large blocks.
+are capable of being bus masters. On the Vortex chip this capability was
+only for a single contiguous region making it far less useful than the full
+bus master capability. There is a significant performance impact of taking
+an extra interrupt or polling for the completion of each transfer, as well
+as difficulty sharing the single transfer engine between the transmit and
+receive threads. Using DMA transfers is a win only with large blocks or
+with the flawed versions of the Intel Orion motherboard PCI controller.
+
+The Boomerang chip's full-bus-master interface is useful, and has the
+currently-unused advantages over other similar chips that queued transmit
+packets may be reordered and receive buffer groups are associated with a
+single frame.
+
+With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
+Tather than a fixed intermediate receive buffer, this scheme allocates
+full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as
+the copying breakpoint: it is chosen to trade-off the memory wasted by
+passing the full-sized skbuff to the queue layer for all frames vs. the
+copying cost of copying a frame to a correctly-sized skbuff.
+
IIIC. Synchronization
The driver runs as two independent, single-threaded flows of control. One
@@ -137,8 +227,8 @@ threaded by the hardware and other software.
IV. Notes
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing both
-3c590 and 3c595 boards.
+Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
+3c590, 3c595, and 3c900 boards.
The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
the EISA version is called "Demon". According to Terry these names come
from rides at the local amusement park.
@@ -169,8 +259,10 @@ limit of 4K.
enum vortex_cmd {
TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
- TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+ RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
+ UpStall = 6<<11, UpUnstall = (6<<11)+1,
+ DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
+ RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
SetTxThreshold = 18<<11, SetTxStart = 19<<11,
@@ -185,7 +277,8 @@ enum RxFilter {
enum vortex_status {
IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080, DMADone = 1<<8,
+ IntReq = 0x0040, StatsFull = 0x0080,
+ DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
DMAInProgress = 1<<11, /* DMA controller is still busy.*/
CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/
};
@@ -200,6 +293,7 @@ enum Window1 {
enum Window0 {
Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
Wn0EepromData = 12, /* Window 0: EEPROM results register. */
+ IntrStatus=0x0E, /* Valid in all windows. */
};
enum Win0_EEPROM_bits {
EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
@@ -222,12 +316,12 @@ union wn3_config {
unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
int pad8:8;
unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
- int pad24:8;
+ int pad24:7;
} u;
};
-enum Window4 {
- Wn4_Media = 0x0A, /* Window 4: Various transcvr/media bits. */
+enum Window4 { /* Window 4: Xcvr/media bits. */
+ Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
};
enum Win4_Media_bits {
Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
@@ -238,12 +332,54 @@ enum Win4_Media_bits {
enum Window7 { /* Window 7: Bus Master control. */
Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
};
+/* Boomerang bus master control registers. */
+enum MasterCtrl {
+ PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
+ TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
+};
+
+/* The Rx and Tx descriptor lists.
+ Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
+ alignment contraint on tx_ring[] and rx_ring[]. */
+#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */
+struct boom_rx_desc {
+ u32 next; /* Last entry points to 0. */
+ s32 status;
+ u32 addr; /* Up to addr/len possible.. */
+ s32 length; /* set high bit to indicate last pair. */
+};
+/* Values for the Rx status entry. */
+enum rx_desc_status {
+ RxDComplete=0x00008000, RxDError=0x4000,
+ /* See boomerang_rx() for actual error bits */
+};
+
+struct boom_tx_desc {
+ u32 next; /* Last entry points to 0. */
+ s32 status; /* bits 0:12 length, others see below. */
+ u32 addr;
+ s32 length;
+};
+
+/* Values for the Tx status entry. */
+enum tx_desc_status {
+ CRCDisable=0x2000, TxDComplete=0x8000,
+ TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */
+};
struct vortex_private {
char devname[8]; /* "ethN" string, also for kernel debug. */
const char *product_name;
struct device *next_module;
- struct net_device_stats stats;
+ /* The Rx and Tx rings are here to keep them quad-word-aligned. */
+ struct boom_rx_desc rx_ring[RX_RING_SIZE];
+ struct boom_tx_desc tx_ring[TX_RING_SIZE];
+ /* The addresses of transmit- and receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ struct enet_statistics stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
int options; /* User-settable misc. driver options. */
@@ -251,12 +387,23 @@ struct vortex_private {
unsigned int available_media:8, /* From Wn3_Options */
media_override:3, /* Passed-in media type. */
default_media:3, /* Read from the EEPROM. */
- full_duplex:1, bus_master:1, autoselect:1;
+ full_duplex:1, autoselect:1,
+ bus_master:1, /* Vortex can only do a fragment bus-m. */
+ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
+ tx_full:1;
+ u16 capabilities; /* Adapter capabilities word. */
+ u16 info1, info2; /* Software information information. */
+ unsigned char phys[2]; /* MII device addresses. */
};
/* The action to take with a media selection timer tick.
Note that we deviate from the 3Com order by checking 10base2 before AUI.
*/
+enum xcvr_types {
+ XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+ XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+};
+
static struct media_table {
char *name;
unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
@@ -264,30 +411,44 @@ static struct media_table {
next:8; /* The media type to try next. */
short wait; /* Time before we check media status. */
} media_tbl[] = {
- { "10baseT", Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10},
- { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10},
- { "undefined", 0, 0x80, 0 /* Undefined */, 0},
- { "10base2", 0, 0x10, 1 /* 10base2->AUI. */, (1*HZ)/10},
- { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10},
- { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10},
- { "MII", 0, 0x40, 0 /* MII->10baseT */, (14*HZ)/10},
- { "undefined", 0, 0x01, 0 /* Undefined/100baseT4 */, 0},
- { "Default", 0, 0xFF, 0 /* Use default */, 0},
+ { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
+ { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
+ { "undefined", 0, 0x80, XCVR_10baseT, 10000},
+ { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
+ { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
+ { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
+ { "MII", 0, 0x40, XCVR_10baseT, 3*HZ },
+ { "undefined", 0, 0x01, XCVR_10baseT, 10000},
+ { "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
static int vortex_scan(struct device *dev);
-static int vortex_found_device(struct device *dev, int ioaddr, int irq,
- int product_index, int options);
+static struct device *vortex_found_device(struct device *dev, int ioaddr,
+ int irq, int product_index,
+ int options, int card_idx);
static int vortex_probe1(struct device *dev);
static int vortex_open(struct device *dev);
+static void mdio_sync(int ioaddr, int bits);
+static int mdio_read(int ioaddr, int phy_id, int location);
+#ifdef HAVE_PRIVATE_IOCTL
+static void mdio_write(int ioaddr, int phy_id, int location, int value);
+#endif
static void vortex_timer(unsigned long arg);
static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
+static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
static int vortex_rx(struct device *dev);
+static int boomerang_rx(struct device *dev);
static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
static int vortex_close(struct device *dev);
static void update_stats(int addr, struct device *dev);
-static struct net_device_stats *vortex_get_stats(struct device *dev);
+static struct enet_statistics *vortex_get_stats(struct device *dev);
static void set_rx_mode(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
+#ifndef NEW_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
/* Unlike the other PCI cards the 59x cards don't need a large contiguous
@@ -307,11 +468,15 @@ static void set_rx_mode(struct device *dev);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
/* Note: this is the only limit on the number of cards supported!! */
static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* A list of all installed Vortex devices, for removing the driver module. */
+static struct device *root_vortex_dev = NULL;
+
+/* Variables to work-around the Compaq PCI BIOS32 problem. */
+static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0;
#ifdef MODULE
static int debug = -1;
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct device *root_vortex_dev = NULL;
int
init_module(void)
@@ -329,7 +494,7 @@ init_module(void)
}
#else
-__initfunc(int tc59x_probe(struct device *dev))
+int tc59x_probe(struct device *dev)
{
int cards_found = 0;
@@ -342,100 +507,148 @@ __initfunc(int tc59x_probe(struct device *dev))
}
#endif /* not MODULE */
-__initfunc(static int vortex_scan(struct device *dev))
+static int vortex_scan(struct device *dev)
{
int cards_found = 0;
-#ifdef CONFIG_PCI
+#ifndef NO_PCI /* Allow an EISA-only driver. */
+ /* Ideally we would detect all cards in slot order. That would
+ be best done a central PCI probe dispatch, which wouldn't work
+ well with the current structure. So instead we detect 3Com cards
+ in slot order. */
if (pcibios_present()) {
static int pci_index = 0;
- static int board_index = 0;
- for (; product_ids[board_index]; board_index++, pci_index = 0) {
- for (; pci_index < 16; pci_index++) {
- unsigned char pci_bus, pci_device_fn, pci_irq_line;
- unsigned char pci_latency;
- unsigned int pci_ioaddr;
- unsigned short pci_command;
-
- if (pcibios_find_device(TCOM_VENDOR_ID,
- product_ids[board_index], pci_index,
- &pci_bus, &pci_device_fn))
+ unsigned char pci_bus, pci_device_fn;
+
+ for (;pci_index < 0xff; pci_index++) {
+ unsigned char pci_irq_line, pci_latency;
+ unsigned short pci_command, vendor, device;
+ unsigned int pci_ioaddr;
+
+ int board_index = 0;
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+ pci_index, &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
+
+ if (vendor != TCOM_VENDOR_ID)
+ continue;
+
+ for (board_index = 0; product_ids[board_index]; board_index++) {
+ if (device == product_ids[board_index])
break;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
+ }
+ if (product_ids[board_index] == 0) {
+ printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:"
+ " not configured.\n", device);
+ continue;
+ }
+ if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
+ continue;
-#ifdef VORTEX_BUS_MASTER
+ dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
+ board_index, dev && dev->mem_start
+ ? dev->mem_start : options[cards_found],
+ cards_found);
+
+ if (dev) {
/* Get and check the bus-master and latency values.
Some PCI BIOSes fail to set the master-enable bit, and
the latency timer must be set to the maximum value to avoid
data corruption that occurs when the timer expires during
- a transfer. Yes, it's a bug. */
+ a transfer -- a bug in the Vortex chip. */
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_COMMAND, &pci_command);
if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(" PCI Master Bit has not been set! Setting...\n");
+ printk("%s: PCI Master Bit has not been set! "
+ " Setting...\n", dev->name);
pci_command |= PCI_COMMAND_MASTER;
pcibios_write_config_word(pci_bus, pci_device_fn,
PCI_COMMAND, pci_command);
}
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency != 255) {
- printk(" Overriding PCI latency timer (CFLT) setting of"
- " %d, new value is 255.\n", pci_latency);
+ if (pci_latency != 248) {
+ printk("%s: Overriding PCI latency"
+ " timer (CFLT) setting of %d, new value is 248.\n",
+ dev->name, pci_latency);
pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 255);
+ PCI_LATENCY_TIMER, 248);
}
-#endif /* VORTEX_BUS_MASTER */
- vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index,
- dev && dev->mem_start ? dev->mem_start
- : options[cards_found]);
dev = 0;
cards_found++;
}
}
}
-#endif /* CONFIG_PCI */
+#endif /* NO_PCI */
/* Now check all slots of the EISA bus. */
if (EISA_bus) {
static int ioaddr = 0x1000;
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int product_id, product_index;
+ if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
+ continue;
/* Check the standard EISA ID register for an encoded '3Com'. */
if (inw(ioaddr + 0xC80) != 0x6d50)
continue;
/* Check for a product that we support, 3c59{2,7} any rev. */
- if ((inw(ioaddr + 0xC82) & 0xF0FF) != 0x7059 /* 597 */
- && (inw(ioaddr + 0xC82) & 0xF0FF) != 0x2059) /* 592 */
+ product_id = inw(ioaddr + 0xC82) & 0xF0FF;
+ if (product_id == 0x7059) /* 597 */
+ product_index = DEMON100_INDEX;
+ else if (product_id == 0x2059) /* 592 */
+ product_index = DEMON10_INDEX;
+ else
continue;
vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- DEMON_INDEX, dev && dev->mem_start
- ? dev->mem_start : options[cards_found]);
+ product_index, dev && dev->mem_start
+ ? dev->mem_start : options[cards_found],
+ cards_found);
dev = 0;
cards_found++;
}
}
+ /* Special code to work-around the Compaq PCI BIOS32 problem. */
+ if (compaq_ioaddr) {
+ vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id,
+ dev && dev->mem_start ? dev->mem_start
+ : options[cards_found], cards_found);
+ cards_found++;
+ dev = 0;
+ }
+
+ /* Finally check for a 3c515 on the ISA bus. */
+ /* (3c515 support omitted on this version.) */
+
return cards_found;
}
-__initfunc(static int vortex_found_device(struct device *dev, int ioaddr, int irq,
- int product_index, int options))
+static struct device *
+vortex_found_device(struct device *dev, int ioaddr, int irq,
+ int product_index, int options, int card_idx)
{
struct vortex_private *vp;
#ifdef MODULE
/* Allocate and fill new device structure. */
int dev_size = sizeof(struct device) +
- sizeof(struct vortex_private);
-
+ sizeof(struct vortex_private) + 15; /* Pad for alignment */
+
dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
memset(dev, 0, dev_size);
- dev->priv = ((void *)dev) + sizeof(struct device);
+ /* Align the Rx and Tx ring entries. */
+ dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
vp = (struct vortex_private *)dev->priv;
dev->name = vp->devname; /* An empty string. */
dev->base_addr = ioaddr;
@@ -443,28 +656,36 @@ __initfunc(static int vortex_found_device(struct device *dev, int ioaddr, int ir
dev->init = vortex_probe1;
vp->product_name = product_names[product_index];
vp->options = options;
+ if (card_idx >= 0) {
+ if (full_duplex[card_idx] >= 0)
+ vp->full_duplex = full_duplex[card_idx];
+ } else
+ vp->full_duplex = (options >= 0 && (options & 0x10) ? 1 : 0);
+
if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
- vp->full_duplex = (options & 8) ? 1 : 0;
+ vp->media_override = ((options & 7) == XCVR_10baseTOnly) ?
+ XCVR_10baseT : options & 7;
vp->bus_master = (options & 16) ? 1 : 0;
} else {
vp->media_override = 7;
- vp->full_duplex = 0;
vp->bus_master = 0;
}
ether_setup(dev);
vp->next_module = root_vortex_dev;
root_vortex_dev = dev;
if (register_netdev(dev) != 0)
- return -EIO;
+ return 0;
#else /* not a MODULE */
if (dev) {
+ /* Caution: quad-word alignment required for rings! */
dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
memset(dev->priv, 0, sizeof (struct vortex_private));
}
dev = init_etherdev(dev, sizeof(struct vortex_private));
dev->base_addr = ioaddr;
dev->irq = irq;
+ dev->mtu = mtu;
+
vp = (struct vortex_private *)dev->priv;
vp->product_name = product_names[product_index];
vp->options = options;
@@ -480,13 +701,14 @@ __initfunc(static int vortex_found_device(struct device *dev, int ioaddr, int ir
vortex_probe1(dev);
#endif /* MODULE */
- return 0;
+ return dev;
}
-__initfunc(static int vortex_probe1(struct device *dev))
+static int vortex_probe1(struct device *dev)
{
int ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
printk("%s: 3Com %s at %#3x,", dev->name,
@@ -494,27 +716,33 @@ __initfunc(static int vortex_probe1(struct device *dev))
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 0x18; i++) {
short *phys_addr = (short *)dev->dev_addr;
int timer;
- outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd);
+ outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
- for (timer = 162*4 + 400; timer >= 0; timer--) {
- udelay(1);
+ for (timer = 4; timer >= 0; timer--) {
+ udelay(162);
if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
break;
}
- phys_addr[i] = htons(inw(ioaddr + Wn0EepromData));
+ eeprom[i] = inw(ioaddr + Wn0EepromData);
+ checksum ^= eeprom[i];
+ if (i >= 10 && i < 13)
+ phys_addr[i - 10] = htons(inw(ioaddr + Wn0EepromData));
}
+ checksum = (checksum ^ (checksum >> 8)) & 0xff;
+ if (checksum != 0x00)
+ printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
printk(", IRQ %d\n", dev->irq);
/* Tell them about an invalid IRQ. */
- if (vortex_debug && (dev->irq <= 0 || dev->irq > 15))
- printk(" *** Warning: this IRQ is unlikely to work!\n");
+ if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
+ printk(" *** Warning: this IRQ is unlikely to work! ***\n");
{
- char *ram_split[] = {"5:3", "3:1", "1:1", "invalid"};
+ char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
union wn3_config config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
@@ -532,8 +760,46 @@ __initfunc(static int vortex_probe1(struct device *dev))
vp->default_media = config.u.xcvr;
vp->autoselect = config.u.autoselect;
}
+ if (vp->media_override != 7) {
+ printk(" Media override to transceiver type %d (%s).\n",
+ vp->media_override, media_tbl[vp->media_override].name);
+ dev->if_port = vp->media_override;
+ }
- /* We do a request_region() only to register /proc/ioports info. */
+ if (dev->if_port == XCVR_MII) {
+ int phy, phy_idx = 0;
+ EL3WINDOW(4);
+ for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
+ int mii_status;
+ mdio_sync(ioaddr, 32);
+ mii_status = mdio_read(ioaddr, phy, 0);
+ if (mii_status != 0xffff) {
+ vp->phys[phy_idx++] = phy;
+ printk("%s: MII transceiver found at address %d.\n",
+ dev->name, phy);
+ mdio_sync(ioaddr, 32);
+ if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
+ mii_preamble_required = 1;
+ }
+ }
+ if (phy_idx == 0) {
+ printk("%s: ***WARNING*** No MII transceivers found!\n",
+ dev->name);
+ vp->phys[0] = 0;
+ }
+ }
+
+ vp->info1 = eeprom[13];
+ vp->info2 = eeprom[15];
+ vp->capabilities = eeprom[16];
+ if ((vp->capabilities & 0x20) && vp->bus_master) {
+ vp->full_bus_master_tx = 1;
+ printk(" Enabling bus-master transmits and %s receives.\n",
+ (vp->info2 & 1) ? "early" : "whole-frame" );
+ vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+ }
+
+ /* We do a request_region() to register /proc/ioports info. */
request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name);
/* The 3c59x-specific entries in the device structure. */
@@ -541,10 +807,97 @@ __initfunc(static int vortex_probe1(struct device *dev))
dev->hard_start_xmit = &vortex_start_xmit;
dev->stop = &vortex_close;
dev->get_stats = &vortex_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &vortex_ioctl;
+#endif
+#ifdef NEW_MULTICAST
dev->set_multicast_list = &set_rx_mode;
+#else
+ dev->set_multicast_list = &set_multicast_list;
+#endif
return 0;
}
+
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. The maxium data clock rate is 2.5 Mhz. */
+#define mdio_delay() udelay(1)
+
+#define MDIO_SHIFT_CLK 0x01
+#define MDIO_DIR_WRITE 0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ 0x02
+#define MDIO_ENB_IN 0x00
+
+static void mdio_sync(int ioaddr, int bits)
+{
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ while (-- bits >= 0) {
+ outw(MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+}
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ unsigned int retval = 0;
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
+ /* Shift the read command bits out. */
+ for (i = 14; i >= 0; i--) {
+ int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outw(dataval, mdio_addr);
+ mdio_delay();
+ outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outw(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return retval>>1 & 0xffff;
+}
+
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+ int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ int i;
+
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outw(dataval, mdio_addr);
+ mdio_delay();
+ outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Leave the interface idle. */
+ for (i = 1; i >= 0; i--) {
+ outw(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+
+ return;
+}
static int
@@ -557,8 +910,6 @@ vortex_open(struct device *dev)
/* Before initializing select the active media port. */
EL3WINDOW(3);
- if (vp->full_duplex)
- outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
config.i = inl(ioaddr + Wn3_Config);
if (vp->media_override != 7) {
@@ -569,7 +920,7 @@ vortex_open(struct device *dev)
dev->if_port = vp->media_override;
} else if (vp->autoselect) {
/* Find first available media type, starting with 100baseTx. */
- dev->if_port = 4;
+ dev->if_port = XCVR_100baseTx;
while (! (vp->available_media & media_tbl[dev->if_port].mask))
dev->if_port = media_tbl[dev->if_port].next;
@@ -588,6 +939,30 @@ vortex_open(struct device *dev)
config.u.xcvr = dev->if_port;
outl(config.i, ioaddr + Wn3_Config);
+ if (dev->if_port == XCVR_MII) {
+ int mii_reg1, mii_reg5;
+ /* We cheat here: we know that we are using the 83840 transceiver
+ which summarizes the FD status in an extended register. */
+ EL3WINDOW(4);
+ /* Read BMSR (reg1) only to clear old status. */
+ mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+ mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+ if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
+ ; /* No MII device or no link partner report */
+ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */
+ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+ vp->full_duplex = 1;
+ if (vortex_debug > 1)
+ printk("%s: MII #%d status %4.4x, link partner capability %4.4x,"
+ " setting %s-duplex.\n", dev->name, vp->phys[0],
+ mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+ EL3WINDOW(3);
+ }
+
+ /* Set the full-duplex bit. */
+ outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+ (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+
if (vortex_debug > 1) {
printk("%s: vortex_open() InternalConfig %8.8x.\n",
dev->name, config.i);
@@ -595,22 +970,32 @@ vortex_open(struct device *dev)
outw(TxReset, ioaddr + EL3_CMD);
for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
outw(RxReset, ioaddr + EL3_CMD);
/* Wait a few ticks for the RxReset command to complete. */
for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
+#ifdef SA_SHIRQ
/* Use the now-standard shared IRQ implementation. */
if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
vp->product_name, dev)) {
return -EAGAIN;
}
+#else
+ if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL)
+ return -EAGAIN;
+ irq2dev_map[dev->irq] = dev;
+ if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name)) {
+ irq2dev_map[dev->irq] = NULL;
+ return -EAGAIN;
+ }
+#endif
if (vortex_debug > 1) {
EL3WINDOW(4);
@@ -625,7 +1010,7 @@ vortex_open(struct device *dev)
for (; i < 12; i+=2)
outw(0, ioaddr + i);
- if (dev->if_port == 3)
+ if (dev->if_port == XCVR_10base2)
/* Start the thinnet transceiver. We should really wait 50ms...*/
outw(StartCoax, ioaddr + EL3_CMD);
EL3WINDOW(4);
@@ -635,18 +1020,52 @@ vortex_open(struct device *dev)
/* Switch to the stats window, and clear all stats by reading. */
outw(StatsDisable, ioaddr + EL3_CMD);
EL3WINDOW(6);
- for (i = 0; i < 10; i++)
+ for (i = 0; i < 10; i++)
inb(ioaddr + i);
inw(ioaddr + 10);
inw(ioaddr + 12);
/* New: On the Vortex we must also clear the BadSSD counter. */
EL3WINDOW(4);
inb(ioaddr + 12);
+ /* ..and on the Boomerang we enable the extra statistics bits. */
+ outw(0x0040, ioaddr + Wn4_NetDiag);
/* Switch to register set 7 for normal use. */
EL3WINDOW(7);
- /* Set receiver mode: presumably accept b-case and phys addr only. */
+ if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+ vp->cur_rx = vp->dirty_rx = 0;
+ /* Initialize the RxEarly register as recommended. */
+ outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
+ outl(0x0020, ioaddr + PktStatus);
+ if (vortex_debug > 2)
+ printk("%s: Filling in the Rx ring.\n", dev->name);
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb;
+ vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
+ vp->rx_ring[i].status = 0; /* Clear complete bit. */
+ vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
+ skb = dev_alloc_skb(PKT_BUF_SZ);
+ vp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+ vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+ }
+ vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
+ outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
+ }
+ if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
+ dev->hard_start_xmit = &boomerang_start_xmit;
+ vp->cur_tx = vp->dirty_tx = 0;
+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+ /* Clear the Tx ring. */
+ for (i = 0; i < TX_RING_SIZE; i++)
+ vp->tx_skbuff[i] = 0;
+ outl(0, ioaddr + DownListPtr);
+ }
+ /* Set reciever mode: presumably accept b-case and phys addr only. */
set_rx_mode(dev);
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
@@ -657,12 +1076,18 @@ vortex_open(struct device *dev)
outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
/* Allow status bits to be seen. */
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+ outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull|TxComplete|
+ (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+ (vp->full_bus_master_rx ? UpComplete : RxComplete) |
+ (vp->bus_master ? DMADone : 0),
+ ioaddr + EL3_CMD);
/* Ack all pending events, and set active indicator mask. */
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
ioaddr + EL3_CMD);
outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
- | DMADone, ioaddr + EL3_CMD);
+ | AdapterFailure | TxComplete
+ | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
+ ioaddr + EL3_CMD);
MOD_INC_USE_COUNT;
@@ -688,7 +1113,7 @@ static void vortex_timer(unsigned long data)
EL3WINDOW(4);
media_status = inw(ioaddr + Wn4_Media);
switch (dev->if_port) {
- case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */
+ case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
if (media_status & Media_LnkBeat) {
ok = 1;
if (vortex_debug > 1)
@@ -697,8 +1122,20 @@ static void vortex_timer(unsigned long data)
} else if (vortex_debug > 1)
printk("%s: Media %s is has no link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
-
+
break;
+ case XCVR_MII:
+ {
+ int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+ int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+ if (vortex_debug > 1)
+ printk("%s: MII #%d status register is %4.4x, "
+ "link partner capability %4.4x.\n",
+ dev->name, vp->phys[0], mii_reg1, mii_reg5);
+ if (mii_reg1 & 0x0004)
+ ok = 1;
+ break;
+ }
default: /* Other media types handled by Tx timeouts. */
if (vortex_debug > 1)
printk("%s: Media %s is has no indication, %x.\n",
@@ -711,7 +1148,7 @@ static void vortex_timer(unsigned long data)
do {
dev->if_port = media_tbl[dev->if_port].next;
} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
- if (dev->if_port == 8) { /* Go back to default. */
+ if (dev->if_port == XCVR_Default) { /* Go back to default. */
dev->if_port = vp->default_media;
if (vortex_debug > 1)
printk("%s: Media selection failing, using default %s port.\n",
@@ -731,7 +1168,8 @@ static void vortex_timer(unsigned long data)
config.u.xcvr = dev->if_port;
outl(config.i, ioaddr + Wn3_Config);
- outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+ outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
+ ioaddr + EL3_CMD);
}
EL3WINDOW(old_window);
} restore_flags(flags);
@@ -743,66 +1181,118 @@ static void vortex_timer(unsigned long data)
return;
}
-static int
-vortex_start_xmit(struct sk_buff *skb, struct device *dev)
+static void vortex_tx_timeout(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;
+ int i;
- /* Part of the following code is inspired by code from Giuseppe Ciaccio,
- ciaccio@disi.unige.it.
- It works around a ?bug? in the 8K Vortex that only occurs on some
- systems: the TxAvailable interrupt seems to be lost.
- The ugly work-around is to busy-wait for room available in the Tx
- buffer before deciding the transmitter is actually hung.
- This busy-wait should never really occur, since the problem is that
- there actually *is* room in the Tx FIFO.
-
- This pointed out an optimization -- we can ignore dev->tbusy if
- we actually have room for this packet.
- */
-
-#if 0
- /* unstable optimization */
- if (inw(ioaddr + TxFree) > skb->len) /* We actually have free room. */
- dev->tbusy = 0; /* Fake out the check below. */
- else
+ printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ dev->name, inb(ioaddr + TxStatus),
+ inw(ioaddr + EL3_STATUS));
+ /* Slight code bloat to be user friendly. */
+ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
+ printk("%s: Transmitter encountered 16 collisions --"
+ " network cable problem?\n", dev->name);
+ if (inw(ioaddr + EL3_STATUS) & IntLatch) {
+ printk("%s: Interrupt posted but not handled --"
+ " IRQ blocked by another device?\n", dev->name);
+ /* Bad idea here.. but we might as well handle a few events. */
+ vortex_interrupt IRQ(dev->irq, dev, 0);
+ }
+#ifndef final_version
+ if (vp->full_bus_master_tx) {
+ printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
+ vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+ printk(" Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+ &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ printk(" %d: @%p length %8.8x status %8.8x\n", i,
+ &vp->tx_ring[i],
+ vp->tx_ring[i].length,
+ vp->tx_ring[i].status);
+ }
+ }
+#ifdef notdef
+ if (vp->full_bus_master_rx) {
+ printk(" Switching to non-bus-master receives.\n");
+ outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
+ (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+ RxComplete | (vp->bus_master ? DMADone : 0),
+ ioaddr + EL3_CMD);
+ }
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (i = 20; i >= 0 ; i--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
#endif
- if (dev->tbusy) {
- /* Transmitter timeout, serious problems. */
- int tickssofar = jiffies - dev->trans_start;
- int i;
-
- if (tickssofar < 2) /* We probably aren't empty. */
- return 1;
- /* Wait a while to see if there really is room. */
- for (i = WAIT_TX_AVAIL; i >= 0; i--)
- if (inw(ioaddr + TxFree) > skb->len)
- break;
- if ( i < 0) {
- if (tickssofar < TX_TIMEOUT)
- return 1;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) break;
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- vp->stats.tx_errors++;
+#endif
+ if (vp->full_bus_master_tx) {
+ /* Change 6/25/97 Michael Sievers sieversm@mail.desy.de
+ The card has been resetted, but the Tx Ring is still full.
+ Since the card won't know where to resume, 'update' the
+ Tx Ring. Probably, we'll lose 16 packets this way, these
+ will be accounted for as 'dropped'. The code to update the
+ Tx Ring is taken from the Interrupt handler. */
+
+ unsigned int dirty_tx = vp->dirty_tx;
+
+ if (vortex_debug > 0)
+ printk("%s: Freeing Tx ring entries:", dev->name);
+ while (vp->cur_tx - dirty_tx > 0) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ if (inl(ioaddr + DownListPtr) ==
+ virt_to_bus(&vp->tx_ring[entry]))
+ break; /* It still hasn't been processed. */
+ if (vp->tx_skbuff[entry]) {
+ if (vortex_debug > 0)
+ printk(" %d\n", entry);
+ dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
+ vp->tx_skbuff[entry] = 0;
vp->stats.tx_dropped++;
- return 0; /* Yes, silently *drop* the packet! */
}
- dev->tbusy = 0;
+ if (vortex_debug > 0)
+ printk(".\n");
+ vp->stats.tx_errors++;
+ dirty_tx++;
+ }
+ vp->dirty_tx = dirty_tx;
+ vp->tx_full= 0;
+ } else { /* not bus-master, no Tx ring to clear */
+ vp->stats.tx_errors++;
+ vp->stats.tx_dropped++;
}
+
+ /* Issue Tx Enable */
+ outw(TxEnable, ioaddr + EL3_CMD);
+ dev->trans_start = jiffies;
+
+ /* Switch to register set 7 for normal use. */
+ EL3WINDOW(7);
+
+ /* The TxFreeThreshold has to be set again after a reset! */
+ if (vp->full_bus_master_tx) {
+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+ /* This is to be sure that all bus-master Tx features
+ are correctly re-initialized after a reset, although
+ the DownListPtr should already be 0 at this point. */
+ outl(0, ioaddr + DownListPtr);
+ }
+ /* finally, allow new Transmits */
+ dev->tbusy = 0;
+ /* End of Michael Sievers <sieversm@mail.desy.de> changes. */
+}
+
+static int
+vortex_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- If this ever occurs the queue layer is doing something evil! */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
+ if (jiffies - dev->trans_start >= TX_TIMEOUT)
+ vortex_tx_timeout(dev);
return 1;
}
@@ -855,7 +1345,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
int j;
outw(TxReset, ioaddr + EL3_CMD);
for (j = 20; j >= 0 ; j--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
outw(TxEnable, ioaddr + EL3_CMD);
@@ -866,16 +1356,80 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
return 0;
}
+static int
+boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ if (jiffies - dev->trans_start >= TX_TIMEOUT)
+ vortex_tx_timeout(dev);
+ return 1;
+ } else {
+ /* Calculate the next Tx descriptor entry. */
+ int entry = vp->cur_tx % TX_RING_SIZE;
+ struct boom_tx_desc *prev_entry =
+ &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
+ unsigned long flags;
+ int i;
+
+ if (vortex_debug > 3)
+ printk("%s: Trying to send a packet, Tx index %d.\n",
+ dev->name, vp->cur_tx);
+ if (vp->tx_full) {
+ if (vortex_debug >0)
+ printk("%s: Tx Ring full, refusing to send buffer.\n",
+ dev->name);
+ return 1;
+ }
+ /* end change 06/25/97 M. Sievers */
+ vp->tx_skbuff[entry] = skb;
+ vp->tx_ring[entry].next = 0;
+ vp->tx_ring[entry].addr = virt_to_bus(skb->data);
+ vp->tx_ring[entry].length = skb->len | LAST_FRAG;
+ vp->tx_ring[entry].status = skb->len | TxIntrUploaded;
+
+ save_flags(flags);
+ cli();
+ outw(DownStall, ioaddr + EL3_CMD);
+ /* Wait for the stall to complete. */
+ for (i = 60; i >= 0 ; i--)
+ if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
+ break;
+ prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
+ if (inl(ioaddr + DownListPtr) == 0) {
+ outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
+ queued_packet++;
+ }
+ outw(DownUnstall, ioaddr + EL3_CMD);
+ restore_flags(flags);
+
+ vp->cur_tx++;
+ if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+ vp->tx_full = 1;
+ else { /* Clear previous interrupt enable. */
+ prev_entry->status &= ~TxIntrUploaded;
+ dev->tbusy = 0;
+ }
+ dev->trans_start = jiffies;
+ return 0;
+ }
+}
+
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
{
- /* Use the now-standard shared IRQ implementation. */
+#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
struct device *dev = dev_id;
+#else
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
struct vortex_private *lp;
int ioaddr, status;
int latency;
- int i = 0;
+ int i = max_interrupt_work;
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
@@ -890,17 +1444,20 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
if (vortex_debug > 4)
printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
status, latency);
- if ((status & 0xE000) != 0xE000) {
+#ifdef notdef
+ /* This code guard against bogus hangs, but fails with shared IRQs. */
+ if ((status & ~0xE000) == 0x0000) {
static int donedidthis=0;
/* Some interrupt controllers store a bogus interrupt from boot-time.
Ignore a single early interrupt, but don't hang the machine for
other interrupt problems. */
- if (donedidthis++ > 1) {
+ if (donedidthis++ > 100) {
printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
dev->name, status, dev->start);
FREE_IRQ(dev->irq, dev);
}
}
+#endif
do {
if (vortex_debug > 5)
@@ -917,13 +1474,53 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
dev->tbusy = 0;
mark_bh(NET_BH);
}
+ if (status & TxComplete) { /* Really "TxError" for us. */
+ unsigned char tx_status = inb(ioaddr + TxStatus);
+ /* Presumably a tx-timeout. We must merely re-enable. */
+ if (vortex_debug > 2
+ || (tx_status != 0x88 && vortex_debug > 0))
+ printk("%s: Transmit error, Tx status register %2.2x.\n",
+ dev->name, tx_status);
+ if (tx_status & 0x04) lp->stats.tx_fifo_errors++;
+ if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ outb(0, ioaddr + TxStatus);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+ if (status & DownComplete) {
+ unsigned int dirty_tx = lp->dirty_tx;
+
+ while (lp->cur_tx - dirty_tx > 0) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ if (inl(ioaddr + DownListPtr) ==
+ virt_to_bus(&lp->tx_ring[entry]))
+ break; /* It still hasn't been processed. */
+ if (lp->tx_skbuff[entry]) {
+ dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+ lp->tx_skbuff[entry] = 0;
+ }
+ /* lp->stats.tx_packets++; Counted below. */
+ dirty_tx++;
+ }
+ lp->dirty_tx = dirty_tx;
+ outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
+ if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+ lp->tx_full= 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ }
#ifdef VORTEX_BUS_MASTER
if (status & DMADone) {
outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
dev->tbusy = 0;
+ dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
mark_bh(NET_BH);
}
#endif
+ if (status & UpComplete) {
+ boomerang_rx(dev);
+ outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+ }
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts at once. */
if (status & RxEarly) { /* Rx early is unused. */
@@ -949,27 +1546,45 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
printk(" %2.2x", inb(ioaddr+reg));
}
EL3WINDOW(7);
- outw(SetIntrEnb | 0x18, ioaddr + EL3_CMD);
+ outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
+ | UpComplete | DownComplete | TxComplete,
+ ioaddr + EL3_CMD);
DoneDidThat++;
}
}
if (status & AdapterFailure) {
- /* Adapter failure requires Rx reset and reinit. */
- outw(RxReset, ioaddr + EL3_CMD);
- /* Set the Rx filter to the current state. */
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ u16 fifo_diag;
+ EL3WINDOW(4);
+ fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+ if (vortex_debug > 0)
+ printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
+ dev->name, fifo_diag);
+ /* Adapter failure requires Tx/Rx reset and reinit. */
+ if (fifo_diag & 0x0400) {
+ int j;
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (j = 20; j >= 0 ; j--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+ if (fifo_diag & 0x2000) {
+ outw(RxReset, ioaddr + EL3_CMD);
+ /* Set the Rx filter to the current state. */
+ set_rx_mode(dev);
+ outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+ outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ }
}
}
- if (++i > 10) {
- printk("%s: Infinite loop in interrupt, status %4.4x. "
+ if (--i < 0) {
+ printk("%s: Too much work in interrupt, status %4.4x. "
"Disabling functions (%4.4x).\n",
- dev->name, status, SetStatusEnb | ((~status) & 0xFE));
+ dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
/* Disable all pending interrupts. */
- outw(SetStatusEnb | ((~status) & 0xFE), ioaddr + EL3_CMD);
- outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+ outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
+ outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
break;
}
/* Acknowledge the IRQ. */
@@ -998,7 +1613,7 @@ vortex_rx(struct device *dev)
while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
if (rx_status & 0x4000) { /* Error, update stats. */
unsigned char rx_error = inb(ioaddr + RxErrors);
- if (vortex_debug > 4)
+ if (vortex_debug > 2)
printk(" Rx error: status %2.2x.\n", rx_error);
vp->stats.rx_errors++;
if (rx_error & 0x01) vp->stats.rx_over_errors++;
@@ -1017,28 +1632,36 @@ vortex_rx(struct device *dev)
pkt_len, rx_status);
if (skb != NULL) {
skb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
(pkt_len + 3) >> 2);
+ outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
+#else
+ skb->len = pkt_len;
+ /* 'skb->data' points to the start of sk_buff data area. */
+ insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2);
outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+#endif /* KERNEL_1_3_0 */
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ vp->stats.rx_packets++;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
- vp->stats.rx_packets++;
continue;
} else if (vortex_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
}
- vp->stats.rx_dropped++;
outw(RxDiscard, ioaddr + EL3_CMD);
+ vp->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
@@ -1046,17 +1669,111 @@ vortex_rx(struct device *dev)
}
static int
+boomerang_rx(struct device *dev)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int entry = vp->cur_rx % RX_RING_SIZE;
+ int ioaddr = dev->base_addr;
+ int rx_status;
+
+ if (vortex_debug > 5)
+ printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
+ inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+ while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
+ if (rx_status & RxDError) { /* Error, update stats. */
+ unsigned char rx_error = rx_status >> 16;
+ if (vortex_debug > 2)
+ printk(" Rx error: status %2.2x.\n", rx_error);
+ vp->stats.rx_errors++;
+ if (rx_error & 0x01) vp->stats.rx_over_errors++;
+ if (rx_error & 0x02) vp->stats.rx_length_errors++;
+ if (rx_error & 0x04) vp->stats.rx_frame_errors++;
+ if (rx_error & 0x08) vp->stats.rx_crc_errors++;
+ if (rx_error & 0x10) vp->stats.rx_length_errors++;
+ } else {
+ /* The packet length: up to 4.5K!. */
+ short pkt_len = rx_status & 0x1fff;
+ struct sk_buff *skb;
+
+ if (vortex_debug > 4)
+ printk("Receiving packet size %d status %4.4x.\n",
+ pkt_len, rx_status);
+
+ /* Check if the packet is long enough to just accept without
+ copying to a properly sized skbuff. */
+ if (pkt_len < rx_copybreak
+ && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+ /* 'skb_put()' points to the start of sk_buff data area. */
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(vp->rx_ring[entry].addr),
+ pkt_len);
+ rx_copy++;
+ } else{
+ void *temp;
+ /* Pass up the skbuff already on the Rx ring. */
+ skb = vp->rx_skbuff[entry];
+ vp->rx_skbuff[entry] = NULL;
+ temp = skb_put(skb, pkt_len);
+ /* Remove this checking code for final release. */
+ if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
+ printk("%s: Warning -- the skbuff addresses do not match"
+ " in boomerang_rx: %p vs. %p / %p.\n", dev->name,
+ bus_to_virt(vp->rx_ring[entry].addr),
+ skb->head, temp);
+ rx_nocopy++;
+ }
+#if LINUX_VERSION_CODE > 0x10300
+ skb->protocol = eth_type_trans(skb, dev);
+#else
+ skb->len = pkt_len;
+#endif
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ vp->stats.rx_packets++;
+ }
+ entry = (++vp->cur_rx) % RX_RING_SIZE;
+ }
+ /* Refill the Rx ring buffers. */
+ for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+ struct sk_buff *skb;
+ entry = vp->dirty_rx % RX_RING_SIZE;
+ if (vp->rx_skbuff[entry] == NULL) {
+ skb = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+ vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
+#else
+ vp->rx_ring[entry].addr = virt_to_bus(skb->data);
+#endif
+ vp->rx_skbuff[entry] = skb;
+ }
+ vp->rx_ring[entry].status = 0; /* Clear complete bit. */
+ }
+ return 0;
+}
+
+static int
vortex_close(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;
+ int i;
dev->start = 0;
dev->tbusy = 1;
- if (vortex_debug > 1)
+ if (vortex_debug > 1) {
printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+ printk("%s: vortex close stats: rx_nocopy %d rx_copy %d"
+ " tx_queued %d.\n",
+ dev->name, rx_nocopy, rx_copy, queued_packet);
+ }
del_timer(&vp->timer);
@@ -1067,27 +1784,57 @@ vortex_close(struct device *dev)
outw(RxDisable, ioaddr + EL3_CMD);
outw(TxDisable, ioaddr + EL3_CMD);
- if (dev->if_port == 3)
+ if (dev->if_port == XCVR_10base2)
/* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD);
- FREE_IRQ(dev->irq, dev);
+#ifdef SA_SHIRQ
+ free_irq(dev->irq, dev);
+#else
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+#endif
+
+ outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
update_stats(ioaddr, dev);
+ if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+ outl(0, ioaddr + UpListPtr);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ if (vp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+ vp->rx_skbuff[i]->free = 1;
+#endif
+ dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+ vp->rx_skbuff[i] = 0;
+ }
+ }
+ if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
+ outl(0, ioaddr + DownListPtr);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ if (vp->tx_skbuff[i]) {
+ dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+ vp->tx_skbuff[i] = 0;
+ }
+ }
+
MOD_DEC_USE_COUNT;
return 0;
}
-static struct net_device_stats *vortex_get_stats(struct device *dev)
+static struct enet_statistics *
+vortex_get_stats(struct device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
unsigned long flags;
- save_flags(flags);
- cli();
- update_stats(dev->base_addr, dev);
- restore_flags(flags);
+ if (dev->start) {
+ save_flags(flags);
+ cli();
+ update_stats(dev->base_addr, dev);
+ restore_flags(flags);
+ }
return &vp->stats;
}
@@ -1129,6 +1876,37 @@ static void update_stats(int ioaddr, struct device *dev)
return;
}
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = vp->phys[0] & 0x1f;
+
+ if (vortex_debug > 2)
+ printk("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+ dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+ data[0], data[1], data[2], data[3]);
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = phy;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ EL3WINDOW(4);
+ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!suser())
+ return -EPERM;
+ mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+#endif /* HAVE_PRIVATE_IOCTL */
+
/* This new version of set_rx_mode() supports v1.4 kernels.
The Vortex chip has no documented multicast filter, so the only
multicast setting is to receive all multicast frames. At least
@@ -1145,11 +1923,19 @@ set_rx_mode(struct device *dev)
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
} else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
- } else
+ } else
new_mode = SetRxFilter | RxStation | RxBroadcast;
outw(new_mode, ioaddr + EL3_CMD);
}
+#ifndef NEW_MULTICAST
+/* The old interface to set the Rx mode. */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ set_rx_mode(dev);
+}
+#endif
#ifdef MODULE
void
@@ -1167,12 +1953,15 @@ cleanup_module(void)
root_vortex_dev = next_dev;
}
}
-#endif /* MODULE */
+
+#endif /* MODULE */
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o"
+ * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
* c-indent-level: 4
+ * c-basic-offset: 4
* tab-width: 4
* End:
*/
+
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 603657a85..f53d758d2 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -181,7 +181,6 @@ if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP
fi
- dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
fi
fi
#
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index fa5ae74e4..dbf0f3beb 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -265,7 +265,7 @@ static char *version =
/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { __SLOW_DOWN_IO; }}while(0)
+#define eeprom_slow_io() udelay(100) /* FIXME: smaller but right value here */
/* Jumperless Configuration Register (BMPR19) */
#define JUMPERLESS_CONFIG 19
diff --git a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in
index 94a86238f..85434e502 100644
--- a/drivers/net/hamradio/Config.in
+++ b/drivers/net/hamradio/Config.in
@@ -26,6 +26,7 @@ if [ "$CONFIG_HAMRADIO" != "n" ] ; then
# tristate 'Serial port 6PACK driver' CONFIG_6PACK
tristate 'BPQ Ethernet driver' CONFIG_BPQETHER
+ tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
tristate 'Z8530 SCC driver' CONFIG_SCC
if [ "$CONFIG_SCC" != "n" ]; then
bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
new file mode 100644
index 000000000..33b473d32
--- /dev/null
+++ b/drivers/net/hamradio/dmascc.c
@@ -0,0 +1,1260 @@
+/*
+ * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $
+ *
+ * Driver for high-speed SCC boards (those with DMA support)
+ * Copyright (C) 1997 Klaus Kudielka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/dmascc.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/netdevice.h>
+#include <linux/sockios.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <net/ax25.h>
+#include <stdio.h>
+#include "z8530.h"
+
+
+/* Number of buffers per channel */
+
+#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (2 recommended) */
+#define NUM_RX_BUF 2 /* NUM_RX_BUF >= 1 (2 recommended) */
+#define BUF_SIZE 2016
+
+
+/* Cards supported */
+
+#define HW_PI { "Ottawa PI", 0x300, 0x20, 0x10, 8, \
+ 0, 8, 1843200, 3686400 }
+#define HW_PI2 { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \
+ 0, 8, 3686400, 7372800 }
+#define HW_TWIN { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \
+ 0, 4, 6144000, 6144000 }
+
+#define HARDWARE { HW_PI, HW_PI2, HW_TWIN }
+
+#define TYPE_PI 0
+#define TYPE_PI2 1
+#define TYPE_TWIN 2
+#define NUM_TYPES 3
+
+#define MAX_NUM_DEVS 32
+
+
+/* SCC chips supported */
+
+#define Z8530 0
+#define Z85C30 1
+#define Z85230 2
+
+#define CHIPNAMES { "Z8530", "Z85C30", "Z85230" }
+
+
+/* I/O registers */
+
+/* 8530 registers relative to card base */
+#define SCCB_CMD 0x00
+#define SCCB_DATA 0x01
+#define SCCA_CMD 0x02
+#define SCCA_DATA 0x03
+
+/* 8254 registers relative to card base */
+#define TMR_CNT0 0x00
+#define TMR_CNT1 0x01
+#define TMR_CNT2 0x02
+#define TMR_CTRL 0x03
+
+/* Additional PI/PI2 registers relative to card base */
+#define PI_DREQ_MASK 0x04
+
+/* Additional PackeTwin registers relative to card base */
+#define TWIN_INT_REG 0x08
+#define TWIN_CLR_TMR1 0x09
+#define TWIN_CLR_TMR2 0x0a
+#define TWIN_SPARE_1 0x0b
+#define TWIN_DMA_CFG 0x08
+#define TWIN_SERIAL_CFG 0x09
+#define TWIN_DMA_CLR_FF 0x0a
+#define TWIN_SPARE_2 0x0b
+
+
+/* PackeTwin I/O register values */
+
+/* INT_REG */
+#define TWIN_SCC_MSK 0x01
+#define TWIN_TMR1_MSK 0x02
+#define TWIN_TMR2_MSK 0x04
+#define TWIN_INT_MSK 0x07
+
+/* SERIAL_CFG */
+#define TWIN_DTRA_ON 0x01
+#define TWIN_DTRB_ON 0x02
+#define TWIN_EXTCLKA 0x04
+#define TWIN_EXTCLKB 0x08
+#define TWIN_LOOPA_ON 0x10
+#define TWIN_LOOPB_ON 0x20
+#define TWIN_EI 0x80
+
+/* DMA_CFG */
+#define TWIN_DMA_HDX_T1 0x08
+#define TWIN_DMA_HDX_R1 0x0a
+#define TWIN_DMA_HDX_T3 0x14
+#define TWIN_DMA_HDX_R3 0x16
+#define TWIN_DMA_FDX_T3R1 0x1b
+#define TWIN_DMA_FDX_T1R3 0x1d
+
+
+/* Status values */
+
+/* tx_state */
+#define TX_IDLE 0
+#define TX_OFF 1
+#define TX_TXDELAY 2
+#define TX_ACTIVE 3
+#define TX_SQDELAY 4
+
+
+/* Data types */
+
+struct scc_hardware {
+ char *name;
+ int io_region;
+ int io_delta;
+ int io_size;
+ int num_devs;
+ int scc_offset;
+ int tmr_offset;
+ int tmr_hz;
+ int pclk_hz;
+};
+
+struct scc_priv {
+ char name[10];
+ struct enet_statistics stats;
+ struct scc_info *info;
+ int channel;
+ int cmd, data, tmr;
+ struct scc_param param;
+ char rx_buf[NUM_RX_BUF][BUF_SIZE];
+ int rx_len[NUM_RX_BUF];
+ int rx_ptr;
+ struct tq_struct rx_task;
+ int rx_head, rx_tail, rx_count;
+ int rx_over;
+ char tx_buf[NUM_TX_BUF][BUF_SIZE];
+ int tx_len[NUM_TX_BUF];
+ int tx_ptr;
+ int tx_head, tx_tail, tx_count;
+ int tx_sem, tx_state;
+ unsigned long tx_start;
+ int status;
+};
+
+struct scc_info {
+ int type;
+ int chip;
+ int open;
+ int scc_base;
+ int tmr_base;
+ int twin_serial_cfg;
+ struct device dev[2];
+ struct scc_priv priv[2];
+ struct scc_info *next;
+};
+
+
+/* Function declarations */
+
+int dmascc_init(void) __init;
+static int setup_adapter(int io, int h, int n) __init;
+
+static inline void write_scc(int ctl, int reg, int val);
+static inline int read_scc(int ctl, int reg);
+static int scc_open(struct device *dev);
+static int scc_close(struct device *dev);
+static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int scc_send_packet(struct sk_buff *skb, struct device *dev);
+static struct enet_statistics *scc_get_stats(struct device *dev);
+static int scc_set_mac_address(struct device *dev, void *sa);
+static void scc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static inline void z8530_isr(struct scc_info *info);
+static void rx_isr(struct device *dev);
+static void special_condition(struct device *dev, int rc);
+static void rx_bh(void *arg);
+static void tx_isr(struct device *dev);
+static void es_isr(struct device *dev);
+static void tm_isr(struct device *dev);
+static inline void delay(struct device *dev, int t);
+static inline unsigned char random(void);
+
+
+/* Initialization variables */
+
+static int io[MAX_NUM_DEVS] __initdata = { 0, };
+/* Beware! hw[] is also used in cleanup_module(). If __initdata also applies
+ to modules, we may not declare hw[] as __initdata */
+static struct scc_hardware hw[NUM_TYPES] __initdata = HARDWARE;
+static char ax25_broadcast[7] __initdata =
+ { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 };
+static char ax25_test[7] __initdata =
+ { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 };
+
+
+/* Global variables */
+
+static struct scc_info *first = NULL;
+static unsigned long rand;
+
+
+
+/* Module functions */
+
+#ifdef MODULE
+
+
+MODULE_AUTHOR("Klaus Kudielka <oe1kib@oe1xtu.ampr.org>");
+MODULE_DESCRIPTION("Driver for high-speed SCC boards");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
+
+
+int init_module(void)
+{
+ return dmascc_init();
+}
+
+
+void cleanup_module(void)
+{
+ int i;
+ struct scc_info *info;
+
+ while (first) {
+ info = first;
+
+ /* Unregister devices */
+ for (i = 0; i < 2; i++) {
+ if (info->dev[i].name)
+ unregister_netdev(&info->dev[i]);
+ }
+
+ /* Reset board */
+ if (info->type == TYPE_TWIN)
+ outb_p(0, info->dev[0].base_addr + TWIN_SERIAL_CFG);
+ write_scc(info->priv[0].cmd, R9, FHWRES);
+ release_region(info->dev[0].base_addr,
+ hw[info->type].io_size);
+
+ /* Free memory */
+ first = info->next;
+ kfree_s(info, sizeof(struct scc_info));
+ }
+}
+
+
+#else
+
+
+__initfunc(void dmascc_setup(char *str, int *ints))
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++)
+ io[i] = ints[i+1];
+}
+
+
+#endif
+
+
+/* Initialization functions */
+
+__initfunc(int dmascc_init(void))
+{
+ int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status;
+ unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS];
+
+ /* Initialize random number generator */
+ rand = jiffies;
+
+ /* Cards found = 0 */
+ n = 0;
+
+ /* Run autodetection for each card type */
+ for (h = 0; h < NUM_TYPES; h++) {
+
+ if (io[0]) {
+ /* User-specified I/O address regions */
+ for (i = 0; i < hw[h].num_devs; i++) base[i] = 0;
+ for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
+ j = (io[i] - hw[h].io_region) / hw[h].io_delta;
+ if (j >= 0 &&
+ j < hw[h].num_devs &&
+ hw[h].io_region + j * hw[h].io_delta == io[i])
+ base[j] = io[i];
+ }
+ } else {
+ /* Default I/O address regions */
+ for (i = 0; i < hw[h].num_devs; i++)
+ base[i] = hw[h].io_region + i * hw[h].io_delta;
+ }
+
+ /* Check valid I/O address regions */
+ for (i = 0; i < hw[h].num_devs; i++)
+ if (base[i] && check_region(base[i], hw[h].io_size))
+ base[i] = 0;
+
+ /* Start timers */
+ for (i = 0; i < hw[h].num_devs; i++)
+ if (base[i]) {
+ tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL;
+ t0 = base[i] + hw[h].tmr_offset + TMR_CNT0;
+ t1 = base[i] + hw[h].tmr_offset + TMR_CNT1;
+ /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
+ outb_p(0x36, tcmd);
+ outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0);
+ outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0);
+ /* Timer 1: LSB+MSB, Mode 0, HZ/10 */
+ outb_p(0x70, tcmd);
+ outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1);
+ outb_p((TMR_0_HZ/HZ*10) >> 8, t1);
+ /* Timer 2: LSB+MSB, Mode 0 */
+ outb_p(0xb0, tcmd);
+ }
+
+ /* Initialize start values in case we miss the null count bit */
+ time = jiffies;
+ for (i = 0; i < hw[h].num_devs; i++) start[i] = time;
+
+ /* Timing loop */
+ while (jiffies - time < 12) {
+ for (i = 0; i < hw[h].num_devs; i++)
+ if (base[i]) {
+ /* Read back Timer 1: Status */
+ outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL);
+ status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1);
+ if ((status & 0x3F) != 0x30) base[i] = 0;
+ if (status & 0x40) start[i] = jiffies;
+ if (~status & 0x80) stop[i] = jiffies;
+ }
+ }
+
+ /* Evaluate measurements */
+ for (i = 0; i < hw[h].num_devs; i++)
+ if (base[i]) {
+ time = stop[i] - start[i];
+ if (time < 9 || time > 11)
+ /* The time expired doesn't match */
+ base[i] = 0;
+ else {
+ /* Ok, we have found an adapter */
+ if (setup_adapter(base[i], h, n) == 0)
+ n++;
+ }
+ }
+
+ } /* NUM_TYPES */
+
+ /* If any adapter was successfully initialized, return ok */
+ if (n) return 0;
+
+ /* If no adapter found, return error */
+ printk("dmascc: no adapters found\n");
+ return -EIO;
+}
+
+
+__initfunc(int setup_adapter(int io, int h, int n))
+{
+ int i, irq, chip;
+ struct scc_info *info;
+ struct device *dev;
+ struct scc_priv *priv;
+ unsigned long time;
+ unsigned int irqs;
+ int tmr = io + hw[h].tmr_offset;
+ int scc = io + hw[h].scc_offset;
+ int cmd = scc + SCCA_CMD;
+ char *chipnames[] = CHIPNAMES;
+
+ /* Reset 8530 */
+ write_scc(cmd, R9, FHWRES | MIE | NV);
+
+ /* Determine type of chip */
+ write_scc(cmd, R15, 1);
+ if (!read_scc(cmd, R15)) {
+ /* WR7' not present. This is an ordinary Z8530 SCC. */
+ chip = Z8530;
+ } else {
+ /* Put one character in TX FIFO */
+ write_scc(cmd, R8, 0);
+ if (read_scc(cmd, R0) & Tx_BUF_EMP) {
+ /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */
+ chip = Z85230;
+ } else {
+ /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */
+ chip = Z85C30;
+ }
+ }
+ write_scc(cmd, R15, 0);
+
+ /* Start IRQ auto-detection */
+ sti();
+ irqs = probe_irq_on();
+
+ /* Enable interrupts */
+ switch (h) {
+ case TYPE_PI:
+ case TYPE_PI2:
+ outb_p(0, io + PI_DREQ_MASK);
+ write_scc(cmd, R15, CTSIE);
+ write_scc(cmd, R0, RES_EXT_INT);
+ write_scc(cmd, R1, EXT_INT_ENAB);
+ break;
+ case TYPE_TWIN:
+ outb_p(0, io + TWIN_DMA_CFG);
+ inb_p(io + TWIN_CLR_TMR1);
+ inb_p(io + TWIN_CLR_TMR2);
+ outb_p(TWIN_EI, io + TWIN_SERIAL_CFG);
+ break;
+ }
+
+ /* Start timer */
+ outb_p(1, tmr + TMR_CNT1);
+ outb_p(0, tmr + TMR_CNT1);
+ /* Wait and detect IRQ */
+ time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ);
+ irq = probe_irq_off(irqs);
+
+ /* Clear pending interrupt, disable interrupts */
+ switch (h) {
+ case TYPE_PI:
+ case TYPE_PI2:
+ write_scc(cmd, R1, 0);
+ write_scc(cmd, R15, 0);
+ write_scc(cmd, R0, RES_EXT_INT);
+ break;
+ case TYPE_TWIN:
+ inb_p(io + TWIN_CLR_TMR1);
+ outb_p(0, io + TWIN_SERIAL_CFG);
+ break;
+ }
+
+ if (irq <= 0) {
+ printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n",
+ hw[h].name, io, irq);
+ return -1;
+ }
+
+ /* Allocate memory */
+ info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+ if (!info) {
+ printk("dmascc: could not allocate memory for %s at %#3x\n",
+ hw[h].name, io);
+ return -1;
+ }
+
+ /* Set up data structures */
+ memset(info, 0, sizeof(struct scc_info));
+ info->type = h;
+ info->chip = chip;
+ info->scc_base = io + hw[h].scc_offset;
+ info->tmr_base = io + hw[h].tmr_offset;
+ info->twin_serial_cfg = 0;
+ for (i = 0; i < 2; i++) {
+ dev = &info->dev[i];
+ priv = &info->priv[i];
+ sprintf(priv->name, "dmascc%i", 2*n+i);
+ priv->info = info;
+ priv->channel = i;
+ priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD);
+ priv->data = info->scc_base + (i ? SCCB_DATA : SCCA_DATA);
+ priv->tmr = info->tmr_base + (i ? TMR_CNT2 : TMR_CNT1);
+ priv->param.pclk_hz = hw[h].pclk_hz;
+ priv->param.brg_tc = -1;
+ priv->param.clocks = TCTRxCP | RCRTxCP;
+ priv->param.txdelay = TMR_0_HZ * 10 / 1000;
+ priv->param.txtime = HZ * 3;
+ priv->param.sqdelay = TMR_0_HZ * 1 / 1000;
+ priv->param.slottime = TMR_0_HZ * 10 / 1000;
+ priv->param.waittime = TMR_0_HZ * 100 / 1000;
+ priv->param.persist = 32;
+ priv->rx_task.routine = rx_bh;
+ priv->rx_task.data = dev;
+ dev->priv = priv;
+ dev->name = priv->name;
+ dev->base_addr = io;
+ dev->irq = irq;
+ dev->open = scc_open;
+ dev->stop = scc_close;
+ dev->do_ioctl = scc_ioctl;
+ dev->hard_start_xmit = scc_send_packet;
+ dev->get_stats = scc_get_stats;
+ dev->hard_header = ax25_encapsulate;
+ dev->rebuild_header = ax25_rebuild_header;
+ dev->set_mac_address = scc_set_mac_address;
+ dev->type = ARPHRD_AX25;
+ dev->hard_header_len = 73;
+ dev->mtu = 1500;
+ dev->addr_len = 7;
+ dev->tx_queue_len = 64;
+ memcpy(dev->broadcast, ax25_broadcast, 7);
+ memcpy(dev->dev_addr, ax25_test, 7);
+ dev->flags = 0;
+ dev_init_buffers(dev);
+ if (register_netdev(dev)) {
+ printk("dmascc: could not register %s\n", dev->name);
+ dev->name = NULL;
+ }
+ }
+
+ request_region(io, hw[h].io_size, "dmascc");
+
+ info->next = first;
+ first = info;
+ printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[h].name,
+ chipnames[chip], io, irq);
+ return 0;
+}
+
+
+/* Driver functions */
+
+static inline void write_scc(int ctl, int reg, int val)
+{
+ outb_p(reg, ctl);
+ outb_p(val, ctl);
+}
+
+
+static inline int read_scc(int ctl, int reg)
+{
+ outb_p(reg, ctl);
+ return inb_p(ctl);
+}
+
+
+static int scc_open(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int io = dev->base_addr;
+ int cmd = priv->cmd;
+
+ /* Request IRQ if not already used by other channel */
+ if (!info->open) {
+ if (request_irq(dev->irq, scc_isr, SA_INTERRUPT, "dmascc", info))
+ return -EAGAIN;
+ }
+
+ /* Request DMA if required */
+ if (dev->dma && request_dma(dev->dma, "dmascc")) {
+ if (!info->open) free_irq(dev->irq, info);
+ return -EAGAIN;
+ }
+
+ /* Initialize local variables */
+ dev->tbusy = 0;
+ priv->rx_ptr = 0;
+ priv->rx_over = 0;
+ priv->rx_head = priv->rx_tail = priv->rx_count = 0;
+ priv->tx_state = TX_IDLE;
+ priv->tx_head = priv->tx_tail = priv->tx_count = 0;
+ priv->tx_ptr = 0;
+ priv->tx_sem = 0;
+
+ /* Reset channel */
+ write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+ /* X1 clock, SDLC mode */
+ write_scc(cmd, R4, SDLC | X1CLK);
+ /* DMA */
+ write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+ /* 8 bit RX char, RX disable */
+ write_scc(cmd, R3, Rx8);
+ /* 8 bit TX char, TX disable */
+ write_scc(cmd, R5, Tx8);
+ /* SDLC address field */
+ write_scc(cmd, R6, 0);
+ /* SDLC flag */
+ write_scc(cmd, R7, FLAG);
+ switch (info->chip) {
+ case Z85C30:
+ /* Select WR7' */
+ write_scc(cmd, R15, 1);
+ /* Auto EOM reset */
+ write_scc(cmd, R7, 0x02);
+ write_scc(cmd, R15, 0);
+ break;
+ case Z85230:
+ /* Select WR7' */
+ write_scc(cmd, R15, 1);
+ /* RX FIFO half full (interrupt only), Auto EOM reset,
+ TX FIFO empty (DMA only) */
+ write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a);
+ write_scc(cmd, R15, 0);
+ break;
+ }
+ /* Preset CRC, NRZ(I) encoding */
+ write_scc(cmd, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
+
+ /* Configure baud rate generator */
+ if (priv->param.brg_tc >= 0) {
+ /* Program BR generator */
+ write_scc(cmd, R12, priv->param.brg_tc & 0xFF);
+ write_scc(cmd, R13, (priv->param.brg_tc>>8) & 0xFF);
+ /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
+ PackeTwin, not connected on the PI2); set DPLL source to BRG */
+ write_scc(cmd, R14, SSBR | DTRREQ | BRSRC | BRENABL);
+ /* Enable DPLL */
+ write_scc(cmd, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
+ } else {
+ /* Disable BR generator */
+ write_scc(cmd, R14, DTRREQ | BRSRC);
+ }
+
+ /* Configure clocks */
+ if (info->type == TYPE_TWIN) {
+ /* Disable external TX clock receiver */
+ outb_p((info->twin_serial_cfg &=
+ ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
+ io + TWIN_SERIAL_CFG);
+ }
+ write_scc(cmd, R11, priv->param.clocks);
+ if ((info->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
+ /* Enable external TX clock receiver */
+ outb_p((info->twin_serial_cfg |=
+ (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
+ io + TWIN_SERIAL_CFG);
+ }
+
+ /* Configure PackeTwin */
+ if (info->type == TYPE_TWIN) {
+ /* Assert DTR, enable interrupts */
+ outb_p((info->twin_serial_cfg |= TWIN_EI |
+ (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
+ io + TWIN_SERIAL_CFG);
+ }
+
+ /* Read current status */
+ priv->status = read_scc(cmd, R0);
+ /* Enable SYNC, DCD, and CTS interrupts */
+ write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
+
+ /* Configure PI2 DMA */
+ if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
+
+ dev->start = 1;
+ info->open++;
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+
+static int scc_close(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int io = dev->base_addr;
+ int cmd = priv->cmd;
+
+ dev->start = 0;
+ info->open--;
+ MOD_DEC_USE_COUNT;
+
+ if (info->type == TYPE_TWIN)
+ /* Drop DTR */
+ outb_p((info->twin_serial_cfg &=
+ (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
+ io + TWIN_SERIAL_CFG);
+
+ /* Reset channel, free DMA */
+ write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
+ if (dev->dma) {
+ if (info->type == TYPE_TWIN) outb_p(0, io + TWIN_DMA_CFG);
+ free_dma(dev->dma);
+ }
+
+ if (!info->open) {
+ if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
+ free_irq(dev->irq, info);
+ }
+ return 0;
+}
+
+
+static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ int rc;
+ struct scc_priv *priv = dev->priv;
+
+ switch (cmd) {
+ case SIOCGSCCPARAM:
+ rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
+ if (rc) return rc;
+ copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
+ return 0;
+ case SIOCSSCCPARAM:
+ if (!suser()) return -EPERM;
+ rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
+ if (rc) return rc;
+ if (dev->start) return -EAGAIN;
+ copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
+ dev->dma = priv->param.dma;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static int scc_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int cmd = priv->cmd;
+ unsigned long flags;
+ int i;
+
+ /* Block a timer-based transmit from overlapping */
+ if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
+ atomic_inc((void *) &priv->stats.tx_dropped);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+
+ /* Return with an error if we cannot accept more data */
+ if (dev->tbusy) {
+ priv->tx_sem = 0;
+ return -1;
+ }
+
+ /* Transfer data to DMA buffer */
+ i = priv->tx_head;
+ memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
+ priv->tx_len[i] = skb->len-1;
+
+ save_flags(flags);
+ cli();
+
+ /* Set the busy flag if we just filled up the last buffer */
+ priv->tx_head = (i + 1) % NUM_TX_BUF;
+ priv->tx_count++;
+ if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
+
+ /* Set new TX state */
+ if (priv->tx_state == TX_IDLE) {
+ /* Assert RTS, start timer */
+ priv->tx_state = TX_TXDELAY;
+ if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
+ write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+ if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
+ priv->tx_start = jiffies;
+ delay(dev, priv->param.txdelay);
+ }
+
+ restore_flags(flags);
+
+ dev_kfree_skb(skb, FREE_WRITE);
+
+ priv->tx_sem = 0;
+ return 0;
+}
+
+
+static struct enet_statistics *scc_get_stats(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+
+ return &priv->stats;
+}
+
+
+static int scc_set_mac_address(struct device *dev, void *sa)
+{
+ memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len);
+ return 0;
+}
+
+
+static void scc_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct scc_info *info = dev_id;
+ int is, io = info->dev[0].base_addr;
+
+ /* We're a fast IRQ handler and are called with interrupts disabled */
+
+ /* IRQ sharing doesn't make sense due to ISA's edge-triggered
+ interrupts, hence it is safe to return if we have found and
+ processed a single device. */
+
+ /* Interrupt processing: We loop until we know that the IRQ line is
+ low. If another positive edge occurs afterwards during the ISR,
+ another interrupt will be triggered by the interrupt controller
+ as soon as the IRQ level is enabled again (see asm/irq.h). */
+
+ switch (info->type) {
+ case TYPE_PI:
+ case TYPE_PI2:
+ outb_p(0, io + PI_DREQ_MASK);
+ z8530_isr(info);
+ outb_p(1, io + PI_DREQ_MASK);
+ return;
+ case TYPE_TWIN:
+ while ((is = ~inb_p(io + TWIN_INT_REG)) &
+ TWIN_INT_MSK) {
+ if (is & TWIN_SCC_MSK) {
+ z8530_isr(info);
+ } else if (is & TWIN_TMR1_MSK) {
+ inb_p(io + TWIN_CLR_TMR1);
+ tm_isr(&info->dev[0]);
+ } else {
+ inb_p(io + TWIN_CLR_TMR2);
+ tm_isr(&info->dev[1]);
+ }
+ }
+ /* No interrupts pending from the PackeTwin */
+ return;
+ }
+}
+
+
+static inline void z8530_isr(struct scc_info *info)
+{
+ int is, a_cmd;
+
+ a_cmd = info->scc_base + SCCA_CMD;
+
+ while ((is = read_scc(a_cmd, R3))) {
+ if (is & CHARxIP) {
+ rx_isr(&info->dev[0]);
+ } else if (is & CHATxIP) {
+ tx_isr(&info->dev[0]);
+ } else if (is & CHAEXT) {
+ es_isr(&info->dev[0]);
+ } else if (is & CHBRxIP) {
+ rx_isr(&info->dev[1]);
+ } else if (is & CHBTxIP) {
+ tx_isr(&info->dev[1]);
+ } else {
+ es_isr(&info->dev[1]);
+ }
+ }
+ /* Ok, no interrupts pending from this 8530. The INT line should
+ be inactive now. */
+}
+
+
+static void rx_isr(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ int cmd = priv->cmd;
+
+ if (dev->dma) {
+ /* Check special condition and perform error reset. See 2.4.7.5. */
+ special_condition(dev, read_scc(cmd, R1));
+ write_scc(cmd, R0, ERR_RES);
+ } else {
+ /* Check special condition for each character. Error reset not necessary.
+ Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
+ int rc;
+ while (read_scc(cmd, R0) & Rx_CH_AV) {
+ rc = read_scc(cmd, R1);
+ if (priv->rx_ptr < BUF_SIZE)
+ priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc(cmd, R8);
+ else {
+ priv->rx_over = 2;
+ read_scc(cmd, R8);
+ }
+ special_condition(dev, rc);
+ }
+ }
+}
+
+
+static void special_condition(struct device *dev, int rc)
+{
+ struct scc_priv *priv = dev->priv;
+ int cb, cmd = priv->cmd;
+
+ /* See Figure 2-15. Only overrun and EOF need to be checked. */
+
+ if (rc & Rx_OVR) {
+ /* Receiver overrun */
+ priv->rx_over = 1;
+ if (!dev->dma) write_scc(cmd, R0, ERR_RES);
+ } else if (rc & END_FR) {
+ /* End of frame. Get byte count */
+ if (dev->dma) {
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ cb = BUF_SIZE - get_dma_residue(dev->dma) - 2;
+ } else {
+ cb = priv->rx_ptr - 2;
+ }
+ if (priv->rx_over) {
+ /* We had an overrun */
+ priv->stats.rx_errors++;
+ if (priv->rx_over == 2) priv->stats.rx_length_errors++;
+ else priv->stats.rx_fifo_errors++;
+ priv->rx_over = 0;
+ } else if (rc & CRC_ERR) {
+ /* Count invalid CRC only if packet length >= minimum */
+ if (cb >= 8) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_crc_errors++;
+ }
+ } else {
+ if (cb >= 8) {
+ /* Put good frame in FIFO */
+ priv->rx_len[priv->rx_head] = cb;
+ priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF;
+ priv->rx_count++;
+ if (priv->rx_count == NUM_RX_BUF) {
+ /* Disable receiver if FIFO full */
+ write_scc(cmd, R3, Rx8);
+ priv->stats.rx_errors++;
+ priv->stats.rx_over_errors++;
+ }
+ /* Mark bottom half handler */
+ queue_task(&priv->rx_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ }
+ /* Get ready for new frame */
+ if (dev->dma) {
+ set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+ set_dma_count(dev->dma, BUF_SIZE);
+ enable_dma(dev->dma);
+ } else {
+ priv->rx_ptr = 0;
+ }
+ }
+}
+
+
+static void rx_bh(void *arg)
+{
+ struct device *dev = arg;
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int cmd = priv->cmd;
+ int i = priv->rx_tail;
+ int cb;
+ unsigned long flags;
+ struct sk_buff *skb;
+ unsigned char *data;
+
+ save_flags(flags);
+ cli();
+
+ while (priv->rx_count) {
+ restore_flags(flags);
+ cb = priv->rx_len[i];
+ /* Allocate buffer */
+ skb = dev_alloc_skb(cb+1);
+ if (skb == NULL) {
+ /* Drop packet */
+ priv->stats.rx_dropped++;
+ } else {
+ /* Fill buffer */
+ data = skb_put(skb, cb+1);
+ data[0] = 0;
+ memcpy(&data[1], priv->rx_buf[i], cb);
+ skb->dev = dev;
+ skb->protocol = ntohs(ETH_P_AX25);
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ priv->stats.rx_packets++;
+ }
+ save_flags(flags);
+ cli();
+ /* Enable receiver if RX buffers have been unavailable */
+ if ((priv->rx_count == NUM_RX_BUF) && (priv->status & DCD)) {
+ if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
+ write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+ if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
+ }
+ /* Move tail */
+ priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
+ priv->rx_count--;
+ }
+
+ restore_flags(flags);
+}
+
+
+static void tx_isr(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ int cmd = priv->cmd;
+ int i = priv->tx_tail, p = priv->tx_ptr;
+
+ /* Suspend TX interrupts if we don't want to send anything.
+ See Figure 2-22. */
+ if (p == priv->tx_len[i]) {
+ write_scc(cmd, R0, RES_Tx_P);
+ return;
+ }
+
+ /* Write characters */
+ while ((read_scc(cmd, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
+ write_scc(cmd, R8, priv->tx_buf[i][p++]);
+ }
+ priv->tx_ptr = p;
+
+}
+
+
+static void es_isr(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int i, cmd = priv->cmd;
+ int st, dst, res;
+
+ /* Read status and reset interrupt bit */
+ st = read_scc(cmd, R0);
+ write_scc(cmd, R0, RES_EXT_INT);
+ dst = priv->status ^ st;
+ priv->status = st;
+
+ /* Since the EOM latch is reset automatically, we assume that
+ it has been zero if and only if we are in the TX_ACTIVE state.
+ Otherwise we follow 2.4.9.6. */
+
+ /* Transmit underrun */
+ if ((priv->tx_state == TX_ACTIVE) && (st & TxEOM)) {
+ /* Get remaining bytes */
+ i = priv->tx_tail;
+ if (dev->dma) {
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ res = get_dma_residue(dev->dma);
+ } else {
+ res = priv->tx_len[i] - priv->tx_ptr;
+ if (res) write_scc(cmd, R0, RES_Tx_P);
+ priv->tx_ptr = 0;
+ }
+ /* Remove frame from FIFO */
+ priv->tx_tail = (i + 1) % NUM_TX_BUF;
+ priv->tx_count--;
+ dev->tbusy = 0;
+ /* Check if another frame is available and we are allowed to transmit */
+ if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
+ if (dev->dma) {
+ set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
+ set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
+ enable_dma(dev->dma);
+ } else {
+ /* If we have an ESCC, we are allowed to write data bytes
+ immediately. Otherwise we have to wait for the next
+ TX interrupt. See Figure 2-22. */
+ if (info->chip == Z85230) {
+ tx_isr(dev);
+ }
+ }
+ } else {
+ /* No frame available. Disable interrupts. */
+ priv->tx_state = TX_SQDELAY;
+ delay(dev, priv->param.sqdelay);
+ write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
+ write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+ }
+ /* Update packet statistics */
+ if (res) {
+ priv->stats.tx_errors++;
+ priv->stats.tx_fifo_errors++;
+ } else {
+ priv->stats.tx_packets++;
+ }
+ /* Inform upper layers */
+ mark_bh(NET_BH);
+ }
+
+ /* DCD transition */
+ if ((priv->tx_state < TX_TXDELAY) && (dst & DCD)) {
+ /* Transmitter state change */
+ priv->tx_state = TX_OFF;
+ /* Enable or disable receiver */
+ if (st & DCD) {
+ if (dev->dma) {
+ /* Program DMA controller */
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_mode(dev->dma, DMA_MODE_READ);
+ set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+ set_dma_count(dev->dma, BUF_SIZE);
+ enable_dma(dev->dma);
+ /* Configure PackeTwin DMA */
+ if (info->type == TYPE_TWIN) {
+ outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
+ dev->base_addr + TWIN_DMA_CFG);
+ }
+ /* Sp. cond. intr. only, ext int enable */
+ write_scc(cmd, R1, EXT_INT_ENAB | INT_ERR_Rx |
+ WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
+ } else {
+ /* Intr. on all Rx characters and Sp. cond., ext int enable */
+ write_scc(cmd, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
+ WT_FN_RDYFN);
+ }
+ if (priv->rx_count < NUM_RX_BUF) {
+ /* Enable receiver */
+ write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+ }
+ } else {
+ /* Disable DMA */
+ if (dev->dma) disable_dma(dev->dma);
+ /* Disable receiver */
+ write_scc(cmd, R3, Rx8);
+ /* DMA disable, RX int disable, Ext int enable */
+ write_scc(cmd, R1, EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+ /* Transmitter state change */
+ if (random() > priv->param.persist)
+ delay(dev, priv->param.slottime);
+ else {
+ if (priv->tx_count) {
+ priv->tx_state = TX_TXDELAY;
+ write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+ priv->tx_start = jiffies;
+ delay(dev, priv->param.txdelay);
+ } else {
+ priv->tx_state = TX_IDLE;
+ }
+ }
+ }
+ }
+
+ /* CTS transition */
+ if ((info->type <= TYPE_PI2) && (dst & CTS) && (~st & CTS)) {
+ /* Timer has expired */
+ tm_isr(dev);
+ }
+
+ /* /SYNC/HUNT transition */
+ if ((dst & SYNC_HUNT) && (~st & SYNC_HUNT)) {
+ /* Reset current frame and clear RX FIFO */
+ while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8);
+ priv->rx_over = 0;
+ if (dev->dma) {
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
+ set_dma_count(dev->dma, BUF_SIZE);
+ enable_dma(dev->dma);
+ } else {
+ priv->rx_ptr = 0;
+ }
+ }
+}
+
+
+static void tm_isr(struct device *dev)
+{
+ struct scc_priv *priv = dev->priv;
+ struct scc_info *info = priv->info;
+ int cmd = priv->cmd;
+
+ switch (priv->tx_state) {
+ case TX_OFF:
+ if (~priv->status & DCD) {
+ if (random() > priv->param.persist) delay(dev, priv->param.slottime);
+ else {
+ if (priv->tx_count) {
+ priv->tx_state = TX_TXDELAY;
+ write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
+ priv->tx_start = jiffies;
+ delay(dev, priv->param.txdelay);
+ } else {
+ priv->tx_state = TX_IDLE;
+ }
+ }
+ }
+ break;
+ case TX_TXDELAY:
+ priv->tx_state = TX_ACTIVE;
+ if (dev->dma) {
+ /* Program DMA controller */
+ disable_dma(dev->dma);
+ clear_dma_ff(dev->dma);
+ set_dma_mode(dev->dma, DMA_MODE_WRITE);
+ set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
+ set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
+ enable_dma(dev->dma);
+ /* Configure PackeTwin DMA */
+ if (info->type == TYPE_TWIN) {
+ outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
+ dev->base_addr + TWIN_DMA_CFG);
+ }
+ /* Enable interrupts and DMA. On the PackeTwin, the DTR//REQ pin
+ is used for TX DMA requests, but we enable the WAIT/DMA request
+ pin, anyway */
+ write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
+ write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
+ } else {
+ write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
+ write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
+ tx_isr(dev);
+ }
+ if (info->chip == Z8530) write_scc(cmd, R0, RES_EOM_L);
+ break;
+ case TX_SQDELAY:
+ /* Disable transmitter */
+ write_scc(cmd, R5, TxCRC_ENAB | Tx8);
+ /* Transmitter state change: Switch to TX_OFF and wait at least
+ 1 slottime. */
+ priv->tx_state = TX_OFF;
+ if (~priv->status & DCD) delay(dev, priv->param.waittime);
+ }
+}
+
+
+static inline void delay(struct device *dev, int t)
+{
+ struct scc_priv *priv = dev->priv;
+ int tmr = priv->tmr;
+
+ outb_p(t & 0xFF, tmr);
+ outb_p((t >> 8) & 0xFF, tmr);
+}
+
+
+static inline unsigned char random(void)
+{
+ /* See "Numerical Recipes in C", second edition, p. 284 */
+ rand = rand * 1664525L + 1013904223L;
+ return (unsigned char) (rand >> 24);
+}
+
+
diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c
index fdca59467..fa3072a6c 100644
--- a/drivers/net/ipddp.c
+++ b/drivers/net/ipddp.c
@@ -1,5 +1,3 @@
-#warning "Needs new networking merges before it will work"
-#if 0
/*
* ipddp.c: IP-over-DDP driver for Linux
*
@@ -309,4 +307,3 @@ void cleanup_module(void)
}
#endif /* MODULE */
-#endif
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c39083b24..7b9a16829 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -154,8 +154,8 @@ struct pci_dev_info dev_info[] = {
DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"),
DEVICE( DPT, DPT, "SmartCache/Raid"),
DEVICE( OPTI, OPTI_92C178, "92C178"),
- DEVICE( OPTI, OPTI_82C557, "82C557"),
- DEVICE( OPTI, OPTI_82C558, "82C558"),
+ DEVICE( OPTI, OPTI_82C557, "82C557 Viper-M"),
+ DEVICE( OPTI, OPTI_82C558, "82C558 Viper-M ISA+IDE"),
DEVICE( OPTI, OPTI_82C621, "82C621"),
DEVICE( OPTI, OPTI_82C700, "82C700"),
DEVICE( OPTI, OPTI_82C701, "82C701 FireStar Plus"),
@@ -394,15 +394,15 @@ struct pci_dev_info dev_info[] = {
DEVICE( INTEL, INTEL_82865, "82865"),
DEVICE( INTEL, INTEL_82557, "82557"),
DEVICE( INTEL, INTEL_82437, "82437"),
- DEVICE( INTEL, INTEL_82371_0, "82371 Triton PIIX"),
- DEVICE( INTEL, INTEL_82371_1, "82371 Triton PIIX"),
+ DEVICE( INTEL, INTEL_82371FB_0,"82371FB PIIX ISA"),
+ DEVICE( INTEL, INTEL_82371FB_1,"82371FB PIIX IDE"),
DEVICE( INTEL, INTEL_82371MX, "430MX - 82371MX MPIIX"),
DEVICE( INTEL, INTEL_82437MX, "430MX - 82437MX MTSC"),
DEVICE( INTEL, INTEL_82441, "82441FX Natoma"),
DEVICE( INTEL, INTEL_82439, "82439HX Triton II"),
- DEVICE( INTEL, INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
- DEVICE( INTEL, INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
- DEVICE( INTEL, INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
+ DEVICE( INTEL, INTEL_82371SB_0,"82371SB PIIX3 ISA"),
+ DEVICE( INTEL, INTEL_82371SB_1,"82371SB PIIX3 IDE"),
+ DEVICE( INTEL, INTEL_82371SB_2,"82371SB PIIX3 USB"),
DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"),
DEVICE( INTEL, INTEL_82439TX, "82439TX"),
DEVICE( INTEL, INTEL_82371AB_0,"82371AB PIIX4 ISA"),
@@ -555,11 +555,11 @@ const char *pci_strclass (unsigned int class)
case PCI_CLASS_NOT_DEFINED: return "Non-VGA device";
case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device";
- case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller";
- case PCI_CLASS_STORAGE_IDE: return "IDE interface";
+ case PCI_CLASS_STORAGE_SCSI: return "SCSI bus controller";
+ case PCI_CLASS_STORAGE_IDE: return "IDE controller";
case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller";
case PCI_CLASS_STORAGE_IPI: return "IPI bus controller";
- case PCI_CLASS_STORAGE_RAID: return "RAID bus controller";
+ case PCI_CLASS_STORAGE_RAID: return "RAID controller";
case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller";
case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller";
@@ -909,7 +909,7 @@ static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
if (len + 40 > size) {
return -1;
}
- len += sprintf(buf + len, "IRQ %x. ", dev->irq);
+ len += sprintf(buf + len, "IRQ %d. ", dev->irq);
}
if (dev->master) {
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index efd6568f1..ff3264da3 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/scsi/ide-scsi.c Version 0.2 - ALPHA Jan 26, 1997
+ * linux/drivers/scsi/ide-scsi.c Version 0.4 Dec 7, 1997
*
* Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -15,9 +15,13 @@
* of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
* to Janos Farkas for pointing this out.
* Avoid using bitfields in structures for m68k.
- * Added Scather/Gather and DMA support.
+ * Added Scatter/Gather and DMA support.
+ * Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives.
+ * Use variable timeout for each command.
*/
+#define IDESCSI_VERSION "0.4"
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -49,11 +53,12 @@ typedef struct idescsi_pc_s {
struct request *rq; /* The corresponding request */
byte *buffer; /* Data buffer */
byte *current_position; /* Pointer into the above buffer */
- struct scatterlist *sg; /* Scather gather table */
+ struct scatterlist *sg; /* Scatter gather table */
int b_count; /* Bytes transferred from current entry */
Scsi_Cmnd *scsi_cmd; /* SCSI command */
void (*done)(Scsi_Cmnd *); /* Scsi completion routine */
unsigned int flags; /* Status/Action flags */
+ unsigned long timeout; /* Command timeout */
} idescsi_pc_t;
/*
@@ -149,7 +154,7 @@ static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
int i;
if (drive->media == ide_cdrom) {
- if (c[0] == READ_6) {
+ if (c[0] == READ_6 || c[0] == WRITE_6) {
c[8] = c[4]; c[5] = c[3]; c[4] = c[2];
c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
c[0] = READ_10;
@@ -226,6 +231,11 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
scsi->pc = NULL;
}
+static inline unsigned long get_timeout(idescsi_pc_t *pc)
+{
+ return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+}
+
/*
* Our interrupt handler.
*/
@@ -247,7 +257,7 @@ static void idescsi_pc_intr (ide_drive_t *drive)
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
pc->actually_transferred=pc->request_transfer;
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
+ (void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
}
status = GET_STAT(); /* Clear the interrupt */
@@ -276,7 +286,7 @@ static void idescsi_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
idescsi_discard_data (drive,bcount);
- ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD);
+ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
return;
}
#if IDESCSI_DEBUG_LOG
@@ -298,12 +308,13 @@ static void idescsi_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount; /* Update the current position */
pc->current_position+=bcount;
- ide_set_handler (drive,&idescsi_pc_intr,WAIT_CMD); /* And set the interrupt handler again */
+ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* And set the interrupt handler again */
}
static void idescsi_transfer_pc (ide_drive_t *drive)
{
idescsi_scsi_t *scsi = drive->driver_data;
+ idescsi_pc_t *pc = scsi->pc;
byte ireason;
if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
@@ -316,8 +327,8 @@ static void idescsi_transfer_pc (ide_drive_t *drive)
ide_do_reset (drive);
return;
}
- ide_set_handler (drive, &idescsi_pc_intr, WAIT_CMD); /* Set the interrupt routine */
- atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */
+ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); /* Set the interrupt routine */
+ atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */
}
/*
@@ -349,7 +360,7 @@ static void idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
}
if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
- ide_set_handler (drive, &idescsi_transfer_pc, WAIT_CMD);
+ ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -426,6 +437,8 @@ static ide_module_t idescsi_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idescsi_driver = {
+ "ide-scsi", /* name */
+ IDESCSI_VERSION, /* version */
ide_scsi, /* media */
0, /* busy */
1, /* supports_dma */
@@ -439,7 +452,8 @@ static ide_driver_t idescsi_driver = {
NULL, /* media_change */
NULL, /* pre_reset */
NULL, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
static struct proc_dir_entry idescsi_proc_dir = {PROC_SCSI_IDESCSI, 8, "ide-scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2};
@@ -555,7 +569,7 @@ static inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc
int segments = pc->scsi_cmd->use_sg;
struct scatterlist *sg = pc->scsi_cmd->request_buffer;
- if (!drive->using_dma || pc->request_transfer % 1024)
+ if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)
return NULL;
if (idescsi_set_direction(pc))
return NULL;
@@ -619,6 +633,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
pc->scsi_cmd = cmd;
pc->done = done;
+ pc->timeout = jiffies + cmd->timeout_per_command;
idescsi_transform_pc1 (drive, pc);
ide_init_drive_cmd (rq);
@@ -645,6 +660,18 @@ int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
return SCSI_RESET_PUNT;
}
+int idescsi_bios (Disk *disk, kdev_t dev, int *parm)
+{
+ ide_drive_t *drive = idescsi_drives[disk->device->id];
+
+ if (drive->cyl && drive->head && drive->sect) {
+ parm[0] = drive->head;
+ parm[1] = drive->sect;
+ parm[2] = drive->cyl;
+ }
+ return 0;
+}
+
#ifdef MODULE
Scsi_Host_Template idescsi_template = IDESCSI;
diff --git a/drivers/scsi/ide-scsi.h b/drivers/scsi/ide-scsi.h
index 44b524e73..2ccbc3c03 100644
--- a/drivers/scsi/ide-scsi.h
+++ b/drivers/scsi/ide-scsi.h
@@ -13,6 +13,7 @@ extern const char *idescsi_info (struct Scsi_Host *host);
extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
extern int idescsi_abort (Scsi_Cmnd *cmd);
extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
+extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
#define IDESCSI \
{ NULL, /* next */ \
@@ -28,7 +29,7 @@ extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
idescsi_abort, /* abort */ \
idescsi_reset, /* reset */ \
NULL, /* slave_attach */ \
- NULL, /* bios_param */ \
+ idescsi_bios, /* bios_param */ \
10, /* can_queue */ \
-1, /* this_id */ \
256, /* sg_tablesize */ \
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b70522280..1d7ed45b4 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -580,6 +580,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
STp->buffer = st_buffers[i];
(STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
+ (STp->buffer)->last_result_fatal = 0;
flags = filp->f_flags;
STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
diff --git a/drivers/sgi/Makefile b/drivers/sgi/Makefile
index 40cb89eaa..e2f0b7b7e 100644
--- a/drivers/sgi/Makefile
+++ b/drivers/sgi/Makefile
@@ -20,3 +20,25 @@ SUB_DIRS += char
L_OBJS += char/sgichar.o
include $(TOPDIR)/Rules.make
+#
+# Makefile for the linux kernel.
+#
+# 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...
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) char
+
+L_OBJS :=
+L_TARGET := sgi.a
+
+# Character devices for SGI machines.
+#
+SUB_DIRS += char
+L_OBJS += char/sgichar.o
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/sgi/char/Makefile b/drivers/sgi/char/Makefile
index 7032c700c..3ccaafd9e 100644
--- a/drivers/sgi/char/Makefile
+++ b/drivers/sgi/char/Makefile
@@ -16,3 +16,21 @@ ifeq ($(CONFIG_SGI_SERIAL),y)
endif
include $(TOPDIR)/Rules.make
+#
+# Makefile for the linux kernel.
+#
+# 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 := sgichar.o
+O_OBJS := graphics.o streamable.o newport.o cons_newport.o sgicons.o \
+ vga_font.o rrm.o shmiq.o usema.o
+
+ifeq ($(CONFIG_SGI_SERIAL),y)
+ O_OBJS += sgiserial.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/sgi/char/cons_newport.c b/drivers/sgi/char/cons_newport.c
index 91212c0ae..30aa1f3b7 100644
--- a/drivers/sgi/char/cons_newport.c
+++ b/drivers/sgi/char/cons_newport.c
@@ -3,7 +3,618 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: cons_newport.c,v 1.5 1997/09/12 01:32:50 ralf Exp $
+ * $Id: cons_newport.c,v 1.1 1997/12/02 02:28:23 ralf Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/sgialib.h>
+#include <asm/ptrace.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+
+#include "gconsole.h"
+#include "newport.h"
+#include "graphics.h" /* Just for now */
+#include <asm/gfx.h>
+#include <asm/ng1.h>
+
+#if 0
+#include "linux_logo.h"
+#endif
+
+#define BMASK(c) (c << 24)
+
+#define RENDER(regs, cp) do { \
+(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
+(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
+(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
+(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
+(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
+(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
+(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
+(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
+} while(0)
+
+#define REVERSE_RENDER(regs, cp) do { \
+(regs)->go.zpattern = BMASK((~(cp)[0x0])); (regs)->go.zpattern = BMASK((~(cp)[0x1])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x2])); (regs)->go.zpattern = BMASK((~(cp)[0x3])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x4])); (regs)->go.zpattern = BMASK((~(cp)[0x5])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x6])); (regs)->go.zpattern = BMASK((~(cp)[0x7])); \
+(regs)->go.zpattern = BMASK((~(cp)[0x8])); (regs)->go.zpattern = BMASK((~(cp)[0x9])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xa])); (regs)->go.zpattern = BMASK((~(cp)[0xb])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xc])); (regs)->go.zpattern = BMASK((~(cp)[0xd])); \
+(regs)->go.zpattern = BMASK((~(cp)[0xe])); (regs)->go.zpattern = BMASK((~(cp)[0xf])); \
+} while(0)
+
+extern int default_red[16], default_grn[16], default_blu[16];
+extern unsigned char video_type;
+
+static int cursor_pos = -1;
+struct newport_regs *npregs;
+
+#define TESTVAL 0xdeadbeef
+#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
+
+static inline void
+newport_disable_video(void)
+{
+ unsigned short treg;
+
+ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+ newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EVIDEO)));
+}
+
+static inline void
+newport_enable_video(void)
+{
+ unsigned short treg;
+
+ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+ newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EVIDEO));
+}
+
+static inline void
+newport_disable_cursor(void)
+{
+ unsigned short treg;
+
+ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+ newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP)));
+}
+
+#if 0
+static inline void
+newport_enable_cursor(void)
+{
+ unsigned short treg;
+
+ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+ newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
+}
+#endif
+
+static inline void
+newport_init_cmap(void)
+{
+ unsigned short i;
+
+ for(i = 0; i < 16; i++) {
+ newport_bfwait();
+ newport_cmap_setaddr(npregs, color_table[i]);
+ newport_cmap_setrgb(npregs,
+ default_red[i],
+ default_grn[i],
+ default_blu[i]);
+ }
+}
+
+#if 0
+static inline void
+newport_init_cursor(void)
+{
+ unsigned char cursor[256];
+ unsigned short *cookie;
+ int i;
+
+ for(i = 0; i < 256; i++)
+ cursor[i] = 0x0;
+ for(i = 211; i < 256; i+=4) {
+ cursor[i] = 0xff;
+#if 0
+ cursor[(i + 128) << 2] = 0xff;
+ cursor[((i + 128) << 2) + 1] = 0xff;
+#endif
+ }
+
+ /* Load the SRAM on the VC2 for this new GLYPH. */
+ cookie = (unsigned short *) cursor;
+ newport_vc2_set(npregs, VC2_IREG_RADDR, VC2_CGLYPH_ADDR);
+ npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+ NPORT_DMODE_W2 | VC2_PROTOCOL);
+ for(i = 0; i < 128; i++) {
+ newport_bfwait();
+ npregs->set.dcbdata0.hwords.s1 = *cookie++;
+ }
+
+ /* Place the cursor at origin. */
+ newport_vc2_set(npregs, VC2_IREG_CURSX, 0);
+ newport_vc2_set(npregs, VC2_IREG_CURSY, 0);
+ newport_enable_cursor();
+}
+#endif
+
+static inline void
+newport_clear_screen(void)
+{
+ newport_wait();
+ npregs->set.wrmask = 0xffffffff;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
+ NPORT_DMODE0_STOPY);
+ npregs->set.colori = 0;
+ npregs->set.xystarti = 0;
+ npregs->go.xyendi = (((1280 + 63) << 16)|(1024));
+ newport_bfwait();
+}
+
+static inline void
+newport_render_version(void)
+{
+#if 0
+ unsigned short *ush;
+ int currcons = 0;
+ char *p;
+
+ ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20;
+ for (p = "SGI/Linux version " UTS_RELEASE; *p; p++, ush++) {
+ *ush = (attr << 8) + *p;
+ newport_blitc (*ush, (unsigned long) ush);
+ }
+#endif
+}
+
+#if 0
+static inline void
+newport_render_logo(void)
+{
+ int i, xpos, ypos;
+ unsigned char *bmap;
+
+ xpos = 8;
+ ypos = 18;
+
+ newport_wait();
+ npregs->set.colori = 9;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+ NPORT_DMODE0_L32);
+
+ for(i = 0; i < 80; i+=8) {
+ /* Set coordinates for bitmap operation. */
+ npregs->set.xystarti = ((xpos + i) << 16) | ypos;
+ npregs->set.xyendi = (((xpos + i) + 7) << 16);
+ newport_wait();
+
+ bmap = linux_logo + (i * 80);
+ RENDER(npregs, bmap); bmap += 0x10;
+ RENDER(npregs, bmap); bmap += 0x10;
+ RENDER(npregs, bmap); bmap += 0x10;
+ RENDER(npregs, bmap); bmap += 0x10;
+ RENDER(npregs, bmap);
+ }
+ prom_getchar();
+ prom_imode();
+}
+#endif
+
+static inline void
+newport_render_background(int xpos, int ypos, int ci)
+{
+ newport_wait();
+ npregs->set.wrmask = 0xffffffff;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
+ NPORT_DMODE0_STOPY);
+ npregs->set.colori = ci;
+ npregs->set.xystarti = (xpos << 16) | ypos;
+ npregs->go.xyendi = ((xpos + 7) << 16) | (ypos + 15);
+}
+
+void
+newport_set_origin(unsigned short offset)
+{
+ /* maybe this works... */
+ __origin = offset;
+}
+
+void
+newport_hide_cursor(void)
+{
+ int xpos, ypos, idx;
+ unsigned long flags;
+
+ if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ return;
+ save_and_cli(flags);
+
+ idx = cursor_pos;
+ if(idx == -1) {
+ restore_flags(flags);
+ return;
+ }
+ xpos = 8 + ((idx % video_num_columns) << 3);
+ ypos = 18 + ((idx / video_num_columns) << 4);
+ newport_render_background(xpos, ypos, 0);
+ restore_flags(flags);
+}
+
+void
+newport_set_cursor(int currcons)
+{
+ int xpos, ypos, idx, oldpos;
+ unsigned short *sp, *osp, cattr;
+ unsigned long flags;
+ unsigned char *p;
+
+ if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+ return;
+
+ if (__real_origin != __origin)
+ __set_origin(__real_origin);
+
+ save_and_cli(flags);
+
+ idx = (pos - video_mem_base) >> 1;
+ sp = (unsigned short *) pos;
+ oldpos = cursor_pos;
+ cursor_pos = idx;
+ if(!deccm) {
+ hide_cursor();
+ restore_flags(flags);
+ return;
+ }
+ xpos = 8 + ((idx % video_num_columns) << 3);
+ ypos = 18 + ((idx / video_num_columns) << 4);
+ if(oldpos != -1) {
+ int oxpos, oypos;
+
+ /* Restore old location. */
+ osp = (unsigned short *) ((oldpos << 1) + video_mem_base);
+ oxpos = 8 + ((oldpos % video_num_columns) << 3);
+ oypos = 18 + ((oldpos / video_num_columns) << 4);
+ cattr = *osp;
+ newport_render_background(oxpos, oypos, (cattr & 0xf000) >> 12);
+ p = &vga_font[(cattr & 0xff) << 4];
+ newport_wait();
+ npregs->set.colori = (cattr & 0x0f00) >> 8;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+ NPORT_DMODE0_L32);
+ npregs->set.xystarti = (oxpos << 16) | oypos;
+ npregs->set.xyendi = ((oxpos + 7) << 16);
+ newport_wait();
+ RENDER(npregs, p);
+ }
+ cattr = *sp;
+ newport_render_background(xpos, ypos, (cattr & 0xf000) >> 12);
+ p = &vga_font[(cattr & 0xff) << 4];
+ newport_wait();
+ npregs->set.colori = (cattr & 0x0f00) >> 8;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+ NPORT_DMODE0_L32);
+ npregs->set.xystarti = (xpos << 16) | ypos;
+ npregs->set.xyendi = ((xpos + 7) << 16);
+ newport_wait();
+ REVERSE_RENDER(npregs, p);
+ restore_flags (flags);
+ return;
+}
+
+void
+newport_get_scrmem(int currcons)
+{
+ memcpyw((unsigned short *)vc_scrbuf[currcons],
+ (unsigned short *)origin, video_screen_size);
+ origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+ scr_end = video_mem_end = video_mem_start + video_screen_size;
+ pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+newport_set_scrmem(int currcons, long offset)
+{
+ if (video_mem_term - video_mem_base < offset + video_screen_size)
+ offset = 0;
+ memcpyw((unsigned short *)(video_mem_base + offset),
+ (unsigned short *) origin, video_screen_size);
+ video_mem_start = video_mem_base;
+ video_mem_end = video_mem_term;
+ origin = video_mem_base + offset;
+ scr_end = origin + video_screen_size;
+ pos = origin + y*video_size_row + (x<<1);
+ has_wrapped = 0;
+}
+
+int
+newport_set_get_cmap(unsigned char * arg, int set)
+{
+ unsigned short ent;
+ int i;
+
+ i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+ if (i)
+ return i;
+
+ for (i=0; i<16; i++) {
+ if (set) {
+ __get_user(default_red[i], arg++);
+ __get_user(default_grn[i], arg++);
+ __get_user(default_blu[i], arg++);
+ } else {
+ __put_user (default_red[i], arg++);
+ __put_user (default_grn[i], arg++);
+ __put_user (default_blu[i], arg++);
+ }
+ }
+ if (set) {
+ for (i=0; i<MAX_NR_CONSOLES; i++) {
+ if (vc_cons_allocated(i)) {
+ int j, k;
+ for (j = k = 0; j<16; j++) {
+ vc_cons[i].d->vc_palette[k++] =
+ default_red[j];
+ vc_cons[i].d->vc_palette[k++] =
+ default_grn[j];
+ vc_cons[i].d->vc_palette[k++] =
+ default_blu[j];
+ }
+ }
+ }
+ if(console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ return 0;
+ for(ent = 0; ent < 16; ent++) {
+ newport_bfwait();
+ newport_cmap_setaddr(npregs, ent);
+ newport_cmap_setrgb(npregs,
+ default_red[ent],
+ default_grn[ent],
+ default_blu[ent]);
+ }
+ }
+
+ return 0;
+}
+
+void
+newport_blitc(unsigned short charattr, unsigned long addr)
+{
+ int idx, xpos, ypos;
+ unsigned char *p;
+
+ idx = (addr - (video_mem_base + (__origin<<1))) >> 1;
+ xpos = 8 + ((idx % video_num_columns) << 3);
+ ypos = 18 + ((idx / video_num_columns) << 4);
+
+ p = &vga_font[(charattr & 0xff) << 4];
+ charattr = (charattr >> 8) & 0xff;
+
+ newport_render_background(xpos, ypos, (charattr & 0xf0) >> 4);
+
+ /* Set the color and drawing mode. */
+ newport_wait();
+ npregs->set.colori = charattr & 0xf;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+ NPORT_DMODE0_L32);
+
+ /* Set coordinates for bitmap operation. */
+ npregs->set.xystarti = (xpos << 16) | ypos;
+ npregs->set.xyendi = ((xpos + 7) << 16);
+ newport_wait();
+
+ /* Go, baby, go... */
+ RENDER(npregs, p);
+}
+
+void
+newport_memsetw(void * s, unsigned short c, unsigned int count)
+{
+ unsigned short * addr = (unsigned short *) s;
+
+ count /= 2;
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+ while (count) {
+ count--;
+ *addr++ = c;
+ }
+ return;
+ }
+ if ((unsigned long) addr + count > video_mem_term ||
+ (unsigned long) addr < video_mem_base) {
+ if ((unsigned long) addr + count <= video_mem_term ||
+ (unsigned long) addr > video_mem_base) {
+ while (count) {
+ count--;
+ *addr++ = c;
+ }
+ return;
+ } else {
+ while (count) {
+ count--;
+ scr_writew(c, addr++);
+ }
+ }
+ } else {
+ while (count) {
+ count--;
+ if (*addr != c) {
+ newport_blitc(c, (unsigned long)addr);
+ *addr++ = c;
+ } else
+ addr++;
+ }
+ }
+}
+
+void
+newport_memcpyw(unsigned short *to, unsigned short *from, unsigned int count)
+{
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+ memcpy(to, from, count);
+ return;
+ }
+ if ((unsigned long) to + count > video_mem_term ||
+ (unsigned long) to < video_mem_base) {
+ if ((unsigned long) to + count <= video_mem_term ||
+ (unsigned long) to > video_mem_base)
+ memcpy(to, from, count);
+ else {
+ count /= 2;
+ while (count) {
+ count--;
+ scr_writew(scr_readw(from++), to++);
+ }
+ }
+ } else {
+ count /= 2;
+ while (count) {
+ count--;
+ if (*to != *from) {
+ newport_blitc(*from, (unsigned long)to);
+ *to++ = *from++;
+ } else {
+ from++;
+ to++;
+ }
+ }
+ }
+}
+
+struct console_ops newport_console = {
+ newport_set_origin,
+ newport_hide_cursor,
+ newport_set_cursor,
+ newport_get_scrmem,
+ newport_set_scrmem,
+ newport_set_get_cmap,
+ newport_blitc,
+ newport_memsetw,
+ newport_memcpyw
+};
+
+/* Currently hard-coded values that are the same as those found on my system */
+struct ng1_info newport_board_info = {
+ { "NG1", "" /* what is the label? */, 1280, 1024, sizeof (struct ng1_info) },
+ 6, /* boardrev */
+ 1, /* rex3rev */
+ 0, /* vc2rev */
+ 2, /* monitor type */
+ 0, /* videoinstalled */
+ 3, /* mcrev */
+ 24, /* bitplanes */
+ 0, /* xmap9rev */
+ 2, /* cmaprev */
+ { 256, 1280, 1024, 76}, /* ng1_vof_info */
+ 13, /* paneltype */
+ 0
+};
+
+void
+newport_reset (void)
+{
+ newport_wait();
+ newport_enable_video();
+
+ /* Init the cursor disappear. */
+ newport_wait();
+#if 0
+ newport_init_cursor();
+#else
+ newport_disable_cursor();
+#endif
+
+ newport_init_cmap();
+
+ /* Clear the screen. */
+ newport_clear_screen();
+}
+
+/* right now the newport does not do anything at all */
+struct graphics_ops newport_graphic_ops = {
+ 0, /* owner */
+ 0, /* current user */
+ (void *) &newport_board_info, /* board info */
+ sizeof (struct ng1_info), /* size of our data structure */
+ 0, 0, /* g_regs, g_regs_size */
+ newport_save, newport_restore, /* g_save_context, g_restore_context */
+ newport_reset, newport_ioctl /* g_reset_console, g_ioctl */
+};
+
+struct graphics_ops *
+newport_probe (int slot, const char **name)
+{
+ struct newport_regs *p;
+
+ npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
+
+ p = npregs;
+ p->cset.config = NPORT_CFG_GD0;
+
+ if(newport_wait()) {
+ prom_printf("whoops, timeout, no NEWPORT there?");
+ return 0;
+ }
+
+ p->set.xstarti = TESTVAL; if(p->set._xstart.i != XSTI_TO_FXSTART(TESTVAL)) {
+ prom_printf("newport_probe: read back wrong value ;-(\n");
+ return 0;
+ }
+
+ if (slot == 0){
+ register_gconsole (&newport_console);
+ video_type = VIDEO_TYPE_SGI;
+ can_do_color = 1;
+ *name = "NEWPORT";
+ }
+
+ newport_reset ();
+ newport_render_version();
+#if 0
+ newport_render_logo();
+#endif
+ newport_graphic_ops.g_regs = 0x1f0f0000;
+ newport_graphic_ops.g_regs_size = sizeof (struct newport_regs);
+ return &newport_graphic_ops;
+}
+/*
+ * cons_newport.c: Newport graphics console code for the SGI.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: cons_newport.c,v 1.6 1997/09/21 23:00:01 miguel Exp $
*/
#include <linux/kernel.h>
diff --git a/drivers/sgi/char/gconsole.h b/drivers/sgi/char/gconsole.h
index 7bc9794bb..89fd84f2b 100644
--- a/drivers/sgi/char/gconsole.h
+++ b/drivers/sgi/char/gconsole.h
@@ -31,3 +31,36 @@ extern unsigned char vga_font[];
extern void disable_gconsole (void);
extern void enable_gconsole (void);
+/*
+ * This is a temporary measure, we should eventually migrate to
+ * Gert's generic graphic console code.
+ */
+
+#define cmapsz 8192
+#define CHAR_HEIGHT 16
+
+struct console_ops {
+ void (*set_origin)(unsigned short offset);
+ void (*hide_cursor)(void);
+ void (*set_cursor)(int currcons);
+ void (*get_scrmem)(int currcons);
+ void (*set_scrmem)(int currcons, long offset);
+ int (*set_get_cmap)(unsigned char *arg, int set);
+ void (*blitc)(unsigned short charattr, unsigned long addr);
+ void (*memsetw)(void *s, unsigned short c, unsigned int count);
+ void (*memcpyw)(unsigned short *to, unsigned short *from, unsigned int count);
+};
+
+void register_gconsole (struct console_ops *);
+
+/* This points to the system console */
+extern struct console_ops *gconsole;
+
+extern void gfx_init (const char **name);
+
+extern void __set_origin (unsigned short offset);
+extern void hide_cursor (void);
+extern unsigned char vga_font[];
+
+extern void disable_gconsole (void);
+extern void enable_gconsole (void);
diff --git a/drivers/sgi/char/graphics.c b/drivers/sgi/char/graphics.c
index b7e69b243..9d55e4867 100644
--- a/drivers/sgi/char/graphics.c
+++ b/drivers/sgi/char/graphics.c
@@ -325,3 +325,330 @@ gfx_init (const char **name)
}
+/*
+ * gfx.c: support for SGI's /dev/graphics, /dev/opengl
+ *
+ * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * On IRIX, /dev/graphics is [10, 146]
+ * /dev/opengl is [10, 147]
+ *
+ * From a mail with Mark J. Kilgard, /dev/opengl and /dev/graphics are
+ * the same thing, the use of /dev/graphics seems deprecated though.
+ *
+ * The reason that the original SGI programmer had to use only one
+ * device for all the graphic cards on the system will remain a
+ * mistery for the rest of our lives. Why some ioctls take a board
+ * number and some others not? Mistery. Why do they map the hardware
+ * registers into the user address space with an ioctl instead of
+ * mmap? Mistery too. Why they did not use the standard way of
+ * making ioctl constants and instead sticked a random constant?
+ * Mistery too.
+ *
+ * We implement those misterious things, and tried not to think about
+ * the reasons behind them.
+ */
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <asm/uaccess.h>
+#include "gconsole.h"
+#include "graphics.h"
+#include <asm/gfx.h>
+#include <asm/rrm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/* The boards */
+#include "newport.h"
+
+#ifdef PRODUCTION_DRIVER
+#define enable_gconsole()
+#define disable_gconsole()
+#endif
+
+static struct graphics_ops cards [MAXCARDS];
+static int boards;
+
+#define GRAPHICS_CARD(inode) 0
+
+int
+sgi_graphics_open (struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+int
+sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned int board;
+ unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
+ int i;
+
+ if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
+ return rrm_command (cmd-RRM_BASE, (void *) arg);
+
+ switch (cmd){
+ case GFX_GETNUM_BOARDS:
+ return boards;
+
+ case GFX_GETBOARD_INFO: {
+ struct gfx_getboardinfo_args *bia = (void *) arg;
+ void *dest_buf;
+ int max_len;
+
+ i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct gfx_getboardinfo_args));
+ if (i) return i;
+
+ __get_user_ret (board, &bia->board, -EFAULT);
+ __get_user_ret (dest_buf, &bia->buf, -EFAULT);
+ __get_user_ret (max_len, &bia->len, -EFAULT);
+
+ if (board >= boards)
+ return -EINVAL;
+ if (max_len < sizeof (struct gfx_getboardinfo_args))
+ return -EINVAL;
+ if (max_len > cards [board].g_board_info_len)
+ max_len = cards [boards].g_board_info_len;
+ i = verify_area (VERIFY_WRITE, dest_buf, max_len);
+ if (i) return i;
+ if (copy_to_user (dest_buf, cards [board].g_board_info, max_len))
+ return -EFAULT;
+ return max_len;
+ }
+
+ case GFX_ATTACH_BOARD: {
+ struct gfx_attach_board_args *att = (void *) arg;
+ void *vaddr;
+ int r;
+
+ i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct gfx_attach_board_args));
+ if (i) return i;
+
+ __get_user_ret (board, &att->board, -EFAULT);
+ __get_user_ret (vaddr, &att->vaddr, -EFAULT);
+
+ /* Ok for now we are assuming /dev/graphicsN -> head N even
+ * if the ioctl api suggests that this is not quite the case.
+ *
+ * Otherwise we fail, we use this assumption in the mmap code
+ * below to find our board information.
+ */
+ if (board != devnum){
+ printk ("Parameter board does not match the current board\n");
+ return -EINVAL;
+ }
+
+ if (board >= boards)
+ return -EINVAL;
+
+ /* If it is the first opening it, then make it the board owner */
+ if (!cards [board].g_owner)
+ cards [board].g_owner = current;
+
+ /*
+ * Ok, we now call mmap on this file, which will end up calling
+ * sgi_graphics_mmap
+ */
+ disable_gconsole ();
+ r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size,
+ PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0);
+ if (r)
+ return r;
+
+ }
+
+ /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
+ * GFX_MAPALL is not even used by IRIX X server
+ */
+ case GFX_MAPALL:
+ return 0;
+
+ case GFX_LABEL:
+ return 0;
+
+ /* Version check
+ * for my IRIX 6.2 X server, this is what the kernel returns
+ */
+ case 1:
+ return 3;
+
+ /* Xsgi does not use this one, I assume minor is the board being queried */
+ case GFX_IS_MANAGED:
+ if (devnum > boards)
+ return -EINVAL;
+ return (cards [devnum].g_owner != 0);
+
+ default:
+ if (cards [devnum].g_ioctl)
+ return (*cards [devnum].g_ioctl)(devnum, cmd, arg);
+
+ }
+ return -EINVAL;
+}
+
+int
+sgi_graphics_close (struct inode *inode, struct file *file)
+{
+ int board = GRAPHICS_CARD (inode->i_rdev);
+
+ /* Tell the rendering manager that one client is going away */
+ rrm_close (inode, file);
+
+ /* Was this file handle from the board owner?, clear it */
+ if (current == cards [board].g_owner){
+ cards [board].g_owner = 0;
+ (*cards [board].g_reset_console)();
+ enable_gconsole ();
+ }
+ return 0;
+}
+
+/*
+ * This is the core of the direct rendering engine.
+ */
+
+unsigned long
+sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+ unsigned long page;
+ int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
+
+#ifdef DEBUG_GRAPHICS
+ printk ("Got a page fault for board %d address=%lx guser=%lx\n", board, address,
+ cards [board].g_user);
+#endif
+
+ /* 1. figure out if another process has this mapped,
+ * and revoke the mapping in that case.
+ */
+ if (cards [board].g_user && cards [board].g_user != current){
+ /* FIXME: save graphics context here, dump it to rendering node? */
+ remove_mapping (cards [board].g_user, vma->vm_start, vma->vm_end);
+ }
+ cards [board].g_user = current;
+#if DEBUG_GRAPHICS
+ printk ("Registers: 0x%lx\n", cards [board].g_regs);
+ printk ("vm_start: 0x%lx\n", vma->vm_start);
+ printk ("address: 0x%lx\n", address);
+ printk ("diff: 0x%lx\n", (address - vma->vm_start));
+
+ printk ("page/pfn: 0x%lx\n", page);
+ printk ("TLB entry: %lx\n", pte_val (mk_pte (page + PAGE_OFFSET, PAGE_USERIO)));
+#endif
+
+ /* 2. Map this into the current process address space */
+ page = ((cards [board].g_regs) + (address - vma->vm_start));
+ return page + PAGE_OFFSET;
+}
+
+/*
+ * We convert a GFX ioctl for mapping hardware registers, in a nice sys_mmap
+ * call, which takes care of everything that must be taken care of.
+ *
+ */
+
+static struct vm_operations_struct graphics_mmap = {
+ NULL, /* no special mmap-open */
+ NULL, /* no special mmap-close */
+ NULL, /* no special mmap-unmap */
+ NULL, /* no special mmap-protect */
+ NULL, /* no special mmap-sync */
+ NULL, /* no special mmap-advise */
+ sgi_graphics_nopage, /* our magic no-page fault handler */
+ NULL, /* no special mmap-wppage */
+ NULL, /* no special mmap-swapout */
+ NULL /* no special mmap-swapin */
+};
+
+int
+sgi_graphics_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+ uint size;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* 1. Set our special graphic virtualizer */
+ vma->vm_ops = &graphics_mmap;
+
+ /* 2. Set the special tlb permission bits */
+ vma->vm_page_prot = PAGE_USERIO;
+
+ /* final setup */
+ vma->vm_dentry = dget (file->f_dentry);
+ return 0;
+}
+
+/* Do any post card-detection setup on graphics_ops */
+static void
+graphics_ops_post_init (int slot)
+{
+ /* There is no owner for the card initially */
+ cards [slot].g_owner = (struct task_struct *) 0;
+ cards [slot].g_user = (struct task_struct *) 0;
+}
+
+struct file_operations sgi_graphics_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ sgi_graphics_ioctl, /* ioctl */
+ sgi_graphics_mmap, /* mmap */
+ sgi_graphics_open, /* open */
+ sgi_graphics_close, /* release */
+ NULL, /* fsync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+/* /dev/graphics */
+static struct miscdevice dev_graphics = {
+ SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
+};
+
+/* /dev/opengl */
+static struct miscdevice dev_opengl = {
+ SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
+};
+
+/* This is called later from the misc-init routine */
+void
+gfx_register (void)
+{
+ misc_register (&dev_graphics);
+ misc_register (&dev_opengl);
+}
+
+void
+gfx_init (const char **name)
+{
+ struct console_ops *console;
+ struct graphics_ops *g;
+
+ printk ("GFX INIT: ");
+ shmiq_init ();
+ usema_init ();
+
+ if ((g = newport_probe (boards, name)) != 0){
+ cards [boards] = *g;
+ graphics_ops_post_init (boards);
+ boards++;
+ console = 0;
+ }
+ /* Add more graphic drivers here */
+ /* Keep passing console around */
+
+ if (boards > MAXCARDS){
+ printk ("Too many cards found on the system\n");
+ prom_halt ();
+ }
+}
+
+
diff --git a/drivers/sgi/char/graphics.h b/drivers/sgi/char/graphics.h
index d5a8d2979..c8ad7e318 100644
--- a/drivers/sgi/char/graphics.h
+++ b/drivers/sgi/char/graphics.h
@@ -26,3 +26,31 @@ struct graphics_ops {
void shmiq_init (void);
void streamable_init (void);
void usema_init (void);
+#define MAXCARDS 4
+
+struct graphics_ops {
+ /* SGIism: Board owner, gets the shmiq requests from the kernel */
+ struct task_struct *g_owner;
+
+ /* Last process that got the graphics registers mapped */
+ struct task_struct *g_user;
+
+ /* Board info */
+ void *g_board_info;
+ int g_board_info_len;
+
+ /* These point to hardware registers that should be mapped with
+ * GFX_ATTACH_BOARD and the size of the information pointed to
+ */
+ unsigned long g_regs;
+ int g_regs_size;
+
+ void (*g_save_context)(void *);
+ void (*g_restore_context)(void *);
+ void (*g_reset_console)(void);
+ int (*g_ioctl)(int device, int cmd, unsigned long arg);
+};
+
+void shmiq_init (void);
+void streamable_init (void);
+void usema_init (void);
diff --git a/drivers/sgi/char/linux_logo.h b/drivers/sgi/char/linux_logo.h
index ca041ddde..62a635ee3 100644
--- a/drivers/sgi/char/linux_logo.h
+++ b/drivers/sgi/char/linux_logo.h
@@ -907,3 +907,912 @@ unsigned char linux_logo[] = {
0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
};
+/* This is a linux logo to be displayed on boot.
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from0x20
+ * (i.e. RGB(linux_logo_red[0],
+ * linux_logo_green[0],
+ * linux_logo_blue[0]) is color0x20)
+ */
+
+#define LINUX_LOGO_COLORS 221
+
+unsigned char linux_logo_red[] = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+ 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
+ 0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
+ 0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
+ 0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
+ 0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
+ 0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
+ 0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
+ 0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
+ 0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
+ 0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
+ 0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
+ 0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
+ 0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
+ 0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
+ 0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
+ 0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
+ 0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_green[] = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+ 0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
+ 0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
+ 0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
+ 0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
+ 0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
+ 0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
+ 0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
+ 0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
+ 0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
+ 0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
+ 0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
+ 0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
+ 0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
+ 0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
+ 0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
+ 0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
+ 0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_blue[] = {
+ 0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
+ 0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
+ 0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
+ 0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
+ 0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
+ 0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
+ 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
+ 0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+ 0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
+ 0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
+ 0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
+ 0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
+ 0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
+ 0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
+ 0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
+ 0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
+ 0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
+ 0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
+ 0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
+ 0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
+ 0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
+ 0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+ 0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
+ 0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
+ 0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
+ 0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
+ 0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
+ 0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo[] = {
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+ 0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
+ 0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
+ 0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
+ 0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+ 0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
+ 0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
+ 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
+ 0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
+ 0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
+ 0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
+ 0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
+ 0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+ 0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
+ 0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
+ 0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
+ 0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
+ 0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
+ 0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
+ 0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
+ 0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
+ 0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
+ 0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
+ 0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
+ 0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
+ 0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
+ 0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
+ 0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
+ 0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
+ 0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
+ 0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
+ 0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
+ 0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
+ 0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
+ 0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
+ 0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
+ 0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
+ 0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
+ 0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
+ 0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
+ 0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
+ 0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
+ 0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
+ 0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
+ 0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+ 0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
+ 0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
+ 0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
+ 0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
+ 0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
+ 0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
+ 0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
+ 0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+ 0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
+ 0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
+ 0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
+ 0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
+ 0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
+ 0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
+ 0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
+ 0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
+ 0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
+ 0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
+ 0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
+ 0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
+ 0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
+ 0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
+ 0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
+ 0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+ 0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
+ 0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
+ 0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
+ 0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
+ 0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
+ 0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
+ 0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
+ 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
+ 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+ 0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
+ 0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
+ 0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
+ 0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
+ 0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
+ 0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
+ 0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
+ 0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
+ 0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
+ 0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
+ 0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
+ 0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
+ 0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
+ 0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
+ 0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
+ 0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
+ 0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
+ 0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
+ 0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
+ 0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
+ 0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
+ 0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
+ 0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
+ 0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
+ 0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
+ 0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
+ 0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
+ 0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
+ 0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
+ 0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
+ 0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
+ 0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
+ 0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
+ 0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
+ 0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
+ 0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
+ 0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
+ 0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
+ 0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
+ 0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
+ 0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
+ 0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
+ 0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
+ 0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
+ 0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
+ 0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
+ 0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
+ 0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
+ 0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
+ 0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
+ 0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
+ 0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
+ 0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
+ 0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
+ 0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
+ 0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
+ 0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
+ 0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
+ 0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
+ 0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
+ 0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
+ 0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
+ 0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
+ 0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
+ 0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
+ 0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
+ 0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
+ 0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
+ 0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
+ 0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
+ 0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
+ 0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
+ 0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
+ 0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
+ 0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
+ 0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
+ 0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
+ 0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
+ 0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
+ 0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
+ 0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
+ 0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
+ 0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
+ 0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
+ 0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
+ 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
+ 0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
+ 0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
+ 0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
+ 0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
+ 0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
+ 0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
+ 0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
+ 0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
+ 0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
+ 0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
+ 0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
+ 0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
+ 0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
+ 0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
+ 0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
+ 0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
+ 0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
+ 0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
+ 0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
+ 0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
+ 0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
+ 0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
+ 0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
+ 0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
+ 0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
+ 0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
+ 0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
+ 0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
+ 0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
+ 0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
+ 0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
+ 0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
+ 0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
+ 0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
+ 0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
+ 0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
+ 0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
+ 0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
+ 0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
+ 0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
+ 0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
+ 0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
+ 0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
+ 0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
+ 0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
+ 0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
+ 0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
+ 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
+ 0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
+ 0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
+ 0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
+ 0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
+ 0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
+ 0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
+ 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
+ 0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
+ 0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
+ 0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
+ 0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
+ 0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
+ 0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
+ 0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
+ 0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
+ 0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
+ 0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
+ 0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
+ 0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
+ 0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
+ 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
+ 0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
+ 0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
+ 0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
+ 0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
+ 0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
+ 0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
+ 0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
+ 0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
+ 0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
+ 0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
+ 0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
+ 0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
+ 0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
+ 0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
+ 0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
+ 0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
+ 0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
+ 0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
+ 0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
+ 0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
+ 0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
+ 0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
+ 0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
+ 0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
+ 0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
+ 0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
+ 0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
+ 0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
+ 0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
+ 0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
+ 0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
+ 0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
+ 0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
+ 0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
+ 0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
+ 0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
+ 0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
+ 0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
+ 0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
+ 0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
+ 0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
+ 0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
+ 0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
+ 0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
+ 0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
+ 0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
+ 0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
+ 0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
+ 0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+ 0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
+ 0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
+ 0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
+ 0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
+ 0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
+ 0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
+ 0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
+ 0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
+ 0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
+ 0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
+ 0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
+ 0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
+ 0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
+ 0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
+ 0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
+ 0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
+ 0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
+ 0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
+ 0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
+ 0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
+ 0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
+ 0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
+ 0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
+ 0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
+ 0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
+ 0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
+ 0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
+ 0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
+ 0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
+ 0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
+ 0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
+ 0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
+ 0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
+ 0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
+ 0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
+ 0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
+ 0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
+ 0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
+ 0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
+ 0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
+ 0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
+ 0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
+ 0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
+ 0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
+ 0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
+ 0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
+ 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
+ 0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
+ 0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
+ 0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
+ 0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
+ 0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
+ 0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
+ 0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
+ 0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+ 0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
+ 0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
+ 0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
+ 0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
+ 0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
+ 0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
+ 0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
+ 0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
+ 0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
+ 0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
+ 0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
+ 0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
+ 0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
+ 0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
+ 0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
+ 0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
+ 0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
+ 0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
+ 0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
+ 0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
+ 0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
+ 0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
+ 0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
+ 0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
+ 0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
+ 0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
+ 0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
+ 0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
+ 0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
+ 0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
+ 0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
+ 0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
+ 0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
+ 0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
+ 0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
+ 0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
+ 0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
+ 0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
+ 0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
+ 0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
+ 0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
+ 0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
+ 0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
+ 0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
+ 0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
+ 0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
+ 0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
+ 0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
+ 0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
+ 0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
+ 0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
+ 0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
+ 0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
+ 0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
+ 0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
+ 0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
+ 0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
+ 0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
+ 0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
+ 0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
+ 0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
+ 0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
+ 0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
+ 0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
+ 0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
+ 0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
+ 0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
+ 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
+ 0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
+ 0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
+ 0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
+ 0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
+ 0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
+ 0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
+ 0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
+ 0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+ 0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
+ 0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
+ 0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
+ 0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
+ 0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
+ 0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
+ 0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
+ 0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+ 0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
+ 0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
+ 0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
+ 0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
+ 0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
+ 0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
+ 0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
+ 0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
+ 0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
+ 0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
+ 0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
+ 0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
+ 0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
+ 0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
+ 0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
+ 0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+ 0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
+ 0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
+ 0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
+ 0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
+ 0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
+ 0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
+ 0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
+ 0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
+ 0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+ 0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
+ 0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
+ 0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
+ 0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
+ 0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
+ 0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
+ 0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
+ 0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
+ 0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
+ 0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
+ 0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
+ 0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
+ 0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
+ 0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
+ 0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
+ 0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
+ 0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
+ 0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
+ 0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
+ 0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
+ 0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
+ 0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
+ 0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
+ 0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
+ 0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
+ 0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
+ 0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
+ 0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
+ 0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
+ 0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
+ 0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
+ 0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
+ 0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
+ 0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
+ 0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
+ 0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
+ 0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
+ 0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
+ 0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
+ 0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
+ 0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
+ 0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
+ 0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
+ 0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
+ 0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
+ 0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
+ 0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
+ 0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
+ 0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
+ 0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
+ 0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
+ 0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
+ 0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
+ 0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
+ 0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
+ 0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
+ 0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
+ 0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
+ 0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
+ 0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
+ 0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
+ 0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
+ 0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
+ 0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
+ 0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
+ 0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
+ 0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
+ 0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
+ 0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
+ 0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
+ 0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
+ 0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
+ 0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
+ 0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
+ 0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
+ 0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
+ 0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
+ 0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
+ 0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
+ 0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
+ 0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
+ 0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
+ 0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
+ 0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
+ 0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
+ 0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
+ 0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
+ 0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
+ 0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
+ 0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
+ 0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
+ 0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
+ 0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
+ 0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
+ 0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
+ 0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
+ 0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
+ 0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
+ 0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
+ 0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
+ 0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
+ 0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
+ 0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
+ 0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
+ 0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
+ 0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
+ 0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
+ 0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
+ 0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
+ 0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
+ 0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
+ 0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
+ 0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
+ 0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
+ 0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
+ 0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
+ 0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
+ 0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
+ 0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
+ 0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
+ 0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
+ 0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
+ 0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
+ 0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
+ 0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
+ 0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
+ 0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
+ 0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
+ 0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
+ 0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
+ 0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
+ 0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
+ 0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
+ 0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
+ 0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
+ 0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
+ 0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
+ 0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
+ 0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
+ 0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
+ 0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
+ 0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
+ 0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
+ 0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
+ 0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
+ 0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
+ 0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
+ 0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
+ 0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
+ 0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
+ 0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
+ 0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
+ 0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
+ 0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
+ 0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
+ 0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
+ 0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
+ 0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
+ 0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
+ 0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
+ 0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
+ 0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
+ 0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
+ 0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
+ 0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
+ 0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
+ 0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
+ 0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
+ 0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
+ 0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
+ 0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
+ 0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
+ 0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
+ 0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
+ 0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
+ 0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
+ 0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
+ 0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
+ 0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
+ 0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
+ 0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
+};
+
diff --git a/drivers/sgi/char/newport.c b/drivers/sgi/char/newport.c
index 756aec709..e617ddd99 100644
--- a/drivers/sgi/char/newport.c
+++ b/drivers/sgi/char/newport.c
@@ -215,3 +215,220 @@ newport_ioctl (int card, int cmd, unsigned long arg)
}
return -EINVAL;
}
+/*
+ * newport.c: context switching the newport graphics card and
+ * newport graphics support.
+ *
+ * Author: Miguel de Icaza
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/types.h>
+#include <asm/gfx.h>
+#include <asm/ng1.h>
+#include <asm/uaccess.h>
+#include "newport.h"
+
+/* Kernel routines for supporting graphics context switching */
+
+void newport_save (void *y)
+{
+ newport_ctx *x = y;
+ newport_wait ();
+
+#define LOAD(val) x->val = npregs->set.val;
+#define LOADI(val) x->val = npregs->set.val.i;
+#define LOADC(val) x->val = npregs->cset.val;
+
+ LOAD(drawmode1);
+ LOAD(drawmode0);
+ LOAD(lsmode);
+ LOAD(lspattern);
+ LOAD(lspatsave);
+ LOAD(zpattern);
+ LOAD(colorback);
+ LOAD(colorvram);
+ LOAD(alpharef);
+ LOAD(smask0x);
+ LOAD(smask0y);
+ LOADI(_xstart);
+ LOADI(_ystart);
+ LOADI(_xend);
+ LOADI(_yend);
+ LOAD(xsave);
+ LOAD(xymove);
+ LOADI(bresd);
+ LOADI(bress1);
+ LOAD(bresoctinc1);
+ LOAD(bresrndinc2);
+ LOAD(brese1);
+ LOAD(bress2);
+ LOAD(aweight0);
+ LOAD(aweight1);
+ LOADI(colorred);
+ LOADI(coloralpha);
+ LOADI(colorgrn);
+ LOADI(colorblue);
+ LOADI(slopered);
+ LOADI(slopealpha);
+ LOADI(slopegrn);
+ LOADI(slopeblue);
+ LOAD(wrmask);
+ LOAD(hostrw0);
+ LOAD(hostrw1);
+
+ /* configregs */
+
+ LOADC(smask1x);
+ LOADC(smask1y);
+ LOADC(smask2x);
+ LOADC(smask2y);
+ LOADC(smask3x);
+ LOADC(smask3y);
+ LOADC(smask4x);
+ LOADC(smask4y);
+ LOADC(topscan);
+ LOADC(xywin);
+ LOADC(clipmode);
+ LOADC(config);
+
+ /* Mhm, maybe I am missing something, but it seems that
+ * saving/restoring the DCB is only a matter of saving these
+ * registers
+ */
+
+ newport_bfwait ();
+ LOAD (dcbmode);
+ newport_bfwait ();
+ x->dcbdata0 = npregs->set.dcbdata0.all;
+ newport_bfwait ();
+ LOAD(dcbdata1);
+}
+
+/*
+ * Importat things to keep in mind when restoring the newport context:
+ *
+ * 1. slopered register is stored as a 2's complete (s12.11);
+ * needs to be converted to a signed magnitude (s(8)12.11).
+ *
+ * 2. xsave should be stored after xstart.
+ *
+ * 3. None of the registers should be written with the GO address.
+ * (read the docs for more details on this).
+ */
+void newport_restore (void *y)
+{
+ newport_ctx *x = y;
+#define STORE(val) npregs->set.val = x->val
+#define STOREI(val) npregs->set.val.i = x->val
+#define STOREC(val) npregs->cset.val = x->val
+ newport_wait ();
+
+ STORE(drawmode1);
+ STORE(drawmode0);
+ STORE(lsmode);
+ STORE(lspattern);
+ STORE(lspatsave);
+ STORE(zpattern);
+ STORE(colorback);
+ STORE(colorvram);
+ STORE(alpharef);
+ STORE(smask0x);
+ STORE(smask0y);
+ STOREI(_xstart);
+ STOREI(_ystart);
+ STOREI(_xend);
+ STOREI(_yend);
+ STORE(xsave);
+ STORE(xymove);
+ STOREI(bresd);
+ STOREI(bress1);
+ STORE(bresoctinc1);
+ STORE(bresrndinc2);
+ STORE(brese1);
+ STORE(bress2);
+ STORE(aweight0);
+ STORE(aweight1);
+ STOREI(colorred);
+ STOREI(coloralpha);
+ STOREI(colorgrn);
+ STOREI(colorblue);
+ STOREI(slopered);
+ STOREI(slopealpha);
+ STOREI(slopegrn);
+ STOREI(slopeblue);
+ STORE(wrmask);
+ STORE(hostrw0);
+ STORE(hostrw1);
+
+ /* configregs */
+
+ STOREC(smask1x);
+ STOREC(smask1y);
+ STOREC(smask2x);
+ STOREC(smask2y);
+ STOREC(smask3x);
+ STOREC(smask3y);
+ STOREC(smask4x);
+ STOREC(smask4y);
+ STOREC(topscan);
+ STOREC(xywin);
+ STOREC(clipmode);
+ STOREC(config);
+
+ /* FIXME: restore dcb thingies */
+}
+
+int
+newport_ioctl (int card, int cmd, unsigned long arg)
+{
+ switch (cmd){
+ case NG1_SETDISPLAYMODE: {
+ int i;
+ struct ng1_setdisplaymode_args request;
+
+ if (copy_from_user (&request, (void *) arg, sizeof (request)))
+ return -EFAULT;
+
+ newport_wait ();
+ newport_bfwait ();
+ npregs->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
+ DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
+ xmap9FIFOWait (npregs);
+
+ /* FIXME: timing is wrong, just be extracted from
+ * the per-board timing table. I still have to figure
+ * out where this comes from
+ *
+ * This is used to select the protocol used to talk to
+ * the xmap9. For now I am using 60, selecting the
+ * WSLOW_DCB_XMAP9_PROTOCOL.
+ *
+ * Robert Tray comments on this issue:
+ *
+ * cfreq refers to the frequency of the monitor
+ * (ie. the refresh rate). Our monitors run typically
+ * between 60 Hz and 76 Hz. But it will be as low as
+ * 50 Hz if you're displaying NTSC/PAL and as high as
+ * 120 Hz if you are runining in stereo mode. You
+ * might want to try the WSLOW values.
+ */
+ xmap9SetModeReg (npregs, request.wid, request.mode, 60);
+ return 0;
+ }
+ case NG1_SET_CURSOR_HOTSPOT: {
+ struct ng1_set_cursor_hotspot request;
+
+ if (copy_from_user (&request, (void *) arg, sizeof (request)))
+ return -EFAULT;
+ /* FIXME: make request.xhot, request.yhot the hot spot */
+ return 0;
+ }
+
+ case NG1_SETGAMMARAMP0:
+ /* FIXME: load the gamma ramps :-) */
+ return 0;
+
+ }
+ return -EINVAL;
+}
diff --git a/drivers/sgi/char/newport.h b/drivers/sgi/char/newport.h
index 2f9f044cb..6ad987045 100644
--- a/drivers/sgi/char/newport.h
+++ b/drivers/sgi/char/newport.h
@@ -1,4 +1,589 @@
-/* $Id: newport.h,v 1.4 1997/08/28 01:45:17 miguel Exp $
+/* $Id: newport.h,v 1.2 1996/06/10 16:38:34 dm Exp $
+ * newport.h: Defines and register layout for NEWPORT graphics
+ * hardware.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+
+#ifndef _SGI_NEWPORT_H
+#define _SGI_NEWPORT_H
+
+
+typedef volatile unsigned long npireg_t;
+
+union npfloat {
+ volatile float f;
+ npireg_t i;
+};
+
+typedef union npfloat npfreg_t;
+
+union np_dcb {
+ npireg_t all;
+ struct { volatile unsigned short s0, s1; } hwords;
+ struct { volatile unsigned char b0, b1, b2, b3; } bytes;
+};
+
+struct newport_rexregs {
+ npireg_t drawmode1; /* GL extra mode bits */
+
+#define DM1_PLANES 0x00000007
+#define DM1_NOPLANES 0x00000000
+#define DM1_RGBPLANES 0x00000001
+#define DM1_RGBAPLANES 0x00000002
+#define DM1_OLAYPLANES 0x00000004
+#define DM1_PUPPLANES 0x00000005
+#define DM1_CIDPLANES 0x00000006
+
+#define NPORT_DMODE1_DDMASK 0x00000018
+#define NPORT_DMODE1_DD4 0x00000000
+#define NPORT_DMODE1_DD8 0x00000008
+#define NPORT_DMODE1_DD12 0x00000010
+#define NPORT_DMODE1_DD24 0x00000018
+#define NPORT_DMODE1_DSRC 0x00000020
+#define NPORT_DMODE1_YFLIP 0x00000040
+#define NPORT_DMODE1_RWPCKD 0x00000080
+#define NPORT_DMODE1_HDMASK 0x00000300
+#define NPORT_DMODE1_HD4 0x00000000
+#define NPORT_DMODE1_HD8 0x00000100
+#define NPORT_DMODE1_HD12 0x00000200
+#define NPORT_DMODE1_HD32 0x00000300
+#define NPORT_DMODE1_RWDBL 0x00000400
+#define NPORT_DMODE1_ESWAP 0x00000800 /* Endian swap */
+#define NPORT_DMODE1_CCMASK 0x00007000
+#define NPORT_DMODE1_CCLT 0x00001000
+#define NPORT_DMODE1_CCEQ 0x00002000
+#define NPORT_DMODE1_CCGT 0x00004000
+#define NPORT_DMODE1_RGBMD 0x00008000
+#define NPORT_DMODE1_DENAB 0x00010000 /* Dither enable */
+#define NPORT_DMODE1_FCLR 0x00020000 /* Fast clear */
+#define NPORT_DMODE1_BENAB 0x00040000 /* Blend enable */
+#define NPORT_DMODE1_SFMASK 0x00380000
+#define NPORT_DMODE1_SF0 0x00000000
+#define NPORT_DMODE1_SF1 0x00080000
+#define NPORT_DMODE1_SFDC 0x00100000
+#define NPORT_DMODE1_SFMDC 0x00180000
+#define NPORT_DMODE1_SFSA 0x00200000
+#define NPORT_DMODE1_SFMSA 0x00280000
+#define NPORT_DMODE1_DFMASK 0x01c00000
+#define NPORT_DMODE1_DF0 0x00000000
+#define NPORT_DMODE1_DF1 0x00400000
+#define NPORT_DMODE1_DFSC 0x00800000
+#define NPORT_DMODE1_DFMSC 0x00c00000
+#define NPORT_DMODE1_DFSA 0x01000000
+#define NPORT_DMODE1_DFMSA 0x01400000
+#define NPORT_DMODE1_BBENAB 0x02000000 /* Back blend enable */
+#define NPORT_DMODE1_PFENAB 0x04000000 /* Pre-fetch enable */
+#define NPORT_DMODE1_ABLEND 0x08000000 /* Alpha blend */
+#define NPORT_DMODE1_LOMASK 0xf0000000
+#define NPORT_DMODE1_LOZERO 0x00000000
+#define NPORT_DMODE1_LOAND 0x10000000
+#define NPORT_DMODE1_LOANDR 0x20000000
+#define NPORT_DMODE1_LOSRC 0x30000000
+#define NPORT_DMODE1_LOANDI 0x40000000
+#define NPORT_DMODE1_LODST 0x50000000
+#define NPORT_DMODE1_LOXOR 0x60000000
+#define NPORT_DMODE1_LOOR 0x70000000
+#define NPORT_DMODE1_LONOR 0x80000000
+#define NPORT_DMODE1_LOXNOR 0x90000000
+#define NPORT_DMODE1_LONDST 0xa0000000
+#define NPORT_DMODE1_LOORR 0xb0000000
+#define NPORT_DMODE1_LONSRC 0xc0000000
+#define NPORT_DMODE1_LOORI 0xd0000000
+#define NPORT_DMODE1_LONAND 0xe0000000
+#define NPORT_DMODE1_LOONE 0xf0000000
+
+ npireg_t drawmode0; /* REX command register */
+
+ /* These bits define the graphics opcode being performed. */
+#define NPORT_DMODE0_OPMASK 0x00000003 /* Opcode mask */
+#define NPORT_DMODE0_NOP 0x00000000 /* No operation */
+#define NPORT_DMODE0_RD 0x00000001 /* Read operation */
+#define NPORT_DMODE0_DRAW 0x00000002 /* Draw operation */
+#define NPORT_DMODE0_S2S 0x00000003 /* Screen to screen operation */
+
+ /* The following decide what addressing mode(s) are to be used */
+#define NPORT_DMODE0_AMMASK 0x0000001c /* Address mode mask */
+#define NPORT_DMODE0_SPAN 0x00000000 /* Spanning address mode */
+#define NPORT_DMODE0_BLOCK 0x00000004 /* Block address mode */
+#define NPORT_DMODE0_ILINE 0x00000008 /* Iline address mode */
+#define NPORT_DMODE0_FLINE 0x0000000c /* Fline address mode */
+#define NPORT_DMODE0_ALINE 0x00000010 /* Aline address mode */
+#define NPORT_DMODE0_TLINE 0x00000014 /* Tline address mode */
+#define NPORT_DMODE0_BLINE 0x00000018 /* Bline address mode */
+
+ /* And now some misc. operation control bits. */
+#define NPORT_DMODE0_DOSETUP 0x00000020
+#define NPORT_DMODE0_CHOST 0x00000040
+#define NPORT_DMODE0_AHOST 0x00000080
+#define NPORT_DMODE0_STOPX 0x00000100
+#define NPORT_DMODE0_STOPY 0x00000200
+#define NPORT_DMODE0_SK1ST 0x00000400
+#define NPORT_DMODE0_SKLST 0x00000800
+#define NPORT_DMODE0_ZPENAB 0x00001000
+#define NPORT_DMODE0_LISPENAB 0x00002000
+#define NPORT_DMODE0_LISLST 0x00004000
+#define NPORT_DMODE0_L32 0x00008000
+#define NPORT_DMODE0_ZOPQ 0x00010000
+#define NPORT_DMODE0_LISOPQ 0x00020000
+#define NPORT_DMODE0_SHADE 0x00040000
+#define NPORT_DMODE0_LRONLY 0x00080000
+#define NPORT_DMODE0_XYOFF 0x00100000
+#define NPORT_DMODE0_CLAMP 0x00200000
+#define NPORT_DMODE0_ENDPF 0x00400000
+#define NPORT_DMODE0_YSTR 0x00800000
+
+ npireg_t lsmode; /* Mode for line stipple ops */
+ npireg_t lspattern; /* Pattern for line stipple ops */
+ npireg_t lspatsave; /* Backup save pattern */
+ npireg_t zpattern; /* Pixel zpattern */
+ npireg_t colorback; /* Background color */
+ npireg_t colorvram; /* Clear color for fast vram */
+ npireg_t alpharef; /* Reference value for afunctions */
+ unsigned long pad0;
+ npireg_t smask0x; /* Window GL relative screen mask 0 */
+ npireg_t smask0y; /* Window GL relative screen mask 0 */
+ npireg_t _setup;
+ npireg_t _stepz;
+ npireg_t _lsrestore;
+ npireg_t _lssave;
+
+ unsigned long _pad1[0x30];
+
+ /* Iterators, full state for context switch */
+ npfreg_t _xstart; /* X-start point (current) */
+ npfreg_t _ystart; /* Y-start point (current) */
+ npfreg_t _xend; /* x-end point */
+ npfreg_t _yend; /* y-end point */
+ npireg_t xsave; /* copy of xstart integer value for BLOCk addressing MODE */
+ npireg_t xymove; /* x.y offset from xstart, ystart for relative operations */
+ npfreg_t bresd;
+ npfreg_t bress1;;
+ npireg_t bresoctinc1;
+ volatile int bresrndinc2;
+ npireg_t brese1;
+ npireg_t bress2;
+ npireg_t aweight0;
+ npireg_t aweight1;
+ npfreg_t xstartf;
+ npfreg_t ystartf;
+ npfreg_t xendf;
+ npfreg_t yendf;
+ npireg_t xstarti;
+ npfreg_t xendf1;
+ npireg_t xystarti;
+ npireg_t xyendi;
+ npireg_t xstartendi;
+
+ unsigned long _unused2[0x29];
+
+ npfreg_t colorred;
+ npfreg_t coloralpha;
+ npfreg_t colorgrn;
+ npfreg_t colorblue;
+ npfreg_t slopered;
+ npfreg_t slopealpha;
+ npfreg_t slopegrn;
+ npfreg_t slopeblue;
+ npireg_t wrmask;
+ npireg_t colori;
+ npfreg_t colorx;
+ npfreg_t slopered1;
+ npireg_t hostrw0;
+ npireg_t hostrw1;
+ npireg_t dcbmode;
+#define NPORT_DMODE_WMASK 0x00000003
+#define NPORT_DMODE_W4 0x00000000
+#define NPORT_DMODE_W1 0x00000001
+#define NPORT_DMODE_W2 0x00000002
+#define NPORT_DMODE_W3 0x00000003
+#define NPORT_DMODE_EDPACK 0x00000004
+#define NPORT_DMODE_ECINC 0x00000008
+#define NPORT_DMODE_CMASK 0x00000070
+#define NPORT_DMODE_AMASK 0x00000780
+#define NPORT_DMODE_AVC2 0x00000000
+#define NPORT_DMODE_ACMALL 0x00000080
+#define NPORT_DMODE_ACM0 0x00000100
+#define NPORT_DMODE_ACM1 0x00000180
+#define NPORT_DMODE_AXMALL 0x00000200
+#define NPORT_DMODE_AXM0 0x00000280
+#define NPORT_DMODE_AXM1 0x00000300
+#define NPORT_DMODE_ABT 0x00000380
+#define NPORT_DMODE_AVCC1 0x00000400
+#define NPORT_DMODE_AVAB1 0x00000480
+#define NPORT_DMODE_ALG3V0 0x00000500
+#define NPORT_DMODE_A1562 0x00000580
+#define NPORT_DMODE_ESACK 0x00000800
+#define NPORT_DMODE_EASACK 0x00001000
+#define NPORT_DMODE_CWMASK 0x0003e000
+#define NPORT_DMODE_CHMASK 0x007c0000
+#define NPORT_DMODE_CSMASK 0x0f800000
+#define NPORT_DMODE_SENDIAN 0x10000000
+
+ unsigned long _unused3;
+
+ union np_dcb dcbdata0;
+ npireg_t dcbdata1;
+};
+
+struct newport_cregs {
+ npireg_t smask1x;
+ npireg_t smask1y;
+ npireg_t smask2x;
+ npireg_t smask2y;
+ npireg_t smask3x;
+ npireg_t smask3y;
+ npireg_t smask4x;
+ npireg_t smask4y;
+ npireg_t topscan;
+ npireg_t xywin;
+ npireg_t clipmode;
+#define NPORT_CMODE_SM0 0x00000001
+#define NPORT_CMODE_SM1 0x00000002
+#define NPORT_CMODE_SM2 0x00000004
+#define NPORT_CMODE_SM3 0x00000008
+#define NPORT_CMODE_SM4 0x00000010
+#define NPORT_CMODE_CMSK 0x00001e00
+
+ unsigned long _unused0;
+ unsigned long config;
+#define NPORT_CFG_G32MD 0x00000001
+#define NPORT_CFG_BWIDTH 0x00000002
+#define NPORT_CFG_ERCVR 0x00000004
+#define NPORT_CFG_BDMSK 0x00000078
+#define NPORT_CFG_GDMSK 0x00000f80
+#define NPORT_CFG_GD0 0x00000080
+#define NPORT_CFG_GD1 0x00000100
+#define NPORT_CFG_GD2 0x00000200
+#define NPORT_CFG_GD3 0x00000400
+#define NPORT_CFG_GD4 0x00000800
+#define NPORT_CFG_GFAINT 0x00001000
+#define NPORT_CFG_TOMSK 0x0000e000
+#define NPORT_CFG_VRMSK 0x00070000
+#define NPORT_CFG_FBTYP 0x00080000
+
+ npireg_t _unused1;
+ npireg_t stat;
+#define NPORT_STAT_VERS 0x00000007
+#define NPORT_STAT_GBUSY 0x00000008
+#define NPORT_STAT_BBUSY 0x00000010
+#define NPORT_STAT_VRINT 0x00000020
+#define NPORT_STAT_VIDINT 0x00000040
+#define NPORT_STAT_GLMSK 0x00001f80
+#define NPORT_STAT_BLMSK 0x0007e000
+#define NPORT_STAT_BFIRQ 0x00080000
+#define NPORT_STAT_GFIRQ 0x00100000
+
+ npireg_t ustat;
+ npireg_t dreset;
+};
+
+struct newport_regs {
+ struct newport_rexregs set;
+ unsigned long _unused0[0x16e];
+ struct newport_rexregs go;
+ unsigned long _unused1[0x22e];
+ struct newport_cregs cset;
+ unsigned long _unused2[0x1ef];
+ struct newport_cregs cgo;
+};
+extern struct newport_regs *npregs;
+
+
+typedef struct {
+ unsigned int drawmode1;
+ unsigned int drawmode0;
+ unsigned int lsmode;
+ unsigned int lspattern;
+ unsigned int lspatsave;
+ unsigned int zpattern;
+ unsigned int colorback;
+ unsigned int colorvram;
+ unsigned int alpharef;
+ unsigned int smask0x;
+ unsigned int smask0y;
+ unsigned int _xstart;
+ unsigned int _ystart;
+ unsigned int _xend;
+ unsigned int _yend;
+ unsigned int xsave;
+ unsigned int xymove;
+ unsigned int bresd;
+ unsigned int bress1;
+ unsigned int bresoctinc1;
+ unsigned int bresrndinc2;
+ unsigned int brese1;
+ unsigned int bress2;
+
+ unsigned int aweight0;
+ unsigned int aweight1;
+ unsigned int colorred;
+ unsigned int coloralpha;
+ unsigned int colorgrn;
+ unsigned int colorblue;
+ unsigned int slopered;
+ unsigned int slopealpha;
+ unsigned int slopegrn;
+ unsigned int slopeblue;
+ unsigned int wrmask;
+ unsigned int hostrw0;
+ unsigned int hostrw1;
+
+ /* configregs */
+
+ unsigned int smask1x;
+ unsigned int smask1y;
+ unsigned int smask2x;
+ unsigned int smask2y;
+ unsigned int smask3x;
+ unsigned int smask3y;
+ unsigned int smask4x;
+ unsigned int smask4y;
+ unsigned int topscan;
+ unsigned int xywin;
+ unsigned int clipmode;
+ unsigned int config;
+
+ /* dcb registers */
+ unsigned int dcbmode;
+ unsigned int dcbdata0;
+ unsigned int dcbdata1;
+} newport_ctx;
+
+/* Reading/writing VC2 registers. */
+#define VC2_REGADDR_INDEX 0x00000000
+#define VC2_REGADDR_IREG 0x00000010
+#define VC2_REGADDR_RAM 0x00000030
+#define VC2_PROTOCOL (NPORT_DMODE_EASACK | 0x00800000 | 0x00040000)
+
+#define VC2_VLINET_ADDR 0x000
+#define VC2_VFRAMET_ADDR 0x400
+#define VC2_CGLYPH_ADDR 0x500
+
+/* Now the Indexed registers of the VC2. */
+#define VC2_IREG_VENTRY 0x00
+#define VC2_IREG_CENTRY 0x01
+#define VC2_IREG_CURSX 0x02
+#define VC2_IREG_CURSY 0x03
+#define VC2_IREG_CCURSX 0x04
+#define VC2_IREG_DENTRY 0x05
+#define VC2_IREG_SLEN 0x06
+#define VC2_IREG_RADDR 0x07
+#define VC2_IREG_VFPTR 0x08
+#define VC2_IREG_VLSPTR 0x09
+#define VC2_IREG_VLIR 0x0a
+#define VC2_IREG_VLCTR 0x0b
+#define VC2_IREG_CTPTR 0x0c
+#define VC2_IREG_WCURSY 0x0d
+#define VC2_IREG_DFPTR 0x0e
+#define VC2_IREG_DLTPTR 0x0f
+#define VC2_IREG_CONTROL 0x10
+#define VC2_IREG_CONFIG 0x20
+
+extern inline void newport_vc2_set(struct newport_regs *regs, unsigned char vc2ireg,
+ unsigned short val)
+{
+ regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W3 |
+ NPORT_DMODE_ECINC | VC2_PROTOCOL);
+ regs->set.dcbdata0.all = (vc2ireg << 24) | (val << 8);
+}
+
+extern inline unsigned short newport_vc2_get(struct newport_regs *regs,
+ unsigned char vc2ireg)
+{
+ regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W1 |
+ NPORT_DMODE_ECINC | VC2_PROTOCOL);
+ regs->set.dcbdata0.bytes.b3 = vc2ireg;
+ regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_IREG | NPORT_DMODE_W2 |
+ NPORT_DMODE_ECINC | VC2_PROTOCOL);
+ return regs->set.dcbdata0.hwords.s1;
+}
+
+/* VC2 Control register bits */
+#define VC2_CTRL_EVIRQ 0x0001
+#define VC2_CTRL_EDISP 0x0002
+#define VC2_CTRL_EVIDEO 0x0004
+#define VC2_CTRL_EDIDS 0x0008
+#define VC2_CTRL_ECURS 0x0010
+#define VC2_CTRL_EGSYNC 0x0020
+#define VC2_CTRL_EILACE 0x0040
+#define VC2_CTRL_ECDISP 0x0080
+#define VC2_CTRL_ECCURS 0x0100
+#define VC2_CTRL_ECG64 0x0200
+#define VC2_CTRL_GLSEL 0x0400
+
+/* Controlling the color map on NEWPORT. */
+#define NCMAP_REGADDR_AREG 0x00000000
+#define NCMAP_REGADDR_ALO 0x00000000
+#define NCMAP_REGADDR_AHI 0x00000010
+#define NCMAP_REGADDR_PBUF 0x00000020
+#define NCMAP_REGADDR_CREG 0x00000030
+#define NCMAP_REGADDR_SREG 0x00000040
+#define NCMAP_REGADDR_RREG 0x00000060
+#define NCMAP_PROTOCOL (0x00008000 | 0x00040000 | 0x00800000)
+
+static inline void newport_cmap_setaddr(struct newport_regs *regs,
+ unsigned short addr)
+{
+ regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
+ NPORT_DMODE_SENDIAN | NPORT_DMODE_ECINC |
+ NCMAP_REGADDR_AREG | NPORT_DMODE_W2);
+ regs->set.dcbdata0.hwords.s1 = addr;
+ regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
+ NCMAP_REGADDR_PBUF | NPORT_DMODE_W3);
+}
+
+static inline void newport_cmap_setrgb(struct newport_regs *regs,
+ unsigned char red,
+ unsigned char green,
+ unsigned char blue)
+{
+ regs->set.dcbdata0.all =
+ (red << 24) |
+ (green << 16) |
+ (blue << 8);
+}
+
+/* Miscellaneous NEWPORT routines. */
+#define BUSY_TIMEOUT 100000
+static inline int newport_wait(void)
+{
+ int i = 0;
+
+ while(i < BUSY_TIMEOUT)
+ if(!(npregs->cset.stat & NPORT_STAT_GBUSY))
+ break;
+ if(i == BUSY_TIMEOUT)
+ return 1;
+ return 0;
+}
+
+static inline int newport_bfwait(void)
+{
+ int i = 0;
+
+ while(i < BUSY_TIMEOUT)
+ if(!(npregs->cset.stat & NPORT_STAT_BBUSY))
+ break;
+ if(i == BUSY_TIMEOUT)
+ return 1;
+ return 0;
+}
+
+/* newport.c and cons_newport.c routines */
+extern struct graphics_ops *newport_probe (int, const char **);
+
+void newport_save (void *);
+void newport_restore (void *);
+void newport_reset (void);
+int newport_ioctl (int card, int cmd, unsigned long arg);
+
+/*
+ * DCBMODE register defines:
+ */
+
+/* Widht of the data being transfered for each DCBDATA[01] word */
+#define DCB_DATAWIDTH_4 0x0
+#define DCB_DATAWIDTH_1 0x1
+#define DCB_DATAWIDTH_2 0x2
+#define DCB_DATAWIDTH_3 0x3
+
+/* If set, all of DCBDATA will be moved, otherwise only DATAWIDTH bytes */
+#define DCB_ENDATAPACK (1 << 2)
+
+/* Enables DCBCRS auto increment after each DCB transfer */
+#define DCB_ENCRSINC (1 << 3)
+
+/* shift for accessing the control register select address (DBCCRS, 3 bits) */
+#define DCB_CRS_SHIFT 4
+
+/* DCBADDR (4 bits): display bus slave address */
+#define DCB_ADDR_SHIFT 7
+#define DCB_VC2 (0 << DCB_ADDR_SHIFT)
+#define DCB_CMAP_ALL (1 << DCB_ADDR_SHIFT)
+#define DCB_CMAP0 (2 << DCB_ADDR_SHIFT)
+#define DCB_CMAP1 (3 << DCB_ADDR_SHIFT)
+#define DCB_XMAP_ALL (4 << DCB_ADDR_SHIFT)
+#define DCB_XMAP0 (5 << DCB_ADDR_SHIFT)
+#define DCB_XMAP1 (6 << DCB_ADDR_SHIFT)
+#define DCB_BT445 (7 << DCB_ADDR_SHIFT)
+#define DCB_VCC1 (8 << DCB_ADDR_SHIFT)
+#define DCB_VAB1 (9 << DCB_ADDR_SHIFT)
+#define DCB_LG3_BDVERS0 (10 << DCB_ADDR_SHIFT)
+#define DCB_LG3_ICS1562 (11 << DCB_ADDR_SHIFT)
+#define DCB_RESERVED (15 << DCB_ADDR_SHIFT)
+
+/* DCB protocol ack types */
+#define DCB_ENSYNCACK (1 << 11)
+#define DCB_ENASYNCACK (1 << 12)
+
+#define DCB_CSWIDTH_SHIFT 13
+#define DCB_CSHOLD_SHIFT 18
+#define DCB_CSSETUP_SHIFT 23
+
+/* XMAP9 specific defines */
+/* XMAP9 -- registers as seen on the DCBMODE register*/
+# define XM9_CRS_CONFIG (0 << DCB_CRS_SHIFT)
+# define XM9_PUPMODE (1 << 0)
+# define XM9_ODD_PIXEL (1 << 1)
+# define XM9_8_BITPLANES (1 << 2)
+# define XM9_SLOW_DCB (1 << 3)
+# define XM9_VIDEO_RGBMAP_MASK (3 << 4)
+# define XM9_EXPRESS_VIDEO (1 << 6)
+# define XM9_VIDEO_OPTION (1 << 7)
+# define XM9_CRS_REVISION (1 << DCB_CRS_SHIFT)
+# define XM9_CRS_FIFO_AVAIL (2 << DCB_CRS_SHIFT)
+# define XM9_FIFO_0_AVAIL 0
+# define XM9_FIFO_1_AVAIL 1
+# define XM9_FIFO_2_AVAIL 3
+# define XM9_FIFO_3_AVAIL 2
+# define XM9_FIFO_FULL XM9_FIFO_0_AVAIL
+# define XM9_FIFO_EMPTY XM9_FIFO_3_AVAIL
+# define XM9_CRS_CURS_CMAP_MSB (3 << DCB_CRS_SHIFT)
+# define XM9_CRS_PUP_CMAP_MSB (4 << DCB_CRS_SHIFT)
+# define XM9_CRS_MODE_REG_DATA (5 << DCB_CRS_SHIFT)
+# define XM9_CRS_MODE_REG_INDEX (7 << DCB_CRS_SHIFT)
+
+
+#define DCB_CYCLES(setup,hold,width) \
+ ((hold << DCB_CSHOLD_SHIFT) | \
+ (setup << DCB_CSSETUP_SHIFT)| \
+ (width << DCB_CSWIDTH_SHIFT))
+
+#define W_DCB_XMAP9_PROTOCOL DCB_CYCLES (2, 1, 0)
+#define WSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (5, 5, 0)
+#define WAYSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (12, 12, 0)
+#define R_DCB_XMAP9_PROTOCOL DCB_CYCLES (2, 1, 3)
+
+static inline void
+xmap9FIFOWait (struct newport_regs *rex)
+{
+ rex->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
+ DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
+ newport_bfwait ();
+
+ while ((rex->set.dcbdata0.bytes.b3 & 3) != XM9_FIFO_EMPTY)
+ ;
+}
+
+static inline void
+xmap9SetModeReg (struct newport_regs *rex, unsigned int modereg, unsigned int data24, int cfreq)
+{
+ if (cfreq > 119)
+ rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+ DCB_DATAWIDTH_4 | W_DCB_XMAP9_PROTOCOL;
+ else if (cfreq > 59)
+ rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+ DCB_DATAWIDTH_4 | WSLOW_DCB_XMAP9_PROTOCOL;
+ else
+ rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
+ DCB_DATAWIDTH_4 | WAYSLOW_DCB_XMAP9_PROTOCOL;
+ rex->set.dcbdata0.all = ((modereg) << 24) | (data24 & 0xffffff);
+}
+
+#endif /* !(_SGI_NEWPORT_H) */
+
+/* $Id: newport.h,v 1.5 1997/09/21 23:06:05 miguel Exp $
* newport.h: Defines and register layout for NEWPORT graphics
* hardware.
*
diff --git a/drivers/sgi/char/rrm.c b/drivers/sgi/char/rrm.c
index b13c79588..507299354 100644
--- a/drivers/sgi/char/rrm.c
+++ b/drivers/sgi/char/rrm.c
@@ -67,3 +67,72 @@ rrm_close (struct inode *inode, struct file *file)
return 0;
}
+/*
+ * Linux Rendering Resource Manager
+ *
+ * Implements the SGI-compatible rendering resource manager.
+ * This takes care of implementing the virtualized video hardware
+ * access required for OpenGL direct rendering.
+ *
+ * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Fixes:
+ */
+#include <asm/uaccess.h>
+#include <asm/rrm.h>
+
+int
+rrm_open_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+int
+rrm_close_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+int
+rrm_bind_proc_to_rn (int rnid, void *arg)
+{
+ return 0;
+}
+
+typedef int (*rrm_function )(void *arg);
+
+struct {
+ int (*r_fn)(int rnid, void *arg);
+ int arg_size;
+} rrm_functions [] = {
+ { rrm_open_rn, sizeof (struct RRM_OpenRN) },
+ { rrm_close_rn, sizeof (struct RRM_CloseRN) },
+ { rrm_bind_proc_to_rn, sizeof (struct RRM_BindProcToRN) }
+};
+
+#define RRM_FUNCTIONS (sizeof (rrm_functions)/sizeof (rrm_functions [0]))
+
+/* cmd is a number in the range [0..RRM_CMD_LIMIT-RRM_BASE] */
+int
+rrm_command (unsigned int cmd, void *arg)
+{
+ int i, rnid;
+
+ if (cmd > RRM_FUNCTIONS){
+ printk ("Called unimplemented rrm ioctl: %d\n", cmd + RRM_BASE);
+ return -EINVAL;
+ }
+ i = verify_area (VERIFY_READ, arg, rrm_functions [cmd].arg_size);
+ if (i) return i;
+
+ __get_user_ret (rnid, (int *) arg, -EFAULT);
+ return (*(rrm_functions [cmd].r_fn))(rnid, arg);
+}
+
+int
+rrm_close (struct inode *inode, struct file *file)
+{
+ /* This routine is invoked when the device is closed */
+ return 0;
+}
+
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index 746ac93b4..069b8dbe1 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -159,6 +159,189 @@ void set_vesa_blanking(const unsigned long arg) { }
void vesa_powerdown(void) { }
void set_palette (void) { }
+extern unsigned long video_mem_base, video_screen_size, video_mem_term;
+
+__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name))
+{
+ extern int serial_console;
+
+ if (serial_console)
+ *name = "NONE";
+ else {
+ gfx_init (name);
+ printk("Video screen size is %08lx at %08lx\n",
+ video_screen_size, start_mem);
+ video_mem_base = start_mem;
+ start_mem += (video_screen_size * 2);
+ video_mem_term = start_mem;
+ }
+ return start_mem;
+}
+
+__initfunc(void con_type_init_finish(void))
+{
+}
+/*
+ * sgicons.c: Setting up and registering console I/O on the SGI.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * This implement a virtual console interface.
+ *
+ * This should be replaced with Gert's all-singing all-dancing
+ * graphics console code in the future
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include "gconsole.h"
+
+/* To make psaux code cleaner */
+int aux_device_present = 0xaa;
+
+/* This is the system graphics console (the first adapter found) */
+struct console_ops *gconsole = 0;
+struct console_ops *real_gconsole = 0;
+
+void
+enable_gconsole (void)
+{
+ if (!gconsole)
+ gconsole = real_gconsole;
+}
+
+void
+disable_gconsole (void)
+{
+ if (gconsole){
+ real_gconsole = gconsole;
+ gconsole = 0;
+ }
+}
+
+void
+register_gconsole (struct console_ops *gc)
+{
+ if (gconsole)
+ return;
+ gconsole = gc;
+}
+
+void
+__set_origin (unsigned short offset)
+{
+ if (gconsole)
+ (*gconsole->set_origin)(offset);
+}
+
+void
+hide_cursor (void)
+{
+
+ if (gconsole)
+ (*gconsole->hide_cursor)();
+}
+
+void
+set_cursor (int currcons)
+{
+ if (gconsole)
+ (*gconsole->set_cursor)(currcons);
+}
+
+void
+get_scrmem (int currcons)
+{
+ if (gconsole)
+ (*gconsole->get_scrmem)(currcons);
+}
+
+void
+set_scrmem (int currcons, long offset)
+{
+ if (gconsole)
+ (*gconsole->set_scrmem)(currcons, offset);
+}
+
+int
+set_get_cmap (unsigned char *arg, int set)
+{
+ if (gconsole)
+ return (*gconsole->set_get_cmap)(arg, set);
+ return 0;
+}
+
+void
+blitc (unsigned short charattr, unsigned long addr)
+{
+ if (gconsole)
+ (*gconsole->blitc)(charattr, addr);
+}
+
+void
+memsetw (void *s, unsigned short c, unsigned int count)
+{
+ if (gconsole)
+ (*gconsole->memsetw)(s, c, count);
+}
+
+void
+memcpyw (unsigned short *to, unsigned short *from, unsigned int count)
+{
+ if (gconsole)
+ (*gconsole->memcpyw)(to, from, count);
+}
+
+int
+con_adjust_height (unsigned long fontheight)
+{
+ return -EINVAL;
+}
+
+int
+set_get_font (char *arg, int set, int ch512)
+{
+ int error, i, line;
+
+ if (!arg)
+ return -EINVAL;
+ error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
+ ch512 ? 2* cmapsz : cmapsz);
+ if (error)
+ return error;
+
+ /* download the current font */
+ if (!set) {
+ memset (arg, 0, cmapsz);
+ for (i = 0; i < 256; i++) {
+ for (line = 0; line < CHAR_HEIGHT; line++)
+ __put_user (vga_font [i], arg+(i*32+line));
+ }
+ return 0;
+ }
+
+ /* set the font */
+ for (i = 0; i < 256; i++) {
+ for (line = 0; line < CHAR_HEIGHT; line++) {
+ __get_user(vga_font [i*CHAR_HEIGHT + line],
+ arg + (i * 32 + line));
+ }
+ }
+ return 0;
+}
+
+/*
+ * dummy routines for the VESA blanking code, which is VGA only,
+ * so we don't have to carry that stuff around for the Sparc... */
+void vesa_blank(void) { }
+void vesa_unblank(void) { }
+void set_vesa_blanking(const unsigned long arg) { }
+void vesa_powerdown(void) { }
+void set_palette (void) { }
+
__initfunc(int con_is_present())
{
return 1;
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index c8d4d7e54..b6a3effc6 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -1601,6 +1601,2025 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
!(info->flags & ZILOG_CLOSING) && do_clocal)
break;
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct sgi_serial *info;
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ /* The zilog lines for the mouse/keyboard must be
+ * opened using their respective drivers.
+ */
+ if ((line < 0) || (line >= NUM_CHANNELS))
+ return -ENODEV;
+ info = zs_soft + line;
+ /* Is the kgdb running over this line? */
+ if (info->kgdb_channel)
+ return -ENODEV;
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
+ return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->count);
+#endif
+ info->count++;
+ tty->driver_data = info;
+ info->tty = tty;
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval)
+ return retval;
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d successful...", info->line);
+#endif
+ return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+ printk("SGI Zilog8530 serial driver version 1.00\n");
+}
+
+/* Return layout for the requested zs chip number. */
+static inline struct sgi_zslayout *get_zs(int chip)
+{
+ extern struct hpc3_miscregs *hpc3mregs;
+
+ if(chip > 0) {
+ prom_printf("Wheee, bogus zs chip number requested.\n");
+ prom_getchar();
+ romvec->imode();
+ }
+ return (struct sgi_zslayout *) (&hpc3mregs->ser1cmd);
+
+}
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct sgi_serial *ss, int channel)
+{
+ int i, o, io;
+ static consout_registered = 0;
+ static msg_printed = 0;
+
+ i = o = io = 0;
+
+ /* Is this one of the serial console lines? */
+ if((zs_cons_chanout != channel) &&
+ (zs_cons_chanin != channel))
+ return;
+ zs_conschan = ss->zs_channel;
+ zs_consinfo = ss;
+
+ /* Register the console output putchar, if necessary */
+ if((zs_cons_chanout == channel)) {
+ o = 1;
+ /* double whee.. */
+ if(!consout_registered) {
+ register_console(zs_console_print);
+ consout_registered = 1;
+ }
+ }
+
+ /* If this is console input, we handle the break received
+ * status interrupt on this line to mean prom_halt().
+ */
+ if(zs_cons_chanin == channel) {
+ ss->break_abort = 1;
+ i = 1;
+ }
+ if(o && i)
+ io = 1;
+ if(ss->zs_baud != 9562) { /* Don't ask... */
+ prom_printf("BAD console baud rate %d\n", ss->zs_baud);
+ prom_getchar();
+ prom_imode();
+ panic("Console baud rate weirdness");
+ }
+
+ /* Set flag variable for this port so that it cannot be
+ * opened for other uses by accident.
+ */
+ ss->is_cons = 1;
+
+ if(io) {
+ if(!msg_printed) {
+ printk("zs%d: console I/O\n", ((channel>>1)&1));
+ msg_printed = 1;
+ }
+ } else {
+ printk("zs%d: console %s\n", ((channel>>1)&1),
+ (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+ }
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+ int chip, channel, i, flags;
+ struct sgi_serial *info;
+
+ /* Setup base handler, and timer table. */
+ init_bh(SERIAL_BH, do_serial_bh);
+ timer_table[RS_TIMER].fn = rs_timer;
+ timer_table[RS_TIMER].expires = 0;
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+ /* SGI: Not all of this is exactly right for us. */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = NUM_CHANNELS;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ save_flags(flags); cli();
+
+ /* Set up our interrupt linked list */
+ zs_chain = &zs_soft[0];
+ zs_soft[0].zs_next = &zs_soft[1];
+ zs_soft[1].zs_next = 0;
+
+ for(chip = 0; chip < NUM_SERIAL; chip++) {
+ /* If we are doing kgdb over one of the channels on
+ * chip zero, kgdb_channel will be set to 1 by the
+ * rs_kgdb_hook() routine below.
+ */
+ if(!zs_chips[chip]) {
+ zs_chips[chip] = get_zs(chip);
+ /* Two channels per chip */
+ zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+ zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+ zs_soft[(chip*2)].kgdb_channel = 0;
+ zs_soft[(chip*2)+1].kgdb_channel = 0;
+ }
+ /* First, set up channel A on this chip. */
+ channel = chip * 2;
+ zs_soft[channel].zs_channel = zs_channels[channel];
+ zs_soft[channel].change_needed = 0;
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+ zs_soft[channel].cons_mouse = 0;
+ /* If not keyboard/mouse and is console serial
+ * line, then enable receiver interrupts.
+ */
+ if(zs_soft[channel].is_cons) {
+ write_zsreg(zs_soft[channel].zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx));
+ write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
+ write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+ write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+ write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB));
+ }
+ /* If this is the kgdb line, enable interrupts because we
+ * now want to receive the 'control-c' character from the
+ * client attached to us asynchronously.
+ */
+ if(zs_soft[channel].kgdb_channel)
+ kgdb_chaninit(&zs_soft[channel], 1,
+ zs_soft[channel].zs_baud);
+
+ /* Now, channel B */
+ channel++;
+ zs_soft[channel].zs_channel = zs_channels[channel];
+ zs_soft[channel].change_needed = 0;
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+ zs_soft[channel].cons_keyb = 0;
+ /* If console serial line, then enable receiver interrupts. */
+ if(zs_soft[channel].is_cons) {
+ write_zsreg(zs_soft[channel].zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx));
+ write_zsreg(zs_soft[channel].zs_channel, R9,
+ (NV | MIE));
+ write_zsreg(zs_soft[channel].zs_channel, R10,
+ (NRZ));
+ write_zsreg(zs_soft[channel].zs_channel, R3,
+ (Rx8|RxENABLE));
+ write_zsreg(zs_soft[channel].zs_channel, R5,
+ (Tx8 | TxENAB | RTS | DTR));
+ }
+ }
+
+ for(info=zs_chain, i=0; info; info = info->zs_next, i++)
+ {
+ info->magic = SERIAL_MAGIC;
+ info->port = (int) info->zs_channel;
+ info->line = i;
+ info->tty = 0;
+ info->irq = zilog_irq;
+ info->custom_divisor = 16;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->callout_termios =callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ printk("tty%02d at 0x%04x (irq = %d)", info->line,
+ info->port, info->irq);
+ printk(" is a Zilog8530\n");
+ }
+
+ if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT),
+ "Zilog8530", zs_chain))
+ panic("Unable to attach zs intr\n");
+ restore_flags(flags);
+
+ return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* SGI: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+ return -1;
+}
+
+void unregister_serial(int line)
+{
+ return;
+}
+
+/* Hooks for running a serial console. con_init() calls this if the
+ * console is being run over one of the ttya/ttyb serial ports.
+ * 'chip' should be zero, as chip 1 drives the mouse/keyboard.
+ * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels
+ * are addressed backwards, channel B is first, then channel A.
+ */
+void
+rs_cons_hook(int chip, int out, int line)
+{
+ int channel;
+
+ if(chip)
+ panic("rs_cons_hook called with chip not zero");
+ if(line != 1 && line != 2)
+ panic("rs_cons_hook called with line not ttya or ttyb");
+ channel = line - 1;
+ if(!zs_chips[chip]) {
+ zs_chips[chip] = get_zs(chip);
+ /* Two channels per chip */
+ zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+ zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+ }
+ zs_soft[channel].zs_channel = zs_channels[channel];
+ zs_soft[channel].change_needed = 0;
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+ if(out)
+ zs_cons_chanout = ((chip * 2) + channel);
+ else
+ zs_cons_chanin = ((chip * 2) + channel);
+ rs_cons_check(&zs_soft[channel], channel);
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line. The 'tty_num' argument is 0 for /dev/ttyd2 and 1 for
+ * /dev/ttyd1 (yes they are backwards on purpose) which is determined
+ * in setup_arch() from the boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+ int chip = 0;
+
+ if(!zs_chips[chip]) {
+ zs_chips[chip] = get_zs(chip);
+ /* Two channels per chip */
+ zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
+ zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+ }
+ zs_soft[tty_num].zs_channel = zs_channels[tty_num];
+ zs_kgdbchan = zs_soft[tty_num].zs_channel;
+ zs_soft[tty_num].change_needed = 0;
+ zs_soft[tty_num].clk_divisor = 16;
+ zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
+ zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+
+ /* Turn on transmitter/receiver at 8-bits/char */
+ kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+ ZS_CLEARERR(zs_kgdbchan);
+ udelay(5);
+ ZS_CLEARFIFO(zs_kgdbchan);
+}
+/* sgiserial.c: Serial port driver for SGI machines.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sgialib.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/sgihpc.h>
+#include <asm/sgint23.h>
+#include <asm/uaccess.h>
+
+#include "sgiserial.h"
+
+#define NUM_SERIAL 1 /* One chip on board. */
+#define NUM_CHANNELS (NUM_SERIAL * 2)
+
+extern struct wait_queue * keypress_wait;
+
+struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
+struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
+struct sgi_zschannel *zs_conschan;
+struct sgi_zschannel *zs_kgdbchan;
+int zs_nodes[NUM_SERIAL] = { 0, };
+
+struct sgi_serial zs_soft[NUM_CHANNELS];
+struct sgi_serial *zs_chain; /* IRQ servicing chain */
+static int zilog_irq = 21;
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct sgi_serial *zs_consinfo = 0;
+
+static unsigned char kgdb_regs[16] = {
+ 0, 0, 0, /* write 0, 1, 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK | SB1 | PAR_EVEN), /* write 4 */
+ (Tx8 | TxENAB), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ (DCDIE) /* write 15 */
+};
+
+#define ZS_CLOCK 3672000 /* Zilog input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void change_speed(struct sgi_serial *info);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct sgi_serial *info,
+ dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for serial struct (%d, %d) in %s\n";
+ static const char *badinfo =
+ "Warning: null sun_serial for (%d, %d) in %s\n";
+
+ if (!info) {
+ printk(badinfo, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+ if (info->magic != SERIAL_MAGIC) {
+ printk(badmagic, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 0 };
+
+/*
+ * Reading and writing Zilog8530 registers. The delays are to make this
+ * driver work on the Sun4 which needs a settling delay after each chip
+ * register access, other machines handle this in hardware via auxiliary
+ * flip-flops which implement the settle time we do in software.
+ */
+static inline unsigned char read_zsreg(struct sgi_zschannel *channel, unsigned char reg)
+{
+ unsigned char retval;
+ volatile unsigned char junk;
+
+ udelay(2);
+ channel->control = reg;
+ junk = ioc_icontrol->istat0;
+ udelay(1);
+ retval = channel->control;
+ return retval;
+}
+
+static inline void write_zsreg(struct sgi_zschannel *channel, unsigned char reg, unsigned char value)
+{
+ volatile unsigned char junk;
+
+ udelay(2);
+ channel->control = reg;
+ junk = ioc_icontrol->istat0;
+ udelay(1);
+ channel->control = value;
+ junk = ioc_icontrol->istat0;
+ return;
+}
+
+static inline void load_zsregs(struct sgi_zschannel *channel, unsigned char *regs)
+{
+ ZS_CLEARERR(channel);
+ ZS_CLEARFIFO(channel);
+ /* Load 'em up */
+ write_zsreg(channel, R4, regs[R4]);
+ write_zsreg(channel, R10, regs[R10]);
+ write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R11, regs[R11]);
+ write_zsreg(channel, R12, regs[R12]);
+ write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14]);
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R3, regs[R3]);
+ write_zsreg(channel, R5, regs[R5]);
+ return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct sgi_serial *ss, int set)
+{
+ if(set) {
+ ss->curregs[5] |= (RTS | DTR);
+ ss->pendregs[5] = ss->curregs[5];
+ write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+ } else {
+ ss->curregs[5] &= ~(RTS | DTR);
+ ss->pendregs[5] = ss->curregs[5];
+ write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+ }
+ return;
+}
+
+static inline void kgdb_chaninit(struct sgi_serial *ss, int intson, int bps)
+{
+ int brg;
+
+ if(intson) {
+ kgdb_regs[R1] = INT_ALL_Rx;
+ kgdb_regs[R9] |= MIE;
+ } else {
+ kgdb_regs[R1] = 0;
+ kgdb_regs[R9] &= ~MIE;
+ }
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ kgdb_regs[R12] = (brg & 255);
+ kgdb_regs[R13] = ((brg >> 8) & 255);
+ load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct sgi_serial *ss)
+{
+ struct sgi_zschannel *channel = ss->zs_channel;
+ int brg;
+
+ /* The baud rate is split up between two 8-bit registers in
+ * what is termed 'BRG time constant' format in my docs for
+ * the chip, it is a function of the clk rate the chip is
+ * receiving which happens to be constant.
+ */
+ brg = ((read_zsreg(channel, 13)&0xff) << 8);
+ brg |= (read_zsreg(channel, 12)&0xff);
+ return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+ save_flags(flags); cli();
+ if (info->curregs[5] & TxENAB) {
+ info->curregs[5] &= ~TxENAB;
+ info->pendregs[5] &= ~TxENAB;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ }
+ restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_start"))
+ return;
+
+ save_flags(flags); cli();
+ if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
+ info->curregs[5] |= TxENAB;
+ info->pendregs[5] = info->curregs[5];
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ }
+ restore_flags(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+ prom_imode();
+#if 0
+ /* If we are doing kadb, we call the debugger
+ * else we just drop into the boot monitor.
+ * Note that we must flush the user windows
+ * first before giving up control.
+ */
+ printk("\n");
+ if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&
+ (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
+ sp_enter_debugger();
+ else
+ prom_halt();
+
+ /* XXX We want to notify the keyboard driver that all
+ * XXX keys are in the up state or else weird things
+ * XXX happen...
+ */
+#endif
+ return;
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct sgi_zschannel *zsc)
+{
+ volatile unsigned char junk;
+
+ udelay(2);
+ zsc->control = ERR_RES;
+ junk = ioc_icontrol->istat0;
+ udelay(2);
+ zsc->control = RES_H_IUS;
+ junk = ioc_icontrol->istat0;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * 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 sgi_serial *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_async_breakpoint(unsigned int epc);
+#endif
+
+static _INLINE_ void receive_chars(struct sgi_serial *info, struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ volatile unsigned char junk;
+ unsigned char ch, stat;
+
+ udelay(2);
+ ch = info->zs_channel->data;
+ junk = ioc_icontrol->istat0;
+ udelay(2);
+ stat = read_zsreg(info->zs_channel, R1);
+
+ /* If this is the console keyboard, we need to handle
+ * L1-A's here.
+ */
+ if(info->is_cons) {
+ if(ch==0) { /* whee, break received */
+ batten_down_hatches();
+ rs_recv_clear(info->zs_channel);
+ return;
+ } else if (ch == 1) {
+ show_state();
+ return;
+ } else if (ch == 2) {
+ show_buffers();
+ return;
+ }
+ /* It is a 'keyboard interrupt' ;-) */
+ wake_up(&keypress_wait);
+ }
+ /* Look for kgdb 'stop' character, consult the gdb documentation
+ * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+ * to see how all this works.
+ */
+#ifdef CONFIG_REMOTE_DEBUG
+ if((info->kgdb_channel) && (ch =='\003')) {
+ set_async_breakpoint(read_32bit_cp0_register(CP0_EPC));
+ goto clear_and_exit;
+ }
+#endif
+ if(!tty)
+ goto clear_and_exit;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ tty->flip.count++;
+ if(stat & PAR_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ else if(stat & Rx_OVR)
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ else if(stat & CRC_ERR)
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ else
+ *tty->flip.flag_buf_ptr++ = 0; /* XXX */
+ *tty->flip.char_buf_ptr++ = ch;
+
+ queue_task(&tty->flip.tqueue, &tq_timer);
+
+clear_and_exit:
+ rs_recv_clear(info->zs_channel);
+ return;
+}
+
+static _INLINE_ void transmit_chars(struct sgi_serial *info)
+{
+ volatile unsigned char junk;
+
+ /* P3: In theory we have to test readiness here because a
+ * serial console can clog the chip through rs_put_char().
+ * David did not do this. I think he relies on 3-chars FIFO in 8530.
+ * Let's watch for lost _output_ characters. XXX
+ */
+
+ /* SGI ADDENDUM: On most SGI machines, the Zilog does possess
+ * a 16 or 17 byte fifo, so no worries. -dm
+ */
+
+ if (info->x_char) {
+ /* Send next char */
+ udelay(2);
+ info->zs_channel->data = info->x_char;
+ junk = ioc_icontrol->istat0;
+
+ info->x_char = 0;
+ goto clear_and_return;
+ }
+
+ if((info->xmit_cnt <= 0) || info->tty->stopped) {
+ /* That's peculiar... */
+ udelay(2);
+ info->zs_channel->control = RES_Tx_P;
+ junk = ioc_icontrol->istat0;
+ goto clear_and_return;
+ }
+
+ /* Send char */
+ udelay(2);
+ info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+ junk = ioc_icontrol->istat0;
+
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+ if(info->xmit_cnt <= 0) {
+ udelay(2);
+ info->zs_channel->control = RES_Tx_P;
+ junk = ioc_icontrol->istat0;
+ goto clear_and_return;
+ }
+
+clear_and_return:
+ /* Clear interrupt */
+ udelay(2);
+ info->zs_channel->control = RES_H_IUS;
+ junk = ioc_icontrol->istat0;
+ return;
+}
+
+static _INLINE_ void status_handle(struct sgi_serial *info)
+{
+ volatile unsigned char junk;
+ unsigned char status;
+
+ /* Get status from Read Register 0 */
+ udelay(2);
+ status = info->zs_channel->control;
+ junk = ioc_icontrol->istat0;
+ /* Clear status condition... */
+ udelay(2);
+ info->zs_channel->control = RES_EXT_INT;
+ junk = ioc_icontrol->istat0;
+ /* Clear the interrupt */
+ udelay(2);
+ info->zs_channel->control = RES_H_IUS;
+ junk = ioc_icontrol->istat0;
+
+#if 0
+ if(status & DCD) {
+ if((info->tty->termios->c_cflag & CRTSCTS) &&
+ ((info->curregs[3] & AUTO_ENAB)==0)) {
+ info->curregs[3] |= AUTO_ENAB;
+ info->pendregs[3] |= AUTO_ENAB;
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ }
+ } else {
+ if((info->curregs[3] & AUTO_ENAB)) {
+ info->curregs[3] &= ~AUTO_ENAB;
+ info->pendregs[3] &= ~AUTO_ENAB;
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ }
+ }
+#endif
+ /* Whee, if this is console input and this is a
+ * 'break asserted' status change interrupt, call
+ * the boot prom.
+ */
+ if((status & BRK_ABRT) && info->break_abort)
+ batten_down_hatches();
+
+ /* XXX Whee, put in a buffer somewhere, the status information
+ * XXX whee whee whee... Where does the information go...
+ */
+ return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct sgi_serial * info = (struct sgi_serial *) dev_id;
+ unsigned char zs_intreg;
+
+ zs_intreg = read_zsreg(info->zs_channel, 3);
+
+ /* NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
+#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+ /* *** Chip 1 *** */
+ /* Channel A -- /dev/ttya, could be the console */
+ if(zs_intreg & CHAN_A_IRQMASK) {
+ if (zs_intreg & CHARxIP)
+ receive_chars(info, regs);
+ if (zs_intreg & CHATxIP)
+ transmit_chars(info);
+ if (zs_intreg & CHAEXT)
+ status_handle(info);
+ }
+
+ info=info->zs_next;
+
+ /* Channel B -- /dev/ttyb, could be the console */
+ if(zs_intreg & CHAN_B_IRQMASK) {
+ if (zs_intreg & CHBRxIP)
+ receive_chars(info, regs);
+ if (zs_intreg & CHBTxIP)
+ transmit_chars(info);
+ if (zs_intreg & CHBEXT)
+ status_handle(info);
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+ struct sgi_serial *info = (struct sgi_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ *
+ */
+static void do_serial_hangup(void *private_)
+{
+ struct sgi_serial *info = (struct sgi_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ tty_hangup(tty);
+}
+
+
+/*
+ * This subroutine is called when the RS_TIMER goes off. It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0). This doesn't work at all for 16450's, as a sun has a Z8530.
+ */
+
+static void rs_timer(void)
+{
+ printk("rs_timer called\n");
+ prom_halt();
+ return;
+}
+
+static int startup(struct sgi_serial * info)
+{
+ volatile unsigned char junk;
+ unsigned long flags;
+
+ if (info->flags & ZILOG_INITIALIZED)
+ return 0;
+
+ if (!info->xmit_buf) {
+ info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+ if (!info->xmit_buf)
+ return -ENOMEM;
+ }
+
+ save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+#endif
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in change_speed())
+ */
+ ZS_CLEARFIFO(info->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ udelay(2);
+ info->zs_channel->control = ERR_RES;
+ junk = ioc_icontrol->istat0;
+ udelay(2);
+ info->zs_channel->control = RES_H_IUS;
+ junk = ioc_icontrol->istat0;
+
+ /*
+ * Now, initialize the Zilog
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
+ info->pendregs[1] = info->curregs[1];
+ info->curregs[3] |= (RxENABLE | Rx8);
+ info->pendregs[3] = info->curregs[3];
+ /* We enable Tx interrupts as needed. */
+ info->curregs[5] |= (TxENAB | Tx8);
+ info->pendregs[5] = info->curregs[5];
+ info->curregs[9] |= (NV | MIE);
+ info->pendregs[9] = info->curregs[9];
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ write_zsreg(info->zs_channel, 9, info->curregs[9]);
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ udelay(2);
+ info->zs_channel->control = ERR_RES;
+ junk = ioc_icontrol->istat0;
+ udelay(2);
+ info->zs_channel->control = RES_H_IUS;
+ junk = ioc_icontrol->istat0;
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * Set up serial timers...
+ */
+#if 0 /* Works well and stops the machine. */
+ timer_table[RS_TIMER].expires = jiffies + 2;
+ timer_active |= 1 << RS_TIMER;
+#endif
+
+ /*
+ * and set the speed of the serial port
+ */
+ change_speed(info);
+
+ info->flags |= ZILOG_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct sgi_serial * info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ZILOG_INITIALIZED))
+ return;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d (irq %d)....", info->line,
+ info->irq);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ZILOG_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct sgi_serial *info)
+{
+ unsigned short port;
+ unsigned cflag;
+ int i;
+ int brg;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+ if (!(port = info->port))
+ return;
+ i = cflag & CBAUD;
+ if (i & CBAUDEX) {
+ /* XXX CBAUDEX is not obeyed.
+ * It is impossible at a 32bits SPARC.
+ * But we have to report this to user ... someday.
+ */
+ i = B9600;
+ }
+ if (i == 0) {
+ /* XXX B0, hangup the line. */
+ do_serial_hangup(info);
+ } else if (baud_table[i]) {
+ info->zs_baud = baud_table[i];
+ info->clk_divisor = 16;
+
+ info->curregs[4] = X16CLK;
+ info->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ info->curregs[12] = (brg & 255);
+ info->curregs[13] = ((brg >> 8) & 255);
+ info->curregs[14] = BRENABL;
+ }
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->curregs[3] &= ~(0xc0);
+ info->curregs[3] |= Rx5;
+ info->pendregs[3] = info->curregs[3];
+ info->curregs[5] &= ~(0xe0);
+ info->curregs[5] |= Tx5;
+ info->pendregs[5] = info->curregs[5];
+ break;
+ case CS6:
+ info->curregs[3] &= ~(0xc0);
+ info->curregs[3] |= Rx6;
+ info->pendregs[3] = info->curregs[3];
+ info->curregs[5] &= ~(0xe0);
+ info->curregs[5] |= Tx6;
+ info->pendregs[5] = info->curregs[5];
+ break;
+ case CS7:
+ info->curregs[3] &= ~(0xc0);
+ info->curregs[3] |= Rx7;
+ info->pendregs[3] = info->curregs[3];
+ info->curregs[5] &= ~(0xe0);
+ info->curregs[5] |= Tx7;
+ info->pendregs[5] = info->curregs[5];
+ break;
+ case CS8:
+ default: /* defaults to 8 bits */
+ info->curregs[3] &= ~(0xc0);
+ info->curregs[3] |= Rx8;
+ info->pendregs[3] = info->curregs[3];
+ info->curregs[5] &= ~(0xe0);
+ info->curregs[5] |= Tx8;
+ info->pendregs[5] = info->curregs[5];
+ break;
+ }
+ info->curregs[4] &= ~(0x0c);
+ if (cflag & CSTOPB) {
+ info->curregs[4] |= SB2;
+ } else {
+ info->curregs[4] |= SB1;
+ }
+ info->pendregs[4] = info->curregs[4];
+ if (cflag & PARENB) {
+ info->curregs[4] |= PAR_ENA;
+ info->pendregs[4] |= PAR_ENA;
+ } else {
+ info->curregs[4] &= ~PAR_ENA;
+ info->pendregs[4] &= ~PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->curregs[4] |= PAR_EVEN;
+ info->pendregs[4] |= PAR_EVEN;
+ } else {
+ info->curregs[4] &= ~PAR_EVEN;
+ info->pendregs[4] &= ~PAR_EVEN;
+ }
+
+ /* Load up the new values */
+ load_zsregs(info->zs_channel, info->curregs);
+
+ return;
+}
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+ struct sgi_zschannel *chan = zs_conschan;
+ volatile unsigned char junk;
+ int flags, loops = 0;
+
+ save_flags(flags); cli();
+ while(((junk = chan->control) & Tx_BUF_EMP)==0 && loops < 10000) {
+ loops++;
+ udelay(2);
+ }
+
+ udelay(2);
+ chan->data = ch;
+ junk = ioc_icontrol->istat0;
+ restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct sgi_zschannel *chan = zs_kgdbchan;
+ volatile unsigned char junk;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ udelay(2);
+ while((chan->control & Tx_BUF_EMP)==0)
+ udelay(2);
+
+ udelay(2);
+ chan->data = kgdb_char;
+ junk = ioc_icontrol->istat0;
+ restore_flags(flags);
+}
+
+char getDebugChar(void)
+{
+ struct sgi_zschannel *chan = zs_kgdbchan;
+ unsigned char junk;
+
+ while((chan->control & Rx_CH_AV)==0)
+ udelay(2);
+
+ junk = ioc_icontrol->istat0;
+ udelay(2);
+ return chan->data;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+ int left; /* Output no more than that */
+ unsigned long flags;
+ struct sgi_serial *info = zs_consinfo;
+ volatile unsigned char junk;
+ char c;
+
+ if (info == 0) return;
+ if (info->xmit_buf == 0) return;
+
+ save_flags(flags); cli();
+ left = info->xmit_cnt;
+ while (left != 0) {
+ c = info->xmit_buf[info->xmit_tail];
+ info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ restore_flags(flags);
+
+ rs_put_char(c);
+
+ save_flags(flags); cli();
+ left = MIN(info->xmit_cnt, left-1);
+ }
+
+ /* Last character is being transmitted now (hopefully). */
+ udelay(2);
+ zs_conschan->control = RES_Tx_P;
+ junk = ioc_icontrol->istat0;
+
+ restore_flags(flags);
+ return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+ char c;
+
+ while((c=*(p++)) != 0) {
+ if(c == '\n')
+ rs_put_char('\r');
+ rs_put_char(c);
+ }
+
+ /* Comment this if you want to have a strict interrupt-driven output */
+ rs_fair_output();
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ write_zsreg(info->zs_channel, 1, info->curregs[1]);
+ info->curregs[5] |= TxENAB;
+ info->pendregs[5] |= TxENAB;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+ /*
+ * Send a first (bootstrapping) character. A best solution is
+ * to call transmit_chars() here which handles output in a
+ * generic way. Current transmit_chars() not only transmits,
+ * but resets interrupts also what we do not desire here.
+ * XXX Discuss with David.
+ */
+ if (info->zs_channel->control & Tx_BUF_EMP) {
+ volatile unsigned char junk;
+
+ /* Send char */
+ udelay(2);
+ info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+ junk = ioc_icontrol->istat0;
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ }
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ copy_from_user(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+ !(info->curregs[5] & TxENAB)) {
+ /* Enable transmitter */
+ info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ write_zsreg(info->zs_channel, 1, info->curregs[1]);
+ info->curregs[5] |= TxENAB;
+ info->pendregs[5] |= TxENAB;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ }
+ restore_flags(flags);
+ return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ int ret;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+ return 0;
+ return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+ return;
+ cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ sti();
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+ return;
+
+ if (I_IXOFF(tty))
+ info->x_char = STOP_CHAR(tty);
+
+ /* Turn off RTS line */
+ cli();
+ info->curregs[5] &= ~RTS;
+ info->pendregs[5] &= ~RTS;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ info->x_char = START_CHAR(tty);
+ }
+
+ /* Assert RTS line */
+ cli();
+ info->curregs[5] |= RTS;
+ info->pendregs[5] |= RTS;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct sgi_serial * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->port;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct sgi_serial * info,
+ struct serial_struct * new_info)
+{
+ struct serial_struct new_serial;
+ struct sgi_serial old_info;
+ int retval = 0;
+
+ if (!new_info)
+ return -EFAULT;
+ copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ old_info = *info;
+
+ if (!suser()) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.type != info->type) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ZILOG_USR_MASK) !=
+ (info->flags & ~ZILOG_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+ (new_serial.flags & ZILOG_USR_MASK));
+ info->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud_base = new_serial.baud_base;
+ info->flags = ((info->flags & ~ZILOG_FLAGS) |
+ (new_serial.flags & ZILOG_FLAGS));
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+ retval = startup(info);
+ return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct sgi_serial * info, unsigned int *value)
+{
+ volatile unsigned char junk;
+ unsigned char status;
+
+ cli();
+ udelay(2);
+ status = info->zs_channel->control;
+ junk = ioc_icontrol->istat0;
+ sti();
+ return put_user(status,value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break( struct sgi_serial * info, int duration)
+{
+ if (!info->port)
+ return;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+ cli();
+ write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
+ schedule();
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int error;
+ struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+ int retval;
+
+ if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ send_break(info, HZ/4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+ case TIOCGSOFTCAR:
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+ if (error)
+ return error;
+ put_user(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ return 0;
+ case TIOCSSOFTCAR:
+ error = get_user(arg, (unsigned long *)arg);
+ if (error)
+ return error;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCGSERIAL:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct sgi_serial));
+ if (error)
+ return error;
+ copy_to_user((struct sun_serial *) arg,
+ info, sizeof(struct sgi_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+
+ change_speed(info);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ rs_start(tty);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * ZILOG structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+ return;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ZILOG_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ /** if (!info->iscons) ... **/
+ info->curregs[3] &= ~RxENABLE;
+ info->pendregs[3] = info->curregs[3];
+ write_zsreg(info->zs_channel, 3, info->curregs[3]);
+ info->curregs[1] &= ~(0x18);
+ info->pendregs[1] = info->curregs[1];
+ write_zsreg(info->zs_channel, 1, info->curregs[1]);
+ ZS_CLEARFIFO(info->zs_channel);
+
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (tty->ldisc.num != ldiscs[N_TTY].num) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open)(tty);
+ }
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->close_delay;
+ schedule();
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+ ZILOG_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+ struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+ return;
+
+ rs_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct sgi_serial *info)
+{
+ struct wait_queue wait = { current, NULL };
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ZILOG_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ZILOG_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ZILOG_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ info->count--;
+ info->blocked_open++;
+ while (1) {
+ cli();
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE))
+ zs_rtsdtr(info, 1);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ZILOG_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ !(info->flags & ZILOG_CLOSING) && do_clocal)
+ break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
diff --git a/drivers/sgi/char/sgiserial.h b/drivers/sgi/char/sgiserial.h
index 35f18cab7..9a6c589d5 100644
--- a/drivers/sgi/char/sgiserial.h
+++ b/drivers/sgi/char/sgiserial.h
@@ -442,3 +442,447 @@ extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
#endif
#endif /* !(_SPARC_SERIAL_H) */
+/* sgiserial.h: Definitions for the SGI Zilog85C30 serial driver.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#ifndef _SGI_SERIAL_H
+#define _SGI_SERIAL_H
+
+/* Just one channel */
+struct sgi_zschannel {
+#ifdef __MIPSEB__
+ volatile unsigned char unused0[3];
+ volatile unsigned char control;
+ volatile unsigned char unused1[3];
+ volatile unsigned char data;
+#else /* __MIPSEL__ */
+ volatile unsigned char control;
+ volatile unsigned char unused0[3];
+ volatile unsigned char data;
+ volatile unsigned char unused1[3];
+#endif
+};
+
+/* The address space layout for each zs chip. Yes they are
+ * backwards.
+ */
+struct sgi_zslayout {
+ struct sgi_zschannel channelB;
+ struct sgi_zschannel channelA;
+};
+
+#define NUM_ZSREGS 16
+
+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 ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE 65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#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.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct sgi_serial {
+ struct sgi_serial *zs_next; /* For IRQ servicing chain */
+ struct sgi_zschannel *zs_channel; /* Channel registers */
+ unsigned char read_reg_zero;
+
+ char soft_carrier; /* Use soft carrier on this channel */
+ char cons_keyb; /* Channel runs the keyboard */
+ char cons_mouse; /* Channel runs the mouse */
+ char break_abort; /* Is serial console in, so process brk/abrt */
+ char kgdb_channel; /* Kgdb is running on this channel */
+ char is_cons; /* Is this our console. */
+
+ /* 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;
+
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int flags; /* defined in tty.h */
+ int type; /* UART 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;
+ 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 tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+};
+
+
+#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
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define CRC_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc inlines */
+extern inline void ZS_CLEARERR(struct sgi_zschannel *channel)
+{
+ volatile unsigned char junk;
+
+ udelay(2);
+ channel->control = ERR_RES;
+ junk = ioc_icontrol->istat0;
+}
+
+extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
+{
+ volatile unsigned char junk;
+
+ udelay(2);
+ junk = channel->data;
+ udelay(2); junk = ioc_icontrol->istat0;
+ junk = channel->data;
+ udelay(2); junk = ioc_icontrol->istat0;
+ junk = channel->data;
+ udelay(2); junk = ioc_icontrol->istat0;
+}
+
+#if 0
+
+#define ZS_CLEARERR(channel) (channel->control = ERR_RES)
+#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
+ garbage = channel->data; \
+ udelay(2); \
+ garbage = channel->data; \
+ udelay(2); \
+ garbage = channel->data; \
+ udelay(2); } while(0)
+
+#endif
+
+#endif /* !(_SPARC_SERIAL_H) */
diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c
index 37a8b9bf9..623f34abe 100644
--- a/drivers/sgi/char/shmiq.c
+++ b/drivers/sgi/char/shmiq.c
@@ -47,6 +47,466 @@
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/major.h>
+
+#include <asm/smp_lock.h>
+#include <asm/shmiq.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include "graphics.h"
+
+/* we are not really getting any more than a few files in the shmiq */
+#define MAX_SHMIQ_DEVS 10
+
+/*
+ * One per X server running, not going to get very big.
+ * Even if we have this we now assume just 1 /dev/qcntl can be
+ * active, I need to find how this works on multi-headed machines.
+ */
+#define MAX_SHMI_QUEUES 4
+
+static struct {
+ int used;
+ struct file *filp;
+ struct shmiqsetcpos cpos;
+} shmiq_pushed_devices [MAX_SHMIQ_DEVS];
+
+/* /dev/qcntlN attached memory regions, location and size of the event queue */
+static struct {
+ int opened; /* if this device has been opened */
+ void *shmiq_vaddr; /* mapping in kernel-land */
+ int tail; /* our copy of the shmiq->tail */
+ int events;
+ int mapped;
+
+ struct wait_queue *proc_list;
+ struct fasync_struct *fasync;
+} shmiqs [MAX_SHMI_QUEUES];
+
+void
+shmiq_push_event (struct shmqevent *e)
+{
+ struct sharedMemoryInputQueue *s;
+ int device = 0; /* FIXME: here is the assumption /dev/shmiq == /dev/qcntl0 */
+ int tail_next;
+
+ if (!shmiqs [device].mapped)
+ return;
+ s = shmiqs [device].shmiq_vaddr;
+
+ s->flags = 0;
+ if (s->tail != shmiqs [device].tail){
+ s->flags |= SHMIQ_CORRUPTED;
+ return;
+ }
+ tail_next = (s->tail + 1) % (shmiqs [device].events);
+
+ if (tail_next == s->head){
+ s->flags |= SHMIQ_OVERFLOW;
+ return;
+ }
+
+ e->un.time = jiffies;
+ s->events [s->tail] = *e;
+ printk ("KERNEL: dev=%d which=%d type=%d flags=%d\n",
+ e->data.device, e->data.which, e->data.type, e->data.flags);
+ s->tail = tail_next;
+ shmiqs [device].tail = tail_next;
+ if (shmiqs [device].fasync)
+ kill_fasync (shmiqs [device].fasync, SIGIO);
+ wake_up_interruptible (&shmiqs [device].proc_list);
+}
+
+static int
+shmiq_manage_file (struct file *filp)
+{
+ int i;
+
+ if (!filp->f_op || !filp->f_op->ioctl)
+ return -ENOSR;
+
+ for (i = 0; i < MAX_SHMIQ_DEVS; i++){
+ if (shmiq_pushed_devices [i].used)
+ continue;
+ if ((*filp->f_op->ioctl)(filp->f_dentry->d_inode, filp, SHMIQ_ON, i) != 0)
+ return -ENOSR;
+ shmiq_pushed_devices [i].used = 1;
+ shmiq_pushed_devices [i].filp = filp;
+ shmiq_pushed_devices [i].cpos.x = 0;
+ shmiq_pushed_devices [i].cpos.y = 0;
+ return i;
+ }
+ return -ENOSR;
+}
+
+static int
+shmiq_forget_file (unsigned long fdes)
+{
+ struct file *filp;
+
+ if (fdes > MAX_SHMIQ_DEVS)
+ return -EINVAL;
+
+ if (!shmiq_pushed_devices [fdes].used)
+ return -EINVAL;
+
+ filp = shmiq_pushed_devices [fdes].filp;
+ if (filp){
+ (*filp->f_op->ioctl)(filp->f_dentry->d_inode, filp, SHMIQ_OFF, 0);
+ shmiq_pushed_devices [fdes].filp = 0;
+ fput (filp);
+ }
+ shmiq_pushed_devices [fdes].used = 0;
+
+ return 0;
+}
+
+static int
+shmiq_sioc (int device, int cmd, struct strioctl *s)
+{
+ switch (cmd){
+ case QIOCGETINDX:
+ /*
+ * Ok, we just return the index they are providing us
+ */
+ printk ("QIOCGETINDX: returning %d\n", *(int *)s->ic_dp);
+ return 0;
+
+ case QIOCIISTR: {
+ struct muxioctl *mux = (struct muxioctl *) s->ic_dp;
+
+ printk ("Double indirect ioctl: [%d, %x\n", mux->index, mux->realcmd);
+ return -EINVAL;
+ }
+
+ case QIOCSETCPOS: {
+ if (copy_from_user (&shmiq_pushed_devices [device].cpos, s->ic_dp,
+ sizeof (struct shmiqsetcpos)))
+ return -EFAULT;
+ return 0;
+ }
+ }
+ printk ("Unknown I_STR request for shmiq device: 0x%x\n", cmd);
+ return -EINVAL;
+}
+
+static int
+shmiq_ioctl (struct inode *inode, struct file *f, unsigned int cmd, unsigned long arg)
+{
+ struct file *file;
+ struct strioctl sioc;
+ int v;
+
+ switch (cmd){
+ /*
+ * They are giving us the file descriptor for one
+ * of their streams devices
+ */
+
+ case I_LINK:
+ file = fget (arg);
+ if (!file)
+ goto bad_file;
+
+ v = shmiq_manage_file (file);
+ return v;
+
+ /*
+ * Remove a device from our list of managed
+ * stream devices
+ */
+ case I_UNLINK:
+ v = shmiq_forget_file (arg);
+ return v;
+
+ case I_STR:
+ v = get_sioc (&sioc, arg);
+ if (v)
+ return v;
+
+ /* FIXME: This forces device = 0 */
+ return shmiq_sioc (0, sioc.ic_cmd, &sioc);
+ }
+
+ return -EINVAL;
+bad_file:
+ unlock_kernel ();
+ return -EBADF;
+}
+
+extern sys_munmap(unsigned long addr, size_t len);
+
+static int
+qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg, int minor)
+{
+ struct shmiqreq req;
+ struct vm_area_struct *vma;
+ int v;
+
+ switch (cmd){
+ /*
+ * The address space is already mapped as a /dev/zero
+ * mapping. FIXME: check that /dev/zero is what the user
+ * had mapped before :-)
+ */
+ case QIOCATTACH: {
+ unsigned long vaddr;
+ int s;
+
+ v = verify_area (VERIFY_READ, (void *) arg, sizeof (struct shmiqreq));
+ if (v)
+ return v;
+ if (copy_from_user (&req, (void *) arg, sizeof (req)))
+ return -EFAULT;
+ /* Do not allow to attach to another region if it has been already attached */
+ if (shmiqs [minor].mapped){
+ printk ("SHMIQ:The thingie is already mapped\n");
+ return -EINVAL;
+ }
+
+ vaddr = (unsigned long) req.user_vaddr;
+ vma = find_vma (current->mm, vaddr);
+ if (!vma){
+ printk ("SHMIQ: could not find %lx the vma\n", vaddr);
+ return -EINVAL;
+ }
+ s = req.arg * sizeof (struct shmqevent) + sizeof (struct sharedMemoryInputQueue);
+ v = sys_munmap (vaddr, s);
+ do_mmap (filp, vaddr, s, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 0);
+ shmiqs [minor].events = req.arg;
+ shmiqs [minor].mapped = 1;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+unsigned long
+shmiq_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+{
+ /* Do not allow for mremap to expand us */
+ return 0;
+}
+
+static struct vm_operations_struct qcntl_mmap = {
+ NULL, /* no special mmap-open */
+ NULL, /* no special mmap-close */
+ NULL, /* no special mmap-unmap */
+ NULL, /* no special mmap-protect */
+ NULL, /* no special mmap-sync */
+ NULL, /* no special mmap-advise */
+ shmiq_nopage, /* our magic no-page fault handler */
+ NULL, /* no special mmap-wppage */
+ NULL, /* no special mmap-swapout */
+ NULL /* no special mmap-swapin */
+};
+
+static int
+shmiq_qcntl_mmap (struct file *file, struct vm_area_struct *vma)
+{
+ int minor = MINOR (file->f_dentry->d_inode->i_rdev), error;
+ unsigned int size;
+ unsigned long mem, start;
+
+ /* mmap is only supported on the qcntl devices */
+ if (minor-- == 0)
+ return -EINVAL;
+
+ if (vma->vm_offset != 0)
+ return -EINVAL;
+
+ size = vma->vm_end - vma->vm_start;
+ start = vma->vm_start;
+ mem = (unsigned long) shmiqs [minor].shmiq_vaddr = vmalloc_uncached (size);
+ if (!mem)
+ return -EINVAL;
+
+ /* Prevent the swapper from considering these pages for swap and touching them */
+ vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+ vma->vm_ops = &qcntl_mmap;
+
+ /* Uncache the pages */
+ vma->vm_page_prot = PAGE_USERIO;
+
+ error = vmap_page_range (vma->vm_start, size, mem);
+
+ shmiqs [minor].tail = 0;
+ /* Init the shared memory input queue */
+ memset (shmiqs [minor].shmiq_vaddr, 0, size);
+
+ return error;
+}
+
+static int
+shmiq_qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int minor = MINOR (inode->i_rdev);
+
+ lock_kernel ();
+
+ if (minor-- == 0)
+ return shmiq_ioctl (inode, filp, cmd, arg);
+
+ return qcntl_ioctl (inode, filp, cmd, arg, minor);
+}
+
+static unsigned int
+shmiq_qcntl_poll (struct file *filp, poll_table *wait)
+{
+ struct sharedMemoryInputQueue *s;
+ int minor = MINOR (filp->f_dentry->d_inode->i_rdev);
+
+ if (minor-- == 0)
+ return 0;
+
+ if (!shmiqs [minor].mapped)
+ return 0;
+
+ poll_wait (&shmiqs [minor].proc_list, wait);
+ s = shmiqs [minor].shmiq_vaddr;
+ if (s->head != s->tail)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static int
+shmiq_qcntl_open (struct inode *inode, struct file *filp)
+{
+ int minor = MINOR (inode->i_rdev);
+
+ if (minor == 0)
+ return 0;
+
+ minor--;
+ if (minor > MAX_SHMI_QUEUES)
+ return -EINVAL;
+ if (shmiqs [minor].opened)
+ return -EBUSY;
+
+ lock_kernel ();
+ shmiqs [minor].opened = 1;
+ shmiqs [minor].shmiq_vaddr = 0;
+ unlock_kernel ();
+ return 0;
+}
+
+static int
+shmiq_qcntl_fasync (struct file *file, int on)
+{
+ int retval;
+ int minor = MINOR (file->f_dentry->d_inode->i_rdev);
+
+ retval = fasync_helper (file, on, &shmiqs [minor].fasync);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int
+shmiq_qcntl_close (struct inode *inode, struct file *filp)
+{
+ int minor = MINOR (inode->i_rdev);
+ int j;
+
+ if (minor-- == 0){
+ for (j = 0; j < MAX_SHMIQ_DEVS; j++)
+ shmiq_forget_file (j);
+ }
+
+ if (minor > MAX_SHMI_QUEUES)
+ return -EINVAL;
+ if (shmiqs [minor].opened == 0)
+ return -EINVAL;
+
+ lock_kernel ();
+ shmiq_qcntl_fasync (filp, 0);
+ shmiqs [minor].opened = 0;
+ shmiqs [minor].mapped = 0;
+ shmiqs [minor].events = 0;
+ shmiqs [minor].fasync = 0;
+ vfree (shmiqs [minor].shmiq_vaddr);
+ shmiqs [minor].shmiq_vaddr = 0;
+ unlock_kernel ();
+ return 0;
+}
+
+
+static struct
+file_operations shmiq_fops =
+{
+ NULL, /* seek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ shmiq_qcntl_poll, /* poll */
+ shmiq_qcntl_ioctl, /* ioctl */
+ shmiq_qcntl_mmap, /* mmap */
+ shmiq_qcntl_open, /* open */
+ shmiq_qcntl_close, /* close */
+ NULL, /* fsync */
+ shmiq_qcntl_fasync, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+};
+
+void
+shmiq_init (void)
+{
+ printk ("SHMIQ setup\n");
+ register_chrdev (SHMIQ_MAJOR, "shmiq", &shmiq_fops);
+}
+/*
+ * shmiq.c: shared memory input queue driver
+ * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * We implement /dev/shmiq, /dev/qcntlN here
+ * this is different from IRIX that has shmiq as a misc
+ * streams device and the and qcntl devices as a major device.
+ *
+ * minor number 0 implements /dev/shmiq,
+ * any other number implements /dev/qcntl${minor-1}
+ *
+ * /dev/shmiq is used by the X server for two things:
+ *
+ * 1. for I_LINK()ing trough ioctl the file handle of a
+ * STREAMS device.
+ *
+ * 2. To send STREAMS-commands to the devices with the
+ * QIO ioctl interface.
+ *
+ * I have not yet figured how to make multiple X servers share
+ * /dev/shmiq for having different servers running. So, for now
+ * I keep a kernel-global array of inodes that are pushed into
+ * /dev/shmiq.
+ *
+ * /dev/qcntlN is used by the X server for two things:
+ *
+ * 1. Issuing the QIOCATTACH for mapping the shared input
+ * queue into the address space of the X server (yeah, yeah,
+ * I did not invent this interface).
+ *
+ * 2. used by select. I bet it is used for checking for events on
+ * the queue.
+ *
+ * Now the problem is that there does not seem anything that
+ * establishes a connection between /dev/shmiq and the qcntlN file. I
+ * need an strace from an X server that runs on a machine with more
+ * than one keyboard. And this is a problem since the file handles
+ * are pushed in /dev/shmiq, while the events should be dispatched to
+ * the /dev/qcntlN device.
+ *
+ * Until then, I just allow for 1 qcntl device.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
diff --git a/drivers/sgi/char/streamable.c b/drivers/sgi/char/streamable.c
index f26aad0e2..02e40cf05 100644
--- a/drivers/sgi/char/streamable.c
+++ b/drivers/sgi/char/streamable.c
@@ -361,3 +361,366 @@ streamable_init (void)
misc_register (&dev_input_keyboard);
misc_register (&dev_input_mouse);
}
+/*
+ * streamable.c: streamable devices. /dev/gfx
+ * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Major 10 is the streams clone device. The IRIX Xsgi server just
+ * opens /dev/gfx and closes it inmediately.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <asm/uaccess.h>
+#include <asm/shmiq.h>
+#include <asm/keyboard.h>
+#include "graphics.h"
+
+
+extern struct kbd_struct kbd_table [MAX_NR_CONSOLES];
+
+/* console number where forwarding is enabled */
+int forward_chars;
+
+/* To which shmiq this keyboard is assigned */
+int kbd_assigned_device;
+
+/* previous kbd_mode for the forward_chars terminal */
+int kbd_prev_mode;
+
+/* Fetchs the strioctl information from user space for I_STR ioctls */
+int
+get_sioc (struct strioctl *sioc, unsigned long arg)
+{
+ int v;
+
+ v = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct strioctl));
+ if (v)
+ return v;
+ if (copy_from_user (sioc, (void *) arg, sizeof (struct strioctl)))
+ return -EFAULT;
+
+ v = verify_area (VERIFY_WRITE, (void *) sioc->ic_dp, sioc->ic_len);
+ if (v)
+ return v;
+ return 0;
+}
+
+/* /dev/gfx device */
+static int
+sgi_gfx_open (struct inode *inode, struct file *file)
+{
+ printk ("GFX: Opened by %d\n", current->pid);
+ return 0;
+}
+
+static int
+sgi_gfx_close (struct inode *inode, struct file *file)
+{
+ printk ("GFX: Closed by %d\n", current->pid);
+ return 0;
+}
+
+static int
+sgi_gfx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ printk ("GFX: ioctl 0x%x %ld called\n", cmd, arg);
+ return 0;
+ return -EINVAL;
+}
+
+struct file_operations sgi_gfx_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ sgi_gfx_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sgi_gfx_open, /* open */
+ sgi_gfx_close, /* release */
+ NULL, /* fsync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+static struct miscdevice dev_gfx = {
+ SGI_GFX_MINOR, "sgi-gfx", &sgi_gfx_fops
+};
+
+/* /dev/input/keyboard streams device */
+static idevDesc sgi_kbd_desc = {
+ "keyboard", /* devName */
+ "KEYBOARD", /* devType */
+ 240, /* nButtons */
+ 0, /* nValuators */
+ 0, /* nLEDs */
+ 0, /* nStrDpys */
+ 0, /* nIntDpys */
+ 0, /* nBells */
+ IDEV_HAS_KEYMAP | IDEV_HAS_PCKBD
+};
+
+static int
+sgi_kbd_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
+{
+ *found = 1;
+
+ switch (cmd){
+
+ case IDEVINITDEVICE:
+ return 0;
+
+ case IDEVGETDEVICEDESC:
+ if (size >= sizeof (idevDesc)){
+ if (copy_to_user (data, &sgi_kbd_desc, sizeof (sgi_kbd_desc)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+
+ case IDEVGETKEYMAPDESC:
+ if (size >= sizeof (idevKeymapDesc)){
+ if (copy_to_user (data, "US", 3))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+ }
+ *found = 0;
+ return -EINVAL;
+}
+
+static int
+sgi_keyb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct strioctl sioc;
+ int f, v;
+
+ /* IRIX calls I_PUSH on the opened device, go figure */
+ if (cmd == I_PUSH)
+ return 0;
+
+ if (cmd == I_STR){
+ v = get_sioc (&sioc, arg);
+ if (v)
+ return v;
+
+ /* Why like this? Because this is a sample piece of code
+ * that can be copied into other drivers and shows how to
+ * call a stock IRIX xxx_wioctl routine
+ *
+ * The NULL is supposed to be a idevInfo, right now we
+ * do not support this in our kernel.
+ */
+ return sgi_kbd_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
+ }
+
+ if (cmd == SHMIQ_ON){
+ kbd_assigned_device = arg;
+ forward_chars = fg_console + 1;
+ kbd_prev_mode = kbd_table [fg_console].kbdmode;
+
+ kbd_table [fg_console].kbdmode = VC_RAW;
+ } else if (cmd == SHMIQ_OFF && forward_chars){
+ kbd_table [forward_chars-1].kbdmode = kbd_prev_mode;
+ forward_chars = 0;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+void
+kbd_forward_char (int ch)
+{
+ static struct shmqevent ev;
+
+ ev.data.flags = (ch & 0200) ? 0 : 1;
+ ev.data.which = ch;
+ ev.data.device = kbd_assigned_device + 0x11;
+ shmiq_push_event (&ev);
+}
+
+static int
+sgi_keyb_open (struct inode *inode, struct file *file)
+{
+ /* Nothing, but required by the misc driver */
+ return 0;
+}
+
+struct file_operations sgi_keyb_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ sgi_keyb_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sgi_keyb_open, /* open */
+ NULL, /* release */
+ NULL, /* fsync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+static struct miscdevice dev_input_keyboard = {
+ SGI_STREAMS_KEYBOARD, "streams-keyboard", &sgi_keyb_fops
+};
+
+/* /dev/input/mouse streams device */
+#define MOUSE_VALUATORS 2
+static idevDesc sgi_mouse_desc = {
+ "mouse", /* devName */
+ "MOUSE", /* devType */
+ 3, /* nButtons */
+ MOUSE_VALUATORS, /* nValuators */
+ 0, /* nLEDs */
+ 0, /* nStrDpys */
+ 0, /* nIntDpys */
+ 0, /* nBells */
+ 0 /* flags */
+};
+
+static idevValuatorDesc mouse_default_valuator = {
+ 200, /* hwMinRes */
+ 200, /* hwMaxRes */
+ 0, /* hwMinVal */
+ 65000, /* hwMaxVal */
+ IDEV_EITHER, /* possibleModes */
+ IDEV_ABSOLUTE, /* default mode */
+ 200, /* resolution */
+ 0, /* minVal */
+ 65000 /* maxVal */
+};
+
+static int mouse_opened;
+static idevValuatorDesc mouse_valuators [MOUSE_VALUATORS];
+
+int
+sgi_mouse_open (struct inode *inode, struct file *file)
+{
+ int i;
+
+ if (mouse_opened)
+ return -EBUSY;
+
+ mouse_opened = 1;
+ for (i = 0; i < MOUSE_VALUATORS; i++)
+ mouse_valuators [i] = mouse_default_valuator;
+ return 0;
+}
+
+static int
+sgi_mouse_close (struct inode *inode, struct file *filp)
+{
+ mouse_opened = 0;
+ return 0;
+}
+
+static int
+sgi_mouse_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
+{
+ *found = 1;
+
+ switch (cmd){
+ case IDEVINITDEVICE:
+ return 0;
+
+ case IDEVGETDEVICEDESC:
+ if (size >= sizeof (idevDesc)){
+ if (copy_to_user (data, &sgi_mouse_desc, sizeof (sgi_mouse_desc)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+
+ case IDEVGETVALUATORDESC: {
+ idevGetSetValDesc request, *ureq = (idevGetSetValDesc *) data;
+
+ if (size < sizeof (idevGetSetValDesc))
+ return -EINVAL;
+
+ if (copy_from_user (&request, data, sizeof (request)))
+ return -EFAULT;
+ if (request.valNum >= MOUSE_VALUATORS)
+ return -EINVAL;
+ if (copy_to_user ((void *)&ureq->desc,
+ (void *)&mouse_valuators [request.valNum],
+ sizeof (idevValuatorDesc)))
+ return -EFAULT;
+ return 0;
+ }
+ }
+ *found = 0;
+ return -EINVAL;
+}
+
+static int
+sgi_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct strioctl sioc;
+ int f, v;
+
+ /* IRIX calls I_PUSH on the opened device, go figure */
+ switch (cmd){
+ case I_PUSH:
+ return 0;
+
+ case I_STR:
+ v = get_sioc (&sioc, arg);
+ if (v)
+ return v;
+
+ /* Why like this? Because this is a sample piece of code
+ * that can be copied into other drivers and shows how to
+ * call a stock IRIX xxx_wioctl routine
+ *
+ * The NULL is supposed to be a idevInfo, right now we
+ * do not support this in our kernel.
+ */
+ return sgi_mouse_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
+
+ case SHMIQ_ON:
+ case SHMIQ_OFF:
+ return 0;
+ }
+ return 0;
+}
+
+struct file_operations sgi_mouse_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ sgi_mouse_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sgi_mouse_open, /* open */
+ sgi_mouse_close, /* release */
+ NULL, /* fsync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+/* /dev/input/mouse */
+static struct miscdevice dev_input_mouse = {
+ SGI_STREAMS_KEYBOARD, "streams-mouse", &sgi_mouse_fops
+};
+
+void
+streamable_init (void)
+{
+ printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n",
+ SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR);
+
+ misc_register (&dev_gfx);
+ misc_register (&dev_input_keyboard);
+ misc_register (&dev_input_mouse);
+}
diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c
index dfef772eb..262f5724f 100644
--- a/drivers/sgi/char/usema.c
+++ b/drivers/sgi/char/usema.c
@@ -27,6 +27,197 @@
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/dcache.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm/smp_lock.h>
+#include <asm/usioctl.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+
+struct irix_usema {
+ struct file *filp;
+ struct wait_queue *proc_list;
+};
+
+static int
+sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
+{
+ int newfd;
+ newfd = get_unused_fd();
+ if (newfd < 0)
+ return newfd;
+
+ current->files->fd [newfd] = usema->filp;
+ usema->filp->f_count++;
+ /* Is that it? */
+ printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
+ return newfd;
+}
+
+static int
+sgi_usemaclone_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct irix_usema *usema = file->private_data;
+ int retval;
+
+ printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)",
+ current->comm, current->pid, cmd, arg);
+
+ switch(cmd) {
+ case UIOCATTACHSEMA: {
+ /* They pass us information about the semaphore to
+ which they wish to be attached, and we create&return
+ a new fd corresponding to the appropriate semaphore.
+ */
+ usattach_t *attach = (usattach_t *)arg;
+ retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+ if (retval) {
+ printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): "
+ "verify_area failure",
+ current->comm, current->pid);
+ return retval;
+ }
+ if (usema == 0)
+ return -EINVAL;
+
+ printk("UIOCATTACHSEMA: attaching usema %p to process %d\n", usema, current->pid);
+ /* XXX what is attach->us_handle for? */
+ return sgi_usema_attach(attach, usema);
+ break;
+ }
+ case UIOCABLOCK: /* XXX make `async' */
+ case UIOCNOIBLOCK: /* XXX maybe? */
+ case UIOCBLOCK: {
+ /* Block this process on the semaphore */
+ usattach_t *attach = (usattach_t *)arg;
+
+ retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+ if (retval) {
+ printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+ "verify_area failure",
+ current->comm, current->pid);
+ return retval;
+ }
+ printk("UIOC*BLOCK: putting process %d to sleep on usema %p",
+ current->pid, usema);
+ if (cmd == UIOCNOIBLOCK)
+ interruptible_sleep_on(&usema->proc_list);
+ else
+ sleep_on(&usema->proc_list);
+ return 0;
+ }
+ case UIOCAUNBLOCK: /* XXX make `async' */
+ case UIOCUNBLOCK: {
+ /* Wake up all process waiting on this semaphore */
+ usattach_t *attach = (usattach_t *)arg;
+
+ retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
+ if (retval) {
+ printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+ "verify_area failure",
+ current->comm, current->pid);
+ return retval;
+ }
+
+ printk("[%s:%d] releasing usema %p",
+ current->comm, current->pid, usema);
+ wake_up(&usema->proc_list);
+ return 0;
+ }
+ }
+ return -ENOSYS;
+}
+
+static unsigned int
+sgi_usemaclone_poll(struct file *filp, poll_table *wait)
+{
+ struct irix_usema *usema = filp->private_data;
+
+ printk("[%s:%d] wants to poll usema %p", current->comm, current->pid, usema);
+
+ return 0;
+}
+
+static int
+sgi_usemaclone_open(struct inode *inode, struct file *filp)
+{
+ struct irix_usema *usema;
+
+ usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL);
+ if (!usema)
+ return -ENOMEM;
+
+ usema->filp = filp;
+ usema->proc_list = NULL;
+ filp->private_data = usema;
+ return 0;
+}
+
+static int
+sgi_usemaclone_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+struct file_operations sgi_usemaclone_fops = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ sgi_usemaclone_poll, /* poll */
+ sgi_usemaclone_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sgi_usemaclone_open, /* open */
+ sgi_usemaclone_release, /* release */
+ NULL, /* fsync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+static struct miscdevice dev_usemaclone = {
+ SGI_USEMACLONE, "usemaclone", &sgi_usemaclone_fops
+};
+
+void
+usema_init(void)
+{
+ printk("usemaclone misc device registered (minor: %d)\n", SGI_USEMACLONE);
+ misc_register(&dev_usemaclone);
+}
+/*
+ * usema.c: software semaphore driver (see IRIX's usema(7M))
+ * written 1997 Mike Shaver (shaver@neon.ingenia.ca)
+ * 1997 Miguel de Icaza (miguel@kernel.org)
+ *
+ * This file contains the implementation of /dev/usemaclone,
+ * the devices used by IRIX's us* semaphore routines.
+ *
+ * /dev/usemaclone is used to create a new semaphore device, and then
+ * the semaphore is manipulated via ioctls.
+ *
+ * At least for the zero-contention case, lock set and unset as well
+ * as semaphore P and V are done in userland, which makes things a
+ * little bit better. I suspect that the ioctls are used to register
+ * the process as blocking, etc.
+ *
+ * Much inspiration and structure stolen from Miguel's shmiq work.
+ *
+ * For more information:
+ * usema(7m), usinit(3p), usnewsema(3p)
+ * /usr/include/sys/usioctl.h
+ *
+*/
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/major.h>
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/dcache.h>
diff --git a/drivers/sgi/char/vga_font.c b/drivers/sgi/char/vga_font.c
index 2ab67797c..2c7def4f6 100644
--- a/drivers/sgi/char/vga_font.c
+++ b/drivers/sgi/char/vga_font.c
@@ -344,3 +344,349 @@ unsigned char vga_font[cmapsz] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+#include "gconsole.h"
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c
index 8ac02d490..a9ac8850e 100644
--- a/drivers/sound/lowlevel/awe_wave.c
+++ b/drivers/sound/lowlevel/awe_wave.c
@@ -564,7 +564,7 @@ int attach_awe(void)
synth_devs[my_dev] = &awe_operations;
#ifdef CONFIG_AWE32_MIXER
- if ((my_mixerdev=sound_alloc_mixerdev())==-1) {
+ if ((my_mixerdev=sound_alloc_mixerdev())!=-1) {
mixer_devs[my_mixerdev] = &awe_mixer_operations;
}
#endif
diff --git a/fs/dcache.c b/fs/dcache.c
index a2aaeeaec..7d41b0bd5 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -744,6 +744,42 @@ char * d_path(struct dentry *dentry, char *buffer, int buflen)
return retval;
}
+/*
+ * Check whether a dentry already exists for the given name,
+ * and return the inode number if it has an inode.
+ *
+ * This routine is used to post-process directory listings for
+ * filesystems using synthetic inode numbers, and is necessary
+ * to keep getcwd() working.
+ */
+ino_t find_inode_number(struct dentry *dir, struct qstr *name)
+{
+ struct dentry * dentry;
+ ino_t ino = 0;
+
+ /*
+ * Check for a fs-specific hash function. Note that we must
+ * calculate the standard hash first, as the d_op->d_hash()
+ * routine may choose to leave the hash value unchanged.
+ */
+ name->hash = full_name_hash(name->name, name->len);
+ if (dir->d_op && dir->d_op->d_hash)
+ {
+ if (dir->d_op->d_hash(dir, name) != 0)
+ goto out;
+ }
+
+ dentry = d_lookup(dir, name);
+ if (dentry)
+ {
+ if (dentry->d_inode)
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
+ }
+out:
+ return ino;
+}
+
__initfunc(void dcache_init(void))
{
int i;
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index b5b531d8c..8a9bdf902 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -57,6 +57,72 @@ static int sync_block (struct inode * inode, u32 * block, int wait)
return 0;
}
+#ifndef __LITTLE_ENDIAN
+static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
+{
+ struct buffer_head * bh;
+
+ if (!le32_to_cpu(*block))
+ return 0;
+ bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
+ if (!bh)
+ return 0;
+ if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+ brelse (bh);
+ return -1;
+ }
+ if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+ brelse (bh);
+ return 0;
+ }
+ ll_rw_block (WRITE, 1, &bh);
+ bh->b_count--;
+ return 0;
+}
+#else
+#define sync_block_swab32 sync_block
+#endif
+
+
+static int sync_iblock (struct inode * inode, u32 * iblock,
+ struct buffer_head ** bh, int wait)
+{
+ int rc, tmp;
+
+ *bh = NULL;
+ tmp = *iblock;
+ if (!tmp)
+ return 0;
+ rc = sync_block (inode, iblock, wait);
+ if (rc)
+ return rc;
+ *bh = bread (inode->i_dev, tmp, blocksize);
+ if (!*bh)
+ return -1;
+ return 0;
+}
+
+#ifndef __LITTLE_ENDIAN
+static int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
+ struct buffer_head ** bh, int wait)
+{
+ int rc, tmp;
+
+ *bh = NULL;
+ tmp = le32_to_cpu(*iblock);
+ if (!tmp)
+ return 0;
+ rc = sync_block_swab32 (inode, iblock, wait);
+ if (rc)
+ return rc;
+ *bh = bread (inode->i_dev, tmp, blocksize);
+ if (!*bh)
+ return -1;
+ return 0;
+}
+#else
+#define sync_iblock_swab32 sync_iblock
+#endif
static int sync_direct (struct inode * inode, int wait)
{
@@ -71,15 +137,122 @@ static int sync_direct (struct inode * inode, int wait)
return err;
}
+static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
+{
+ int i;
+ struct buffer_head * ind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock (inode, iblock, &ind_bh, wait);
+ if (rc || !ind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_block_swab32 (inode,
+ ((u32 *) ind_bh->b_data) + i,
+ wait);
+ if (rc)
+ err = rc;
+ }
+ brelse (ind_bh);
+ return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
+{
+ int i;
+ struct buffer_head * ind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
+ if (rc || !ind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_block_swab32 (inode,
+ ((u32 *) ind_bh->b_data) + i,
+ wait);
+ if (rc)
+ err = rc;
+ }
+ brelse (ind_bh);
+ return err;
+}
+#else
+#define sync_indirect_swab32 sync_indirect
+#endif
+
+static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+{
+ int i;
+ struct buffer_head * dind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock (inode, diblock, &dind_bh, wait);
+ if (rc || !dind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_indirect_swab32 (inode,
+ ((u32 *) dind_bh->b_data) + i,
+ wait);
+ if (rc)
+ err = rc;
+ }
+ brelse (dind_bh);
+ return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
+{
+ int i;
+ struct buffer_head * dind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
+ if (rc || !dind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_indirect_swab32 (inode,
+ ((u32 *) dind_bh->b_data) + i,
+ wait);
+ if (rc)
+ err = rc;
+ }
+ brelse (dind_bh);
+ return err;
+}
+#else
+#define sync_dindirect_swab32 sync_dindirect
+#endif
+
+static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
+{
+ int i;
+ struct buffer_head * tind_bh;
+ int rc, err = 0;
+
+ rc = sync_iblock (inode, tiblock, &tind_bh, wait);
+ if (rc || !tind_bh)
+ return rc;
+
+ for (i = 0; i < addr_per_block; i++) {
+ rc = sync_dindirect_swab32 (inode,
+ ((u32 *) tind_bh->b_data) + i,
+ wait);
+ if (rc)
+ err = rc;
+ }
+ brelse (tind_bh);
+ return err;
+}
+
/*
* File may be NULL when we are called. Perhaps we shouldn't
* even pass file to fsync ?
- *
- * This currently falls back to synching the whole device when
- * the file is larger than can fit directly in the inode. This
- * is because dirty-buffer handling is indexed by the device
- * of the buffer, which makes it much faster to sync the whole
- * device than to sync just one large file.
*/
int ext2_sync_file(struct file * file, struct dentry *dentry)
@@ -96,12 +269,18 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
*/
goto skip;
- if (inode->i_size > EXT2_NDIR_BLOCKS*blocksize)
- return file_fsync(file, dentry);
-
for (wait=0; wait<=1; wait++)
{
err |= sync_direct (inode, wait);
+ err |= sync_indirect (inode,
+ inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
+ wait);
+ err |= sync_dindirect (inode,
+ inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
+ wait);
+ err |= sync_tindirect (inode,
+ inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
+ wait);
}
skip:
err |= ext2_sync_inode (inode);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 732d0b9ba..a907785f3 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -117,6 +117,16 @@ inode->i_ino, inode->i_count);
void fat_delete_inode(struct inode *inode)
{
+ /*
+ * Make sure there are no active dependencies ...
+ */
+ if (MSDOS_I(inode)->i_old)
+ printk("fat_delete_inode: inode %ld, old=%p??\n",
+ inode->i_ino, MSDOS_I(inode)->i_old);
+ if (MSDOS_I(inode)->i_oldlink)
+ printk("fat_delete_inode: inode %ld, oldlink=%p??\n",
+ inode->i_ino, MSDOS_I(inode)->i_oldlink);
+
fat_cache_inval_inode(inode);
inode->i_size = 0;
fat_truncate(inode);
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 67ff77bd9..79d49a858 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -207,22 +207,22 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
}
+ map = 1;
+ if (inode->i_sb->u.isofs_sb.s_rock) {
+ len = get_rock_ridge_filename(de, tmpname, inode);
+ if (len != 0) {
+ p = tmpname;
+ map = 0;
+ }
+ }
+ if (map) {
#ifdef CONFIG_JOLIET
- if (inode->i_sb->u.isofs_sb.s_joliet_level) {
- len = get_joliet_filename(de, inode, tmpname);
- p = tmpname;
- } else
+ if (inode->i_sb->u.isofs_sb.s_joliet_level) {
+ len = get_joliet_filename(de, inode, tmpname);
+ p = tmpname;
+ } else
#endif
- /* if not joliet */ {
- map = 1;
- if (inode->i_sb->u.isofs_sb.s_rock) {
- len = get_rock_ridge_filename(de, tmpname, inode);
- if (len != 0) {
- p = tmpname;
- map = 0;
- }
- }
- if (map) {
+ {
if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
len = isofs_name_translate(de->name, de->name_len[0],
tmpname);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 88cf1fd4a..9445b921e 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -283,7 +283,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
struct iso_supplementary_descriptor *sec = NULL;
struct iso_volume_descriptor * vdp;
unsigned int vol_desc_start;
-
+ struct inode * inode;
MOD_INC_USE_COUNT;
@@ -384,7 +384,6 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
sec = (struct iso_supplementary_descriptor *)vdp;
if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
if (opt.joliet == 'y') {
- opt.rock = 'n';
if (sec->escape[2] == 0x40) {
joliet_level = 1;
} else if (sec->escape[2] == 0x43) {
@@ -418,16 +417,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_joliet_level = joliet_level;
-#ifdef CONFIG_JOLIET
- if (joliet_level) {
- /* Note: In theory, it is possible to have Rock Ridge
- * extensions mixed with Joliet. All character strings
- * would just be saved as Unicode. Until someone sees such
- * a disc, do not allow the two to be mixed
+ if (joliet_level && opt.rock == 'n') {
+ /* This is the case of Joliet with the norock mount flag.
+ * A disc with both Joliet and Rock Ridge is handled later
*/
pri = (struct iso_primary_descriptor *) sec;
}
-#endif
if(high_sierra){
rootp = (struct iso_directory_record *) h_pri->root_directory_record;
@@ -486,11 +481,6 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
goto out;
}
- /* RDE: data zone now byte offset! */
-
- s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
s->s_magic = ISOFS_SUPER_MAGIC;
/* The CDROM is read-only, has no nodes (devices) on it, and since
@@ -502,14 +492,18 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
brelse(bh);
+ /* RDE: data zone now byte offset! */
+
+ s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
#ifndef BEQUIET
printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_size);
printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n",
s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
- (isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ s->u.isofs_sb.s_firstdatazone);
if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
#endif
unlock_super(s);
@@ -549,8 +543,9 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
#endif
}
-#ifdef CONFIG_JOLIET
s->u.isofs_sb.s_nls_iocharset = NULL;
+
+#ifdef CONFIG_JOLIET
if (joliet_level == 0) {
if (opt.iocharset) {
kfree(opt.iocharset);
@@ -574,7 +569,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->s_dev = dev;
s->s_op = &isofs_sops;
s->u.isofs_sb.s_mapping = opt.map;
- s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
+ s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0);
s->u.isofs_sb.s_name_check = opt.check;
s->u.isofs_sb.s_conversion = opt.conversion;
s->u.isofs_sb.s_cruft = opt.cruft;
@@ -589,9 +584,30 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
- s->s_root = d_alloc_root(iget(s, (isonum_733(rootp->extent) +
- isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size), NULL);
+ inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+
+ /*
+ * If this disk has both Rock Ridge and Joliet on it, then we
+ * want to use Rock Ridge by default. This can be overridden
+ * by using the norock mount option. There is still one other
+ * possibility that is not taken into account: a Rock Ridge
+ * CD with Unicode names. Until someone sees such a beast, it
+ * will not be supported.
+ */
+ if (joliet_level && opt.rock == 'y' && s->u.isofs_sb.s_rock != 1) {
+ iput(inode);
+ pri = (struct iso_primary_descriptor *) sec;
+ rootp = (struct iso_directory_record *)
+ pri->root_directory_record;
+ s->u.isofs_sb.s_firstdatazone =
+ ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
+ inode = iget(s, s->u.isofs_sb.s_firstdatazone);
+ s->u.isofs_sb.s_rock = 0;
+ }
+
+ s->s_root = d_alloc_root(inode, NULL);
unlock_super(s);
if (!(s->s_root)) {
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index e006ac3ee..7d943d0fe 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -265,6 +265,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
CHECK_CE;
break;
case SIG('E','R'):
+ inode->i_sb->u.isofs_sb.s_rock = 1;
printk(KERN_DEBUG"ISO9660 Extensions: ");
{ int p;
for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index a0eb8165a..38f131d84 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -173,56 +173,60 @@ static int msdos_find(struct inode *dir,const char *name,int len,
return fat_scan(dir,msdos_name,bh,de,ino,scantype);
}
-
+/*
+ * Compute the hash for the msdos name corresponding to the dentry.
+ * Note: if the name is invalid, we leave the hash code unchanged so
+ * that the existing dentry can be used. The msdos fs routines will
+ * return ENOENT or EINVAL as appropriate.
+ */
static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
{
- unsigned long hash;
- char msdos_name[MSDOS_NAME];
+ struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
int error;
- int i;
- struct fat_mount_options *options =
- & (MSDOS_SB(dentry->d_inode->i_sb)->options);
+ char msdos_name[MSDOS_NAME];
- error = msdos_format_name(options->name_check,
- qstr->name, qstr->len, msdos_name,1,
- options->dotsOK);
- if(error)
- return error;
- hash = init_name_hash();
- for(i=0; i< MSDOS_NAME; i++)
- hash = partial_name_hash(msdos_name[i], hash);
- qstr->hash = end_name_hash(hash);
+ error = msdos_format_name(options->name_check, qstr->name, qstr->len,
+ msdos_name, 1, options->dotsOK);
+ if (!error)
+ qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
return 0;
}
-
-static int msdos_cmp(struct dentry *dentry,
- struct qstr *a, struct qstr *b)
+/*
+ * Compare two msdos names. If either of the names are invalid,
+ * we fall back to doing the standard name comparison.
+ */
+static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
- char a_msdos_name[MSDOS_NAME],b_msdos_name[MSDOS_NAME];
+ struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
int error;
- struct fat_mount_options *options =
- & (MSDOS_SB(dentry->d_inode->i_sb)->options);
-
- error = msdos_format_name(options->name_check,
- a->name, a->len, a_msdos_name,1,
- options->dotsOK);
- if(error)
- return error;
- error = msdos_format_name(options->name_check,
- b->name, b->len, b_msdos_name,1,
- options->dotsOK);
- if(error)
- return error;
-
- return memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
+ char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
+
+ error = msdos_format_name(options->name_check, a->name, a->len,
+ a_msdos_name, 1, options->dotsOK);
+ if (error)
+ goto old_compare;
+ error = msdos_format_name(options->name_check, b->name, b->len,
+ b_msdos_name, 1, options->dotsOK);
+ if (error)
+ goto old_compare;
+ error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
+out:
+ return error;
+
+old_compare:
+ error = 1;
+ if (a->len == b->len)
+ error = memcmp(a->name, b->name, a->len);
+ goto out;
}
static struct dentry_operations msdos_dentry_operations = {
- 0, /* d_revalidate */
+ NULL, /* d_revalidate */
msdos_hash,
- msdos_cmp
+ msdos_cmp,
+ NULL /* d_delete */
};
struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
@@ -233,14 +237,16 @@ struct super_block *msdos_read_super(struct super_block *sb,void *data, int sile
MSDOS_SB(sb)->options.isvfat = 0;
sb->s_op = &msdos_sops;
- res = fat_read_super(sb, data, silent);
- if (res == NULL) {
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ res = fat_read_super(sb, data, silent);
+ if (res == NULL)
+ goto out_fail;
sb->s_root->d_op = &msdos_dentry_operations;
return res;
+
+out_fail:
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
@@ -290,11 +296,14 @@ int msdos_lookup(struct inode *dir,struct dentry *dentry)
PRINTK (("msdos_lookup 6\n"));
while (MSDOS_I(inode)->i_old) {
next = MSDOS_I(inode)->i_old;
+#ifdef MSDOS_PARANOIA
+printk("msdos_lookup: ino %ld, old ino=%ld\n", inode->i_ino, next->i_ino);
+if (MSDOS_I(next)->i_depend != inode)
+printk("msdos_lookup: depend=%p, inode=%p??\n", MSDOS_I(next)->i_depend, inode);
+#endif
+ next->i_count++;
iput(inode);
- if (!(inode = iget(next->i_sb,next->i_ino))) {
- fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
- return -ENOENT; /* N.B. Maybe ENOMEM is better? */
- }
+ inode = next;
}
PRINTK (("msdos_lookup 7\n"));
d_add(dentry, inode);
diff --git a/fs/namei.c b/fs/namei.c
index 2e7c4bff6..ab8d6089e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -73,6 +73,10 @@
* and in the old Linux semantics.
*/
+/* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink
+ * semantics. See the comments in "open_namei" and "do_link" below.
+ */
+
static char * quicklist = NULL;
static int quickcount = 0;
struct semaphore quicklock = MUTEX;
@@ -530,7 +534,13 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
- dentry = lookup_dentry(pathname, NULL, 1);
+ /*
+ * Special case: O_CREAT|O_EXCL on a dangling symlink should
+ * give EEXIST for security reasons. While inconsistent, this
+ * is the same scheme used by, for example, Solaris 2.5.1. --KAB
+ */
+ dentry = lookup_dentry(pathname, NULL,
+ (flag & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL));
if (IS_ERR(dentry))
return dentry;
@@ -731,7 +741,7 @@ static inline int do_mkdir(const char * pathname, int mode)
struct dentry *dir;
struct dentry *dentry;
- dentry = lookup_dentry(pathname, NULL, 1);
+ dentry = lookup_dentry(pathname, NULL, 0);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto exit;
@@ -1010,7 +1020,16 @@ static inline int do_link(const char * oldname, const char * newname)
if (IS_ERR(old_dentry))
goto exit;
- new_dentry = lookup_dentry(newname, NULL, 1);
+ /*
+ * Hardlinks are often used in delicate situations. We avoid
+ * security-related surprises by not following symlinks on the
+ * newname. We *do* follow them on the oldname. This is
+ * the same as Digital Unix 4.0, for example.
+ *
+ * Solaris 2.5.1 is similar, but for a laugh try linking from
+ * a dangling symlink. --KAB
+ */
+ new_dentry = lookup_dentry(newname, NULL, 0);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
goto exit_old;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c74c73243..aaf17187b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -471,11 +471,11 @@ void nfs_renew_times(struct dentry * dentry)
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
+ int len = dentry->d_name.len;
struct inode *inode;
+ int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- int len = dentry->d_name.len;
- int error;
dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
dir->i_dev, dir->i_ino, len, dentry->d_name.name);
@@ -516,10 +516,38 @@ out:
}
/*
+ * Attempt to patch up certain errors following a create or
+ * mkdir operation. We clear the original error if the new
+ * lookup succeeds and has the correct mode.
+ */
+static int nfs_fixup(struct inode *dir, struct dentry *dentry, int mode,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr, int error)
+{
+ int newerr;
+
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: %s/%s, error=%d, mode=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error, mode);
+#endif
+ if (error == -EEXIST) {
+ newerr = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, fhandle, fattr);
+ if (!newerr) {
+#ifdef NFS_PARANOIA
+printk("nfs_fixup: lookup OK, got mode=%x, want mode=%x\n", fattr->mode, mode);
+#endif
+ if ((fattr->mode & S_IFMT) == (mode & S_IFMT))
+ error = 0;
+ }
+ }
+ return error;
+}
+
+/*
* Code common to create, mkdir, and mknod.
*/
-static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr,
- struct nfs_fh *fhandle)
+static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
struct inode *inode;
int error = -EACCES;
@@ -545,12 +573,12 @@ inode->i_ino, inode->i_count, inode->i_nlink);
* that the operation succeeded on the server, but an error in the
* reply path made it appear to have failed.
*/
-static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -574,9 +602,11 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error)
+ error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error)
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- else
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ if (error)
d_drop(dentry);
out:
return error;
@@ -587,10 +617,10 @@ out:
*/
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -612,9 +642,11 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error)
+ error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error)
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- else
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ if (error)
d_drop(dentry);
return error;
}
@@ -624,10 +656,10 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
*/
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
+ int error;
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
@@ -640,6 +672,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
+ /* For some reason mode doesn't have the S_IFDIR flag ... */
+ mode |= S_IFDIR;
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -647,6 +681,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
nfs_invalidate_dircache(dir);
error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error)
+ error = nfs_fixup(dir, dentry, mode, &fhandle, &fattr, error);
if (!error) {
/*
* Some AIX servers reportedly fail to fill out the fattr.
@@ -660,8 +696,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
fattr.mode);
goto drop;
}
- error = nfs_instantiate(dentry, &fattr, &fhandle);
- } else {
+ error = nfs_instantiate(dentry, &fhandle, &fattr);
+ }
+ if (error) {
drop:
d_drop(dentry);
}
@@ -858,11 +895,8 @@ out:
* Remove a file after making sure there are no pending writes,
* and after checking that the file has only one user.
*
- * Updating inode->i_nlink here rather than waiting for the next
- * nfs_refresh_inode() is not merely cosmetic; once an object has
- * been deleted, we want to get rid of the inode locally. The NFS
- * server may reuse the fileid for a new inode, and we don't want
- * that to be confused with this inode.
+ * We update inode->i_nlink and free the inode prior to the operation
+ * to avoid possible races if the server reuses the inode.
*/
static int nfs_safe_remove(struct dentry *dentry)
{
@@ -870,6 +904,7 @@ static int nfs_safe_remove(struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int error, rehash = 0;
+ /* N.B. not needed now that d_delete is done in advance? */
error = -EBUSY;
if (inode) {
if (NFS_WRITEBACK(inode)) {
@@ -897,7 +932,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
goto out;
}
#ifdef NFS_PARANOIA
-if (inode && inode->i_count > 1)
+if (inode && inode->i_count > inode->i_nlink)
printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_count, inode->i_nlink);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c070d130b..eb56950eb 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -35,9 +35,6 @@
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
-extern void nfs_invalidate_dircache_sb(struct super_block *);
-extern int check_failed_request(struct inode *);
-
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
@@ -99,8 +96,9 @@ nfs_delete_inode(struct inode * inode)
*/
if (NFS_WRITEBACK(inode) != NULL) {
unsigned long timeout = jiffies + 5*HZ;
- printk("NFS: inode %ld, invalidating pending RPC requests\n",
- inode->i_ino);
+#ifdef NFS_DEBUG_VERBOSE
+printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
+#endif
nfs_invalidate_pages(inode);
while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) {
current->state = TASK_INTERRUPTIBLE;
@@ -112,7 +110,7 @@ nfs_delete_inode(struct inode * inode)
printk("NFS: Arghhh, stuck RPC requests!\n");
}
- failed = check_failed_request(inode);
+ failed = nfs_check_failed_request(inode);
if (failed)
printk("NFS: inode %ld had %d failed requests\n",
inode->i_ino, failed);
@@ -355,8 +353,6 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
* instead of inode number. We use this technique instead of using
* the vfs read_inode function because there is no way to pass the
* file handle or current attributes into the read_inode function.
- * We just have to be careful not to subvert iget's special handling
- * of mount points.
*/
struct inode *
nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
@@ -422,8 +418,10 @@ printk("nfs_fhget: impossible\n");
inode->i_size = fattr->size;
inode->i_mtime = fattr->mtime.seconds;
NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ *NFS_FH(inode) = *fhandle;
}
- *NFS_FH(inode) = *fhandle;
+ if (memcmp(NFS_FH(inode), fhandle, sizeof(struct nfs_fh)))
+ printk("nfs_fhget: fhandle changed!\n");
nfs_refresh_inode(inode, fattr);
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 97663cc11..53c227e58 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -68,8 +68,6 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-int check_failed_request(struct inode *);
-
static void nfs_wback_lock(struct rpc_task *task);
static void nfs_wback_result(struct rpc_task *task);
@@ -331,7 +329,7 @@ remove_failed_request(struct nfs_wreq * req)
* Find and release all failed requests for this inode.
*/
int
-check_failed_request(struct inode * inode)
+nfs_check_failed_request(struct inode * inode)
{
struct nfs_wreq * req;
int found = 0;
@@ -496,8 +494,7 @@ wait_on_write_request(struct nfs_wreq *req)
}
remove_wait_queue(&page->wait, &wait);
current->state = TASK_RUNNING;
- if (atomic_read(&page->count) == 1)
- printk("NFS: page unused while waiting\n");
+ /* N.B. page may have been unused, so we must use free_page() */
free_page(page_address(page));
return retval;
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 81b9a3f79..29a36a554 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -62,7 +62,8 @@ extern void fh_update(struct svc_fh*);
struct raparms {
struct raparms *p_next;
unsigned int p_count;
- struct dentry *p_dentry;
+ ino_t p_ino;
+ dev_t p_dev;
unsigned long p_reada,
p_ramax,
p_raend,
@@ -316,29 +317,27 @@ nfsd_sync(struct inode *inode, struct file *filp)
}
/*
- * Obtain the readahead parameters for the given file
- *
- * N.B. is raparm cache for a file cleared when the file closes??
- * (dentry might be reused later.)
+ * Obtain the readahead parameters for the file
+ * specified by (dev, ino).
*/
static inline struct raparms *
-nfsd_get_raparms(struct dentry *dentry)
+nfsd_get_raparms(dev_t dev, ino_t ino)
{
struct raparms *ra, **rap, **frap = NULL;
for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
- if (ra->p_dentry != dentry) {
- if (ra->p_count == 0)
- frap = rap;
- } else
+ if (ra->p_ino == ino && ra->p_dev == dev)
goto found;
+ if (ra->p_count == 0)
+ frap = rap;
}
if (!frap)
return NULL;
rap = frap;
ra = *frap;
memset(ra, 0, sizeof(*ra));
- ra->p_dentry = dentry;
+ ra->p_dev = dev;
+ ra->p_ino = ino;
found:
if (rap != &raparm_cache) {
*rap = ra->p_next;
@@ -359,23 +358,20 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf,
unsigned long *count)
{
struct raparms *ra;
- struct dentry *dentry;
- struct inode *inode;
- struct file file;
mm_segment_t oldfs;
int err;
+ struct file file;
- if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file)) != 0)
- return err;
- dentry = file.f_dentry;
- inode = dentry->d_inode;
- if (!file.f_op->read) {
- nfsd_close(&file);
- return nfserr_perm;
- }
+ err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file);
+ if (err)
+ goto out;
+ err = nfserr_perm;
+ if (!file.f_op->read)
+ goto out_close;
/* Get readahead parameters */
- if ((ra = nfsd_get_raparms(dentry)) != NULL) {
+ ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino);
+ if (ra) {
file.f_reada = ra->p_reada;
file.f_ramax = ra->p_ramax;
file.f_raend = ra->p_raend;
@@ -401,12 +397,15 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf,
ra->p_count -= 1;
}
+ if (err >= 0) {
+ *count = err;
+ err = 0;
+ } else
+ err = nfserrno(-err);
+out_close:
nfsd_close(&file);
-
- if (err < 0)
- return nfserrno(-err);
- *count = err;
- return 0;
+out:
+ return err;
}
/*
@@ -423,16 +422,16 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct dentry *dentry;
struct inode *inode;
mm_segment_t oldfs;
- int err;
+ int err = 0;
if (!cnt)
- return 0;
- if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file)) != 0)
- return err;
- if (!file.f_op->write) {
- nfsd_close(&file);
- return nfserr_perm;
- }
+ goto out;
+ err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file);
+ if (err)
+ goto out;
+ err = nfserr_perm;
+ if (!file.f_op->write)
+ goto out_close;
dentry = file.f_dentry;
inode = dentry->d_inode;
@@ -507,10 +506,15 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
last_dev = inode->i_dev;
}
- nfsd_close(&file);
-
dprintk("nfsd: write complete\n");
- return (err < 0)? nfserrno(-err) : 0;
+ if (err >= 0)
+ err = 0;
+ else
+ err = nfserrno(-err);
+out_close:
+ nfsd_close(&file);
+out:
+ return err;
}
/*
@@ -824,20 +828,27 @@ out:
return err;
}
-/* More "hidden treasure" from the generic VFS. -DaveM */
-/* N.B. VFS double_down was modified to fix a bug ... should use VFS one */
+/*
+ * This follows the model of double_lock() in the VFS.
+ */
static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
{
- if((unsigned long) s1 < (unsigned long) s2) {
- down(s1);
- down(s2);
- } else if(s1 == s2) {
- down(s1);
- atomic_dec(&s1->count);
- } else {
- down(s2);
+ if (s1 != s2) {
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ struct semaphore *tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
down(s1);
}
+ down(s2);
+}
+
+static inline void nfsd_double_up(struct semaphore *s1, struct semaphore *s2)
+{
+ up(s1);
+ if (s1 != s2)
+ up(s2);
}
/*
@@ -866,43 +877,47 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
tdir = tdentry->d_inode;
/* N.B. We shouldn't need this ... dentry layer handles it */
+ err = nfserr_perm;
if (!flen || (fname[0] == '.' &&
(flen == 1 || (flen == 2 && fname[1] == '.'))) ||
!tlen || (tname[0] == '.' &&
(tlen == 1 || (tlen == 2 && tname[1] == '.'))))
- return nfserr_perm;
+ goto out;
+
+ err = -EXDEV;
+ if (fdir->i_dev != tdir->i_dev)
+ goto out_nfserr;
+ err = -EPERM;
+ if (!fdir->i_op || !fdir->i_op->rename)
+ goto out_nfserr;
odentry = lookup_dentry(fname, dget(fdentry), 0);
err = PTR_ERR(odentry);
if (IS_ERR(odentry))
- goto out_no_unlock;
+ goto out_nfserr;
ndentry = lookup_dentry(tname, dget(tdentry), 0);
err = PTR_ERR(ndentry);
if (IS_ERR(ndentry))
goto out_dput_old;
- /* N.B. check this ... problems in locking?? */
+ /*
+ * Lock the parent directories.
+ */
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
- err = -EXDEV;
- if (fdir->i_dev != tdir->i_dev)
- goto out_unlock;
- err = -EPERM;
- if (!fdir->i_op || !fdir->i_op->rename)
- goto out_unlock;
+ /* N.B. check for parent changes after locking?? */
+
err = fdir->i_op->rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
write_inode_now(fdir);
write_inode_now(tdir);
}
-out_unlock:
- up(&tdir->i_sem);
- up(&fdir->i_sem);
-
+ nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
dput(ndentry);
+
out_dput_old:
dput(odentry);
-out_no_unlock:
+out_nfserr:
if (err)
err = nfserrno(-err);
out:
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 89da7544b..a467af4df 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -154,7 +154,7 @@ proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
break;
}
- n -= copy_to_user(buf, start, n);
+ n -= copy_to_user(buf, start, n); /* BUG ??? */
if (n == 0) {
if (retval == 0)
retval = -EFAULT;
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 921aa86e1..5af80e91b 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -85,7 +85,18 @@ find_inode_number(struct dentry *dir, struct qstr *name)
struct dentry * dentry;
ino_t ino = 0;
+ /*
+ * Check for a fs-specific hash function. Note that we must
+ * calculate the standard hash first, as the d_op->d_hash()
+ * routine may choose to leave the hash value unchanged.
+ */
name->hash = full_name_hash(name->name, name->len);
+ if (dir->d_op && dir->d_op->d_hash)
+ {
+ if (dir->d_op->d_hash(dir, name) != 0)
+ goto out;
+ }
+
dentry = d_lookup(dir, name);
if (dentry)
{
@@ -93,6 +104,7 @@ find_inode_number(struct dentry *dir, struct qstr *name)
ino = dentry->d_inode->i_ino;
dput(dentry);
}
+out:
return ino;
}
@@ -179,27 +191,51 @@ out:
return result;
}
+/*
+ * Note: in order to allow the smbclient process to open the
+ * mount point, we don't revalidate for the connection pid.
+ */
static int
smb_dir_open(struct inode *dir, struct file *file)
{
+ struct dentry *dentry = file->f_dentry;
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ int error = 0;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_dir_open: (%s/%s)\n", file->f_dentry->d_parent->d_name.name,
+printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name,
file->f_dentry->d_name.name);
#endif
- return smb_revalidate_inode(dir);
+ /*
+ * Directory timestamps in the core protocol aren't updated
+ * when a file is added, so we give them a very short TTL.
+ */
+ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
+ {
+ unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
+ if (age > 2*HZ)
+ smb_invalid_dir_cache(dir);
+ }
+
+ if (server->conn_pid)
+ error = smb_revalidate_inode(dir);
+ else
+ printk("smb_dir_open: smbclient process\n");
+ return error;
}
/*
* Dentry operations routines
*/
static int smb_lookup_validate(struct dentry *);
+static int smb_hash_dentry(struct dentry *, struct qstr *);
+static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static void smb_delete_dentry(struct dentry *);
static struct dentry_operations smbfs_dentry_operations =
{
smb_lookup_validate, /* d_validate(struct dentry *) */
- NULL, /* d_hash */
- NULL, /* d_compare */
+ smb_hash_dentry, /* d_hash */
+ smb_compare_dentry, /* d_compare */
smb_delete_dentry /* d_delete(struct dentry *) */
};
@@ -218,7 +254,7 @@ smb_lookup_validate(struct dentry * dentry)
* we believe in dentries for 5 seconds. (But each
* successful server lookup renews the timestamp.)
*/
- valid = (age <= SMBFS_MAX_AGE) || IS_ROOT(dentry);
+ valid = (age <= SMBFS_MAX_AGE);
#ifdef SMBFS_DEBUG_VERBOSE
if (!valid)
printk("smb_lookup_validate: %s/%s not valid, age=%lu\n",
@@ -234,7 +270,8 @@ printk("smb_lookup_validate: %s/%s has dud inode\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
valid = 0;
- }
+ } else if (!valid)
+ valid = (smb_revalidate_inode(inode) == 0);
} else
{
/*
@@ -245,21 +282,49 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
}
/*
+ * XXX: It would be better to use the tolower from linux/ctype.h,
+ * but _ctype is needed and it is not exported.
+ */
+#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
+
+static int
+smb_hash_dentry(struct dentry *dir, struct qstr *this)
+{
+ unsigned long hash;
+ int i;
+
+ hash = init_name_hash();
+ for (i=0; i < this->len ; i++)
+ hash = partial_name_hash(tolower(this->name[i]), hash);
+ this->hash = end_name_hash(hash);
+
+ return 0;
+}
+
+static int
+smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
+{
+ int i, result = 1;
+
+ if (a->len != b->len)
+ goto out;
+ for (i=0; i < a->len; i++)
+ {
+ if (tolower(a->name[i]) != tolower(b->name[i]))
+ goto out;
+ }
+ result = 0;
+out:
+ return result;
+}
+
+/*
* This is the callback from dput() when d_count is going to 0.
* We use this to unhash dentries with bad inodes and close files.
*/
static void
smb_delete_dentry(struct dentry * dentry)
{
- if ((jiffies - dentry->d_time) > SMBFS_MAX_AGE)
- {
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_delete_dentry: %s/%s expired, d_time=%lu, now=%lu\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_time, jiffies);
-#endif
- d_drop(dentry);
- }
-
if (dentry->d_inode)
{
if (is_bad_inode(dentry->d_inode))
@@ -305,7 +370,7 @@ smb_lookup(struct inode *dir, struct dentry *dentry)
if (dentry->d_name.len > SMB_MAXNAMELEN)
goto out;
- error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &finfo);
+ error = smb_proc_getattr(dentry, &finfo);
#ifdef SMBFS_PARANOIA
if (error && error != -ENOENT)
printk("smb_lookup: find %s/%s failed, error=%d\n",
@@ -350,7 +415,7 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
printk("smb_instantiate: file %s/%s, fileid=%u\n",
dentry->d_parent->d_name.name, dentry->d_name.name, fileid);
#endif
- error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+ error = smb_proc_getattr(dentry, &fattr);
if (error)
goto out_close;
@@ -402,9 +467,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode);
goto out;
smb_invalid_dir_cache(dir);
- error = smb_proc_create(dentry->d_parent, &(dentry->d_name),
- 0, CURRENT_TIME, &fileid);
- if (!error) {
+ error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
+ if (!error)
+ {
error = smb_instantiate(dentry, fileid, 1);
} else
{
@@ -428,7 +493,7 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
goto out;
smb_invalid_dir_cache(dir);
- error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name));
+ error = smb_proc_mkdir(dentry);
if (!error)
{
error = smb_instantiate(dentry, 0, 0);
@@ -440,17 +505,17 @@ out:
static int
smb_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode = dentry->d_inode;
int error;
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > SMB_MAXNAMELEN)
+ error = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
goto out;
/*
- * Since the dentry is holding an inode, the file
- * is in use, so we have to close it first.
+ * Close the directory if it's open.
*/
- smb_close(dentry->d_inode);
+ smb_close(inode);
/*
* Prune any child dentries so this dentry can become negative.
@@ -463,7 +528,7 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
}
smb_invalid_dir_cache(dir);
- error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name));
+ error = smb_proc_rmdir(dentry);
if (!error)
{
smb_renew_times(dentry);
@@ -478,24 +543,18 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > SMB_MAXNAMELEN)
- goto out;
-
/*
- * Since the dentry is holding an inode, the file
- * is in use, so we have to close it first.
+ * Close the file if it's open.
*/
smb_close(dentry->d_inode);
smb_invalid_dir_cache(dir);
- error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name));
+ error = smb_proc_unlink(dentry);
if (!error)
{
smb_renew_times(dentry);
d_delete(dentry);
}
-out:
return error;
}
@@ -511,50 +570,33 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out;
/*
- * Since the old and new dentries are holding the files open,
- * we have to close the files first.
+ * Close any open files, and check whether to delete the
+ * target before attempting the rename.
*/
if (old_dentry->d_inode)
smb_close(old_dentry->d_inode);
if (new_dentry->d_inode)
- smb_close(new_dentry->d_inode);
-
- smb_invalid_dir_cache(old_dir);
- smb_invalid_dir_cache(new_dir);
- error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
- new_dentry->d_parent, &(new_dentry->d_name));
- /*
- * If the new file exists, attempt to delete it.
- */
- if (error == -EEXIST)
{
+ smb_close(new_dentry->d_inode);
+ error = smb_proc_unlink(new_dentry);
+ if (error)
+ {
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_rename: existing file %s/%s, d_count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
-#endif
- error = smb_proc_unlink(new_dentry->d_parent,
- &(new_dentry->d_name));
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_rename: after unlink error=%d\n", error);
+printk("smb_rename: unlink %s/%s, error=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name, error);
#endif
- if (!error)
- {
- d_delete(new_dentry);
- error = smb_proc_mv(old_dentry->d_parent,
- &(old_dentry->d_name),
- new_dentry->d_parent,
- &(new_dentry->d_name));
+ goto out;
}
+ d_delete(new_dentry);
}
- /*
- * Update the dcache
- */
+ smb_invalid_dir_cache(old_dir);
+ smb_invalid_dir_cache(new_dir);
+ error = smb_proc_mv(old_dentry, new_dentry);
if (!error)
{
smb_renew_times(old_dentry);
- smb_renew_times(new_dentry->d_parent);
+ smb_renew_times(new_dentry);
d_move(old_dentry, new_dentry);
}
out:
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 2454fdf8e..c04e0acc0 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -306,9 +306,9 @@ smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
ssize_t result;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_write: file %s/%s, count=%lu@%lu\n",
+printk("smb_file_write: file %s/%s, count=%lu@%lu, pages=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
-(unsigned long) count, (unsigned long) *ppos);
+(unsigned long) count, (unsigned long) *ppos, inode->i_nrpages);
#endif
result = smb_revalidate_inode(inode);
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index b21892863..1e72f59a1 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -55,12 +55,12 @@ static struct super_operations smb_sops =
unsigned long
smb_invent_inos(unsigned long n)
{
- static unsigned long ino = 1;
+ static unsigned long ino = 2;
if (ino + 2*n < ino)
{
/* wrap around */
- ino += n;
+ ino = 2;
}
ino += n;
return ino;
@@ -93,6 +93,7 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
memset(fattr, 0, sizeof(struct smb_fattr));
fattr->f_mode = inode->i_mode;
fattr->f_nlink = inode->i_nlink;
+ fattr->f_ino = inode->i_ino;
fattr->f_uid = inode->i_uid;
fattr->f_gid = inode->i_gid;
fattr->f_rdev = inode->i_rdev;
@@ -102,6 +103,15 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
fattr->f_atime = inode->i_atime;
fattr->f_blksize= inode->i_blksize;
fattr->f_blocks = inode->i_blocks;
+
+ fattr->attr = inode->u.smbfs_i.attr;
+ /*
+ * Keep the attributes in sync with the inode permissions.
+ */
+ if (fattr->f_mode & S_IWUSR)
+ fattr->attr &= ~aRONLY;
+ else
+ fattr->attr |= aRONLY;
}
static void
@@ -112,13 +122,22 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode->i_uid = fattr->f_uid;
inode->i_gid = fattr->f_gid;
inode->i_rdev = fattr->f_rdev;
- inode->i_size = fattr->f_size;
- inode->i_mtime = fattr->f_mtime;
inode->i_ctime = fattr->f_ctime;
- inode->i_atime = fattr->f_atime;
inode->i_blksize= fattr->f_blksize;
inode->i_blocks = fattr->f_blocks;
/*
+ * Don't change the size and mtime/atime fields
+ * if we're writing to the file.
+ */
+ if (!(inode->u.smbfs_i.cache_valid & SMB_F_LOCALWRITE))
+ {
+ inode->i_size = fattr->f_size;
+ inode->i_mtime = fattr->f_mtime;
+ inode->i_atime = fattr->f_atime;
+ }
+
+ inode->u.smbfs_i.attr = fattr->attr;
+ /*
* Update the "last time refreshed" field for revalidation.
*/
inode->u.smbfs_i.oldmtime = jiffies;
@@ -177,9 +196,9 @@ smb_revalidate_inode(struct inode *inode)
* If this is a file opened with write permissions,
* the inode will be up-to-date.
*/
- if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
- if (inode->u.smbfs_i.access == SMB_O_RDWR ||
- inode->u.smbfs_i.access == SMB_O_WRONLY)
+ if (S_ISREG(inode->i_mode) && smb_is_open(inode))
+ {
+ if (inode->u.smbfs_i.access != SMB_O_RDONLY)
goto out;
}
@@ -237,15 +256,7 @@ smb_refresh_inode(struct inode *inode)
goto out;
}
- /*
- * Kludge alert ... for some reason we can't get attributes
- * for the root directory, so just return success.
- */
- error = 0;
- if (IS_ROOT(dentry))
- goto out;
-
- error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+ error = smb_proc_getattr(dentry, &fattr);
if (!error)
{
smb_renew_times(dentry);
@@ -261,12 +272,8 @@ smb_refresh_inode(struct inode *inode)
* Big trouble! The inode has become a new object,
* so any operations attempted on it are invalid.
*
- * Take a couple of steps to limit damage:
- * (1) Mark the inode as bad so that subsequent
- * lookup validations will fail.
- * (2) Clear i_nlink so the inode will be released
- * at iput() time. (Unhash it as well?)
- * We also invalidate the caches for good measure.
+ * To limit damage, mark the inode as bad so that
+ * subsequent lookup validations will fail.
*/
#ifdef SMBFS_PARANOIA
printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
@@ -354,7 +361,7 @@ smb_put_super(struct super_block *sb)
}
if (server->conn_pid)
- kill_proc(server->conn_pid, SIGTERM, 0);
+ kill_proc(server->conn_pid, SIGTERM, 1);
kfree(server->mnt);
if (server->packet)
@@ -487,7 +494,8 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
struct smb_sb_info *server = SMB_SERVER(inode);
struct dentry *dentry = inode->u.smbfs_i.dentry;
unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- int error, refresh = 0;
+ int error, changed, refresh = 0;
+ struct smb_fattr fattr;
error = -EIO;
if (!dentry)
@@ -515,14 +523,14 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
- error = smb_open(dentry, O_WRONLY);
- if (error)
- goto out;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_notify_change: changing %s/%s, old size=%ld, new size=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long) inode->i_size, (long) attr->ia_size);
#endif
+ error = smb_open(dentry, O_WRONLY);
+ if (error)
+ goto out;
error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
attr->ia_size);
if (error)
@@ -531,32 +539,76 @@ dentry->d_parent->d_name.name, dentry->d_name.name,
* We don't implement an i_op->truncate operation,
* so we have to update the page cache here.
*/
- if (attr->ia_size < inode->i_size) {
+ if (attr->ia_size < inode->i_size)
+ {
truncate_inode_pages(inode, attr->ia_size);
inode->i_size = attr->ia_size;
}
refresh = 1;
}
- if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
- {
- struct smb_fattr fattr;
-
- smb_get_inode_attr(inode, &fattr);
- if ((attr->ia_valid & ATTR_CTIME) != 0)
- fattr.f_ctime = attr->ia_ctime;
-
- if ((attr->ia_valid & ATTR_MTIME) != 0)
- fattr.f_mtime = attr->ia_mtime;
-
- if ((attr->ia_valid & ATTR_ATIME) != 0)
- fattr.f_atime = attr->ia_atime;
+ /*
+ * Initialize the fattr and check for changed fields.
+ * Note: CTIME under SMB is creation time rather than
+ * change time, so we don't attempt to change it.
+ */
+ smb_get_inode_attr(inode, &fattr);
- error = smb_proc_setattr(server, dentry, &fattr);
+ changed = 0;
+ if ((attr->ia_valid & ATTR_MTIME) != 0)
+ {
+ fattr.f_mtime = attr->ia_mtime;
+ changed = 1;
+ }
+ if ((attr->ia_valid & ATTR_ATIME) != 0)
+ {
+ fattr.f_atime = attr->ia_atime;
+ /* Earlier protocols don't have an access time */
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+ changed = 1;
+ }
+ if (changed)
+ {
+ error = smb_proc_settime(dentry, &fattr);
if (error)
goto out;
refresh = 1;
}
+
+ /*
+ * Check for mode changes ... we're extremely limited in
+ * what can be set for SMB servers: just the read-only bit.
+ */
+ if ((attr->ia_valid & ATTR_MODE) != 0)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_notify_change: %s/%s mode change, old=%x, new=%lx\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, fattr.f_mode,attr->ia_mode);
+#endif
+ changed = 0;
+ if (attr->ia_mode & S_IWUSR)
+ {
+ if (fattr.attr & aRONLY)
+ {
+ fattr.attr &= ~aRONLY;
+ changed = 1;
+ }
+ } else
+ {
+ if (!(fattr.attr & aRONLY))
+ {
+ fattr.attr |= aRONLY;
+ changed = 1;
+ }
+ }
+ if (changed)
+ {
+ error = smb_proc_setattr(dentry, &fattr);
+ if (error)
+ goto out;
+ refresh = 1;
+ }
+ }
error = 0;
out:
diff --git a/fs/smbfs/ioctl.c b/fs/smbfs/ioctl.c
index 5eb3dc88f..f9e6fd4c2 100644
--- a/fs/smbfs/ioctl.c
+++ b/fs/smbfs/ioctl.c
@@ -11,6 +11,7 @@
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
+
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
@@ -20,29 +21,33 @@ int
smb_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
+ struct smb_sb_info *server = SMB_SERVER(inode);
int result = -EINVAL;
switch (cmd)
{
case SMB_IOC_GETMOUNTUID:
- result = put_user(SMB_SERVER(inode)->mnt->mounted_uid,
- (uid_t *) arg);
+ result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
break;
case SMB_IOC_NEWCONN:
{
struct smb_conn_opt opt;
- if (arg == 0)
+ if (arg)
{
- /* The process offers a new connection upon SIGUSR1 */
- result = smb_offerconn(SMB_SERVER(inode));
+ result = -EFAULT;
+ if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
+ result = smb_newconn(server, &opt);
}
else
{
- result = -EFAULT;
- if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
- result = smb_newconn(SMB_SERVER(inode), &opt);
+#if 0
+ /* obsolete option ... print a warning */
+ printk("SMBFS: ioctl deprecated, please upgrade "
+ "smbfs package\n");
+#endif
+ result = 0;
}
break;
}
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 966ee1e27..05a1ac4f1 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -38,9 +38,8 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
-static int smb_proc_setfile_trans2(struct smb_sb_info *, struct inode *,
+static int smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
struct smb_fattr *);
-
static inline int
min(int a, int b)
{
@@ -237,7 +236,6 @@ date_unix2dos(int unix_date, __u16 *date, __u16 *time)
*date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
}
-
/*****************************************************************************/
/* */
/* Support section. */
@@ -349,7 +347,7 @@ server->packet_size, server->opt.max_xmit, size);
return size;
}
-static int
+int
smb_errno(struct smb_sb_info *server)
{
int errcls = server->rcls;
@@ -402,7 +400,7 @@ smb_errno(struct smb_sb_info *server)
case 123: /* Invalid name?? e.g. .tmp* */
return ENOENT;
case 145: /* Win NT 4.0: non-empty directory? */
- return EBUSY;
+ return ENOTEMPTY;
/* This next error seems to occur on an mv when
* the destination exists */
case 183:
@@ -413,6 +411,7 @@ smb_errno(struct smb_sb_info *server)
} else if (errcls == ERRSRV)
switch (error)
{
+ /* N.B. This is wrong ... EIO ? */
case ERRerror:
return ENFILE;
case ERRbadpw:
@@ -421,6 +420,13 @@ smb_errno(struct smb_sb_info *server)
return EIO;
case ERRaccess:
return EACCES;
+ /*
+ * This is a fatal error, as it means the "tree ID"
+ * for this connection is no longer valid. We map
+ * to a special error code and get a new connection.
+ */
+ case ERRinvnid:
+ return EBADSLT;
default:
class = "ERRSRV";
goto err_unknown;
@@ -474,62 +480,54 @@ smb_unlock_server(struct smb_sb_info *server)
of any use.
* N.B. The server must be locked for this call.
*/
-
static int
smb_retry(struct smb_sb_info *server)
{
- struct wait_queue wait = { current, NULL };
- unsigned long timeout;
- int result = 0;
+ pid_t pid = server->conn_pid;
+ int error, result = 0;
if (server->state != CONN_INVALID)
goto out;
smb_close_socket(server);
- if (server->conn_pid == 0)
+ if (pid == 0)
{
printk("smb_retry: no connection process\n");
server->state = CONN_RETRIED;
goto out;
}
- kill_proc(server->conn_pid, SIGUSR1, 0);
-#if 0
+ /*
+ * Clear the pid to enable the ioctl.
+ */
server->conn_pid = 0;
-#endif
+ /*
+ * Note: use the "priv" flag, as a user process may need to reconnect.
+ */
+ error = kill_proc(pid, SIGUSR1, 1);
+ if (error)
+ {
+ printk("smb_retry: signal failed, error=%d\n", error);
+ goto out_restore;
+ }
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_retry: signalled pid %d, waiting for new connection\n",
server->conn_pid);
#endif
/*
- * Wait here for a new connection.
+ * Wait for the new connection.
*/
- timeout = jiffies + 10*HZ;
- add_wait_queue(&server->wait, &wait);
- while (1)
- {
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ;
- if (server->state != CONN_INVALID)
- break;
- if (jiffies > timeout)
- {
- printk("smb_retry: timed out, try again later\n");
- break;
- }
- if (signal_pending(current))
- {
- printk("smb_retry: caught signal\n");
- break;
- }
- schedule();
- }
- remove_wait_queue(&server->wait, &wait);
+ current->timeout = jiffies + 5*HZ;
+ interruptible_sleep_on(&server->wait);
current->timeout = 0;
- current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ printk("smb_retry: caught signal\n");
+ /*
+ * Check for a valid connection.
+ */
if (server->state == CONN_VALID)
{
#ifdef SMBFS_PARANOIA
@@ -538,6 +536,13 @@ printk("smb_retry: new connection pid=%d\n", server->conn_pid);
result = 1;
}
+ /*
+ * Restore the original pid if we didn't get a new one.
+ */
+out_restore:
+ if (!server->conn_pid)
+ server->conn_pid = pid;
+
out:
return result;
}
@@ -599,43 +604,12 @@ out:
}
/*
- * This is called with the server locked after a successful smb_newconn().
- * It installs the new connection pid, sets server->state to CONN_VALID,
- * and wakes up the process waiting for the new connection.
- * N.B. The first call is made without locking the server -- need to fix!
- */
-int
-smb_offerconn(struct smb_sb_info *server)
-{
- int error;
-
- error = -EACCES;
- if ((current->uid != server->mnt->mounted_uid) && !suser())
- goto out;
- if (atomic_read(&server->sem.count) == 1)
- {
- printk("smb_offerconn: server not locked, count=%d\n",
- atomic_read(&server->sem.count));
-#if 0
- goto out;
-#endif
- }
-
- server->conn_pid = current->pid;
- server->state = CONN_VALID;
- wake_up_interruptible(&server->wait);
-#ifdef SMBFS_PARANOIA
-printk("smb_offerconn: state valid, pid=%d\n", server->conn_pid);
-#endif
- error = 0;
-
-out:
- return error;
-}
-
-/*
- * This must be called with the server locked.
- * N.B. The first call is made without locking the server -- need to fix!
+ * This implements the NEWCONN ioctl. It installs the server pid,
+ * sets server->state to CONN_VALID, and wakes up the waiting process.
+ *
+ * Note that this must be called with the server locked, except for
+ * the first call made after mounting the volume. The server pid
+ * will be set to zero to indicate that smbfs is awaiting a connection.
*/
int
smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
@@ -643,8 +617,13 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
struct file *filp;
int error;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid);
+#endif
error = -EBADF;
- if (opt->fd >= NR_OPEN || !(filp = current->files->fd[opt->fd]))
+ if (opt->fd < 0 || opt->fd >= NR_OPEN)
+ goto out;
+ if (!(filp = current->files->fd[opt->fd]))
goto out;
if (!smb_valid_socket(filp->f_dentry->d_inode))
goto out;
@@ -652,19 +631,22 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
error = -EACCES;
if ((current->uid != server->mnt->mounted_uid) && !suser())
goto out;
- if (atomic_read(&server->sem.count) == 1)
+
+ /*
+ * Make sure we don't already have a pid ...
+ */
+ error = -EINVAL;
+ if (server->conn_pid)
{
- printk("smb_newconn: server not locked, count=%d\n",
- atomic_read(&server->sem.count));
-#if 0
+ printk("SMBFS: invalid ioctl call\n");
goto out;
-#endif
}
+ server->conn_pid = current->pid;
- /*
- * Make sure the old socket is closed
- */
- smb_close_socket(server);
+#ifdef SMBFS_PARANOIA
+if (server->sock_file)
+printk("smb_newconn: old socket not closed!\n");
+#endif
filp->f_count += 1;
server->sock_file = filp;
@@ -675,9 +657,14 @@ printk("smb_newconn: protocol=%d, max_xmit=%d\n",
server->opt.protocol, server->opt.max_xmit);
#endif
server->generation += 1;
+ server->state = CONN_VALID;
+#ifdef SMBFS_PARANOIA
+printk("smb_newconn: state valid, pid=%d\n", server->conn_pid);
+#endif
error = 0;
out:
+ wake_up_interruptible(&server->wait);
return error;
}
@@ -774,13 +761,14 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
if (mode == read_write &&
(error == -EACCES || error == -ETXTBSY || error == -EROFS))
{
-#ifdef SMBFS_PARANOIA
+#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
dentry->d_parent->d_name.name, dentry->d_name.name, error);
#endif
mode = read_only;
goto retry;
}
+ goto out;
}
/* We should now have data in vwv[0..6]. */
@@ -788,17 +776,10 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error);
ino->u.smbfs_i.attr = WVAL(server->packet, smb_vwv1);
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
- ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
- ino->u.smbfs_i.access &= SMB_ACCMASK;
-
- /* N.B. Suppose the open failed?? */
+ ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
ino->u.smbfs_i.open = server->generation;
-#ifdef SMBFS_PARANOIA
-if (error)
-printk("smb_proc_open: %s/%s failed, error=%d, access=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,error,ino->u.smbfs_i.access);
-#endif
+out:
return error;
}
@@ -881,8 +862,8 @@ smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime)
*
* Win NT 4.0 has an apparent bug in that it fails to update the
* modify time when writing to a file. As a workaround, we update
- * the attributes if the file has been modified locally (we want to
- * keep modify and access times in sync ...)
+ * both modify and access time locally, and post the times to the
+ * server when closing the file.
*/
static int
smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
@@ -891,33 +872,32 @@ smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
if (smb_is_open(ino))
{
/*
- * Check whether to update locally-modified attributes at
- * closing time. This is necessary to keep the modify and
- * access times in sync.
- *
- * Kludge alert: If we're using trans2 getattr messages,
- * the timestamps are accurate only to two seconds ...
- * we must round the time to avoid cache invalidations!
+ * We clear the open flag in advance, in case another
+ * process observes the value while we block below.
*/
- if (ino->u.smbfs_i.access == SMB_O_RDWR ||
- ino->u.smbfs_i.access == SMB_O_WRONLY) {
- struct smb_fattr fattr;
+ ino->u.smbfs_i.open = 0;
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
- if (ino->i_mtime & 1)
- ino->i_mtime--;
- if (ino->i_atime & 1)
- ino->i_atime--;
- }
+ /*
+ * Kludge alert: SMB timestamps are accurate only to
+ * two seconds ... round the times to avoid needless
+ * cache invalidations!
+ */
+ if (ino->i_mtime & 1)
+ ino->i_mtime--;
+ if (ino->i_atime & 1)
+ ino->i_atime--;
+ /*
+ * If the file is open with write permissions,
+ * update the time stamps to sync mtime and atime.
+ */
+ if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
+ !(ino->u.smbfs_i.access == SMB_O_RDONLY))
+ {
+ struct smb_fattr fattr;
smb_get_inode_attr(ino, &fattr);
- smb_proc_setfile_trans2(server, ino, &fattr);
+ smb_proc_setattr_ext(server, ino, &fattr);
}
- /*
- * We clear the open flag in advance, in case another
- * process observes the value while we block below.
- */
- ino->u.smbfs_i.open = 0;
result = smb_proc_close(server, ino->u.smbfs_i.fileid,
ino->i_mtime);
ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
@@ -1082,14 +1062,12 @@ count, offset, server->packet_size);
}
int
-smb_proc_create(struct dentry *dir, struct qstr *name,
- __u16 attr, time_t ctime, __u16 *fileid)
+smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
{
- struct smb_sb_info *server;
+ struct smb_sb_info *server = server_from_dentry(dentry);
char *p;
int error;
- server = server_from_dentry(dir);
smb_lock_server(server);
retry:
@@ -1097,7 +1075,7 @@ smb_proc_create(struct dentry *dir, struct qstr *name,
WSET(server->packet, smb_vwv0, attr);
DSET(server->packet, smb_vwv1, utc2local(ctime));
*p++ = 4;
- p = smb_encode_path(server, p, dir, name);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
error = smb_request_ok(server, SMBcreate, 1, 0);
@@ -1116,23 +1094,21 @@ out:
}
int
-smb_proc_mv(struct dentry *odir, struct qstr *oname,
- struct dentry *ndir, struct qstr *nname)
+smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry)
{
- struct smb_sb_info *server;
+ struct smb_sb_info *server = server_from_dentry(old_dentry);
char *p;
int result;
- server = server_from_dentry(odir);
smb_lock_server(server);
retry:
p = smb_setup_header(server, SMBmv, 1, 0);
WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
*p++ = 4;
- p = smb_encode_path(server, p, odir, oname);
+ p = smb_encode_path(server, p, old_dentry, NULL);
*p++ = 4;
- p = smb_encode_path(server, p, ndir, nname);
+ p = smb_encode_path(server, p, new_dentry, NULL);
smb_setup_bcc(server, p);
if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
@@ -1147,23 +1123,26 @@ out:
return result;
}
-int
-smb_proc_mkdir(struct dentry *dir, struct qstr *name)
+/*
+ * Code common to mkdir and rmdir.
+ */
+static int
+smb_proc_generic_command(struct dentry *dentry, __u8 command)
{
- struct smb_sb_info *server;
+ struct smb_sb_info *server = server_from_dentry(dentry);
char *p;
int result;
- server = server_from_dentry(dir);
smb_lock_server(server);
retry:
- p = smb_setup_header(server, SMBmkdir, 0, 0);
+ p = smb_setup_header(server, command, 0, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dir, name);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
+ result = smb_request_ok(server, command, 0, 0);
+ if (result < 0)
{
if (smb_retry(server))
goto retry;
@@ -1176,48 +1155,31 @@ out:
}
int
-smb_proc_rmdir(struct dentry *dir, struct qstr *name)
+smb_proc_mkdir(struct dentry *dentry)
{
- struct smb_sb_info *server;
- char *p;
- int result;
-
- server = server_from_dentry(dir);
- smb_lock_server(server);
-
- retry:
- p = smb_setup_header(server, SMBrmdir, 0, 0);
- *p++ = 4;
- p = smb_encode_path(server, p, dir, name);
- smb_setup_bcc(server, p);
+ return smb_proc_generic_command(dentry, SMBmkdir);
+}
- if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
- {
- if (smb_retry(server))
- goto retry;
- goto out;
- }
- result = 0;
-out:
- smb_unlock_server(server);
- return result;
+int
+smb_proc_rmdir(struct dentry *dentry)
+{
+ return smb_proc_generic_command(dentry, SMBrmdir);
}
int
-smb_proc_unlink(struct dentry *dir, struct qstr *name)
+smb_proc_unlink(struct dentry *dentry)
{
- struct smb_sb_info *server;
+ struct smb_sb_info *server = server_from_dentry(dentry);
char *p;
int result;
- server = server_from_dentry(dir);
smb_lock_server(server);
retry:
p = smb_setup_header(server, SMBunlink, 1, 0);
WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
*p++ = 4;
- p = smb_encode_path(server, p, dir, name);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
@@ -1276,17 +1238,15 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
static void
smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
+ fattr->f_mode = server->mnt->file_mode;
if (fattr->attr & aDIR)
{
- /* N.B. check for read-only directories */
fattr->f_mode = server->mnt->dir_mode;
fattr->f_size = 512;
- } else
- {
- fattr->f_mode = server->mnt->file_mode;
- if (fattr->attr & aRONLY)
- fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
+ /* Check the read-only flag */
+ if (fattr->attr & aRONLY)
+ fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
fattr->f_blocks = 0;
if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
@@ -1302,7 +1262,7 @@ smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
smb_init_dirent(server, fattr);
fattr->attr = aDIR;
- fattr->f_ino = 1;
+ fattr->f_ino = 2; /* traditional root inode number */
fattr->f_mtime = CURRENT_TIME;
smb_finish_dirent(server, fattr);
}
@@ -1475,11 +1435,17 @@ entries_seen, i, fpos);
* Interpret a long filename structure using the specified info level:
* level 1 -- Win NT, Win 95, OS/2
* level 259 -- File name and length only, Win NT, Win 95
- * There seem to be numerous inconsistencies and bugs in implementation.
*
* We return a reference to the name string to avoid copying, and perform
* any needed upper/lower casing in place. Note!! Level 259 entries may
* not have any space beyond the name, so don't try to write a null byte!
+ *
+ * Bugs Noted:
+ * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
+ * (2) When using Info Level 1 Win NT 4.0 truncates directory listings
+ * for certain patterns of names and/or lengths. The breakage pattern is
+ * completely reproducible and can be toggled by the addition of a single
+ * file to the directory. (E.g. echo hi >foo breaks, rm -f foo works.)
*/
static char *
smb_decode_long_dirent(struct smb_sb_info *server, char *p,
@@ -1791,7 +1757,7 @@ smb_proc_readdir(struct dentry *dir, int fpos, void *cachep)
*/
static int
smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
- struct qstr *name, struct smb_fattr *fattr)
+ struct smb_fattr *fattr)
{
int result;
char *p;
@@ -1799,7 +1765,7 @@ smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
retry:
p = smb_setup_header(server, SMBgetatr, 0, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dir, name);
+ p = smb_encode_path(server, p, dir, NULL);
smb_setup_bcc(server, p);
if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
@@ -1825,10 +1791,13 @@ out:
/*
* Note: called with the server locked.
+ *
+ * Bugs Noted:
+ * (1) Win 95 swaps the date and time fields in the standard info level.
*/
static int
smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
- struct qstr *name, struct smb_fattr *attr)
+ struct smb_fattr *attr)
{
char *p;
int result;
@@ -1843,7 +1812,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, name);
+ p = smb_encode_path(server, param + 6, dir, NULL);
result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
0, NULL, p - param, param,
@@ -1906,8 +1875,7 @@ out:
}
int
-smb_proc_getattr(struct dentry *dir, struct qstr *name,
- struct smb_fattr *fattr)
+smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr)
{
struct smb_sb_info *server = server_from_dentry(dir);
int result;
@@ -1921,9 +1889,9 @@ smb_proc_getattr(struct dentry *dir, struct qstr *name,
*/
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
!(server->mnt->version & SMB_FIX_OLDATTR))
- result = smb_proc_getattr_trans2(server, dir, name, fattr);
+ result = smb_proc_getattr_trans2(server, dir, fattr);
else
- result = smb_proc_getattr_core(server, dir, name, fattr);
+ result = smb_proc_getattr_core(server, dir, fattr);
smb_finish_dirent(server, fattr);
@@ -1932,35 +1900,42 @@ smb_proc_getattr(struct dentry *dir, struct qstr *name,
}
/*
- * In the core protocol there is only one time to be set,
- * so we use fattr->f_mtime to make `touch' work.
- * Note: called with the server locked.
+ * Called with the server locked. Because of bugs in the
+ * core protocol, we use this only to set attributes. See
+ * smb_proc_settime() below for timestamp handling.
+ *
+ * Bugs Noted:
+ * (1) If mtime is non-zero, both Win 3.1 and Win 95 fail
+ * with an undocumented error (ERRDOS code 50). Setting
+ * mtime to 0 allows the attributes to be set.
+ * (2) The extra parameters following the name string aren't
+ * in the CIFS docs, but seem to be necessary for operation.
*/
static int
-smb_proc_setattr_core(struct smb_sb_info *server,
- struct dentry *dir, struct smb_fattr *fattr)
+smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
+ __u16 attr)
{
char *p;
- char *buf;
int result;
-#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("setattr_core: %s/%s, mtime=%ld\n",
-dir->d_parent->d_name.name, dir->d_name.name, fattr->f_mtime);
-#endif
-
retry:
- buf = server->packet;
p = smb_setup_header(server, SMBsetatr, 8, 0);
- WSET(buf, smb_vwv0, fattr->attr);
- DSET(buf, smb_vwv1, utc2local(fattr->f_mtime));
- WSET(buf, smb_vwv3, 0); /* reserved values */
- WSET(buf, smb_vwv4, 0);
- WSET(buf, smb_vwv5, 0);
- WSET(buf, smb_vwv6, 0);
- WSET(buf, smb_vwv7, 0);
+ WSET(server->packet, smb_vwv0, attr);
+ DSET(server->packet, smb_vwv1, 0); /* mtime */
+ WSET(server->packet, smb_vwv3, 0); /* reserved values */
+ WSET(server->packet, smb_vwv4, 0);
+ WSET(server->packet, smb_vwv5, 0);
+ WSET(server->packet, smb_vwv6, 0);
+ WSET(server->packet, smb_vwv7, 0);
*p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ /*
+ * Samba uses three leading '\', so we'll do it too.
+ */
+ *p++ = '\\';
+ *p++ = '\\';
+ p = smb_encode_path(server, p, dentry, NULL);
+ *p++ = 4;
+ *p++ = 0;
smb_setup_bcc(server, p);
result = smb_request_ok(server, SMBsetatr, 0, 0);
@@ -1976,50 +1951,55 @@ out:
}
/*
- * Note: called with the server locked.
+ * Because of bugs in the trans2 setattr messages, we must set
+ * attributes and timestamps separately. The core SMBsetatr
+ * message seems to be the only reliable way to set attributes.
+ */
+int
+smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr)
+{
+ struct smb_sb_info *server = server_from_dentry(dir);
+ int result;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_setattr: setting %s/%s, open=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#endif
+ smb_lock_server(server);
+ result = smb_proc_setattr_core(server, dir, fattr->attr);
+ smb_unlock_server(server);
+ return result;
+}
+
+/*
+ * Called with the server locked. Sets the timestamps for an
+ * file open with write permissions.
*/
static int
-smb_proc_setattr_trans2(struct smb_sb_info *server,
- struct dentry *dir, struct smb_fattr *fattr)
+smb_proc_setattr_ext(struct smb_sb_info *server,
+ struct inode *inode, struct smb_fattr *fattr)
{
__u16 date, time;
- char *p;
int result;
- unsigned char *resp_data = NULL;
- unsigned char *resp_param = NULL;
- int resp_data_len = 0;
- int resp_param_len = 0;
- char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
- char data[26];
-
retry:
- WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
- DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, dir, NULL);
-
- date_unix2dos(fattr->f_ctime, &date, &time);
- WSET(data, 0, date);
- WSET(data, 2, time);
+ smb_setup_header(server, SMBsetattrE, 7, 0);
+ WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
+ /* We don't change the creation time */
+ WSET(server->packet, smb_vwv1, 0);
+ WSET(server->packet, smb_vwv2, 0);
date_unix2dos(fattr->f_atime, &date, &time);
- WSET(data, 4, date);
- WSET(data, 6, time);
+ WSET(server->packet, smb_vwv3, date);
+ WSET(server->packet, smb_vwv4, time);
date_unix2dos(fattr->f_mtime, &date, &time);
- WSET(data, 8, date);
- WSET(data, 10, time);
+ WSET(server->packet, smb_vwv5, date);
+ WSET(server->packet, smb_vwv6, time);
#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
-dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+printk("smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n",
+date, time, fattr->f_mtime);
#endif
- DSET(data, 12, fattr->f_size);
- DSET(data, 16, fattr->f_blksize);
- WSET(data, 20, fattr->attr);
- DSET(data, 22, 0); /* ULONG EA size */
- result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
- 26, data, p - param, param,
- &resp_data_len, &resp_data,
- &resp_param_len, &resp_param);
+ result = smb_request_ok(server, SMBsetattrE, 0, 0);
if (result < 0)
{
if (smb_retry(server))
@@ -2027,54 +2007,58 @@ dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
goto out;
}
result = 0;
- if (server->rcls != 0)
- result = -smb_errno(server);
-
out:
return result;
}
/*
- * Set the attributes for an open file.
+ * Note: called with the server locked.
+ *
+ * Bugs Noted:
+ * (1) The TRANSACT2_SETPATHINFO message under Win NT 4.0 doesn't
+ * set the file's attribute flags.
*/
static int
-smb_proc_setfile_trans2(struct smb_sb_info *server,
- struct inode * inode, struct smb_fattr *fattr)
+smb_proc_setattr_trans2(struct smb_sb_info *server,
+ struct dentry *dir, struct smb_fattr *fattr)
{
__u16 date, time;
+ char *p;
+ int result;
+
unsigned char *resp_data = NULL;
- unsigned char *resp_parm = NULL;
+ unsigned char *resp_param = NULL;
int resp_data_len = 0;
- int resp_parm_len = 0;
- int result;
- char parm[6], data[26];
+ int resp_param_len = 0;
+ char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
+ char data[26];
retry:
- WSET(parm, 0, inode->u.smbfs_i.fileid);
- WSET(parm, 2, 1); /* Info level SMB_INFO_STANDARD */
+ WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
+ DSET(param, 2, 0);
+ p = smb_encode_path(server, param + 6, dir, NULL);
- date_unix2dos(fattr->f_ctime, &date, &time);
- WSET(data, 0, date);
- WSET(data, 2, time);
+ WSET(data, 0, 0); /* creation time */
+ WSET(data, 2, 0);
date_unix2dos(fattr->f_atime, &date, &time);
WSET(data, 4, date);
WSET(data, 6, time);
-#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("smb_proc_setfile_trans2: date=%x, time=%x, atime=%ld\n",
-date, time, fattr->f_atime);
-#endif
date_unix2dos(fattr->f_mtime, &date, &time);
WSET(data, 8, date);
WSET(data, 10, time);
- DSET(data, 12, fattr->f_size);
- DSET(data, 16, fattr->f_blksize);
- WSET(data, 20, fattr->attr);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+#endif
+ DSET(data, 12, 0); /* size */
+ DSET(data, 16, 0); /* blksize */
+ WSET(data, 20, 0); /* attr */
DSET(data, 22, 0); /* ULONG EA size */
- result = smb_trans2_request(server, TRANSACT2_SETFILEINFO,
- 26, data, 6, parm,
+ result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+ 26, data, p - param, param,
&resp_data_len, &resp_data,
- &resp_parm_len, &resp_parm);
+ &resp_param_len, &resp_param);
if (result < 0)
{
if (smb_retry(server))
@@ -2089,27 +2073,70 @@ out:
return result;
}
+/*
+ * Set the modify and access timestamps for a file.
+ *
+ * Incredibly enough, in all of SMB there is no message to allow
+ * setting both attributes and timestamps at once.
+ *
+ * Bugs Noted:
+ * (1) Win 95 doesn't support the TRANSACT2_SETFILEINFO message
+ * with info level 1 (INFO_STANDARD).
+ * (2) Under the core protocol apparently the only way to set the
+ * timestamp is to open and close the file.
+ */
int
-smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
- struct smb_fattr *fattr)
+smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ struct inode *inode = dentry->d_inode;
int result;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_setattr: setting %s/%s, open=%d\n",
-dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("smb_proc_settime: setting %s/%s, open=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, smb_is_open(inode));
#endif
smb_lock_server(server);
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
- struct inode *inode = dir->d_inode;
-
- if (smb_is_open(inode))
- result = smb_proc_setfile_trans2(server, inode, fattr);
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+ {
+ if (smb_is_open(inode) &&
+ inode->u.smbfs_i.access != SMB_O_RDONLY)
+ result = smb_proc_setattr_ext(server, inode, fattr);
else
- result = smb_proc_setattr_trans2(server, dir, fattr);
+ result = smb_proc_setattr_trans2(server, dentry, fattr);
} else
- result = smb_proc_setattr_core(server, dir, fattr);
+ {
+ /*
+ * Fail silently on directories ... timestamp can't be set?
+ */
+ result = 0;
+ if (S_ISREG(inode->i_mode))
+ {
+ /*
+ * Set the mtime by opening and closing the file.
+ */
+ result = -EACCES;
+ if (!smb_is_open(inode))
+ smb_proc_open(server, dentry, SMB_O_WRONLY);
+ if (smb_is_open(inode) &&
+ inode->u.smbfs_i.access != SMB_O_RDONLY)
+ {
+ inode->i_mtime = fattr->f_mtime;
+ result = smb_proc_close_inode(server, inode);
+ }
+ }
+ }
+#if 1 /* temporary */
+ if (result)
+ {
+printk("smb_proc_settime: %s/%s failed, open=%d, res=%d, rcls=%d, err=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, smb_is_open(inode),
+result, server->rcls, server->err);
+ /* squash errors for now */
+ result = 0;
+ }
+#endif
smb_unlock_server(server);
return result;
}
@@ -2133,8 +2160,8 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr)
goto out;
}
p = SMB_VWV(server->packet);
- attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
attr->f_blocks = WVAL(p, 0);
+ attr->f_bsize = WVAL(p, 2) * WVAL(p, 4);
attr->f_bavail = attr->f_bfree = WVAL(p, 6);
error = 0;
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 45a0790fc..0803a483f 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -397,10 +397,6 @@ smb_receive(struct smb_sb_info *server)
{
int new_len = smb_round_length(len + 4);
-#ifdef SMBFS_PARANOIA
-printk("smb_receive: Increase packet size from %d to %d\n",
-server->packet_size, new_len);
-#endif
result = -ENOMEM;
packet = smb_vmalloc(new_len);
if (packet == NULL)
@@ -655,6 +651,17 @@ smb_request(struct smb_sb_info *server)
}
if (result < 0)
goto bad_conn;
+ /*
+ * Check for fatal server errors ...
+ */
+ if (server->rcls) {
+ int error = smb_errno(server);
+ if (error == EBADSLT) {
+ printk("smb_request: tree ID invalid\n");
+ result = error;
+ goto bad_conn;
+ }
+ }
out:
pr_debug("smb_request: result = %d\n", result);
@@ -827,6 +834,17 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
}
if (result < 0)
goto bad_conn;
+ /*
+ * Check for fatal server errors ...
+ */
+ if (server->rcls) {
+ int error = smb_errno(server);
+ if (error == EBADSLT) {
+ printk("smb_request: tree ID invalid\n");
+ result = error;
+ goto bad_conn;
+ }
+ }
out:
return result;
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index bb8828efa..ff3d7c7af 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -9,10 +9,10 @@
*
* sysv/namei.c
* Copyright (C) 1993 Bruno Haible
- */
-/*
- 7 Dec 1997 - updated to use dentries by Krzysztof G. Baranowski
- <kgb@manjak.knm.org.pl>
+ *
+ *
+ * Revised: 15 Dec 1997 by Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
+ * Driver updated to use dentries.
*/
@@ -107,7 +107,6 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
int sysv_lookup(struct inode * dir, struct dentry * dentry)
{
- int ino;
struct inode * inode = NULL;
struct sysv_dir_entry * de;
struct buffer_head * bh;
@@ -117,16 +116,16 @@ int sysv_lookup(struct inode * dir, struct dentry * dentry)
if (!S_ISDIR(dir->i_mode)) {
return -ENOENT;
}
- if (!(bh = sysv_find_entry(dir, dentry->d_name.name,
- dentry->d_name.len, &de))) {
- return -ENOENT;
- }
- ino = de->inode;
- brelse(bh);
- inode = iget(dir->i_sb,ino);
+ bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+
+ if (bh) {
+ int ino = de->inode;
+ brelse(bh);
+ inode = iget(dir->i_sb,ino);
- if (!inode)
- return -EACCES;
+ if (!inode)
+ return -EACCES;
+ }
d_add(dentry, inode);
return 0;
}
@@ -302,9 +301,8 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
brelse(bh);
return -EEXIST;
}
- if (dir->i_nlink >= dir->i_sb->sv_link_max) {
+ if (dir->i_nlink >= dir->i_sb->sv_link_max)
return -EMLINK;
- }
inode = sysv_new_inode(dir);
if (!inode)
return -ENOSPC;
@@ -595,6 +593,7 @@ int sysv_link(struct inode * oldinode, struct inode * dir,
error = sysv_add_entry(dir, dentry->d_name.name,
dentry->d_name.len, &bh, &de);
if (error) {
+ brelse(bh);
return error;
}
de->inode = oldinode->i_ino;
@@ -652,8 +651,6 @@ try_again:
brelse(old_bh);
brelse(new_bh);
brelse(dir_bh);
- iput(old_inode);
- iput(new_inode);
current->counter = 0;
schedule();
start_up:
@@ -759,15 +756,12 @@ start_up:
mark_inode_dirty(new_dir);
}
}
+ d_move(old_dentry, new_dentry);
retval = 0;
end_rename:
brelse(dir_bh);
brelse(old_bh);
brelse(new_bh);
- iput(old_inode);
- iput(new_inode);
- iput(old_dir);
- iput(new_dir);
return retval;
}
diff --git a/include/asm-i386/math_emu.h b/include/asm-i386/math_emu.h
index d1b0134cc..7284939fe 100644
--- a/include/asm-i386/math_emu.h
+++ b/include/asm-i386/math_emu.h
@@ -3,17 +3,8 @@
#include <asm/sigcontext.h>
-void restore_i387_soft(struct _fpstate *buf);
-struct _fpstate * save_i387_soft(struct _fpstate * buf);
-
-struct fpu_reg {
- char sign;
- char tag;
- long exp;
- unsigned sigl;
- unsigned sigh;
-};
-
+void restore_i387_soft(void *s387, struct _fpstate *buf);
+struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf);
/* This structure matches the layout of the data saved to the stack
following a device-not-present interrupt, part of it saved
@@ -42,5 +33,4 @@ struct info {
long ___vm86_fs;
long ___vm86_gs;
};
-
#endif
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 449caf768..9e4ca405d 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -76,9 +76,8 @@ struct i387_soft_struct {
long fcs;
long foo;
long fos;
- long top;
- struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */
- unsigned char lookahead;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+ unsigned char ftop, changed, lookahead, no_update, rm, alimit;
struct info *info;
unsigned long entry_eip;
};
diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
index 90aa9a55e..985d28829 100644
--- a/include/asm-i386/ptrace.h
+++ b/include/asm-i386/ptrace.h
@@ -41,6 +41,12 @@ struct pt_regs {
int xss;
};
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+
#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip)
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 145118a71..738268052 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -275,22 +275,20 @@ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
((limit) & 0x0ffff); }
#define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw $" #limit ",%1\n\t" \
- "movw %%ax,%2\n\t" \
+__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
+ "movw %%ax,2(%2)\n\t" \
"rorl $16,%%eax\n\t" \
- "movb %%al,%3\n\t" \
- "movb $" type ",%4\n\t" \
- "movb $0x00,%5\n\t" \
- "movb %%ah,%6\n\t" \
+ "movb %%al,4(%2)\n\t" \
+ "movb %4,5(%2)\n\t" \
+ "movb $0,6(%2)\n\t" \
+ "movb %%ah,7(%2)\n\t" \
"rorl $16,%%eax" \
- : /* no output */ \
- :"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
- "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
- )
+ : "=m"(*(n)) : "a" (addr), "r"(n), "i"(limit), "i"(type))
-#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),235,"0x89")
+#define set_tss_desc(n,addr) \
+ _set_tssldt_desc(((char *) (n)),((int)(addr)),235,0x89)
#define set_ldt_desc(n,addr,size) \
- _set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),"0x82")
+ _set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),0x82)
/*
* This is the ldt that every process will get unless we need
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 9bad95386..1e7005e6c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -70,4 +70,6 @@ extern int * hardsect_size[MAX_BLKDEV];
extern int * max_readahead[MAX_BLKDEV];
+extern int * max_sectors[MAX_BLKDEV];
+
#endif
diff --git a/include/linux/dmascc.h b/include/linux/dmascc.h
index 01b46df73..a30d84e60 100644
--- a/include/linux/dmascc.h
+++ b/include/linux/dmascc.h
@@ -41,3 +41,46 @@ struct scc_param {
int dma; /* 1, 3 */
};
+/*
+ * $Id: dmascc.h,v 1.1 1997/12/01 10:44:55 oe1kib Exp $
+ *
+ * Driver for high-speed SCC boards (those with DMA support)
+ * Copyright (C) 1997 Klaus Kudielka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Ioctls */
+#define SIOCGSCCPARAM SIOCDEVPRIVATE
+#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1)
+
+/* Frequency of timer 0 */
+#define TMR_0_HZ 25600
+
+/* Configurable parameters */
+struct scc_param {
+ int pclk_hz; /* frequency of BRG input (read-only - don't change) */
+ int brg_tc; /* baud rate generator terminal count - BRG disabled if < 0 */
+ int nrzi; /* 0 (nrz), 1 (nrzi) */
+ int clocks; /* see documentation */
+ int txdelay; /* [1/TMR_0_HZ] */
+ int txtime; /* [1/HZ] */
+ int sqdelay; /* [1/TMR_0_HZ] */
+ int waittime; /* [1/TMR_0_HZ] */
+ int slottime; /* [1/TMR_0_HZ] */
+ int persist; /* 0 ... 255 */
+ int dma; /* 1, 3 */
+};
+
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 28b6f1e50..4c2bcd91c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -138,6 +138,10 @@ extern int max_files, nr_files, nr_free_files;
#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
#define BLKRASET _IO(0x12,98) /* Set read ahead for block device */
#define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
+#define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
+#define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
+#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
+#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP _IO(0x00,1) /* bmap access */
@@ -713,6 +717,7 @@ extern void put_write_access(struct inode *inode);
extern struct dentry * open_namei(const char * pathname, int flag, int mode);
extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
extern int do_pipe(int *);
+extern ino_t find_inode_number(struct dentry *, struct qstr *);
/*
* Kernel pointers have redundant information, so we can use a
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index cedbd1e2c..35db77dc9 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -195,10 +195,6 @@ struct hd_driveid {
void hd_setup(char *, int *);
#endif /* CONFIG_BLK_DEV_HD */
-#ifdef CONFIG_BLK_DEV_IDE
-void ide_setup(char *);
-#endif /* CONFIG_BLK_DEV_IDE */
-
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
int ide_register(int io_port, int ctl_port, int irq);
void ide_unregister(unsigned int);
diff --git a/include/linux/ip_fw.h b/include/linux/ip_fw.h
index 0b6c103f1..a9933659c 100644
--- a/include/linux/ip_fw.h
+++ b/include/linux/ip_fw.h
@@ -126,7 +126,8 @@ struct ip_fw
#define IP_FW_IN 1
#define IP_FW_OUT 2
#define IP_FW_ACCT 3
-#define IP_FW_CHAINS 4 /* total number of ip_fw chains */
+#define IP_FW_MASQ 4
+#define IP_FW_CHAINS 5 /* total number of ip_fw chains */
#define IP_FW_INSERT (IP_FW_BASE_CTL)
#define IP_FW_APPEND (IP_FW_BASE_CTL+1)
@@ -167,6 +168,11 @@ struct ip_fw
#define IP_ACCT_FLUSH (IP_FW_FLUSH | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_ACCT_ZERO (IP_FW_ZERO | (IP_FW_ACCT << IP_FW_SHIFT))
+#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
+#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT))
+
struct ip_fwpkt
{
struct iphdr fwp_iph; /* IP header */
@@ -179,6 +185,20 @@ struct ip_fwpkt
char fwp_vianame[IFNAMSIZ]; /* interface name */
};
+#define IP_FW_MASQCTL_MAX 256
+#define IP_MASQ_MOD_NMAX 32
+
+struct ip_fw_masqctl
+{
+ int mctl_action;
+ union {
+ struct {
+ char name[IP_MASQ_MOD_NMAX];
+ char data[1];
+ } mod;
+ } u;
+};
+
/*
* timeouts for ip masquerading
*/
@@ -211,9 +231,13 @@ extern int ip_fw_ctl(int, void *, int);
extern struct ip_fw *ip_acct_chain;
extern int ip_acct_ctl(int, void *, int);
#endif
+#ifdef CONFIG_IP_MASQUERADE
+extern int ip_masq_ctl(int, void *, int);
+#endif
extern int ip_fw_chk(struct iphdr *, struct device *, __u16 *, struct ip_fw *, int, int);
extern void ip_fw_init(void);
#endif /* KERNEL */
+
#endif /* _IP_FW_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 276c27960..4a44f193d 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -144,7 +144,6 @@ typedef struct page {
#define PageLocked(page) (test_bit(PG_locked, &(page)->flags))
#define PageError(page) (test_bit(PG_error, &(page)->flags))
#define PageReferenced(page) (test_bit(PG_referenced, &(page)->flags))
-#define PageDirty(page) (test_bit(PG_dirty, &(page)->flags))
#define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags))
#define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags))
#define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags))
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e233695c0..3c869e38d 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -168,6 +168,7 @@ extern int nfs_lock(struct file *file, int cmd, struct file_lock *fl);
* linux/fs/nfs/write.c
*/
extern int nfs_writepage(struct inode *, struct page *);
+extern int nfs_check_failed_request(struct inode *);
extern int nfs_check_error(struct inode *);
extern int nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
extern int nfs_truncate_dirty_pages(struct inode *, unsigned long);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 164a32768..d242a9912 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -789,8 +789,8 @@
#define PCI_DEVICE_ID_INTEL_82865 0x1227
#define PCI_DEVICE_ID_INTEL_82557 0x1229
#define PCI_DEVICE_ID_INTEL_82437 0x122d
-#define PCI_DEVICE_ID_INTEL_82371_0 0x122e
-#define PCI_DEVICE_ID_INTEL_82371_1 0x1230
+#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230
#define PCI_DEVICE_ID_INTEL_82371MX 0x1234
#define PCI_DEVICE_ID_INTEL_82437MX 0x1235
#define PCI_DEVICE_ID_INTEL_82441 0x1237
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 902e63f39..2d2a7453e 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -248,6 +248,11 @@ struct proc_dir_entry {
int deleted; /* delete flag */
};
+typedef int (read_proc_t)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+typedef int (write_proc_t)(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index d34e9d77d..f21d66080 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -106,22 +106,23 @@ __u8 *smb_encode_smb_length(__u8 *, __u32);
__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
int smb_get_rsize(struct smb_sb_info *);
int smb_get_wsize(struct smb_sb_info *);
-int smb_offerconn(struct smb_sb_info *);
int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *);
+int smb_errno(struct smb_sb_info *);
int smb_close(struct inode *);
void smb_close_dentry(struct dentry *);
int smb_close_fileid(struct dentry *, __u16);
int smb_open(struct dentry *, int);
int smb_proc_read(struct inode *, off_t, int, char *);
int smb_proc_write(struct inode *, off_t, int, const char *);
-int smb_proc_create(struct dentry *, struct qstr *, __u16, time_t, __u16 *);
-int smb_proc_mv(struct dentry *, struct qstr *, struct dentry *, struct qstr *);
-int smb_proc_mkdir(struct dentry *, struct qstr *);
-int smb_proc_rmdir(struct dentry *, struct qstr *);
-int smb_proc_unlink(struct dentry *dir, struct qstr *);
+int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
+int smb_proc_mv(struct dentry *, struct dentry *);
+int smb_proc_mkdir(struct dentry *);
+int smb_proc_rmdir(struct dentry *);
+int smb_proc_unlink(struct dentry *);
int smb_proc_readdir(struct dentry *, int, void *);
-int smb_proc_getattr(struct dentry *, struct qstr *, struct smb_fattr *);
-int smb_proc_setattr(struct smb_sb_info *, struct dentry *, struct smb_fattr *);
+int smb_proc_getattr(struct dentry *, struct smb_fattr *);
+int smb_proc_setattr(struct dentry *, struct smb_fattr *);
+int smb_proc_settime(struct dentry *, struct smb_fattr *);
int smb_proc_dskattr(struct super_block *, struct statfs *);
int smb_proc_reconnect(struct smb_sb_info *);
int smb_proc_connect(struct smb_sb_info *);
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 86d2b5665..e274a3c51 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -221,7 +221,7 @@ extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov,
extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
struct iovec *iov,
int offset,
- int len, int *csump);
+ unsigned int len, int *csump);
extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 1f9ab2bf8..68b6fee1b 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -173,6 +173,8 @@ enum
NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY,
NET_IPV4_IGMP_TIMER_SCALE,
NET_IPV4_IGMP_AGE_THRESHOLD,
+ NET_IPV4_IP_DYNADDR,
+ NET_IPV4_IP_MASQ_DEBUG,
NET_TCP_SYNCOOKIES,
NET_TCP_STDURG,
NET_TCP_SYN_TAILDROP,
diff --git a/include/net/ip_autofw.h b/include/net/ip_autofw.h
new file mode 100644
index 000000000..feeec7bb1
--- /dev/null
+++ b/include/net/ip_autofw.h
@@ -0,0 +1,33 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#ifndef _IP_AUTOFW_H
+#define _IP_AUTOFW_H
+
+#define IP_AUTOFW_EXPIRE 15*HZ
+
+#define IP_FWD_RANGE 1
+#define IP_FWD_PORT 2
+#define IP_FWD_DIRECT 3
+
+#define IP_AUTOFW_ACTIVE 1
+#define IP_AUTOFW_USETIME 2
+#define IP_AUTOFW_SECURE 4
+
+struct ip_autofw {
+ struct ip_autofw * next;
+ __u16 type;
+ __u16 low;
+ __u16 hidden;
+ __u16 high;
+ __u16 visible;
+ __u16 protocol;
+ __u32 lastcontact;
+ __u32 where;
+ __u16 ctlproto;
+ __u16 ctlport;
+ __u16 flags;
+ struct timer_list timer;
+};
+int ip_autofw_init(void);
+#endif /* _IP_AUTOFW_H */
diff --git a/include/net/ip_masq.h b/include/net/ip_masq.h
index 4a0b10a55..810abd5f6 100644
--- a/include/net/ip_masq.h
+++ b/include/net/ip_masq.h
@@ -5,9 +5,23 @@
#ifndef _IP_MASQ_H
#define _IP_MASQ_H
+#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/netdevice.h>
+#include <linux/ip.h>
#include <linux/skbuff.h>
+#endif /* __KERNEL__ */
+
+/*
+ * This define affects the number of ports that can be handled
+ * by each of the protocol helper modules.
+ */
+#define MAX_MASQ_APP_PORTS 12
+
+/*
+ * Linux ports don't normally get allocated above 32K.
+ * I used an extra 4K port-space
+ */
/*
* Linux ports don't normally get allocated above 32K.
@@ -20,18 +34,21 @@
#define MASQUERADE_EXPIRE_TCP 15*60*HZ
#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ
#define MASQUERADE_EXPIRE_UDP 5*60*HZ
+/*
+ * ICMP can no longer be modified on the fly using an ioctl - this
+ * define is the only way to change the timeouts
+ */
+#define MASQUERADE_EXPIRE_ICMP 125*HZ
#define IP_MASQ_F_OUT_SEQ 0x01 /* must do output seq adjust */
#define IP_MASQ_F_IN_SEQ 0x02 /* must do input seq adjust */
-#define IP_MASQ_F_NO_DPORT 0x04 /* no dport set yet */
-#define IP_MASQ_F_NO_DADDR 0x08 /* no daddr yet */
-#define IP_MASQ_F_HASHED 0x10 /* hashed entry */
-#define IP_MASQ_F_SAW_RST 0x20 /* tcp rst pkt seen */
-#define IP_MASQ_F_SAW_FIN_IN 0x40 /* tcp fin pkt seen incoming */
-#define IP_MASQ_F_SAW_FIN_OUT 0x80 /* tcp fin pkt seen outgoing */
-#define IP_MASQ_F_SAW_FIN (IP_MASQ_F_SAW_FIN_IN | \
- IP_MASQ_F_SAW_FIN_OUT)
- /* tcp fin pkts seen */
+#define IP_MASQ_F_NO_DPORT 0x04 /* no dport set yet */
+#define IP_MASQ_F_NO_DADDR 0x08 /* no daddr yet */
+#define IP_MASQ_F_HASHED 0x10 /* hashed entry */
+
+#define IP_MASQ_F_NO_SPORT 0x200 /* no sport set yet */
+#define IP_MASQ_F_NO_REPLY 0x800 /* no reply yet from outside */
+#define IP_MASQ_F_MPORT 0x1000 /* own mport specified */
#ifdef __KERNEL__
@@ -51,6 +68,7 @@ struct ip_masq_seq {
*/
struct ip_masq {
struct ip_masq *m_link, *s_link; /* hashed link ptrs */
+ atomic_t refcnt; /* reference count */
struct timer_list timer; /* Expiration timer */
__u16 protocol; /* Which protocol are we talking? */
__u16 sport, dport, mport; /* src, dst & masq ports */
@@ -58,7 +76,12 @@ struct ip_masq {
struct ip_masq_seq out_seq, in_seq;
struct ip_masq_app *app; /* bound ip_masq_app object */
void *app_data; /* Application private data */
- unsigned flags; /* status flags */
+ struct ip_masq *control; /* Master control connection */
+ atomic_t n_control; /* Number of "controlled" masqs */
+ unsigned flags; /* status flags */
+ unsigned timeout; /* timeout */
+ unsigned state; /* state info */
+ struct ip_masq_timeout_table *timeout_table;
};
/*
@@ -76,9 +99,10 @@ extern struct ip_fw_masq *ip_masq_expire;
/*
* [0]: UDP free_ports
* [1]: TCP free_ports
+ * [2]: ICMP free_ports
*/
-extern int ip_masq_free_ports[2];
+extern atomic_t ip_masq_free_ports[3];
/*
* ip_masq initializer (registers symbols and /proc/net entries)
@@ -89,14 +113,17 @@ extern int ip_masq_init(void);
* functions called from ip layer
*/
extern int ip_fw_masquerade(struct sk_buff **, __u32 maddr);
-extern int ip_fw_masq_icmp(struct sk_buff **);
+extern int ip_fw_masq_icmp(struct sk_buff **, __u32 maddr);
extern int ip_fw_demasquerade(struct sk_buff **);
/*
* ip_masq obj creation/deletion functions.
*/
-extern struct ip_masq *ip_masq_new(__u32 maddr, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
-extern void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout);
+extern struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
+
+extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms);
+extern void ip_masq_control_del(struct ip_masq *ms);
+extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms);
/*
@@ -118,7 +145,7 @@ struct ip_masq_app
int (*pkt_out) /* output (masquerading) hook */
(struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
int (*pkt_in) /* input (demasq) hook */
- (struct ip_masq_app *, struct ip_masq *, struct sk_buff **);
+ (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
};
/*
@@ -148,13 +175,109 @@ extern int ip_masq_unbind_app(struct ip_masq *ms);
*
*/
extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
-extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p);
+extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
/*
* service routine(s).
*/
-extern struct ip_masq * ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
-extern struct ip_masq * ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+extern struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+extern struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+extern int ip_masq_listen(struct ip_masq *);
+
+static __inline__ struct ip_masq * ip_masq_in_get_iph(const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ return ip_masq_in_get(iph->protocol,
+ iph->saddr, portp[0],
+ iph->daddr, portp[1]);
+}
+
+static __inline__ struct ip_masq * ip_masq_out_get_iph(const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ return ip_masq_out_get(iph->protocol,
+ iph->saddr, portp[0],
+ iph->daddr, portp[1]);
+}
+
+extern void ip_masq_put(struct ip_masq *ms);
+
+
+/*
+ * Locking stuff
+ */
+
+
+static __inline__ void ip_masq_lock(atomic_t *lock, int rw)
+{
+#if 0
+ if (rw)
+#endif
+ start_bh_atomic();
+ atomic_inc(lock);
+}
+
+static __inline__ void ip_masq_unlock(atomic_t *lock, int rw)
+{
+ atomic_dec(lock);
+#if 0
+ if (rw)
+#endif
+ end_bh_atomic();
+}
+
+/*
+ * Sleep-able lockzzz...
+ */
+static __inline__ void ip_masq_lockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
+{
+ if (rw)
+ while(atomic_read(lock)) sleep_on(waitq);
+ ip_masq_lock(lock, rw);
+}
+
+static __inline__ void ip_masq_unlockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
+{
+ ip_masq_unlock(lock, rw);
+ if (rw)
+ wake_up(waitq);
+}
+
+/*
+ * Perfect for winning races ... ;)
+ */
+static __inline__ int ip_masq_nlocks(atomic_t *lock)
+{
+ return atomic_read(lock);
+}
+
+extern atomic_t __ip_masq_lock;
+
+/*
+ * Debugging stuff
+ */
+
+extern int ip_masq_get_debug_level(void);
+
+#ifndef CONFIG_IP_MASQ_NDEBUG
+#define IP_MASQ_DEBUG(level, msg...) \
+ if (level <= ip_masq_get_debug_level()) \
+ printk(KERN_DEBUG "IP_MASQ:" ## msg)
+#else /* NO DEBUGGING at ALL */
+#define IP_MASQ_DEBUG(level, msg...) do { } while (0)
+#endif
+
+#define IP_MASQ_INFO(msg...) \
+ printk(KERN_INFO "IP_MASQ:" ## msg)
+
+#define IP_MASQ_ERR(msg...) \
+ printk(KERN_ERR "IP_MASQ:" ## msg)
+
+#define IP_MASQ_WARNING(msg...) \
+ printk(KERN_WARNING "IP_MASQ:" ## msg)
+
/*
* /proc/net entry
@@ -167,6 +290,71 @@ extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int len
*/
extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len);
+/*
+ * masq_proto_num returns 0 for UDP, 1 for TCP, 2 for ICMP
+ */
+
+static __inline__ int masq_proto_num(unsigned proto)
+{
+ switch (proto)
+ {
+ case IPPROTO_UDP: return (0); break;
+ case IPPROTO_TCP: return (1); break;
+ case IPPROTO_ICMP: return (2); break;
+ default: return (-1); break;
+ }
+}
+
+static __inline__ const char *masq_proto_name(unsigned proto)
+{
+ static char buf[20];
+ static const char *strProt[] = {"UDP","TCP","ICMP"};
+ int msproto = masq_proto_num(proto);
+
+ if (msproto<0||msproto>2) {
+ sprintf(buf, "IP_%d", proto);
+ return buf;
+ }
+ return strProt[msproto];
+}
+
+enum {
+ IP_MASQ_S_NONE = 0,
+ IP_MASQ_S_ESTABLISHED,
+ IP_MASQ_S_SYN_SENT,
+ IP_MASQ_S_SYN_RECV,
+ IP_MASQ_S_FIN_WAIT,
+ IP_MASQ_S_TIME_WAIT,
+ IP_MASQ_S_CLOSE,
+ IP_MASQ_S_CLOSE_WAIT,
+ IP_MASQ_S_LAST_ACK,
+ IP_MASQ_S_LISTEN,
+ IP_MASQ_S_UDP,
+ IP_MASQ_S_ICMP,
+ IP_MASQ_S_LAST
+};
+
+struct ip_masq_timeout_table {
+ atomic_t refcnt;
+ int scale;
+ int timeout[IP_MASQ_S_LAST+1];
+};
+
+static __inline__ void ip_masq_timeout_attach(struct ip_masq *ms, struct ip_masq_timeout_table *mstim)
+{
+ atomic_inc (&mstim->refcnt);
+ ms->timeout_table=mstim;
+}
+
+static __inline__ void ip_masq_timeout_detach(struct ip_masq *ms)
+{
+ struct ip_masq_timeout_table *mstim = ms->timeout_table;
+
+ if (!mstim)
+ return;
+ atomic_dec(&mstim->refcnt);
+}
+
#endif /* __KERNEL__ */
#endif /* _IP_MASQ_H */
diff --git a/include/net/ip_masq_mod.h b/include/net/ip_masq_mod.h
new file mode 100644
index 000000000..427421d9b
--- /dev/null
+++ b/include/net/ip_masq_mod.h
@@ -0,0 +1,78 @@
+/*
+ * IP Masquerading Modules Support
+ *
+ * Version: @(#)ip_masq_mod.h 0.01 97/10/30
+ *
+ * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ */
+
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/ip_fw.h>
+#include <linux/proc_fs.h>
+#include <net/ip_masq.h>
+
+enum {
+ IP_MASQ_MOD_NOP,
+ IP_MASQ_MOD_ACCEPT,
+ IP_MASQ_MOD_REJECT
+};
+
+struct ip_masq_mod {
+ struct ip_masq_mod *next; /* next mod for addrs. lookups */
+ struct ip_masq_mod *next_reg; /* next mod for configuration ctls */
+ char *mmod_name;
+ atomic_t refcnt;
+ atomic_t mmod_nent; /* number of entries */
+ struct proc_dir_entry *mmod_proc_ent;
+ int (*mmod_ctl) (int optname, struct ip_fw_masqctl *, int optlen);
+ int (*mmod_init) (void);
+ int (*mmod_done) (void);
+ int (*mmod_in_rule) (struct iphdr *, __u16 *);
+ int (*mmod_in_update) (struct iphdr *, struct ip_masq *);
+ struct ip_masq * (*mmod_in_create) (struct iphdr *, __u16 *, __u32);
+ int (*mmod_out_rule) (struct iphdr *, __u16 *);
+ int (*mmod_out_update) (struct iphdr *, __u16 *, struct ip_masq *);
+ struct ip_masq * (*mmod_out_create) (struct iphdr *, __u16 *, __u32);
+};
+
+/*
+ * Service routines (called from ip_masq.c)
+ */
+int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp);
+int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
+
+int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp);
+int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
+
+extern int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *, int len);
+
+/*
+ * ip_masq_mod registration functions
+ */
+extern int register_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod);
+
+/*
+ * Utility ...
+ */
+static __inline__ void ip_masq_mod_dec_nent(struct ip_masq_mod *mmod)
+{
+ if (atomic_dec_and_test(&mmod->mmod_nent)) {
+ ip_masq_mod_lkp_unlink(mmod);
+ }
+}
+static __inline__ void ip_masq_mod_inc_nent(struct ip_masq_mod *mmod)
+{
+ atomic_inc(&mmod->mmod_nent);
+ if (atomic_read(&mmod->mmod_nent)==1)
+ ip_masq_mod_lkp_link(mmod);
+}
+
+#endif /* __KERNEL__ */
diff --git a/include/net/ip_portfw.h b/include/net/ip_portfw.h
new file mode 100644
index 000000000..f2b51ea1c
--- /dev/null
+++ b/include/net/ip_portfw.h
@@ -0,0 +1,29 @@
+#ifndef _IP_PORTFW_H
+#define _IP_PORTFW_H
+
+#include <linux/types.h>
+
+#define IP_PORTFW_PORT_MIN 1
+#define IP_PORTFW_PORT_MAX 60999
+
+#ifdef __KERNEL__
+struct ip_portfw {
+ struct list_head list;
+ __u32 laddr, raddr;
+ __u16 lport, rport;
+ atomic_t pref_cnt; /* pref "counter" down to 0 */
+ int pref; /* user set pref */
+};
+extern int ip_portfw_init(void);
+
+#endif /* __KERNEL__ */
+
+struct ip_portfw_edits {
+ __u16 protocol; /* Which protocol are we talking? */
+ __u32 laddr, raddr; /* Remote address */
+ __u16 lport, rport; /* Local and remote port */
+ __u16 dummy; /* Make up to multiple of 4 */
+ int pref; /* Preference value */
+};
+
+#endif
diff --git a/include/net/llc.h b/include/net/llc.h
index 37abe50af..654a658d7 100644
--- a/include/net/llc.h
+++ b/include/net/llc.h
@@ -13,6 +13,7 @@ struct llc_struct
{
char eye[4]; /* To recognize llc area in dump */
int retry_count; /* LLC link state variables */
+ unsigned char name[9]; /* name of this llc instance */
unsigned char s_flag;
unsigned char p_flag;
unsigned char f_flag;
@@ -68,9 +69,7 @@ struct llc_struct
char * client_data; /* Pointer to clients context */
unsigned char local_sap;
unsigned char remote_sap ;
- char remote_mac[MAX_ADDR_LEN]; /* MAC address of remote session partner */
- int remote_mac_len; /* Actual length of mac address */
- int mac_offset; /* Source mac offset in skb */
+ char remote_mac[MAX_ADDR_LEN]; /* MAC address of remote session partner */
struct device *dev; /* Device we are attached to */
unsigned char llc_mode; /* See doc 7.1 on p70 */
@@ -132,3 +131,5 @@ void llc_test_request(llcptr lp, int data_len, char *pdu_data);
int register_cl2llc_client(llcptr llc, const char *device, void (*ops)(llcptr), u8 *rmac, u8 ssap, u8 dsap);
void unregister_cl2llc_client(llcptr lp);
+int llc_mac_data_indicate(llcptr lp, struct sk_buff *skb );
+
diff --git a/include/net/tcp.h b/include/net/tcp.h
index f47a273d0..39c1b1f70 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -181,6 +181,9 @@ static __inline__ void tcp_sk_unbindify(struct sock *sk)
* to be no checksum */
#define TCP_SYNACK_PERIOD (HZ/2)
+#define TCP_QUICK_TRIES 8 /* How often we try to retransmit, until
+ * we tell the LL layer that it is something
+ * wrong (e.g. that it can expire redirects) */
/*
* TCP option
@@ -462,8 +465,6 @@ extern int tcp_chkaddr(struct sk_buff *);
/* tcp_timer.c */
#define tcp_reset_msl_timer(x,y,z) net_reset_timer(x,y,z)
extern void tcp_reset_xmit_timer(struct sock *, int, unsigned long);
-extern void tcp_clear_xmit_timer(struct sock *, int);
-extern int tcp_timer_is_set(struct sock *, int);
extern void tcp_init_xmit_timers(struct sock *);
extern void tcp_clear_xmit_timers(struct sock *);
@@ -744,4 +745,49 @@ extern __inline__ void tcp_dec_slow_timer(int timer)
atomic_dec(&slt->count);
}
+extern const char timer_bug_msg[];
+
+static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct timer_list *timer;
+
+ switch (what) {
+ case TIME_RETRANS:
+ timer = &tp->retransmit_timer;
+ break;
+ case TIME_DACK:
+ timer = &tp->delack_timer;
+ break;
+ case TIME_PROBE0:
+ timer = &tp->probe_timer;
+ break;
+ default:
+ printk(timer_bug_msg);
+ return;
+ };
+ del_timer(timer);
+}
+
+static inline int tcp_timer_is_set(struct sock *sk, int what)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ switch (what) {
+ case TIME_RETRANS:
+ return tp->retransmit_timer.next != NULL;
+ break;
+ case TIME_DACK:
+ return tp->delack_timer.next != NULL;
+ break;
+ case TIME_PROBE0:
+ return tp->probe_timer.next != NULL;
+ break;
+ default:
+ printk(timer_bug_msg);
+ };
+ return 0;
+}
+
+
#endif /* _TCP_H */
diff --git a/init/main.c b/init/main.c
index 3f40f8e90..a509f5cbe 100644
--- a/init/main.c
+++ b/init/main.c
@@ -109,6 +109,9 @@ extern void com90xx_setup(char *str, int *ints);
extern void decnet_setup(char *str, int *ints);
#endif
extern void xd_setup(char *str, int *ints);
+#ifdef CONFIG_BLK_DEV_IDE
+extern void ide_setup(char *);
+#endif
#ifdef CONFIG_BLK_DEV_EZ
extern void ez_setup(char *str, int *ints);
#endif
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index c9cf990e2..a66acd361 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -202,6 +202,7 @@ EXPORT_SYMBOL(put_cached_page);
EXPORT_SYMBOL(prune_dcache);
EXPORT_SYMBOL(shrink_dcache_sb);
EXPORT_SYMBOL(shrink_dcache_parent);
+EXPORT_SYMBOL(find_inode_number);
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL(do_nfsservctl);
@@ -239,6 +240,7 @@ EXPORT_SYMBOL(make_request);
EXPORT_SYMBOL(tq_disk);
EXPORT_SYMBOL(efind_buffer);
EXPORT_SYMBOL(init_buffer);
+EXPORT_SYMBOL(max_sectors);
/* tty routines */
EXPORT_SYMBOL(tty_hangup);
diff --git a/kernel/printk.c b/kernel/printk.c
index c67c4d748..91bc771f2 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -109,7 +109,7 @@ __initfunc(void console_setup(char *str, int *ints))
*/
asmlinkage int sys_syslog(int type, char * buf, int len)
{
- unsigned long i, j, count;
+ unsigned long i, j, count, flags;
int do_clear = 0;
char c;
int error = -EPERM;
@@ -170,12 +170,19 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
error = verify_area(VERIFY_WRITE,buf,len);
if (error)
goto out;
+ /*
+ * The logged_chars, log_start, and log_size values may
+ * change from an interrupt, so we disable interrupts.
+ */
+ __save_flags(flags);
+ __cli();
count = len;
if (count > LOG_BUF_LEN)
count = LOG_BUF_LEN;
if (count > logged_chars)
count = logged_chars;
j = log_start + log_size - count;
+ __restore_flags(flags);
for (i = 0; i < count; i++) {
c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
__put_user(c, buf++);
diff --git a/kernel/signal.c b/kernel/signal.c
index 03e64eed6..25168d989 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -118,14 +118,15 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
case 2: if ((x = s[0] &~ m[0]) != 0)
sig = 1;
- else if ((x = s[1] &~ m[0]) != 0)
+ else if ((x = s[1] &~ m[1]) != 0)
sig = _NSIG_BPW + 1;
else
break;
sig += ffz(~x);
break;
- case 1: if ((x = *s &~ *m) != 0) sig = ffz(~x) + 1;
+ case 1: if ((x = *s &~ *m) != 0)
+ sig = ffz(~x) + 1;
break;
}
diff --git a/net/Config.in b/net/Config.in
index e1c9487bf..5a5964e34 100644
--- a/net/Config.in
+++ b/net/Config.in
@@ -16,7 +16,7 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then
fi
fi
bool 'Network aliasing' CONFIG_NET_ALIAS
-tristate 'BSD Unix domain sockets' CONFIG_UNIX
+tristate 'Unix domain sockets' CONFIG_UNIX
bool 'TCP/IP networking' CONFIG_INET
if [ "$CONFIG_INET" = "y" ]; then
source net/ipv4/Config.in
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 9574da96c..335f17e16 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -56,7 +56,7 @@
#include <linux/if_ether.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
-/*#include <linux/inetdevice.h> -- coming soon */
+#include <linux/inetdevice.h>
#include <linux/route.h>
#include <linux/inet.h>
#include <linux/etherdevice.h>
@@ -1843,11 +1843,9 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
case SIOCGIFMTU:
case SIOCGIFCONF:
case SIOCADDMULTI:
- case SIOCDELMULTI:
+ case SIOCDELMULTI:
case SIOCGIFCOUNT:
-#if 0 /* Also coming in the IP merge */
case SIOCGIFINDEX:
-#endif
case SIOCGIFNAME:
return ((dev_ioctl(cmd,(void *) arg)));
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 10aa7a4cc..bff328b19 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -13,6 +13,7 @@
* csum_..._fromiovecend.
* Andi Kleen : fixed error handling for 2.1
* Alexey Kuznetsov: 2.1 optimisations
+ * Andi Kleen : Fix csum*fromiovecend for IPv6.
*/
@@ -196,7 +197,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
int csum_partial_copy_fromiovecend(unsigned char *kdata,
struct iovec *iov, int offset,
- int len, int *csump)
+ unsigned int len, int *csump)
{
int partial_cnt = 0;
int err = 0;
@@ -238,7 +239,15 @@ int csum_partial_copy_fromiovecend(unsigned char *kdata,
while (len>0)
{
u8 *base = iov->iov_base;
- int copy = min(len, iov->iov_len);
+ unsigned int copy = min(len, iov->iov_len);
+
+ /* FIXME: more sanity checking is needed here, because
+ * the iovs are copied from the user.
+ */
+ if (base == NULL) {
+ printk(KERN_DEBUG "%s: iov too short\n",current->comm);
+ return -EINVAL;
+ }
/* There is a remnant from previous iov. */
if (partial_cnt)
@@ -277,6 +286,9 @@ int csum_partial_copy_fromiovecend(unsigned char *kdata,
}
}
+ if (copy == 0)
+ break;
+
csum = csum_partial_copy_from_user(base, kdata, copy, csum, &err);
len -= copy + partial_cnt;
kdata += copy + partial_cnt;
diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in
index ea50576ab..2f057ab4a 100644
--- a/net/ipv4/Config.in
+++ b/net/ipv4/Config.in
@@ -36,6 +36,12 @@ bool 'IP: accounting' CONFIG_IP_ACCT
bool 'IP: masquerading' CONFIG_IP_MASQUERADE
if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
comment 'Protocol-specific masquerading support will be built as modules.'
+ bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
+ comment 'Protocol-specific masquerading support will be built as modules.'
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
+ tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+ fi
fi
bool 'IP: optimize as router not host' CONFIG_IP_ROUTER
tristate 'IP: tunneling' CONFIG_NET_IPIP
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 759def7ea..10f4c5e7c 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -56,8 +56,26 @@ else
endif
ifeq ($(CONFIG_IP_MASQUERADE),y)
-IPV4X_OBJS += ip_masq.o ip_masq_app.o
+IPV4X_OBJS += ip_masq.o ip_masq_mod.o ip_masq_app.o
+
+ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y)
+IPV4_OBJS += ip_masq_autofw.o
+else
+ ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m)
+ M_OBJS += ip_masq_autofw.o
+ endif
+endif
+
+ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y)
+IPV4_OBJS += ip_masq_portfw.o
+else
+ ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m)
+ M_OBJS += ip_masq_portfw.o
+ endif
+endif
+
M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o
+M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o
endif
ifeq ($(CONFIG_SYN_COOKIES),y)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 26cc21977..58bb4174a 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1,6 +1,6 @@
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.56 1997/11/24 12:51:47 freitag Exp $
+ * Version: $Id: arp.c,v 1.3 1997/12/16 05:37:34 ralf Exp $
*
* Copyright (C) 1994 by Florian La Roche
*
@@ -1532,7 +1532,8 @@ int arp_req_set(struct arpreq *r, struct device * dev)
int err;
if ((r->arp_flags & ATF_PERM) && !(r->arp_flags & ATF_COM))
- return -EINVAL;
+ r->arp_flags |= ATF_COM;
+
err = ip_route_output(&rt, ip, 0, 1, dev ? dev->ifindex : 0);
if (err)
return err;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 16d72fcd2..8775c43bf 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -259,7 +259,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
if (copy_from_user(&r, arg, sizeof(struct rtentry)))
return -EFAULT;
rtnl_lock();
- err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, arg);
+ err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
if (err == 0) {
if (cmd == SIOCDELRT) {
struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index e66efde90..77d96acf9 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@cymru.net>
*
- * Version: $Id: icmp.c,v 1.35 1997/10/19 18:17:13 freitag Exp $
+ * Version: $Id: icmp.c,v 1.3 1997/12/16 05:37:35 ralf Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -44,7 +44,7 @@
* and moved all kfree_skb() up to
* icmp_rcv.
* Andi Kleen : Move the rate limit bookkeeping
- * into the dest entry and use a tocken
+ * into the dest entry and use a token
* bucket filter (thanks to ANK). Make
* the rates sysctl configurable.
*
@@ -549,7 +549,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info)
/* XXX: use a more aggressive expire for routes created by
* this call (not longer than the rate limit timeout).
* It could be also worthwhile to not put them into ipv4
- * fast routing cache at first.
+ * fast routing cache at first. Otherwise an attacker can
+ * grow the routing table.
*/
if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
return;
@@ -1021,8 +1022,11 @@ static unsigned long dummy;
/*
* Configurable rate limits.
- * Send at most one packets per time.
* Someone should check if these default values are correct.
+ * Note that these values interact with the routing cache GC timeout.
+ * If you chose them too high they won't take effect, because the
+ * dst_entry gets expired too early. The same should happen when
+ * the cache grows too big.
*/
int sysctl_icmp_sourcequench_time = 1*HZ;
int sysctl_icmp_destunreach_time = 1*HZ;
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 8f48894a4..7010e3a30 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -5,7 +5,7 @@
*
* The IP forwarding functionality.
*
- * Version: $Id: ip_forward.c,v 1.32 1997/10/24 17:16:06 kuznet Exp $
+ * Version: $Id: ip_forward.c,v 1.2 1997/12/16 05:37:36 ralf Exp $
*
* Authors: see ip.c
*
@@ -175,7 +175,16 @@ int ip_forward(struct sk_buff *skb)
* and skip the firewall checks
*/
if (iph->protocol == IPPROTO_ICMP) {
- if ((fw_res = ip_fw_masq_icmp(&skb)) < 0) {
+ __u32 maddr;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+#define icmph ((struct icmphdr *)((char *)iph + (iph->ihl<<2)))
+ if ((icmph->type==ICMP_DEST_UNREACH)||
+ (icmph->type==ICMP_SOURCE_QUENCH)||
+ (icmph->type==ICMP_TIME_EXCEEDED))
+ {
+#endif
+ maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+ if (fw_res = ip_fw_masq_icmp(&skb, maddr) < 0) {
kfree_skb(skb, FREE_READ);
return -1;
}
@@ -183,6 +192,9 @@ int ip_forward(struct sk_buff *skb)
if (fw_res)
/* ICMP matched - skip firewall */
goto skip_call_fw_firewall;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ }
+#endif
}
if (rt->rt_flags&RTCF_MASQ)
goto skip_call_fw_firewall;
@@ -225,6 +237,12 @@ skip_call_fw_firewall:
if (ip_fw_masquerade(&skb, maddr) < 0) {
kfree_skb(skb, FREE_READ);
return -1;
+ } else {
+ /*
+ * Masquerader may have changed skb
+ */
+ iph = skb->nh.iph;
+ opt = &(IPCB(skb)->opt);
}
}
#endif
diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c
index 8c300e155..dc367a289 100644
--- a/net/ipv4/ip_masq.c
+++ b/net/ipv4/ip_masq.c
@@ -4,6 +4,9 @@
*
* Copyright (c) 1994 Pauline Middelink
*
+ * Version: @(#)ip_masq.c 0.12 97/11/30
+ *
+ *
* See ip_fw.c for original log
*
* Fixes:
@@ -12,10 +15,24 @@
* Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport
* Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted
* Juan Jose Ciarlante : Added NO_ADDR status flag.
+ * Richard Lynch : Added IP Autoforward
* Nigel Metheringham : Added ICMP handling for demasquerade
* Nigel Metheringham : Checksum checking of masqueraded data
* Nigel Metheringham : Better handling of timeouts of TCP conns
- *
+ * Delian Delchev : Added support for ICMP requests and replys
+ * Nigel Metheringham : ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional
+ * Juan Jose Ciarlante : re-assign maddr if no packet received from outside
+ * Juan Jose Ciarlante : ported to 2.1 tree
+ * Juan Jose Ciarlante : reworked control connections
+ * Steven Clarke : Added Port Forwarding
+ * Juan Jose Ciarlante : Just ONE ip_masq_new (!)
+ * Juan Jose Ciarlante : IP masq modules support
+ * Juan Jose Ciarlante : don't go into search loop if mport specified
+ * Juan Jose Ciarlante : locking
+ * Steven Clarke : IP_MASQ_S_xx state design
+ * Juan Jose Ciarlante : IP_MASQ_S state implementation
+ * Juan Jose Ciarlante : xx_get() clears timer, _put() inserts it
+ *
*
*/
@@ -38,21 +55,252 @@
#include <net/udp.h>
#include <net/checksum.h>
#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+
+#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
+#include <net/ip_autofw.h>
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
+#include <net/ip_portfw.h>
+#endif
+
+
+int sysctl_ip_masq_debug = 0;
+
+/*
+ * Exported wrapper
+ */
+int ip_masq_get_debug_level(void)
+{
+ return sysctl_ip_masq_debug;
+}
+
+/*
+ * Timeout table[state]
+ */
+/* static int masq_timeout_table[IP_MASQ_S_LAST+1] = { */
+static struct ip_masq_timeout_table masq_timeout_table = {
+ ATOMIC_INIT(0), /* refcnt */
+ 0, /* scale */
+ {
+ 30*60*HZ, /* IP_MASQ_S_NONE, */
+ 15*60*HZ, /* IP_MASQ_S_ESTABLISHED, */
+ 2*60*HZ, /* IP_MASQ_S_SYN_SENT, */
+ 1*60*HZ, /* IP_MASQ_S_SYN_RECV, */
+ 2*60*HZ, /* IP_MASQ_S_FIN_WAIT, */
+ 2*60*HZ, /* IP_MASQ_S_TIME_WAIT, */
+ 10*HZ, /* IP_MASQ_S_CLOSE, */
+ 60*HZ, /* IP_MASQ_S_CLOSE_WAIT, */
+ 30*HZ, /* IP_MASQ_S_LAST_ACK, */
+ 2*60*HZ, /* IP_MASQ_S_LISTEN, */
+ 5*60*HZ, /* IP_MASQ_S_UDP, */
+ 1*60*HZ, /* IP_MASQ_S_ICMP, */
+ 2*HZ,/* IP_MASQ_S_LAST */
+ },
+};
+
+#define MASQUERADE_EXPIRE_RETRY masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT]
+
+static const char * state_name_table[IP_MASQ_S_LAST+1] = {
+ "NONE", /* IP_MASQ_S_NONE, */
+ "ESTABLISHED", /* IP_MASQ_S_ESTABLISHED, */
+ "SYN_SENT", /* IP_MASQ_S_SYN_SENT, */
+ "SYN_RECV", /* IP_MASQ_S_SYN_RECV, */
+ "FIN_WAIT", /* IP_MASQ_S_FIN_WAIT, */
+ "TIME_WAIT", /* IP_MASQ_S_TIME_WAIT, */
+ "CLOSE", /* IP_MASQ_S_CLOSE, */
+ "CLOSE_WAIT", /* IP_MASQ_S_CLOSE_WAIT, */
+ "LAST_ACK", /* IP_MASQ_S_LAST_ACK, */
+ "LISTEN", /* IP_MASQ_S_LISTEN, */
+ "UDP", /* IP_MASQ_S_UDP, */
+ "ICMP", /* IP_MASQ_S_ICMP, */
+ "BUG!", /* IP_MASQ_S_LAST */
+};
+
+#define mNO IP_MASQ_S_NONE
+#define mES IP_MASQ_S_ESTABLISHED
+#define mSS IP_MASQ_S_SYN_SENT
+#define mSR IP_MASQ_S_SYN_RECV
+#define mFW IP_MASQ_S_FIN_WAIT
+#define mTW IP_MASQ_S_TIME_WAIT
+#define mCL IP_MASQ_S_CLOSE
+#define mCW IP_MASQ_S_CLOSE_WAIT
+#define mLA IP_MASQ_S_LAST_ACK
+#define mLI IP_MASQ_S_LISTEN
+
+struct masq_tcp_states_t {
+ int next_state[IP_MASQ_S_LAST]; /* should be _LAST_TCP */
+};
+
+static const char * masq_state_name(int state)
+{
+ if (state >= IP_MASQ_S_LAST)
+ return "ERR!";
+ return state_name_table[state];
+}
+
+struct masq_tcp_states_t masq_tcp_states [] = {
+/* INPUT */
+/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */
+/*syn*/ {{mSR, mES, mES, mSR, mSR, mSR, mSR, mSR, mSR, mSR }},
+/*fin*/ {{mCL, mCW, mSS, mTW, mTW, mTW, mCL, mCW, mLA, mLI }},
+/*ack*/ {{mCL, mES, mSS, mSR, mFW, mTW, mCL, mCW, mCL, mLI }},
+/*rst*/ {{mCL, mCL, mCL, mSR, mCL, mCL, mCL, mCL, mLA, mLI }},
+
+/* OUTPUT */
+/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */
+/*syn*/ {{mSS, mES, mSS, mES, mSS, mSS, mSS, mSS, mSS, mLI }},
+/*fin*/ {{mTW, mFW, mSS, mTW, mFW, mTW, mCL, mTW, mLA, mLI }},
+/*ack*/ {{mES, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mES }},
+/*rst*/ {{mCL, mCL, mSS, mCL, mCL, mTW, mCL, mCL, mCL, mCL }},
+};
+
+static __inline__ int masq_tcp_state_idx(struct tcphdr *th, int output)
+{
+ /*
+ * [0-3]: input states, [4-7]: output.
+ */
+ if (output)
+ output=4;
+
+ if (th->rst)
+ return output+3;
+ if (th->syn)
+ return output+0;
+ if (th->fin)
+ return output+1;
+ if (th->ack)
+ return output+2;
+ return -1;
+}
+
+
+
+static int masq_set_state_timeout(struct ip_masq *ms, int state)
+{
+ struct ip_masq_timeout_table *mstim = ms->timeout_table;
+ int scale;
+
+ /*
+ * Use default timeout table if no specific for this entry
+ */
+ if (!mstim)
+ mstim = &masq_timeout_table;
+
+ ms->timeout = mstim->timeout[ms->state=state];
+ scale = mstim->scale;
+
+ if (scale<0)
+ ms->timeout >>= -scale;
+ else if (scale > 0)
+ ms->timeout <<= scale;
+
+ return state;
+}
+
+static int masq_tcp_state(struct ip_masq *ms, int output, struct tcphdr *th)
+{
+ int state_idx;
+ int new_state = IP_MASQ_S_CLOSE;
+
+ if ((state_idx = masq_tcp_state_idx(th, output)) < 0) {
+ IP_MASQ_DEBUG(1, "masq_state_idx(%d)=%d!!!\n",
+ output, state_idx);
+ goto tcp_state_out;
+ }
+
+ new_state = masq_tcp_states[state_idx].next_state[ms->state];
+
+tcp_state_out:
+ if (new_state!=ms->state)
+ IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n",
+ masq_proto_name(ms->protocol),
+ output? "output" : "input ",
+ th->syn? 'S' : '.',
+ th->fin? 'F' : '.',
+ th->ack? 'A' : '.',
+ th->rst? 'R' : '.',
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ masq_state_name(ms->state),
+ masq_state_name(new_state));
+ return masq_set_state_timeout(ms, new_state);
+}
+
+
+/*
+ * Handle state transitions
+ */
+static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp)
+{
+ struct tcphdr *th = tp;
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return masq_set_state_timeout(ms, IP_MASQ_S_ICMP);
+ case IPPROTO_UDP:
+ return masq_set_state_timeout(ms, IP_MASQ_S_UDP);
+ case IPPROTO_TCP:
+ return masq_tcp_state(ms, output, th);
+ }
+ return -1;
+}
+
+/*
+ * Moves tunnel to listen state
+ */
+int ip_masq_listen(struct ip_masq *ms)
+{
+ masq_set_state_timeout(ms, IP_MASQ_S_LISTEN);
+ return ms->timeout;
+}
#define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */
+/*
+ * Dynamic address rewriting
+ */
+extern int sysctl_ip_dynaddr;
+
/*
- * Implement IP packet masquerading
+ * Lookup lock
*/
+static struct wait_queue *masq_wait;
+atomic_t __ip_masq_lock = ATOMIC_INIT(0);
-static const char *strProt[] = {"UDP","TCP"};
-static __inline__ const char * masq_proto_name(unsigned proto)
+/*
+ * Implement IP packet masquerading
+ */
+
+/*
+ * Converts an ICMP reply code into the equivalent request code
+ */
+static __inline__ const __u8 icmp_type_request(__u8 type)
{
- return strProt[proto==IPPROTO_TCP];
+ switch (type)
+ {
+ case ICMP_ECHOREPLY: return ICMP_ECHO; break;
+ case ICMP_TIMESTAMPREPLY: return ICMP_TIMESTAMP; break;
+ case ICMP_INFO_REPLY: return ICMP_INFO_REQUEST; break;
+ case ICMP_ADDRESSREPLY: return ICMP_ADDRESS; break;
+ default: return (255); break;
+ }
}
/*
+ * Helper macros - attempt to make code clearer!
+ */
+
+/* ID used in ICMP lookups */
+#define icmp_id(icmph) ((icmph->un).echo.id)
+/* (port) hash value using in ICMP lookups for requests */
+#define icmp_hv_req(icmph) ((__u16)(icmph->code+(__u16)(icmph->type<<8)))
+/* (port) hash value using in ICMP lookups for replies */
+#define icmp_hv_rep(icmph) ((__u16)(icmph->code+(__u16)(icmp_type_request(icmph->type)<<8)))
+
+/*
* Last masq_port number in use.
* Will cycle in MASQ_PORT boundaries.
*/
@@ -68,18 +316,38 @@ static __u16 masq_port = PORT_MASQ_BEGIN;
* Greater values could lower MASQ_EXPIRATION setting as a way to
* manage 'masq_entries resource'.
*
+ * By default we will reuse masq.port iff (output) connection
+ * (5-upla) if not duplicated.
+ * This may break midentd and others ...
*/
-int ip_masq_free_ports[2] = {
- PORT_MASQ_END - PORT_MASQ_BEGIN, /* UDP */
- PORT_MASQ_END - PORT_MASQ_BEGIN /* TCP */
+#ifdef CONFIG_IP_MASQ_NREUSE
+#define PORT_MASQ_MUL 1
+#else
+#define PORT_MASQ_MUL 10
+#endif
+
+atomic_t ip_masq_free_ports[3] = {
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */
};
+EXPORT_SYMBOL(ip_masq_get_debug_level);
EXPORT_SYMBOL(ip_masq_new);
+EXPORT_SYMBOL(ip_masq_listen);
+/*
EXPORT_SYMBOL(ip_masq_set_expire);
+*/
EXPORT_SYMBOL(ip_masq_free_ports);
EXPORT_SYMBOL(ip_masq_expire);
-EXPORT_SYMBOL(ip_masq_out_get_2);
+EXPORT_SYMBOL(ip_masq_out_get);
+EXPORT_SYMBOL(ip_masq_in_get);
+EXPORT_SYMBOL(ip_masq_put);
+EXPORT_SYMBOL(ip_masq_control_add);
+EXPORT_SYMBOL(ip_masq_control_del);
+EXPORT_SYMBOL(ip_masq_control_get);
+EXPORT_SYMBOL(__ip_masq_lock);
/*
* 2 ip_masq hash tables: for input and output pkts lookups.
@@ -100,12 +368,29 @@ static struct ip_fw_masq ip_masq_dummy = {
struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
+
/*
- * Returns hash value
+ * Set masq expiration (deletion) and adds timer,
+ * if timeout==0 cancel expiration.
+ * Warning: it does not check/delete previous timer!
*/
-static __inline__ unsigned
+void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
+{
+ if (tout) {
+ ms->timer.expires = jiffies+tout;
+ add_timer(&ms->timer);
+ } else {
+ del_timer(&ms->timer);
+ }
+}
+
+/*
+ * Returns hash value
+ */
+
+static __inline__ unsigned
ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
{
return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1);
@@ -117,13 +402,13 @@ ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
* returns bool success.
*/
-static __inline__ int
-ip_masq_hash(struct ip_masq *ms)
+static int ip_masq_hash(struct ip_masq *ms)
{
unsigned hash;
if (ms->flags & IP_MASQ_F_HASHED) {
- printk(KERN_INFO "ip_masq_hash(): request for already hashed\n");
+ IP_MASQ_ERR( "ip_masq_hash(): request for already hashed, called from %p\n",
+ __builtin_return_address(0));
return 0;
}
/*
@@ -131,6 +416,7 @@ ip_masq_hash(struct ip_masq *ms)
*/
hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
ms->m_link = ip_masq_m_tab[hash];
+ atomic_inc(&ms->refcnt);
ip_masq_m_tab[hash] = ms;
/*
@@ -138,6 +424,7 @@ ip_masq_hash(struct ip_masq *ms)
*/
hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
ms->s_link = ip_masq_s_tab[hash];
+ atomic_inc(&ms->refcnt);
ip_masq_s_tab[hash] = ms;
@@ -151,12 +438,13 @@ ip_masq_hash(struct ip_masq *ms)
* returns bool success.
*/
-static __inline__ int ip_masq_unhash(struct ip_masq *ms)
+static int ip_masq_unhash(struct ip_masq *ms)
{
unsigned hash;
struct ip_masq ** ms_p;
if (!(ms->flags & IP_MASQ_F_HASHED)) {
- printk(KERN_INFO "ip_masq_unhash(): request for unhash flagged\n");
+ IP_MASQ_ERR( "ip_masq_unhash(): request for unhash flagged, called from %p\n",
+ __builtin_return_address(0));
return 0;
}
/*
@@ -165,16 +453,19 @@ static __inline__ int ip_masq_unhash(struct ip_masq *ms)
hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link)
if (ms == (*ms_p)) {
- *ms_p = ms->m_link;
+ atomic_dec(&ms->refcnt);
+ *ms_p = ms->m_link;
break;
}
+
/*
* UNhash by s{addr,port}
*/
hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link)
if (ms == (*ms_p)) {
- *ms_p = ms->s_link;
+ atomic_dec(&ms->refcnt);
+ *ms_p = ms->s_link;
break;
}
@@ -183,40 +474,14 @@ static __inline__ int ip_masq_unhash(struct ip_masq *ms)
}
/*
- * Returns ip_masq associated with addresses found in iph.
- * called for pkts coming from outside-to-INside the firewall
- *
- * NB. Cannot check destination address, just for the incoming port.
- * reason: archie.doc.ac.uk has 6 interfaces, you send to
- * phoenix and get a reply from any other interface(==dst)!
- *
- * [Only for UDP] - AC
- */
-
-struct ip_masq *
-ip_masq_in_get(struct iphdr *iph)
-{
- __u16 *portptr;
- int protocol;
- __u32 s_addr, d_addr;
- __u16 s_port, d_port;
-
- portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- protocol = iph->protocol;
- s_addr = iph->saddr;
- s_port = portptr[0];
- d_addr = iph->daddr;
- d_port = portptr[1];
-
- return ip_masq_in_get_2(protocol, s_addr, s_port, d_addr, d_port);
-}
-
-/*
* Returns ip_masq associated with supplied parameters, either
* broken out of the ip/tcp headers or directly supplied for those
* pathological protocols with address/port in the data stream
* (ftp, irc). addresses and ports are in network order.
- * called for pkts coming from INside-to-outside the firewall.
+ * called for pkts coming from OUTside-to-INside the firewall.
+ *
+ * s_addr, s_port: pkt source address (foreign host)
+ * d_addr, d_port: pkt dest address (firewall)
*
* NB. Cannot check destination address, just for the incoming port.
* reason: archie.doc.ac.uk has 6 interfaces, you send to
@@ -225,44 +490,39 @@ ip_masq_in_get(struct iphdr *iph)
* [Only for UDP] - AC
*/
-struct ip_masq *
-ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
{
unsigned hash;
- struct ip_masq *ms;
+ struct ip_masq *ms = NULL;
+
+ ip_masq_lock(&__ip_masq_lock, 0);
hash = ip_masq_hash_key(protocol, d_addr, d_port);
for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
- if ( protocol==ms->protocol &&
- (s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR) &&
- (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
- (d_addr==ms->maddr && d_port==ms->mport))
- return ms;
+ if (protocol==ms->protocol &&
+ ((s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR)) &&
+ (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
+ (d_addr==ms->maddr && d_port==ms->mport)) {
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
}
- return NULL;
-}
-
-/*
- * Returns ip_masq associated with addresses found in iph.
- * called for pkts coming from inside-to-OUTside the firewall.
- */
-
-struct ip_masq *
-ip_masq_out_get(struct iphdr *iph)
-{
- __u16 *portptr;
- int protocol;
- __u32 s_addr, d_addr;
- __u16 s_port, d_port;
-
- portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- protocol = iph->protocol;
- s_addr = iph->saddr;
- s_port = portptr[0];
- d_addr = iph->daddr;
- d_port = portptr[1];
-
- return ip_masq_out_get_2(protocol, s_addr, s_port, d_addr, d_port);
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX fail\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+out:
+ ip_masq_unlock(&__ip_masq_lock, 0);
+ return ms;
}
/*
@@ -271,66 +531,209 @@ ip_masq_out_get(struct iphdr *iph)
* pathological protocols with address/port in the data stream
* (ftp, irc). addresses and ports are in network order.
* called for pkts coming from inside-to-OUTside the firewall.
+ *
+ * Normally we know the source address and port but for some protocols
+ * (e.g. ftp PASV) we do not know the source port initially. Alas the
+ * hash is keyed on source port so if the first lookup fails then try again
+ * with a zero port, this time only looking at entries marked "no source
+ * port".
*/
-struct ip_masq *
-ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
{
unsigned hash;
- struct ip_masq *ms;
+ struct ip_masq *ms = NULL;
+ /*
+ * Check for "full" addressed entries
+ */
hash = ip_masq_hash_key(protocol, s_addr, s_port);
+
+ ip_masq_lock(&__ip_masq_lock, 0);
+
for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
if (protocol == ms->protocol &&
s_addr == ms->saddr && s_port == ms->sport &&
- d_addr == ms->daddr && d_port == ms->dport )
- return ms;
+ d_addr == ms->daddr && d_port == ms->dport ) {
+ IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+
}
- return NULL;
+ /*
+ * Check for NO_SPORT entries
+ */
+ hash = ip_masq_hash_key(protocol, s_addr, 0);
+ for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
+ if (ms->flags & IP_MASQ_F_NO_SPORT &&
+ protocol == ms->protocol &&
+ s_addr == ms->saddr &&
+ d_addr == ms->daddr && d_port == ms->dport ) {
+ IP_MASQ_DEBUG(2, "lk/out2 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
+ IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX fail\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+out:
+ ip_masq_unlock(&__ip_masq_lock, 0);
+ return ms;
}
+#ifdef CONFIG_IP_MASQUERADE_NREUSE
/*
* Returns ip_masq for given proto,m_addr,m_port.
* called by allocation routine to find an unused m_port.
*/
-struct ip_masq *
-ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
+static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
{
unsigned hash;
- struct ip_masq *ms;
+ struct ip_masq *ms = NULL;
hash = ip_masq_hash_key(protocol, m_addr, m_port);
+
+ ip_masq_lock(&__ip_masq_lock, 0);
+
for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
if ( protocol==ms->protocol &&
- (m_addr==ms->maddr && m_port==ms->mport))
- return ms;
+ (m_addr==ms->maddr && m_port==ms->mport)) {
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
}
- return NULL;
+
+out:
+ ip_masq_unlock(&__ip_masq_lock, 0);
+ return ms;
+}
+#endif
+
+struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ struct ip_masq *ms;
+ ms = __ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port);
+ if (ms)
+ __ip_masq_set_expire(ms, 0);
+ return ms;
+}
+
+struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ struct ip_masq *ms;
+ ms = __ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port);
+ if (ms)
+ __ip_masq_set_expire(ms, 0);
+ return ms;
+}
+
+static __inline__ void __ip_masq_put(struct ip_masq *ms)
+{
+ atomic_dec(&ms->refcnt);
+}
+
+void ip_masq_put(struct ip_masq *ms)
+{
+ /*
+ * Decrement refcnt
+ */
+ __ip_masq_put(ms);
+
+ /*
+ * if refcnt==2 (2 hashes)
+ */
+ if (atomic_read(&ms->refcnt)==2) {
+ __ip_masq_set_expire(ms, ms->timeout);
+ } else {
+ IP_MASQ_DEBUG(0, "did not set timer with refcnt=%d, called from %p\n",
+ atomic_read(&ms->refcnt),
+ __builtin_return_address(0));
+ }
}
static void masq_expire(unsigned long data)
{
struct ip_masq *ms = (struct ip_masq *)data;
- unsigned long flags;
+ ms->timeout = MASQUERADE_EXPIRE_RETRY;
+
+ /*
+ * hey, I'm using it
+ */
+ atomic_inc(&ms->refcnt);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Masqueraded %s %lX:%X expired\n",
+ IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n",
masq_proto_name(ms->protocol),
ntohl(ms->saddr),ntohs(ms->sport));
-#endif
- save_flags(flags);
- cli();
+ ip_masq_lock(&__ip_masq_lock, 1);
+
+ /*
+ * Already locked, do bounce ...
+ */
+ if (ip_masq_nlocks(&__ip_masq_lock) != 1) {
+ goto masq_expire_later;
+ }
+
+ /*
+ * do I control anybody?
+ */
+ if (atomic_read(&ms->n_control))
+ goto masq_expire_later;
+
+ /*
+ * does anybody controls me?
+ */
+
+ if (ms->control)
+ ip_masq_control_del(ms);
if (ip_masq_unhash(ms)) {
- ip_masq_free_ports[ms->protocol==IPPROTO_TCP]++;
- ip_masq_unbind_app(ms);
- kfree_s(ms,sizeof(*ms));
+ if (!(ms->flags&IP_MASQ_F_MPORT))
+ atomic_inc(ip_masq_free_ports + masq_proto_num(ms->protocol));
+ ip_masq_unbind_app(ms);
}
- restore_flags(flags);
+ /*
+ * refcnt==1 implies I'm the only one referrer
+ */
+ if (atomic_read(&ms->refcnt) == 1) {
+ kfree_s(ms,sizeof(*ms));
+ goto masq_expire_out;
+ }
+
+masq_expire_later:
+ IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X nlocks-1=%d masq.refcnt-1=%d masq.n_control=%d\n",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ ip_masq_nlocks(&__ip_masq_lock)-1,
+ atomic_read(&ms->refcnt)-1,
+ atomic_read(&ms->n_control));
+
+ ip_masq_put(ms);
+
+masq_expire_out:
+ ip_masq_unlock(&__ip_masq_lock, 1);
}
/*
@@ -339,25 +742,28 @@ static void masq_expire(unsigned long data)
* given boundaries MASQ_BEGIN and MASQ_END.
*/
-struct ip_masq * ip_masq_new(__u32 maddr, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
+struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
{
struct ip_masq *ms, *mst;
- int ports_tried, *free_ports_p;
- unsigned long flags;
+ int ports_tried;
+ atomic_t *free_ports_p = NULL;
static int n_fails = 0;
- free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP];
- if (*free_ports_p == 0) {
- if (++n_fails < 5)
- printk(KERN_ERR "ip_masq_new(proto=%s): no free ports.\n",
- masq_proto_name(proto));
- return NULL;
- }
+ if (masq_proto_num(proto)!=-1 && mport == 0) {
+ free_ports_p = ip_masq_free_ports + masq_proto_num(proto);
+
+ if (atomic_read(free_ports_p) == 0) {
+ if (++n_fails < 5)
+ IP_MASQ_ERR( "ip_masq_new(proto=%s): no free ports.\n",
+ masq_proto_name(proto));
+ return NULL;
+ }
+ }
ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
if (ms == NULL) {
if (++n_fails < 5)
- printk(KERN_ERR "ip_masq_new(proto=%s): no memory available.\n",
+ IP_MASQ_ERR("ip_masq_new(proto=%s): no memory available.\n",
masq_proto_name(proto));
return NULL;
}
@@ -372,73 +778,115 @@ struct ip_masq * ip_masq_new(__u32 maddr, int proto, __u32 saddr, __u16 sport, _
ms->dport = dport;
ms->flags = mflags;
ms->app_data = NULL;
+ ms->control = NULL;
+
+ atomic_set(&ms->n_control,0);
+ atomic_set(&ms->refcnt,0);
- if (proto == IPPROTO_UDP)
+ if (proto == IPPROTO_UDP && !mport)
ms->flags |= IP_MASQ_F_NO_DADDR;
+
/* get masq address from rif */
ms->maddr = maddr;
- for (ports_tried = 0; ports_tried < *free_ports_p; ports_tried++){
- save_flags(flags);
- cli();
+ /*
+ * This flag will allow masq. addr (ms->maddr)
+ * to follow forwarding interface address.
+ */
+ ms->flags |= IP_MASQ_F_NO_REPLY;
+
+ /*
+ * We want a specific mport. Be careful.
+ */
+ if (masq_proto_num(proto) == -1 || mport) {
+ ms->mport = mport;
- /*
- * Try the next available port number
- */
+ /*
+ * Check 5-upla uniqueness
+ */
+ ip_masq_lock(&__ip_masq_lock, 1);
- ms->mport = htons(masq_port++);
- if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
+ mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+ if (mst==NULL) {
+ ms->flags |= IP_MASQ_F_MPORT;
- restore_flags(flags);
+ ip_masq_hash(ms);
+ ip_masq_unlock(&__ip_masq_lock, 1);
- /*
- * lookup to find out if this port is used.
- */
+ ip_masq_bind_app(ms);
+ atomic_inc(&ms->refcnt);
+ masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+ return ms;
+ }
- mst = ip_masq_getbym(proto, ms->maddr, ms->mport);
- if (mst == NULL) {
- save_flags(flags);
- cli();
+ ip_masq_unlock(&__ip_masq_lock, 1);
+ __ip_masq_put(mst);
- if (*free_ports_p == 0) {
- restore_flags(flags);
- break;
- }
- (*free_ports_p)--;
- ip_masq_hash(ms);
+ IP_MASQ_ERR( "Already used connection: %s, %d.%d.%d.%d:%d => %d.%d.%d.%d:%d, called from %p\n",
+ masq_proto_name(proto),
+ NIPQUAD(maddr), ntohs(mport),
+ NIPQUAD(daddr), ntohs(dport),
+ __builtin_return_address(0));
- restore_flags(flags);
- ip_masq_bind_app(ms);
- n_fails = 0;
- return ms;
- }
+ goto mport_nono;
+ }
+
+
+ for (ports_tried = 0;
+ (atomic_read(free_ports_p) && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN)));
+ ports_tried++){
+
+ cli();
+ /*
+ * Try the next available port number
+ */
+ mport = ms->mport = htons(masq_port++);
+ if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
+
+ sti();
+
+ /*
+ * lookup to find out if this connection is used.
+ */
+
+ ip_masq_lock(&__ip_masq_lock, 1);
+
+#ifdef CONFIG_IP_MASQUERADE_NREUSE
+ mst = __ip_masq_getbym(proto, maddr, mport);
+#else
+ mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+#endif
+ if (mst == NULL) {
+
+ if (atomic_read(free_ports_p) == 0) {
+ ip_masq_unlock(&__ip_masq_lock, 1);
+ break;
+ }
+ atomic_dec(free_ports_p);
+ ip_masq_hash(ms);
+ ip_masq_unlock(&__ip_masq_lock, 1);
+
+ ip_masq_bind_app(ms);
+ n_fails = 0;
+ atomic_inc(&ms->refcnt);
+ masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+ return ms;
+ }
+ ip_masq_unlock(&__ip_masq_lock, 1);
+ __ip_masq_put(mst);
}
if (++n_fails < 5)
- printk(KERN_ERR "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
- masq_proto_name(ms->protocol), *free_ports_p);
+ IP_MASQ_ERR( "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
+ masq_proto_name(ms->protocol),
+ atomic_read(free_ports_p));
+mport_nono:
kfree_s(ms, sizeof(*ms));
return NULL;
}
-/*
- * Set masq expiration (deletion) and adds timer,
- * if timeout==0 cancel expiration.
- * Warning: it does not check/delete previous timer!
- */
-
-void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
-{
- if (tout) {
- ms->timer.expires = jiffies+tout;
- add_timer(&ms->timer);
- } else {
- del_timer(&ms->timer);
- }
-}
-
static void recalc_check(struct udphdr *uh, __u32 saddr,
__u32 daddr, int len)
{
@@ -456,7 +904,6 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
__u16 *portptr;
struct ip_masq *ms;
int size;
- unsigned long timeout;
/*
* We can only masquerade protocols with ports...
@@ -464,6 +911,9 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
* We may need to consider masq-ing some ICMP related to masq-ed protocols
*/
+ if (iph->protocol==IPPROTO_ICMP)
+ return (ip_fw_masq_icmp(skb_ptr, maddr));
+
if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
return -1;
@@ -472,31 +922,72 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
*/
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Outgoing %s %lX:%X -> %lX:%X\n",
- masq_proto_name(iph->protocol),
- ntohl(iph->saddr), ntohs(portptr[0]),
- ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
+ IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",
+ masq_proto_name(iph->protocol),
+ ntohl(iph->saddr), ntohs(portptr[0]),
+ ntohl(iph->daddr), ntohs(portptr[1]));
- ms = ip_masq_out_get(iph);
- if (ms!=NULL)
- ip_masq_set_expire(ms,0);
+ ms = ip_masq_out_get_iph(iph);
+ if (ms!=NULL) {
- /*
- * Nope, not found, create a new entry for it
- */
+ /*
+ * If sysctl !=0 and no pkt has been received yet
+ * in this tunnel and routing iface address has changed...
+ * "You are welcome, diald".
+ */
+ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
- if (ms==NULL)
- {
- ms = ip_masq_new(maddr, iph->protocol,
- iph->saddr, portptr[0],
- iph->daddr, portptr[1],
- 0);
+ if (sysctl_ip_dynaddr > 1) {
+ IP_MASQ_INFO( "ip_fw_masquerade(): change masq.addr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(ms->maddr),NIPQUAD(maddr));
+ }
+
+ ip_masq_lock(&__ip_masq_lock, 1);
+
+ ip_masq_unhash(ms);
+ ms->maddr = maddr;
+ ip_masq_hash(ms);
+
+ ip_masq_unlock(&__ip_masq_lock, 1);
+ }
+
+ /*
+ * Set sport if not defined yet (e.g. ftp PASV). Because
+ * masq entries are hashed on sport, unhash with old value
+ * and hash with new.
+ */
+
+ if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
+ ms->flags &= ~IP_MASQ_F_NO_SPORT;
+
+ ip_masq_lock(&__ip_masq_lock, 1);
+
+ ip_masq_unhash(ms);
+ ms->sport = portptr[0];
+ ip_masq_hash(ms); /* hash on new sport */
+
+ ip_masq_unlock(&__ip_masq_lock, 1);
+
+ IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",
+ ntohs(ms->sport));
+ }
+ } else {
+ /*
+ * Nope, not found, create a new entry for it
+ */
+
+ if (!(ms = ip_masq_mod_out_create(iph, portptr, maddr)))
+ ms = ip_masq_new(iph->protocol,
+ maddr, 0,
+ iph->saddr, portptr[0],
+ iph->daddr, portptr[1],
+ 0);
if (ms == NULL)
return -1;
}
+ ip_masq_mod_out_update(iph, portptr, ms);
+
/*
* Change the fragments origin
*/
@@ -527,40 +1018,12 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
* Adjust packet accordingly to protocol
*/
- if (iph->protocol==IPPROTO_UDP)
+ if (iph->protocol == IPPROTO_UDP)
{
- timeout = ip_masq_expire->udp_timeout;
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
- }
- else
- {
- struct tcphdr *th;
- th = (struct tcphdr *)portptr;
-
- /* Set the flags up correctly... */
- if (th->fin)
- {
- ms->flags |= IP_MASQ_F_SAW_FIN_OUT;
- }
-
- if (th->rst)
- {
- ms->flags |= IP_MASQ_F_SAW_RST;
- }
+ } else {
+ struct tcphdr *th = (struct tcphdr *)portptr;
- /*
- * Timeout depends if FIN packet has been seen
- * Very short timeout if RST packet seen.
- */
- if (ms->flags & IP_MASQ_F_SAW_RST)
- {
- timeout = 1;
- }
- else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
- {
- timeout = ip_masq_expire->tcp_fin_timeout;
- }
- else timeout = ip_masq_expire->tcp_timeout;
skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
th->check = 0;
@@ -568,12 +1031,14 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
csum_partial((char *)th, sizeof(*th),
skb->csum));
}
- ip_masq_set_expire(ms, timeout);
- ip_send_check(iph);
- #ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("O-routed from %lX:%X via %lX\n",ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
- #endif
+ ip_send_check(iph);
+
+ IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",
+ ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
+
+ masq_set_state(ms, 1, iph, portptr);
+ ip_masq_put(ms);
return 0;
}
@@ -586,7 +1051,7 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
* Currently handles error types - unreachable, quench, ttl exceeded
*/
-int ip_fw_masq_icmp(struct sk_buff **skb_p)
+int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
{
struct sk_buff *skb = *skb_p;
struct iphdr *iph = skb->nh.iph;
@@ -596,10 +1061,78 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p)
struct ip_masq *ms;
unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Incoming forward ICMP (%d) %lX -> %lX\n",
- icmph->type,
+ IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n",
+ icmph->type, ntohs(icmp_id(icmph)),
ntohl(iph->saddr), ntohl(iph->daddr));
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if ((icmph->type == ICMP_ECHO ) ||
+ (icmph->type == ICMP_TIMESTAMP ) ||
+ (icmph->type == ICMP_INFO_REQUEST ) ||
+ (icmph->type == ICMP_ADDRESS )) {
+
+ IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ ms = ip_masq_out_get(iph->protocol,
+ iph->saddr,
+ icmp_id(icmph),
+ iph->daddr,
+ icmp_hv_req(icmph));
+ if (ms == NULL) {
+ ms = ip_masq_new(iph->protocol,
+ maddr, 0,
+ iph->saddr, icmp_id(icmph),
+ iph->daddr, icmp_hv_req(icmph),
+ 0);
+ if (ms == NULL)
+ return (-1);
+ IP_MASQ_DEBUG(1, "Created new icmp entry\n");
+ }
+ /* Rewrite source address */
+
+ /*
+ * If sysctl !=0 and no pkt has been received yet
+ * in this tunnel and routing iface address has changed...
+ * "You are welcome, diald".
+ */
+ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
+
+ if (sysctl_ip_dynaddr > 1) {
+ IP_MASQ_INFO( "ip_fw_masq_icmp(): change masq.addr %d.%d.%d.%d to %d.%d.%d.%d",
+ NIPQUAD(ms->maddr), NIPQUAD(maddr));
+ }
+
+ ip_masq_lock(&__ip_masq_lock, 1);
+
+ ip_masq_unhash(ms);
+ ms->maddr = maddr;
+ ip_masq_hash(ms);
+
+ ip_masq_unlock(&__ip_masq_lock, 1);
+ }
+
+ iph->saddr = ms->maddr;
+ ip_send_check(iph);
+ /* Rewrite port (id) */
+ (icmph->un).echo.id = ms->mport;
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph, len);
+
+ IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ masq_set_state(ms, 1, iph, icmph);
+ ip_masq_put(ms);
+
+ return 1;
+ }
#endif
/*
@@ -618,6 +1151,59 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p)
/* Now find the contained IP header */
ciph = (struct iphdr *) (icmph + 1);
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if (ciph->protocol == IPPROTO_ICMP) {
+ /*
+ * This section handles ICMP errors for ICMP packets
+ */
+ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph +
+ (ciph->ihl<<2));
+
+
+ IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ ms = __ip_masq_out_get(ciph->protocol,
+ ciph->daddr,
+ icmp_id(cicmph),
+ ciph->saddr,
+ icmp_hv_rep(cicmph));
+
+ if (ms == NULL)
+ return 0;
+
+ /* Now we do real damage to this packet...! */
+ /* First change the source IP address, and recalc checksum */
+ iph->saddr = ms->maddr;
+ ip_send_check(iph);
+
+ /* Now change the *dest* address in the contained IP */
+ ciph->daddr = ms->maddr;
+ __ip_masq_put(ms);
+
+ ip_send_check(ciph);
+
+ /* Change the ID to the masqed one! */
+ (cicmph->un).echo.id = ms->mport;
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ return 1;
+ }
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
/* We are only interested ICMPs generated from TCP or UDP packets */
if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
return 0;
@@ -628,27 +1214,36 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p)
* (but reversed relative to outer IP header!)
*/
pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+#if 0
if (ntohs(pptr[1]) < PORT_MASQ_BEGIN ||
ntohs(pptr[1]) > PORT_MASQ_END)
return 0;
+#endif
/* Ensure the checksum is correct */
if (ip_compute_csum((unsigned char *) icmph, len))
{
/* Failed checksum! */
- printk(KERN_INFO "MASQ: forward ICMP: failed checksum from %s!\n",
- in_ntoa(iph->saddr));
+ IP_MASQ_WARNING( "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
+ NIPQUAD(iph->saddr));
return(-1);
}
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Handling forward ICMP for %lX:%X -> %lX:%X\n",
+
+ IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n",
ntohl(ciph->saddr), ntohs(pptr[0]),
ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
- /* This is pretty much what ip_masq_in_get() does */
- ms = ip_masq_in_get_2(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
+
+#if 0
+ /* This is pretty much what __ip_masq_in_get_iph() does */
+ ms = __ip_masq_in_get(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
+#endif
+ ms = __ip_masq_out_get(ciph->protocol,
+ ciph->daddr,
+ pptr[1],
+ ciph->saddr,
+ pptr[0]);
if (ms == NULL)
return 0;
@@ -664,16 +1259,17 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p)
/* the TCP/UDP dest port - cannot redo check */
pptr[1] = ms->mport;
+ __ip_masq_put(ms);
/* And finally the ICMP checksum */
icmph->checksum = 0;
icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Rewrote forward ICMP to %lX:%X -> %lX:%X\n",
+
+ IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n",
ntohl(ciph->saddr), ntohs(pptr[0]),
ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
+
return 1;
}
@@ -695,22 +1291,133 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
struct ip_masq *ms;
unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Incoming reverse ICMP (%d) %lX -> %lX\n",
- icmph->type,
+
+ IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n",
+ icmph->type, ntohs(icmp_id(icmph)),
ntohl(iph->saddr), ntohl(iph->daddr));
-#endif
- if ((icmph->type != ICMP_DEST_UNREACH) &&
- (icmph->type != ICMP_SOURCE_QUENCH) &&
- (icmph->type != ICMP_TIME_EXCEEDED))
- return 0;
- /* Now find the contained IP header */
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if ((icmph->type == ICMP_ECHOREPLY) ||
+ (icmph->type == ICMP_TIMESTAMPREPLY) ||
+ (icmph->type == ICMP_INFO_REPLY) ||
+ (icmph->type == ICMP_ADDRESSREPLY)) {
+
+ IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type,
+ icmp_type_request(icmph->type));
+
+ ms = ip_masq_in_get(iph->protocol,
+ iph->saddr,
+ icmp_hv_rep(icmph),
+ iph->daddr,
+ icmp_id(icmph));
+ if (ms == NULL)
+ return 0;
+
+ /*
+ * got reply, so clear flag
+ */
+ ms->flags &= ~IP_MASQ_F_NO_REPLY;
+
+ /* Reset source address */
+ iph->daddr = ms->saddr;
+ /* Redo IP header checksum */
+ ip_send_check(iph);
+ /* Set ID to fake port number */
+ (icmph->un).echo.id = ms->sport;
+ /* Reset ICMP checksum and set expiry */
+ icmph->checksum=0;
+ icmph->checksum=ip_compute_csum((unsigned char *)icmph,len);
+
+
+
+ IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ masq_set_state(ms, 0, iph, icmph);
+ ip_masq_put(ms);
+
+ return 1;
+ } else {
+#endif
+ if ((icmph->type != ICMP_DEST_UNREACH) &&
+ (icmph->type != ICMP_SOURCE_QUENCH) &&
+ (icmph->type != ICMP_TIME_EXCEEDED))
+ return 0;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ }
+#endif
+ /*
+ * If we get here we have an ICMP error of one of the above 3 types
+ * Now find the contained IP header
+ */
+
ciph = (struct iphdr *) (icmph + 1);
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if (ciph->protocol == IPPROTO_ICMP) {
+ /*
+ * This section handles ICMP errors for ICMP packets
+ *
+ * First get a new ICMP header structure out of the IP packet
+ */
+ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph +
+ (ciph->ihl<<2));
+
+
+ IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ ms = __ip_masq_in_get(ciph->protocol,
+ ciph->daddr,
+ icmp_hv_req(cicmph),
+ ciph->saddr,
+ icmp_id(cicmph));
+
+ if (ms == NULL)
+ return 0;
+
+ /* Now we do real damage to this packet...! */
+ /* First change the dest IP address, and recalc checksum */
+ iph->daddr = ms->saddr;
+ ip_send_check(iph);
+
+ /* Now change the *source* address in the contained IP */
+ ciph->saddr = ms->saddr;
+ ip_send_check(ciph);
+
+ /* Change the ID to the original one! */
+ (cicmph->un).echo.id = ms->sport;
+ __ip_masq_put(ms);
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ return 1;
+ }
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
/* We are only interested ICMPs generated from TCP or UDP packets */
- if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
+ if ((ciph->protocol != IPPROTO_UDP) &&
+ (ciph->protocol != IPPROTO_TCP))
return 0;
/*
@@ -726,19 +1433,23 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
if (ip_compute_csum((unsigned char *) icmph, len))
{
/* Failed checksum! */
- printk(KERN_INFO "MASQ: reverse ICMP: failed checksum from %s!\n",
- in_ntoa(iph->saddr));
+ IP_MASQ_ERR( "reverse ICMP: failed checksum from %d.%d.%d.%d!\n",
+ NIPQUAD(iph->saddr));
return(-1);
}
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Handling reverse ICMP for %lX:%X -> %lX:%X\n",
+
+ IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n",
ntohl(ciph->saddr), ntohs(pptr[0]),
ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
- /* This is pretty much what ip_masq_in_get() does, except params are wrong way round */
- ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]);
+
+ /* This is pretty much what __ip_masq_in_get_iph() does, except params are wrong way round */
+ ms = __ip_masq_in_get(ciph->protocol,
+ ciph->daddr,
+ pptr[1],
+ ciph->saddr,
+ pptr[0]);
if (ms == NULL)
return 0;
@@ -754,16 +1465,17 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
/* the TCP/UDP source port - cannot redo check */
pptr[0] = ms->sport;
+ __ip_masq_put(ms);
/* And finally the ICMP checksum */
icmph->checksum = 0;
icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Rewrote reverse ICMP to %lX:%X -> %lX:%X\n",
+
+ IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n",
ntohl(ciph->saddr), ntohs(pptr[0]),
ntohl(ciph->daddr), ntohs(pptr[1]));
-#endif
+
return 1;
}
@@ -785,7 +1497,10 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
__u16 *portptr;
struct ip_masq *ms;
unsigned short len;
- unsigned long timeout;
+
+ __u32 maddr;
+
+ maddr = iph->daddr;
switch (iph->protocol) {
case IPPROTO_ICMP:
@@ -794,9 +1509,11 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
case IPPROTO_UDP:
/* Make sure packet is in the masq range */
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
- ntohs(portptr[1]) > PORT_MASQ_END)
+ if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN
+ || ntohs(portptr[1]) > PORT_MASQ_END)
+ && (ip_masq_mod_in_rule(iph, portptr) != 1))
return 0;
+
/* Check that the checksum is OK */
len = ntohs(iph->tot_len) - (iph->ihl * 4);
if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
@@ -811,8 +1528,8 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
iph->protocol, skb->csum))
{
- printk(KERN_INFO "MASQ: failed TCP/UDP checksum from %s!\n",
- in_ntoa(iph->saddr));
+ IP_MASQ_WARNING( "failed TCP/UDP checksum from %d.%d.%d.%d!\n",
+ NIPQUAD(iph->saddr));
return -1;
}
default:
@@ -824,42 +1541,50 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
}
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("Incoming %s %lX:%X -> %lX:%X\n",
+
+ IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n",
masq_proto_name(iph->protocol),
ntohl(iph->saddr), ntohs(portptr[0]),
ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
+
/*
* reroute to original host:port if found...
*/
- ms = ip_masq_in_get(iph);
+ ms = ip_masq_in_get_iph(iph);
+
+ if (!ms)
+ ms = ip_masq_mod_in_create(iph, portptr, maddr);
+
+ ip_masq_mod_in_update(iph, portptr, ms);
if (ms != NULL)
{
- /* Stop the timer ticking.... */
- ip_masq_set_expire(ms,0);
/*
+ * got reply, so clear flag
+ */
+ ms->flags &= ~IP_MASQ_F_NO_REPLY;
+
+ /*
* Set dport if not defined yet.
*/
- if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
+ if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /* && ms->protocol == IPPROTO_TCP ) { */
ms->flags &= ~IP_MASQ_F_NO_DPORT;
ms->dport = portptr[0];
-#if DEBUG_CONFIG_IP_MASQUERADE
- printk("ip_fw_demasquerade(): filled dport=%d\n",
+
+ IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n",
ntohs(ms->dport));
-#endif
+
}
- if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP) {
+ if (ms->flags & IP_MASQ_F_NO_DADDR ) { /* && ms->protocol == IPPROTO_TCP) { */
ms->flags &= ~IP_MASQ_F_NO_DADDR;
ms->daddr = iph->saddr;
-#if DEBUG_CONFIG_IP_MASQUERADE
- printk("ip_fw_demasquerade(): filled daddr=%X\n",
+
+ IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%X\n",
ntohs(ms->daddr));
-#endif
+
}
iph->daddr = ms->saddr;
portptr[1] = ms->sport;
@@ -869,7 +1594,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
* will fix ip_masq and iph ack_seq stuff
*/
- if (ip_masq_app_pkt_in(ms, skb_p) != 0)
+ if (ip_masq_app_pkt_in(ms, skb_p, maddr) != 0)
{
/*
* skb has changed, update pointers.
@@ -886,50 +1611,27 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
* timeouts.
* If a TCP RST is seen collapse the tunnel (by using short timeout)!
*/
- if (iph->protocol==IPPROTO_UDP)
- {
+ if (iph->protocol == IPPROTO_UDP) {
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
- timeout = ip_masq_expire->udp_timeout;
- }
- else
- {
- struct tcphdr *th;
- skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
+ } else {
+ struct tcphdr *th = (struct tcphdr *)portptr;
+ skb->csum = csum_partial((void *)(th + 1),
len - sizeof(struct tcphdr), 0);
- th = (struct tcphdr *) portptr;
+
th->check = 0;
- th->check = tcp_v4_check(th, len, iph->saddr,
- iph->daddr,
+ th->check = tcp_v4_check(th, len, iph->saddr, iph->daddr,
csum_partial((char *)th,
sizeof(*th),
skb->csum));
- /* Check if TCP FIN or RST */
- if (th->fin)
- {
- ms->flags |= IP_MASQ_F_SAW_FIN_IN;
- }
- if (th->rst)
- {
- ms->flags |= IP_MASQ_F_SAW_RST;
- }
-
- /* Now set the timeouts */
- if (ms->flags & IP_MASQ_F_SAW_RST)
- {
- timeout = 1;
- }
- else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
- {
- timeout = ip_masq_expire->tcp_fin_timeout;
- }
- else timeout = ip_masq_expire->tcp_timeout;
}
- ip_masq_set_expire(ms, timeout);
ip_send_check(iph);
-#ifdef DEBUG_CONFIG_IP_MASQUERADE
- printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
-#endif
+
+ IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(portptr[1]));
+
+ masq_set_state (ms, 0, iph, portptr);
+ ip_masq_put(ms);
+
return 1;
}
@@ -937,43 +1639,89 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
return 0;
}
+
+void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms)
+{
+ if (ms->control) {
+ IP_MASQ_ERR( "request control ADD for already controlled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ ip_masq_control_del(ms);
+ }
+ IP_MASQ_DEBUG(1, "ADDing control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->daddr),ntohs(ms->dport),
+ NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+ ms->control = ctl_ms;
+ atomic_inc(&ctl_ms->n_control);
+}
+
+void ip_masq_control_del(struct ip_masq *ms)
+{
+ struct ip_masq *ctl_ms = ms->control;
+ if (!ctl_ms) {
+ IP_MASQ_ERR( "request control DEL for uncontrolled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ return;
+ }
+ IP_MASQ_DEBUG(1, "DELeting control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->daddr),ntohs(ms->dport),
+ NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+ ms->control = NULL;
+ if (atomic_read(&ctl_ms->n_control) == 0) {
+ IP_MASQ_ERR( "BUG control DEL with n=0 : %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ return;
+
+ }
+ atomic_dec(&ctl_ms->n_control);
+}
+
+struct ip_masq * ip_masq_control_get(struct ip_masq *ms)
+{
+ return ms->control;
+}
+
#ifdef CONFIG_PROC_FS
/*
- * /proc/net entry
+ * /proc/net entries
+ * From userspace
*/
-
static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
int length, int unused)
{
off_t pos=0, begin;
struct ip_masq *ms;
- unsigned long flags;
char temp[129];
int idx = 0;
int len=0;
+ ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
if (offset < 128)
{
sprintf(temp,
- "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d)",
- ip_masq_free_ports[0], ip_masq_free_ports[1]);
+ "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d,%d)",
+ atomic_read(ip_masq_free_ports),
+ atomic_read(ip_masq_free_ports+1),
+ atomic_read(ip_masq_free_ports+2));
len = sprintf(buffer, "%-127s\n", temp);
}
pos = 128;
- save_flags(flags);
- cli();
for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
{
- int timer_active;
pos += 128;
if (pos <= offset)
continue;
- timer_active = del_timer(&ms->timer);
- if (!timer_active)
- ms->timer.expires = jiffies;
+ /*
+ * We have locked the tables, no need to del/add timers
+ * nor cli() 8)
+ */
+
sprintf(temp,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %7lu",
masq_proto_name(ms->protocol),
ntohl(ms->saddr), ntohs(ms->sport),
@@ -983,15 +1731,75 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
ms->out_seq.delta,
ms->out_seq.previous_delta,
ms->timer.expires-jiffies);
- if (timer_active)
- add_timer(&ms->timer);
len += sprintf(buffer+len, "%-127s\n", temp);
if(len >= length)
goto done;
}
done:
- restore_flags(flags);
+
+ ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ if(len>length)
+ len = length;
+ return len;
+}
+
+static int ip_masq_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin;
+ struct ip_masq *ms;
+ char temp[129];
+ int idx = 0;
+ int len=0;
+
+ ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
+ if (offset < 128)
+ {
+ sprintf(temp,
+ "Prot SrcIP SPrt DstIP DPrt MAddr MPrt State Ref Ctl Expires (free=%d,%d,%d)",
+ atomic_read(ip_masq_free_ports),
+ atomic_read(ip_masq_free_ports+1),
+ atomic_read(ip_masq_free_ports+2));
+ len = sprintf(buffer, "%-127s\n", temp);
+ }
+ pos = 128;
+
+ for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+ for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
+ {
+ pos += 128;
+ if (pos <= offset)
+ continue;
+
+ /*
+ * We have locked the tables, no need to del/add timers
+ * nor cli() 8)
+ */
+
+ sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3d %3d %7lu",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ ntohl(ms->maddr), ntohs(ms->mport),
+ masq_state_name(ms->state),
+ atomic_read(&ms->refcnt),
+ atomic_read(&ms->n_control),
+ (ms->timer.expires-jiffies)/HZ);
+ len += sprintf(buffer+len, "%-127s\n", temp);
+
+ if(len >= length)
+ goto done;
+ }
+done:
+
+ ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
@@ -1000,21 +1808,51 @@ done:
return len;
}
-static struct proc_dir_entry proc_net_ipmsqhst = {
- PROC_NET_IPMSQHST, 13, "ip_masquerade",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_msqhst_procinfo
-};
#endif
/*
+ * Control from ip_sockglue
+ * From userspace
+ */
+int ip_masq_ctl(int optname, void *arg, int arglen)
+{
+ struct ip_fw_masqctl *mctl = arg;
+ int ret = EINVAL;
+
+ ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+
+ if (1) /* (mctl->mctl_action == IP_MASQ_MOD_CTL) */
+ ret = ip_masq_mod_ctl(optname, mctl, arglen);
+
+ ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+
+ return ret;
+}
+
+/*
* Initialize ip masquerading
*/
__initfunc(int ip_masq_init(void))
{
-#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_ipmsqhst);
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_IPMSQHST, 13, "ip_masquerade",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ip_msqhst_procinfo
+ });
+ proc_net_register(&(struct proc_dir_entry) {
+ 0, 7, "ip_masq",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ip_masq_procinfo
+ });
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
+ ip_autofw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
+ ip_portfw_init();
#endif
ip_masq_app_init();
diff --git a/net/ipv4/ip_masq_app.c b/net/ipv4/ip_masq_app.c
index f03aef04b..814da2aa8 100644
--- a/net/ipv4/ip_masq_app.c
+++ b/net/ipv4/ip_masq_app.c
@@ -39,13 +39,6 @@
#include <linux/proc_fs.h>
#include <net/ip_masq.h>
-static const char *strProt[] = {"UDP","TCP"};
-
-static __inline__ const char * masq_proto_name(unsigned proto)
-{
- return strProt[proto==IPPROTO_TCP];
-}
-
#define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */
#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
@@ -74,7 +67,7 @@ int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 p
unsigned long flags;
unsigned hash;
if (!mapp) {
- printk(KERN_ERR "register_ip_masq_app(): NULL arg\n");
+ IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
return -EINVAL;
}
mapp->type = IP_MASQ_APP_TYPE(proto, port);
@@ -100,14 +93,14 @@ int unregister_ip_masq_app(struct ip_masq_app *mapp)
unsigned hash;
unsigned long flags;
if (!mapp) {
- printk(KERN_ERR "unregister_ip_masq_app(): NULL arg\n");
+ IP_MASQ_ERR("unregister_ip_masq_app(): NULL arg\n");
return -EINVAL;
}
/*
* only allow unregistration if it has no attachments
*/
if (mapp->n_attach) {
- printk(KERN_ERR "unregister_ip_masq_app(): has %d attachments. failed\n",
+ IP_MASQ_ERR("unregister_ip_masq_app(): has %d attachments. failed\n",
mapp->n_attach);
return -EINVAL;
}
@@ -123,7 +116,7 @@ int unregister_ip_masq_app(struct ip_masq_app *mapp)
}
restore_flags(flags);
- printk(KERN_ERR "unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
+ IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
return -EINVAL;
}
@@ -165,7 +158,7 @@ static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
n_at = mapp->n_attach + delta;
if (n_at < 0) {
restore_flags(flags);
- printk(KERN_ERR "ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
+ IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
IP_MASQ_APP_PORT(mapp->type));
return -1;
@@ -183,14 +176,26 @@ static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
{
struct ip_masq_app * mapp;
+
+ if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+ return NULL;
+
mapp = ip_masq_app_get(ms->protocol, ms->dport);
+
+#if 0000
+/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */
+ if (mapp == NULL)
+ mapp = ip_masq_app_get(ms->protocol, ms->sport);
+/* #endif */
+#endif
+
if (mapp != NULL) {
/*
* don't allow binding if already bound
*/
if (ms->app != NULL) {
- printk(KERN_ERR "ip_masq_bind_app() called for already bound object.\n");
+ IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
return ms->app;
}
@@ -209,6 +214,10 @@ int ip_masq_unbind_app(struct ip_masq *ms)
{
struct ip_masq_app * mapp;
mapp = ms->app;
+
+ if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+ return 0;
+
if (mapp != NULL) {
if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
ms->app = NULL;
@@ -236,14 +245,10 @@ static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcp
if (ms_seq->delta || ms_seq->previous_delta) {
if(after(seq,ms_seq->init_seq) ) {
th->seq = htonl(seq + ms_seq->delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
- printk("masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
-#endif
+ IP_MASQ_DEBUG(1, "masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
} else {
th->seq = htonl(seq + ms_seq->previous_delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
- printk("masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
-#endif
+ IP_MASQ_DEBUG(1, "masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
}
}
@@ -269,14 +274,11 @@ static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct
if (ms_seq->delta || ms_seq->previous_delta) {
if(after(ack_seq,ms_seq->init_seq)) {
th->ack_seq = htonl(ack_seq-ms_seq->delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
- printk("masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
-#endif
+ IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
+
} else {
th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
-#if DEBUG_CONFIG_IP_MASQ_APP
- printk("masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
-#endif
+ IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
}
}
@@ -369,7 +371,7 @@ int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
* returns (new - old) skb->len diff.
*/
-int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p)
+int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
{
struct ip_masq_app * mapp;
struct iphdr *iph;
@@ -414,7 +416,7 @@ int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p)
if ( mapp->pkt_in == NULL )
return 0;
- diff = mapp->pkt_in(mapp, ms, skb_p);
+ diff = mapp->pkt_in(mapp, ms, skb_p, maddr);
/*
* Update ip_masq seq stuff if len has changed.
@@ -529,7 +531,7 @@ static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, i
n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
if (n_skb == NULL) {
- printk(KERN_ERR "skb_replace(): no room left (from %p)\n",
+ IP_MASQ_ERR(KERN_ERR "skb_replace(): no room left (from %p)\n",
return_address());
return skb;
@@ -589,9 +591,7 @@ struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf,
if (diff)
{
struct iphdr *iph;
-#if DEBUG_CONFIG_IP_MASQ_APP
- printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len);
-#endif
+ IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len);
/*
* update ip header
*/
diff --git a/net/ipv4/ip_masq_autofw.c b/net/ipv4/ip_masq_autofw.c
new file mode 100644
index 000000000..30493d4cd
--- /dev/null
+++ b/net/ipv4/ip_masq_autofw.c
@@ -0,0 +1,427 @@
+/*
+ * IP_MASQ_AUTOFW auto forwarding module
+ *
+ *
+ * Version: @(#)ip_masq_autofw.c 0.02 97/10/22
+ *
+ * Author: Richard Lynch
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
+ * Juan Jose Ciarlante : modularized
+ * Juan Jose Ciarlante : use GFP_KERNEL when creating entries
+ * Juan Jose Ciarlante : call del_timer() when freeing entries (!)
+ * FIXME:
+ * - implement refcnt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/if.h>
+#include <linux/init.h>
+#include <linux/ip_fw.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <net/ip_autofw.h>
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*
+ * Auto-forwarding table
+ */
+
+static struct ip_autofw * ip_autofw_hosts = NULL;
+static struct ip_masq_mod * mmod_self = NULL;
+
+/*
+ * Check if a masq entry should be created for a packet
+ */
+
+static __inline__ struct ip_autofw * ip_autofw_check_range (__u32 where, __u16 port, __u16 protocol, int reqact)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af) {
+ if (af->type==IP_FWD_RANGE &&
+ port>=af->low &&
+ port<=af->high &&
+ protocol==af->protocol &&
+
+ /*
+ * It's ok to create masq entries after
+ * the timeout if we're in insecure mode
+ */
+ (af->flags & IP_AUTOFW_ACTIVE || !reqact || !(af->flags & IP_AUTOFW_SECURE)) &&
+ (!(af->flags & IP_AUTOFW_SECURE) || af->lastcontact==where || !reqact))
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_port (__u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_PORT && port==af->visible && protocol==af->protocol)
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_direct (__u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_DIRECT && af->low<=port && af->high>=port)
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ void ip_autofw_update_out (__u32 who, __u32 where, __u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_RANGE && af->ctlport==port && af->ctlproto==protocol)
+ {
+ if (af->flags & IP_AUTOFW_USETIME)
+ {
+ if (af->timer.expires)
+ del_timer(&af->timer);
+ af->timer.expires=jiffies+IP_AUTOFW_EXPIRE;
+ add_timer(&af->timer);
+ }
+ af->flags|=IP_AUTOFW_ACTIVE;
+ af->lastcontact=where;
+ af->where=who;
+ }
+ af=af->next;
+ }
+}
+
+#if 0
+static __inline__ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_check_range(where, port,protocol);
+ if (af)
+ {
+ del_timer(&af->timer);
+ af->timer.expires=jiffies+IP_AUTOFW_EXPIRE;
+ add_timer(&af->timer);
+ }
+}
+#endif
+
+
+static __inline__ void ip_autofw_expire(unsigned long data)
+{
+ struct ip_autofw * af;
+ af=(struct ip_autofw *) data;
+ af->flags &= ~IP_AUTOFW_ACTIVE;
+ af->timer.expires=0;
+ af->lastcontact=0;
+ if (af->flags & IP_AUTOFW_SECURE)
+ af->where=0;
+}
+
+
+
+static __inline__ int ip_autofw_add(struct ip_autofw * af)
+{
+ struct ip_autofw * newaf;
+ init_timer(&af->timer);
+ newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL );
+ if ( newaf == NULL )
+ {
+ printk("ip_autofw_add: malloc said no\n");
+ return( ENOMEM );
+ }
+
+ MOD_INC_USE_COUNT;
+
+ memcpy(newaf, af, sizeof(struct ip_autofw));
+ newaf->timer.data = (unsigned long) newaf;
+ newaf->timer.function = ip_autofw_expire;
+ newaf->timer.expires = 0;
+ newaf->lastcontact=0;
+ newaf->next=ip_autofw_hosts;
+ ip_autofw_hosts=newaf;
+ ip_masq_mod_inc_nent(mmod_self);
+ return(0);
+}
+
+static __inline__ int ip_autofw_del(struct ip_autofw * af)
+{
+ struct ip_autofw ** af_p, *curr;
+
+ for (af_p=&ip_autofw_hosts, curr=*af_p; (curr=*af_p); af_p = &(*af_p)->next) {
+ if (af->type == curr->type &&
+ af->low == curr->low &&
+ af->high == curr->high &&
+ af->hidden == curr->hidden &&
+ af->visible == curr->visible &&
+ af->protocol == curr->protocol &&
+ af->where == curr->where &&
+ af->ctlproto == curr->ctlproto &&
+ af->ctlport == curr->ctlport)
+ {
+ ip_masq_mod_dec_nent(mmod_self);
+ *af_p = curr->next;
+ if (af->flags&IP_AUTOFW_ACTIVE)
+ del_timer(&curr->timer);
+ kfree_s(curr,sizeof(struct ip_autofw));
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+ curr=curr->next;
+ }
+ return EINVAL;
+}
+
+static __inline__ int ip_autofw_flush(void)
+{
+ struct ip_autofw * af;
+
+ while (ip_autofw_hosts)
+ {
+ af=ip_autofw_hosts;
+ ip_masq_mod_dec_nent(mmod_self);
+ ip_autofw_hosts=ip_autofw_hosts->next;
+ if (af->flags&IP_AUTOFW_ACTIVE)
+ del_timer(&af->timer);
+ kfree_s(af,sizeof(struct ip_autofw));
+ MOD_DEC_USE_COUNT;
+ }
+ return(0);
+}
+
+/*
+ * Methods for registered object
+ */
+
+static int autofw_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+{
+ struct ip_autofw *af = (struct ip_autofw*) mctl->u.mod.data;
+
+ switch (optname) {
+ case IP_FW_MASQ_ADD:
+ if (optlen<sizeof(*af))
+ return EINVAL;
+ return ip_autofw_add(af);
+ case IP_FW_MASQ_DEL:
+ if (optlen<sizeof(*af))
+ return EINVAL;
+ return ip_autofw_del(af);
+ case IP_FW_MASQ_FLUSH:
+ return ip_autofw_flush();
+
+ }
+ return EINVAL;
+}
+
+
+static int autofw_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+ /*
+ * Update any ipautofw entries ...
+ */
+
+ ip_autofw_update_out(iph->saddr, iph->daddr, portp[1], iph->protocol);
+ return IP_MASQ_MOD_NOP;
+}
+
+static struct ip_masq * autofw_out_create(struct iphdr *iph, __u16 * portp, __u32 maddr)
+{
+ /*
+ * If the source port is supposed to match the masq port, then
+ * make it so
+ */
+
+ if (ip_autofw_check_direct(portp[1],iph->protocol)) {
+ return ip_masq_new(iph->protocol,
+ maddr, portp[0],
+ iph->saddr, portp[0],
+ iph->daddr, portp[1],
+ 0);
+ }
+ return NULL;
+}
+
+#if 0
+static int autofw_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+ ip_autofw_update_in(iph->saddr, portp[1], iph->protocol);
+ return IP_MASQ_MOD_NOP;
+}
+#endif
+
+static int autofw_in_rule(struct iphdr *iph, __u16 *portp)
+{
+ return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0)
+ || ip_autofw_check_direct(portp[1], iph->protocol)
+ || ip_autofw_check_port(portp[1], iph->protocol));
+}
+
+static struct ip_masq * autofw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+ struct ip_autofw *af;
+
+ if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) {
+ IP_MASQ_DEBUG(1-debug, "autofw_check_range HIT\n");
+ return ip_masq_new(iph->protocol,
+ maddr, portp[1],
+ af->where, portp[1],
+ iph->saddr, portp[0],
+ 0);
+ }
+ if ((af=ip_autofw_check_port(portp[1], iph->protocol)) ) {
+ IP_MASQ_DEBUG(1-debug, "autofw_check_port HIT\n");
+ return ip_masq_new(iph->protocol,
+ maddr, htons(af->visible),
+ af->where, htons(af->hidden),
+ iph->saddr, portp[0],
+ 0);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int autofw_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin=0;
+ struct ip_autofw * af;
+ int len=0;
+
+ len=sprintf(buffer,"Type Prot Low High Vis Hid Where Last CPto CPrt Timer Flags\n");
+
+ for(af = ip_autofw_hosts; af ; af = af->next)
+ {
+ len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n",
+ af->type,
+ af->protocol,
+ af->low,
+ af->high,
+ af->visible,
+ af->hidden,
+ ntohl(af->where),
+ ntohl(af->lastcontact),
+ af->ctlproto,
+ af->ctlport,
+ (af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies),
+ af->flags);
+
+ pos=begin+len;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ }
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+static struct proc_dir_entry autofw_proc_entry = {
+ 0, 0, NULL,
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ autofw_procinfo
+};
+
+#define proc_ent &autofw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+
+#define autofw_in_update NULL
+#define autofw_out_rule NULL
+#define autofw_mod_init NULL
+#define autofw_mod_done NULL
+
+static struct ip_masq_mod autofw_mod = {
+ NULL, /* next */
+ NULL, /* next_reg */
+ "autofw", /* name */
+ ATOMIC_INIT(0), /* nent */
+ ATOMIC_INIT(0), /* refcnt */
+ proc_ent,
+ autofw_ctl,
+ autofw_mod_init,
+ autofw_mod_done,
+ autofw_in_rule,
+ autofw_in_update,
+ autofw_in_create,
+ autofw_out_rule,
+ autofw_out_update,
+ autofw_out_create,
+};
+
+__initfunc(int ip_autofw_init(void))
+{
+ return register_ip_masq_mod ((mmod_self=&autofw_mod));
+}
+
+int ip_autofw_done(void)
+{
+ return unregister_ip_masq_mod(&autofw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_autofw_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_autofw_done() != 0)
+ printk(KERN_INFO "ip_autofw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/net/ipv4/ip_masq_cuseeme.c b/net/ipv4/ip_masq_cuseeme.c
new file mode 100644
index 000000000..a306b4f25
--- /dev/null
+++ b/net/ipv4/ip_masq_cuseeme.c
@@ -0,0 +1,261 @@
+/*
+ * IP_MASQ_FTP CUSeeMe masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.2 1997/11/28 15:32:18 alan Exp $
+ *
+ * Author: Richard Lynch
+ *
+ *
+ * Fixes:
+ * Richard Lynch : Updated patch to conform to new module
+ * specifications
+ * Nigel Metheringham : Multiple port support
+ * Michael Owings : Fixed broken init code
+ * Added code to update inbound
+ * packets with correct local addresses.
+ * Fixes audio and "chat" problems
+ * Thanx to the CU-SeeMe Consortium for
+ * technical docs
+ * Steven Clarke : Small changes for 2.1
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ */
+
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+
+/* #define IP_MASQ_NDEBUG */
+#include <net/ip_masq.h>
+
+#pragma pack(1)
+/* CU-SeeMe Data Header */
+typedef struct {
+ u_short dest_family;
+ u_short dest_port;
+ u_long dest_addr;
+ short family;
+ u_short port;
+ u_long addr;
+ u_long seq;
+ u_short msg;
+ u_short data_type;
+ u_short packet_len;
+} cu_header;
+
+/* Open Continue Header */
+typedef struct {
+ cu_header cu_head;
+ u_short client_count; /* Number of client info structs */
+ u_long seq_no;
+ char user_name[20];
+ char stuff[4]; /* flags, version stuff, etc */
+}oc_header;
+
+/* client info structures */
+typedef struct {
+ u_long address; /* Client address */
+ char stuff[8]; /* Flags, pruning bitfield, packet counts etc */
+} client_info;
+#pragma pack()
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7648}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+static int
+masq_cuseeme_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+masq_cuseeme_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int
+masq_cuseeme_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+ cu_header *cu_head;
+ char *data=(char *)&uh[1];
+
+ if (skb->len - ((unsigned char *) data - skb->h.raw) >= sizeof(cu_header))
+ {
+ cu_head = (cu_header *) data;
+ /* cu_head->port = ms->mport; */
+ if( cu_head->addr )
+ cu_head->addr = (u_long) maddr;
+ if(ntohs(cu_head->data_type) == 257)
+ IP_MASQ_DEBUG(1-debug, "Sending talk packet!\n");
+ }
+ return 0;
+}
+
+int
+masq_cuseeme_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+ cu_header *cu_head;
+ oc_header *oc;
+ client_info *ci;
+ char *data=(char *)&uh[1];
+ u_short len = skb->len - ((unsigned char *) data - skb->h.raw);
+ int i, off;
+
+ if (len >= sizeof(cu_header))
+ {
+ cu_head = (cu_header *) data;
+ if(cu_head->dest_addr) /* Correct destination address */
+ cu_head->dest_addr = (u_long) ms->saddr;
+ if(ntohs(cu_head->data_type)==101 && len > sizeof(oc_header))
+ {
+ oc = (oc_header * ) data;
+ /* Spin (grovel) thru client_info structs till we find our own */
+ off=sizeof(oc_header);
+ for(i=0;
+ (i < oc->client_count && off+sizeof(client_info) <= len);
+ i++)
+ {
+ ci=(client_info *)(data+off);
+ if(ci->address==(u_long) maddr)
+ {
+ /* Update w/ our real ip address and exit */
+ ci->address = (u_long) ms->saddr;
+ break;
+ }
+ else
+ off+=sizeof(client_info);
+ }
+ }
+ }
+ return 0;
+}
+
+struct ip_masq_app ip_masq_cuseeme = {
+ NULL, /* next */
+ "cuseeme",
+ 0, /* type */
+ 0, /* n_attach */
+ masq_cuseeme_init_1, /* ip_masq_init_1 */
+ masq_cuseeme_done_1, /* ip_masq_done_1 */
+ masq_cuseeme_out, /* pkt_out */
+ masq_cuseeme_in /* pkt_in */
+};
+
+
+/*
+ * ip_masq_cuseeme initialization
+ */
+
+__initfunc(int ip_masq_cuseeme_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_cuseeme, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_UDP,
+ ports[i]))) {
+ return j;
+ }
+#if DEBUG_CONFIG_IP_MASQ_CUSEEME
+ IP_MASQ_DEBUG(1-debug, "CuSeeMe: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+#endif
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_cuseeme fin.
+ */
+
+int ip_masq_cuseeme_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "CuSeeMe: unloaded support on port[%d] = %d\n", i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_cuseeme_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_cuseeme_done() != 0)
+ IP_MASQ_DEBUG(1-debug, "ip_masq_cuseeme: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/net/ipv4/ip_masq_ftp.c b/net/ipv4/ip_masq_ftp.c
index 4cb88d925..5313f4429 100644
--- a/net/ipv4/ip_masq_ftp.c
+++ b/net/ipv4/ip_masq_ftp.c
@@ -2,14 +2,20 @@
* IP_MASQ_FTP ftp masquerading module
*
*
- * Version: @(#)ip_masq_ftp.c 0.01 02/05/96
+ * Version: @(#)ip_masq_ftp.c 0.04 02/05/96
*
* Author: Wouter Gadeyne
- *
+ *
*
* Fixes:
* Wouter Gadeyne : Fixed masquerading support of ftp PORT commands
* Juan Jose Ciarlante : Code moved and adapted from ip_fw.c
+ * Keith Owens : Add keep alive for ftp control channel
+ * Nigel Metheringham : Added multiple port support
+ * Juan Jose Ciarlante : Use control_add() for ftp control chan
+ * Juan Jose Ciarlante : Litl bits for 2.1
+ * Juan Jose Ciarlante : use ip_masq_listen()
+ * Juan Jose Ciarlante : use private app_data for own flag(s)
*
*
*
@@ -17,7 +23,18 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
- *
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
*/
#include <linux/config.h>
@@ -31,9 +48,28 @@
#include <linux/init.h>
#include <net/protocol.h>
#include <net/tcp.h>
+
+/* #define IP_MASQ_NDEBUG */
#include <net/ip_masq.h>
-#define DEBUG_CONFIG_IP_MASQ_FTP 0
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/* Dummy variable */
+static int masq_ftp_pasv;
static int
masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -70,6 +106,8 @@ masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
data = (char *)&th[1];
data_limit = skb->h.raw + skb->len - 18;
+ if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0))
+ ms->app_data = &masq_ftp_pasv;
while (data < data_limit)
{
@@ -100,39 +138,30 @@ masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
port = (p5<<8) | p6;
-#if DEBUG_CONFIG_IP_MASQ_FTP
- printk("PORT %X:%X detected\n",from,port);
-#endif
+
+ IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port);
+
/*
* Now update or create an masquerade entry for it
*/
-#if DEBUG_CONFIG_IP_MASQ_FTP
- printk("protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
-#endif
- n_ms = ip_masq_out_get_2(iph->protocol,
+ IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
+
+ n_ms = ip_masq_out_get(iph->protocol,
htonl(from), htons(port),
iph->daddr, 0);
- if (n_ms) {
- /* existing masquerade, clear timer */
- ip_masq_set_expire(n_ms,0);
- }
- else {
- n_ms = ip_masq_new(maddr, IPPROTO_TCP,
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
htonl(from), htons(port),
iph->daddr, 0,
IP_MASQ_F_NO_DPORT);
if (n_ms==NULL)
return 0;
+ ip_masq_control_add(n_ms, ms);
}
- /*
- * keep for a bit longer than tcp_fin, caller may not reissue
- * PORT before tcp_fin_timeout.
- */
- ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout*3);
-
/*
* Replace the old PORT with the new one
*/
@@ -142,30 +171,34 @@ masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
from>>24&255,from>>16&255,from>>8&255,from&255,
port>>8&255,port&255);
buf_len = strlen(buf);
-#if DEBUG_CONFIG_IP_MASQ_FTP
- printk("new PORT %X:%X\n",from,port);
-#endif
+
+ IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port);
/*
* Calculate required delta-offset to keep TCP happy
*/
-
+
diff = buf_len - (data-p);
-
+
/*
* No shift.
*/
-
- if (diff==0)
- {
+
+ if (diff==0) {
/*
* simple case, just replace the old PORT cmd
*/
memcpy(p,buf,buf_len);
- return 0;
- }
+ } else {
+
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
+ }
+ /*
+ * Move tunnel to listen state
+ */
+ ip_masq_listen(n_ms);
+ ip_masq_put(n_ms);
- *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
return diff;
}
@@ -173,6 +206,108 @@ masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
}
+/*
+ * Look at incoming ftp packets to catch the response to a PASV command. When
+ * we see one we build a masquerading entry for the client address, client port
+ * 0 (unknown at the moment), the server address and the server port. Mark the
+ * current masquerade entry as a control channel and point the new entry at the
+ * control entry. All this work just for ftp keepalive across masquerading.
+ *
+ * The incoming packet should be something like
+ * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
+ * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
+ * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into
+ * the data so we do the same. If it's good enough for ncftp then it's good
+ * enough for me.
+ *
+ * In this case, the client is the source machine being masqueraded, the server
+ * is the destination for ftp requests. It all depends on your point of view ...
+ */
+
+int
+masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ unsigned char p1,p2,p3,p4,p5,p6;
+ __u32 to;
+ __u16 port;
+ struct ip_masq *n_ms;
+
+ if (ms->app_data != &masq_ftp_pasv)
+ return 0; /* quick exit if no outstanding PASV */
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+ data_limit = skb->h.raw + skb->len;
+
+ while (data < data_limit && *data != ' ')
+ ++data;
+ while (data < data_limit && *data == ' ')
+ ++data;
+ data += 22;
+ if (data >= data_limit || *data != '(')
+ return 0;
+ p1 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p2 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p3 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p4 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p5 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p6 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ')')
+ return 0;
+
+ to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+ port = (p5<<8) | p6;
+
+ /*
+ * Now update or create an masquerade entry for it
+ */
+ IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port);
+
+ n_ms = ip_masq_out_get(iph->protocol,
+ ms->saddr, 0,
+ htonl(to), htons(port));
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
+ ms->saddr, 0,
+ htonl(to), htons(port),
+ IP_MASQ_F_NO_SPORT);
+
+ if (n_ms==NULL)
+ return 0;
+ ip_masq_control_add(n_ms, ms);
+ }
+
+#if 0 /* v0.12 state processing */
+
+ /*
+ * keep for a bit longer than tcp_fin, client may not issue open
+ * to server port before tcp_fin_timeout.
+ */
+ n_ms->timeout = ip_masq_expire->tcp_fin_timeout*3;
+#endif
+ ms->app_data = NULL;
+ ip_masq_put(n_ms);
+
+ return 0; /* no diff required for incoming packets, thank goodness */
+}
+
struct ip_masq_app ip_masq_ftp = {
NULL, /* next */
"ftp", /* name */
@@ -181,7 +316,7 @@ struct ip_masq_app ip_masq_ftp = {
masq_ftp_init_1, /* ip_masq_init_1 */
masq_ftp_done_1, /* ip_masq_done_1 */
masq_ftp_out, /* pkt_out */
- NULL /* pkt_in */
+ masq_ftp_in, /* pkt_in */
};
/*
@@ -190,7 +325,27 @@ struct ip_masq_app ip_masq_ftp = {
__initfunc(int ip_masq_ftp_init(void))
{
- return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21);
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_ftp, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "Ftp: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
}
/*
@@ -199,7 +354,22 @@ __initfunc(int ip_masq_ftp_init(void))
int ip_masq_ftp_done(void)
{
- return unregister_ip_masq_app(&ip_masq_ftp);
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "Ftp: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
}
#ifdef MODULE
diff --git a/net/ipv4/ip_masq_irc.c b/net/ipv4/ip_masq_irc.c
index b2e325ce6..6668efdaf 100644
--- a/net/ipv4/ip_masq_irc.c
+++ b/net/ipv4/ip_masq_irc.c
@@ -2,13 +2,22 @@
* IP_MASQ_IRC irc masquerading module
*
*
- * Version: @(#)ip_masq_irc.c 0.01 03/20/96
+ * Version: @(#)ip_masq_irc.c 0.03 97/11/30
*
* Author: Juan Jose Ciarlante
- *
- *
+ *
+ * Additions:
+ * - recognize a few non-irc-II DCC requests (Oliver Wagner)
+ * DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
+ * DCC SCHAT (AmIRC IDEA encrypted CHAT)
+ * DCC TSEND (AmIRC/PIRCH SEND without ACKs)
* Fixes:
- * - set NO_DADDR flag in ip_masq_new().
+ * Juan Jose Ciarlante : set NO_DADDR flag in ip_masq_new()
+ * Nigel Metheringham : Added multiple port support
+ * Juan Jose Ciarlante : litl bits for 2.1
+ * Oliver Wagner : more IRC cmds processing
+ * <winmute@lucifer.gv.kotnet.org>
+ * Juan Jose Ciarlante : put new ms entry to listen()
*
* FIXME:
* - detect also previous "PRIVMSG" string ?.
@@ -17,7 +26,18 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
- *
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
*/
#include <linux/config.h>
@@ -34,7 +54,43 @@
#include <net/tcp.h>
#include <net/ip_masq.h>
-#define DEBUG_CONFIG_IP_MASQ_IRC 0
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+
+/*
+ * List of supported DCC protocols
+ */
+
+#define NUM_DCCPROTO 5
+
+struct dccproto
+{
+ char *match;
+ int matchlen;
+ int xtra_args;
+};
+
+struct dccproto dccprotos[NUM_DCCPROTO] = {
+ { "SEND ", 5, 1 },
+ { "CHAT ", 5, 0, },
+ { "MOVE ", 5, 1 },
+ { "TSEND ", 6, 1, },
+ { "SCHAT ", 6, 0, }
+};
+#define MAXMATCHLEN 6
static int
masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -72,145 +128,148 @@ masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
data = (char *)&th[1];
/*
- * Hunt irc DCC string, the _shortest_:
- *
- * strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
- * strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
- * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
- * P: bound port (min 1 d )
- * F: filename (min 1 d )
- * S: size (min 1 d )
- * 0x01, \n: terminators
+ * Hunt irc DCC string, the _shortest_:
+ *
+ * strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
+ * strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27
+ * strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
+ * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+ * strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26
+ * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
+ * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+ * P: bound port (min 1 d )
+ * F: filename (min 1 d )
+ * S: size (min 1 d )
+ * 0x01, \n: terminators
*/
data_limit = skb->h.raw + skb->len;
-
- while (data < (data_limit - 25) )
+
+ while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) )
{
+ int i;
if (memcmp(data,"DCC ",4)) {
data ++;
continue;
}
- dcc_p = data;
+ dcc_p = data;
data += 4; /* point to DCC cmd */
- if (memcmp(data, "CHAT ", 5) == 0 ||
- memcmp(data, "SEND ", 5) == 0)
- {
- /*
- * extra arg (file_size) req. for "SEND"
- */
-
- if (*data == 'S') xtra_args++;
- data += 5;
- }
- else
- continue;
-
- /*
- * skip next string.
- */
-
- while( *data++ != ' ')
-
- /*
- * must still parse, at least, "AAAAAAAA P\x01\n",
- * 12 bytes left.
- */
- if (data > (data_limit-12)) return 0;
-
-
- addr_beg_p = data;
-
- /*
- * client bound address in dec base
- */
-
- s_addr = simple_strtoul(data,&data,10);
- if (*data++ !=' ')
- continue;
-
- /*
- * client bound port in dec base
- */
-
- s_port = simple_strtoul(data,&data,10);
- addr_end_p = data;
-
- /*
- * should check args consistency?
- */
-
- while(xtra_args) {
- if (*data != ' ')
- break;
- data++;
- simple_strtoul(data,&data,10);
- xtra_args--;
- }
-
- if (xtra_args != 0) continue;
-
- /*
- * terminators.
- */
-
- if (data[0] != 0x01)
- continue;
- if (data[1]!='\r' && data[1]!='\n')
- continue;
-
- /*
- * Now create an masquerade entry for it
- * must set NO_DPORT and NO_DADDR because
- * connection is requested by another client.
- */
-
- n_ms = ip_masq_new(maddr, IPPROTO_TCP,
- htonl(s_addr),htons(s_port),
- 0, 0,
- IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR
- );
- if (n_ms==NULL)
- return 0;
-
- ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
-
- /*
- * Replace the old "address port" with the new one
- */
-
- buf_len = sprintf(buf,"%lu %u",
- ntohl(n_ms->maddr),ntohs(n_ms->mport));
-
- /*
- * Calculate required delta-offset to keep TCP happy
- */
-
- diff = buf_len - (addr_end_p-addr_beg_p);
-
-#if DEBUG_CONFIG_IP_MASQ_IRC
- *addr_beg_p = '\0';
- printk("masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
-#endif
- /*
- * No shift.
- */
-
- if (diff==0)
+ for(i=0; i<NUM_DCCPROTO; i++)
{
/*
- * simple case, just copy.
- */
- memcpy(addr_beg_p,buf,buf_len);
- return 0;
- }
-
- *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
- addr_beg_p, addr_end_p-addr_beg_p,
- buf, buf_len);
- return diff;
+ * go through the table and hunt a match string
+ */
+
+ if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
+ {
+ xtra_args = dccprotos[i].xtra_args;
+ data += dccprotos[i].matchlen;
+
+ /*
+ * skip next string.
+ */
+
+ while( *data++ != ' ')
+
+ /*
+ * must still parse, at least, "AAAAAAAA P\x01\n",
+ * 12 bytes left.
+ */
+ if (data > (data_limit-12)) return 0;
+
+
+ addr_beg_p = data;
+
+ /*
+ * client bound address in dec base
+ */
+
+ s_addr = simple_strtoul(data,&data,10);
+ if (*data++ !=' ')
+ continue;
+
+ /*
+ * client bound port in dec base
+ */
+
+ s_port = simple_strtoul(data,&data,10);
+ addr_end_p = data;
+
+ /*
+ * should check args consistency?
+ */
+
+ while(xtra_args) {
+ if (*data != ' ')
+ break;
+ data++;
+ simple_strtoul(data,&data,10);
+ xtra_args--;
+ }
+
+ if (xtra_args != 0) continue;
+
+ /*
+ * terminators.
+ */
+
+ if (data[0] != 0x01)
+ continue;
+ if (data[1]!='\r' && data[1]!='\n')
+ continue;
+
+ /*
+ * Now create an masquerade entry for it
+ * must set NO_DPORT and NO_DADDR because
+ * connection is requested by another client.
+ */
+
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
+ htonl(s_addr),htons(s_port),
+ 0, 0,
+ IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+ if (n_ms==NULL)
+ return 0;
+
+ /*
+ * Replace the old "address port" with the new one
+ */
+
+ buf_len = sprintf(buf,"%lu %u",
+ ntohl(n_ms->maddr),ntohs(n_ms->mport));
+
+ /*
+ * Calculate required delta-offset to keep TCP happy
+ */
+
+ diff = buf_len - (addr_end_p-addr_beg_p);
+
+ *addr_beg_p = '\0';
+ IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+
+ /*
+ * No shift.
+ */
+
+ if (diff==0) {
+ /*
+ * simple case, just copy.
+ */
+ memcpy(addr_beg_p,buf,buf_len);
+ } else {
+
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+ addr_beg_p, addr_end_p-addr_beg_p,
+ buf, buf_len);
+ }
+ ip_masq_listen(n_ms);
+ ip_masq_put(n_ms);
+ return diff;
+ }
+ }
}
return 0;
@@ -221,7 +280,7 @@ masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
* You need 1 object per port in case you need
* to offer also other used irc ports (6665,6666,etc),
* they will share methods but they need own space for
- * data.
+ * data.
*/
struct ip_masq_app ip_masq_irc = {
@@ -241,7 +300,28 @@ struct ip_masq_app ip_masq_irc = {
__initfunc(int ip_masq_irc_init(void))
{
- return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug,
+ "Irc: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
}
/*
@@ -250,9 +330,25 @@ __initfunc(int ip_masq_irc_init(void))
int ip_masq_irc_done(void)
{
- return unregister_ip_masq_app(&ip_masq_irc);
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
}
+
#ifdef MODULE
EXPORT_NO_SYMBOLS;
diff --git a/net/ipv4/ip_masq_mod.c b/net/ipv4/ip_masq_mod.c
new file mode 100644
index 000000000..797f9112f
--- /dev/null
+++ b/net/ipv4/ip_masq_mod.c
@@ -0,0 +1,316 @@
+/*
+ * IP_MASQ_MOD masq modules support
+ *
+ *
+ * Version: @(#)ip_masq_mod.c 0.02 97/10/30
+ *
+ * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+EXPORT_SYMBOL(register_ip_masq_mod);
+EXPORT_SYMBOL(unregister_ip_masq_mod);
+EXPORT_SYMBOL(ip_masq_mod_lkp_link);
+EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
+
+/*
+ * Base pointer for registered modules
+ */
+struct ip_masq_mod * ip_masq_mod_reg_base = NULL;
+
+/*
+ * Base pointer for lookup (subset of above, a module could be
+ * registered, but it could have no active rule); will avoid
+ * unnecessary lookups.
+ */
+struct ip_masq_mod * ip_masq_mod_lkp_base = NULL;
+
+int ip_masq_mod_register_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS
+ int ret;
+
+ struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+
+ if (!ent)
+ return 0;
+ if (!ent->name) {
+ ent->name = mmod->mmod_name;
+ ent->namelen = strlen (mmod->mmod_name);
+ }
+ ret = proc_net_register(ent);
+ if (ret) mmod->mmod_proc_ent = NULL;
+
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+ if (!ent)
+ return;
+ proc_unregister(proc_net, ent->low_ino);
+#endif
+}
+
+/*
+ * Link/unlink object for lookups
+ */
+
+int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod)
+{
+ struct ip_masq_mod **mmod_p;
+
+ start_bh_atomic();
+
+ for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next)
+ if (mmod == (*mmod_p)) {
+ *mmod_p = mmod->next;
+ mmod->next = NULL;
+ end_bh_atomic();
+ return 0;
+ }
+
+ end_bh_atomic();
+ return -EINVAL;
+}
+
+int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod)
+{
+ start_bh_atomic();
+
+ mmod->next = ip_masq_mod_lkp_base;
+ ip_masq_mod_lkp_base=mmod;
+
+ end_bh_atomic();
+ return 0;
+}
+
+int register_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+ if (!mmod) {
+ IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n");
+ return -EINVAL;
+ }
+ if (!mmod->mmod_name) {
+ IP_MASQ_ERR("register_ip_masq_mod(): NULL mmod_name\n");
+ return -EINVAL;
+ }
+ ip_masq_mod_register_proc(mmod);
+
+ mmod->next_reg = ip_masq_mod_reg_base;
+ ip_masq_mod_reg_base=mmod;
+
+ return 0;
+}
+
+int unregister_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+ struct ip_masq_mod **mmod_p;
+
+ if (!mmod) {
+ IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Only allow unregistration if it is not referenced
+ */
+ if (atomic_read(&mmod->refcnt)) {
+ IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n",
+ atomic_read(&mmod->refcnt));
+ return -EINVAL;
+ }
+
+ /*
+ * Must be already unlinked from lookup list
+ */
+ if (mmod->next) {
+ IP_MASQ_WARNING("MASQ: unregistering \"%s\" while in lookup list.fixed.",
+ mmod->mmod_name);
+ ip_masq_mod_lkp_unlink(mmod);
+ }
+
+ for (mmod_p = &ip_masq_mod_reg_base; *mmod_p ; mmod_p = &(*mmod_p)->next_reg)
+ if (mmod == (*mmod_p)) {
+ ip_masq_mod_unregister_proc(mmod);
+ *mmod_p = mmod->next_reg;
+ return 0;
+ }
+
+ IP_MASQ_ERR("unregister_ip_masq_mod(%s): not linked \n", mmod->mmod_name);
+ return -EINVAL;
+}
+
+int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp)
+{
+ struct ip_masq_mod *mmod;
+ int ret;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_rule) continue;
+ switch (ret=mmod->mmod_in_rule(iph, portp)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ return 1;
+ case IP_MASQ_MOD_REJECT:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp)
+{
+ struct ip_masq_mod *mmod;
+ int ret;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_rule) continue;
+ switch (ret=mmod->mmod_out_rule(iph, portp)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ return 1;
+ case IP_MASQ_MOD_REJECT:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+ struct ip_masq_mod *mmod;
+ struct ip_masq *ms;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_create) continue;
+ if ((ms=mmod->mmod_in_create(iph, portp, maddr))) {
+ return ms;
+ }
+ }
+ return NULL;
+}
+
+struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+ struct ip_masq_mod *mmod;
+ struct ip_masq *ms;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_create) continue;
+ if ((ms=mmod->mmod_out_create(iph, portp, maddr))) {
+ return ms;
+ }
+ }
+ return NULL;
+}
+
+int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+ struct ip_masq_mod *mmod;
+ int ret;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_update) continue;
+ switch (ret=mmod->mmod_in_update(iph, ms)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ return 1;
+ case IP_MASQ_MOD_REJECT:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+ struct ip_masq_mod *mmod;
+ int ret;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_update) continue;
+ switch (ret=mmod->mmod_out_update(iph, portp, ms)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ return 1;
+ case IP_MASQ_MOD_REJECT:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
+{
+ struct ip_masq_mod * mmod;
+
+ IP_MASQ_DEBUG(1, "searching mmod_name \"%s\"\n", mmod_name);
+
+ for (mmod=ip_masq_mod_reg_base; mmod ; mmod=mmod->next) {
+ if (mmod->mmod_ctl && *(mmod_name)
+ && (strcmp(mmod_name, mmod->mmod_name)==0)) {
+ /* HIT */
+ return mmod;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Module control entry
+ * no need to lock (already locked in ip_masq.c)
+ */
+int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+{
+ struct ip_masq_mod * mmod;
+#ifdef CONFIG_KERNELD
+ char kmod_name[IP_MASQ_MOD_NMAX+8];
+#endif
+ /* tappo */
+ mctl->u.mod.name[IP_MASQ_MOD_NMAX-1] = 0;
+
+ mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+ if (mmod)
+ return mmod->mmod_ctl(optname, mctl, optlen);
+#ifdef CONFIG_KERNELD
+ sprintf(kmod_name,"ip_masq_%s", mctl->u.mod.name);
+
+ IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
+
+ /*
+ * Let sleep for a while ...
+ */
+ request_module(kmod_name);
+ mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+ if (mmod)
+ return mmod->mmod_ctl(optname, mctl, optlen);
+#endif
+ return ESRCH;
+}
diff --git a/net/ipv4/ip_masq_portfw.c b/net/ipv4/ip_masq_portfw.c
new file mode 100644
index 000000000..862742a21
--- /dev/null
+++ b/net/ipv4/ip_masq_portfw.c
@@ -0,0 +1,461 @@
+/*
+ * IP_MASQ_PORTFW masquerading module
+ *
+ *
+ * Version: @(#)ip_masq_portfw.c 0.02 97/10/30
+ *
+ * Author: Steven Clarke <steven.clarke@monmouth.demon.co.uk>
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
+ * Juan Jose Ciarlante : modularized
+ * Juan Jose Ciarlante : use GFP_KERNEL
+ *
+ * FIXME
+ * - after creating /proc/net/ip_masq/ direct, put portfw underneath
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <linux/ip_fw.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <net/ip_portfw.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+static struct ip_masq_mod *mmod_self = NULL;
+
+/*
+ * Lock
+ */
+static atomic_t portfw_lock = ATOMIC_INIT(0);
+static struct wait_queue *portfw_wait;
+
+static struct list_head portfw_list[2];
+static __inline__ int portfw_idx(int protocol)
+{
+ return (protocol==IPPROTO_TCP);
+}
+
+/*
+ *
+ * Delete forwarding entry(s):
+ * called from _DEL, u-space.
+ * . "relaxed" match, except for lport
+ *
+ */
+
+static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)
+{
+ int prot = portfw_idx(protocol);
+ struct ip_portfw *n;
+ struct list_head *entry;
+ struct list_head *list = &portfw_list[prot];
+ int nent;
+
+ nent = atomic_read(&mmod_self->mmod_nent);
+
+ ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+ for (entry=list->next;entry != list;entry = entry->next) {
+ n = list_entry(entry, struct ip_portfw, list);
+ if (n->lport == lport &&
+ (!laddr || n->laddr == laddr) &&
+ (!raddr || n->raddr == raddr) &&
+ (!rport || n->rport == rport)) {
+ list_del(entry);
+ ip_masq_mod_dec_nent(mmod_self);
+ kfree_s(n, sizeof(struct ip_portfw));
+ MOD_DEC_USE_COUNT;
+ }
+ }
+ ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+
+ return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
+}
+
+/*
+ * Flush tables
+ * called from _FLUSH, u-space.
+ */
+static __inline__ void ip_portfw_flush(void)
+{
+ int prot;
+ struct list_head *l;
+ struct list_head *e;
+ struct ip_portfw *n;
+
+ ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+ for (prot = 0; prot < 2;prot++) {
+ l = &portfw_list[prot];
+ while((e=l->next) != l) {
+ ip_masq_mod_dec_nent(mmod_self);
+ n = list_entry (e, struct ip_portfw, list);
+ list_del(e);
+ kfree_s(n, sizeof (*n));
+ MOD_DEC_USE_COUNT;
+ }
+ }
+
+ ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+}
+
+/*
+ * Lookup routine for lport,laddr match
+ * called from ip_masq module (via registered obj)
+ */
+static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
+{
+ int prot = portfw_idx(protocol);
+
+ struct ip_portfw *n = NULL;
+ struct list_head *l, *e;
+
+ ip_masq_lock(&portfw_lock, 0);
+
+ l = &portfw_list[prot];
+
+ for (e=l->next;e!=l;e=e->next) {
+ n = list_entry(e, struct ip_portfw, list);
+ if (lport == n->lport && laddr == n->laddr) {
+ /* Please be nice, don't pass only a NULL dport */
+ if (daddr_p) {
+ *daddr_p = n->raddr;
+ *dport_p = n->rport;
+ }
+
+ goto out;
+ }
+ }
+ n = NULL;
+out:
+ ip_masq_unlock(&portfw_lock, 0);
+ return n;
+}
+
+/*
+ * Edit routine for lport,[laddr], [raddr], [rport] match
+ * By now, only called from u-space
+ */
+static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+ int prot = portfw_idx(protocol);
+
+ struct ip_portfw *n = NULL;
+ struct list_head *l, *e;
+ int count = 0;
+
+
+ ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+
+ l = &portfw_list[prot];
+
+ for (e=l->next;e!=l;e=e->next) {
+ n = list_entry(e, struct ip_portfw, list);
+ if (lport == n->lport &&
+ (!laddr || laddr == n->laddr) &&
+ (!rport || rport == n->rport) &&
+ (!raddr || raddr == n->raddr)) {
+ n->pref = pref;
+ atomic_set(&n->pref_cnt, pref);
+ count++;
+ }
+ }
+
+ ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+
+ return count;
+}
+
+/*
+ * Add/edit en entry
+ * called from _ADD, u-space.
+ * must return 0 or +errno
+ */
+static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+ struct ip_portfw *npf;
+ int prot = portfw_idx(protocol);
+
+ if (pref <= 0)
+ return EINVAL;
+
+ if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) {
+ /*
+ * Edit ok ...
+ */
+ return 0;
+ }
+
+ /* may block ... */
+ npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL);
+
+ if (!npf)
+ return ENOMEM;
+
+ MOD_INC_USE_COUNT;
+ memset(npf, 0, sizeof(*npf));
+
+ npf->laddr = laddr;
+ npf->lport = lport;
+ npf->rport = rport;
+ npf->raddr = raddr;
+ npf->pref = pref;
+
+ atomic_set(&npf->pref_cnt, npf->pref);
+ INIT_LIST_HEAD(&npf->list);
+
+ ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+
+ /*
+ * Add at head
+ */
+ list_add(&npf->list, &portfw_list[prot]);
+
+ ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+
+ ip_masq_mod_inc_nent(mmod_self);
+ return 0;
+}
+
+
+
+static __inline__ int portfw_ctl(int cmd, struct ip_fw_masqctl *mctl, int optlen)
+{
+ struct ip_portfw_edits *mm = (struct ip_portfw_edits *) mctl->u.mod.data;
+ int ret = EINVAL;
+
+ /*
+ * Don't trust the lusers - plenty of error checking!
+ */
+ if (optlen<sizeof(*mm))
+ return EINVAL;
+
+ if (cmd != IP_FW_MASQ_FLUSH) {
+ if (htons(mm->lport) < IP_PORTFW_PORT_MIN
+ || htons(mm->lport) > IP_PORTFW_PORT_MAX)
+ return EINVAL;
+
+ if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
+ return EINVAL;
+ }
+
+
+ switch(cmd) {
+ case IP_FW_MASQ_ADD:
+ ret = ip_portfw_add(mm->protocol,
+ mm->lport, mm->laddr,
+ mm->rport, mm->raddr,
+ mm->pref);
+ break;
+
+ case IP_FW_MASQ_DEL:
+ ret = ip_portfw_del(mm->protocol,
+ mm->lport, mm->laddr,
+ mm->rport, mm->raddr);
+ break;
+ case IP_FW_MASQ_FLUSH:
+ ip_portfw_flush();
+ ret = 0;
+ break;
+ }
+
+
+ return ret;
+}
+
+
+
+
+#ifdef CONFIG_PROC_FS
+
+static int portfw_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin;
+ struct ip_portfw *pf;
+ struct list_head *l, *e;
+ char temp[65];
+ int ind;
+ int len=0;
+
+ ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+
+ if (offset < 64)
+ {
+ sprintf(temp, "Prot LAddr LPort > RAddr RPort PrCnt Pref");
+ len = sprintf(buffer, "%-63s\n", temp);
+ }
+ pos = 64;
+
+ for(ind = 0; ind < 2; ind++)
+ {
+ l = &portfw_list[ind];
+ for (e=l->next; e!=l; e=e->next)
+ {
+ pf = list_entry(e, struct ip_portfw, list);
+ pos += 64;
+ if (pos <= offset)
+ continue;
+
+ sprintf(temp,"%s %08lX %5u > %08lX %5u %5d %5d",
+ ind ? "TCP" : "UDP",
+ ntohl(pf->laddr), ntohs(pf->lport),
+ ntohl(pf->raddr), ntohs(pf->rport),
+ atomic_read(&pf->pref_cnt), pf->pref);
+ len += sprintf(buffer+len, "%-63s\n", temp);
+
+ if (len >= length)
+ goto done;
+ }
+ }
+done:
+ ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ if(len>length)
+ len = length;
+ return len;
+}
+
+static struct proc_dir_entry portfw_proc_entry = {
+/* 0, 0, NULL", */
+ 0, 9, "ip_portfw", /* Just for compatibility, for now ... */
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ portfw_procinfo
+};
+
+#define proc_ent &portfw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+static int portfw_in_rule(struct iphdr *iph, __u16 *portp)
+{
+
+ return (ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL)!=0);
+}
+
+static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+{
+ /*
+ * If no entry exists in the masquerading table
+ * and the port is involved
+ * in port forwarding, create a new masq entry
+ */
+
+ __u32 raddr;
+ __u16 rport;
+ struct ip_masq *ms = NULL;
+ struct ip_portfw *pf;
+
+ /*
+ * Lock for reading only, by now...
+ */
+ ip_masq_lock(&portfw_lock, 0);
+
+ if ((pf=ip_portfw_lookup(iph->protocol,
+ portp[1], iph->daddr,
+ &raddr, &rport))) {
+ ms = ip_masq_new(iph->protocol,
+ iph->daddr, portp[1],
+ raddr, rport,
+ iph->saddr, portp[0],
+ 0);
+ ip_masq_listen(ms);
+
+ if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1 ||
+ ip_masq_nlocks(&portfw_lock) != 1)
+ /*
+ * Maybe later...
+ */
+ goto out;
+
+ /*
+ * Entry created, lock==1.
+ * if pref_cnt == 0, move
+ * entry at _tail_.
+ * This is a simple load balance scheduling
+ */
+
+ if (atomic_dec_and_test(&pf->pref_cnt)) {
+ start_bh_atomic();
+
+ atomic_set(&pf->pref_cnt, pf->pref);
+ list_del(&pf->list);
+ list_add(&pf->list,
+ portfw_list[portfw_idx(iph->protocol)].prev);
+
+ end_bh_atomic();
+ }
+ }
+out:
+ ip_masq_unlock(&portfw_lock, 0);
+ return ms;
+}
+
+#define portfw_in_update NULL
+#define portfw_out_rule NULL
+#define portfw_out_create NULL
+#define portfw_out_update NULL
+
+static struct ip_masq_mod portfw_mod = {
+ NULL, /* next */
+ NULL, /* next_reg */
+ "portfw", /* name */
+ ATOMIC_INIT(0), /* nent */
+ ATOMIC_INIT(0), /* refcnt */
+ proc_ent,
+ portfw_ctl,
+ NULL, /* masq_mod_init */
+ NULL, /* masq_mod_done */
+ portfw_in_rule,
+ portfw_in_update,
+ portfw_in_create,
+ portfw_out_rule,
+ portfw_out_update,
+ portfw_out_create,
+};
+
+
+
+__initfunc(int ip_portfw_init(void))
+{
+ INIT_LIST_HEAD(&portfw_list[0]);
+ INIT_LIST_HEAD(&portfw_list[1]);
+ return register_ip_masq_mod ((mmod_self=&portfw_mod));
+}
+
+int ip_portfw_done(void)
+{
+ return unregister_ip_masq_mod(&portfw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_portfw_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_portfw_done() != 0)
+ printk(KERN_INFO "ip_portfw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/net/ipv4/ip_masq_quake.c b/net/ipv4/ip_masq_quake.c
index 482096f2b..fb0978175 100644
--- a/net/ipv4/ip_masq_quake.c
+++ b/net/ipv4/ip_masq_quake.c
@@ -11,6 +11,7 @@
* Harald Hoyer : Unofficial Quake Specs found at
* http://www.gamers.org/dEngine/quake/spec/
* Harald Hoyer : Check for QUAKE-STRING
+ * Juan Jose Ciarlante : litl bits for 2.1
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -73,7 +74,7 @@ masq_quake_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
}
int
-masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p)
+masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
{
struct sk_buff *skb;
struct iphdr *iph;
@@ -234,7 +235,8 @@ masq_quake_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **s
memcpy(&udp_port, data, 2);
- n_ms = ip_masq_new(maddr, IPPROTO_UDP,
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
ms->saddr, htons(udp_port),
ms->daddr, ms->dport,
0);
@@ -249,6 +251,10 @@ masq_quake_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **s
udp_port = ntohs(n_ms->mport);
memcpy(data, &udp_port, 2);
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+ ip_masq_put(n_ms);
+
break;
}
diff --git a/net/ipv4/ip_masq_raudio.c b/net/ipv4/ip_masq_raudio.c
index 26b5cd4da..d68be7555 100644
--- a/net/ipv4/ip_masq_raudio.c
+++ b/net/ipv4/ip_masq_raudio.c
@@ -2,11 +2,13 @@
* IP_MASQ_RAUDIO - Real Audio masquerading module
*
*
- * Version: @(#)$Id: ip_masq_raudio.c,v 1.7 1997/09/16 18:43:40 kuznet Exp $
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.8 1997/11/28 15:32:32 alan Exp $
*
* Author: Nigel Metheringham
+ * Real Time Streaming code by Progressive Networks
* [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
* [Real Audio information taken from Progressive Networks firewall docs]
+ * [Kudos to Progressive Networks for making the protocol specs available]
*
*
*
@@ -31,16 +33,40 @@
*
* At present the "first packet" is defined as a packet starting with
* the protocol ID string - "PNA".
- * When the link is up there appears to be enough control data
+ * When the link is up there appears to be enough control data
* crossing the control link to keep it open even if a long audio
* piece is playing.
*
+ * The Robust UDP support added in RealAudio 3.0 is supported, but due
+ * to servers/clients not making great use of this has not been greatly
+ * tested. RealVideo (as used in the Real client version 4.0beta1) is
+ * supported but again is not greatly tested (bandwidth requirements
+ * appear to exceed that available at the sites supporting the protocol).
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : Use control_add() for control chan
+ * 10/15/97 - Modifications to allow masquerading of RTSP connections as
+ * well as PNA, which can potentially exist on the same port.
+ * Joe Rumsey <ogre@real.com>
+ *
*/
#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <linux/types.h>
+#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
@@ -50,30 +76,62 @@
#include <net/tcp.h>
#include <net/ip_masq.h>
+/*
#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
#endif
+*/
+
+#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c))
+#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
struct raudio_priv_data {
/* Associated data connection - setup but not used at present */
struct ip_masq *data_conn;
+ /* UDP Error correction connection - setup but not used at present */
+ struct ip_masq *error_conn;
/* Have we seen and performed setup */
short seen_start;
+ short is_rtsp;
};
+int
+masq_rtsp_out (struct ip_masq_app *mapp,
+ struct ip_masq *ms,
+ struct sk_buff **skb_p,
+ __u32 maddr);
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+
static int
masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
{
MOD_INC_USE_COUNT;
if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
- GFP_ATOMIC)) == NULL)
+ GFP_ATOMIC)) == NULL)
printk(KERN_INFO "RealAudio: No memory for application data\n");
- else
+ else
{
- struct raudio_priv_data *priv =
+ struct raudio_priv_data *priv =
(struct raudio_priv_data *)ms->app_data;
priv->seen_start = 0;
priv->data_conn = NULL;
+ priv->error_conn = NULL;
+ priv->is_rtsp = 0;
}
return 0;
}
@@ -96,34 +154,43 @@ masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **
char *p, *data, *data_limit;
struct ip_masq *n_ms;
unsigned short version, msg_id, msg_len, udp_port;
- struct raudio_priv_data *priv =
+ struct raudio_priv_data *priv =
(struct raudio_priv_data *)ms->app_data;
/* Everything running correctly already */
if (priv && priv->seen_start)
return 0;
+ if(priv && priv->is_rtsp)
+ return masq_rtsp_out(mapp, ms, skb_p, maddr);
+
skb = *skb_p;
iph = skb->nh.iph;
th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
data = (char *)&th[1];
- data_limit = skb->h.raw + skb->len - 18;
+ data_limit = skb->h.raw + skb->len;
+
+ if(memcmp(data, "OPTIONS", 7) == 0 ||
+ memcmp(data, "DESCRIBE", 8) == 0)
+ {
+ IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n");
+ /* This is an RTSP client */
+ if(priv)
+ priv->is_rtsp = 1;
+ return masq_rtsp_out(mapp, ms, skb_p, maddr);
+ }
/* Check to see if this is the first packet with protocol ID */
if (memcmp(data, "PNA", 3)) {
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
- printk("RealAudio: not initial protocol packet - ignored\n");
-#endif
+ IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - ignored\n");
return(0);
}
data += 3;
memcpy(&version, data, 2);
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
- printk("RealAudio: initial seen - protocol version %d\n",
+ IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n",
ntohs(version));
-#endif
if (priv)
priv->seen_start = 1;
@@ -135,15 +202,22 @@ masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **
}
data += 2;
- while (data < data_limit) {
+ while (data+4 < data_limit) {
memcpy(&msg_id, data, 2);
data += 2;
memcpy(&msg_len, data, 2);
data += 2;
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
- printk("RealAudio: msg %d - %d byte\n",
+ if (ntohs(msg_id) == 0) {
+ /* The zero tag indicates the end of options */
+ IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n");
+ return 0;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n",
ntohs(msg_id), ntohs(msg_len));
-#endif
+ if (ntohs(msg_id) == 0) {
+ /* The zero tag indicates the end of options */
+ return 0;
+ }
p = data;
data += ntohs(msg_len);
if (data > data_limit)
@@ -151,39 +225,272 @@ masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **
printk(KERN_INFO "RealAudio: Packet too short for data\n");
return 0;
}
- if (ntohs(msg_id) == 1) {
- /* This is a message detailing the UDP port to be used */
+ if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
+ /*
+ * MsgId == 1
+ * Audio UDP data port on client
+ *
+ * MsgId == 7
+ * Robust UDP error correction port number on client
+ *
+ * Since these messages are treated just the same, they
+ * are bundled together here....
+ */
memcpy(&udp_port, p, 2);
- n_ms = ip_masq_new(maddr, IPPROTO_UDP,
- ms->saddr, udp_port,
- ms->daddr, 0,
- IP_MASQ_F_NO_DPORT);
+
+ /*
+ * Sometimes a server sends a message 7 with a zero UDP port
+ * Rather than do anything with this, just ignore it!
+ */
+ if (udp_port == 0)
+ continue;
+
+
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
if (n_ms==NULL)
return 0;
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+
memcpy(p, &(n_ms->mport), 2);
-#if DEBUG_CONFIG_IP_MASQ_RAUDIO
- printk("RealAudio: rewrote UDP port %d -> %d\n",
- ntohs(udp_port), ntohs(n_ms->mport));
-#endif
- ip_masq_set_expire(n_ms, ip_masq_expire->udp_timeout);
+ IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d in msg %d\n",
+ ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id));
/* Make ref in application data to data connection */
- if (priv)
- priv->data_conn = n_ms;
+ if (priv) {
+ if (ntohs(msg_id) == 1)
+ priv->data_conn = n_ms;
+ else
+ priv->error_conn = n_ms;
+ }
+
+ ip_masq_put(n_ms);
+ }
+ }
+ return 0;
+}
- /*
- * There is nothing else useful we can do
- * Maybe a development could do more, but for now
- * we exit gracefully!
- */
- return 0;
+/*
+ * masq_rtsp_out
+ *
+ *
+ */
+int
+masq_rtsp_out (struct ip_masq_app *mapp,
+ struct ip_masq *ms,
+ struct sk_buff **skb_p,
+ __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ struct ip_masq *n_ms, *n_ms2;
+ unsigned short udp_port;
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+ const char* srch = "transport:";
+ const char* srchpos = srch;
+ const char* srchend = srch + strlen(srch);
+ int state = 0;
+ char firstport[6];
+ int firstportpos = 0;
+ char secondport[6];
+ int secondportpos = 0;
+ char *portstart = NULL, *portend = NULL;
+ int diff;
- } else if (ntohs(msg_id) == 0)
+ /* Everything running correctly already */
+ if (priv && priv->seen_start)
+ return 0;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len;
+
+ firstport[0] = 0;
+ secondport[0] = 0;
+
+ while(data < data_limit && state >= 0)
+ {
+ switch(state)
+ {
+ case 0:
+ case 1:
+ if(TOLOWER(*data) == *srchpos)
+ {
+ srchpos++;
+ if(srchpos == srchend)
+ {
+ IP_MASQ_DEBUG(1-debug, "Found string %s in message\n",
+ srch);
+ state++;
+ if(state == 1)
+ {
+ srch = "client_port";
+ srchpos = srch;
+ srchend = srch + strlen(srch);
+ }
+ }
+ }
+ else
+ {
+ srchpos = srch;
+ }
+ break;
+ case 2:
+ if(*data == '=')
+ state = 3;
+ break;
+ case 3:
+ if(ISDIGIT(*data))
+ {
+ portstart = data;
+ firstportpos = 0;
+ firstport[firstportpos++] = *data;
+ state = 4;
+ }
+ break;
+ case 4:
+ if(*data == '-')
+ {
+ state = 5;
+ }
+ else if(*data == ';')
+ {
+ portend = data - 1;
+ firstport[firstportpos] = 0;
+ state = -1;
+ }
+ else if(ISDIGIT(*data))
+ {
+ firstport[firstportpos++] = *data;
+ }
+ else if(*data != ' ' && *data != '\t')
+ {
+ /* This is a badly formed RTSP message, let's bail out */
+ IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
return 0;
+ }
+ break;
+ case 5:
+ if(ISDIGIT(*data))
+ {
+ secondportpos = 0;
+ secondport[secondportpos++] = *data;
+ state = 6;
+ }
+ else if(*data == ';')
+ {
+ portend = data - 1;
+ secondport[secondportpos] = 0;
+ state = -1;
+ }
+ break;
+ case 6:
+ if(*data == ';')
+ {
+ portend = data - 1;
+ secondport[secondportpos] = 0;
+ state = -1;
+ }
+ else if(ISDIGIT(*data))
+ {
+ secondport[secondportpos++] = *data;
+ }
+ else if(*data != ' ' && *data != '\t')
+ {
+ /* This is a badly formed RTSP message, let's bail out */
+ IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
+ return 0;
+ }
+ break;
+ }
+ data++;
}
- return 0;
+
+ if(state >= 0)
+ return 0;
+
+ if(firstportpos > 0)
+ {
+ char newbuf[12]; /* xxxxx-xxxxx\0 */
+ char* tmpptr;
+
+ udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+ if (n_ms==NULL)
+ return 0;
+
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+
+ if(secondportpos > 0)
+ {
+ udp_port = htons(simple_strtoul(secondport, &tmpptr, 10));
+ n_ms2 = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+ if (n_ms2==NULL) {
+ ip_masq_put(n_ms);
+ return 0;
+ }
+
+ ip_masq_listen(n_ms2);
+ ip_masq_control_add(n_ms2, ms);
+ sprintf(newbuf, "%d-%d", ntohs(n_ms->mport),
+ ntohs(n_ms2->mport));
+ }
+ else
+ {
+ sprintf(newbuf, "%d", ntohs(n_ms->mport));
+ n_ms2 = NULL;
+ }
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+ portstart, portend - portstart + 1,
+ newbuf, strlen(newbuf));
+ IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
+ diff = strlen(newbuf) - (portend - portstart);
+ }
+ else
+ {
+ return 0;
+ }
+
+ if(priv)
+ {
+ priv->seen_start = 1;
+ if(n_ms)
+ priv->data_conn = n_ms;
+ if(n_ms2)
+ priv->error_conn = n_ms2;
+ }
+ /*
+ * Release tunnels
+ */
+
+ if (n_ms)
+ ip_masq_put(n_ms);
+
+ if (n_ms2)
+ ip_masq_put(n_ms2);
+
+ return diff;
}
struct ip_masq_app ip_masq_raudio = {
@@ -203,7 +510,27 @@ struct ip_masq_app ip_masq_raudio = {
__initfunc(int ip_masq_raudio_init(void))
{
- return register_ip_masq_app(&ip_masq_raudio, IPPROTO_TCP, 7070);
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_raudio, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
}
/*
@@ -212,7 +539,22 @@ __initfunc(int ip_masq_raudio_init(void))
int ip_masq_raudio_done(void)
{
- return unregister_ip_masq_app(&ip_masq_raudio);
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "RealAudio: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
}
#ifdef MODULE
diff --git a/net/ipv4/ip_masq_vdolive.c b/net/ipv4/ip_masq_vdolive.c
new file mode 100644
index 000000000..3b74d5f6f
--- /dev/null
+++ b/net/ipv4/ip_masq_vdolive.c
@@ -0,0 +1,291 @@
+/*
+ * IP_MASQ_VDOLIVE - VDO Live masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_vdolive.c,v 1.2 1997/11/28 15:32:35 alan Exp $
+ *
+ * Author: Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
+ * PLAnet Online Ltd
+ *
+ * Fixes: Minor changes for 2.1 by
+ * Steven Clarke <Steven.Clarke@ThePlanet.Net>, Planet Online Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Thanks:
+ * Thank you to VDOnet Corporation for allowing me access to
+ * a protocol description without an NDA. This means that
+ * this module can be distributed as source - a great help!
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+struct vdolive_priv_data {
+ /* Ports used */
+ unsigned short origport;
+ unsigned short masqport;
+ /* State of decode */
+ unsigned short state;
+};
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+static int
+masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data),
+ GFP_ATOMIC)) == NULL)
+ IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n");
+ else
+ {
+ struct vdolive_priv_data *priv =
+ (struct vdolive_priv_data *)ms->app_data;
+ priv->origport = 0;
+ priv->masqport = 0;
+ priv->state = 0;
+ }
+ return 0;
+}
+
+static int
+masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ if (ms->app_data)
+ kfree_s(ms->app_data, sizeof(struct vdolive_priv_data));
+ return 0;
+}
+
+int
+masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ unsigned int tagval; /* This should be a 32 bit quantity */
+ struct ip_masq *n_ms;
+ struct vdolive_priv_data *priv =
+ (struct vdolive_priv_data *)ms->app_data;
+
+ /* This doesn't work at all if no priv data was allocated on startup */
+ if (!priv)
+ return 0;
+
+ /* Everything running correctly already */
+ if (priv->state == 3)
+ return 0;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len;
+
+ if (data+8 > data_limit) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit);
+ return 0;
+ }
+ memcpy(&tagval, data+4, 4);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+
+ /* Check for leading packet ID */
+ if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+ return 0;
+ }
+
+
+ /* Check packet is long enough for data - ignore if not */
+ if ((ntohl(tagval) == 6) && (data+36 > data_limit)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit);
+ return 0;
+ } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) {
+ IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit);
+ return 0;
+ }
+
+ /* Adjust data pointers */
+ /*
+ * I could check the complete protocol version tag
+ * in here however I am just going to look for the
+ * "VDO Live" tag in the hope that this part will
+ * remain constant even if the version changes
+ */
+ if (ntohl(tagval) == 6) {
+ data += 24;
+ IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n");
+ } else {
+ data += 8;
+ IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n");
+ }
+
+ if (memcmp(data, "VDO Live", 8) != 0) {
+ IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n");
+ return 0;
+ }
+ /*
+ * The port number is the next word after the tag.
+ * VDOlive encodes all of these values
+ * in 32 bit words, so in this case I am
+ * skipping the first 2 bytes of the next
+ * word to get to the relevant 16 bits
+ */
+ data += 10;
+
+ /*
+ * If we have not seen the port already,
+ * set the masquerading tunnel up
+ */
+ if (!priv->origport) {
+ memcpy(&priv->origport, data, 2);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport));
+
+ /* Open up a tunnel */
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, priv->origport,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL) {
+ ip_masq_put(n_ms);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport);
+ /* Leave state as unset */
+ priv->origport = 0;
+ return 0;
+ }
+ ip_masq_listen(n_ms);
+
+ ip_masq_put(ms);
+ priv->masqport = n_ms->mport;
+ } else if (memcmp(data, &(priv->origport), 2)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n");
+ /* Write the port in anyhow!!! */
+ }
+
+ /*
+ * Write masq port into packet
+ */
+ memcpy(data, &(priv->masqport), 2);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr);
+
+ /*
+ * Set state bit to make which bit has been done
+ */
+
+ priv->state |= (ntohl(tagval) == 6) ? 1 : 2;
+
+ return 0;
+}
+
+
+struct ip_masq_app ip_masq_vdolive = {
+ NULL, /* next */
+ "VDOlive", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_vdolive_init_1, /* ip_masq_init_1 */
+ masq_vdolive_done_1, /* ip_masq_done_1 */
+ masq_vdolive_out, /* pkt_out */
+ NULL /* pkt_in */
+};
+
+/*
+ * ip_masq_vdolive initialization
+ */
+
+__initfunc(int ip_masq_vdolive_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_vdolive, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n", i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_vdolive fin.
+ */
+
+int ip_masq_vdolive_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug,"VDOlive: unloaded support on port[%d] = %d\n", i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_vdolive_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_vdolive_done() != 0)
+ IP_MASQ_DEBUG(1-debug, "ip_masq_vdolive: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 106236c93..4ed7f7638 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.40 1997/10/12 17:01:48 kuznet Exp $
+ * Version: $Id: ip_output.c,v 1.3 1997/12/16 05:37:41 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -70,6 +70,12 @@
#include <linux/netlink.h>
#include <linux/ipsec.h>
+/*
+ * Shall we try to damage output packets if routing dev changes?
+ */
+
+int sysctl_ip_dynaddr = 0;
+
static void __inline__ ip_ll_header_reserve(struct sk_buff *skb)
{
struct rtable *rt = (struct rtable*)skb->dst;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 080452dd3..2fd2b16ab 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -5,7 +5,7 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.28 1997/11/17 17:36:08 kuznet Exp $
+ * Version: $Id: ip_sockglue.c,v 1.3 1997/12/16 05:37:41 ralf Exp $
*
* Authors: see ip.c
*
@@ -229,7 +229,10 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
int val=0,err;
#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
struct ip_fw tmp_fw;
-#endif
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ char masq_ctl[IP_FW_MASQCTL_MAX];
+#endif
if(optlen>=sizeof(int)) {
if(get_user(val, (int *) optval))
@@ -465,6 +468,20 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
return -err; /* -0 is 0 after all */
#endif
+#ifdef CONFIG_IP_MASQUERADE
+ case IP_FW_MASQ_ADD:
+ case IP_FW_MASQ_DEL:
+ case IP_FW_MASQ_FLUSH:
+ if(!suser())
+ return -EPERM;
+ if(optlen>sizeof(masq_ctl) || optlen<1)
+ return -EINVAL;
+ if(copy_from_user(masq_ctl,optval,optlen))
+ return -EFAULT;
+ err=ip_masq_ctl(optname, masq_ctl,optlen);
+ return -err; /* -0 is 0 after all */
+
+#endif
#ifdef CONFIG_IP_ACCT
case IP_ACCT_INSERT:
case IP_ACCT_APPEND:
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 046c60beb..552b83664 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -5,7 +5,7 @@
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.33 1997/10/24 17:16:08 kuznet Exp $
+ * Version: $Id: route.c,v 1.3 1997/12/16 05:37:45 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1000,6 +1000,8 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
rth->u.dst.pmtu = res.fi->fib_mtu ? : out_dev->dev->mtu;
rth->u.dst.window=res.fi->fib_window ? : 0;
rth->u.dst.rtt = res.fi->fib_rtt ? : TCP_TIMEOUT_INIT;
+ rth->u.dst.rate_last = rth->u.dst.rate_tokens = 0;
+
if (FIB_RES_GW(res) && FIB_RES_NH(res).nh_scope == RT_SCOPE_LINK)
rth->rt_gateway = FIB_RES_GW(res);
@@ -1370,6 +1372,7 @@ make_route:
rth->u.dst.window=0;
rth->u.dst.rtt = TCP_TIMEOUT_INIT;
}
+ rth->u.dst.rate_last = rth->u.dst.rate_tokens = 0;
rth->rt_flags = flags;
rth->rt_type = res.type;
hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index f49514171..637f2f933 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1,7 +1,7 @@
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.21 1997/10/17 01:21:18 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.5 1997/12/16 05:37:46 ralf Exp $
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -47,6 +47,12 @@ extern int sysctl_ipfrag_low_thresh;
extern int sysctl_ipfrag_high_thresh;
extern int sysctl_ipfrag_time;
+/* From ip_output.c */
+extern int sysctl_ip_dynaddr;
+
+/* From ip_masq.c */
+extern int sysctl_ip_masq_debug;
+
extern int sysctl_tcp_cong_avoidance;
extern int sysctl_tcp_hoe_retransmits;
extern int sysctl_tcp_sack;
@@ -198,6 +204,12 @@ ctl_table ipv4_table[] = {
&sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
{NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
&sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IP_DYNADDR, "ip_dynaddr",
+ &sysctl_ip_dynaddr, sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_IP_MASQUERADE
+ {NET_IPV4_IP_MASQ_DEBUG, "ip_masq_debug",
+ &sysctl_ip_masq_debug, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
{NET_IPV4_IPFRAG_TIME, "ipfrag_time",
&sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
{NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes",
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 10c7cd4f4..8c75bce3e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.74 1997/10/30 23:52:27 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.76 1997/12/07 04:44:19 freitag Exp $
*
* IPv4 specific functions
*
@@ -40,6 +40,7 @@
* Added tail drop and some other bugfixes.
* Added new listen sematics (ifdefed by
* NEW_LISTEN for now)
+ * Juan Jose Ciarlante: ip_dynaddr bits
*/
#include <linux/config.h>
@@ -47,6 +48,7 @@
#include <linux/fcntl.h>
#include <linux/random.h>
#include <linux/ipsec.h>
+#include <linux/inet.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -59,6 +61,7 @@ extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_syncookies;
+extern int sysctl_ip_dynaddr;
/* Check TCP sequence numbers in ICMP packets. */
#define ICMP_PARANOIA 1
@@ -846,31 +849,6 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
return;
}
- /* pointless, because we have no way to retry when sk is locked.
- But the socket should be really locked here for better interaction
- with the socket layer. This needs to be solved for SMP
- (I would prefer an "ICMP backlog").
-
- tcp_v4_err is called only from bh, so that lock_sock is pointless,
- even in commented form :-) --ANK
-
- Note "for SMP" ;) -AK
-
- Couple of notes about backlogging:
- - error_queue could be used for it.
- - could, but MUST NOT :-), because:
- a) it is not clear,
- who will process deferred messages.
- b) ICMP is not reliable by design, so that you can safely
- drop ICMP messages. Besides that, if ICMP really arrived
- it is very unlikely, that socket is locked. --ANK
-
- I don't think it's unlikely that sk is locked. With the
- open_request stuff there is much more stress on the main
- LISTEN socket. I just want to make sure that all ICMP unreachables
- destroy unneeded open_requests as reliable as possible (for
- syn flood protection) -AK
- */
tp = &sk->tp_pinfo.af_tcp;
#ifdef ICMP_PARANOIA
seq = ntohl(th->seq);
@@ -1617,10 +1595,31 @@ int tcp_v4_rebuild_header(struct sock *sk, struct sk_buff *skb)
struct iphdr *iph;
struct tcphdr *th;
int size;
+ int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT;
/* Check route */
rt = (struct rtable*)skb->dst;
+
+ /* Force route checking if want_rewrite */
+ if (want_rewrite) {
+ int tmp;
+ __u32 old_saddr = rt->rt_src;
+
+ /* Query new route */
+ tmp = ip_route_connect(&rt, rt->rt_dst, 0,
+ RT_TOS(sk->ip_tos)|(sk->localroute||0),
+ sk->bound_dev_if);
+
+ /* Only useful if different source addrs */
+ if (tmp == 0 || rt->rt_src != old_saddr ) {
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+ } else {
+ want_rewrite = 0;
+ dst_release(&rt->u.dst);
+ }
+ } else
if (rt->u.dst.obsolete) {
int err;
err = ip_route_output(&rt, rt->rt_dst, rt->rt_src, rt->key.tos, rt->key.oif);
@@ -1640,6 +1639,50 @@ int tcp_v4_rebuild_header(struct sock *sk, struct sk_buff *skb)
th = skb->h.th;
size = skb->tail - skb->h.raw;
+ if (want_rewrite) {
+ __u32 new_saddr = rt->rt_src;
+
+ /*
+ * Ouch!, this should not happen.
+ */
+ if (!sk->saddr || !sk->rcv_saddr) {
+ printk(KERN_WARNING "tcp_v4_rebuild_header(): not valid sock addrs: saddr=%08lX rcv_saddr=%08lX\n",
+ ntohl(sk->saddr),
+ ntohl(sk->rcv_saddr));
+ return 0;
+ }
+
+ /*
+ * Maybe whe are in a skb chain loop and socket address has
+ * yet been 'damaged'.
+ */
+
+ if (new_saddr != sk->saddr) {
+ if (sysctl_ip_dynaddr > 1) {
+ printk(KERN_INFO "tcp_v4_rebuild_header(): shifting sk->saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(sk->saddr),
+ NIPQUAD(new_saddr));
+ }
+
+ sk->saddr = new_saddr;
+ sk->rcv_saddr = new_saddr;
+ /* sk->prot->rehash(sk); */
+ tcp_v4_rehash(sk);
+ }
+
+ if (new_saddr != iph->saddr) {
+ if (sysctl_ip_dynaddr > 1) {
+ printk(KERN_INFO "tcp_v4_rebuild_header(): shifting iph->saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(iph->saddr),
+ NIPQUAD(new_saddr));
+ }
+
+ iph->saddr = new_saddr;
+ ip_send_check(iph);
+ }
+
+ }
+
return 0;
}
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 5cb05d55b..1d804a864 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_timer.c,v 1.31 1997/11/05 08:14:01 freitag Exp $
+ * Version: $Id: tcp_timer.c,v 1.4 1997/12/16 05:37:48 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -44,6 +44,8 @@ struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {
{ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive} /* KEEPALIVE */
};
+const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+
/*
* Using different timers for retransmit, delayed acks and probes
* We may wish use just one timer maintaining a list of expire jiffies
@@ -112,45 +114,6 @@ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when)
};
}
-void tcp_clear_xmit_timer(struct sock *sk, int what)
-{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-
- switch (what) {
- case TIME_RETRANS:
- del_timer(&tp->retransmit_timer);
- break;
- case TIME_DACK:
- del_timer(&tp->delack_timer);
- break;
- case TIME_PROBE0:
- del_timer(&tp->probe_timer);
- break;
- default:
- printk(KERN_DEBUG "bug: unknown timer value\n");
- };
-}
-
-int tcp_timer_is_set(struct sock *sk, int what)
-{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-
- switch (what) {
- case TIME_RETRANS:
- return tp->retransmit_timer.next != NULL;
- break;
- case TIME_DACK:
- return tp->delack_timer.next != NULL;
- break;
- case TIME_PROBE0:
- return tp->probe_timer.next != NULL;
- break;
- default:
- printk(KERN_DEBUG "bug: unknown timer value\n");
- };
- return 0;
-}
-
void tcp_clear_xmit_timers(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -160,6 +123,25 @@ void tcp_clear_xmit_timers(struct sock *sk)
del_timer(&tp->probe_timer);
}
+static int tcp_write_err(struct sock *sk, int force)
+{
+ sk->err = sk->err_soft ? sk->err_soft : ETIMEDOUT;
+ sk->error_report(sk);
+
+ tcp_clear_xmit_timers(sk);
+
+ /* Time wait the socket. */
+ if (!force && (1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
+ tcp_set_state(sk,TCP_TIME_WAIT);
+ tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ } else {
+ /* Clean up time. */
+ tcp_set_state(sk, TCP_CLOSE);
+ return 0;
+ }
+ return 1;
+}
+
/*
* A write timeout has occurred. Process the after effects. BROKEN (badly)
*/
@@ -172,10 +154,7 @@ static int tcp_write_timeout(struct sock *sk)
* Look for a 'soft' timeout.
*/
if ((sk->state == TCP_ESTABLISHED &&
-
- /* Eric, what the heck is this doing?!?! */
- tp->retransmits && !(tp->retransmits & 7)) ||
-
+ tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) ||
(sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
/* Attempt to recover if arp has changed (unlikely!) or
* a route has shifted (not supported prior to 1.3).
@@ -185,42 +164,15 @@ static int tcp_write_timeout(struct sock *sk)
/* Have we tried to SYN too many times (repent repent 8)) */
if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
- if(sk->err_soft)
- sk->err=sk->err_soft;
- else
- sk->err=ETIMEDOUT;
-#ifdef TCP_DEBUG
- printk(KERN_DEBUG "syn timeout\n");
-#endif
-
- sk->error_report(sk);
- tcp_clear_xmit_timers(sk);
- tcp_statistics.TcpAttemptFails++; /* Is this right ??? - FIXME - */
- tcp_set_state(sk,TCP_CLOSE);
+ tcp_write_err(sk, 1);
/* Don't FIN, we got nothing back */
return 0;
}
/* Has it gone just too far? */
- if (tp->retransmits > sysctl_tcp_retries2) {
- if(sk->err_soft)
- sk->err = sk->err_soft;
- else
- sk->err = ETIMEDOUT;
- sk->error_report(sk);
-
- tcp_clear_xmit_timers(sk);
+ if (tp->retransmits > sysctl_tcp_retries2)
+ return tcp_write_err(sk, 0);
- /* Time wait the socket. */
- if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
- tcp_set_state(sk,TCP_TIME_WAIT);
- tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- } else {
- /* Clean up time. */
- tcp_set_state(sk, TCP_CLOSE);
- return 0;
- }
- }
return 1;
}
@@ -251,7 +203,8 @@ void tcp_probe_timer(unsigned long data) {
}
/*
- * *WARNING* RFC 1122 forbids this
+ * *WARNING* RFC 1122 forbids this
+ * It doesn't AFAIK, because we kill the retransmit timer -AK
* FIXME: We ought not to do it, Solaris 2.5 actually has fixing
* this behaviour in Solaris down as a bug fix. [AC]
*/
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 42a3df7ca..84586867f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.44 1997/10/15 19:56:35 freitag Exp $
+ * Version: $Id: udp.c,v 1.2 1997/12/16 05:37:48 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -53,6 +53,8 @@
* Last socket cache retained as it
* does have a high hit rate.
* Olaf Kirch : Don't linearise iovec on sendmsg.
+ * Andi Kleen : Some cleanups, cache destination entry
+ * for connect.
*
*
* This program is free software; you can redistribute it and/or
@@ -69,7 +71,7 @@
MUST pass IP options from IP -> application (OK)
MUST allow application to specify IP options (OK)
4.1.3.3 (ICMP Messages)
- MUST pass ICMP error messages to application (OK)
+ MUST pass ICMP error messages to application (OK -- except when SO_BSDCOMPAT is set)
4.1.3.4 (UDP Checksums)
MUST provide facility for checksumming (OK)
MAY allow application to control checksumming (OK)
@@ -78,12 +80,10 @@
4.1.3.5 (UDP Multihoming)
MUST allow application to specify source address (OK)
SHOULD be able to communicate the chosen src addr up to application
- when application doesn't choose (NOT YET - doesn't seem to be in the BSD API)
- [Does opening a SOCK_PACKET and snooping your output count 8)]
+ when application doesn't choose (DOES - use recvmsg cmsgs)
4.1.3.6 (Invalid Addresses)
MUST discard invalid source addresses (OK -- done in the new routing code)
- MUST only send datagrams with one of our addresses (NOT YET - ought to be OK )
- 950728 -- MS
+ MUST only send datagrams with one of our addresses (OK)
*/
#include <asm/system.h>
@@ -459,8 +459,6 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk,
return s;
}
-#define min(a,b) ((a)<(b)?(a):(b))
-
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
@@ -497,33 +495,27 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
kfree_skb(skb2, FREE_READ);
}
- if (type == ICMP_SOURCE_QUENCH) {
-#if 0 /* FIXME: If you check the rest of the code, this is a NOP!
- * Someone figure out what we were trying to be doing
- * here. Besides, cong_window is a TCP thing and thus
- * I moved it out of normal sock and into tcp_opt.
- */
- /* Slow down! */
- if (sk->cong_window > 1)
- sk->cong_window = sk->cong_window/2;
-#endif
+ switch (type) {
+ case ICMP_SOURCE_QUENCH:
return;
- }
-
- if (type == ICMP_PARAMETERPROB)
- {
+ case ICMP_PARAMETERPROB:
sk->err = EPROTO;
sk->error_report(sk);
return;
- }
-
- if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
- {
- if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
- sk->err = EMSGSIZE;
- sk->error_report(sk);
+ case ICMP_DEST_UNREACH:
+ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+ if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
+ /*
+ * There should be really a way to pass the
+ * discovered MTU value back to the user (the
+ * ICMP layer did all the work for us)
+ */
+ sk->err = EMSGSIZE;
+ sk->error_report(sk);
+ }
+ return;
}
- return;
+ break;
}
/*
@@ -622,8 +614,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
int ulen = len + sizeof(struct udphdr);
struct ipcm_cookie ipc;
struct udpfakehdr ufh;
- struct rtable *rt;
- int free = 0;
+ struct rtable *rt = NULL;
+ int free = 0, localroute = 0;
u32 daddr;
u8 tos;
int err;
@@ -635,12 +627,13 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
* Check the flags.
*/
- if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */
+ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */
return -EOPNOTSUPP;
if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT))
return -EINVAL;
+
/*
* Get and verify the address.
*/
@@ -660,11 +653,13 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
ufh.uh.dest = usin->sin_port;
if (ufh.uh.dest == 0)
return -EINVAL;
+ /* XXX: is a one-behind cache for the dst_entry worth it? */
} else {
if (sk->state != TCP_ESTABLISHED)
return -EINVAL;
ufh.daddr = sk->daddr;
ufh.uh.dest = sk->dummy_th.dest;
+ rt = (struct rtable *)sk->dst_cache;
}
ipc.addr = sk->saddr;
@@ -688,9 +683,13 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
return -EINVAL;
daddr = ipc.opt->faddr;
}
- tos = RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||
- (ipc.opt && ipc.opt->is_strictroute));
-
+ tos = RT_TOS(sk->ip_tos);
+ if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||
+ (ipc.opt && ipc.opt->is_strictroute)) {
+ tos |= 1;
+ rt = NULL; /* sorry */
+ }
+
if (MULTICAST(daddr)) {
if (!ipc.oif)
ipc.oif = sk->ip_mc_index;
@@ -698,17 +697,15 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
ufh.saddr = sk->ip_mc_addr;
}
- err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
-
- if (err) {
- if (free) kfree(ipc.opt);
- return err;
- }
+ if (rt == NULL) {
+ err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
+ if (err)
+ goto out;
+ localroute = 1;
- if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) {
- if (free) kfree(ipc.opt);
- ip_rt_put(rt);
- return -EACCES;
+ err = -EACCES;
+ if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast)
+ goto out;
}
ufh.saddr = rt->rt_src;
@@ -727,15 +724,13 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
/* violation above. -- MS */
lock_sock(sk);
- if (sk->no_check)
- err = ip_build_xmit(sk, udp_getfrag_nosum, &ufh, ulen,
- &ipc, rt, msg->msg_flags);
- else
- err = ip_build_xmit(sk, udp_getfrag, &ufh, ulen,
- &ipc, rt, msg->msg_flags);
- ip_rt_put(rt);
+ err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,
+ &ufh, ulen, &ipc, rt, msg->msg_flags);
release_sock(sk);
+out:
+ if (localroute)
+ ip_rt_put(rt);
if (free)
kfree(ipc.opt);
if (!err) {
@@ -776,7 +771,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
* of this packet since that is all
* that will be read.
*/
- amount = skb->len-sizeof(struct udphdr);
+ amount = skb->tail - skb->h.raw;
}
return put_user(amount, (int *)arg);
}
@@ -905,6 +900,9 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (usin->sin_family && usin->sin_family != AF_INET)
return(-EAFNOSUPPORT);
+ dst_release(sk->dst_cache);
+ sk->dst_cache = NULL;
+
err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
sk->ip_tos|sk->localroute, sk->bound_dev_if);
if (err)
@@ -920,9 +918,11 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->daddr = rt->rt_dst;
sk->dummy_th.dest = usin->sin_port;
sk->state = TCP_ESTABLISHED;
+
if(uh_cache_sk == sk)
uh_cache_sk = NULL;
- ip_rt_put(rt);
+
+ sk->dst_cache = &rt->u.dst;
return(0);
}
@@ -1074,13 +1074,6 @@ int udp_rcv(struct sk_buff *skb, unsigned short len)
return(0);
}
- /* RFC1122 warning: According to 4.1.3.6, we MUST discard any */
- /* datagram which has an invalid source address, either here or */
- /* in IP. */
- /* Right now, IP isn't doing it, and neither is UDP. It's on the */
- /* FIXME list for IP, though, so I wouldn't worry about it. */
- /* (That's the Right Place to do it, IMHO.) -- MS */
-
if (uh->check &&
(((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,len,saddr,daddr,skb->csum)) ||
((skb->ip_summed==CHECKSUM_NONE) &&
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 6e69b8813..c66902f13 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.28 1997/11/05 20:20:43 kuznet Exp $
+ * $Id: addrconf.c,v 1.30 1997/12/09 17:12:47 freitag Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -18,6 +18,8 @@
*
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
+ * Andi Kleen : kill doube kfree on module
+ * unload.
*/
#include <linux/config.h>
@@ -1045,7 +1047,6 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
return NOTIFY_OK;
}
-
static int addrconf_ifdown(struct device *dev)
{
struct inet6_dev *idev, **bidev;
@@ -1067,6 +1068,8 @@ static int addrconf_ifdown(struct device *dev)
if (idev == NULL) {
end_bh_atomic();
+
+ printk(KERN_DEBUG "addrconf_ifdown: invalid device %p\n",dev);
return -ENODEV;
}
@@ -1403,13 +1406,10 @@ void addrconf_cleanup(void)
*/
for (i=0; i < IN6_ADDR_HSIZE; i++) {
- for (idev = inet6_dev_lst[i]; idev; ) {
- struct inet6_dev *back;
-
+ struct inet6_dev *next;
+ for (idev = inet6_dev_lst[i]; idev; idev = next) {
+ next = idev->next;
addrconf_ifdown(idev->dev);
- back = idev;
- idev = idev->next;
- kfree(back);
}
}
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 731072fe5..79882845c 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -21,6 +21,7 @@
#include <linux/sunrpc/clnt.h>
#define RPCDBG_FACILITY RPCDBG_SVCDSP
+#define RPC_PARANOIA 1
/*
* Create an RPC service
@@ -162,8 +163,9 @@ svc_exit_thread(struct svc_rqst *rqstp)
}
/*
- * Register an RPC service with the local portmapper. To
- * unregister a service, call this routine with proto and port == 0.
+ * Register an RPC service with the local portmapper.
+ * To unregister a service, call this routine with
+ * proto and port == 0.
*/
int
svc_register(struct svc_serv *serv, int proto, unsigned short port)
@@ -196,7 +198,7 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
continue;
error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
if (error < 0)
- return error;
+ break;
if (port && !dummy) {
error = -EACCES;
break;
@@ -246,14 +248,8 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
serv->sv_stats->rpcbadfmt++;
goto dropit; /* drop request */
}
- if (vers != 2) { /* RPC version number */
- serv->sv_stats->rpcbadfmt++;
- resp->buf[-1] = xdr_one; /* REJECT */
- svc_putlong(resp, xdr_zero); /* RPC_MISMATCH */
- svc_putlong(resp, xdr_two); /* Only RPCv2 supported */
- svc_putlong(resp, xdr_two);
- goto error;
- }
+ if (vers != 2) /* RPC version number */
+ goto err_bad_rpc;
rqstp->rq_prog = prog = ntohl(*bufp++); /* program number */
rqstp->rq_vers = vers = ntohl(*bufp++); /* version number */
@@ -269,50 +265,23 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
*/
svc_authenticate(rqstp, &rpc_stat, &auth_stat);
- if (rpc_stat != rpc_success) {
- serv->sv_stats->rpcbadfmt++;
- svc_putlong(resp, rpc_garbage_args);
- goto error;
- }
+ if (rpc_stat != rpc_success)
+ goto err_garbage;
- if (auth_stat != rpc_auth_ok) {
- dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat));
- serv->sv_stats->rpcbadauth++;
- resp->buf[-1] = xdr_one; /* REJECT */
- svc_putlong(resp, xdr_one); /* AUTH_ERROR */
- svc_putlong(resp, auth_stat); /* status */
- goto error;
- return svc_send(rqstp);
- }
+ if (auth_stat != rpc_auth_ok)
+ goto err_bad_auth;
progp = serv->sv_program;
- if (prog != progp->pg_prog) {
- dprintk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
- serv->sv_stats->rpcbadfmt++;
- svc_putlong(resp, rpc_prog_unavail);
- goto error;
- return svc_send(rqstp);
- }
+ if (prog != progp->pg_prog)
+ goto err_bad_prog;
versp = progp->pg_vers[vers];
- if (!versp || vers >= progp->pg_nvers) {
- dprintk("svc: unknown version (%d)\n", vers);
- serv->sv_stats->rpcbadfmt++;
- svc_putlong(resp, rpc_prog_mismatch);
- svc_putlong(resp, htonl(progp->pg_lovers));
- svc_putlong(resp, htonl(progp->pg_hivers));
- goto error;
- return svc_send(rqstp);
- }
+ if (!versp || vers >= progp->pg_nvers)
+ goto err_bad_vers;
procp = versp->vs_proc + proc;
- if (proc >= versp->vs_nproc || !procp->pc_func) {
- dprintk("svc: unknown procedure (%d)\n", proc);
- serv->sv_stats->rpcbadfmt++;
- svc_putlong(resp, rpc_proc_unavail);
- goto error;
- return svc_send(rqstp);
- }
+ if (proc >= versp->vs_nproc || !procp->pc_func)
+ goto err_unknown;
rqstp->rq_server = serv;
rqstp->rq_procinfo = procp;
@@ -334,16 +303,10 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
if (!versp->vs_dispatch) {
/* Decode arguments */
xdr = procp->pc_decode;
- if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
- dprintk("svc: failed to decode args\n");
- serv->sv_stats->rpcbadfmt++;
- svc_putlong(resp, rpc_garbage_args);
- goto error;
- }
+ if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp))
+ goto err_garbage;
- *statp = procp->pc_func(rqstp,
- rqstp->rq_argp,
- rqstp->rq_resp);
+ *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
/* Encode reply */
if (*statp == rpc_success && (xdr = procp->pc_encode)
@@ -374,6 +337,55 @@ dropit:
svc_drop(rqstp);
return 0;
+err_bad_rpc:
+ serv->sv_stats->rpcbadfmt++;
+ resp->buf[-1] = xdr_one; /* REJECT */
+ svc_putlong(resp, xdr_zero); /* RPC_MISMATCH */
+ svc_putlong(resp, xdr_two); /* Only RPCv2 supported */
+ svc_putlong(resp, xdr_two);
+ goto error;
+
+err_bad_auth:
+ dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat));
+ serv->sv_stats->rpcbadauth++;
+ resp->buf[-1] = xdr_one; /* REJECT */
+ svc_putlong(resp, xdr_one); /* AUTH_ERROR */
+ svc_putlong(resp, auth_stat); /* status */
+ goto error;
+
+err_bad_prog:
+#ifdef RPC_PARANOIA
+ printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
+#endif
+ serv->sv_stats->rpcbadfmt++;
+ svc_putlong(resp, rpc_prog_unavail);
+ goto error;
+
+err_bad_vers:
+#ifdef RPC_PARANOIA
+ printk("svc: unknown version (%d)\n", vers);
+#endif
+ serv->sv_stats->rpcbadfmt++;
+ svc_putlong(resp, rpc_prog_mismatch);
+ svc_putlong(resp, htonl(progp->pg_lovers));
+ svc_putlong(resp, htonl(progp->pg_hivers));
+ goto error;
+
+err_unknown:
+#ifdef RPC_PARANOIA
+ printk("svc: unknown procedure (%d)\n", proc);
+#endif
+ serv->sv_stats->rpcbadfmt++;
+ svc_putlong(resp, rpc_proc_unavail);
+ goto error;
+
+err_garbage:
+#ifdef RPC_PARANOIA
+ printk("svc: failed to decode args\n");
+#endif
+ serv->sv_stats->rpcbadfmt++;
+ svc_putlong(resp, rpc_garbage_args);
+
error:
return svc_send(rqstp);
}