]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Linux-0.96a (May 22, 1992 ??) 0.96a
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:00 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:00 +0000 (15:09 -0500)
More VFS cleanups.  Minixfs code reorganized to be more logical, and
split up into a few new files.

SCSI support!!

 - Drew Eckhardt does the SCSI stuff, and does the ST01/ST02 lowlevel
   driver.

 - Ultrastor driver by David Gentzel.

 - Tommy Thorn shows up again.  He did the Danish keyboard tables, now
   he does the AHA 1542 driver.  Ten years later we ended up being
   co-workers at Transmeta ;)

First networking code appears: X11 port needs UNIX domain sockets, and
thus the "socketcall()" system call.  It's not really meant for real
networking, although the code will eventually evolve to support that.
Which explains some of the bad early decisions..  ;)

Werner Almerberger starts taking over floppy driver maintenance.  Thank
Gods!

Johan Myreen translates my assembly-level keyboard driver into C code,
and adds support for diacriticals.

OMAGIC a.out format support

Syslog support for the kernel appears.  If I remember correctly, this
was Peter MacDonald, but no mention of that in the sources.

135 files changed:
.version
Makefile
fs/Makefile
fs/block_dev.c
fs/buffer.c
fs/char_dev.c [deleted file]
fs/exec.c
fs/fcntl.c
fs/inode.c
fs/ioctl.c
fs/minix/Makefile
fs/minix/bitmap.c
fs/minix/blkdev.c [new file with mode: 0644]
fs/minix/chrdev.c [new file with mode: 0644]
fs/minix/dir.c [new file with mode: 0644]
fs/minix/file.c [new file with mode: 0644]
fs/minix/file_dev.c [deleted file]
fs/minix/inode.c
fs/minix/minix_op.c [deleted file]
fs/minix/namei.c
fs/minix/symlink.c [new file with mode: 0644]
fs/minix/truncate.c
fs/namei.c
fs/open.c
fs/pipe.c
fs/read_write.c
fs/select.c
fs/super.c
include/asm/io.h
include/asm/system.h
include/ctype.h [deleted file]
include/errno.h
include/linux/config.dist.h [new file with mode: 0644]
include/linux/config.h
include/linux/config.site.h [new file with mode: 0644]
include/linux/config_rel.h
include/linux/config_ver.h
include/linux/ctype.h [new file with mode: 0644]
include/linux/fd.h [new file with mode: 0644]
include/linux/fdreg.h
include/linux/fs.h
include/linux/kernel.h
include/linux/lp.h
include/linux/minix_fs.h
include/linux/sched.h
include/linux/string.h [new file with mode: 0644]
include/linux/sys.h
include/linux/timer.h
include/linux/tty.h
include/linux/unistd.h [new file with mode: 0644]
include/string.h [deleted file]
include/sys/kd.h [new file with mode: 0644]
include/sys/mman.h [new file with mode: 0644]
include/sys/resource.h
include/sys/socket.h [new file with mode: 0644]
include/sys/stat.h
include/sys/types.h
include/sys/un.h [new file with mode: 0644]
include/sys/vfs.h [new file with mode: 0644]
include/sys/vt.h [new file with mode: 0644]
include/termios.h
include/unistd.h
init/main.c
kernel/Makefile
kernel/asm.s
kernel/blk_drv/Makefile
kernel/blk_drv/blk.h
kernel/blk_drv/floppy.c
kernel/blk_drv/hd.c
kernel/blk_drv/ll_rw_blk.c
kernel/blk_drv/ramdisk.c
kernel/blk_drv/scsi/Makefile [new file with mode: 0644]
kernel/blk_drv/scsi/aha1542.c [new file with mode: 0644]
kernel/blk_drv/scsi/aha1542.h [new file with mode: 0644]
kernel/blk_drv/scsi/config.in [new file with mode: 0644]
kernel/blk_drv/scsi/hosts.c [new file with mode: 0644]
kernel/blk_drv/scsi/hosts.h [new file with mode: 0644]
kernel/blk_drv/scsi/scsi.c [new file with mode: 0644]
kernel/blk_drv/scsi/scsi.h [new file with mode: 0644]
kernel/blk_drv/scsi/scsi_ioctl.c [new file with mode: 0644]
kernel/blk_drv/scsi/scsi_ioctl.h [new file with mode: 0644]
kernel/blk_drv/scsi/sd.c [new file with mode: 0644]
kernel/blk_drv/scsi/sd.h [new file with mode: 0644]
kernel/blk_drv/scsi/sd_ioctl.c [new file with mode: 0644]
kernel/blk_drv/scsi/seagate.c [new file with mode: 0644]
kernel/blk_drv/scsi/seagate.h [new file with mode: 0644]
kernel/blk_drv/scsi/st.c [new file with mode: 0644]
kernel/blk_drv/scsi/st.h [new file with mode: 0644]
kernel/blk_drv/scsi/st_ioctl.c [new file with mode: 0644]
kernel/blk_drv/scsi/ultrastor.c [new file with mode: 0644]
kernel/blk_drv/scsi/ultrastor.h [new file with mode: 0644]
kernel/chr_drv/Makefile
kernel/chr_drv/console.c
kernel/chr_drv/keyboard.S [deleted file]
kernel/chr_drv/keyboard.c [new file with mode: 0644]
kernel/chr_drv/lp.c
kernel/chr_drv/mem.c [new file with mode: 0644]
kernel/chr_drv/pty.c
kernel/chr_drv/rs_io.s [deleted file]
kernel/chr_drv/serial.c
kernel/chr_drv/tty_io.c
kernel/chr_drv/tty_ioctl.c
kernel/chr_drv/vt.c [new file with mode: 0644]
kernel/chr_drv/vt_kern.h [new file with mode: 0644]
kernel/exit.c
kernel/fork.c
kernel/ioport.c [new file with mode: 0644]
kernel/math/Makefile
kernel/printk.c
kernel/ptrace.c
kernel/sched.c
kernel/signal.c
kernel/sys.c
kernel/sys_call.S [new file with mode: 0644]
kernel/sys_call.s [deleted file]
kernel/traps.c
kernel/vsprintf.c
lib/Makefile
lib/close.c
lib/ctype.c
lib/dup.c
lib/execve.c
lib/setsid.c
lib/string.c
lib/wait.c
lib/write.c
mm/Makefile
mm/memory.c
mm/mmap.c [new file with mode: 0644]
mm/swap.c
net/Makefile [new file with mode: 0644]
net/kern_sock.h [new file with mode: 0644]
net/socket.c [new file with mode: 0644]
net/socketcall.h [new file with mode: 0644]
net/unix.c [new file with mode: 0644]

index 3c032078a4a21c5c51d3c93d91717c1dabbb8cd0..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 100644 (file)
--- a/.version
+++ b/.version
@@ -1 +1 @@
-18
+10
index 59d5f66b405733658e8258d921e4a1e73ba3a067..968f18bee90bd33f44960d17064b64dd5fcbbb74 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,45 @@
 #
-# comment this line if you don't want the emulation-code
+# ROOT_DEV specifies the default root-device when making the image.
+# This can be either FLOPPY, /dev/xxxx or empty, in which case the
+# default of FLOPPY is used by 'build'.
 #
 
-MATH_EMULATION = -DKERNEL_MATH_EMULATION
+ROOT_DEV = /dev/hdb1
 
 #
 # uncomment the correct keyboard:
 #
+# The value of KBDFLAGS should be or'ed together from the following
+# bits, depending on which features you want enabled.
+# 0x80 - Off: the Alt key will set bit 7 if pressed together with
+#             another key.
+#        On:  the Alt key will NOT set the high bit; an escape
+#             character is prepended instead.
+# The least significant bits control if the following keys are "dead".
+# The key is dead by default if the bit is on.
+# 0x01 - backquote (`)
+# 0x02 - accent acute
+# 0x04 - circumflex (^)
+# 0x08 - tilde (~)
+# 0x10 - dieresis (umlaut)
+
+KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
+# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_US -DKBDFLAGS=0
+# KEYBOARD = -DKBD_GR -DKBDFLAGS=0
+# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_FR -DKBDFLAGS=0
+# KEYBOARD = -DKBD_FR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_UK -DKBDFLAGS=0
+# KEYBOARD = -DKBD_DK -DKBDFLAGS=0
+# KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0
 
-# KEYBOARD = -DKBD_FINNISH
-KEYBOARD = -DKBD_US
-# KEYBOARD = -DKBD_GR
-# KEYBOARD = -DKBD_FR
-# KEYBOARD = -DKBD_UK
-# KEYBOARD = -DKBD_DK
+#
+# comment this line if you don't want the emulation-code
+#
+
+MATH_EMULATION = -DKERNEL_MATH_EMULATION
 
 #
 # uncomment this line if you are using gcc-1.40
@@ -26,14 +52,6 @@ KEYBOARD = -DKBD_US
 
 CFLAGS =-Wall -O6 -fomit-frame-pointer $(GCC_OPT)
 
-#
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, /dev/xxxx or empty, in which case the
-# default of FLOPPY is used by 'build'.
-#
-
-# ROOT_DEV = /dev/hdb1
-
 #
 # if you want the ram-disk device, define this to be the
 # size in blocks.
@@ -52,9 +70,10 @@ CC   =gcc $(RAMDISK)
 MAKE   =make CFLAGS="$(CFLAGS)"
 CPP    =cpp -nostdinc -Iinclude
 
-ARCHIVES       =kernel/kernel.o mm/mm.o fs/fs.o
+ARCHIVES       =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
 FILESYSTEMS    =fs/minix/minix.o
-DRIVERS                =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
+DRIVERS                =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
+                kernel/blk_drv/scsi/scsi.a
 MATH           =kernel/math/math.a
 LIBS           =lib/lib.a
 
@@ -71,7 +90,7 @@ all:  Version Image
 
 Version:
        @./makever.sh
-       @echo \#define UTS_RELEASE \"0.95c-`cat .version`\" > include/linux/config_rel.h
+       @echo \#define UTS_RELEASE \"0.96a-`cat .version`\" > include/linux/config_rel.h
        @echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
        touch include/linux/config.h
 
@@ -86,7 +105,7 @@ disk: Image
        dd bs=8192 if=Image of=/dev/PS0
 
 tools/build: tools/build.c
-       $(CC) $(CFLAGS) \
+       $(CC) -static $(CFLAGS) \
        -o tools/build tools/build.c
 
 boot/head.o: boot/head.s
@@ -107,6 +126,9 @@ kernel/math/math.a: dummy
 kernel/blk_drv/blk_drv.a: dummy
        (cd kernel/blk_drv; $(MAKE))
 
+kernel/blk_drv/scsi/scsi.a: dummy
+       (cd kernel/blk_drv/scsi; $(MAKE))
+
 kernel/chr_drv/chr_drv.a: dummy
        (cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)")
 
@@ -119,6 +141,9 @@ mm/mm.o: dummy
 fs/fs.o: dummy
        (cd fs; $(MAKE))
 
+net/net.o: dummy
+       (cd net; $(MAKE))
+
 fs/minix/minix.o: dummy
        (cd fs/minix; $(MAKE))
 
@@ -147,6 +172,7 @@ clean:
        (cd fs;make clean)
        (cd kernel;make clean)
        (cd lib;make clean)
+       (cd net;make clean)
 
 backup: clean
        (cd .. ; tar cf - linux | compress - > backup.Z)
@@ -159,15 +185,16 @@ dep:
        (cd fs; make dep)
        (cd kernel; make dep)
        (cd mm; make dep)
+       (cd net;make dep)
+       (cd lib; make dep)
 
 dummy:
 
 ### Dependencies:
-init/main.o : init/main.c include/unistd.h include/sys/stat.h \
-  include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \
-  include/sys/utsname.h include/sys/param.h include/sys/resource.h \
-  include/utime.h include/linux/tty.h include/termios.h include/linux/sched.h \
-  include/linux/head.h include/linux/fs.h include/sys/dirent.h \
+init/main.o : init/main.c include/stddef.h include/stdarg.h include/fcntl.h include/sys/types.h \
+  include/time.h include/asm/system.h include/asm/io.h include/linux/config.h \
+  include/linux/config_rel.h include/linux/config_ver.h include/linux/config.dist.h \
+  include/linux/sched.h include/linux/head.h include/linux/fs.h include/sys/dirent.h \
   include/limits.h include/linux/mm.h include/linux/kernel.h include/signal.h \
-  include/asm/system.h include/asm/io.h include/stddef.h include/stdarg.h \
-  include/fcntl.h include/string.h 
+  include/sys/param.h include/sys/time.h include/sys/resource.h include/linux/tty.h \
+  include/termios.h include/linux/unistd.h 
index 312f2f689fca00102dd669cf16720ef377e88ad5..87d2b5bbd108dce00ce47c95496b346780ef241d 100644 (file)
@@ -23,8 +23,8 @@ CPP   =cpp -nostdinc -I../include
        $(AS) -o $*.o $<
 
 OBJS=  open.o read_write.o inode.o file_table.o buffer.o super.o \
-       block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
-       fcntl.o ioctl.o select.o
+       block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
+       select.o
 
 fs.o: $(OBJS)
        $(LD) -r -o fs.o $(OBJS)
@@ -41,97 +41,74 @@ dep:
        cd minix; make dep
 
 ### Dependencies:
-block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/asm/segment.h ../include/asm/system.h 
-buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \
-  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
-  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/asm/system.h ../include/asm/io.h 
-char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \
-  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/asm/segment.h ../include/asm/io.h 
-exec.o : exec.c ../include/signal.h ../include/sys/types.h \
-  ../include/errno.h ../include/string.h ../include/sys/stat.h \
-  ../include/a.out.h ../include/linux/fs.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
+  ../include/asm/system.h 
+buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h ../include/linux/config_rel.h \
+  ../include/linux/config_ver.h ../include/linux/config.dist.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+  ../include/asm/system.h ../include/asm/io.h 
+exec.o : exec.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+  ../include/linux/string.h ../include/sys/stat.h ../include/a.out.h ../include/linux/fs.h \
+  ../include/sys/dirent.h ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h 
+fcntl.o : fcntl.c ../include/errno.h ../include/fcntl.h ../include/sys/types.h \
+  ../include/sys/stat.h ../include/asm/segment.h ../include/linux/string.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h 
+file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+  ../include/limits.h 
+inode.o : inode.c ../include/linux/string.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+  ../include/asm/system.h 
+ioctl.o : ioctl.c ../include/linux/string.h ../include/errno.h ../include/sys/stat.h \
+  ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+  ../include/signal.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+  ../include/sys/resource.h 
+namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ../include/linux/string.h \
+  ../include/fcntl.h ../include/errno.h ../include/const.h ../include/sys/stat.h 
+open.o : open.c ../include/errno.h ../include/fcntl.h ../include/sys/types.h \
+  ../include/utime.h ../include/sys/stat.h ../include/sys/vfs.h ../include/linux/string.h \
+  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
   ../include/asm/segment.h 
-fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
-  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
-  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/asm/segment.h ../include/fcntl.h \
-  ../include/sys/stat.h 
-file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h 
-inode.o : inode.c ../include/string.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/asm/system.h 
-ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
-  ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+pipe.o : pipe.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+  ../include/termios.h ../include/fcntl.h ../include/asm/segment.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
   ../include/time.h ../include/sys/resource.h 
-namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
-  ../include/string.h ../include/fcntl.h ../include/errno.h \
-  ../include/const.h ../include/sys/stat.h 
-open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
-  ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
-  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/asm/segment.h 
-pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
-  ../include/errno.h ../include/termios.h ../include/fcntl.h \
-  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h 
-read_write.o : read_write.c ../include/errno.h ../include/sys/types.h \
-  ../include/sys/stat.h ../include/sys/dirent.h ../include/limits.h \
-  ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/linux/minix_fs.h \
+read_write.o : read_write.c ../include/errno.h ../include/sys/types.h ../include/sys/stat.h \
+  ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+  ../include/linux/minix_fs.h ../include/asm/segment.h 
+select.o : select.c ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/kernel.h ../include/linux/tty.h ../include/asm/system.h \
+  ../include/termios.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
+  ../include/signal.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+  ../include/sys/resource.h ../include/linux/string.h ../include/asm/segment.h \
+  ../include/sys/stat.h ../include/const.h ../include/errno.h 
+stat.o : stat.c ../include/errno.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
   ../include/asm/segment.h 
-select.o : select.c ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \
-  ../include/linux/tty.h ../include/termios.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h \
-  ../include/sys/stat.h ../include/string.h ../include/const.h \
-  ../include/errno.h 
-stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/linux/fs.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/asm/segment.h 
-super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/linux/minix_fs.h ../include/asm/system.h ../include/errno.h \
-  ../include/sys/stat.h 
+super.o : super.c ../include/linux/config.h ../include/linux/config_rel.h ../include/linux/config_ver.h \
+  ../include/linux/config.dist.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \
+  ../include/asm/system.h ../include/asm/segment.h ../include/errno.h ../include/sys/stat.h 
index cca44d36266146bc81a13e404b6db7e0d4a06a91..c102c943a653794a5e2d73723d07b0ad15df9ab7 100644 (file)
@@ -50,6 +50,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
                memcpy_fromfs(p,buf,chars);
                p += chars;
                buf += chars;
+               bh->b_uptodate = 1;
                bh->b_dirt = 1;
                brelse(bh);
        }
index 54fa80562f1e4f9dda4d7ca556733477e9770348..ef54e864d8d031995929eb8409b9a8bf9261f38a 100644 (file)
@@ -47,18 +47,12 @@ static void sync_buffers(int dev)
        struct buffer_head * bh;
 
        bh = free_list;
-       for (i=0 ; i<NR_BUFFERS ; i++,bh = bh->b_next_free) {
-#if 0
-               if (dev && (bh->b_dev != dev))
+       for (i = NR_BUFFERS*2 ; i-- > 0 ; bh = bh->b_next_free) {
+               if (bh->b_lock)
                        continue;
-#endif
-               wait_on_buffer(bh);
-#if 0
-               if (dev && (bh->b_dev != dev))
+               if (!bh->b_dirt)
                        continue;
-#endif
-               if (bh->b_dirt)
-                       ll_rw_block(WRITE,bh);
+               ll_rw_block(WRITE,bh);
        }
 }
 
@@ -200,7 +194,8 @@ static inline void insert_into_queues(struct buffer_head * bh)
                return;
        bh->b_next = hash(bh->b_dev,bh->b_blocknr);
        hash(bh->b_dev,bh->b_blocknr) = bh;
-       bh->b_next->b_prev = bh;
+       if (bh->b_next)
+               bh->b_next->b_prev = bh;
 }
 
 static struct buffer_head * find_buffer(int dev, int block)
@@ -257,9 +252,7 @@ repeat:
        if (bh = get_hash_table(dev,block))
                return bh;
        buffers = NR_BUFFERS;
-       tmp = free_list;
-       do {
-               tmp = tmp->b_next_free;
+       for (tmp = free_list ; buffers-- > 0 ; tmp = tmp->b_next_free) {
                if (tmp->b_count)
                        continue;
                if (!bh || BADNESS(tmp)<BADNESS(bh)) {
@@ -267,10 +260,12 @@ repeat:
                        if (!BADNESS(tmp))
                                break;
                }
+#if 0
                if (tmp->b_dirt)
                        ll_rw_block(WRITEA,tmp);
+#endif
+       }
 /* and repeat until we find something good */
-       } while (buffers--);
        if (!bh) {
                sleep_on(&buffer_wait);
                goto repeat;
@@ -279,7 +274,7 @@ repeat:
        if (bh->b_count)
                goto repeat;
        while (bh->b_dirt) {
-               sync_dev(bh->b_dev);
+               sync_buffers(bh->b_dev);
                wait_on_buffer(bh);
                if (bh->b_count)
                        goto repeat;
@@ -383,7 +378,7 @@ struct buffer_head * breada(int dev,int first, ...)
                tmp=getblk(dev,first);
                if (tmp) {
                        if (!tmp->b_uptodate)
-                               ll_rw_block(READA,bh);
+                               ll_rw_block(READA,tmp);
                        tmp->b_count--;
                }
        }
@@ -419,6 +414,7 @@ void buffer_init(long buffer_end)
                h->b_next = NULL;
                h->b_prev = NULL;
                h->b_data = (char *) b;
+               h->b_reqnext = NULL;
                h->b_prev_free = h-1;
                h->b_next_free = h+1;
                h++;
diff --git a/fs/char_dev.c b/fs/char_dev.c
deleted file mode 100644 (file)
index 081b18e..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- *  linux/fs/char_dev.c
- *
- *  (C) 1991  Linus Torvalds
- */
-
-#include <errno.h>
-#include <sys/types.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-
-#include <checkpoint.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-extern int tty_read(unsigned minor,char * buf,int count,unsigned short flags);
-extern int tty_write(unsigned minor,char * buf,int count);
-extern int lp_write(unsigned minor,char *buf, int count);
-
-typedef (*crw_ptr)(int,unsigned,char *,int,off_t *,unsigned short);
-
-static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
-{
-       return ((rw==READ)?tty_read(minor,buf,count,flags):
-               tty_write(minor,buf,count));
-}
-
-static int rw_lp(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
-{
-       return ((rw==READ)?-EINVAL:lp_write(minor,buf,count));
-}
-
-static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos, unsigned short flags)
-{
-       if (current->tty<0)
-               return -EPERM;
-       return rw_ttyx(rw,current->tty,buf,count,pos,flags);
-}
-
-static int rw_ram(int rw,char * buf, int count, off_t *pos)
-{
-       return -EIO;
-}
-
-static int rw_mem(int rw,char * buf, int count, off_t * pos)
-{
-       char *p;
-       unsigned long pde, pte, tmp;
-       int i = count;
-
-       if (count <= 0)
-               return(0);
-       /*
-        * return EOF on nonexistant pages or pages swapped out to disk
-        */
-       pde = (unsigned long) pg_dir + (*pos >> 20 & 0xffc);
-       if (((pte = *((unsigned long *) pde)) & 1) == 0)
-               return 0;       /* page table not present */
-       pte &= 0xfffff000;
-       pte += *pos >> 10 & 0xffc;
-       if (((tmp = *((unsigned long *) pte)) & 1) == 0)
-               return 0;
-       if (rw == WRITE && (tmp & 2) == 0)
-               un_wp_page((unsigned long *) pte);
-       p = (char *) ((tmp & 0xfffff000) + (*pos & 0xfff));
-       while (1) {
-               if (rw == WRITE)
-                       *p++ = get_fs_byte(buf++);
-               else
-                       put_fs_byte(*p++, buf++);
-
-               if (--i == 0)
-                       break;
-
-               if (count && ((unsigned long) p & 0xfff) == 0) {
-                       if (((pte += 4) & 0xfff) == 0) {
-                               if (((pde += 4) & 0xfff) == 0)
-                                       break;
-                               if (((pte = *((unsigned long *) pde)) & 1) == 0)
-                                       break;
-                               pte &= 0xfffff000;
-                       }
-                       if (((tmp = *((unsigned long *) pte)) & 1) == 0)
-                               break;
-
-                       if (rw == WRITE && (tmp & 2) == 0)
-                               un_wp_page((unsigned long *) pte);
-                       p = (char *) (tmp & 0xfffff000);
-               }
-       }
-       return(count - i);
-}
-
-static int rw_kmem(int rw,char * buf, int count, off_t * pos)
-{
-       char *p=(char *) *pos;
-
-       if ((unsigned long) *pos > HIGH_MEMORY)
-               return 0;
-       if ((unsigned long) *pos + count > HIGH_MEMORY)
-               count = HIGH_MEMORY - *pos;
-
-       switch (rw) {
-               case READ:
-                       while ((count -= 4) >= 0)
-                               put_fs_long(*((unsigned long *) p)++, 
-                                           ((unsigned long *) buf)++);
-                       count += 4;
-                       while (--count >= 0)
-                               put_fs_byte(*p++, buf++);
-                       break;
-               case WRITE:
-                       while (--count >= 0)
-                               *p++ = get_fs_byte(buf++);
-                       break;
-               default:
-                       return -EINVAL;
-       }
-       p -= *pos;
-       *pos += (int) p;
-       return (int) p;
-}
-
-static int rw_port(int rw,char * buf, int count, off_t * pos)
-{
-       int i=*pos;
-
-       while (count-->0 && i<65536) {
-               if (rw==READ)
-                       put_fs_byte(inb(i),buf++);
-               else
-                       outb(get_fs_byte(buf++),i);
-               i++;
-       }
-       i -= *pos;
-       *pos += i;
-       return i;
-}
-
-static int rw_memory(int rw, unsigned minor, char * buf, int count,
-       off_t * pos, unsigned short flags)
-{
-       switch(minor) {
-               case 0:
-                       return rw_ram(rw,buf,count,pos);
-               case 1:
-                       return rw_mem(rw,buf,count,pos);
-               case 2:
-                       return rw_kmem(rw,buf,count,pos);
-               case 3:
-                       return (rw==READ)?0:count;      /* rw_null */
-               case 4:
-                       return rw_port(rw,buf,count,pos);
-               default:
-                       return -EIO;
-       }
-}
-
-#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
-
-static crw_ptr crw_table[]={
-       NULL,           /* nodev */
-       rw_memory,      /* /dev/mem etc */
-       NULL,           /* /dev/fd */
-       NULL,           /* /dev/hd */
-       rw_ttyx,        /* /dev/ttyx */
-       rw_tty,         /* /dev/tty */
-       rw_lp,          /* /dev/lp */
-       NULL};          /* unnamed pipes */
-
-int char_read(struct inode * inode, struct file * filp, char * buf, int count)
-{
-       unsigned int major,minor;
-       crw_ptr call_addr;
-
-       major = MAJOR(inode->i_rdev);
-       minor = MINOR(inode->i_rdev);
-       if (major >= NRDEVS)
-               return -ENODEV;
-       if (!(call_addr = crw_table[major]))
-               return -ENODEV;
-       return call_addr(READ,minor,buf,count,&filp->f_pos,filp->f_flags);
-}
-
-int char_write(struct inode * inode, struct file * filp, char * buf, int count)
-{
-       unsigned int major,minor;
-       crw_ptr call_addr;
-
-       major = MAJOR(inode->i_rdev);
-       minor = MINOR(inode->i_rdev);
-       if (major >= NRDEVS)
-               return -ENODEV;
-       if (!(call_addr=crw_table[major]))
-               return -ENODEV;
-       return call_addr(WRITE,minor,buf,count,&filp->f_pos,filp->f_flags);
-}
index f27b51f44b2e5f98f61c31bf20dff82cf32dbd26..48d727f4bb1c439094e35c631d9d052fde05180a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -19,7 +19,7 @@
 
 #include <signal.h>
 #include <errno.h>
-#include <string.h>
+#include <linux/string.h>
 #include <sys/stat.h>
 #include <a.out.h>
 
@@ -39,26 +39,57 @@ extern int sys_close(int fd);
  */
 #define MAX_ARG_PAGES 32
 
+/*
+ * Note that a shared library must be both readable and executable due to
+ * security reasons.
+ *
+ * Also note that we take the address to load from from the file itself.
+ */
 int sys_uselib(const char * library)
 {
+#define libnum (current->numlibraries)
        struct inode * inode;
-       unsigned long base;
+       struct buffer_head * bh;
+       struct exec ex;
 
        if (get_limit(0x17) != TASK_SIZE)
                return -EINVAL;
-       if (library) {
-               if (!(inode=namei(library)))            /* get library inode */
-                       return -ENOENT;
-       } else
+       if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
+               return -EINVAL;
+       if (library)
+               inode = namei(library);
+       else
                inode = NULL;
-/* we should check filetypes (headers etc), but we don't */
-       iput(current->library);
-       current->library = NULL;
-       base = get_base(current->ldt[2]);
-       base += LIBRARY_OFFSET;
-       free_page_tables(base,LIBRARY_SIZE);
-       current->library = inode;
+       if (!inode)
+               return -ENOENT;
+       if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
+               iput(inode);
+               return -EACCES;
+       }
+       if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+               iput(inode);
+               return -EACCES;
+       }
+       ex = *(struct exec *) bh->b_data;
+       brelse(bh);
+       if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
+               ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
+               inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
+               iput(inode);
+               return -ENOEXEC;
+       }
+       current->libraries[libnum].library = inode;
+       current->libraries[libnum].start = ex.a_entry;
+       current->libraries[libnum].length = (ex.a_data+ex.a_text+0xfff) & 0xfffff000;
+#if 0
+       printk("Loaded library %d at %08x, length %08x\n",
+               libnum,
+               current->libraries[libnum].start,
+               current->libraries[libnum].length);
+#endif
+       libnum++;
        return 0;
+#undef libnum
 }
 
 /*
@@ -198,6 +229,32 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
        return data_limit;
 }
 
+static void read_omagic(struct inode *inode, int bytes)
+{
+       struct buffer_head *bh;
+       int n, blkno, blk = 0;
+       char *dest = (char *) 0;
+
+       while (bytes > 0) {
+               if (!(blkno = bmap(inode, blk)))
+                       sys_exit(-1);
+               if (!(bh = bread(inode->i_dev, blkno)))
+                       sys_exit(-1);
+               n = (blk ? BLOCK_SIZE : BLOCK_SIZE - sizeof(struct exec));
+               if (bytes < n)
+                       n = bytes;
+
+               memcpy_tofs(dest, (blk ? bh->b_data :
+                               bh->b_data + sizeof(struct exec)), n);
+               brelse(bh);
+               ++blk;
+               dest += n;
+               bytes -= n;
+       }
+       iput(inode);
+       current->executable = NULL;
+}
+
 /*
  * 'do_execve()' executes a new program.
  *
@@ -328,13 +385,14 @@ restart_interp:
                goto restart_interp;
        }
        brelse(bh);
-       if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
+       if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
+               ex.a_trsize || ex.a_drsize ||
                ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
                inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
                retval = -ENOEXEC;
                goto exec_error2;
        }
-       if (N_TXTOFF(ex) != BLOCK_SIZE) {
+       if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
                printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
                retval = -ENOEXEC;
                goto exec_error2;
@@ -348,7 +406,6 @@ restart_interp:
                }
        }
 /* OK, This is the point of no return */
-/* note that current->library stays unchanged by an exec */
        for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
                if (ch == '/')
                        i = 0;
@@ -357,9 +414,14 @@ restart_interp:
                                current->comm[i++] = ch;
        if (i < 8)
                current->comm[i] = '\0';
-       
        if (current->executable)
                iput(current->executable);
+       i = current->numlibraries;
+       while (i-- > 0) {
+               iput(current->libraries[i].library);
+               current->libraries[i].library = NULL;
+       }
+       current->numlibraries = 0;
        current->executable = inode;
        current->signal = 0;
        for (i=0 ; i<32 ; i++) {
@@ -387,6 +449,8 @@ restart_interp:
        current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
        current->suid = current->euid = e_uid;
        current->sgid = current->egid = e_gid;
+       if (N_MAGIC(ex) == OMAGIC)
+               read_omagic(inode, ex.a_text+ex.a_data);
        eip[0] = ex.a_entry;            /* eip, magic happens :-) */
        eip[3] = p;                     /* stack pointer */
        if (current->flags & PF_PTRACED)
index ab7fe1f21c685bdb37712240e5257ee431525992..952bf8cb488bde00e5d3b6f56d6a1f8e7110337f 100644 (file)
@@ -4,15 +4,17 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <string.h>
 #include <errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
 #include <fcntl.h>
+
 #include <sys/stat.h>
 
+#include <asm/segment.h>
+
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
 extern int sys_close(int fd);
 
 static int dupfd(unsigned int fd, unsigned int arg)
index c1634d87bcfdbd0a1d599f2c5007e6da8ff59af0..1f144c61212991aa2ad6fbef7e617d255a2bffb2 100644 (file)
@@ -4,7 +4,7 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <string.h>
+#include <linux/string.h>
 #include <sys/stat.h>
 
 #include <linux/sched.h>
@@ -39,13 +39,13 @@ static inline void unlock_inode(struct inode * inode)
 
 static void write_inode(struct inode * inode)
 {
-       lock_inode(inode);
-       if (!inode->i_dirt || !inode->i_dev) {
-               unlock_inode(inode);
+       if (!inode->i_dirt)
                return;
-       }
-       if (inode->i_op && inode->i_op->write_inode)
-               inode->i_op->write_inode(inode);
+       inode->i_dirt = 0;
+       lock_inode(inode);
+       if (inode->i_dev && inode->i_sb &&
+           inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
+               inode->i_sb->s_op->write_inode(inode);
        unlock_inode(inode);
 }
 
@@ -110,8 +110,12 @@ void iput(struct inode * inode)
        if (!inode)
                return;
        wait_on_inode(inode);
-       if (!inode->i_count)
-               panic("iput: trying to free free inode");
+       if (!inode->i_count) {
+               printk("iput: trying to free free inode\n");
+               printk("device %04x, inode %d, mode=%07o\n",inode->i_rdev,
+                       inode->i_ino,inode->i_mode);
+               return;
+       }
        if (inode->i_pipe) {
                wake_up(&inode->i_wait);
                wake_up(&inode->i_wait2);
@@ -127,18 +131,14 @@ void iput(struct inode * inode)
                inode->i_count--;
                return;
        }
-       if (S_ISBLK(inode->i_mode)) {
-               sync_dev(inode->i_rdev);
-               wait_on_inode(inode);
-       }
 repeat:
        if (inode->i_count>1) {
                inode->i_count--;
                return;
        }
        if (!inode->i_nlink) {
-               if (inode->i_op && inode->i_op->put_inode)
-                       inode->i_op->put_inode(inode);
+               if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode)
+                       inode->i_sb->s_op->put_inode(inode);
                return;
        }
        if (inode->i_dirt) {
index 284a0dc0c8c43d5e6f3d604a65703c8f1f06e1e0..7b2811674620a67397632c66eaafd6fb79831f75 100644 (file)
@@ -4,47 +4,19 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <string.h>
+#include <linux/string.h>
 #include <errno.h>
 #include <sys/stat.h>
 
 #include <linux/sched.h>
 
-extern int hd_ioctl(int dev, int cmd, int arg);
-extern int tty_ioctl(int dev, int cmd, int arg);
-extern int pipe_ioctl(struct inode *pino, int cmd, int arg);
-
-typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
-
-#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
-
-static ioctl_ptr ioctl_table[]={
-       NULL,           /* nodev */
-       NULL,           /* /dev/mem */
-       NULL,           /* /dev/fd */
-       hd_ioctl,       /* /dev/hd */
-       tty_ioctl,      /* /dev/ttyx */
-       tty_ioctl,      /* /dev/tty */
-       NULL,           /* /dev/lp */
-       NULL};          /* named pipes */
-       
-
 int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {      
        struct file * filp;
-       int dev,mode;
 
        if (fd >= NR_OPEN || !(filp = current->filp[fd]))
                return -EBADF;
-       if (filp->f_inode->i_pipe)
-               return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF;
-       mode=filp->f_inode->i_mode;
-       if (!S_ISCHR(mode) && !S_ISBLK(mode))
-               return -EINVAL;
-       dev = filp->f_inode->i_rdev;
-       if (MAJOR(dev) >= NRDEVS)
-               return -ENODEV;
-       if (!ioctl_table[MAJOR(dev)])
-               return -ENOTTY;
-       return ioctl_table[MAJOR(dev)](dev,cmd,arg);
+       if (filp->f_op && filp->f_op->ioctl)
+               return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
+       return -EINVAL;
 }
index fd1a331e2af6f773d1f323e49d4c273f528ebb24..fe1b2a5a7877e50b5ee0d2c6703f7cfdef1a5c81 100644 (file)
@@ -22,7 +22,8 @@ CPP   =cpp -nostdinc -I../../include
 .s.o:
        $(AS) -o $*.o $<
 
-OBJS=  minix_op.o bitmap.o truncate.o namei.o inode.o file_dev.o
+OBJS=  bitmap.o truncate.o namei.o inode.o \
+       file.o dir.o symlink.o blkdev.o chrdev.o
 
 minix.o: $(OBJS)
        $(LD) -r -o minix.o $(OBJS)
@@ -37,46 +38,52 @@ dep:
        cp tmp_make Makefile
 
 ### Dependencies:
-bitmap.o : bitmap.c ../../include/string.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
+bitmap.o : bitmap.c ../../include/linux/string.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/minix_fs.h 
+blkdev.o : blkdev.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
-  ../../include/time.h ../../include/sys/resource.h \
-  ../../include/linux/minix_fs.h 
-file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/minix_fs.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/termios.h ../../include/errno.h ../../include/fcntl.h ../../include/sys/stat.h 
+chrdev.o : chrdev.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/sys/stat.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
-  ../../include/time.h ../../include/sys/resource.h \
-  ../../include/linux/minix_fs.h ../../include/asm/segment.h 
-inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \
-  ../../include/sys/types.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/minix_fs.h \
-  ../../include/asm/system.h 
-minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \
-  ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/minix_fs.h 
-namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/minix_fs.h \
-  ../../include/asm/segment.h ../../include/string.h ../../include/fcntl.h \
-  ../../include/errno.h ../../include/const.h ../../include/sys/stat.h 
-truncate.o : truncate.c ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/minix_fs.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/termios.h ../../include/errno.h ../../include/fcntl.h ../../include/sys/stat.h 
+dir.o : dir.c ../../include/errno.h ../../include/sys/stat.h ../../include/sys/types.h \
+  ../../include/asm/segment.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/minix_fs.h 
+file.o : file.c ../../include/errno.h ../../include/fcntl.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/sys/stat.h ../../include/asm/segment.h \
+  ../../include/asm/system.h ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/minix_fs.h 
+inode.o : inode.c ../../include/linux/string.h ../../include/sys/stat.h ../../include/sys/types.h \
+  ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/minix_fs.h ../../include/asm/system.h 
+namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
-  ../../include/time.h ../../include/sys/resource.h \
-  ../../include/linux/minix_fs.h ../../include/linux/tty.h \
-  ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/minix_fs.h ../../include/asm/segment.h ../../include/linux/string.h \
+  ../../include/fcntl.h ../../include/errno.h ../../include/const.h ../../include/sys/stat.h 
+symlink.o : symlink.c ../../include/errno.h ../../include/sys/stat.h ../../include/sys/types.h \
+  ../../include/asm/segment.h ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
+  ../../include/linux/kernel.h ../../include/signal.h ../../include/sys/param.h \
+  ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h ../../include/linux/minix_fs.h 
+truncate.o : truncate.c ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/minix_fs.h ../../include/linux/tty.h \
+  ../../include/asm/system.h ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \
   ../../include/sys/stat.h 
index 645db74b0c9e5b930328bb9567e13cd3bcdf0ccf..a7fd3c32619ab26641dcbb742552ff04f7eb1852 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /* bitmap.c contains the code that handles the inode and block bitmaps */
-#include <string.h>
+#include <linux/string.h>
 
 #include <linux/sched.h>
 #include <linux/minix_fs.h>
@@ -179,6 +179,6 @@ struct inode * minix_new_inode(int dev)
        inode->i_dirt = 1;
        inode->i_ino = j + i*8192;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       inode->i_op = &minix_inode_operations;
+       inode->i_op = NULL;
        return inode;
 }
diff --git a/fs/minix/blkdev.c b/fs/minix/blkdev.c
new file mode 100644 (file)
index 0000000..fec1bc9
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/fs/chrdev.c
+ *
+ *  (C) 1991  Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/*
+ * Called every time a minix block special file is opened
+ */
+static int blkdev_open(struct inode * inode, struct file * filp)
+{
+       int i;
+
+       check_disk_change(inode->i_rdev);
+       i = MAJOR(inode->i_rdev);
+       if (i < MAX_BLKDEV) {
+               filp->f_op = blkdev_fops[i];
+               if (filp->f_op && filp->f_op->open)
+                       return filp->f_op->open(inode,filp);
+       }
+       return 0;
+}      
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+static struct file_operations def_blk_fops = {
+       NULL,           /* lseek */
+       NULL,           /* read */
+       NULL,           /* write */
+       NULL,           /* readdir */
+       NULL,           /* select */
+       NULL,           /* ioctl */
+       blkdev_open,    /* open */
+       NULL,           /* release */
+};
+
+struct inode_operations minix_blkdev_inode_operations = {
+       &def_blk_fops,          /* default file operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       minix_bmap,             /* bmap */
+       minix_truncate          /* truncate */
+};
diff --git a/fs/minix/chrdev.c b/fs/minix/chrdev.c
new file mode 100644 (file)
index 0000000..489849f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/fs/chrdev.c
+ *
+ *  (C) 1991  Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/*
+ * Called every time a minix character special file is opened
+ */
+static int chrdev_open(struct inode * inode, struct file * filp)
+{
+       int i;
+
+       i = MAJOR(inode->i_rdev);
+       if (i < MAX_CHRDEV) {
+               filp->f_op = chrdev_fops[i];
+               if (filp->f_op && filp->f_op->open)
+                       return filp->f_op->open(inode,filp);
+       }
+       return 0;
+}
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+static struct file_operations def_chr_fops = {
+       NULL,           /* lseek */
+       NULL,           /* read */
+       NULL,           /* write */
+       NULL,           /* readdir */
+       NULL,           /* select */
+       NULL,           /* ioctl */
+       chrdev_open,    /* open */
+       NULL,           /* release */
+};
+
+struct inode_operations minix_chrdev_inode_operations = {
+       &def_chr_fops,          /* default file operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       minix_bmap,             /* bmap */
+       minix_truncate          /* truncate */
+};
+
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
new file mode 100644 (file)
index 0000000..d09585a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * linux/fs/minix/dir.c
+ *
+ * minix directory hadnling functions
+ */
+
+#include <errno.h>
+
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+static int minix_readdir(struct inode *, struct file *, struct dirent *, int);
+
+static struct file_operations minix_dir_operations = {
+       NULL,                   /* lseek - default */
+       minix_file_read,        /* read */
+       NULL,                   /* write - bad */
+       minix_readdir,          /* readdir */
+       NULL,                   /* select - default */
+       NULL,                   /* ioctl - default */
+       NULL,                   /* no special open code */
+       NULL                    /* no special release code */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations minix_dir_inode_operations = {
+       &minix_dir_operations,  /* default directory file-ops */
+       minix_create,           /* create */
+       minix_lookup,           /* lookup */
+       minix_link,             /* link */
+       minix_unlink,           /* unlink */
+       minix_symlink,          /* symlink */
+       minix_mkdir,            /* mkdir */
+       minix_rmdir,            /* rmdir */
+       minix_mknod,            /* mknod */
+       minix_rename,           /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       minix_bmap,             /* bmap */
+       minix_truncate          /* truncate */
+};
+
+static int minix_readdir(struct inode * inode, struct file * filp,
+       struct dirent * dirent, int count)
+{
+       unsigned int block,offset,i;
+       char c;
+       struct buffer_head * bh;
+       struct minix_dir_entry * de;
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               return -EBADF;
+       if (filp->f_pos & (sizeof (struct minix_dir_entry) - 1))
+               return -EBADF;
+       while (filp->f_pos < inode->i_size) {
+               offset = filp->f_pos & 1023;
+               block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
+               if (!block || !(bh = bread(inode->i_dev,block))) {
+                       filp->f_pos += 1024-offset;
+                       continue;
+               }
+               de = (struct minix_dir_entry *) (offset + bh->b_data);
+               while (offset < 1024 && filp->f_pos < inode->i_size) {
+                       offset += sizeof (struct minix_dir_entry);
+                       filp->f_pos += sizeof (struct minix_dir_entry);
+                       if (de->inode) {
+                               for (i = 0; i < MINIX_NAME_LEN; i++)
+                                       if (c = de->name[i])
+                                               put_fs_byte(c,i+dirent->d_name);
+                                       else
+                                               break;
+                               if (i) {
+                                       put_fs_long(de->inode,&dirent->d_ino);
+                                       put_fs_byte(0,i+dirent->d_name);
+                                       put_fs_word(i,&dirent->d_reclen);
+                                       brelse(bh);
+                                       return i;
+                               }
+                       }
+                       de++;
+               }
+               brelse(bh);
+       }
+       return 0;
+}
diff --git a/fs/minix/file.c b/fs/minix/file.c
new file mode 100644 (file)
index 0000000..9ebeebb
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * linux/fs/minix/file.c
+ *
+ * minix regular file handling primitives
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/dirent.h>
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+
+#define        NBUF    16
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+int minix_file_read(struct inode *, struct file *, char *, int);
+static int minix_file_write(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the minix filesystem.
+ */
+static struct file_operations minix_file_operations = {
+       NULL,                   /* lseek - default */
+       minix_file_read,        /* read */
+       minix_file_write,       /* write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select - default */
+       NULL,                   /* ioctl - default */
+       NULL,                   /* no special open is needed */
+       NULL                    /* release */
+};
+
+struct inode_operations minix_file_inode_operations = {
+       &minix_file_operations, /* default file operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       minix_bmap,             /* bmap */
+       minix_truncate          /* truncate */
+};
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+       cli();
+       while (bh->b_lock)
+               sleep_on(&bh->b_wait);
+       sti();
+}
+
+/*
+ * minix_file_read() is also needed by the directory read-routine,
+ * so it's not static. NOTE! reading directories directly is a bad idea,
+ * but has to be supported for now for compatability reasons with older
+ * versions.
+ */
+int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+       int read,left,chars,nr;
+       int block, blocks, offset;
+       struct buffer_head ** bhb, ** bhe;
+       struct buffer_head * buflist[NBUF];
+
+       if (!inode) {
+               printk("minix_file_read: inode = NULL\n");
+               return -EINVAL;
+       }
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
+               printk("minix_file_read: mode = %07o\n",inode->i_mode);
+               return -EINVAL;
+       }
+       if (filp->f_pos > inode->i_size)
+               left = 0;
+       else
+               left = inode->i_size - filp->f_pos;
+       if (left > count)
+               left = count;
+       if (left <= 0)
+               return 0;
+       read = 0;
+       block = filp->f_pos >> BLOCK_SIZE_BITS;
+       offset = filp->f_pos & (BLOCK_SIZE-1);
+       blocks = (left + offset + BLOCK_SIZE - 1) / BLOCK_SIZE;
+       bhb = bhe = buflist;
+       do {
+               if (blocks) {
+                       --blocks;
+                       if (nr = minix_bmap(inode,block++)) {
+                               *bhb = getblk(inode->i_dev,nr);
+                               if (!(*bhb)->b_uptodate)
+                                       ll_rw_block(READ,*bhb);
+                       } else
+                               *bhb = NULL;
+
+                       if (++bhb == &buflist[NBUF])
+                               bhb = buflist;
+
+                       if (bhb != bhe)
+                               continue;
+               }
+               if (*bhe) {
+                       wait_on_buffer(*bhe);
+                       if (!(*bhe)->b_uptodate) {
+                               do {
+                                       brelse(*bhe);
+                                       if (++bhe == &buflist[NBUF])
+                                               bhe = buflist;
+                               } while (bhe != bhb);
+                               break;
+                       }
+               }
+
+               if (left < BLOCK_SIZE - offset)
+                       chars = left;
+               else
+                       chars = BLOCK_SIZE - offset;
+               filp->f_pos += chars;
+               left -= chars;
+               read += chars;
+               if (*bhe) {
+                       memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
+                       brelse(*bhe);
+                       buf += chars;
+               } else {
+                       while (chars-->0)
+                               put_fs_byte(0,buf++);
+               }
+               offset = 0;
+               if (++bhe == &buflist[NBUF])
+                       bhe = buflist;
+       } while (left > 0);
+       if (!read)
+               return -EIO;
+       inode->i_atime = CURRENT_TIME;
+       inode->i_dirt = 1;
+       return read;
+}
+
+static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
+{
+       off_t pos;
+       int written,block,c;
+       struct buffer_head * bh;
+       char * p;
+
+       if (!inode) {
+               printk("minix_file_write: inode = NULL\n");
+               return -EINVAL;
+       }
+       if (!S_ISREG(inode->i_mode)) {
+               printk("minix_file_write: mode = %07o\n",inode->i_mode);
+               return -EINVAL;
+       }
+/*
+ * ok, append may not work when many processes are writing at the same time
+ * but so what. That way leads to madness anyway.
+ */
+       if (filp->f_flags & O_APPEND)
+               pos = inode->i_size;
+       else
+               pos = filp->f_pos;
+       written = 0;
+       while (written<count) {
+               if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
+                       if (!written)
+                               written = -ENOSPC;
+                       break;
+               }
+               c = BLOCK_SIZE - (pos % BLOCK_SIZE);
+               if (c > count-written)
+                       c = count-written;
+               if (c == BLOCK_SIZE)
+                       bh = getblk(inode->i_dev, block);
+               else
+                       bh = bread(inode->i_dev,block);
+               if (!bh) {
+                       if (!written)
+                               written = -EIO;
+                       break;
+               }
+               p = (pos % BLOCK_SIZE) + bh->b_data;
+               pos += c;
+               if (pos > inode->i_size) {
+                       inode->i_size = pos;
+                       inode->i_dirt = 1;
+               }
+               written += c;
+               memcpy_fromfs(p,buf,c);
+               buf += c;
+               bh->b_uptodate = 1;
+               bh->b_dirt = 1;
+               brelse(bh);
+       }
+       inode->i_mtime = CURRENT_TIME;
+       if (!(filp->f_flags & O_APPEND)) {
+               filp->f_pos = pos;
+               inode->i_ctime = CURRENT_TIME;
+       }
+       inode->i_dirt = 1;
+       return written;
+}
diff --git a/fs/minix/file_dev.c b/fs/minix/file_dev.c
deleted file mode 100644 (file)
index 91995d9..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *  linux/fs/file_dev.c
- *
- *  (C) 1991  Linus Torvalds
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/dirent.h>
-#include <sys/stat.h>
-
-#include <linux/sched.h>
-#include <linux/minix_fs.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent)
-{
-       unsigned int block,offset,i;
-       char c;
-       struct buffer_head * bh;
-       struct minix_dir_entry * de;
-
-       if (!S_ISDIR(inode->i_mode))
-               return -EBADF;
-       if (filp->f_pos & 15)
-               return -EBADF;
-       while (filp->f_pos < inode->i_size) {
-               offset = filp->f_pos & 1023;
-               block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
-               if (!block || !(bh = bread(inode->i_dev,block))) {
-                       filp->f_pos += 1024-offset;
-                       continue;
-               }
-               de = (struct minix_dir_entry *) (offset + bh->b_data);
-               while (offset < 1024 && filp->f_pos < inode->i_size) {
-                       offset += 16;
-                       filp->f_pos += 16;
-                       if (de->inode) {
-                               for (i = 0; i < 14; i++)
-                                       if (c = de->name[i])
-                                               put_fs_byte(c,i+dirent->d_name);
-                                       else
-                                               break;
-                               if (i) {
-                                       put_fs_long(de->inode,&dirent->d_ino);
-                                       put_fs_byte(0,i+dirent->d_name);
-                                       put_fs_word(i,&dirent->d_reclen);
-                                       brelse(bh);
-                                       return i;
-                               }
-                       }
-                       de++;
-               }
-               brelse(bh);
-       }
-       return 0;
-}
-
-int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
-{
-       int read,left,chars,nr;
-       struct buffer_head * bh;
-
-       if (filp->f_pos > inode->i_size)
-               left = 0;
-       else
-               left = inode->i_size - filp->f_pos;
-       if (left > count)
-               left = count;
-       read = 0;
-       while (left > 0) {
-               if (nr = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) {
-                       if (!(bh=bread(inode->i_dev,nr)))
-                               return read?read:-EIO;
-               } else
-                       bh = NULL;
-               nr = filp->f_pos & (BLOCK_SIZE-1);
-               chars = MIN( BLOCK_SIZE-nr , left );
-               filp->f_pos += chars;
-               left -= chars;
-               read += chars;
-               if (bh) {
-                       memcpy_tofs(buf,nr+bh->b_data,chars);
-                       buf += chars;
-                       brelse(bh);
-               } else {
-                       while (chars-->0)
-                               put_fs_byte(0,buf++);
-               }
-       }
-       inode->i_atime = CURRENT_TIME;
-       return read;
-}
-
-int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
-{
-       off_t pos;
-       int written,block,c;
-       struct buffer_head * bh;
-       char * p;
-
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
-       if (filp->f_flags & O_APPEND)
-               pos = inode->i_size;
-       else
-               pos = filp->f_pos;
-       written = 0;
-       while (written<count) {
-               if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
-                       if (!written)
-                               written = -ENOSPC;
-                       break;
-               }
-               if (!(bh=bread(inode->i_dev,block))) {
-                       if (!written)
-                               written = -EIO;
-                       break;
-               }
-               c = pos % BLOCK_SIZE;
-               p = c + bh->b_data;
-               c = BLOCK_SIZE-c;
-               if (c > count-written)
-                       c = count-written;
-               pos += c;
-               if (pos > inode->i_size) {
-                       inode->i_size = pos;
-                       inode->i_dirt = 1;
-               }
-               written += c;
-               memcpy_fromfs(p,buf,c);
-               buf += c;
-               bh->b_dirt = 1;
-               brelse(bh);
-       }
-       inode->i_mtime = CURRENT_TIME;
-       if (!(filp->f_flags & O_APPEND)) {
-               filp->f_pos = pos;
-               inode->i_ctime = CURRENT_TIME;
-       }
-       inode->i_dirt = 1;
-       return written;
-}
index 75ec7a2b2770c123c6541a3263d5110b89198299..4ddf5c2472049f49dc453d03fdb3920b8d5e068b 100644 (file)
@@ -4,7 +4,7 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <string.h>
+#include <linux/string.h>
 #include <sys/stat.h>
 
 #include <linux/sched.h>
 
 int sync_dev(int dev);
 
+void minix_put_inode(struct inode *inode)
+{
+       inode->i_size = 0;
+       minix_truncate(inode);
+       minix_free_inode(inode);
+}
+
 void minix_put_super(struct super_block *sb)
 {
        int i;
@@ -31,6 +38,8 @@ void minix_put_super(struct super_block *sb)
 
 static struct super_operations minix_sops = { 
        minix_read_inode,
+       minix_write_inode,
+       minix_put_inode,
        minix_put_super
 };
 
@@ -199,7 +208,17 @@ void minix_read_inode(struct inode * inode)
        else for (block = 0; block < 9; block++)
                inode->i_data[block] = raw_inode->i_zone[block];
        brelse(bh);
-       inode->i_op = &minix_inode_operations;
+       inode->i_op = NULL;
+       if (S_ISREG(inode->i_mode))
+               inode->i_op = &minix_file_inode_operations;
+       else if (S_ISDIR(inode->i_mode))
+               inode->i_op = &minix_dir_inode_operations;
+       else if (S_ISLNK(inode->i_mode))
+               inode->i_op = &minix_symlink_inode_operations;
+       else if (S_ISCHR(inode->i_mode))
+               inode->i_op = &minix_chrdev_inode_operations;
+       else if (S_ISBLK(inode->i_mode))
+               inode->i_op = &minix_blkdev_inode_operations;
 }
 
 void minix_write_inode(struct inode * inode)
diff --git a/fs/minix/minix_op.c b/fs/minix/minix_op.c
deleted file mode 100644 (file)
index 7fd5559..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * linux/fs/minix/minix_op.c
- *
- * structures for the minix super_block/inode/file-operations
- */
-
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-
-void minix_put_inode(struct inode *inode)
-{
-       minix_truncate(inode);
-       minix_free_inode(inode);
-}
-
-/*
- * These are the low-level inode operations for minix filesystem inodes.
- */
-struct inode_operations minix_inode_operations = {
-       minix_create,
-       minix_lookup,
-       minix_link,
-       minix_unlink,
-       minix_symlink,
-       minix_mkdir,
-       minix_rmdir,
-       minix_mknod,
-       minix_rename,
-       minix_readlink,
-       minix_open,
-       minix_release,
-       minix_follow_link,
-       minix_bmap,
-       minix_truncate,
-       minix_write_inode,
-       minix_put_inode
-};
-
-/*
- * We have mostly NULL's here: the current defaults are ok for
- * the minix filesystem.
- */
-struct file_operations minix_file_operations = {
-       NULL,   /* lseek */
-       NULL,   /* read */
-       NULL,   /* write */
-       minix_readdir
-};
-       
index ba891cba9929bf010ce7cb1285467902e8416af2..8682e9cedbfcf68df537c2636e2b1c0356e718bf 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kernel.h>
 #include <asm/segment.h>
 
-#include <string.h>
+#include <linux/string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <const.h>
@@ -103,40 +103,6 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
        return NULL;
 }
 
-struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
-{
-       unsigned short fs;
-       struct buffer_head * bh;
-
-       if (!dir) {
-               dir = current->root;
-               dir->i_count++;
-       }
-       if (!inode) {
-               iput(dir);
-               return NULL;
-       }
-       if (!S_ISLNK(inode->i_mode)) {
-               iput(dir);
-               return inode;
-       }
-       __asm__("mov %%fs,%0":"=r" (fs));
-       if ((current->link_count > 5) || !inode->i_data[0] ||
-          !(bh = bread(inode->i_dev, inode->i_data[0]))) {
-               iput(dir);
-               iput(inode);
-               return NULL;
-       }
-       iput(inode);
-       __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
-       current->link_count++;
-       inode = _namei(bh->b_data,dir,1);
-       current->link_count--;
-       __asm__("mov %0,%%fs"::"r" (fs));
-       brelse(bh);
-       return inode;
-}
-
 int minix_lookup(struct inode * dir,const char * name, int len,
        struct inode ** result)
 {
@@ -249,11 +215,13 @@ int minix_create(struct inode * dir,const char * name, int len, int mode,
                iput(dir);
                return -ENOSPC;
        }
+       inode->i_op = &minix_file_inode_operations;
        inode->i_mode = mode;
        inode->i_dirt = 1;
        bh = minix_add_entry(dir,name,len,&de);
        if (!bh) {
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                iput(dir);
                return -ENOSPC;
@@ -287,6 +255,17 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
        }
        inode->i_uid = current->euid;
        inode->i_mode = mode;
+       inode->i_op = NULL;
+       if (S_ISREG(inode->i_mode))
+               inode->i_op = &minix_file_inode_operations;
+       else if (S_ISDIR(inode->i_mode))
+               inode->i_op = &minix_dir_inode_operations;
+       else if (S_ISLNK(inode->i_mode))
+               inode->i_op = &minix_symlink_inode_operations;
+       else if (S_ISCHR(inode->i_mode))
+               inode->i_op = &minix_chrdev_inode_operations;
+       else if (S_ISBLK(inode->i_mode))
+               inode->i_op = &minix_blkdev_inode_operations;
        if (S_ISBLK(mode) || S_ISCHR(mode))
                inode->i_rdev = rdev;
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
@@ -294,6 +273,7 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
        bh = minix_add_entry(dir,name,len,&de);
        if (!bh) {
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                iput(dir);
                return -ENOSPC;
@@ -323,12 +303,13 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
                iput(dir);
                return -ENOSPC;
        }
-       inode->i_size = 32;
-       inode->i_dirt = 1;
+       inode->i_op = &minix_dir_inode_operations;
+       inode->i_size = 2 * sizeof (struct minix_dir_entry);
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
        if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
                iput(dir);
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                return -ENOSPC;
        }
@@ -336,8 +317,9 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
        if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
                iput(dir);
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
-               return -ERROR;
+               return -EIO;
        }
        de = (struct minix_dir_entry *) dir_block->b_data;
        de->inode=inode->i_ino;
@@ -517,10 +499,11 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
                return -ENOSPC;
        }
        inode->i_mode = S_IFLNK | 0777;
-       inode->i_dirt = 1;
+       inode->i_op = &minix_symlink_inode_operations;
        if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
                iput(dir);
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                return -ENOSPC;
        }
@@ -528,8 +511,9 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
        if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
                iput(dir);
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
-               return -ERROR;
+               return -EIO;
        }
        i = 0;
        while (i < 1023 && (c=get_fs_byte(symname++)))
@@ -542,6 +526,7 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
        bh = minix_find_entry(dir,name,len,&de);
        if (bh) {
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                brelse(bh);
                iput(dir);
@@ -550,6 +535,7 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
        bh = minix_add_entry(dir,name,len,&de);
        if (!bh) {
                inode->i_nlink--;
+               inode->i_dirt = 1;
                iput(inode);
                iput(dir);
                return -ENOSPC;
@@ -667,6 +653,10 @@ start_up:
        old_inode = iget(old_dir->i_dev, old_de->inode);
        if (!old_inode)
                goto end_rename;
+       if ((old_dir->i_mode & S_ISVTX) && 
+           current->euid != old_inode->i_uid &&
+           current->euid != old_dir->i_uid && !suser())
+               goto end_rename;
        new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
        if (new_bh) {
                new_inode = iget(new_dir->i_dev, new_de->inode);
@@ -712,8 +702,10 @@ start_up:
 /* ok, that's it */
        old_de->inode = 0;
        new_de->inode = old_inode->i_ino;
-       if (new_inode)
+       if (new_inode) {
                new_inode->i_nlink--;
+               new_inode->i_dirt = 1;
+       }
        old_bh->b_dirt = 1;
        new_bh->b_dirt = 1;
        if (dir_bh) {
@@ -761,31 +753,3 @@ int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
        wake_up(&wait);
        return result;
 }
-
-int minix_readlink(struct inode * inode, char * buffer, int buflen)
-{
-       struct buffer_head * bh;
-       int i;
-       char c;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               iput(inode);
-               return -EINVAL;
-       }
-       if (buflen > 1023)
-               buflen = 1023;
-       if (inode->i_data[0])
-               bh = bread(inode->i_dev, inode->i_data[0]);
-       else
-               bh = NULL;
-       iput(inode);
-       if (!bh)
-               return 0;
-       i = 0;
-       while (i<buflen && (c = bh->b_data[i])) {
-               i++;
-               put_fs_byte(c,buffer++);
-       }
-       brelse(bh);
-       return i;
-}
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
new file mode 100644 (file)
index 0000000..70fbeb0
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * linux/fs/minix/symlink.c
+ *
+ * minix symlink handling code
+ */
+
+#include <errno.h>
+
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+static int minix_readlink(struct inode *, char *, int);
+static struct inode * minix_follow_link(struct inode *, struct inode *);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations minix_symlink_inode_operations = {
+       NULL,                   /* no file-operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       minix_readlink,         /* readlink */
+       minix_follow_link,      /* follow_link */
+       NULL,                   /* bmap */
+       NULL                    /* truncate */
+};
+
+static struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
+{
+       unsigned short fs;
+       struct buffer_head * bh;
+
+       if (!dir) {
+               dir = current->root;
+               dir->i_count++;
+       }
+       if (!inode) {
+               iput(dir);
+               return NULL;
+       }
+       if (!S_ISLNK(inode->i_mode)) {
+               iput(dir);
+               return inode;
+       }
+       __asm__("mov %%fs,%0":"=r" (fs));
+       if ((current->link_count > 5) || !inode->i_data[0] ||
+          !(bh = bread(inode->i_dev, inode->i_data[0]))) {
+               iput(dir);
+               iput(inode);
+               return NULL;
+       }
+       iput(inode);
+       __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+       current->link_count++;
+       inode = _namei(bh->b_data,dir,1);
+       current->link_count--;
+       __asm__("mov %0,%%fs"::"r" (fs));
+       brelse(bh);
+       return inode;
+}
+
+static int minix_readlink(struct inode * inode, char * buffer, int buflen)
+{
+       struct buffer_head * bh;
+       int i;
+       char c;
+
+       if (!S_ISLNK(inode->i_mode)) {
+               iput(inode);
+               return -EINVAL;
+       }
+       if (buflen > 1023)
+               buflen = 1023;
+       if (inode->i_data[0])
+               bh = bread(inode->i_dev, inode->i_data[0]);
+       else
+               bh = NULL;
+       iput(inode);
+       if (!bh)
+               return 0;
+       i = 0;
+       while (i<buflen && (c = bh->b_data[i])) {
+               i++;
+               put_fs_byte(c,buffer++);
+       }
+       brelse(bh);
+       return i;
+}
index ab72736b5d43e3b0b6c66e39ad97d9f9db7ab203..215daf36663aab1e37e6a1400b69e016c6de9f65 100644 (file)
 #include <fcntl.h>
 #include <sys/stat.h>
 
-static int minix_free_ind(int dev,int block)
+/*
+ * Truncate has the most races in the whole filesystem: coding it is
+ * a pain in the a**. Especially as I don't do any locking...
+ *
+ * The code may look a bit weird, but that's just because I've tried to
+ * handle things like file-size changes in a somewhat graceful manner.
+ * Anyway, truncating a file at the same time somebody else writes to it
+ * is likely to result in pretty weird behaviour...
+ *
+ * The new code handles normal truncates (size = 0) as well as the more
+ * general case (size = XXX). I hope.
+ */
+
+static int trunc_direct(struct inode * inode)
 {
-       struct buffer_head * bh;
-       unsigned short * p;
        int i;
-       int block_busy;
+       int result = 0;
+#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
 
-       if (!block)
-               return 1;
-       block_busy = 0;
-       if (bh=bread(dev,block)) {
-               p = (unsigned short *) bh->b_data;
-               for (i=0;i<512;i++,p++)
-                       if (*p)
-                               if (minix_free_block(dev,*p)) {
-                                       *p = 0;
-                                       bh->b_dirt = 1;
-                               } else
-                                       block_busy = 1;
-               brelse(bh);
+repeat:
+       for (i = DIRECT_BLOCK ; i < 7 ; i++) {
+               if (i < DIRECT_BLOCK)
+                       goto repeat;
+               if (!inode->i_data[i])
+                       continue;
+               result = 1;
+               if (minix_free_block(inode->i_dev,inode->i_data[i]))
+                       inode->i_data[i] = 0;
        }
-       if (block_busy)
-               return 0;
-       else
-               return minix_free_block(dev,block);
+       return result;
 }
 
-static int minix_free_dind(int dev,int block)
+static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
 {
-       struct buffer_head * bh;
-       unsigned short * p;
        int i;
-       int block_busy;
+       struct buffer_head * bh = NULL;
+       unsigned short * ind;
+       int result = 0;
+#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
 
-       if (!block)
-               return 1;
-       block_busy = 0;
-       if (bh=bread(dev,block)) {
-               p = (unsigned short *) bh->b_data;
-               for (i=0;i<512;i++,p++)
-                       if (*p)
-                               if (minix_free_ind(dev,*p)) {
-                                       *p = 0;
-                                       bh->b_dirt = 1;
-                               } else
-                                       block_busy = 1;
-               brelse(bh);
-       }
-       if (block_busy)
+       if (*p)
+               bh = bread(inode->i_dev,*p);
+       if (!bh)
                return 0;
-       else
-               return minix_free_block(dev,block);
+repeat:
+       for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
+               if (i < 0)
+                       i = 0;
+               if (i < INDIRECT_BLOCK)
+                       goto repeat;
+               ind = i+(unsigned short *) bh->b_data;
+               if (!*ind)
+                       continue;
+               result = 1;
+               if (minix_free_block(inode->i_dev,*ind))
+                       *ind = 0;
+       }
+       ind = (unsigned short *) bh->b_data;
+       for (i = 0; i < 512; i++)
+               if (*(ind++))
+                       break;
+       brelse(bh);
+       if (i >= 512) {
+               result = 1;
+               if (minix_free_block(inode->i_dev,*p))
+                       *p = 0;
+       }
+       return result;
 }
+               
+static int trunc_dindirect(struct inode * inode)
+{
+       int i;
+       struct buffer_head * bh = NULL;
+       unsigned short * dind;
+       int result = 0;
+#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
 
+       if (inode->i_data[8])
+               bh = bread(inode->i_dev,inode->i_data[8]);
+       if (!bh)
+               return 0;
+repeat:
+       for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
+               if (i < 0)
+                       i = 0;
+               if (i < DINDIRECT_BLOCK)
+                       goto repeat;
+               dind = i+(unsigned short *) bh->b_data;
+               if (!*dind)
+                       continue;
+               result |= trunc_indirect(inode,7+512+(i<<9),dind);
+       }
+       dind = (unsigned short *) bh->b_data;
+       for (i = 0; i < 512; i++)
+               if (*(dind++))
+                       break;
+       brelse(bh);
+       if (i >= 512) {
+               result = 1;
+               if (minix_free_block(inode->i_dev,inode->i_data[8]))
+                       inode->i_data[8] = 0;
+       }
+       return result;
+}
+               
 void minix_truncate(struct inode * inode)
 {
-       int i;
-       int block_busy;
+       int flag;
 
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
             S_ISLNK(inode->i_mode)))
                return;
-repeat:
-       block_busy = 0;
-       for (i=0;i<7;i++)
-               if (inode->i_data[i]) {
-                       if (minix_free_block(inode->i_dev,inode->i_data[i]))
-                               inode->i_data[i]=0;
-                       else
-                               block_busy = 1;
-               }
-       if (minix_free_ind(inode->i_dev,inode->i_data[7]))
-               inode->i_data[7] = 0;
-       else
-               block_busy = 1;
-       if (minix_free_dind(inode->i_dev,inode->i_data[8]))
-               inode->i_data[8] = 0;
-       else
-               block_busy = 1;
-       inode->i_dirt = 1;
-       if (block_busy) {
+       if (inode->i_data[7] & 0xffff0000)
+               printk("BAD! minix inode has 16 high bits set\n");
+       while (1) {
+               flag = trunc_direct(inode);
+               flag |= trunc_indirect(inode,7,(unsigned short *)&inode->i_data[7]);
+               flag |= trunc_dindirect(inode);
+               if (!flag)
+                       break;
                current->counter = 0;
                schedule();
-               goto repeat;
        }
-       inode->i_size = 0;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_dirt = 1;
 }
 
 /*
@@ -110,47 +149,3 @@ void minix_release(struct inode * inode, struct file * filp)
 {
        printk("minix_release not implemented\n");
 }
-
-static int check_char_dev(struct inode * inode, struct file * filp)
-{
-       struct tty_struct *tty;
-       int min, dev;
-
-       dev = inode->i_rdev;
-       if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
-               if (MAJOR(dev) == 5)
-                       min = current->tty;
-               else
-                       min = MINOR(dev);
-               if (min < 0)
-                       return -1;
-               if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
-                       return -1;
-               tty = TTY_TABLE(min);
-               if (!(filp->f_flags & O_NOCTTY) &&
-                   current->leader &&
-                   current->tty<0 &&
-                   tty->session==0) {
-                       current->tty = min;
-                       tty->session= current->session;
-                       tty->pgrp = current->pgrp;
-               }
-               if (IS_A_SERIAL(min))
-                       serial_open(min-64);
-       }
-       return 0;
-}
-
-/*
- * Called every time a minix-file is opened
- */
-int minix_open(struct inode * inode, struct file * filp)
-{
-       if (S_ISCHR(inode->i_mode)) {
-               if (check_char_dev(inode,filp))
-                       return -EAGAIN;
-       } else if (S_ISBLK(inode->i_mode))
-               check_disk_change(inode->i_rdev);
-       filp->f_op = &minix_file_operations;
-       return 0;
-}
index 6833d622a70e41be682a22a3f7003846b7c65c0a..c4f4acca3e1482d4c790c065f007d3095ffbb317 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <asm/segment.h>
 
-#include <string.h>
+#include <linux/string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <const.h>
@@ -167,10 +167,6 @@ struct inode * _namei(const char * pathname, struct inode * base,
                inode = follow_link(base,inode);
        else
                iput(base);
-       if (inode) {
-               inode->i_atime=CURRENT_TIME;
-               inode->i_dirt=1;
-       }
        return inode;
 }
 
@@ -248,8 +244,10 @@ int open_namei(const char * pathname, int flag, int mode,
        }
        inode->i_atime = CURRENT_TIME;
        if (flag & O_TRUNC)
-               if (inode->i_op && inode->i_op->truncate)
+               if (inode->i_op && inode->i_op->truncate) {
+                       inode->i_size = 0;
                        inode->i_op->truncate(inode);
+               }
        *res_inode = inode;
        return 0;
 }
index fe0fb5b5db9d8db7760acc2c6d39853be154eeb2..3e47592ce1777498dd1ea779b6cd4ca4d129daf1 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,23 +4,83 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <utime.h>
+
 #include <sys/stat.h>
+#include <sys/vfs.h>
 
+#include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 
 #include <asm/segment.h>
 
+struct file_operations * chrdev_fops[MAX_CHRDEV] = {
+       NULL,
+};
+
+struct file_operations * blkdev_fops[MAX_BLKDEV] = {
+       NULL,
+};
+
 int sys_ustat(int dev, struct ustat * ubuf)
 {
        return -ENOSYS;
 }
 
+int sys_statfs(const char * path, struct statfs * buf)
+{
+       printk("statfs not implemented\n");
+       return -ENOSYS;
+}
+
+int sys_fstatfs(unsigned int fd, struct statfs * buf)
+{
+       printk("fstatfs not implemented\n");
+       return -ENOSYS;
+}
+
+int sys_truncate(const char * path, unsigned int length)
+{
+       struct inode * inode;
+
+       if (!(inode = namei(path)))
+               return -ENOENT;
+       if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
+               iput(inode);
+               return -EACCES;
+       }
+       inode->i_size = length;
+       if (inode->i_op && inode->i_op->truncate)
+               inode->i_op->truncate(inode);
+       inode->i_atime = inode->i_mtime = CURRENT_TIME;
+       inode->i_dirt = 1;
+       iput(inode);
+       return 0;
+}
+
+int sys_ftruncate(unsigned int fd, unsigned int length)
+{
+       struct inode * inode;
+       struct file * file;
+
+       if (fd >= NR_OPEN || !(file = current->filp[fd]))
+               return -EBADF;
+       if (!(inode = file->f_inode))
+               return -ENOENT;
+       if (S_ISDIR(inode->i_mode) || !(file->f_flags & 2))
+               return -EACCES;
+       inode->i_size = length;
+       if (inode->i_op && inode->i_op->truncate)
+               inode->i_op->truncate(inode);
+       inode->i_atime = inode->i_mtime = CURRENT_TIME;
+       inode->i_dirt = 1;
+       return 0;
+}
+
 int sys_utime(char * filename, struct utimbuf * times)
 {
        struct inode * inode;
@@ -32,7 +92,7 @@ int sys_utime(char * filename, struct utimbuf * times)
                if (current->euid != inode->i_uid &&
                    !permission(inode,MAY_WRITE)) {
                        iput(inode);
-                       return -EPERM;
+                       return -EACCES;
                }
                actime = get_fs_long((unsigned long *) &times->actime);
                modtime = get_fs_long((unsigned long *) &times->modtime);
@@ -87,6 +147,10 @@ int sys_chdir(const char * filename)
                iput(inode);
                return -ENOTDIR;
        }
+       if (!permission(inode,MAY_EXEC)) {
+               iput(inode);
+               return -EACCES;
+       }
        iput(current->pwd);
        current->pwd = inode;
        return (0);
@@ -102,20 +166,40 @@ int sys_chroot(const char * filename)
                iput(inode);
                return -ENOTDIR;
        }
+       if (!suser()) {
+               iput(inode);
+               return -EPERM;
+       }
        iput(current->root);
        current->root = inode;
        return (0);
 }
 
-int sys_chmod(const char * filename,int mode)
+int sys_fchmod(unsigned int fd, mode_t mode)
 {
        struct inode * inode;
+       struct file * file;
 
-       if (!(inode=namei(filename)))
+       if (fd >= NR_OPEN || !(file = current->filp[fd]))
+               return -EBADF;
+       if (!(inode = file->f_inode))
+               return -ENOENT;
+       if ((current->euid != inode->i_uid) && !suser())
+               return -EPERM;
+       inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
+       inode->i_dirt = 1;
+       return 0;
+}
+
+int sys_chmod(const char * filename, mode_t mode)
+{
+       struct inode * inode;
+
+       if (!(inode = namei(filename)))
                return -ENOENT;
        if ((current->euid != inode->i_uid) && !suser()) {
                iput(inode);
-               return -EACCES;
+               return -EPERM;
        }
        inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
        inode->i_dirt = 1;
@@ -123,21 +207,43 @@ int sys_chmod(const char * filename,int mode)
        return 0;
 }
 
-int sys_chown(const char * filename,int uid,int gid)
+int sys_fchown(unsigned int fd, uid_t user, gid_t group)
 {
        struct inode * inode;
+       struct file * file;
 
-       if (!(inode=namei(filename)))
+       if (fd >= NR_OPEN || !(file = current->filp[fd]))
+               return -EBADF;
+       if (!(inode = file->f_inode))
                return -ENOENT;
-       if (!suser()) {
+       if ((current->euid == inode->i_uid && user == inode->i_uid &&
+            (in_group_p(group) || group == inode->i_gid)) ||
+           suser()) {
+               inode->i_uid = user;
+               inode->i_gid = group;
+               inode->i_dirt=1;
+               return 0;
+       }
+       return -EPERM;
+}
+
+int sys_chown(const char * filename, uid_t user, gid_t group)
+{
+       struct inode * inode;
+
+       if (!(inode = lnamei(filename)))
+               return -ENOENT;
+       if ((current->euid == inode->i_uid && user == inode->i_uid &&
+            (in_group_p(group) || group == inode->i_gid)) ||
+           suser()) {
+               inode->i_uid = user;
+               inode->i_gid = group;
+               inode->i_dirt=1;
                iput(inode);
-               return -EACCES;
+               return 0;
        }
-       inode->i_uid=uid;
-       inode->i_gid=gid;
-       inode->i_dirt=1;
        iput(inode);
-       return 0;
+       return -EPERM;
 }
 
 int sys_open(const char * filename,int flag,int mode)
@@ -157,20 +263,23 @@ int sys_open(const char * filename,int flag,int mode)
                if (!f->f_count) break;
        if (i>=NR_FILE)
                return -EINVAL;
-       (current->filp[fd]=f)->f_count++;
-       if ((i=open_namei(filename,flag,mode,&inode))<0) {
+       (current->filp[fd] = f)->f_count++;
+       if ((i = open_namei(filename,flag,mode,&inode))<0) {
                current->filp[fd]=NULL;
                f->f_count=0;
                return i;
        }
-       f->f_op = NULL;
        f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
        f->f_flags = flag;
        f->f_count = 1;
        f->f_inode = inode;
        f->f_pos = 0;
-       if (inode->i_op && inode->i_op->open)
-               if (i = inode->i_op->open(inode,f)) {
+       f->f_reada = 0;
+       f->f_op = NULL;
+       if (inode->i_op)
+               f->f_op = inode->i_op->default_file_ops;
+       if (f->f_op && f->f_op->open)
+               if (i = f->f_op->open(inode,f)) {
                        iput(inode);
                        f->f_count=0;
                        current->filp[fd]=NULL;
@@ -194,10 +303,17 @@ int sys_close(unsigned int fd)
        if (!(filp = current->filp[fd]))
                return -EINVAL;
        current->filp[fd] = NULL;
-       if (filp->f_count == 0)
-               panic("Close: file count is 0");
-       if (--filp->f_count)
-               return (0);
+       if (filp->f_count == 0) {
+               printk("Close: file count is 0\n");
+               return 0;
+       }
+       if (filp->f_count > 1) {
+               filp->f_count--;
+               return 0;
+       }
+       if (filp->f_op && filp->f_op->release)
+               filp->f_op->release(filp->f_inode,filp);
        iput(filp->f_inode);
-       return (0);
+       filp->f_count--;
+       return 0;
 }
index 5f773d9c155c22a99ee98bf171cb40f6cc790b7a..1657ccb529d540143ca7ba22341399a202956e00 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -9,11 +9,12 @@
 #include <termios.h>
 #include <fcntl.h>
 
-#include <linux/sched.h>
 #include <asm/segment.h>
+
+#include <linux/sched.h>
 #include <linux/kernel.h>
 
-int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
+static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
 {
        int chars, size, read = 0;
 
@@ -44,7 +45,7 @@ int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
        return read?read:-EAGAIN;
 }
        
-int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
+static int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
 {
        int chars, size, written = 0;
 
@@ -76,6 +77,68 @@ int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
        return written;
 }
 
+static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+       return -ESPIPE;
+}
+
+static int pipe_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
+{
+       return -ENOTDIR;
+}
+
+static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int count)
+{
+       return -EBADF;
+}
+
+static int pipe_ioctl(struct inode *pino, struct file * filp,
+       unsigned int cmd, unsigned int arg)
+{
+       switch (cmd) {
+               case FIONREAD:
+                       verify_area((void *) arg,4);
+                       put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
+                       return 0;
+               default:
+                       return -EINVAL;
+       }
+}
+
+/*
+ * Ok, these two routines should keep track of readers/writers,
+ * but it's currently done with the inode->i_count checking.
+ */
+static void pipe_read_release(struct inode * inode, struct file * filp)
+{
+}
+
+static void pipe_write_release(struct inode * inode, struct file * filp)
+{
+}
+
+static struct file_operations read_pipe_fops = {
+       pipe_lseek,
+       pipe_read,
+       bad_pipe_rw,
+       pipe_readdir,
+       NULL,           /* pipe_select */
+       pipe_ioctl,
+       NULL,           /* no special open code */
+       pipe_read_release
+};
+
+static struct file_operations write_pipe_fops = {
+       pipe_lseek,
+       bad_pipe_rw,
+       pipe_write,
+       pipe_readdir,
+       NULL,           /* pipe_select */
+       pipe_ioctl,
+       NULL,           /* no special open code */
+       pipe_write_release
+};
+
 int sys_pipe(unsigned long * fildes)
 {
        struct inode * inode;
@@ -111,21 +174,11 @@ int sys_pipe(unsigned long * fildes)
        }
        f[0]->f_inode = f[1]->f_inode = inode;
        f[0]->f_pos = f[1]->f_pos = 0;
+       f[0]->f_op = &read_pipe_fops;
        f[0]->f_mode = 1;               /* read */
+       f[1]->f_op = &write_pipe_fops;
        f[1]->f_mode = 2;               /* write */
        put_fs_long(fd[0],0+fildes);
        put_fs_long(fd[1],1+fildes);
        return 0;
 }
-
-int pipe_ioctl(struct inode *pino, int cmd, int arg)
-{
-       switch (cmd) {
-               case FIONREAD:
-                       verify_area((void *) arg,4);
-                       put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-}
index 1a9b20a4a066ad3fce03b8dc6bcdabd6debf32d1..b28d7e7eeca403f82db1de6120b6fa673cff52e9 100644 (file)
@@ -28,43 +28,41 @@ int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
                return -EBADF;
        if (file->f_op && file->f_op->readdir) {
                verify_area(dirent, sizeof (*dirent));
-               return file->f_op->readdir(inode,file,dirent);
+               return file->f_op->readdir(inode,file,dirent,count);
        }
-       return -EBADF;
+       return -ENOTDIR;
 }
 
 int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
        struct file * file;
-       int tmp, mem_dev;
+       int tmp;
 
        if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode))
                return -EBADF;
        if (origin > 2)
                return -EINVAL;
-       if (file->f_inode->i_pipe)
-               return -ESPIPE;
        if (file->f_op && file->f_op->lseek)
                return file->f_op->lseek(file->f_inode,file,offset,origin);
-       mem_dev = S_ISCHR(file->f_inode->i_mode);
 
 /* this is the default handler if no lseek handler is present */
        switch (origin) {
                case 0:
-                       if (offset<0 && !mem_dev) return -EINVAL;
-                       file->f_pos=offset;
+                       tmp = offset;
                        break;
                case 1:
-                       if (file->f_pos+offset<0 && !mem_dev) return -EINVAL;
-                       file->f_pos += offset;
+                       tmp = file->f_pos + offset;
                        break;
                case 2:
-                       if ((tmp=file->f_inode->i_size+offset)<0 && !mem_dev)
+                       if (!file->f_inode)
                                return -EINVAL;
-                       file->f_pos = tmp;
+                       tmp = file->f_inode->i_size + offset;
+                       break;
        }
-       if (mem_dev && file->f_pos < 0)
-               return 0;
+       if (tmp < 0)
+               return -EINVAL;
+       file->f_pos = tmp;
+       file->f_reada = 0;
        return file->f_pos;
 }
 
@@ -82,15 +80,6 @@ int sys_read(unsigned int fd,char * buf,unsigned int count)
        verify_area(buf,count);
        if (file->f_op && file->f_op->read)
                return file->f_op->read(inode,file,buf,count);
-/* these are the default read-functions */
-       if (inode->i_pipe)
-               return pipe_read(inode,file,buf,count);
-       if (S_ISCHR(inode->i_mode))
-               return char_read(inode,file,buf,count);
-       if (S_ISBLK(inode->i_mode))
-               return block_read(inode,file,buf,count);
-       if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode))
-               return minix_file_read(inode,file,buf,count);
        printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
        return -EINVAL;
 }
@@ -108,15 +97,6 @@ int sys_write(unsigned int fd,char * buf,unsigned int count)
                return 0;
        if (file->f_op && file->f_op->write)
                return file->f_op->write(inode,file,buf,count);
-/* these are the default read-functions */
-       if (inode->i_pipe)
-               return pipe_write(inode,file,buf,count);
-       if (S_ISCHR(inode->i_mode))
-               return char_write(inode,file,buf,count);
-       if (S_ISBLK(inode->i_mode))
-               return block_write(inode,file,buf,count);
-       if (S_ISREG(inode->i_mode))
-               return minix_file_write(inode,file,buf,count);
        printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
        return -EINVAL;
 }
index e5d14396bc6f8e4226f263f438337d2315cfc1d0..efd65491958575209232b320c32f779dad079ca2 100644 (file)
@@ -9,16 +9,17 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
+#include <linux/string.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
 
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <string.h>
+#include <sys/time.h>
+
 #include <const.h>
 #include <errno.h>
-#include <sys/time.h>
 #include <signal.h>
 
 /*
  * task.
  */
 
-typedef struct {
-       struct task_struct * old_task;
-       struct task_struct ** wait_address;
-} wait_entry;
-
-typedef struct select_table_struct {
-       int nr, woken;
-       struct task_struct * current;
-       struct select_table_struct * next_table;
-       wait_entry entry[NR_OPEN*3];
-} select_table;
-
 static select_table * sel_tables = NULL;
 
 static void add_wait(struct task_struct ** wait_address, select_table * p)
@@ -138,6 +127,11 @@ static int check_in(select_table * wait, struct inode * inode)
                        return 1;
                else
                        add_wait(&inode->i_wait, wait);
+       else if (S_ISSOCK(inode->i_mode))
+               if (sock_select(inode, NULL, SEL_IN, wait))
+                       return 1;
+               else
+                       add_wait(&inode->i_wait, wait);
        return 0;
 }
 
@@ -155,6 +149,11 @@ static int check_out(select_table * wait, struct inode * inode)
                        return 1;
                else
                        add_wait(&inode->i_wait, wait);
+       else if (S_ISSOCK(inode->i_mode))
+               if (sock_select(inode, NULL, SEL_OUT, wait))
+                       return 1;
+               else
+                       add_wait(&inode->i_wait, wait);
        return 0;
 }
 
@@ -172,6 +171,11 @@ static int check_ex(select_table * wait, struct inode * inode)
                        return 1;
                else
                        add_wait(&inode->i_wait,wait);
+       else if (S_ISSOCK(inode->i_mode))
+               if (sock_select(inode, NULL, SEL_EX, wait))
+                       return 1;
+               else
+                       add_wait(&inode->i_wait, wait);
        return 0;
 }
 
@@ -197,6 +201,8 @@ int do_select(fd_set in, fd_set out, fd_set ex,
                        continue;
                if (S_ISFIFO(current->filp[i]->f_inode->i_mode))
                        continue;
+               if (S_ISSOCK(current->filp[i]->f_inode->i_mode))
+                       continue;
                return -EBADF;
        }
 repeat:
@@ -207,6 +213,7 @@ repeat:
        sel_tables = &wait_table;
        *inp = *outp = *exp = 0;
        count = 0;
+       current->state = TASK_INTERRUPTIBLE;
        mask = 1;
        for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
                if (mask & in)
@@ -227,14 +234,12 @@ repeat:
        }
        if (!(current->signal & ~current->blocked) &&
            current->timeout && !count) {
-               current->state = TASK_INTERRUPTIBLE;
-               sti();
                schedule();
-               cli();
                free_wait(&wait_table);
                goto repeat;
        }
        free_wait(&wait_table);
+       current->state = TASK_RUNNING;
        return count;
 }
 
@@ -277,13 +282,11 @@ int sys_select( unsigned long *buffer )
                timeout += jiffies;
        }
        current->timeout = timeout;
-       cli();
        i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
        if (current->timeout > jiffies)
                timeout = current->timeout - jiffies;
        else
                timeout = 0;
-       sti();
        current->timeout = 0;
        if (i < 0)
                return i;
index b4c95e0315ff2bb5fea8d72d892249f38376b41e..78f8b6c0a4ceaa35bd05d30d96241adfbc32a66d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/minix_fs.h>
 #include <linux/kernel.h>
 #include <asm/system.h>
+#include <asm/segment.h>
 
 #include <errno.h>
 #include <sys/stat.h>
@@ -146,7 +147,9 @@ int sys_umount(char * dev_name)
        struct super_block * sb;
        int dev;
 
-       if (!(inode=namei(dev_name)))
+       if (!suser())
+               return -EPERM;
+       if (!(inode = namei(dev_name)))
                return -ENOENT;
        dev = inode->i_rdev;
        if (!S_ISBLK(inode->i_mode)) {
@@ -176,13 +179,17 @@ int sys_umount(char * dev_name)
        return 0;
 }
 
-int sys_mount(char * dev_name, char * dir_name, int rw_flag)
+int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag)
 {
        struct inode * dev_i, * dir_i;
        struct super_block * sb;
        int dev;
+       char tmp[100],*t;
+       int i;
 
-       if (!(dev_i=namei(dev_name)))
+       if (!suser())
+               return -EPERM;
+       if (!(dev_i = namei(dev_name)))
                return -ENOENT;
        dev = dev_i->i_rdev;
        if (!S_ISBLK(dev_i->i_mode)) {
@@ -204,7 +211,14 @@ int sys_mount(char * dev_name, char * dir_name, int rw_flag)
                iput(dir_i);
                return -EPERM;
        }
-       if (!(sb=read_super(dev,"minix",NULL))) {
+       if (type) {
+               i = 0;
+               while (i < 100 && (tmp[i] = get_fs_byte(type++)))
+                       i++;
+               t = tmp;
+       } else
+               t = "minix";
+       if (!(sb = read_super(dev,t,NULL))) {
                iput(dir_i);
                return -EBUSY;
        }
index 226f3439bf60525ea490d08709533ced10fc8936..af1c72feb6ecae64c08b8aeb16e74fc69366816b 100644 (file)
@@ -1,6 +1,14 @@
 #ifndef _ASM_IO_H
 #define _ASM_IO_H
 
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ *             Linus
+ */
+
 extern void inline outb(char value, unsigned short port)
 {
 __asm__ volatile ("outb %0,%1"
@@ -9,12 +17,11 @@ __asm__ volatile ("outb %0,%1"
 
 extern void inline outb_p(char value, unsigned short port)
 {
-__asm__ volatile ("outb %0,%1\n"
-                 "\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:"
+__asm__ volatile ("outb %0,%1\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80"
                ::"a" ((char) value),"d" ((unsigned short) port));
 }
 
@@ -29,12 +36,11 @@ __asm__ volatile ("inb %1,%0"
 extern unsigned char inline inb_p(unsigned short port)
 {
        unsigned char _v;
-__asm__ volatile ("inb %1,%0\n"
-                 "\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:\tjmp 1f\n"
-               "1:"
+__asm__ volatile ("inb %1,%0\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80\n\t"
+                 "outb %0,$0x80"
                :"=a" (_v):"d" ((unsigned short) port));
        return _v;
 }
index 6f5f670bad04454b05b8f276644f73b75a26c801..6fbcf1bba0824ce5b75b3d8714507590d73e9b42 100644 (file)
@@ -50,7 +50,7 @@ __asm__ ("movw %%dx,%%ax\n\t" \
                ((limit) & 0x0ffff); }
 
 #define _set_tssldt_desc(n,addr,type) \
-__asm__ ("movw $104,%1\n\t" \
+__asm__ ("movw $232,%1\n\t" \
        "movw %%ax,%2\n\t" \
        "rorl $16,%%eax\n\t" \
        "movb %%al,%3\n\t" \
diff --git a/include/ctype.h b/include/ctype.h
deleted file mode 100644 (file)
index 7acf55d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _CTYPE_H
-#define _CTYPE_H
-
-#define _U     0x01    /* upper */
-#define _L     0x02    /* lower */
-#define _D     0x04    /* digit */
-#define _C     0x08    /* cntrl */
-#define _P     0x10    /* punct */
-#define _S     0x20    /* white space (space/lf/tab) */
-#define _X     0x40    /* hex digit */
-#define _SP    0x80    /* hard space (0x20) */
-
-extern unsigned char _ctype[];
-extern char _ctmp;
-
-#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
-#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
-#define iscntrl(c) ((_ctype+1)[c]&(_C))
-#define isdigit(c) ((_ctype+1)[c]&(_D))
-#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
-#define islower(c) ((_ctype+1)[c]&(_L))
-#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
-#define ispunct(c) ((_ctype+1)[c]&(_P))
-#define isspace(c) ((_ctype+1)[c]&(_S))
-#define isupper(c) ((_ctype+1)[c]&(_U))
-#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
-
-#define isascii(c) (((unsigned) c)<=0x7f)
-#define toascii(c) (((unsigned) c)&0x7f)
-
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
-
-#endif
index a38b78fd239c2a2cd1a56aef94fb8d1f6f7d460d..fdb1b14b58c67242f0e4548904b7561bcb20ac23 100644 (file)
@@ -16,7 +16,6 @@
 
 extern int errno;
 
-#define ERROR          99
 #define EPERM           1
 #define ENOENT          2
 #define ESRCH           3
diff --git a/include/linux/config.dist.h b/include/linux/config.dist.h
new file mode 100644 (file)
index 0000000..4a84fbf
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _CONFIG_DIST_H
+#define _CONFIG_DIST_H
+#ifdef CONFIG_DISTRIBUTION
+
+#undef CONFG_SCSI
+#define CONFIG_SCSI
+
+#undef CONFIG_SCSI_AHA1542
+#define CONFIG_SCSI_AHA1542
+#undef CONFIG_SCSI_CSC
+#define CONFIG_SCSI_CSC
+#undef CONFIG_SCSI_DTC
+#define CONFIG_SCSI_DTC
+#undef CONFIG_SCSI_FUTURE_DOMAIN
+#define CONFIG_SCSI_FUTURE_DOMAIN
+#undef CONFIG_SCSI_SEAGATE
+#define CONFIG_SCSI_SEAGATE
+#undef CONFIG_SCSI_ULTRASTOR
+#define CONFIG_SCSI_ULTRASTOR
+
+#undef CONFIG_BLK_DEV_SD
+#define CONFIG_BLK_DEV_SD
+#undef CONFIG_BLK_DEV_ST
+#define CONFIG_BLK_DEV_ST
+
+#endif
+#endif
index 8c79f935c3759dbf60ecd7ea21d6ea6c614e5e36..db499dc26301b75bd158d742f414afd535cdb55d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
+#define CONFIG_DISTRIBUTION
+
 /*
  * Defines for what uname() should return 
  */
  leave HD_TYPE undefined. This is the normal thing to do.
 */
 
+#undef HD_TYPE
+
+#undef CONFIG_BLK_DEV_SD
+#undef CONFIG_BLK_DEV_ST
+
+/*
+       Choose supported SCSI adapters here.
+*/
+
+#undef CONFIG_SCSI_AHA1542
+#undef CONFIG_SCSI_ALWAYS
+#undef CONFIG_SCSI_CSC
+#undef CONFIG_SCSI_DTC
+#undef CONFIG_SCSI_FUTURE_DOMAIN
+#undef CONFIG_SCSI_SEAGATE
+#undef CONFIG_SCSI_ULTRASTOR
+
+#if defined(CONFIG_BLK_DEV_SD) || defined(CONFIG_BLK_DEV_ST)
+       #ifndef CONFIG_SCSI
+               #define CONFIG_SCSI
+       #endif
+       
+       #if !defined(CONFIG_SCSI_AHA1542) && !defined(CONFIG_SCSI_CSC) && !defined(CONFIG_SCSI_DTC) && \
+               !defined(CONFIG_SCSI_FUTURE_DOMAIN) &&  !defined(CONFIG_SCSI_SEAGATE) && !defined(CONFIG_SCSI_ULTRASTOR) 
+
+       #error  Error : SCSI devices enabled, but no low level drivers have been enabled.
+       #endif
+#endif
+
+#ifdef CONFIG_DISTRIBUTION
+       #include <linux/config.dist.h>
+#else
+       #include <linux/config.site.h>
+#endif
+
+/*
+       File type specific stuff goes into this.
+*/
+
+#ifdef ASM_SRC
+#endif
+
+#ifdef C_SRC
+#endif
+
+#ifdef MAKE
+#endif
+
 #endif
diff --git a/include/linux/config.site.h b/include/linux/config.site.h
new file mode 100644 (file)
index 0000000..49b731b
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _CONFIG_SITE_H
+#define _CONFIG_SITE_H
+
+/*
+       This configuration file contains site specific things, things 
+       that you have added and config.dist will not know about.
+*/
+
+#endif
index 0e26529824ec9268c252f6b5845b7495bd71799b..e1998799de1161d893c225f9a4d714ea7ba72645 100644 (file)
@@ -1 +1 @@
-#define UTS_RELEASE "0.95c-18"
+#define UTS_RELEASE "0.96a-10"
index 102462450c5fb9a1920ecd03983d82e968a443f2..dde55d7a44879db039460ac08ee73f96b99d7775 100644 (file)
@@ -1 +1 @@
-#define UTS_VERSION "04/09/92"
+#define UTS_VERSION "05/22/92"
diff --git a/include/linux/ctype.h b/include/linux/ctype.h
new file mode 100644 (file)
index 0000000..7acf55d
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#define _U     0x01    /* upper */
+#define _L     0x02    /* lower */
+#define _D     0x04    /* digit */
+#define _C     0x08    /* cntrl */
+#define _P     0x10    /* punct */
+#define _S     0x20    /* white space (space/lf/tab) */
+#define _X     0x40    /* hex digit */
+#define _SP    0x80    /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+extern char _ctmp;
+
+#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
+#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
+#define iscntrl(c) ((_ctype+1)[c]&(_C))
+#define isdigit(c) ((_ctype+1)[c]&(_D))
+#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
+#define islower(c) ((_ctype+1)[c]&(_L))
+#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
+#define ispunct(c) ((_ctype+1)[c]&(_P))
+#define isspace(c) ((_ctype+1)[c]&(_S))
+#define isupper(c) ((_ctype+1)[c]&(_U))
+#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
+
+#define isascii(c) (((unsigned) c)<=0x7f)
+#define toascii(c) (((unsigned) c)&0x7f)
+
+#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
+#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
+
+#endif
diff --git a/include/linux/fd.h b/include/linux/fd.h
new file mode 100644 (file)
index 0000000..990dce5
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _FD_H_
+#define _FD_H
+
+#define FDCLRPRM 0 /* clear user-defined parameters */
+#define FDSETPRM 1 /* set user-defined parameters for current media */
+#define FDDEFPRM 2 /* set user-defined parameters until explicitly cleared */
+#define FDGETPRM 3 /* get disk parameters */
+#define        FDMSGON  4 /* issue kernel messages on media type change */
+#define        FDMSGOFF 5 /* don't issue kernel messages on media type change */
+#define FDFMTBEG 6 /* begin formatting a disk */
+#define        FDFMTTRK 7 /* format the specified track */
+#define FDFMTEND 8 /* end formatting a disk */
+
+#define FD_FILL_BYTE 0xF6 /* format fill byte */
+
+#define FORMAT_NONE    0       /* no format request */
+#define FORMAT_WAIT    1       /* format request is waiting */
+#define FORMAT_BUSY    2       /* formatting in progress */
+#define FORMAT_OKAY    3       /* successful completion */
+#define FORMAT_ERROR   4       /* formatting error */
+
+struct floppy_struct {
+       unsigned int size, sect, head, track, stretch;
+       unsigned char gap,rate,spec1,fmt_gap;
+       char *name; /* used only for predefined formats */
+};
+
+struct format_descr {
+    unsigned int device,head,track;
+};
+
+#endif
index 01355af4a7ed9961a61f1ba894a6cf1ac696f10c..77a270eb398cb292a13b02eda8e0d0885224e97a 100644 (file)
@@ -63,6 +63,7 @@ extern void floppy_deselect(unsigned int nr);
 #define FD_WRITE       0xC5            /* write with MT, MFM */
 #define FD_SENSEI      0x08            /* Sense Interrupt Status */
 #define FD_SPECIFY     0x03            /* specify HUT etc */
+#define FD_FORMAT      0x4D            /* format one track */
 
 /* DMA commands */
 #define DMA_READ       0x46
index d75dd80f491063a1c9afaa5fcea5fe91657069d0..c4bcb8420e2c5f49eec11fe687a3dae1d696110c 100644 (file)
  * 5 - /dev/tty
  * 6 - /dev/lp
  * 7 - unnamed pipes
+ * 8 - /dev/sd
+ * 9 - /dev/st
  */
 
-#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3)
+#define IS_SEEKABLE(x) ((x)>=1 && (x)<=3 || (x)==8)
 
 #define MAY_EXEC 1
 #define MAY_WRITE 2
@@ -46,6 +48,9 @@ void buffer_init(long buffer_end);
 #define NR_BUFFERS nr_buffers
 #define BLOCK_SIZE 1024
 #define BLOCK_SIZE_BITS 10
+#define MAX_CHRDEV 16
+#define MAX_BLKDEV 16
+
 #ifndef NULL
 #define NULL ((void *) 0)
 #endif
@@ -78,6 +83,7 @@ struct buffer_head {
        struct buffer_head * b_next;
        struct buffer_head * b_prev_free;
        struct buffer_head * b_next_free;
+       struct buffer_head * b_reqnext;
 };
 
 struct inode {
@@ -110,11 +116,24 @@ struct file {
        unsigned short f_mode;
        unsigned short f_flags;
        unsigned short f_count;
+       unsigned short f_reada;
        struct inode * f_inode;
        struct file_operations * f_op;
        off_t f_pos;
 };
 
+typedef struct {
+       struct task_struct * old_task;
+       struct task_struct ** wait_address;
+} wait_entry;
+
+typedef struct select_table_struct {
+       int nr, woken;
+       struct task_struct * current;
+       struct select_table_struct * next_table;
+       wait_entry entry[NR_OPEN*3];
+} select_table;
+
 struct super_block {
        unsigned short s_ninodes;
        unsigned short s_nzones;
@@ -143,10 +162,15 @@ struct file_operations {
        int (*lseek) (struct inode *, struct file *, off_t, int);
        int (*read) (struct inode *, struct file *, char *, int);
        int (*write) (struct inode *, struct file *, char *, int);
-       int (*readdir) (struct inode *, struct file *, struct dirent *);
+       int (*readdir) (struct inode *, struct file *, struct dirent *, int count);
+       int (*select) (struct inode *, struct file *, int, select_table *);
+       int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned int);
+       int (*open) (struct inode *, struct file *);
+       void (*release) (struct inode *, struct file *);
 };
 
 struct inode_operations {
+       struct file_operations * default_file_ops;
        int (*create) (struct inode *,const char *,int,int,struct inode **);
        int (*lookup) (struct inode *,const char *,int,struct inode **);
        int (*link) (struct inode *,struct inode *,const char *,int);
@@ -157,18 +181,15 @@ struct inode_operations {
        int (*mknod) (struct inode *,const char *,int,int,int);
        int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
        int (*readlink) (struct inode *,char *,int);
-       int (*open) (struct inode *, struct file *);
-       void (*release) (struct inode *, struct file *);
        struct inode * (*follow_link) (struct inode *, struct inode *);
        int (*bmap) (struct inode *,int);
        void (*truncate) (struct inode *);
-       /* added by entropy */
-       void (*write_inode)(struct inode *inode);
-       void (*put_inode)(struct inode *inode);
 };
 
 struct super_operations {
        void (*read_inode)(struct inode *inode);
+       void (*write_inode) (struct inode *inode);
+       void (*put_inode) (struct inode *inode);
        void (*put_super)(struct super_block *sb);
 };
 
@@ -177,6 +198,9 @@ struct file_system_type {
        char *name;
 };
 
+extern struct file_operations * chrdev_fops[MAX_CHRDEV];
+extern struct file_operations * blkdev_fops[MAX_BLKDEV];
+
 extern struct file_system_type *get_fs_type(char *name);
 
 extern struct inode inode_table[NR_INODE];
@@ -190,7 +214,6 @@ extern int floppy_change(struct buffer_head * first_block);
 extern int ticks_to_floppy_on(unsigned int dev);
 extern void floppy_on(unsigned int dev);
 extern void floppy_off(unsigned int dev);
-extern void truncate(struct inode * inode);
 extern void sync_inodes(void);
 extern void wait_on(struct inode * inode);
 extern int bmap(struct inode * inode,int block);
@@ -222,11 +245,9 @@ extern void mount_root(void);
 extern void lock_super(struct super_block * sb);
 extern void free_super(struct super_block * sb);
 
-extern int pipe_read(struct inode *, struct file *, char *, int);
 extern int char_read(struct inode *, struct file *, char *, int);
 extern int block_read(struct inode *, struct file *, char *, int);
 
-extern int pipe_write(struct inode *, struct file *, char *, int);
 extern int char_write(struct inode *, struct file *, char *, int);
 extern int block_write(struct inode *, struct file *, char *, int);
 
index eab299bc3b17abef2a3371ce26c81b0d71b8734e..ef27d832fa1781abccddd7bf4170b1ca754c3636 100644 (file)
@@ -4,10 +4,7 @@
 void verify_area(void * addr,int count);
 volatile void panic(const char * str);
 volatile void do_exit(long error_code);
-int printf(const char * fmt, ...);
 int printk(const char * fmt, ...);
-void console_print(const char * str);
-int tty_write(unsigned ch,char * buf,int count);
 void * malloc(unsigned int size);
 void free_s(void * obj, int size);
 
index 69049a73880e26088bcfc029ed967c405c380295..dd92cf09d541b1b5712bb8b409ed12e2aed37f04 100644 (file)
@@ -31,9 +31,7 @@ $Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wie
 
 #define LP_B(minor)    lp_table[(minor)].base
 #define LP_F(minor)    lp_table[(minor)].flags
-#define LP_T(minor)    lp_table[(minor)].lp_task
 #define LP_S(minor)    inb(LP_B((minor)) + 1)
-#define LP_R(minor)    lp_table[(minor)].remainder
 
 /* 
 since we are dealing with a horribly slow device
@@ -45,10 +43,6 @@ I don't see the need for a queue
 struct lp_struct {
        int base;
        int flags;
-       /* number of characters yet to be printed in current block */
-       int remainder;
-       /* needed for busy determination */
-       int lp_task;
 };
 
 /* 
@@ -107,8 +101,3 @@ struct lp_struct lp_table[] = {
  */
 
 extern void lp_init(void);
-
-extern int lp_reset(int minor);
-extern int lp_char(char lpchar, int minor);
-extern int lp_write(unsigned minor, char *buf, int count);
-
index 189f438f190f6c9f6e549c83a69a71e191f8f75f..a51b60c77fc93e3559c0492ef5c45a28af97b638 100644 (file)
@@ -45,7 +45,6 @@ struct minix_dir_entry {
 
 extern int minix_open(struct inode * inode, struct file * filp);
 extern void minix_release(struct inode * inode, struct file * filp);
-extern struct inode * minix_follow_link(struct inode * dir, struct inode * inode);
 extern int minix_lookup(struct inode * dir,const char * name, int len,
        struct inode ** result);
 extern int minix_create(struct inode * dir,const char * name, int len, int mode,
@@ -59,29 +58,33 @@ extern int minix_link(struct inode * oldinode, struct inode * dir, const char *
 extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
        struct inode * new_dir, const char * new_name, int new_len);
-extern int minix_readlink(struct inode * inode, char * buffer, int buflen);
 extern struct inode * minix_new_inode(int dev);
 extern void minix_free_inode(struct inode * inode);
 extern int minix_new_block(int dev);
 extern int minix_free_block(int dev, int block);
 
-extern int minix_create_block(struct inode * inode, int block);
-extern int minix_bmap(struct inode * inode,int block);
+extern int minix_create_block(struct inode *, int);
+extern int minix_bmap(struct inode *,int);
 
-extern void minix_truncate(struct inode * inode);
-extern void minix_put_super(struct super_block *sb);
-extern struct super_block *minix_read_super(struct super_block *s,void *data);
-extern void minix_read_inode(struct inode * inode);
-extern void minix_write_inode(struct inode * inode);
+extern void minix_truncate(struct inode *);
+extern void minix_put_super(struct super_block *);
+extern struct super_block *minix_read_super(struct super_block *,void *);
+extern void minix_read_inode(struct inode *);
+extern void minix_write_inode(struct inode *);
+extern void minix_put_inode(struct inode *);
 
-extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin);
-extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count);
-extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count);
-extern int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent);
+extern int minix_lseek(struct inode *, struct file *, off_t, int);
+extern int minix_read(struct inode *, struct file *, char *, int);
+extern int minix_write(struct inode *, struct file *, char *, int);
 extern int minix_file_read(struct inode *, struct file *, char *, int);
-extern int minix_file_write(struct inode *, struct file *, char *, int);
 
-extern struct inode_operations minix_inode_operations;
+extern struct inode_operations minix_file_inode_operations;
+extern struct inode_operations minix_dir_inode_operations;
+extern struct inode_operations minix_symlink_inode_operations;
+extern struct inode_operations minix_chrdev_inode_operations;
+extern struct inode_operations minix_blkdev_inode_operations;
+
 extern struct file_operations minix_file_operations;
+extern struct file_operations minix_dir_operations;
 
 #endif
index e1fac82440338a7cade0dc41d316d19fca2eec21..b52578dad7d68452217c1061ed168df9c7ac54c5 100644 (file)
@@ -7,6 +7,11 @@
 #define TASK_SIZE      0x04000000
 #define LIBRARY_SIZE   0x00400000
 
+/*
+ * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
+ */
+#define IO_BITMAP_SIZE 32
+
 #if (TASK_SIZE & 0x3fffff)
 #error "TASK_SIZE must be multiple of 4M"
 #endif
@@ -53,6 +58,8 @@
 #define NULL ((void *) 0)
 #endif
 
+#define MAX_SHARED_LIBS 6
+
 extern int copy_page_tables(unsigned long from, unsigned long to, long size);
 extern int free_page_tables(unsigned long from, unsigned long size);
 
@@ -60,7 +67,6 @@ extern void sched_init(void);
 extern void schedule(void);
 extern void trap_init(void);
 extern void panic(const char * str);
-extern int tty_write(unsigned minor,char * buf,int count);
 
 typedef int (*fn_ptr)();
 
@@ -76,29 +82,30 @@ struct i387_struct {
 };
 
 struct tss_struct {
-       long    back_link;      /* 16 high bits zero */
-       long    esp0;
-       long    ss0;            /* 16 high bits zero */
-       long    esp1;
-       long    ss1;            /* 16 high bits zero */
-       long    esp2;
-       long    ss2;            /* 16 high bits zero */
-       long    cr3;
-       long    eip;
-       long    eflags;
-       long    eax,ecx,edx,ebx;
-       long    esp;
-       long    ebp;
-       long    esi;
-       long    edi;
-       long    es;             /* 16 high bits zero */
-       long    cs;             /* 16 high bits zero */
-       long    ss;             /* 16 high bits zero */
-       long    ds;             /* 16 high bits zero */
-       long    fs;             /* 16 high bits zero */
-       long    gs;             /* 16 high bits zero */
-       long    ldt;            /* 16 high bits zero */
-       long    trace_bitmap;   /* bits: trace 0, bitmap 16-31 */
+       unsigned long   back_link;      /* 16 high bits zero */
+       unsigned long   esp0;
+       unsigned long   ss0;            /* 16 high bits zero */
+       unsigned long   esp1;
+       unsigned long   ss1;            /* 16 high bits zero */
+       unsigned long   esp2;
+       unsigned long   ss2;            /* 16 high bits zero */
+       unsigned long   cr3;
+       unsigned long   eip;
+       unsigned long   eflags;
+       unsigned long   eax,ecx,edx,ebx;
+       unsigned long   esp;
+       unsigned long   ebp;
+       unsigned long   esi;
+       unsigned long   edi;
+       unsigned long   es;             /* 16 high bits zero */
+       unsigned long   cs;             /* 16 high bits zero */
+       unsigned long   ss;             /* 16 high bits zero */
+       unsigned long   ds;             /* 16 high bits zero */
+       unsigned long   fs;             /* 16 high bits zero */
+       unsigned long   gs;             /* 16 high bits zero */
+       unsigned long   ldt;            /* 16 high bits zero */
+       unsigned long   trace_bitmap;   /* bits: trace 0, bitmap 16-31 */
+       unsigned long   io_bitmap[IO_BITMAP_SIZE];
        struct i387_struct i387;
 };
 
@@ -143,9 +150,14 @@ struct task_struct {
        struct inode * pwd;
        struct inode * root;
        struct inode * executable;
-       struct inode * library;
-       unsigned long close_on_exec;
+       struct {
+               struct inode * library;
+               unsigned long start;
+               unsigned long length;
+       } libraries[MAX_SHARED_LIBS];
+       int numlibraries;
        struct file * filp[NR_OPEN];
+       unsigned long close_on_exec;
 /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
        struct desc_struct ldt[3];
 /* tss for this task */
@@ -183,17 +195,18 @@ struct task_struct {
 /* math */     0, \
 /* rss */      2, \
 /* comm */     "swapper", \
-/* fs info */  0,-1,0022,NULL,NULL,NULL,NULL,0, \
-/* filp */     {NULL,}, \
-       { \
-               {0,0}, \
-/* ldt */      {0x9f,0xc0fa00}, \
-               {0x9f,0xc0f200}, \
-       }, \
+/* fs info */  0,-1,0022,NULL,NULL,NULL, \
+/* libraries */        { { NULL, 0, 0}, }, 0, \
+/* filp */     {NULL,}, 0, \
+               { \
+                       {0,0}, \
+/* ldt */              {0x9f,0xc0fa00}, \
+                       {0x9f,0xc0f200} \
+               }, \
 /*tss*/        {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
         0,0,0,0,0,0,0,0, \
         0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
-        _LDT(0),0x80000000, \
+        _LDT(0),0x80000000,{0xffffffff}, \
                {} \
        }, \
 }
@@ -209,6 +222,7 @@ extern int jiffies_offset;
 
 extern void add_timer(long jiffies, void (*fn)(void));
 extern void sleep_on(struct task_struct ** p);
+extern int send_sig(long sig,struct task_struct * p,int priv);
 extern void interruptible_sleep_on(struct task_struct ** p);
 extern void wake_up(struct task_struct ** p);
 extern int in_group_p(gid_t grp);
diff --git a/include/linux/string.h b/include/linux/string.h
new file mode 100644 (file)
index 0000000..7da1793
--- /dev/null
@@ -0,0 +1,411 @@
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+extern char * strerror(int errno);
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ *             (C) 1991 Linus Torvalds
+ */
+extern inline char * strcpy(char * dest,const char *src)
+{
+__asm__("cld\n"
+       "1:\tlodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b"
+       ::"S" (src),"D" (dest):"si","di","ax");
+return dest;
+}
+
+extern inline char * strncpy(char * dest,const char *src,size_t count)
+{
+__asm__("cld\n"
+       "1:\tdecl %2\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n\t"
+       "rep\n\t"
+       "stosb\n"
+       "2:"
+       ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strcat(char * dest,const char * src)
+{
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "decl %1\n"
+       "1:\tlodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b"
+       ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strncat(char * dest,const char * src,size_t count)
+{
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "decl %1\n\t"
+       "movl %4,%3\n"
+       "1:\tdecl %3\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n"
+       "2:\txorl %2,%2\n\t"
+       "stosb"
+       ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
+       :"si","di","ax","cx");
+return dest;
+}
+
+extern inline int strcmp(const char * cs,const char * ct)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+       "1:\tlodsb\n\t"
+       "scasb\n\t"
+       "jne 2f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "jmp 3f\n"
+       "2:\tmovl $1,%%eax\n\t"
+       "jl 3f\n\t"
+       "negl %%eax\n"
+       "3:"
+       :"=a" (__res):"D" (cs),"S" (ct):"si","di");
+return __res;
+}
+
+extern inline int strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+       "1:\tdecl %3\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "scasb\n\t"
+       "jne 3f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n"
+       "2:\txorl %%eax,%%eax\n\t"
+       "jmp 4f\n"
+       "3:\tmovl $1,%%eax\n\t"
+       "jl 4f\n\t"
+       "negl %%eax\n"
+       "4:"
+       :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
+return __res;
+}
+
+extern inline char * strchr(const char * s,char c)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t"
+       "movb %%al,%%ah\n"
+       "1:\tlodsb\n\t"
+       "cmpb %%ah,%%al\n\t"
+       "je 2f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n\t"
+       "movl $1,%1\n"
+       "2:\tmovl %1,%0\n\t"
+       "decl %0"
+       :"=a" (__res):"S" (s),"0" (c):"si");
+return __res;
+}
+
+extern inline char * strrchr(const char * s,char c)
+{
+register char * __res __asm__("dx");
+__asm__("cld\n\t"
+       "movb %%al,%%ah\n"
+       "1:\tlodsb\n\t"
+       "cmpb %%ah,%%al\n\t"
+       "jne 2f\n\t"
+       "movl %%esi,%0\n\t"
+       "decl %0\n"
+       "2:\ttestb %%al,%%al\n\t"
+       "jne 1b"
+       :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
+return __res;
+}
+
+extern inline size_t strspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 1b\n"
+       "2:\tdecl %0"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline size_t strcspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 1b\n"
+       "2:\tdecl %0"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline char * strpbrk(const char * cs,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 1b\n\t"
+       "decl %0\n\t"
+       "jmp 3f\n"
+       "2:\txorl %0,%0\n"
+       "3:"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline char * strstr(const char * cs,const char * ct)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t" \
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"        /* NOTE! This also sets Z if searchstring='' */
+       "movl %%ecx,%%edx\n"
+       "1:\tmovl %4,%%edi\n\t"
+       "movl %%esi,%%eax\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repe\n\t"
+       "cmpsb\n\t"
+       "je 2f\n\t"             /* also works for empty string, see above */
+       "xchgl %%eax,%%esi\n\t"
+       "incl %%esi\n\t"
+       "cmpb $0,-1(%%eax)\n\t"
+       "jne 1b\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "2:"
+       :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
+       :"cx","dx","di","si");
+return __res;
+}
+
+extern inline size_t strlen(const char * s)
+{
+register int __res __asm__("cx");
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %0\n\t"
+       "decl %0"
+       :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
+return __res;
+}
+
+extern char * ___strtok;
+
+extern inline char * strtok(char * s,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("testl %1,%1\n\t"
+       "jne 1f\n\t"
+       "testl %0,%0\n\t"
+       "je 8f\n\t"
+       "movl %0,%1\n"
+       "1:\txorl %0,%0\n\t"
+       "movl $-1,%%ecx\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "je 7f\n\t"                     /* empty delimeter-string */
+       "movl %%ecx,%%edx\n"
+       "2:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 7f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 2b\n\t"
+       "decl %1\n\t"
+       "cmpb $0,(%1)\n\t"
+       "je 7f\n\t"
+       "movl %1,%0\n"
+       "3:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 5f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 3b\n\t"
+       "decl %1\n\t"
+       "cmpb $0,(%1)\n\t"
+       "je 5f\n\t"
+       "movb $0,(%1)\n\t"
+       "incl %1\n\t"
+       "jmp 6f\n"
+       "5:\txorl %1,%1\n"
+       "6:\tcmpb $0,(%0)\n\t"
+       "jne 7f\n\t"
+       "xorl %0,%0\n"
+       "7:\ttestl %0,%0\n\t"
+       "jne 8f\n\t"
+       "movl %0,%1\n"
+       "8:"
+#if __GNUC__ == 2
+       :"=r" (__res)
+#else
+       :"=b" (__res)
+#endif
+       ,"=S" (___strtok)
+       :"0" (___strtok),"1" (s),"g" (ct)
+       :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline void * memcpy(void * dest,const void * src, size_t n)
+{
+__asm__("cld\n\t"
+       "rep\n\t"
+       "movsb"
+       ::"c" (n),"S" (src),"D" (dest)
+       :"cx","si","di");
+return dest;
+}
+
+extern inline void * memmove(void * dest,const void * src, size_t n)
+{
+if (dest<src)
+__asm__("cld\n\t"
+       "rep\n\t"
+       "movsb"
+       ::"c" (n),"S" (src),"D" (dest)
+       :"cx","si","di");
+else
+__asm__("std\n\t"
+       "rep\n\t"
+       "movsb\n\t"
+       "cld"
+       ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
+       :"cx","si","di");
+return dest;
+}
+
+extern inline int memcmp(const void * cs,const void * ct,size_t count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n\t"
+       "repe\n\t"
+       "cmpsb\n\t"
+       "je 1f\n\t"
+       "movl $1,%%eax\n\t"
+       "jl 1f\n\t"
+       "negl %%eax\n"
+       "1:"
+       :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
+       :"si","di","cx");
+return __res;
+}
+
+extern inline void * memchr(const void * cs,char c,size_t count)
+{
+register void * __res __asm__("di");
+if (!count)
+       return NULL;
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 1f\n\t"
+       "movl $1,%0\n"
+       "1:\tdecl %0"
+       :"=D" (__res):"a" (c),"D" (cs),"c" (count)
+       :"cx");
+return __res;
+}
+
+extern inline void * memset(void * s,char c,size_t count)
+{
+__asm__("cld\n\t"
+       "rep\n\t"
+       "stosb"
+       ::"a" (c),"D" (s),"c" (count)
+       :"cx","di");
+return s;
+}
+
+#endif
index e7218655e4335d89207f780a5d16db63bebb91a1..d35b1d7d64a4838636c32fe79e72b66c99ed4df2 100644 (file)
@@ -92,6 +92,20 @@ extern int sys_uselib();
 extern int sys_swapon();
 extern int sys_reboot();
 extern int sys_readdir();
+extern int sys_mmap();
+extern int sys_munmap();
+extern int sys_truncate();
+extern int sys_ftruncate();
+extern int sys_fchmod();
+extern int sys_fchown();
+extern int sys_getpriority();
+extern int sys_setpriority();
+extern int sys_profil();
+extern int sys_statfs();
+extern int sys_fstatfs();
+extern int sys_ioperm();
+extern int sys_socketcall();
+extern int sys_syslog();
 
 fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
 sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
@@ -105,10 +119,14 @@ sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
 sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
 sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
 sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
-sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname,
-sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, 
-sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,
-sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir };
+sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending,
+sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage,
+sys_gettimeofday,  sys_settimeofday, sys_getgroups, sys_setgroups,
+sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
+sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap,
+sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority,
+sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
+sys_socketcall, sys_syslog };
 
 /* So we don't have to do any more manual updating.... */
 int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
index ab3c74ed3be1bc06ba2290c0c358e2811e4de1dc..aa92aa300a5bfb99ce45360a004467e854d35950 100644 (file)
@@ -20,6 +20,8 @@
  * HD_TIMER            harddisk timer
  *
  * FLOPPY_TIMER                floppy disk timer (not used right now)
+ * 
+ * SCSI_TIMER          scsi.c timeout timer
  */
 
 #define BLANK_TIMER    0
@@ -37,6 +39,7 @@
 
 #define HD_TIMER       16
 #define FLOPPY_TIMER   17
+#define SCSI_TIMER     18
 
 struct timer_struct {
        unsigned long expires;
index d185dd661355ca0f0400b9c62ecf56fc4bf3c006..57c3b58c1c5eabc4aa94bc5fd7abca76599e2c8d 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef _TTY_H
 #define _TTY_H
 
+#include <asm/system.h>
+
 #define MAX_CONSOLES   8
 #define NR_SERIALS     4
 #define NR_PTYS                4
@@ -24,7 +26,7 @@ struct tty_queue {
        unsigned long head;
        unsigned long tail;
        struct task_struct * proc_list;
-       char buf[TTY_BUF_SIZE];
+       unsigned char buf[TTY_BUF_SIZE];
 };
 
 #define IS_A_CONSOLE(min)      (((min) & 0xC0) == 0x00)
@@ -41,11 +43,31 @@ struct tty_queue {
 #define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)])
 #define FULL(a) (!LEFT(a))
 #define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
-#define GETCH(queue,c) \
-(void)({c=(queue)->buf[(queue)->tail];INC((queue)->tail);})
-#define PUTCH(c,queue) \
-(void)({(queue)->buf[(queue)->head]=(c);INC((queue)->head);})
 
+static inline void PUTCH(char c, struct tty_queue * queue)
+{
+       int head;
+
+       cli();
+       head = (queue->head + 1) & (TTY_BUF_SIZE-1);
+       if (head != queue->tail) {
+               queue->buf[queue->head] = c;
+               queue->head = head;
+       }
+       sti();
+}
+
+static inline int GETCH(struct tty_queue * queue)
+{
+       int result = -1;
+
+       if (queue->tail != queue->head) {
+               result = 0xff & queue->buf[queue->tail];
+               queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
+       }
+       return result;
+}
+       
 #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
 #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
 #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
@@ -55,12 +77,43 @@ struct tty_queue {
 #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
 #define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
 
+#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
+#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
+#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
+
+#define L_CANON(tty)   _L_FLAG((tty),ICANON)
+#define L_ISIG(tty)    _L_FLAG((tty),ISIG)
+#define L_ECHO(tty)    _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty)   _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty)   _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty)  _L_FLAG((tty),ECHONL)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOKE(tty)  _L_FLAG((tty),ECHOKE)
+#define L_TOSTOP(tty)  _L_FLAG((tty),TOSTOP)
+
+#define I_UCLC(tty)    _I_FLAG((tty),IUCLC)
+#define I_NLCR(tty)    _I_FLAG((tty),INLCR)
+#define I_CRNL(tty)    _I_FLAG((tty),ICRNL)
+#define I_NOCR(tty)    _I_FLAG((tty),IGNCR)
+#define I_IXON(tty)    _I_FLAG((tty),IXON)
+#define I_STRP(tty)    _I_FLAG((tty),ISTRIP)
+
+#define O_POST(tty)    _O_FLAG((tty),OPOST)
+#define O_NLCR(tty)    _O_FLAG((tty),ONLCR)
+#define O_CRNL(tty)    _O_FLAG((tty),OCRNL)
+#define O_NLRET(tty)   _O_FLAG((tty),ONLRET)
+#define O_LCUC(tty)    _O_FLAG((tty),OLCUC)
+
+#define C_SPEED(tty)   ((tty)->termios.c_cflag & CBAUD)
+#define C_HUP(tty)     (C_SPEED((tty)) == B0)
+
 struct tty_struct {
        struct termios termios;
        int pgrp;
        int session;
        int stopped;
        int busy;
+       int count;
        struct winsize winsize;
        void (*write)(struct tty_struct * tty);
        struct tty_queue *read_q;
@@ -103,6 +156,7 @@ do { \
 } while (0)
 
 extern struct tty_struct tty_table[];
+extern struct tty_struct * redirect;
 extern int fg_console;
 extern unsigned long video_num_columns;
 extern unsigned long video_num_lines;
@@ -119,17 +173,22 @@ extern unsigned long video_num_lines;
 */
 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
 
-void rs_init(void);
-void con_init(void);
-void tty_init(void);
+extern void rs_init(void);
+extern void lp_init(void);
+extern void con_init(void);
+extern void tty_init(void);
+
+extern void flush(struct tty_queue * queue);
 
-int tty_read(unsigned c, char * buf, int n, unsigned short flags);
-int tty_write(unsigned c, char * buf, int n);
+extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
+extern int is_orphaned_pgrp(int pgrp);
+extern int is_ignored(int sig);
+extern int tty_signal(int sig, struct tty_struct *tty);
 
-void con_write(struct tty_struct * tty);
-void rs_write(struct tty_struct * tty);
-void mpty_write(struct tty_struct * tty);
-void spty_write(struct tty_struct * tty);
+extern void rs_write(struct tty_struct * tty);
+extern void con_write(struct tty_struct * tty);
+extern void mpty_write(struct tty_struct * tty);
+extern void spty_write(struct tty_struct * tty);
 
 extern void serial_open(unsigned int line);
 
@@ -137,4 +196,6 @@ void copy_to_cooked(struct tty_struct * tty);
 
 void update_screen(int new_console);
 
+int kill_pg(int pgrp, int sig, int priv);
+   
 #endif
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
new file mode 100644 (file)
index 0000000..21e19ba
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef _LINUX_UNISTD_H
+#define _LINUX_UNISTD_H
+
+/*
+ * This file contains the system call numbers and the syscallX
+ * macros
+ */
+
+#define __NR_setup               0     /* used only by init, to get system going */
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_chown              16
+#define __NR_break              17
+#define __NR_stat               18
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount             22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_fstat              28
+#define __NR_pause              29
+#define __NR_utime              30
+#define __NR_stty               31
+#define __NR_gtty               32
+#define __NR_access             33
+#define __NR_nice               34
+#define __NR_ftime              35
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_prof               44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_signal             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_phys               52
+#define __NR_lock               53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_mpx                56
+#define __NR_setpgid            57
+#define __NR_ulimit             58
+#define __NR_uname              59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_sigaction          67
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_sigsuspend                 72
+#define __NR_sigpending                 73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_lstat              84
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+#define __NR_readdir            89
+#define __NR_mmap               90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+/*
+ * Not all of these are implemented yet, but these are the
+ * numbers they will use.
+ */
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_profil             98
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+#define __NR_ioperm            101
+#define __NR_socketcall                102
+#define __NR_syslog            103
+
+extern int errno;
+
+/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name)); \
+if (__res >= 0) \
+       return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall1(type,name,atype,a) \
+type name(atype a) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+       "int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name),"g" ((long)(a)):"bx"); \
+if (__res >= 0) \
+       return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall2(type,name,atype,a,btype,b) \
+type name(atype a,btype b) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+       "int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \
+if (__res >= 0) \
+       return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+type name(atype a,btype b,ctype c) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+       "int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \
+if (__res>=0) \
+       return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
+type name (atype a, btype b, ctype c, dtype d) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+       "int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \
+         "d" ((long)(c)),"S" ((long)(d))); \
+if (__res>=0) \
+       return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
+type name (atype a,btype b,ctype c,dtype d,etype e) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+       "int $0x80" \
+       : "=a" (__res) \
+       : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \
+         "d" ((long)(c)),"S" ((long)(d)),"D" ((long)(e))); \
+if (__res>=0) \
+       return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#endif /* _LINUX_UNISTD_H */
diff --git a/include/string.h b/include/string.h
deleted file mode 100644 (file)
index 7da1793..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-#ifndef _STRING_H_
-#define _STRING_H_
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-#ifndef _SIZE_T
-#define _SIZE_T
-typedef unsigned int size_t;
-#endif
-
-extern char * strerror(int errno);
-
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- *             (C) 1991 Linus Torvalds
- */
-extern inline char * strcpy(char * dest,const char *src)
-{
-__asm__("cld\n"
-       "1:\tlodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b"
-       ::"S" (src),"D" (dest):"si","di","ax");
-return dest;
-}
-
-extern inline char * strncpy(char * dest,const char *src,size_t count)
-{
-__asm__("cld\n"
-       "1:\tdecl %2\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "rep\n\t"
-       "stosb\n"
-       "2:"
-       ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
-return dest;
-}
-
-extern inline char * strcat(char * dest,const char * src)
-{
-__asm__("cld\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "decl %1\n"
-       "1:\tlodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b"
-       ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
-return dest;
-}
-
-extern inline char * strncat(char * dest,const char * src,size_t count)
-{
-__asm__("cld\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "decl %1\n\t"
-       "movl %4,%3\n"
-       "1:\tdecl %3\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "stosb\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n"
-       "2:\txorl %2,%2\n\t"
-       "stosb"
-       ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
-       :"si","di","ax","cx");
-return dest;
-}
-
-extern inline int strcmp(const char * cs,const char * ct)
-{
-register int __res __asm__("ax");
-__asm__("cld\n"
-       "1:\tlodsb\n\t"
-       "scasb\n\t"
-       "jne 2f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "xorl %%eax,%%eax\n\t"
-       "jmp 3f\n"
-       "2:\tmovl $1,%%eax\n\t"
-       "jl 3f\n\t"
-       "negl %%eax\n"
-       "3:"
-       :"=a" (__res):"D" (cs),"S" (ct):"si","di");
-return __res;
-}
-
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res __asm__("ax");
-__asm__("cld\n"
-       "1:\tdecl %3\n\t"
-       "js 2f\n\t"
-       "lodsb\n\t"
-       "scasb\n\t"
-       "jne 3f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n"
-       "2:\txorl %%eax,%%eax\n\t"
-       "jmp 4f\n"
-       "3:\tmovl $1,%%eax\n\t"
-       "jl 4f\n\t"
-       "negl %%eax\n"
-       "4:"
-       :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
-return __res;
-}
-
-extern inline char * strchr(const char * s,char c)
-{
-register char * __res __asm__("ax");
-__asm__("cld\n\t"
-       "movb %%al,%%ah\n"
-       "1:\tlodsb\n\t"
-       "cmpb %%ah,%%al\n\t"
-       "je 2f\n\t"
-       "testb %%al,%%al\n\t"
-       "jne 1b\n\t"
-       "movl $1,%1\n"
-       "2:\tmovl %1,%0\n\t"
-       "decl %0"
-       :"=a" (__res):"S" (s),"0" (c):"si");
-return __res;
-}
-
-extern inline char * strrchr(const char * s,char c)
-{
-register char * __res __asm__("dx");
-__asm__("cld\n\t"
-       "movb %%al,%%ah\n"
-       "1:\tlodsb\n\t"
-       "cmpb %%ah,%%al\n\t"
-       "jne 2f\n\t"
-       "movl %%esi,%0\n\t"
-       "decl %0\n"
-       "2:\ttestb %%al,%%al\n\t"
-       "jne 1b"
-       :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
-return __res;
-}
-
-extern inline size_t strspn(const char * cs, const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "je 1b\n"
-       "2:\tdecl %0"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
-return __res-cs;
-}
-
-extern inline size_t strcspn(const char * cs, const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 1b\n"
-       "2:\tdecl %0"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
-return __res-cs;
-}
-
-extern inline char * strpbrk(const char * cs,const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 1b\n\t"
-       "decl %0\n\t"
-       "jmp 3f\n"
-       "2:\txorl %0,%0\n"
-       "3:"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
-return __res;
-}
-
-extern inline char * strstr(const char * cs,const char * ct)
-{
-register char * __res __asm__("ax");
-__asm__("cld\n\t" \
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"        /* NOTE! This also sets Z if searchstring='' */
-       "movl %%ecx,%%edx\n"
-       "1:\tmovl %4,%%edi\n\t"
-       "movl %%esi,%%eax\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repe\n\t"
-       "cmpsb\n\t"
-       "je 2f\n\t"             /* also works for empty string, see above */
-       "xchgl %%eax,%%esi\n\t"
-       "incl %%esi\n\t"
-       "cmpb $0,-1(%%eax)\n\t"
-       "jne 1b\n\t"
-       "xorl %%eax,%%eax\n\t"
-       "2:"
-       :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
-       :"cx","dx","di","si");
-return __res;
-}
-
-extern inline size_t strlen(const char * s)
-{
-register int __res __asm__("cx");
-__asm__("cld\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %0\n\t"
-       "decl %0"
-       :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
-return __res;
-}
-
-extern char * ___strtok;
-
-extern inline char * strtok(char * s,const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("testl %1,%1\n\t"
-       "jne 1f\n\t"
-       "testl %0,%0\n\t"
-       "je 8f\n\t"
-       "movl %0,%1\n"
-       "1:\txorl %0,%0\n\t"
-       "movl $-1,%%ecx\n\t"
-       "xorl %%eax,%%eax\n\t"
-       "cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "je 7f\n\t"                     /* empty delimeter-string */
-       "movl %%ecx,%%edx\n"
-       "2:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 7f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "je 2b\n\t"
-       "decl %1\n\t"
-       "cmpb $0,(%1)\n\t"
-       "je 7f\n\t"
-       "movl %1,%0\n"
-       "3:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 5f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 3b\n\t"
-       "decl %1\n\t"
-       "cmpb $0,(%1)\n\t"
-       "je 5f\n\t"
-       "movb $0,(%1)\n\t"
-       "incl %1\n\t"
-       "jmp 6f\n"
-       "5:\txorl %1,%1\n"
-       "6:\tcmpb $0,(%0)\n\t"
-       "jne 7f\n\t"
-       "xorl %0,%0\n"
-       "7:\ttestl %0,%0\n\t"
-       "jne 8f\n\t"
-       "movl %0,%1\n"
-       "8:"
-#if __GNUC__ == 2
-       :"=r" (__res)
-#else
-       :"=b" (__res)
-#endif
-       ,"=S" (___strtok)
-       :"0" (___strtok),"1" (s),"g" (ct)
-       :"ax","cx","dx","di");
-return __res;
-}
-
-extern inline void * memcpy(void * dest,const void * src, size_t n)
-{
-__asm__("cld\n\t"
-       "rep\n\t"
-       "movsb"
-       ::"c" (n),"S" (src),"D" (dest)
-       :"cx","si","di");
-return dest;
-}
-
-extern inline void * memmove(void * dest,const void * src, size_t n)
-{
-if (dest<src)
-__asm__("cld\n\t"
-       "rep\n\t"
-       "movsb"
-       ::"c" (n),"S" (src),"D" (dest)
-       :"cx","si","di");
-else
-__asm__("std\n\t"
-       "rep\n\t"
-       "movsb\n\t"
-       "cld"
-       ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
-       :"cx","si","di");
-return dest;
-}
-
-extern inline int memcmp(const void * cs,const void * ct,size_t count)
-{
-register int __res __asm__("ax");
-__asm__("cld\n\t"
-       "repe\n\t"
-       "cmpsb\n\t"
-       "je 1f\n\t"
-       "movl $1,%%eax\n\t"
-       "jl 1f\n\t"
-       "negl %%eax\n"
-       "1:"
-       :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
-       :"si","di","cx");
-return __res;
-}
-
-extern inline void * memchr(const void * cs,char c,size_t count)
-{
-register void * __res __asm__("di");
-if (!count)
-       return NULL;
-__asm__("cld\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "je 1f\n\t"
-       "movl $1,%0\n"
-       "1:\tdecl %0"
-       :"=D" (__res):"a" (c),"D" (cs),"c" (count)
-       :"cx");
-return __res;
-}
-
-extern inline void * memset(void * s,char c,size_t count)
-{
-__asm__("cld\n\t"
-       "rep\n\t"
-       "stosb"
-       ::"a" (c),"D" (s),"c" (count)
-       :"cx","di");
-return s;
-}
-
-#endif
diff --git a/include/sys/kd.h b/include/sys/kd.h
new file mode 100644 (file)
index 0000000..9335ebf
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef _KD_H
+#define _KD_H
+
+/* 0x4B is 'K', to avoid collision with termios and vt */
+
+#define SWAPMONO       0x4B00  /* use mca as output device */
+#define SWAPCGA                0x4B01  /* use cga as output device */
+#define SWAPEGA                0x4B02  /* use ega as output device */
+#define SWAPVGA                0x4B03  /* use vga as output device */
+#define CONS_CURRENT   0x4B04  /* return current output device */
+#define                MONO            0x01
+#define                CGA             0x02
+#define                EGA             0x03
+
+#define SW_B40x25      0x4B05  /* 40x25 mono text (cga/ega) */
+#define SW_C40x25      0x4B06  /* 40x24 color text (cga/ega) */
+#define SW_B80x25      0x4B07  /* 80x25 mono text (cga/ega) */
+#define SW_C80x25      0x4B08  /* 80x25 color text (cga/ega) */
+#define SW_BG320       0x4B09  /* 320x200 mono graphics (cga/ega) */
+#define SW_CG320       0x4B0A  /* 320x200 color graphics (cga/ega) */
+#define SW_BG640       0x4B0B  /* 640x200 mono graphics (cga/ega) */
+#define SW_CG320_D     0x4B0C  /* 320x200 graphics (ega mode d) */
+#define SW_CG640_E     0x4B0D  /* 640x200 graphics (ega mode e) */
+#define SW_EGAMONOAPA  0x4B0E  /* 640x350 graphics (ega mode f) */
+#define SW_ENH_MONOAPA2        0x4B0F  /* 640x350 graphics extd mem (ega mode f*) */
+#define SW_CG640x350   0x4B10  /* 640x350 graphics (ega mode 10) */
+#define SW_ENH_CG640   0x4B11  /* 640x350 graphics extd mem (ega mode 10*) */
+#define SW_EGAMONO80x25        0x4B12  /* 80x25 mono text (ega mode 7) */
+#define SW_ENHB40x25   0x4B13  /* enhanced 40x25 mono text (ega) */
+#define SW_ENHC40x25   0x4B14  /* enhanced 40x25 color text (ega) */
+#define SW_ENHB80x25   0x4B15  /* enhanced 80x25 mono text (ega) */
+#define SW_ENHC80x25   0x4B16  /* enhanced 80x25 color text (ega) */
+#define SW_ENHB80x43   0x4B17  /* enhanced 80x43 mono text (ega) */
+#define SW_ENHC80x43   0x4B18  /* enhanced 80x43 color text (ega) */
+#define SW_MCAMODE     0x4B19  /* reinit mca */
+#define SW_ATT640      0x4B1A  /* 640x400 16color */
+/* should add more vga modes, etc */
+
+#define CONS_GET       0x4B1B  /* get current display mode */
+#define                M_B40x25        0       /* 40x25 mono (cga/ega) */
+#define                M_C40x25        1       /* 40x25 color (cga/ega) */
+#define                M_B80x25        2       /* 80x25 mono (cga/ega) */
+#define                M_C80x25        3       /* 80x25 color (cga/ega) */
+#define                M_BG320         4       /* 320x200 mono (cga/ega) */
+#define                M_CG320         5       /* 320x200 color (cga/ega) */
+#define                M_BG640         6       /* 640x200 mono (cga/ega) */
+#define                M_EGAMONO80x25  7       /* 80x25 mono (ega) */
+#define                M_CG320_D       13      /* ega mode d */
+#define                M_CG640_E       14      /* ega mode e */
+#define                M_EFAMONOAPA    15      /* ega mode f */
+#define                M_CG640x350     16      /* ega mode 10 */
+#define                M_ENHMONOAPA2   17      /* ega mode f with ext mem */
+#define                M_ENH_CG640     18      /* ega mode 10* */
+#define                M_ENH_B40x25    19      /* ega enh 40x25 mono */
+#define                M_ENH_C40x25    20      /* ega enh 40x25 color */
+#define                M_ENH_B80x25    21      /* ega enh 80x25 mono */
+#define                M_ENH_C80x25    22      /* ega enh 80x25 color */
+#define                M_ENH_B80x43    0x70    /* ega enh 80x43 mono */
+#define                M_ENH_C80x43    0x71    /* ega enh 80x43 color */
+#define                M_MCA_MODE      0xff    /* monochrome adapter mode */
+#define MCA_GET                0x4B1C  /* get mca display mode */
+#define CGA_GET                0x4B1D  /* get cga display mode */
+#define EGA_GET                0x4B1E  /* get ega display mode */
+
+#define MAPCONS                0x4B1F  /* map current video mem into address space */
+#define MAPMONO                0x4B20  /* map mca video mem into address space */
+#define MAPCGA         0x4B21  /* map cga video mem into address space */
+#define MAPEGA         0x4B22  /* map ega video mem into address space */
+#define MAPVGA         0x4B23  /* map vga video mem into address space */
+
+struct port_io_struc {
+       char dir;                       /* direction in vs out */
+       unsigned short port;
+       char data;
+};
+#define                IN_ON_PORT      0x00
+#define                OUT_ON_PORT     0x01
+struct port_io_arg {
+       struct port_io_struc args[4];
+};
+#define MCAIO          0x4B24  /* i/o to mca video board */
+#define CGAIO          0x4B25  /* i/o to cga video board */
+#define EGAIO          0x4B26  /* i/o to ega video board */
+#define VGAIO          0x4B27  /* i/o to vga video board */
+
+#define GIO_FONT8x8    0x4B28  /* gets current 8x8 font used */
+#define PIO_FONT8x8    0x4B29  /* use supplied 8x8 font */
+#define GIO_FONT8x14   0x4B2A  /* gets current 8x14 font used */
+#define PIO_FONT8x14   0x4B2B  /* use supplied 8x14 font */
+#define GIO_FONT8x16   0x4B2C  /* gets current 8x16 font used */
+#define PIO_FONT8x16   0x4B2D  /* use supplied 8x16 font */
+
+#define MKDIOADDR      32      /* io bitmap size from <linux/sched.h> */
+struct kd_disparam {
+       long type;                      /* type of display */
+       char *addr;                     /* display mem address */
+       ushort ioaddr[MKDIOADDR];       /* valid i/o addresses */
+};
+#define KDDISPTYPE     0x4B2E  /* gets display info */
+#define                KD_MONO         0x01
+#define                KD_HERCULES     0x02
+#define                KD_CGA          0x03
+#define                KD_EGA          0x04
+
+#define KIOCSOUND      0x4B2F  /* start sound generation (0 for off) */
+#define KDMKTONE       0x4B30  /* generate tone */
+
+#define KDGETLED       0x4B31  /* return current led flags */
+#define KDSETLED       0x4B32  /* set current led flags */
+#define        LED_SCR         0x01    /* scroll lock */
+#define        LED_CAP         0x04    /* caps lock */
+#define        LED_NUM         0x02    /* num lock */
+
+#define KDGKBTYPE      0x4B33  /* get keyboard type */
+#define        KB_84           0x01
+#define        KB_101          0x02
+#define        KB_OTHER        0x03
+
+#define KDADDIO                0x4B34  /* add i/o port as valid */
+#define KDDELIO                0x4B35  /* del i/o port as valid */
+#define KDENABIO       0x4B36  /* enable i/o to video board */
+#define KDDISABIO      0x4B37  /* disable i/o to video board */
+
+struct kd_quemode {
+       int qsize;              /* desired # elem in queue */
+       int signo;              /* signal to send when queue not empty */
+       char *qaddr;            /* user virt addr of queue */
+};
+#define KDQUEMODE      0x4B38  /* enable/disable special queue mode */
+
+#define KDSBORDER      0x4B39  /* set screen boarder in ega text mode */
+
+#define KDSETMODE      0x4B3A  /* set text/grahics mode */
+#define                KD_TEXT         0x00
+#define                KD_GRAPHICS     0x01
+#define                KD_TEXT0        0x02    /* ? */
+#define                KD_TEXT1        0x03    /* ? */
+#define KDGETMODE      0x4B3B  /* get current mode */
+
+struct kd_memloc {
+       char *vaddr;            /* virt addr to map to */
+       char *physaddr;         /* phys addr to map from */
+       long length;            /* number of bytes */
+       long ioflg;             /* enable i/o if set */
+};
+#define KDMAPDISP      0x4B3C  /* map display into address space */
+#define KDUNMAPDISP    0x4B3D  /* unmap display from address space */
+
+#define KDVDCTYPE      0x4B3E  /* return vdc controller/display info */
+
+#define KIOCINFO       0x4B3F  /* tell what the device is */
+
+typedef char scrnmap_t;
+#define                E_TABSZ         256
+#define GIO_SCRNMAP    0x4B40  /* get screen mapping from kernel */
+#define PIO_SCRNMAP    0x4B41  /* put screen mapping table in kernel */
+
+#define GIO_ATTR       0x4B42  /* get screen attributes */
+#define GIO_COLOR      0x4B43  /* return nonzero if display is color */
+
+#define                K_RAW           0x00
+#define                K_XLATE         0x01
+#define KDGKBMODE      0x4B44  /* gets current keyboard mode */
+#define KDSKBMODE      0x4B45  /* sets current keyboard mode */
+
+struct kbentry {
+       u_char kb_table;
+       u_char kb_index;
+       u_char kb_value;
+};
+#define                K_NORMTAB       0x00
+#define                K_SHIFTTAB      0x01
+#define                K_ALTTAB        0x02
+#define                K_ALTSHIFTTAB   0x03
+#define                K_SRQTAB        0x04
+#define KDGKBENT       0x4B46  /* gets one entry in translation table */
+#define KDSKBENT       0x4B47  /* sets one entry in translation table */
+
+#endif /* _KD_H */
diff --git a/include/sys/mman.h b/include/sys/mman.h
new file mode 100644 (file)
index 0000000..0a26c1b
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _MMAN_H
+#define _MMAN_H
+
+#define PROT_READ        0x1       /* page can be read */
+#define PROT_WRITE       0x2       /* page can be written */
+#define PROT_EXEC        0x4       /* page can be executed */
+#define PROT_NONE        0x0       /* page can not be accessed */
+
+#define MAP_SHARED       1         /* Share changes */
+#define MAP_PRIVATE      2         /* Changes are private */
+#define MAP_TYPE         0xf       /* Mask for type of mapping */
+#define MAP_FIXED        0x10      /* Interpret addr exactly */
+
+extern caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd,
+                   off_t off);
+extern int munmap(caddr_t addr, size_t len);
+
+#endif /* _MMAN_H */
index e23ec63987a6f285357e38af578bc5c397bb2c7c..3f34379682a6bfc2a1a4f6b6f2959402fec0b731 100644 (file)
@@ -60,4 +60,11 @@ struct rlimit {
        int     rlim_max;
 };
 
+#define        PRIO_MIN        -99
+#define        PRIO_MAX        14
+
+#define        PRIO_PROCESS    0
+#define        PRIO_PGRP       1
+#define        PRIO_USER       2
+
 #endif /* _SYS_RESOURCE_H */
diff --git a/include/sys/socket.h b/include/sys/socket.h
new file mode 100644 (file)
index 0000000..7d840a6
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+struct sockaddr {
+       u_short sa_family;              /* address family, AF_xxx */
+       char sa_data[14];               /* 14 bytes of protocol address */
+};
+
+/*
+ * socket types
+ */
+#define SOCK_STREAM    1               /* stream (connection) socket */
+#define SOCK_DGRAM     2               /* datagram (connectionless) socket */
+#define SOCK_SEQPACKET 3               /* sequential packet socket */
+#define SOCK_RAW       4               /* raw socket */
+
+/*
+ * supported address families
+ */
+#define AF_UNSPEC      0
+#define AF_UNIX                1
+#define AF_INET                2
+
+/*
+ * protocol families, same as address families
+ */
+#define PF_UNIX                AF_UNIX
+#define PF_INET                AF_INET
+
+int socket(int family, int type, int protocol);
+int socketpair(int family, int type, int protocol, int sockvec[2]);
+int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
+int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
+int listen(int sockfd, int backlog);
+int accept(int sockfd, struct sockaddr *peer, int *paddrlen);
+int getsockname(int sockfd, struct sockaddr *addr, int *paddrlen);
+int getpeername(int sockfd, struct sockaddr *peer, int *paddrlen);
+
+#endif /* _SOCKET_H */
index e917e9c27f5182535e2fd19e8e3381216fa846cc..b709165c4517985b06291a37fafd50633e9fbc34 100644 (file)
@@ -18,6 +18,7 @@ struct stat {
 };
 
 #define S_IFMT  00170000
+#define S_IFSOCK 0140000
 #define S_IFLNK         0120000
 #define S_IFREG  0100000
 #define S_IFBLK  0060000
@@ -34,6 +35,7 @@ struct stat {
 #define S_ISCHR(m)     (((m) & S_IFMT) == S_IFCHR)
 #define S_ISBLK(m)     (((m) & S_IFMT) == S_IFBLK)
 #define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)
 
 #define S_IRWXU 00700
 #define S_IRUSR 00400
index 5e220faa3794dd716482171200ad3a3a379e8e80..8529532ad4c00ec2830facd8bb9f9fa9f861c1e1 100644 (file)
@@ -31,6 +31,8 @@ typedef unsigned short nlink_t;
 typedef int daddr_t;
 typedef long off_t;
 typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned long u_long;
 typedef unsigned short ushort;
 typedef char *caddr_t;
 
diff --git a/include/sys/un.h b/include/sys/un.h
new file mode 100644 (file)
index 0000000..26a51f4
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _UN_H
+#define _UN_H
+
+struct sockaddr_un {
+       u_short sun_family;             /* AF_UNIX */
+       char sun_path[108];             /* pathname */
+};
+
+#endif /* _UN_H */
diff --git a/include/sys/vfs.h b/include/sys/vfs.h
new file mode 100644 (file)
index 0000000..c7e113e
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _SYS_VFS_H_
+#define _SYS_VFS_H_
+
+typedef struct {
+       long    val[2];
+} fsid_t;
+
+struct statfs {
+       long f_type;
+       long f_bsize;
+       long f_blocks;
+       long f_bfree;
+       long f_bavail;
+       long f_files;
+       long f_ffree;
+       fsid_t f_fsid;
+       long f_spare[7];
+};
+
+#endif
diff --git a/include/sys/vt.h b/include/sys/vt.h
new file mode 100644 (file)
index 0000000..092ae0d
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _VT_H
+#define _VT_H
+
+/* 0x56 is 'V', to avoid collision with termios and kd */
+
+#define VT_OPENQRY     0x5600  /* find available vt */
+
+struct vt_mode {
+       char mode;              /* vt mode */
+       char waitv;             /* if set, hang on writes if not active */
+       short relsig;           /* signal to raise on release req */
+       short acqsig;           /* signal to raise on acquisition */
+       short frsig;            /* unused (set to 0) */
+};
+#define VT_GETMODE     0x5601  /* get mode of active vt */
+#define VT_SETMODE     0x5602  /* set mode of active vt */
+#define                VT_AUTO         0x00    /* auto vt switching */
+#define                VT_PROCESS      0x01    /* process controls switching */
+
+struct vt_stat {
+       ushort v_active;        /* active vt */
+       ushort v_signal;        /* signal to send */
+       ushort v_state;         /* vt bitmask */
+};
+#define VT_GETSTATE    0x5603  /* get global vt state info */
+#define VT_SENDSIG     0x5604  /* signal to send to bitmask of vts */
+
+#define VT_RELDISP     0x5605  /* release display */
+
+#define VT_ACTIVATE    0x5606  /* make vt active */
+
+#endif /* _VT_H */
index b04a0e9928ecb212c19da1dd2ac0bde95f1ddfbf..740f3d8b3f1b7d6b7ec2e00c9ec364666aa02609 100644 (file)
@@ -34,6 +34,7 @@
 #define FIONREAD       0x541B
 #define TIOCINQ                FIONREAD
 #define TIOCLINUX      0x541C
+#define TIOCCONS       0x541D
 
 struct winsize {
        unsigned short ws_row;
index f297df97d980d8255642a29a923d0e269ff324d5..e7a1c6ed9e655a05d2fd0caa9c44f8263adf51b7 100644 (file)
 #include <utime.h>
 
 #ifdef __LIBRARY__
-
-#define __NR_setup     0       /* used only by init, to get system going */
-#define __NR_exit      1
-#define __NR_fork      2
-#define __NR_read      3
-#define __NR_write     4
-#define __NR_open      5
-#define __NR_close     6
-#define __NR_waitpid   7
-#define __NR_creat     8
-#define __NR_link      9
-#define __NR_unlink    10
-#define __NR_execve    11
-#define __NR_chdir     12
-#define __NR_time      13
-#define __NR_mknod     14
-#define __NR_chmod     15
-#define __NR_chown     16
-#define __NR_break     17
-#define __NR_stat      18
-#define __NR_lseek     19
-#define __NR_getpid    20
-#define __NR_mount     21
-#define __NR_umount    22
-#define __NR_setuid    23
-#define __NR_getuid    24
-#define __NR_stime     25
-#define __NR_ptrace    26
-#define __NR_alarm     27
-#define __NR_fstat     28
-#define __NR_pause     29
-#define __NR_utime     30
-#define __NR_stty      31
-#define __NR_gtty      32
-#define __NR_access    33
-#define __NR_nice      34
-#define __NR_ftime     35
-#define __NR_sync      36
-#define __NR_kill      37
-#define __NR_rename    38
-#define __NR_mkdir     39
-#define __NR_rmdir     40
-#define __NR_dup       41
-#define __NR_pipe      42
-#define __NR_times     43
-#define __NR_prof      44
-#define __NR_brk       45
-#define __NR_setgid    46
-#define __NR_getgid    47
-#define __NR_signal    48
-#define __NR_geteuid   49
-#define __NR_getegid   50
-#define __NR_acct      51
-#define __NR_phys      52
-#define __NR_lock      53
-#define __NR_ioctl     54
-#define __NR_fcntl     55
-#define __NR_mpx       56
-#define __NR_setpgid   57
-#define __NR_ulimit    58
-#define __NR_uname     59
-#define __NR_umask     60
-#define __NR_chroot    61
-#define __NR_ustat     62
-#define __NR_dup2      63
-#define __NR_getppid   64
-#define __NR_getpgrp   65
-#define __NR_setsid    66
-#define __NR_sigaction 67
-#define __NR_sgetmask  68
-#define __NR_ssetmask  69
-#define __NR_setreuid  70
-#define __NR_setregid  71
-#define __NR_sigsuspend        72
-#define __NR_sigpending 73
-#define __NR_sethostname 74
-#define __NR_setrlimit 75
-#define __NR_getrlimit 76
-#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
-#define __NR_getgroups 80
-#define __NR_setgroups 81
-#define __NR_select    82
-#define __NR_symlink   83
-#define __NR_lstat     84
-#define __NR_readlink  85
-#define __NR_uselib    86
-#define __NR_swapon    87
-#define __NR_reboot    88
-#define __NR_readdir   89
-
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
-#define _syscall0(type,name) \
-type name(void) \
-{ \
-long __res; \
-__asm__ volatile ("int $0x80" \
-       : "=a" (__res) \
-       : "0" (__NR_##name)); \
-if (__res >= 0) \
-       return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall1(type,name,atype,a) \
-type name(atype a) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
-       "int $0x80" \
-       : "=a" (__res) \
-       : "0" (__NR_##name),"g" ((long)(a)):"bx"); \
-if (__res >= 0) \
-       return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall2(type,name,atype,a,btype,b) \
-type name(atype a,btype b) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
-       "int $0x80" \
-       : "=a" (__res) \
-       : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \
-if (__res >= 0) \
-       return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
-type name(atype a,btype b,ctype c) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
-       "int $0x80" \
-       : "=a" (__res) \
-       : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \
-if (__res>=0) \
-       return (type) __res; \
-errno=-__res; \
-return -1; \
-}
-
+#include <linux/unistd.h>
 #endif /* __LIBRARY__ */
 
 /* XXX - illegal. */
@@ -255,7 +108,7 @@ int kill(pid_t pid, int signal);
 int link(const char * filename1, const char * filename2);
 off_t lseek(int fildes, off_t offset, int origin);
 int mknod(const char * filename, mode_t mode, dev_t dev); /* XXX - shorts */
-int mount(const char * specialfile, const char * dir, int rwflag);
+int mount(const char * specialfile, const char * dir, const char * type, int rwflag);
 int nice(int val);
 int open(const char * filename, int flag, ...);
 int pause(void);
index d53e00f4061ae162468420b49a79f1519d2e8ece..839161a0df968d29a8072ff81a0fabfe9c95e37b 100644 (file)
@@ -4,10 +4,22 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#define __LIBRARY__
-#include <unistd.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <fcntl.h>
 #include <time.h>
 
+#include <sys/types.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/head.h>
+#include <linux/unistd.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -24,36 +36,35 @@ static inline _syscall0(int,fork)
 static inline _syscall0(int,pause)
 static inline _syscall1(int,setup,void *,BIOS)
 static inline _syscall0(int,sync)
-
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-
-#include <linux/fs.h>
-
-#include <string.h>
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall1(int,dup,int,fd)
+static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+
+static inline pid_t wait(int * wait_stat)
+{
+       return waitpid(-1,wait_stat,0);
+}
 
 static char printbuf[1024];
 
-extern char *strcpy();
 extern int vsprintf();
 extern void init(void);
 extern void blk_dev_init(void);
 extern void chr_dev_init(void);
 extern void hd_init(void);
 extern void floppy_init(void);
+extern void sock_init(void);
 extern void mem_init(long start, long end);
 extern long rd_init(long mem_start, int length);
 extern long kernel_mktime(struct tm * tm);
 
+#ifdef CONFIG_SCSI
+extern void scsi_dev_init(void);
+#endif
+
 static int sprintf(char * str, const char *fmt, ...)
 {
        va_list args;
@@ -156,15 +167,19 @@ void start_kernel(void)
 #endif
        mem_init(main_memory_start,memory_end);
        trap_init();
-       blk_dev_init();
+       sched_init();
        chr_dev_init();
-       tty_init();
+       blk_dev_init();
        time_init();
-       sched_init();
+       printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
        buffer_init(buffer_memory_end);
        hd_init();
        floppy_init();
+       sock_init();
        sti();
+#ifdef CONFIG_SCSI
+       scsi_dev_init();
+#endif
        move_to_user_mode();
        if (!fork()) {          /* we count on this going ok */
                init();
index a822e41bc0fcfbc2a363a2f177fb1e7b1d42dd58..716bcfd9d67d23fc9f23bf8e3b1518621b29c3d9 100644 (file)
@@ -15,6 +15,8 @@ CC    =gcc -nostdinc -I../include
 CPP    =cpp -nostdinc -I../include
 
 
+.S.s:
+       $(CPP) -traditional $< -o $*.s
 .c.s:
        $(CC) $(CFLAGS) \
        -S -o $*.s $<
@@ -26,17 +28,21 @@ CPP =cpp -nostdinc -I../include
 
 OBJS  = sched.o sys_call.o traps.o asm.o fork.o \
        panic.o printk.o vsprintf.o sys.o exit.o \
-       signal.o mktime.o ptrace.o
+       signal.o mktime.o ptrace.o ioport.o
 
 kernel.o: $(OBJS)
        $(LD) -r -o kernel.o $(OBJS)
        sync
 
+sys_call.s: sys_call.S
+
+sys_call.o: sys_call.s
+
 sched.o: sched.c
        $(CC) $(CFLAGS) -fno-omit-frame-pointer -c $<
 
 clean:
-       rm -f core *.o *.a tmp_make keyboard.s
+       rm -f core *.o *.a tmp_make sys_call.s
        for i in *.c;do rm -f `basename $$i .c`.s;done
        (cd chr_drv; make clean)
        (cd blk_drv; make clean)
@@ -49,61 +55,59 @@ dep:
        cp tmp_make Makefile
        (cd chr_drv; make dep)
        (cd blk_drv; make dep)
+       (cd math; make dep)
 
 ### Dependencies:
-exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
-  ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
-  ../include/sys/param.h ../include/sys/time.h ../include/time.h \
-  ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
-  ../include/asm/segment.h 
-fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+exit.s exit.o : exit.c ../include/errno.h ../include/signal.h ../include/sys/types.h \
+  ../include/sys/wait.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+  ../include/linux/tty.h ../include/asm/system.h ../include/termios.h ../include/asm/segment.h 
+fork.s fork.o : fork.c ../include/errno.h ../include/stddef.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
   ../include/asm/segment.h ../include/asm/system.h 
+ioport.s ioport.o : ioport.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/errno.h 
 mktime.s mktime.o : mktime.c ../include/time.h 
-panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
   ../include/time.h ../include/sys/resource.h 
-printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
-  ../include/linux/kernel.h 
-ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \
-  ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h ../include/errno.h \
-  ../include/asm/segment.h ../include/asm/system.h ../include/sys/ptrace.h 
-sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h ../include/linux/timer.h \
-  ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \
-  ../include/asm/io.h ../include/asm/segment.h ../include/errno.h 
-signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
-  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
-  ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
-  ../include/sys/wait.h ../include/errno.h 
-sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/linux/tty.h ../include/termios.h ../include/linux/config.h \
-  ../include/asm/segment.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/string.h 
-traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
-  ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
-  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
-  ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
-  ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h \
+printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h ../include/errno.h \
+  ../include/asm/segment.h ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h 
+ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h ../include/linux/sched.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/errno.h ../include/asm/segment.h \
+  ../include/asm/system.h ../include/sys/ptrace.h 
+sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/linux/timer.h ../include/linux/sys.h \
+  ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \
+  ../include/errno.h 
+signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+  ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+  ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ../include/sys/wait.h \
   ../include/errno.h 
-vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h 
+sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h ../include/linux/head.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/linux/tty.h \
+  ../include/asm/system.h ../include/termios.h ../include/linux/config.h ../include/linux/config_rel.h \
+  ../include/linux/config_ver.h ../include/linux/config.dist.h ../include/asm/segment.h \
+  ../include/sys/times.h ../include/sys/utsname.h ../include/linux/string.h 
+traps.s traps.o : traps.c ../include/linux/string.h ../include/linux/head.h ../include/linux/sched.h \
+  ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/system.h \
+  ../include/asm/segment.h ../include/asm/io.h ../include/errno.h 
+vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/linux/string.h 
index 299e4a95983dc4dd0ed2785571ee82b56a0d1d06..f62751ca6ac89233bbe9a5f70d01dffd65a43fd5 100644 (file)
  */
 
 /*
- * asm.s contains the low-level code for most hardware faults.
- * page_exception is handled by the mm, so that isn't here. This
- * file also handles (hopefully) fpu-exceptions due to TS-bit, as
- * the fpu must be properly saved/resored. This hasn't been tested.
+ * asm.s contains the low-level code for interrupts that cannot
+ * result in an task-switch. These are things like the hd- and
+ * floppy-interrupt etc. With these interrupts, we don't have to
+ * care about the stack layout etc.
  */
 
-.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
-.globl _double_fault,_coprocessor_segment_overrun
-.globl _invalid_TSS,_segment_not_present,_stack_segment
-.globl _general_protection,_coprocessor_error,_irq13,_reserved
-.globl _alignment_check
-.globl _page_fault
+.globl _floppy_interrupt,_parallel_interrupt
 
-_divide_error:
-       pushl $0                # no error code
-       pushl $_do_divide_error
-error_code:
-       push %fs
-       push %es
-       push %ds
+_floppy_interrupt:
+       cld
        pushl %eax
-       pushl %ebp
-       pushl %edi
-       pushl %esi
-       pushl %edx
        pushl %ecx
-       pushl %ebx
-       cld
-       movl $-1, %eax
-       xchgl %eax, 0x2c(%esp)  # orig_eax (get the error code. )
-       xorl %ebx,%ebx          # zero ebx
-       mov %gs,%bx             # get the lower order bits of gs
-       xchgl %ebx, 0x28(%esp)  # get the address and save gs.
-       pushl %eax              # push the error code
-       lea 52(%esp),%edx
        pushl %edx
-       movl $0x10,%edx
-       mov %dx,%ds
-       mov %dx,%es
-       mov %dx,%fs
-       call *%ebx
-       addl $8,%esp
-       popl %ebx
-       popl %ecx
+       push %ds
+       push %es
+       push %fs
+       movl $0x10,%eax
+       mov %ax,%ds
+       mov %ax,%es
+       movl $0x17,%eax
+       mov %ax,%fs
+       movb $0x20,%al
+       outb %al,$0x20          # EOI to interrupt controller #1
+       xorl %eax,%eax
+       xchgl _do_floppy,%eax
+       testl %eax,%eax
+       jne 1f
+       movl $_unexpected_floppy_interrupt,%eax
+1:     call *%eax              # "interesting" way of handling intr.
+       pop %fs
+       pop %es
+       pop %ds
        popl %edx
-       popl %esi
-       popl %edi
-       popl %ebp
+       popl %ecx
        popl %eax
-       pop %ds
-       pop %es
-       pop %fs
-       pop %gs
-       addl $4,%esp
        iret
 
-_debug:
-       pushl $0
-       pushl $_do_int3         # _do_debug
-       jmp error_code
-
-_nmi:
-       pushl $0
-       pushl $_do_nmi
-       jmp error_code
-
-_int3:
-       pushl $0
-       pushl $_do_int3
-       jmp error_code
-
-_overflow:
-       pushl $0
-       pushl $_do_overflow
-       jmp error_code
-
-_bounds:
-       pushl $0
-       pushl $_do_bounds
-       jmp error_code
-
-_invalid_op:
-       pushl $0
-       pushl $_do_invalid_op
-       jmp error_code
-
-_coprocessor_segment_overrun:
-       pushl $0
-       pushl $_do_coprocessor_segment_overrun
-       jmp error_code
-
-_reserved:
-       pushl $0
-       pushl $_do_reserved
-       jmp error_code
-
-_irq13:
+_parallel_interrupt:
+       cld
        pushl %eax
-       xorb %al,%al
-       outb %al,$0xF0
        movb $0x20,%al
        outb %al,$0x20
-       jmp 1f
-1:     jmp 1f
-1:     outb %al,$0xA0
        popl %eax
-       jmp _coprocessor_error
-
-_double_fault:
-       pushl $_do_double_fault
-       jmp error_code
-
-_invalid_TSS:
-       pushl $_do_invalid_TSS
-       jmp error_code
-
-_segment_not_present:
-       pushl $_do_segment_not_present
-       jmp error_code
-
-_stack_segment:
-       pushl $_do_stack_segment
-       jmp error_code
-
-_general_protection:
-       pushl $_do_general_protection
-       jmp error_code
-
-_alignment_check:
-       pushl $_do_alignment_check
-       jmp error_code
-
-_page_fault:
-       pushl $_do_page_fault
-       jmp error_code
+       iret
index 516ab48771fd03bcd9cf987aa4be6cbadc1cedd1..58dc4aa7fdf0b6517b2366fb11b89628e028690d 100644 (file)
@@ -25,15 +25,19 @@ CPP =cpp -nostdinc -I../../include
        $(CC) $(CFLAGS) \
        -c -o $*.o $<
 
-OBJS  = ll_rw_blk.o floppy.o hd.o ramdisk.o
+OBJS = hd.o ll_rw_blk.o floppy.o ramdisk.o
+
+all: blk_drv.a
 
 blk_drv.a: $(OBJS)
+       rm -f blk_drv.a
        $(AR) rcs blk_drv.a $(OBJS)
        sync
 
 clean:
        rm -f core *.o *.a tmp_make
        for i in *.c;do rm -f `basename $$i .c`.s;done
+       (cd scsi; make clean)
 
 dep:
        sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
@@ -42,36 +46,31 @@ dep:
        cp tmp_make Makefile
 
 ### Dependencies:
-floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/fdreg.h \
-  ../../include/asm/system.h ../../include/asm/io.h \
-  ../../include/asm/segment.h blk.h 
-hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/timer.h \
-  ../../include/linux/hdreg.h ../../include/asm/system.h \
-  ../../include/asm/io.h ../../include/asm/segment.h blk.h 
+floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/timer.h ../../include/linux/fdreg.h ../../include/linux/fd.h \
+  ../../include/asm/system.h ../../include/asm/io.h ../../include/asm/segment.h \
+  ../../include/errno.h blk.h 
+hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h ../../include/linux/config_rel.h \
+  ../../include/linux/config_ver.h ../../include/linux/config.dist.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/timer.h ../../include/linux/hdreg.h \
+  ../../include/asm/system.h ../../include/asm/io.h ../../include/asm/segment.h \
+  blk.h 
 ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/asm/system.h blk.h 
+ramdisk.s ramdisk.o : ramdisk.c ../../include/linux/string.h ../../include/linux/config.h \
+  ../../include/linux/config_rel.h ../../include/linux/config_ver.h ../../include/linux/config.dist.h \
+  ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
-  ../../include/time.h ../../include/sys/resource.h \
-  ../../include/asm/system.h blk.h 
-ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/minix_fs.h \
-  ../../include/asm/system.h ../../include/asm/segment.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/minix_fs.h ../../include/asm/system.h ../../include/asm/segment.h \
   ../../include/asm/memory.h blk.h 
index 746f5f024f058b8e4face541ba7350c453ec9ccc..40a59255f877ce7c9b90a6a6d3157e28c81f8f9d 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _BLK_H
 #define _BLK_H
 
-#define NR_BLK_DEV     7
+#define NR_BLK_DEV     10
 /*
  * NR_REQUEST is the number of entries in the request-queue.
  * NOTE that writes may use only the low 2/3 of these: reads
@@ -29,6 +29,7 @@ struct request {
        char * buffer;
        struct task_struct * waiting;
        struct buffer_head * bh;
+       struct buffer_head * bhtail;
        struct request * next;
 };
 
@@ -88,6 +89,24 @@ extern int * blk_size[NR_BLK_DEV];
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == 8)
+/* scsi disk */
+#define DEVICE_NAME "scsidisk"
+#define DEVICE_INTR do_sd  
+#define DEVICE_REQUEST do_sd_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == 9)
+/* scsi tape */
+#define DEVICE_NAME "scsitape"
+#define DEVICE_INTR do_st  
+#define DEVICE_REQUEST do_st_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #elif
 /* unknown blk device */
 #error "unknown blk device"
@@ -130,22 +149,45 @@ extern inline void unlock_buffer(struct buffer_head * bh)
        wake_up(&bh->b_wait);
 }
 
-extern inline void end_request(int uptodate)
+extern inline void next_buffer(int uptodate)
 {
-       DEVICE_OFF(CURRENT->dev);
-       if (CURRENT->bh) {
-               CURRENT->bh->b_uptodate = uptodate;
-               unlock_buffer(CURRENT->bh);
-       }
+       struct buffer_head *tmp;
+
+       CURRENT->bh->b_uptodate = uptodate;
+       unlock_buffer(CURRENT->bh);
        if (!uptodate) {
                printk(DEVICE_NAME " I/O error\n\r");
                printk("dev %04x, block %d\n\r",CURRENT->dev,
                        CURRENT->bh->b_blocknr);
        }
-       wake_up(&CURRENT->waiting);
+       tmp = CURRENT->bh;
+       CURRENT->bh = CURRENT->bh->b_reqnext;
+       tmp->b_reqnext = NULL;
+       if (!CURRENT->bh)
+               panic("next_buffer: request buffer list destroyed\r\n");
+       CURRENT->buffer = CURRENT->bh->b_data;
+       CURRENT->errors = 0;
+}
+
+extern inline void end_request(int uptodate)
+{
+       struct request * tmp;
+
+       tmp = CURRENT;
+       DEVICE_OFF(tmp->dev);
+       CURRENT = tmp->next;
+       if (tmp->bh) {
+               tmp->bh->b_uptodate = uptodate;
+               unlock_buffer(tmp->bh);
+       }
+       if (!uptodate) {
+               printk(DEVICE_NAME " I/O error\n\r");
+               printk("dev %04x, block %d\n\r",tmp->dev,
+                       tmp->bh->b_blocknr);
+       }
+       wake_up(&tmp->waiting);
+       tmp->dev = -1;
        wake_up(&wait_for_request);
-       CURRENT->dev = -1;
-       CURRENT = CURRENT->next;
 }
 
 #ifdef DEVICE_INTR
index 82c3583e23418f21d0a31b79227e49ac556781b6..2b9d2384b12dba816d7a7cb690de9e30b455f02f 100644 (file)
  * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
  */
 
+/*
+ * Automatic floppy-detection and formatting written by Werner Almesberger
+ * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
+ * the floppy-change signa| detection.
+ */
+
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/timer.h>
 #include <linux/fdreg.h>
+#include <linux/fd.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
+#include <errno.h>
 
 #define MAJOR_NR 2
 #include "blk.h"
 
-unsigned int changed_floppies = 0;
+static unsigned int changed_floppies = 0, fake_change = 0;
 
 static int recalibrate = 0;
 static int reset = 0;
+static int recover = 0; /* recalibrate immediately after resetting */
 static int seek = 0;
 
 extern unsigned char current_DOR;
@@ -63,6 +73,20 @@ __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
  */
 #define MAX_ERRORS 12
 
+/*
+ * Maximum disk size (in kilobytes). This default is used whenever the
+ * current disk size is unknown.
+ */
+
+#define MAX_DISK_SIZE 1440
+
+/*
+ * Maximum number of sectors in a track buffer. Track buffering is disabled
+ * if tracks are bigger.
+ */
+
+#define MAX_BUFFER_SECTORS 18
+
 /*
  * globals used by 'result()'
  */
@@ -83,22 +107,95 @@ static unsigned char reply_buffer[MAX_REPLIES];
  * types (ie 360kB diskette in 1.2MB drive etc). Others should
  * be self-explanatory.
  */
-struct floppy_struct {
-       unsigned int size, sect, head, track, stretch;
-       unsigned char gap,rate,spec1;
-};
 
 static struct floppy_struct floppy_type[] = {
-       {    0, 0,0, 0,0,0x00,0x00,0x00 },      /* no testing */
-       {  720, 9,2,40,0,0x2A,0x02,0xDF },      /* 360kB PC diskettes */
-       { 2400,15,2,80,0,0x1B,0x00,0xDF },      /* 1.2 MB AT-diskettes */
-       {  720, 9,2,40,1,0x2A,0x02,0xDF },      /* 360kB in 720kB drive */
-       { 1440, 9,2,80,0,0x2A,0x02,0xDF },      /* 3.5" 720kB diskette */
-       {  720, 9,2,40,1,0x23,0x01,0xDF },      /* 360kB in 1.2MB drive */
-       { 1440, 9,2,80,0,0x23,0x01,0xDF },      /* 720kB in 1.2MB drive */
-       { 2880,18,2,80,0,0x1B,0x00,0xCF },      /* 1.44MB diskette */
+       {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },    /* no testing */
+       {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL },    /* 360kB PC diskettes */
+       { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL },    /* 1.2 MB AT-diskettes */
+       {  720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL },    /* 360kB in 720kB drive */
+       { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL },    /* 3.5" 720kB diskette */
+       {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL },    /* 360kB in 1.2MB drive */
+       { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL },    /* 720kB in 1.2MB drive */
+       { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL },    /* 1.44MB diskette */
 };
 
+/* For auto-detection. Each drive type has a pair of formats to try. */
+
+static struct floppy_struct floppy_types[] = {
+       {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
+       {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
+       { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" },    /* 1.2 MB AT-diskettes */
+       {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */
+       { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },    /* 3.5" 720kB diskette */
+       { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },    /* 3.5" 720kB diskette */
+       { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" },   /* 1.44MB diskette */
+       { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
+};
+
+/* Auto-detection: Disk type used until the next media change occurs. */
+
+struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
+
+/* This type is tried first. */
+
+struct floppy_struct *base_type[4];
+
+/* User-provided type information. current_type points to the respective entry
+   of this array. */
+
+struct floppy_struct user_params[4];
+
+static int floppy_sizes[] ={
+       MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
+        360, 360 ,360, 360,
+       1200,1200,1200,1200,
+        360, 360, 360, 360,
+        720, 720, 720, 720,
+        360, 360, 360, 360,
+        720, 720, 720, 720,
+       1440,1440,1440,1440
+};
+
+/* The driver is trying to determine the correct media format while probing
+   is set. rw_interrupts clears it after a successful access. */
+
+static int probing = 0;
+
+/* (User-provided) media information is _not_ discarded after a media change
+   if the corresponding keep_data flag is non-zero. Positive values are
+   decremented after each probe. */
+
+static int keep_data[4] = { 0,0,0,0 };
+
+/* Announce successful media type detection and media information loss after
+   disk changes. */
+
+static ftd_msg[4] = { 1,1,1,1 };
+
+/* Synchronization of FDC access. */
+
+static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
+static struct task_struct *fdc_wait = NULL, *format_done = NULL;
+
+/* Errors during formatting are counted here. */
+
+static int format_errors;
+
+/* Format request descriptor. */
+
+static struct format_descr format_req;
+
+/* Current device number. Taken either from the block header or from the
+   format request descriptor. */
+
+#define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \
+   (CURRENT->dev))
+
+/* Current error count. */
+
+#define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \
+    (CURRENT->errors))
+
 /*
  * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
  * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
@@ -110,7 +207,9 @@ static struct floppy_struct floppy_type[] = {
 
 extern void floppy_interrupt(void);
 extern char tmp_floppy_area[1024];
-extern char floppy_track_buffer[512*2*18];
+extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
+
+static void redo_fd_request(void);
 
 /*
  * These are global variables, as that's the easiest way to give
@@ -143,6 +242,16 @@ void floppy_deselect(unsigned int nr)
        wake_up(&wait_on_floppy_select);
 }
 
+void request_done(int uptodate)
+{
+       timer_active &= ~(1 << FLOPPY_TIMER);
+       if (format_status != FORMAT_BUSY) end_request(uptodate);
+       else {
+               format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
+               wake_up(&format_done);
+       }
+}
+
 /*
  * floppy-change is never called from an interrupt, so we can relax a bit
  * here, sleep etc. Note that floppy-on tries to set current_DOR to point
@@ -154,9 +263,15 @@ int floppy_change(struct buffer_head * bh)
        unsigned int mask = 1 << (bh->b_dev & 0x03);
 
        if (MAJOR(bh->b_dev) != 2) {
-               printk("floppy_changed: not a floppy\n");
+               printk("floppy_changed: not a floppy\r\n");
                return 0;
        }
+       if (fake_change & mask) {
+               fake_change &= ~mask;
+/* omitting the next line breaks formatting in a horrible way ... */
+               changed_floppies &= ~mask;
+               return 1;
+       }
        if (changed_floppies & mask) {
                changed_floppies &= ~mask;
                recalibrate = 1;
@@ -179,7 +294,7 @@ int floppy_change(struct buffer_head * bh)
                changed_floppies &= ~mask;
                recalibrate = 1;
                return 1;
-       }       
+       }
        return 0;
 }
 
@@ -190,10 +305,16 @@ __asm__("cld ; rep ; movsl" \
 
 static void setup_DMA(void)
 {
-       unsigned long addr = (long) CURRENT->buffer;
-       unsigned long count = 1024;
+       unsigned long addr,count;
 
-       cli();
+       if (command == FD_FORMAT) {
+               addr = (long) tmp_floppy_area;
+               count = floppy->sect*4;
+       }
+       else {
+               addr = (long) CURRENT->buffer;
+               count = 1024;
+       }
        if (read_track) {
 /* mark buffer-track bad, in case all this fails.. */
                buffer_drive = buffer_track = -1;
@@ -205,6 +326,7 @@ static void setup_DMA(void)
                        copy_buffer(CURRENT->buffer,tmp_floppy_area);
        }
 /* mask DMA 2 */
+       cli();
        immoutb_p(4|2,10);
 /* output command byte. I don't know why, but everyone (minix, */
 /* sanches & canton) output this twice, first to 12 then to 11 */
@@ -274,12 +396,12 @@ static int result(void)
 static void bad_flp_intr(void)
 {
        current_track = NO_TRACK;
-       CURRENT->errors++;
-       if (CURRENT->errors > MAX_ERRORS) {
+       CURRENT_ERRORS++;
+       if (CURRENT_ERRORS > MAX_ERRORS) {
                floppy_deselect(current_drive);
-               end_request(0);
+               request_done(0);
        }
-       if (CURRENT->errors > MAX_ERRORS/2)
+       if (CURRENT_ERRORS > MAX_ERRORS/2)
                reset = 1;
        else
                recalibrate = 1;
@@ -297,12 +419,22 @@ static void rw_interrupt(void)
                if (ST1 & 0x02) {
                        printk("Drive %d is write protected\n\r",current_drive);
                        floppy_deselect(current_drive);
-                       end_request(0);
+                       request_done(0);
                } else
                        bad_flp_intr();
-               do_fd_request();
+               redo_fd_request();
                return;
        }
+       if (probing) {
+               int drive = MINOR(CURRENT->dev);
+
+               if (ftd_msg[drive])
+                       printk("Auto-detected floppy type %s in fd%d\r\n",
+                           floppy->name,drive);
+               current_type[drive] = floppy;
+               floppy_sizes[drive] = floppy->size >> 1;
+               probing = 0;
+       }
        if (read_track) {
                buffer_track = seek_track;
                buffer_drive = current_drive;
@@ -313,8 +445,8 @@ static void rw_interrupt(void)
                (unsigned long)(CURRENT->buffer) >= 0x100000)
                copy_buffer(tmp_floppy_area,CURRENT->buffer);
        floppy_deselect(current_drive);
-       end_request(1);
-       do_fd_request();
+       request_done(1);
+       redo_fd_request();
 }
 
 /*
@@ -329,23 +461,31 @@ inline void setup_rw_floppy(void)
        setup_DMA();
        do_floppy = rw_interrupt;
        output_byte(command);
-       if (read_track) {
-               output_byte(current_drive);
-               output_byte(track);
-               output_byte(0);
-               output_byte(1);
+       if (command != FD_FORMAT) {
+               if (read_track) {
+                       output_byte(current_drive);
+                       output_byte(track);
+                       output_byte(0);
+                       output_byte(1);
+               } else {
+                       output_byte(head<<2 | current_drive);
+                       output_byte(track);
+                       output_byte(head);
+                       output_byte(sector);
+               }
+               output_byte(2);         /* sector size = 512 */
+               output_byte(floppy->sect);
+               output_byte(floppy->gap);
+               output_byte(0xFF);      /* sector size (0xff when n!=0 ?) */
        } else {
                output_byte(head<<2 | current_drive);
-               output_byte(track);
-               output_byte(head);
-               output_byte(sector);
+               output_byte(2);
+               output_byte(floppy->sect);
+               output_byte(floppy->fmt_gap);
+               output_byte(FD_FILL_BYTE);
        }
-       output_byte(2);         /* sector size = 512 */
-       output_byte(floppy->sect);
-       output_byte(floppy->gap);
-       output_byte(0xFF);      /* sector size (0xff when n!=0 ?) */
        if (reset)
-               do_fd_request();
+               redo_fd_request();
 }
 
 /*
@@ -360,7 +500,7 @@ static void seek_interrupt(void)
        if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
                recalibrate = 1;
                bad_flp_intr();
-               do_fd_request();
+               redo_fd_request();
                return;
        }
        current_track = ST1;
@@ -374,7 +514,8 @@ static void seek_interrupt(void)
  */
 static void transfer(void)
 {
-       read_track = (command == FD_READ) && (CURRENT->errors < 4);
+       read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
+           (floppy->sect <= MAX_BUFFER_SECTORS);
        if (cur_spec1 != floppy->spec1) {
                cur_spec1 = floppy->spec1;
                output_byte(FD_SPECIFY);
@@ -384,7 +525,7 @@ static void transfer(void)
        if (cur_rate != floppy->rate)
                outb_p(cur_rate = floppy->rate,FD_DCR);
        if (reset) {
-               do_fd_request();
+               redo_fd_request();
                return;
        }
        if (!seek) {
@@ -399,19 +540,24 @@ static void transfer(void)
                output_byte((head<<2) | current_drive);
        output_byte(seek_track);
        if (reset)
-               do_fd_request();
+               redo_fd_request();
 }
 
 /*
  * Special case - used after a unexpected interrupt (or reset)
  */
+
+static void recalibrate_floppy();
+
 static void recal_interrupt(void)
 {
        output_byte(FD_SENSEI);
        current_track = NO_TRACK;
        if (result()!=2 || (ST0 & 0xE0) == 0x60)
                reset = 1;
-       do_fd_request();
+/* Recalibrate until track 0 is reached. Might help on some errors. */
+       if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
+       else redo_fd_request();
 }
 
 void unexpected_floppy_interrupt(void)
@@ -432,7 +578,7 @@ static void recalibrate_floppy(void)
        output_byte(FD_RECALIBRATE);
        output_byte(head<<2 | current_drive);
        if (reset)
-               do_fd_request();
+               redo_fd_request();
 }
 
 static void reset_interrupt(void)
@@ -442,7 +588,11 @@ static void reset_interrupt(void)
        output_byte(FD_SPECIFY);
        output_byte(cur_spec1);         /* hut etc */
        output_byte(6);                 /* Head load time =6ms, DMA */
-       do_fd_request();
+       if (!recover) redo_fd_request();
+       else {
+               recalibrate_floppy();
+               recover = 0;
+       }
 }
 
 /*
@@ -467,11 +617,72 @@ static void reset_floppy(void)
        sti();
 }
 
+static void floppy_shutdown(void)
+{
+       cli();
+       request_done(0);
+       recover = 1;
+       reset_floppy();
+       sti();
+}
+
+static void shake_done(void)
+{
+       current_track = NO_TRACK;
+       if (inb(FD_DIR) & 0x80) request_done(0);
+       redo_fd_request();
+}
+
+static int retry_recal(void (*proc)(void))
+{
+       output_byte(FD_SENSEI);
+       if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;
+       do_floppy = proc;
+       output_byte(FD_RECALIBRATE);
+       output_byte(head<<2 | current_drive);
+       return 1;
+}
+
+static void shake_zero(void)
+{
+       if (!retry_recal(shake_zero)) shake_done();
+}
+
+static void shake_one(void)
+{
+       if (retry_recal(shake_one)) return;
+       do_floppy = shake_done;
+       output_byte(FD_SEEK);
+       output_byte(head << 2 | current_drive);
+       output_byte(1);
+}
+
 static void floppy_on_interrupt(void)
 {
        if (inb(FD_DIR) & 0x80) {
                changed_floppies |= 1<<current_drive;
                buffer_track = -1;
+               if (keep_data[current_drive]) {
+                       if (keep_data[current_drive] > 0)
+                               keep_data[current_drive]--;
+               }
+               else {
+                       if (ftd_msg[current_drive] && current_type[
+                           current_drive] != NULL)
+                               printk("Disk type is undefined after disk "
+                                   "change in fd%d\r\n",current_drive);
+                       current_type[current_drive] = NULL;
+                       floppy_sizes[current_drive] = MAX_DISK_SIZE;
+               }
+/* Forcing the drive to seek makes the "media changed" condition go away.
+   There should be a cleaner solution for that ... */
+               if (!reset && !recalibrate) {
+                       do_floppy = (current_track && current_track != NO_TRACK)
+                           ?  shake_zero : shake_one;
+                       output_byte(FD_RECALIBRATE);
+                       output_byte(head<<2 | current_drive);
+                       return;
+               }
        }
        if (reset) {
                reset_floppy();
@@ -494,45 +705,109 @@ static void floppy_on_interrupt(void)
                transfer();
 }
 
-void do_fd_request(void)
+static void setup_format_params(void)
+{
+    unsigned char *here = (unsigned char *) tmp_floppy_area;
+    int count;
+
+    for (count = 1; count <= floppy->sect; count++) {
+       *here++ = track;
+       *here++ = head;
+       *here++ = count;
+       *here++ = 2; /* 512 bytes */
+    }
+}
+
+static void redo_fd_request(void)
 {
        unsigned int block;
        char * buffer_area;
-
-       INIT_REQUEST;
+       int device;
+
+repeat:
+       if (format_status == FORMAT_WAIT) format_status = FORMAT_BUSY;
+       if (format_status != FORMAT_BUSY) {
+               if (!CURRENT) {
+                       if (!fdc_busy) panic("FDC access conflict");
+                       fdc_busy = 0;
+                       wake_up(&fdc_wait);
+                       CLEAR_INTR;
+                       return;
+               }
+               if (MAJOR(CURRENT->dev) != MAJOR_NR)
+                       panic(DEVICE_NAME ": request list destroyed"); \
+               if (CURRENT->bh) {
+                       if (!CURRENT->bh->b_lock)
+                               panic(DEVICE_NAME ": block not locked");
+               }
+       }
        seek = 0;
-       floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
-       if (current_drive != CURRENT_DEV)
-               current_track = NO_TRACK;
-       current_drive = CURRENT_DEV;
-       block = CURRENT->sector;
-       if (block+2 > floppy->size) {
-               end_request(0);
-               goto repeat;
+       probing = 0;
+       device = MINOR(CURRENT_DEVICE);
+       if (device > 3)
+               floppy = (device >> 2) + floppy_type;
+       else { /* Auto-detection */
+               if ((floppy = current_type[device & 3]) == NULL) {
+                       probing = 1;
+                       if ((floppy = base_type[device & 3]) ==
+                           NULL) {
+                               request_done(0);
+                               goto repeat;
+                       }
+                       floppy += CURRENT_ERRORS & 1;
+               }
+       }
+       if (format_status != FORMAT_BUSY) {
+               if (current_drive != CURRENT_DEV)
+                       current_track = NO_TRACK;
+               current_drive = CURRENT_DEV;
+               block = CURRENT->sector;
+               if (block+2 > floppy->size) {
+                       request_done(0);
+                       goto repeat;
+               }
+               sector = block % floppy->sect;
+               block /= floppy->sect;
+               head = block % floppy->head;
+               track = block / floppy->head;
+               seek_track = track << floppy->stretch;
+               if (CURRENT->cmd == READ)
+                       command = FD_READ;
+               else if (CURRENT->cmd == WRITE)
+                       command = FD_WRITE;
+               else {
+                       printk("do_fd_request: unknown command\n");
+                       request_done(0);
+                       goto repeat;
+               }
        }
-       sector = block % floppy->sect;
-       block /= floppy->sect;
-       head = block % floppy->head;
-       track = block / floppy->head;
-       seek_track = track << floppy->stretch;
-       if (CURRENT->cmd == READ)
-               command = FD_READ;
-       else if (CURRENT->cmd == WRITE)
-               command = FD_WRITE;
        else {
-               printk("do_fd_request: unknown command\n");
-               end_request(0);
-               goto repeat;
+               if (current_drive != (format_req.device & 3))
+                       current_track = NO_TRACK;
+               current_drive = format_req.device & 3;
+               if (format_req.track < 0 || format_req.track >= floppy->track ||
+                   (format_req.head & 0xfffe) || probing) {
+                       request_done(0);
+                       goto repeat;
+               }
+               head = format_req.head;
+               track = format_req.track;
+               seek_track = track << floppy->stretch;
+               if (seek_track == buffer_track) buffer_track = -1;
+               command = FD_FORMAT;
+               setup_format_params();
        }
+       timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
+       timer_active |= 1 << FLOPPY_TIMER;
        if ((seek_track == buffer_track) &&
         (current_drive == buffer_drive)) {
                buffer_area = floppy_track_buffer +
                        ((sector + head*floppy->sect)<<9);
                if (command == FD_READ) {
                        copy_buffer(buffer_area,CURRENT->buffer);
-                       end_request(1);
+                       request_done(1);
                        goto repeat;
-               } else
+               } else if (command == FD_WRITE)
                        copy_buffer(CURRENT->buffer,buffer_area);
        }
        if (seek_track != current_track)
@@ -541,15 +816,162 @@ void do_fd_request(void)
        add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
 }
 
-static int floppy_sizes[] ={
-          0,   0,   0,   0,
-        360, 360 ,360, 360,
-       1200,1200,1200,1200,
-        360, 360, 360, 360,
-        720, 720, 720, 720,
-        360, 360, 360, 360,
-        720, 720, 720, 720,
-       1440,1440,1440,1440
+void do_fd_request(void)
+{
+       cli();
+       while (fdc_busy) sleep_on(&fdc_wait);
+       fdc_busy = 1;
+       sti();
+       redo_fd_request();
+}
+
+static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+    unsigned int param)
+{
+       int drive,cnt,okay;
+       struct floppy_struct *this;
+
+       if (!suser()) return -EPERM;
+       drive = MINOR(inode->i_rdev);
+       switch (cmd) {
+               case FDFMTBEG:
+                       return 0;
+               case FDFMTEND:
+                       cli();
+                       fake_change |= 1 << (drive & 3);
+                       sti();
+                       drive &= 3;
+                       cmd = FDCLRPRM;
+                       break;
+               case FDGETPRM:
+                       if (drive > 3) this = &floppy_type[drive >> 2];
+                       else if ((this = current_type[drive & 3]) == NULL)
+                                   return -ENODEV;
+                       verify_area((void *) param,sizeof(struct floppy_struct));
+                       for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
+                               put_fs_byte(((char *) this)[cnt],
+                                   (char *) param+cnt);
+                       return 0;
+               case FDFMTTRK:
+                       cli();
+                       while (format_status != FORMAT_NONE)
+                               sleep_on(&format_done);
+                       for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
+                               ((char *) &format_req)[cnt] = get_fs_byte(
+                                   (char *) param+cnt);
+                       format_req.device = drive;
+                       format_status = FORMAT_WAIT;
+                       format_errors = 0;
+                       while (format_status != FORMAT_OKAY && format_status !=
+                           FORMAT_ERROR) {
+                               if (fdc_busy) sleep_on(&fdc_wait);
+                               else {
+                                       fdc_busy = 1;
+                                       redo_fd_request();
+                               }
+                       }
+                       while (format_status != FORMAT_OKAY && format_status !=
+                           FORMAT_ERROR)
+                               sleep_on(&format_done);
+                       sti();
+                       okay = format_status == FORMAT_OKAY;
+                       format_status = FORMAT_NONE;
+                       wake_up(&format_done);
+                       return okay ? 0 : -EIO;
+       }
+       if (drive < 0 || drive > 3) return -EINVAL;
+       switch (cmd) {
+               case FDCLRPRM:
+                       current_type[drive] = NULL;
+                       floppy_sizes[drive] = MAX_DISK_SIZE;
+                       keep_data[drive] = 0;
+                       break;
+               case FDSETPRM:
+               case FDDEFPRM:
+                       for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
+                               ((char *) &user_params[drive])[cnt] =
+                                   get_fs_byte((char *) param+cnt);
+                       current_type[drive] = &user_params[drive];
+                       floppy_sizes[drive] = user_params[drive].size >> 1;
+                       if (cmd == FDDEFPRM) keep_data[drive] = -1;
+                       else {
+                               cli();
+                               while (fdc_busy) sleep_on(&fdc_wait);
+                               fdc_busy = 1;
+                               sti();
+                               outb_p((current_DOR & 0xfc) | drive |
+                                   (0x10 << drive),FD_DOR);
+                               for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
+                               keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
+                               outb_p(current_DOR,FD_DOR);
+                               fdc_busy = 0;
+                               wake_up(&fdc_wait);
+                       }
+                       break;
+               case FDMSGON:
+                       ftd_msg[drive] = 1;
+                       break;
+               case FDMSGOFF:
+                       ftd_msg[drive] = 0;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+#define CMOS_READ(addr) ({ \
+outb_p(0x80|addr,0x70); \
+inb_p(0x71); \
+})
+
+static struct floppy_struct *find_base(int drive,int code)
+{
+       struct floppy_struct *base;
+
+       if (code > 0 && code < 5) {
+               base = &floppy_types[(code-1)*2];
+               printk("fd%d is %s",drive,base->name);
+               return base;
+       }
+       printk("fd%d is unknown type %d",drive,code);
+       return NULL;
+}
+
+static void config_types(void)
+{
+       printk("Floppy drive(s): ");
+       base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
+       if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[0] = NULL;
+       else {
+               printk(", ");
+               base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
+       }
+       base_type[2] = base_type[3] = NULL;
+       printk("\r\n");
+}
+
+static int floppy_open(struct inode * inode, struct file * filp)
+{
+       if (filp->f_mode)
+               check_disk_change(inode->i_rdev);
+       return 0;
+}
+
+static void floppy_release(struct inode * inode, struct file * filp)
+{
+       sync_dev(inode->i_rdev);
+}
+
+static struct file_operations floppy_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       fd_ioctl,               /* ioctl */
+       floppy_open,            /* open */
+       floppy_release          /* release */
 };
 
 void floppy_init(void)
@@ -557,6 +979,10 @@ void floppy_init(void)
        outb(current_DOR,FD_DOR);
        blk_size[MAJOR_NR] = floppy_sizes;
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blkdev_fops[MAJOR_NR] = &floppy_fops;
+       timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
+       timer_active &= ~(1 << FLOPPY_TIMER);
+       config_types();
        set_intr_gate(0x26,&floppy_interrupt);
        outb(inb_p(0x21)&~0x40,0x21);
 }
index 1ca50c923ac99837dd3350bf5338a559c8424544..43ce9b722ea5d2dfa904b42a9033ddcf0c108d88 100644 (file)
@@ -37,6 +37,8 @@ static inline unsigned char CMOS_READ(unsigned char addr)
        return inb_p(0x71);
 }
 
+#define        HD_DELAY        0
+
 /* Max read/write errors/sector */
 #define MAX_ERRORS     7
 #define MAX_HD         2
@@ -47,6 +49,10 @@ static void bad_rw_intr(void);
 static int recalibrate = 0;
 static int reset = 0;
 
+#if (HD_DELAY > 0)
+unsigned long last_req, read_timer();
+#endif
+
 /*
  *  This struct defines the HD's and their types.
  */
@@ -125,7 +131,7 @@ static void extended_partition(unsigned int dev)
                               current_minor, hd[current_minor].start_sect, 
                               hd[current_minor].nr_sects,
                               hd[current_minor].start_sect + 
-                              hd[current_minor].nr_sects);
+                              hd[current_minor].nr_sects - 1);
                        current_minor++;
                        p++;
                /*
@@ -171,7 +177,7 @@ static void check_partition(unsigned int dev)
                        hd[minor].start_sect = first_sector + p->start_sect;
                        printk(" part %d start %d size %d end %d \n\r", i, 
                               hd[minor].start_sect, hd[minor].nr_sects, 
-                              hd[minor].start_sect + hd[minor].nr_sects);
+                              hd[minor].start_sect + hd[minor].nr_sects - 1);
                        if ((current_minor & 0x3f) >= 60)
                                continue;
                        if (p->sys_ind == EXTENDED_PARTITION) {
@@ -196,7 +202,7 @@ static void check_partition(unsigned int dev)
                                       hd[current_minor].start_sect, 
                                       hd[current_minor].nr_sects,
                                       hd[current_minor].start_sect + 
-                                      hd[current_minor].nr_sects);
+                                      hd[current_minor].nr_sects - 1);
                        }
                }
        } else
@@ -276,6 +282,22 @@ int sys_setup(void * BIOS)
        return (0);
 }
 
+#if (HD_DELAY > 0)
+unsigned long read_timer(void)
+{
+       unsigned long t;
+       int i;
+
+       cli();
+       outb_p(0xc2, 0x43);
+       t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
+       i = inb_p(0x40);
+       i |= inb(0x40) << 8;
+       sti();
+       return(t - i / 2);
+}
+#endif
+
 static int controller_ready(void)
 {
        int retries = 100000;
@@ -308,6 +330,10 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
 
        if (drive>1 || head>15)
                panic("Trying to write bad sector");
+#if (HD_DELAY > 0)
+       while (read_timer() - last_req < HD_DELAY)
+               /* nothing */;
+#endif
        if (reset || !controller_ready()) {
                reset = 1;
                return;
@@ -321,7 +347,7 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
        outb_p(cyl,++port);
        outb_p(cyl>>8,++port);
        outb_p(0xA0|(drive<<4)|head,++port);
-       outb(cmd,++port);
+       outb_p(cmd,++port);
 }
 
 static int drive_busy(void)
@@ -343,6 +369,7 @@ static void reset_controller(void)
 {
        int     i;
 
+       printk("HD-controller reset\r\n");
        outb(4,HD_CMD);
        for(i = 0; i < 1000; i++) nop();
        outb(hd_info[0].ctl & 0x0f ,HD_CMD);
@@ -396,49 +423,90 @@ static void bad_rw_intr(void)
        if (!CURRENT)
                return;
        if (++CURRENT->errors >= MAX_ERRORS)
-               end_request(0);
+               if (CURRENT->bh && CURRENT->nr_sectors > 2) {
+                       CURRENT->nr_sectors &= ~1;
+                       next_buffer(0);
+               } else
+                       end_request(0);
        if (CURRENT->errors > MAX_ERRORS/2)
                reset = 1;
        else
                recalibrate = 1;
 }
 
+#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
+#define STAT_OK (READY_STAT | SEEK_STAT)
+
 static void read_intr(void)
 {
-       SET_INTR(&read_intr);
-       if (win_result()) {
-               SET_INTR(NULL);
-               bad_rw_intr();
-               do_hd_request();
-               return;
-       }
+       int i;
+
+       i = (unsigned) inb_p(HD_STATUS);
+       if (!(i & DRQ_STAT))
+               goto bad_read;
+       if ((i & STAT_MASK) != STAT_OK)
+               goto bad_read;
        port_read(HD_DATA,CURRENT->buffer,256);
+       i = (unsigned) inb_p(HD_STATUS);
+       if (!(i & BUSY_STAT))
+               if ((i & STAT_MASK) != STAT_OK)
+                       goto bad_read;
        CURRENT->errors = 0;
-       CURRENT->buffer += 512;
+       if (CURRENT->bh && (CURRENT->nr_sectors&1) && CURRENT->nr_sectors > 2)
+               next_buffer(1);
+       else
+               CURRENT->buffer += 512;
        CURRENT->sector++;
-       if (--CURRENT->nr_sectors)
+       if (--CURRENT->nr_sectors) {
+               SET_INTR(&read_intr);
                return;
-       SET_INTR(NULL);
+       }
        end_request(1);
+#if (HD_DELAY > 0)
+       last_req = read_timer();
+#endif
        do_hd_request();
+       return;
+bad_read:
+       if (i & ERR_STAT)
+               i = (unsigned) inb(HD_ERROR);
+       bad_rw_intr();
+       do_hd_request();
+       return;
 }
 
 static void write_intr(void)
 {
-       if (win_result()) {
-               bad_rw_intr();
+       int i;
+
+       i = (unsigned) inb_p(HD_STATUS);
+       if ((i & STAT_MASK) != STAT_OK)
+               goto bad_write;
+       if (CURRENT->nr_sectors < 2) {
+               end_request(1);
+#if (HD_DELAY > 0)
+               last_req = read_timer();
+#endif
                do_hd_request();
                return;
        }
-       if (--CURRENT->nr_sectors) {
-               CURRENT->sector++;
+       if (!(i & DRQ_STAT))
+               goto bad_write;
+       CURRENT->sector++;
+       CURRENT->nr_sectors--;
+       if (CURRENT->bh && !(CURRENT->nr_sectors & 1))
+               next_buffer(1);
+       else
                CURRENT->buffer += 512;
-               SET_INTR(&write_intr);
-               port_write(HD_DATA,CURRENT->buffer,256);
-               return;
-       }
-       end_request(1);
+       SET_INTR(&write_intr);
+       port_write(HD_DATA,CURRENT->buffer,256);
+       return;
+bad_write:
+       if (i & ERR_STAT)
+               i = (unsigned) inb(HD_ERROR);
+       bad_rw_intr();
        do_hd_request();
+       return;
 }
 
 static void recal_intr(void)
@@ -461,7 +529,11 @@ static void hd_times_out(void)
        printk("HD timeout\n\r");
        cli();
        if (++CURRENT->errors >= MAX_ERRORS)
-               end_request(0);
+               if (CURRENT->bh && CURRENT->nr_sectors > 2) {
+                       CURRENT->nr_sectors &= ~1;
+                       next_buffer(0);
+               } else
+                       end_request(0);
        do_hd_request();
 }
 
@@ -494,8 +566,7 @@ static void do_hd_request(void)
        }
        if (recalibrate) {
                recalibrate = 0;
-               hd_out(dev,hd_info[dev].sect,0,0,0,
-                       WIN_RESTORE,&recal_intr);
+               hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
                if (reset)
                        goto repeat;
                return;
@@ -519,27 +590,20 @@ static void do_hd_request(void)
                panic("unknown hd-command");
 }
 
-void hd_init(void)
-{
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       set_intr_gate(0x2E,&hd_interrupt);
-       outb_p(inb_p(0x21)&0xfb,0x21);
-       outb(inb_p(0xA1)&0xbf,0xA1);
-       timer_table[HD_TIMER].fn = hd_times_out;
-}
-
-int hd_ioctl(int dev, int cmd, int arg)
+static int hd_ioctl(struct inode * inode, struct file * file,
+       unsigned int cmd, unsigned int arg)
 {
        struct hd_geometry *loc = (void *) arg;
+       int dev;
 
-       if (!loc)
+       if (!loc || !inode)
                return -EINVAL;
-       dev = MINOR(dev) >> 6;
+       dev = MINOR(inode->i_rdev) >> 6;
        if (dev >= NR_HD)
                return -EINVAL;
-
        switch (cmd) {
                case HDIO_REQ:
+                       verify_area(loc, sizeof(*loc));
                        put_fs_byte(hd_info[dev].head,
                                (char *) &loc->heads);
                        put_fs_byte(hd_info[dev].sect,
@@ -551,3 +615,33 @@ int hd_ioctl(int dev, int cmd, int arg)
                        return -EINVAL;
        }
 }
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static void hd_release(struct inode * inode, struct file * file)
+{
+       sync_dev(inode->i_rdev);
+}
+
+static struct file_operations hd_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       hd_ioctl,               /* ioctl */
+       NULL,                   /* no special open code */
+       hd_release              /* release */
+};
+
+void hd_init(void)
+{
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blkdev_fops[MAJOR_NR] = &hd_fops;
+       set_intr_gate(0x2E,&hd_interrupt);
+       outb_p(inb_p(0x21)&0xfb,0x21);
+       outb(inb_p(0xA1)&0xbf,0xA1);
+       timer_table[HD_TIMER].fn = hd_times_out;
+}
index 7b17306c71dcefd31599e1586b8de0b71bd3d629..18f58d48443fc4760db7e89956bb11a23ba66e37 100644 (file)
@@ -36,7 +36,10 @@ struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
        { NULL, NULL },         /* dev hd */
        { NULL, NULL },         /* dev ttyx */
        { NULL, NULL },         /* dev tty */
-       { NULL, NULL }          /* dev lp */
+       { NULL, NULL },         /* dev lp */
+       { NULL, NULL },         /* dev pipes */
+       { NULL, NULL },         /* dev sd */
+       { NULL, NULL }          /* dev st */
 };
 
 /*
@@ -128,6 +131,23 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                return;
        }
 repeat:
+       cli();
+       if (major == 3 && (req = blk_dev[major].current_request)) {
+               while (req = req->next) {
+                       if (req->dev == bh->b_dev &&
+                           !req->waiting &&
+                           req->cmd == rw &&
+                           req->sector + req->nr_sectors == bh->b_blocknr << 1 &&
+                           req->nr_sectors < 254) {
+                               req->bhtail->b_reqnext = bh;
+                               req->bhtail = bh;
+                               req->nr_sectors += 2;
+                               bh->b_dirt = 0;
+                               sti();
+                               return;
+                       }
+               }
+       }
 /* we don't allow the write-requests to fill up the queue completely:
  * we want some room for reads: they take precedence. The last third
  * of the requests are only for reads.
@@ -135,9 +155,8 @@ repeat:
        if (rw == READ)
                req = request+NR_REQUEST;
        else
-               req = request+((NR_REQUEST*2)/3);
+               req = request+(NR_REQUEST/2);
 /* find an empty request */
-       cli();
        while (--req >= request)
                if (req->dev < 0)
                        goto found;
@@ -161,6 +180,7 @@ found:      sti();
        req->buffer = bh->b_data;
        req->waiting = NULL;
        req->bh = bh;
+       req->bhtail = bh;
        req->next = NULL;
        add_request(major+blk_dev,req);
 }
@@ -206,6 +226,8 @@ void ll_rw_block(int rw, struct buffer_head * bh)
 {
        unsigned int major;
 
+       if (!bh)
+               return;
        if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
        !(blk_dev[major].request_fn)) {
                printk("ll_rw_block: Trying to read nonexistent block-device\n\r");
index a7d86fbbd62538a580c3c10e70e3b1566a40e9d3..8448022b7b6eeead05f8d6b20fca8f2281b20310 100644 (file)
@@ -4,7 +4,7 @@
  *  Written by Theodore Ts'o, 12/2/91
  */
 
-#include <string.h>
+#include <linux/string.h>
 
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -47,6 +47,17 @@ void do_rd_request(void)
        goto repeat;
 }
 
+static struct file_operations rd_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       NULL,                   /* ioctl */
+       NULL,                   /* no special open code */
+       NULL                    /* no special release code */
+};
+
 /*
  * Returns amount of memory which needs to be reserved.
  */
@@ -56,6 +67,7 @@ long rd_init(long mem_start, int length)
        char    *cp;
 
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blkdev_fops[MAJOR_NR] = &rd_fops;
        rd_start = (char *) mem_start;
        rd_length = length;
        cp = rd_start;
diff --git a/kernel/blk_drv/scsi/Makefile b/kernel/blk_drv/scsi/Makefile
new file mode 100644 (file)
index 0000000..acfeec7
--- /dev/null
@@ -0,0 +1,149 @@
+#
+# Makefile for the linux kernel block device drivers.
+#
+# 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).
+#
+
+#DEBUG = -DDEBUG=0xffffffff -DDEBUG_NO_CMD
+
+AR     =ar
+AS     =as
+LD     =ld
+LDFLAGS        =-s -x
+CC     =cc
+
+CPP    =cc -E -nostdinc -I../../../include
+
+.c.s:
+       $(CC) -nostdinc $(CFLAGS) $(DEBUG) \
+       -S -o $*.s $<
+.s.o:
+       $(AS) -c -o $*.o $<
+.c.o:
+       $(CC) -nostdinc -I../../../include $(CFLAGS) $(DEBUG) \
+       -c -o $*.o $<
+
+LOWLEVELCSRC = aha1542.c seagate.c ultrastor.c 
+LOWLEVELHSRC = aha1542.c seagate.h ultrastor.h
+CSRC = hosts.c sd.c st.c scsi.c $(LOWLEVELCSRC)
+HSRC = hosts.h sd.h st.h scsi.h $(LOWLEVELHSRC)
+
+OBJS = scsi.o hosts.o scsi_ioctl.o sd.o sd_ioctl.o st.o st_ioctl.o \
+       aha1542.o seagate.o ultrastor.o
+
+all: scsi.a
+
+config.out : config.in ../../../include/linux/config.h
+       rm -f  foo.c
+       ln -s config.in foo.c   
+       $(CPP) foo.c | grep '\.o' > config.out 
+       rm foo.c
+
+figure : hosts.h ../../../include/linux/config.h hosts.c config.out
+       $(CC) -I../../../include -DFIGURE_MAX_SCSI_HOSTS hosts.c -o figure
+
+max_hosts.h : figure
+       (echo "#ifndef _MAX_HOSTS_H"; \
+        echo "#define _MAX_HOSTS_H"; \
+        echo "#define MAX_SCSI_HOSTS `./figure`";\
+        echo "#endif") > tmp_max
+       cp tmp_max max_hosts.h
+               
+scsi.a: $(OBJS)
+       $(AR) rcs scsi.a $(OBJS)
+       sync
+
+scsi.shar: Makefile scsi.doc $(CSRC) $(HSRC) ../ll_rw_blk.c ../blk.h all.diff
+       (cd ..; shar scsi/scsi.doc scsi/Makefile scsi/*.{c,h} scsi/all.diff blk.h ll_rw_blk.c) > scsi.shar;
+
+clean:
+       rm -f core *.o *.a tmp_make tmp_max figure config.out Makefile.tag max_hosts.h
+
+seagate.s seagate.o : seagate.c ../../../include/linux/config.h \
+  ../../../include/linux/config.dist.h ../../../include/linux/sched.h \
+  ../../../include/linux/head.h ../../../include/linux/fs.h \
+  ../../../include/sys/types.h ../../../include/linux/mm.h \
+  ../../../include/linux/kernel.h ../../../include/signal.h \
+  ../../../include/sys/param.h ../../../include/sys/time.h \
+  ../../../include/time.h ../../../include/sys/resource.h \
+  ../../../include/linux/string.h seagate.h scsi.h hosts.h max_hosts.h 
+       cc -nostdinc -I../../../include -Wall -c seagate.c $(DEBUG) 
+
+dep:
+       sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+       (for i in *.c ;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
+               $(CPP) -M $$i;done) >> tmp_make
+       cp tmp_make Makefile
+
+### Dependencies:
+aha1542.s aha1542.o : aha1542.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+  ../../../include/linux/head.h ../../../include/linux/string.h ../../../include/asm/system.h \
+  ../../../include/asm/io.h scsi.h hosts.h max_hosts.h aha1542.h 
+hosts.s hosts.o : hosts.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+  scsi.h hosts.h max_hosts.h aha1542.h seagate.h ultrastor.h 
+scsi.s scsi.o : scsi.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/asm/system.h \
+  ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+  ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+  ../../../include/linux/mm.h ../../../include/linux/kernel.h ../../../include/signal.h \
+  ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+  ../../../include/sys/resource.h ../../../include/linux/timer.h ../../../include/linux/string.h \
+  scsi.h hosts.h max_hosts.h sd.h st.h 
+scsi_ioctl.s scsi_ioctl.o : scsi_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/errno.h \
+  ../../../include/asm/io.h ../../../include/asm/segment.h ../../../include/asm/system.h \
+  ../../../include/linux/kernel.h ../../../include/linux/sched.h ../../../include/linux/head.h \
+  ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+  ../../../include/limits.h ../../../include/linux/mm.h ../../../include/signal.h \
+  ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+  ../../../include/sys/resource.h ../../../include/linux/string.h scsi.h hosts.h \
+  max_hosts.h scsi_ioctl.h 
+sd.s sd.o : sd.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/string.h \
+  ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+  ../../../include/limits.h ../../../include/linux/kernel.h ../../../include/linux/sched.h \
+  ../../../include/linux/head.h ../../../include/linux/mm.h ../../../include/signal.h \
+  ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+  ../../../include/sys/resource.h scsi.h sd.h ../blk.h 
+sd_ioctl.s sd_ioctl.o : sd_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+  ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+  ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+  ../../../include/linux/mm.h ../../../include/signal.h ../../../include/sys/param.h \
+  ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+  scsi.h sd.h 
+seagate.s seagate.o : seagate.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/sched.h \
+  ../../../include/linux/head.h ../../../include/linux/fs.h ../../../include/sys/types.h \
+  ../../../include/sys/dirent.h ../../../include/limits.h ../../../include/linux/mm.h \
+  ../../../include/linux/kernel.h ../../../include/signal.h ../../../include/sys/param.h \
+  ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+  seagate.h scsi.h hosts.h max_hosts.h 
+st.s st.o : st.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h scsi.h \
+  st.h ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+  ../../../include/limits.h ../../../include/linux/kernel.h ../../../include/linux/sched.h \
+  ../../../include/linux/head.h ../../../include/linux/mm.h ../../../include/signal.h \
+  ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+  ../../../include/sys/resource.h ../blk.h 
+st_ioctl.s st_ioctl.o : st_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+  ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+  ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+  ../../../include/linux/mm.h ../../../include/signal.h ../../../include/sys/param.h \
+  ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+  st.h scsi.h 
+ultrastor.s ultrastor.o : ultrastor.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+  ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/stddef.h \
+  ../../../include/linux/string.h ../../../include/linux/sched.h ../../../include/linux/head.h \
+  ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+  ../../../include/limits.h ../../../include/linux/mm.h ../../../include/linux/kernel.h \
+  ../../../include/signal.h ../../../include/sys/param.h ../../../include/sys/time.h \
+  ../../../include/time.h ../../../include/sys/resource.h ../../../include/linux/hdreg.h \
+  ../../../include/asm/system.h ../../../include/asm/io.h ../../../include/asm/segment.h \
+  ultrastor.h scsi.h hosts.h max_hosts.h 
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
new file mode 100644 (file)
index 0000000..9547dda
--- /dev/null
@@ -0,0 +1,481 @@
+/* $Id: aha1542.c,v 1.1 1992/04/24 18:01:50 root Exp root $
+ *  linux/kernel/aha1542.c
+ *
+ *  (C) 1992  Tommy Thorn
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aha1542.h"
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+#define base 0x330
+#define intr_chan 11
+
+static struct mailbox mb[2];
+static struct ccb ccb;
+
+long WAITtimeout, WAITnexttimeout = 3000000;
+
+void (*do_done)() = NULL;
+extern void aha1542_interrupt();
+
+#define aha1542_intr_reset()  outb(IRST, CONTROL)
+#define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
+#define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
+
+#define WAIT(port, mask, allof, noneof)                                        \
+ { register WAITbits;                                                  \
+   register WAITtimeout = WAITnexttimeout;                             \
+   while (1) {                                                         \
+     WAITbits = inb(port) & (mask);                                    \
+     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+       break;                                                          \
+     if (--WAITtimeout == 0) goto fail;                                        \
+   }                                                                   \
+ }
+
+static void aha1542_stat(void)
+{
+    int s = inb(STATUS), i = inb(INTRFLAGS);
+/*  printk("status = %x, intrflags = %x served %d last %x timeout %d\n", s, i, intr_flag, intr_last, WAITtimeout); */
+    printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout);
+}
+
+static int aha1542_out(unchar *cmdp, int len)
+{
+    while (len--)
+      {
+         WAIT(STATUS, CDF, 0, CDF);
+         outb(*cmdp++, DATA);
+      }
+    return 0;
+  fail:
+    printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
+    return 1;
+}
+
+int makecode(unsigned hosterr, unsigned scsierr)
+{
+    switch (hosterr) {
+      case 0x0:
+      case 0xa: /* Linked command complete without error and linked normally */
+      case 0xb: /* Linked command complete without error, interrupt generated */
+       hosterr = 0;
+       break;
+
+      case 0x11: /* Selection time out-The initiator selection or target
+                   reselection was not complete within the SCSI Time out period */
+       hosterr = DID_TIME_OUT;
+       break;
+
+      case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
+                   thean was allocated by the Data Length field or the sum of the
+                   Scatter / Gather Data Length fields. */
+
+      case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+      case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
+                   invalid. This usually indicates a software failure. */
+
+      case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+                   This usually indicates a software failure. */
+
+      case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
+                   of linked CCB's does not specify the same logical unit number as
+                   the first. */
+      case 0x18: /* Invalid Target Direction received from Host-The direction of a
+                   Target Mode CCB was invalid. */
+
+      case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
+                   received to service data transfer between the same target LUN
+                   and initiator SCSI ID in the same direction. */
+
+      case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
+                   length segment or invalid segment list boundaries was received.
+                   A CCB parameter was invalid. */
+       hosterr = DID_ERROR; /* Couldn't find any better */
+       break;
+
+      case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
+                   phase sequence was requested by the target. The host adapter
+                   will generate a SCSI Reset Condition, notifying the host with
+                   a SCRD interrupt */
+       hosterr = DID_RESET;
+       break;
+      default:
+       printk("makecode: unknown hoststatus %x\n", hosterr);
+       break;
+    }
+    return scsierr|(hosterr << 16);
+}
+
+int aha1542_test_port(void)
+{
+    volatile int debug = 0;
+    
+    /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
+    
+    /*  DEB(printk("aha1542_test_port called \n")); */
+    
+    outb(SRST|IRST/*|SCRST*/, CONTROL);
+    
+    debug = 1;
+    /* Expect INIT and IDLE, any of the others are bad */
+    WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+    
+    debug = 2;
+    /* Shouldn't have generated any interrupts during reset */
+    if (inb(INTRFLAGS)&INTRMASK) goto fail;
+    
+    debug = 3;
+    /* Test the basic ECHO command */
+    outb(CMD_ECHO, DATA);
+    
+    debug = 4;
+    /* Wait for CDF=0. If any of the others are set, it's bad */
+    WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
+    
+    debug = 5;
+    /* The meaning of life */
+    outb(42, DATA);
+    
+    debug = 6;
+    /* Expect only DF, that is, data ready */
+    WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
+    
+    debug = 7;
+    /* Is the answer correct? */
+    if (inb(DATA) != 42) goto fail;
+    
+    debug = 8;
+    /* Reading port should reset DF */
+    if (inb(STATUS) & DF) goto fail;
+    
+    debug = 9;
+    /* When HACC, command is completed, and we're though testing */
+    WAIT(INTRFLAGS, HACC, HACC, 0);
+    /* now initialize adapter */
+    
+    debug = 10;
+    /* Clear interrupts */
+    outb(IRST, CONTROL);
+    
+    debug = 11;
+    
+    return debug;                              /* 1 = ok */
+  fail:
+    return 0;                                  /* 0 = not ok */
+}
+
+/* What's this little function for? */
+char *aha1542_info(void)
+{
+    static char buffer[] = "Adaptec 1542";
+    return buffer;
+}
+
+/* A "high" level interrupt handler */
+void aha1542_intr_handle(void)
+{
+    int flag = inb(INTRFLAGS);
+    void (*my_done)() = do_done;
+    int errstatus;
+
+    do_done = NULL;
+#ifdef DEBUG
+    printk("aha1542_intr_handle: ");
+    if (!(flag&ANYINTR)) printk("no interrupt?");
+    if (flag&MBIF) printk("MBIF ");
+    if (flag&MBOA) printk("MBOF ");
+    if (flag&HACC) printk("HACC ");
+    if (flag&SCRD) printk("SCRD ");
+    printk("status %02x\n", inb(STATUS));
+    if (ccb.tarstat|ccb.hastat)
+      printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
+#endif
+    aha1542_intr_reset();
+    if (!my_done) {
+       printk("aha1542_intr_handle: Unexpected interrupt\n");
+       return;
+    }
+
+    /* is there mail :-) */
+       
+    if (!mb[1].status) {
+       DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
+       my_done(DID_TIME_OUT << 16);
+       return;
+    }
+
+    /* more error checking left out here */
+    if (mb[1].status != 1)
+      /* This is surely wrong, but I don't know what's right */
+      errstatus = makecode(ccb.hastat, ccb.tarstat);
+    else
+      errstatus = 0;
+
+    mb[1].status = 0;
+
+    if (ccb.tarstat == 2) {
+       int i;
+       DEB(printk("aha1542_intr_handle: sense:"));
+       for (i = 0; i < 12; i++)
+         printk("%02x ", ccb.cdb[ccb.cdblen+i]);
+       printk("\n");
+/*
+       DEB(printk("aha1542_intr_handle: buf:"));
+       for (i = 0; i < bufflen; i++)
+         printk("%02x ", ((unchar *)buff)[i]);
+       printk("\n");
+*/
+    }
+    DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+    my_done(errstatus);
+    return;
+}
+
+int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int))
+{
+    unchar ahacmd = CMD_START_SCSI;
+    int i;
+    unchar *cmd = (unchar *) cmnd;
+
+    DEB(if (target > 1) {done(DID_TIME_OUT << 16); return 0;});
+    
+#ifdef DEBUG
+    if (*cmd == READ_10 || *cmd == WRITE_10)
+      i = xscsi2int(cmd+2);
+    else if (*cmd == READ_6 || *cmd == WRITE_6)
+      i = scsi2int(cmd+2);
+    else
+      i = -1;
+    if (done)
+      printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+    else
+      printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+    aha1542_stat();
+    printk("aha1542_queuecommand: dumping scsi cmd:");
+    for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
+    printk("\n");
+    if (*cmd == WRITE_10 || *cmd == WRITE_6)
+      return 0; /* we are still testing, so *don't* write */
+#endif
+    memset(&ccb, 0, sizeof ccb);
+    
+    ccb.cdblen = (*cmd<=0x1f)?6:10;    /* SCSI Command Descriptor Block Length */
+    
+    memcpy(ccb.cdb, cmd, ccb.cdblen);
+    ccb.op = 0;                                /* SCSI Initiator Command */
+    ccb.idlun = (target&7)<<5;         /* SCSI Target Id */
+    ccb.rsalen = 12;
+    any2scsi(ccb.datalen, bufflen);
+    any2scsi(ccb.dataptr, buff);
+    ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
+    ccb.commlinkid = 0;
+    
+    mb[0].status = 1;
+    mb[1].status = 0;
+    
+#ifdef DEBUGd
+    printk("aha1542_command: sending.. ");
+    for (i = 0; i < sizeof(ccb)-10; i++)
+      printk("%02x ", ((unchar *)&ccb)[i]);
+#endif
+    
+    if (done) {
+       DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
+       if (do_done)
+         printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
+       else
+         do_done = done;
+       aha1542_out(&ahacmd, 1);                /* start scsi command */
+       DEB(aha1542_stat());
+       aha1542_enable_intr();
+    }
+    else
+      printk("aha1542_queuecommand: done can't be NULL\n");
+    
+    return 0;
+}
+
+volatile static int internal_done_flag = 0;
+volatile static int internal_done_errcode = 0;
+static void internal_done(int errcode)
+{
+    internal_done_errcode = errcode;
+    ++internal_done_flag;
+}
+
+int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
+{
+    DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
+    aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
+
+    while (!internal_done_flag);
+    internal_done_flag = 0;
+    return internal_done_errcode;
+}
+
+/* Initialize mailboxes */
+static void setup_mailboxes()
+{
+    static unchar cmd[5] = {CMD_MBINIT, 1};
+    
+    mb[0].status = mb[1].status = 0;
+    aha1542_intr_reset();              /* reset interrupts, so they don't block */     
+    any2scsi((cmd+2), mb);
+    any2scsi(mb[0].ccbptr, &ccb);
+    aha1542_out(cmd, 5);
+    WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+    while (0) {
+      fail:
+       printk("aha1542_detect: failed setting up mailboxes\n");
+    }
+    aha1542_intr_reset();
+}
+
+/* a hack to avoid a strange compilation error */
+
+void call_buh()
+{
+    set_intr_gate(0x2b,&aha1542_interrupt);
+}
+
+/* return non-zero on detection */
+int aha1542_detect(int hostnum) /* hostnum ignored for now */
+{
+    int i;
+
+    DEB(printk("aha1542_detect: \n"));
+    
+    if (!(i = aha1542_test_port())) {
+       return 0;
+    }
+    /* Set the Bus on/off-times as not to ruin floppy performens */
+    {
+       static unchar oncmd[] = {CMD_BUSON_TIME, 5};
+       static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
+       
+       aha1542_intr_reset();
+       aha1542_out(oncmd, 2);
+       WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+       aha1542_intr_reset();
+       aha1542_out(offcmd, 2);
+       WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+       while (0) {
+         fail:
+           printk("aha1542_detect: setting bus on/off-time failed\n");
+       }
+       aha1542_intr_reset();
+    }
+
+    aha1542_stat();
+    setup_mailboxes();
+
+    aha1542_stat();
+
+    DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
+    call_buh();
+
+    if (intr_chan >= 8)
+      outb(inb_p(0x21)&0xfb,0x21);             /* open for slave ?? */
+
+    DEB(printk("aha1542_detect: enabling interrupts\n"));
+    aha1542_enable_intr();
+
+#ifdef DEBUG
+    DEB(printk(" *** READ CAPACITY ***\n"));
+
+    {
+       unchar buf[8];
+       static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       int i;
+       
+       for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
+       for (i = 0; i < 2; ++i)
+         if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+             printk("aha_detect: LU %d sector_size %d device_size %d\n",
+                    i, xscsi2int(buf+4), xscsi2int(buf));
+         }
+    }
+
+    DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+    for (i = 0; i < 4; ++i)
+      {
+         unsigned char cmd[10];
+         static buffer[512];
+         
+         cmd[0] = READ_10;
+         cmd[1] = 0;
+         xany2scsi(cmd+2, i);
+         cmd[6] = 0;
+         cmd[7] = 0;
+         cmd[8] = 1;
+         cmd[9] = 0;
+         aha1542_command(0, cmd, buffer, 512);
+      }
+#endif
+    return 1;
+}
+
+int aha1542_abort(int i)
+{
+    DEB(printk("aha1542_abort\n"));
+    return 0;
+}
+
+int aha1542_reset(void)
+{
+    DEB(printk("aha1542_reset called\n"));
+    return 0;
+}
+
+__asm__("
+_aha1542_interrupt:
+       cld
+       pushl %eax
+       pushl %ecx
+       pushl %edx
+       push %ds
+       push %es
+       push %fs
+       movl $0x10,%eax
+       mov %ax,%ds
+       mov %ax,%es
+       movl $0x17,%eax
+       mov %ax,%fs
+       movb $0x20,%al
+       outb %al,$0xA0          # EOI to interrupt controller #1
+       jmp 1f                  # give port chance to breathe
+1:     jmp 1f
+1:     outb %al,$0x20
+# Please, someone, change this to use the timer
+#      andl $0xfffeffff,_timer_active
+       movl $_aha1542_intr_handle,%edx
+       call *%edx              # ``interesting'' way of handling intr.
+       pop %fs
+       pop %es
+       pop %ds
+       popl %edx
+       popl %ecx
+       popl %eax
+       iret
+");
diff --git a/kernel/blk_drv/scsi/aha1542.h b/kernel/blk_drv/scsi/aha1542.h
new file mode 100644 (file)
index 0000000..6609a4e
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef _AHA1542_H
+
+/* $Id: aha1542.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+ *
+ * Header file for the adaptec 1542 driver for Linux
+ *
+ * $Log: aha1542.h,v $
+ * Revision 1.1  1992/04/24  18:01:50  root
+ * Initial revision
+ *
+ * Revision 1.1  1992/04/02  03:23:13  drew
+ * Initial revision
+ *
+ * Revision 1.3  1992/01/27  14:46:29  tthorn
+ * *** empty log message ***
+ *
+ */
+
+typedef unsigned char unchar;
+
+/* I/O Port interface 4.2 */
+/* READ */
+#define STATUS base
+#define STST   0x80            /* Self Test in Progress */
+#define DIAGF  0x40            /* Internal Diagonostic Failure */
+#define INIT   0x20            /* Mailbox Initialization Required */
+#define IDLE   0x10            /* SCSI Host Adapter Idle */
+#define CDF    0x08            /* Command/Data Out Port Full */
+#define DF     0x04            /* Data In Port Full */
+#define INVDCMD        0x01            /* Invalid H A Command */
+#define STATMASK 0xfd          /* 0x02 is reserved */
+
+#define INTRFLAGS STATUS+2
+#define ANYINTR        0x80            /* Any Interrupt */
+#define SCRD   0x08            /* SCSI Reset Detected */
+#define HACC   0x04            /* HA Command Complete */
+#define MBOA   0x02            /* MBO Empty */
+#define MBIF   0x01            /* MBI Full */
+#define INTRMASK 0x8f
+
+/* WRITE */
+#define CONTROL STATUS
+#define HRST   0x80            /* Hard Reset */
+#define SRST   0x40            /* Soft Reset */
+#define IRST   0x20            /* Interrupt Reset */
+#define SCRST  0x10            /* SCSI Bus Reset */
+
+/* READ/WRITE */
+#define DATA STATUS+1
+#define CMD_NOP                0x00    /* No Operation */
+#define CMD_MBINIT     0x01    /* Mailbox Initialization */
+#define CMD_START_SCSI 0x02    /* Start SCSI Command */
+#define CMD_INQUIRY    0x04    /* Adapter Inquiry */
+#define CMD_EMBOI      0x05    /* Enable MailBox Out Interrupt */
+#define CMD_BUSON_TIME 0x07    /* Set Bus-On Time */
+#define CMD_BUSOFF_TIME        0x08    /* Set Bus-Off Time */
+#define CMD_RETDEVS    0x0a    /* Return Installed Devices */
+#define CMD_RETCONF    0x0b    /* Return Configuration Data */
+#define CMD_RETSETUP   0x0d    /* Return Setup Data */
+#define CMD_ECHO       0x1f    /* ECHO Command Data */
+
+/* Mailbox Definition 5.2.1 and 5.2.2 */
+struct mailbox {
+  unchar status;               /* Command/Status */
+  unchar ccbptr[3];            /* msb, .., lsb */
+};
+
+/* These belong in scsi.h also */
+#define any2scsi(up, p)                        \
+(up)[0] = (((long)(p)) >> 16) & 0xff;  \
+(up)[1] = ((long)(p)) >> 8;            \
+(up)[2] = ((long)(p));
+
+#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
+
+#define xany2scsi(up, p)       \
+(up)[0] = ((long)(p)) >> 24;   \
+(up)[1] = ((long)(p)) >> 16;   \
+(up)[2] = ((long)(p)) >> 8;    \
+(up)[3] = ((long)(p));
+
+#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+                     + (((long)(up)[2]) <<  8) +  ((long)(up)[3]) )
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+
+struct ccb {                   /* Command Control Block 5.3 */
+  unchar op;                   /* Command Control Block Operation Code */
+  unchar idlun;                        /* op=0,2:Target Id, op=1:Initiator Id */
+                               /* Outbound data transfer, length is checked*/
+                               /* Inbound data transfer, length is checked */
+                               /* Logical Unit Number */
+  unchar cdblen;               /* SCSI Command Length */
+  unchar rsalen;               /* Request Sense Allocation Length/Disable */
+  unchar datalen[3];           /* Data Length (msb, .., lsb) */
+  unchar dataptr[3];           /* Data Pointer */
+  unchar linkptr[3];           /* Link Pointer */
+  unchar commlinkid;           /* Command Linking Identifier */
+  unchar hastat;               /* Host Adapter Status (HASTAT) */
+  unchar tarstat;              /* Target Device Status */
+  unchar reserved[2];
+  unchar cdb[MAX_CDB+MAX_SENSE];/* SCSI Command Descriptor Block */
+                               /* REQUEST SENSE */
+};
+
+int aha1542_detect(int);
+int aha1542_command(unsigned char target, const void *cmnd, void *buff, int bufflen);
+/*int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int));*/
+int aha1542_abort(int);
+char *aha1542_info(void);
+int aha1542_reset(void);
+
+#ifndef NULL
+       #define NULL 0
+#endif
+
+#define AHA1542 {"Adaptec 1542", aha1542_detect,       \
+               aha1542_info, aha1542_command,          \
+               /*aha1542_queuecommand*/ NULL,          \
+               aha1542_abort,                          \
+               aha1542_reset,                          \
+               0, 7, 0}
+#endif
diff --git a/kernel/blk_drv/scsi/config.in b/kernel/blk_drv/scsi/config.in
new file mode 100644 (file)
index 0000000..75c1fde
--- /dev/null
@@ -0,0 +1,29 @@
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI
+scsi.o
+hosts.o
+scsi_ioctl.o
+#endif
+
+#ifdef CONFIG_BLK_DEV_SD
+sd.o
+sd_ioctl.o
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+st.o
+st_ioctl.o
+#endif
+
+#ifdef CONFIG_SCSI_AHA1542
+aha1542.o
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+seagate.o
+#endif
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+ultrastor.o
+#endif
diff --git a/kernel/blk_drv/scsi/hosts.c b/kernel/blk_drv/scsi/hosts.c
new file mode 100644 (file)
index 0000000..71f7450
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *     hosts.c Copyright (C) 1992 Drew Eckhardt 
+ *     mid to lowlevel SCSI driver interface by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+
+/*
+       This file contains the medium level SCSI
+       host interface initialization, as well as the scsi_hosts array of SCSI
+       hosts currently present in the system. 
+*/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI
+#include <linux/kernel.h>
+#include "scsi.h"
+
+#ifndef NULL 
+       #define NULL 0L
+#endif
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+       #define MAX_SCSI_HOSTS
+#endif
+
+#include "hosts.h"
+
+#ifdef CONFIG_SCSI_AHA1542
+#include "aha1542.h"
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include "seagate.h"
+#endif
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+#include "ultrastor.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+/*
+       The scsi host entries should be in the order you wish the 
+       cards to be detected.  A driver may appear more than once IFF
+       it can deal with being detected (and therefore initialized) 
+       with more than one simulatenous host number, can handle being
+       rentrant, etc.
+
+       They may appear in any order, as each SCSI host  is told which host number it is
+       during detection.
+*/
+
+/*
+       When figure is run, we don't want to link to any object code.  Since 
+       the macro for each host will contain function pointers, we cannot 
+       use it and instead must use a "blank" that does no such 
+       idiocy.
+*/
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+       #define BLANKIFY(what) BLANK_HOST
+#else
+       #define BLANKIFY(what) what
+#endif
+
+Scsi_Host scsi_hosts[] =
+       {
+#ifdef CONFIG_SCSI_AHA1542
+       BLANKIFY(AHA1542),
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+       BLANKIFY(SEAGATE_ST0X),
+#endif
+#ifdef CONFIG_SCSI_ULTRASTOR
+       BLANKIFY(ULTRASTOR_14F),
+#endif
+       };
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+       #undef MAX_SCSI_HOSTS
+       #define  MAX_SCSI_HOSTS  (sizeof(scsi_hosts) / sizeof(Scsi_Host))
+#endif
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+#include <stdio.h>
+void main (void)
+{
+       printf("%d", MAX_SCSI_HOSTS);
+}
+#else
+/*
+       Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here. 
+*/
+
+volatile unsigned char host_busy[MAX_SCSI_HOSTS];
+volatile int host_timeout[MAX_SCSI_HOSTS];
+volatile Scsi_Cmnd *host_queue[MAX_SCSI_HOSTS]; 
+/*
+       scsi_init initializes the scsi hosts. 
+*/
+
+void scsi_init(void)
+       {
+       static int called = 0;
+       int i, count;   
+       if (!called)
+               {
+               called = 1;     
+               for (count = i = 0; i < MAX_SCSI_HOSTS; ++i)
+                       {
+                       /*
+                               Initialize our semaphores.  -1 is interpreted to mean 
+                               "inactive" - where as 0 will indicate a time out condition.
+                       */ 
+
+                       host_busy[i] = 0;
+                       host_timeout[i] = 0;
+                       host_queue[i] = NULL;   
+                       
+                       if ((scsi_hosts[i].detect) &&  (scsi_hosts[i].present = scsi_hosts[i].detect(i)))
+                                       {               
+                                       printk ("Host %d is detected as a(n) %s.\n\r",
+                                               count, scsi_hosts[i].name);
+                                       printk ("%s", scsi_hosts[i].info());
+                                       ++count;
+                                       }
+                       }
+               printk ("%d host adapters detected. \n\r", count);
+               }
+
+       }
+
+#endif
+
+#endif 
diff --git a/kernel/blk_drv/scsi/hosts.h b/kernel/blk_drv/scsi/hosts.h
new file mode 100644 (file)
index 0000000..468a044
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *     hosts.h Copyright (C) 1992 Drew Eckhardt 
+ *     mid to low-level SCSI driver interface header by        
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+#ifndef _HOSTS_H
+       #define _HOSTS_H
+
+#ifndef MAX_SCSI_HOSTS
+       #include "max_hosts.h"
+#endif
+
+/*
+       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+*/
+
+/*
+       The Scsi_Cmnd structure is used by scsi.c internally, and for communication with
+       low level drivers that support multiple outstanding commands.
+*/
+
+typedef struct scsi_cmnd {
+       int host;
+       unsigned char target, lun;
+       unsigned char cmnd[10];
+       unsigned bufflen;
+       void *buffer;
+       
+       unsigned char sense_cmnd[6];
+       unsigned char *sense_buffer;    
+
+       unsigned flags;
+               
+       int retries;
+       int allowed;
+       int timeout_per_command, timeout_total, timeout;
+       
+       void (*done)(int,int);
+       struct scsi_cmnd *next, *prev;  
+       } Scsi_Cmnd;             
+
+/*
+       The Scsi_Host type has all that is needed to interface with a SCSI
+       host in a device independant matter.  
+*/
+
+typedef struct     
+       {
+       /*
+               The name pointer is a pointer to the name of the SCSI
+               device detected.
+       */
+
+       char *name;
+
+       /*
+               The detect function shall return non zero on detection,
+               and initialize all data necessary for this particular
+               SCSI driver.  It is passed the host number, so this host
+               knows where it is in the hosts array
+       */
+
+       int (* detect)(int); 
+
+       /*
+               The info function will return whatever useful
+               information the developer sees fit.              
+       */
+
+        char *(* info)(void);
+
+       /*
+               The command function takes a target, a command (this is a SCSI 
+               command formatted as per the SCSI spec, nothing strange), a 
+               data buffer pointer, and data buffer length pointer.  The return
+               is a status int, bit fielded as follows : 
+               Byte    What
+               0       SCSI status code
+               1       SCSI 1 byte message
+               2       host error return.
+               3       mid level error return
+       */
+
+       int (* command)(unsigned char target, const void *cmnd, 
+                            void *buff, int bufflen);
+
+        /*
+                The QueueCommand function works in a similar manner
+                to the command function.  It takes an additional parameter,
+                void (* done)(int host, int code) which is passed the host 
+               # and exit result when the command is complete.  
+               Host number is the POSITION IN THE hosts array of THIS
+               host adapter.
+        */
+
+        int (* queuecommand)(unsigned char target, const void *cmnd,
+                             void *buff, int bufflen, void (*done)(int,int));
+
+       
+       /*
+               Since the mid level driver handles time outs, etc, we want to 
+               be able to abort the current command.  Abort returns 0 if the 
+               abortion was successful.  If non-zero, the code passed to it 
+               will be used as the return code, otherwise 
+               DID_ABORT  should be returned.
+
+               Note that the scsi driver should "clean up" after itself, 
+               resetting the bus, etc.  if necessary. 
+       */
+
+       int (* abort)(int);
+
+       /*
+               The reset function will reset the SCSI bus.  Any executing 
+               commands should fail with a DID_RESET in the host byte.
+       */ 
+
+       int (* reset)(void);
+       
+       /*
+               This determines if we will use a non-interrupt driven
+               or an interrupt driven scheme,  It is set to the maximum number
+               of simulataneous commands a given host adapter will accept.
+       */
+
+       int can_queue;
+
+       /*
+               In many instances, especially where disconnect / reconnect are 
+               supported, our host also has an ID on the SCSI bus.  If this is 
+               the case, then it must be reserved.  Please set this_id to -1 if                your settup is in single initiator mode, and the host lacks an 
+               ID.
+       */
+       
+       int this_id;
+
+       /*
+               present contains a flag as to weather we are present -
+               so we don't have to call detect multiple times.
+       */
+
+       unsigned present:1;     
+       } Scsi_Host;
+
+/*
+       The scsi_hosts array is the array containing the data for all 
+       possible <supported> scsi hosts.   
+*/
+
+extern Scsi_Host scsi_hosts[];
+
+/*
+       This is our semaphore array, used by scsi.c, sd.c, st.c.
+       Other routines SHOULD NOT mess with it.  Your driver should NOT mess with it.
+       This is used to protect against contention by disk and tape drivers.
+*/
+
+extern volatile unsigned char host_busy[];
+extern volatile int host_timeout[];
+
+/*
+       This is the queue of currently pending commands for a given
+       SCSI host.
+*/
+
+extern volatile Scsi_Cmnd *host_queue[];
+
+/*
+       scsi_init initializes the scsi hosts.
+*/
+
+
+void scsi_init(void);
+
+#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#endif
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
new file mode 100644 (file)
index 0000000..22f3402
--- /dev/null
@@ -0,0 +1,1016 @@
+/*
+ *     scsi.c Copyright (C) 1992 Drew Eckhardt 
+ *     generic mid-level SCSI driver by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+#ifdef CONFIG_BLK_DEV_SD
+#include "sd.h"
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+#include "st.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+#define INTERNAL_ERROR (printk ("Internal error in file %s, line %s.\n", __FILE__, __LINE__), panic(""))
+
+static void scsi_done (int host, int result);
+static void update_timeout (void);
+
+static int time_start;
+static int time_elapsed;
+
+/*
+       global variables : 
+       NR_SCSI_DEVICES is the number of SCSI devices we have detected, 
+       scsi_devices an array of these specifing the address for each 
+       (host, id, LUN)
+*/
+       
+int NR_SCSI_DEVICES=0;
+Scsi_Device scsi_devices[MAX_SCSI_DEVICE];
+
+#define SENSE_LENGTH 255
+/*
+       As the scsi do command functions are inteligent, and may need to 
+       redo a command, we need to keep track of the last command 
+       executed on each one.
+*/
+
+#define WAS_RESET      0x01
+#define WAS_TIMEDOUT   0x02
+#define WAS_SENSE      0x04
+#define IS_RESETTING   0x08
+
+static Scsi_Cmnd last_cmnd[MAX_SCSI_HOSTS];
+static int last_reset[MAX_SCSI_HOSTS];
+
+/*
+       This is the number  of clock ticks we should wait before we time out 
+       and abort the command.  This is for  where the scsi.c module generates 
+       the command, not where it originates from a higher level, in which
+       case the timeout is specified there.
+       
+
+       ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+       respectively.
+*/
+#ifdef DEBUG
+       #define SCSI_TIMEOUT 500
+#else
+       #define SCSI_TIMEOUT 100
+#endif
+#ifdef DEBUG
+       #define SENSE_TIMEOUT SCSI_TIMEOUT
+       #define ABORT_TIMEOUT SCSI_TIMEOUT
+       #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+
+       #define SENSE_TIMEOUT 50
+       #define RESET_TIMEOUT 50
+       #define ABORT_TIMEOUT 50
+       #define MIN_RESET_DELAY 25
+
+#endif
+/*
+       As the actual SCSI command runs in the background, we must set up a 
+       flag that tells scan_scsis() when the result it has is valid.  
+       scan_scsis can set the_result to -1, and watch for it to become the 
+       actual return code for that call.  the scan_scsis_done function() is 
+       our user specified completion function that is passed on to the  
+       scsi_do_cmd() function.
+*/
+
+static int the_result;
+static unsigned char sense_buffer[SENSE_LENGTH];
+static void scan_scsis_done (int host, int result)
+       {
+       
+#ifdef DEBUG
+       printk ("scan_scsis_done(%d, %06x\n\r", host, result);
+#endif 
+       the_result = result;
+       }
+/*
+       Detecting SCSI devices :        
+       We scan all present host adapter's busses,  from ID 0 to ID 6.  
+       We use the INQUIRY command, determine device type, and pass the ID / 
+       lun address of all sequential devices to the tape driver, all random 
+       devices to the disk driver.
+*/
+
+static void scan_scsis (void)
+       {
+        int host_nr , dev, lun, type, maxed;
+       static unsigned char scsi_cmd [12];
+       static unsigned char scsi_result [256];
+
+        for (host_nr = 0; host_nr < MAX_SCSI_HOSTS; ++host_nr)
+                if (scsi_hosts[host_nr].present)
+                       {
+                       for (dev = 0; dev < 7; ++dev)
+                               if (scsi_hosts[host_nr].this_id != dev)
+                                #ifdef MULTI_LUN
+                               for (lun = 0; lun < 8; ++lun)
+                                       {
+                               #else
+                                       {
+                                       lun = 0;
+                               #endif
+                                       /* Build an INQUIRY command block.  */
+
+                                       scsi_cmd[0] = INQUIRY;
+                                       scsi_cmd[1] = (lun << 5) & 0xe0;
+                                       scsi_cmd[2] = 0;
+                                       scsi_cmd[3] = 0;
+                                       scsi_cmd[4] = 255;
+                                       scsi_cmd[5] = 0;
+                                       the_result = -1;        
+#ifdef DEBUG
+       memset ((void *) scsi_result , 0, 255);
+#endif 
+                                       scsi_do_cmd (host_nr, dev, (void *)  scsi_cmd, (void *)                                                             
+                                                scsi_result, 256,  scan_scsis_done, 
+                                                SCSI_TIMEOUT, sense_buffer, 3);
+                                       
+                                       /* Wait for valid result */
+
+                                       while (the_result < 0);
+       
+
+                                        if (!the_result)
+                                               {
+                                                scsi_devices[NR_SCSI_DEVICES].
+                                                       host_no = host_nr;
+                                                scsi_devices[NR_SCSI_DEVICES].
+                                                       id = dev;
+                                                scsi_devices[NR_SCSI_DEVICES].
+                                                       lun = lun;
+                                                scsi_devices[NR_SCSI_DEVICES].
+                                                       removable = (0x80 & 
+                                                       scsi_result[1]) >> 7;
+
+
+
+/* 
+       Currently, all sequential devices are assumed to be tapes,
+       all random devices disk, with the appropriate read only 
+       flags set for ROM / WORM treated as RO.
+*/ 
+
+                                                switch (type = scsi_result[0])
+                                                       {
+                                                        case TYPE_TAPE:
+                                                        case TYPE_DISK:
+                                                               scsi_devices[NR_SCSI_DEVICES].writeable = 1;
+                                                                break;
+                                                        case TYPE_WORM:
+                                                        case TYPE_ROM:
+                                                               scsi_devices[NR_SCSI_DEVICES].writeable = 0;
+                                                                break;
+                                                        default:
+                                                                type = -1;
+                                                        }
+
+                                                scsi_devices[NR_SCSI_DEVICES].random = (type == TYPE_TAPE) ? 0 : 1;
+
+                                                maxed = 0;
+                                                switch (type)
+                                                       {
+                                                        case -1:
+                                                               break;
+                                                        case TYPE_TAPE:
+                                                               printk("Detected scsi tape at host %d, ID  %d, lun %d \n", host_nr, dev, lun);
+#ifdef CONFIG_BLK_DEV_ST
+                                                                if (!(maxed = (NR_ST == MAX_ST)))
+                                                                                scsi_tapes[NR_ST].device = &scsi_devices[NR_SCSI_DEVICES];
+#endif
+                                                        default:
+                                                               printk("Detected scsi disk at host %d, ID  %d, lun %d \n", host_nr, dev, lun);
+#ifdef CONFIG_BLK_DEV_SD
+                                                                       if (!(maxed = (NR_SD >= MAX_SD)))
+                                                                               rscsi_disks[NR_SD].device = &scsi_devices[NR_SCSI_DEVICES];
+#endif
+                                                                }
+
+                                                        if (maxed)
+                                                                {
+                                                                printk ("Already have detected maximum number of SCSI %ss Unable to \n"
+                                                                        "add drive at SCSI host %s, ID %d, LUN %d\n\r", (type == TYPE_TAPE) ?
+                                                                        "tape" : "disk", scsi_hosts[host_nr].name,
+                                                                        dev, lun);
+                                                                type = -1;
+                                                                break;
+                                                                }
+
+                                                        else if (type != -1)
+                                                                {
+                                                                if (type == TYPE_TAPE)
+#ifdef CONFIG_BLK_DEV_ST
+                                                                       ++NR_ST;
+#else
+;
+#endif
+
+                                                                else
+#ifdef CONFIG_BLK_DEV_SD
+                                                                        ++NR_SD;
+#else
+;
+#endif
+                                                                }
+                                                       ++NR_SCSI_DEVICES;
+                                                        }       /* if result == DID_OK ends */
+                                        }       /* for lun ends */
+                        }              /* if present */  
+
+       printk("Detected "
+#ifdef CONFIG_BLK_DEV_SD
+"%d disk%s "
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+"%d tape%s "
+#endif
+
+"total.\n",  
+
+#ifdef CONFIG_BLK_DEV_SD
+NR_SD, (NR_SD != 1) ? "s" : ""
+#ifdef CONFIG_BLK_DEV_ST 
+,
+#endif
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+NR_ST, (NR_ST != 1) ? "s" : ""
+#endif
+);
+        }       /* scan_scsis  ends */
+
+/*
+       We handle the timeout differently if it happens when a reset, 
+       abort, etc are in process. 
+*/
+
+static unsigned char internal_timeout[MAX_SCSI_HOSTS];
+
+/* Flag bits for the internal_timeout array */
+
+#define NORMAL_TIMEOUT 0
+#define IN_ABORT 1
+#define IN_RESET 2
+/*
+       This is our time out function, called when the timer expires for a 
+       given host adapter.  It will attempt to abort the currently executing 
+       command, that failing perform a kernel panic.
+*/ 
+
+static void scsi_times_out (int host)
+       {
+       
+       switch (internal_timeout[host] & (IN_ABORT | IN_RESET))
+               {
+               case NORMAL_TIMEOUT:
+                       printk("SCSI host %d timed out - aborting command \r\n",
+                               host);
+                       
+                       if (!scsi_abort (host, DID_TIME_OUT))
+                               return;                         
+               case IN_ABORT:
+                       printk("SCSI host %d abort() timed out - reseting \r\n",
+                               host);
+                       if (!scsi_reset (host)) 
+                               return;
+               case IN_RESET:
+               case (IN_ABORT | IN_RESET):
+                       printk("Unable to reset scsi host %d\r\n",host);
+                       panic("");
+               default:
+                       INTERNAL_ERROR;
+               }
+                                       
+       }
+
+/*
+       This is inline because we have stack problemes if we recurse to deeply.
+*/
+                        
+static void internal_cmnd (int host,  unsigned char target, const void *cmnd , 
+                 void *buffer, unsigned bufflen, void (*done)(int,int))
+       {
+       int temp;
+
+#ifdef DEBUG_DELAY     
+       int clock;
+#endif
+
+       if ((host < 0) ||  (host > MAX_SCSI_HOSTS))
+               panic ("Host number in internal_cmnd() is out of range.\n");
+
+
+/*
+       We will wait MIN_RESET_DELAY clock ticks after the last reset so 
+       we can avoid the drive not being ready.
+*/ 
+temp = last_reset[host];
+while (jiffies < temp);
+
+host_timeout[host] = last_cmnd[host].timeout_per_command;
+update_timeout();
+
+/*
+       We will use a queued command if possible, otherwise we will emulate the
+       queing and calling of completion function ourselves. 
+*/
+#ifdef DEBUG
+       printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer =  %08x, \n"
+               "bufflen = %d, done = %08x)\n", host, target, cmnd, buffer, bufflen, done);
+#endif
+
+       
+        if (scsi_hosts[host].can_queue)
+               {
+#ifdef DEBUG
+       printk("queuecommand : routine at %08x\n", 
+               scsi_hosts[host].queuecommand);
+#endif
+                scsi_hosts[host].queuecommand (target, cmnd, buffer, bufflen, 
+                                              done);
+               }
+       else
+               {
+
+#ifdef DEBUG
+       printk("command() :  routine at %08x\n", scsi_hosts[host].command);
+#endif
+               temp=scsi_hosts[host].command (target, cmnd, buffer, bufflen);
+
+#ifdef DEBUG_DELAY
+       clock = jiffies + 400;
+       while (jiffies < clock);
+       printk("done(host = %d, result = %04x) : routine at %08x\n", host, temp, done);
+#endif
+               done(host, temp);
+               }       
+#ifdef DEBUG
+       printk("leaving internal_cmnd()\n");
+#endif
+       }       
+
+static void scsi_request_sense (int host, unsigned char target, 
+                                       unsigned char lun)
+       {
+       cli();
+       host_timeout[host] = SENSE_TIMEOUT;
+       update_timeout();
+       last_cmnd[host].flags |= WAS_SENSE;
+       sti();
+       
+       last_cmnd[host].sense_cmnd[1] = lun << 5;       
+
+       internal_cmnd (host, target, (void *) last_cmnd[host].sense_cmnd, 
+                      (void *) last_cmnd[host].sense_buffer, SENSE_LENGTH,
+                      scsi_done);
+       }
+
+
+
+
+
+/*
+       scsi_do_cmd sends all the commands out to the low-level driver.  It 
+       handles the specifics required for each low level driver - ie queued 
+       or non queud.  It also prevents conflicts when different high level 
+       drivers go for the same host at the same time.
+*/
+
+void scsi_do_cmd (int host,  unsigned char target, const void *cmnd , 
+                 void *buffer, unsigned bufflen, void (*done)(int,int),
+                 int timeout, unsigned  char *sense_buffer, int retries 
+                  )
+        {
+       int ok = 0;
+
+#ifdef DEBUG
+       int i;  
+       printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, "
+               "bufflen = %d, done = %08x, timeout = %d, retries = %d)\n"
+               "command : " , host, target, buffer, bufflen, done, timeout, retries);
+       for (i = 0; i < 10; ++i)
+               printk ("%02x  ", ((unsigned char *) cmnd)[i]); 
+       printk("\n");
+#endif
+       
+       if ((host  >= MAX_SCSI_HOSTS) || !scsi_hosts[host].present)
+               {
+               printk ("Invalid or not present host number. %d\n", host);
+               panic("");
+               }
+
+       
+/*
+       We must prevent reentrancy to the lowlevel host driver.  This prevents 
+       it - we enter a loop until the host we want to talk to is not busy.   
+       Race conditions are prevented, as interrupts are disabled inbetween the
+       time we check for the host being not busy, and the time we mark it busy
+       ourselves.
+*/
+
+       do      {
+               cli();
+               if (host_busy[host])
+                       {
+                       sti();
+#ifdef DEBUG
+                       printk("Host %d is busy.\n"     );
+#endif
+                       while (host_busy[host]);
+#ifdef DEBUG
+                       printk("Host %d is no longer busy.");
+#endif
+                       }
+               else
+                       {
+                       host_busy[host] = 1;
+                       ok = 1;
+                       sti();
+                       }
+               } while (!ok);
+               
+
+/*
+       Our own function scsi_done (which marks the host as not busy, disables 
+       the timeout counter, etc) will be called by us or by the 
+       scsi_hosts[host].queuecommand() function needs to also call
+       the completion function for the high level driver.
+
+*/
+
+       memcpy ((void *) last_cmnd[host].cmnd , (void *) cmnd, 10);
+       last_cmnd[host].host = host;
+       last_cmnd[host].target = target;
+       last_cmnd[host].lun = (last_cmnd[host].cmnd[1] >> 5);
+       last_cmnd[host].bufflen = bufflen;
+       last_cmnd[host].buffer = buffer;
+       last_cmnd[host].sense_buffer = sense_buffer;
+       last_cmnd[host].flags=0;
+       last_cmnd[host].retries=0;
+       last_cmnd[host].allowed=retries;
+       last_cmnd[host].done = done;
+       last_cmnd[host].timeout_per_command = timeout;
+                               
+       /* Start the timer ticking.  */
+
+       internal_timeout[host] = 0;
+       internal_cmnd (host,  target, cmnd , buffer, bufflen, scsi_done);
+
+#ifdef DEBUG
+       printk ("Leaving scsi_do_cmd()\n");
+#endif
+        }
+
+
+/*
+       The scsi_done() function disables the timeout timer for the scsi host, 
+       marks the host as not busy, and calls the user specified completion 
+       function for that host's current command.
+*/
+
+static void reset (int host)
+       {
+       #ifdef DEBUG
+               printk("reset(%d)\n", host);
+       #endif
+
+       last_cmnd[host].flags |= (WAS_RESET | IS_RESETTING);
+       scsi_reset(host);
+
+       #ifdef DEBUG
+               printk("performing request sense\n");
+       #endif
+
+       scsi_request_sense (host, last_cmnd[host].target, last_cmnd[host].lun);
+       }
+       
+       
+
+static int check_sense (int host)
+       {
+       if (((sense_buffer[0] & 0x70) >> 4) == 7)
+               switch (sense_buffer[2] & 0xf)
+               {
+               case NO_SENSE:
+               case RECOVERED_ERROR:
+                       return 0;
+
+               case ABORTED_COMMAND:
+               case NOT_READY:
+               case UNIT_ATTENTION:    
+                       return SUGGEST_RETRY;   
+       
+               /* these three are not supported */     
+               case COPY_ABORTED:
+               case VOLUME_OVERFLOW:
+               case MISCOMPARE:
+       
+               case MEDIUM_ERROR:
+                       return SUGGEST_REMAP;
+               case BLANK_CHECK:
+               case DATA_PROTECT:
+               case HARDWARE_ERROR:
+               case ILLEGAL_REQUEST:
+               default:
+                       return SUGGEST_ABORT;
+               }
+       else
+               return SUGGEST_RETRY;   
+       }       
+
+static void scsi_done (int host, int result)
+       {
+       int status=0;
+       int exit=0;
+       int checked;
+       int oldto;
+       oldto = host_timeout[host];
+       host_timeout[host] = 0;
+       update_timeout();
+
+#define FINISHED 0
+#define MAYREDO  1
+#define REDO    3
+
+#ifdef DEBUG
+       printk("In scsi_done(host = %d, result = %06x)\n", host, result);
+#endif
+       if (host > MAX_SCSI_HOSTS || host  < 0) 
+               {
+               host_timeout[host] = 0;
+               update_timeout();
+               panic("scsi_done() called with invalid host number.\n");
+               }
+
+       switch (host_byte(result))      
+       {
+       case DID_OK:
+               if (last_cmnd[host].flags & IS_RESETTING)
+                       {
+                       last_cmnd[host].flags &= ~IS_RESETTING;
+                       status = REDO;
+                       break;
+                       }
+
+               if (status_byte(result) && (last_cmnd[host].flags & 
+                   WAS_SENSE)) 
+                       {
+                       last_cmnd[host].flags &= ~WAS_SENSE;
+                       cli();
+                       internal_timeout[host] &= ~SENSE_TIMEOUT;
+                       sti();
+
+                       if (!(last_cmnd[host].flags & WAS_RESET)) 
+                               reset(host);
+                       else
+                               {
+                               exit = (DRIVER_HARD | SUGGEST_ABORT);
+                               status = FINISHED;
+                               }
+                       }
+               else switch(msg_byte(result))
+                       {
+                       case COMMAND_COMPLETE:
+                       switch (status_byte(result))
+                       {
+                       case GOOD:
+                               if (last_cmnd[host].flags & WAS_SENSE)
+                                       {
+#ifdef DEBUG
+       printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
+#endif
+
+                                       last_cmnd[host].flags &= ~WAS_SENSE;
+                                       cli();
+                                       internal_timeout[host] &= ~SENSE_TIMEOUT;
+                                       sti();
+       
+                                       switch (checked = check_sense(host))
+                                       {
+                                       case 0: 
+#ifdef DEBUG
+       printk("NO SENSE.  status = REDO\n");
+#endif
+
+                                               host_timeout[host] = oldto;
+                                               update_timeout();
+                                               status = REDO;
+                                               break;
+                                       case SUGGEST_REMAP:                     
+                                       case SUGGEST_RETRY: 
+#ifdef DEBUG
+       printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
+#endif
+
+                                               status = MAYREDO;
+                                               exit = SUGGEST_RETRY;
+                                               break;
+                                       case SUGGEST_ABORT:
+#ifdef DEBUG
+       printk("SENSE SUGGEST ABORT - status = FINISHED");
+#endif
+
+                                               status = FINISHED;
+                                               exit =  DRIVER_SENSE;
+                                               break;
+                                       default:
+                                               printk ("Internal error %s %s \n", __FILE__, 
+                                                       __LINE__);
+                                       }                          
+                                       }       
+                               else
+                                       {
+#ifdef DEBUG
+       printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
+#endif
+
+                                       exit =  DRIVER_OK;
+                                       status = FINISHED;
+                                       }
+                               break;  
+
+                       case CHECK_CONDITION:
+
+#ifdef DEBUG
+       printk("CHECK CONDITION message returned, performing request sense.\n");
+#endif
+
+                               scsi_request_sense (host, last_cmnd[host].target, last_cmnd[host].lun);
+                               break;          
+                       
+                       case CONDITION_GOOD:
+                       case INTERMEDIATE_GOOD:
+                       case INTERMEDIATE_C_GOOD:
+#ifdef DEBUG
+       printk("CONDITION GOOD, INTERMEDIATE GOOD, or INTERMEDIATE CONDITION GOOD recieved and ignored. \n");
+#endif
+                               break;
+                               
+                       case BUSY:
+#ifdef DEBUG
+       printk("BUSY message returned, performing REDO");
+#endif
+                               host_timeout[host] = oldto;
+                               update_timeout();
+                               status = REDO;
+                               break;
+
+                       case RESERVATION_CONFLICT:
+                               reset(host);
+                               exit = DRIVER_SOFT | SUGGEST_ABORT;
+                               status = MAYREDO;
+                               break;
+                       default:
+                               printk ("Internal error %s %s \n"
+                                       "status byte = %d \n", __FILE__, 
+                                       __LINE__, status_byte(result));
+                               
+                       }
+                       break;
+                       default:
+                               panic ("unsupported message byte recieved.");
+                       }
+                       break;
+       case DID_TIME_OUT:      
+#ifdef DEBUG
+       printk("Host returned DID_TIME_OUT - ");
+#endif
+
+               if (last_cmnd[host].flags & WAS_TIMEDOUT)       
+                       {
+#ifdef DEBUG
+       printk("Aborting\n");
+#endif 
+                       exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+                       }               
+               else 
+                       {
+#ifdef DEBUG
+                       printk ("Retrying.\n");
+#endif
+                       last_cmnd[host].flags  |= WAS_TIMEDOUT;
+                       status = REDO;
+                       }
+               break;
+       case DID_BUS_BUSY:
+       case DID_PARITY:
+               status = REDO;
+               break;
+       case DID_NO_CONNECT:
+#ifdef DEBUG
+               printk("Couldn't connect.\n");
+#endif
+               exit  = (DRIVER_HARD | SUGGEST_ABORT);
+               break;
+       case DID_ERROR: 
+               status = MAYREDO;
+               exit = (DRIVER_HARD | SUGGEST_ABORT);
+               break;
+       case DID_BAD_TARGET:
+       case DID_ABORT:
+               exit = (DRIVER_INVALID | SUGGEST_ABORT);
+               break;  
+       default :               
+               exit = (DRIVER_ERROR | SUGGEST_DIE);
+       }
+
+       switch (status) 
+               {
+               case FINISHED:
+                       break;
+               case MAYREDO:
+
+#ifdef DEBUG
+       printk("In MAYREDO, allowing %d retries, have %d\n\r",
+              last_cmnd[host].allowed, last_cmnd[host].retries);
+#endif
+
+                       if ((++last_cmnd[host].retries) < last_cmnd[host].allowed)
+                       {
+                       if ((last_cmnd[host].retries >= (last_cmnd[host].allowed >> 1)) 
+                           && !(last_cmnd[host].flags & WAS_RESET))
+                               reset(host);
+                               break;
+                       
+                       }
+                       else
+                               {
+                               status = FINISHED;
+                               break;
+                               }
+                       /* fall through to REDO */
+
+               case REDO:
+                       if (last_cmnd[host].flags & WAS_SENSE)                  
+                               scsi_request_sense (host, last_cmnd[host].target,       
+                              last_cmnd[host].lun);    
+                       else    
+                               internal_cmnd (host, last_cmnd[host].target,    
+                               last_cmnd[host].cmnd,  
+                               last_cmnd[host].buffer,   
+                               last_cmnd[host].bufflen, scsi_done);                    
+                       break;  
+               default: 
+                       INTERNAL_ERROR;
+               }
+
+       if (status == FINISHED) 
+               {
+               #ifdef DEBUG
+                       printk("Calling done function - at address %08x\n", last_cmnd[host].done);
+               #endif
+               last_cmnd[host].done (host, (result | ((exit & 0xff) << 24)));
+               host_busy[host] = 0;
+               }
+
+
+#undef FINISHED
+#undef REDO
+#undef MAYREDO
+               
+       }
+
+/*
+       The scsi_abort function interfaces with the abort() function of the host
+       we are aborting, and causes the current command to not complete.  The 
+       caller should deal with any error messages or status returned on the 
+       next call.
+       
+       This will not be called rentrantly for a given host.
+*/
+       
+/*
+       Since we're nice guys and specified that abort() and reset()
+       can be non-reentrant.  The internal_timeout flags are used for
+       this.
+*/
+
+
+int scsi_abort (int host, int why)
+       {
+       int temp, oldto;
+       
+       while(1)        
+               {
+               cli();
+               if (internal_timeout[host] & IN_ABORT) 
+                       {
+                       sti();
+                       while (internal_timeout[host] & IN_ABORT);
+                       }
+               else
+                       {       
+                       internal_timeout[host] |= IN_ABORT;
+                       host_timeout[host] = ABORT_TIMEOUT;     
+                       update_timeout();
+
+                       oldto = host_timeout[host];
+                       
+                       sti();
+                       if (!host_busy[host] || !scsi_hosts[host].abort(why))
+                               temp =  0;
+                       else
+                               temp = 1;
+                       
+                       cli();
+                       internal_timeout[host] &= ~IN_ABORT;
+                       host_timeout[host]=oldto;
+                       update_timeout();
+                       sti();
+                       return temp;
+                       }
+               }       
+       }
+
+int scsi_reset (int host)
+       {
+       int temp, oldto;
+       
+       while (1) {
+               cli();  
+               if (internal_timeout[host] & IN_RESET)
+                       {
+                       sti();
+                       while (internal_timeout[host] & IN_RESET);
+                       }
+               else
+                       {
+                       oldto = host_timeout[host];     
+                       host_timeout[host] = RESET_TIMEOUT;     
+                       update_timeout();       
+                       internal_timeout[host] |= IN_RESET;
+                                       
+                       if (host_busy[host])
+                               {       
+                               sti();
+                               if (!(last_cmnd[host].flags & IS_RESETTING) && !(internal_timeout[host] & IN_ABORT))
+                                       scsi_abort(host, DID_RESET);
+
+                               temp = scsi_hosts[host].reset();                        
+                               }                               
+                       else
+                               {
+                               host_busy[host]=1;
+       
+                               sti();
+                               temp = scsi_hosts[host].reset();
+                               last_reset[host] = jiffies;
+                               host_busy[host]=0;
+                               }
+       
+                       cli();
+                       host_timeout[host] = oldto;             
+                       update_timeout();
+                       internal_timeout[host] &= ~IN_RESET;
+                       sti();
+                       return temp;    
+                       }
+               }
+       }
+                        
+
+static void scsi_main_timeout(void)
+       {
+       /*
+               We must not enter update_timeout with a timeout condition still pending.
+       */
+
+       int i, timed_out;
+
+       do      {       
+               cli();
+
+       /*
+               Find all timers such that they have 0 or negative (shouldn't happen)
+               time remaining on them.
+       */
+                       
+               for (i = timed_out = 0; i < MAX_SCSI_HOSTS; ++i)
+                       if (host_timeout[i] != 0 && host_timeout[i] <= time_elapsed)
+                               {
+                               sti();
+                               host_timeout[i] = 0;
+                               scsi_times_out(i);
+                               ++timed_out; 
+                               }
+
+               update_timeout();                               
+               } while (timed_out);    
+       sti();
+       }
+
+/*
+       These are used to keep track of things. 
+*/
+
+static int time_start, time_elapsed;
+
+/*
+       The strategy is to cause the timer code to call scsi_times_out()
+       when the soonest timeout is pending.  
+*/
+       
+static void update_timeout(void)
+       {
+       int i, least, used;
+
+       cli();
+
+/* 
+       Figure out how much time has passed since the last time the timeouts 
+       were updated 
+*/
+       used = (time_start) ? (jiffies - time_start) : 0;
+
+/*
+       Find out what is due to timeout soonest, and adjust all timeouts for
+       the amount of time that has passed since the last time we called 
+       update_timeout. 
+*/
+       
+       for (i = 0, least = 0xffffffff; i < MAX_SCSI_HOSTS; ++i)        
+               if (host_timeout[i] > 0 && (host_timeout[i] -= used) < least)
+                       least = host_timeout[i]; 
+
+/*
+       If something is due to timeout again, then we will set the next timeout 
+       interrupt to occur.  Otherwise, timeouts are disabled.
+*/
+       
+       if (least != 0xffffffff)
+               {
+               time_start = jiffies;   
+               timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;     
+               timer_active |= 1 << SCSI_TIMER;
+               }
+       else
+               {
+               timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
+               timer_active &= ~(1 << SCSI_TIMER);
+               }       
+       sti();
+       }               
+/*
+       scsi_dev_init() is our initialization routine, which inturn calls host 
+       initialization, bus scanning, and sd/st initialization routines.  It 
+       should be called from main().
+*/
+
+static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};                
+void scsi_dev_init (void)
+       {
+       int i;
+#ifdef FOO_ON_YOU
+       return;
+#endif 
+       timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+       timer_table[SCSI_TIMER].expires = 0;
+
+       scsi_init();            /* initialize all hosts */
+       /*
+               Set up sense command in each host structure.
+       */
+
+       for (i = 0; i < MAX_SCSI_HOSTS; ++i)
+               {
+               memcpy ((void *) last_cmnd[i].sense_cmnd, (void *) generic_sense,
+                       6);
+               last_reset[i] = 0;
+               }
+                               
+        scan_scsis();           /* scan for scsi devices */
+
+#ifdef CONFIG_BLK_DEV_SD
+       sd_init();              /* init scsi disks */
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+        st_init();              /* init scsi tapes */
+#endif
+       }
+#endif
diff --git a/kernel/blk_drv/scsi/scsi.h b/kernel/blk_drv/scsi/scsi.h
new file mode 100644 (file)
index 0000000..1a949ab
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ *     scsi.h Copyright (C) 1992 Drew Eckhardt 
+ *     generic SCSI package header file by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+#ifndef _SCSI_H
+       #define _SCSI_H
+/*
+       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+
+       For documentation on the OPCODES, MESSAGES, and SENSE values,
+       please consult the SCSI standard.
+
+*/
+
+/*
+       SCSI opcodes
+*/
+
+#define TEST_UNIT_READY        0x00
+#define REZERO_UNIT            0x01
+#define REQUEST_SENSE          0x03
+#define FORMAT_UNIT            0x04
+#define REASSIGN_BLOCKS                0x07
+#define READ_6                 0x08
+#define WRITE_6                        0x0a
+#define SEEK_6                 0x0b
+#define INQUIRY                        0x12
+#define MODE_SELECT            0x15
+#define RESERVE                        0x16
+#define RELEASE                        0x17
+#define COPY                   0x18
+#define MODE_SENSE             0x1a
+#define START_STOP             0x1b
+#define RECIEVE_DAIGNOSTIC     0x1c
+#define SEND_DIAGNOSTIC                0x1d
+#define ALLOW_MEDIUM_REMOVAL   0x1e
+
+#define READ_CAPACITY          0x25
+#define READ_10                        0x28
+#define WRITE_10               0x2a
+#define SEEK_10                        0x2b
+#define WRITE_VERIFY           0x2e
+#define VERIFY                 0x2f
+#define SEARCH_HIGH            0x30
+#define SEARCH_EQUAL           0x31
+#define SEARCH_LOW             0x32
+#define SET_LIMITS             0x33
+#define COMPARE                        0x39
+#define COPY_VERIFY            0x3a
+
+#define COMMAND_SIZE(opcode) ((opcode) ? ((opcode) > 0x20 ? 10 : 6) : 0)
+
+/*
+       MESSAGE CODES
+*/
+
+#define COMMAND_COMPLETE       0x00
+#define EXTENDED_MESSAGE       0x01
+#define SAVE_POINTERS          0x02
+#define RESTORE_POINTERS       0x03
+#define DISCONNECT             0x04
+#define INITIATOR_ERROR                0x05
+#define ABORT                  0x06
+#define MESSAGE_REJECT         0x07
+#define NOP                    0x08
+#define MSG_PARITY_ERROR       0x09
+#define LINKED_CMD_COMPLETE    0x0a
+#define LINKED_FLG_CMD_COMPLETE        0x0b
+#define BUS_DEVICE_RESET       0x0c
+#define IDENTIFY               0x80
+/*
+       Status codes
+*/
+
+#define GOOD                   0x00
+#define CHECK_CONDITION                0x01
+#define CONDITION_GOOD         0x02
+#define BUSY                   0x04
+#define INTERMEDIATE_GOOD      0x08
+#define INTERMEDIATE_C_GOOD    0x0a
+#define RESERVATION_CONFLICT   0x0c
+
+#define STATUS_MASK            0x1e
+       
+/*
+       the return of the status word will be in the following format :
+       The low byte is the status returned by the SCSI command, 
+       with vendor specific bits masked.
+
+       The next byte is the message which followed the SCSI status.
+       This allows a stos to be used, since the Intel is a little
+       endian machine.
+
+       The final byte is a host return code, which is one of the following.
+
+       IE 
+       lsb             msb
+       status  msg     host code       
+
+        Our errors returned by OUR driver, NOT SCSI message.  Orr'd with
+        SCSI message passed back to driver <IF any>.
+*/
+
+/*     NO error                                                        */
+#define DID_OK                         0x00
+/*     Couldn't connect before timeout period                          */
+#define DID_NO_CONNECT         0x01
+/*     BUS stayed busy through time out period                         */
+#define DID_BUS_BUSY           0x02
+/*     TIMED OUT for other reason                                      */
+#define DID_TIME_OUT           0x03
+/*     BAD target.                                                     */
+#define DID_BAD_TARGET         0x04
+/*     Told to abort for some other reason                             */
+#define        DID_ABORT               0x05
+/*
+       Parity error
+*/
+#define DID_PARITY             0x06
+/*
+       Internal error
+*/
+#define DID_ERROR              0x07    
+/*
+       Reset by somebody.
+*/
+#define DID_RESET              0x08
+
+/*
+       Driver status
+*/ 
+#define DRIVER_OK              0x00
+
+/*
+       These indicate the error that occured, and what is available.
+*/
+
+#define DRIVER_BUSY            0x01
+#define DRIVER_SOFT            0x02
+#define DRIVER_MEDIA           0x03
+#define DRIVER_ERROR           0x04    
+
+#define DRIVER_INVALID         0x05
+#define DRIVER_TIMEOUT         0x06
+#define DRIVER_HARD            0x07
+
+#define SUGGEST_RETRY          0x08
+#define SUGGEST_ABORT          0x09 
+#define SUGGEST_REMAP          0x0a
+#define SUGGEST_DIE            0x0b
+
+#define DRIVER_SENSE           0x10
+
+#define DRIVER_MASK 0x0f
+#define SUGGEST_MASK 0xf0
+
+/*
+
+       SENSE KEYS
+*/
+
+#define NO_SENSE               0x00
+#define RECOVERED_ERROR                0x01
+#define NOT_READY              0x02
+#define MEDIUM_ERROR           0x03
+#define        HARDWARE_ERROR          0x04
+#define ILLEGAL_REQUEST                0x05
+#define UNIT_ATTENTION         0x06
+#define DATA_PROTECT           0x07
+#define BLANK_CHECK            0x08
+#define COPY_ABORTED           0x0a
+#define ABORTED_COMMAND                0x0b
+#define        VOLUME_OVERFLOW         0x0d
+#define MISCOMPARE             0x0e
+
+
+/*
+       DEVICE TYPES
+
+*/
+
+#define TYPE_DISK      0x00
+#define TYPE_TAPE      0x01
+#define TYPE_WORM      0x04    /* Treated as ROM by our system */
+#define TYPE_ROM       0x05
+#define TYPE_NO_LUN    0x7f
+/*
+       Every SCSI command starts with a one byte OP-code.
+       The next byte's high three bits are the LUN of the
+       device.  Any multi-byte quantities are stored high byte
+       first, and may have a 5 bit MSB in the same byte
+       as the LUN.
+*/
+
+
+/*
+       The scsi_device struct contains what we know about each given scsi
+       device.
+*/
+
+typedef struct scsi_device {
+       unsigned char host_no, id, lun;
+       unsigned writeable:1;
+       unsigned removable:1; 
+       unsigned random:1;
+       } Scsi_Device;
+/*
+       Use these to separate status msg and our bytes
+*/
+
+#define status_byte(result) (((result) >> 1) & 0xf)
+#define msg_byte(result) (((result) >> 8) & 0xff)
+#define host_byte(result) (((result) >> 16) & 0xff)
+#define driver_byte(result) (((result) >> 24) & 0xff)
+#define sugestion(result) (driver_byte(result) & SUGGEST_MASK)
+
+#define sense_class(sense) (((sense) >> 4) & 0x7)
+#define sense_error(sense) ((sense) & 0xf)
+#define sense_valid(sense) ((sense) & 0x80);
+
+/*
+       These are the SCSI devices available on the system.
+*/
+
+#define MAX_SCSI_DEVICE 2
+extern int NR_SCSI_DEVICES;
+extern Scsi_Device scsi_devices[MAX_SCSI_DEVICE];
+/*
+       scsi_abort aborts the current command that is executing on host host.
+       The error code, if non zero is returned in the host byte, otherwise 
+       DID_ABORT is returned in the hostbyte.
+*/
+
+extern int scsi_abort (int host, int code);
+
+/*
+       Initializes all SCSI devices.  This scans all scsi busses.
+*/
+
+extern void scsi_dev_init (void);
+
+/*
+       You guesed it.  This sends a command to the selected SCSI host 
+*/
+
+
+
+extern void scsi_do_cmd (int host,  unsigned char target, const void *cmnd ,
+                  void *buffer, unsigned bufflen, void (*done)(int,int),
+                  int timeout, unsigned  char *sense_buffer, int retries);
+
+int scsi_reset (int host);
+#endif
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c
new file mode 100644 (file)
index 0000000..b373c3b
--- /dev/null
@@ -0,0 +1,153 @@
+#include <linux/config.h>
+#ifdef CONFIG_SCSI 
+
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "scsi_ioctl.h"
+
+#define MAX_RETRIES 5  
+#define MAX_TIMEOUT 200
+#define MAX_BUF 1024   
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+/*
+ * If we are told to probe a host, we will return 0 if  the host is not
+ * present, 1 if the host is present, and will return an identifying
+ * string at *arg, if arg is non null, filling to the length stored at
+ * (int *) arg
+ */
+
+static int ioctl_probe(int dev, void *buffer)
+{
+       int temp;
+       int len;
+       
+       if ((temp = scsi_hosts[dev].present) && buffer) {
+               len = get_fs_long ((int *) buffer);
+               memcpy_tofs (buffer, scsi_hosts[dev].info(), len);
+       }
+       return temp;
+}
+
+/*
+ * 
+ * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
+ * The MAX_TIMEOUT and MAX_RETRIES  variables are used.  
+ * 
+ * dev is the SCSI device number, *(int *) arg the length of the input
+ * data, *((int *)arg + 1) the output buffer.
+ * 
+ * *(char *) ((int *) arg)[1] the actual command.   
+ * 
+ * Note that no more than MAX_BUF bytes will be transfered.  Since
+ * SCSI block device size is 512 bytes, I figured 1K was good.
+ * 
+ * This size * does  * include  the initial lengths that were passed.
+ * 
+ * The SCSI command is read from  the memory location immediately after the
+ * length words, and the out data after the command.  The SCSI routines know the
+ * command size based on the length byte.  
+ * 
+ * The area is then filled in from the byte at offset 0. 
+ */
+
+static int the_result[MAX_SCSI_HOSTS];
+
+static void scsi_ioctl_done (int host, int result)
+{
+       the_result[host] = result;      
+}      
+       
+static int ioctl_command(Scsi_Device *dev, void *buffer)
+{
+       char buf[MAX_BUF];
+       char cmd[10];
+       char * cmd_in;
+       unsigned char opcode;
+       int inlen, outlen, cmdlen, temp, host;
+
+       if (!buffer)
+               return -EINVAL;
+       
+       inlen = get_fs_long((int *) buffer);
+       outlen = get_fs_long(((int *) buffer) + 1);
+
+       cmd_in = (char *) ( ((int *)buffer) + 2);
+       opcode = get_fs_byte(cmd_in); 
+
+       memcpy_fromfs ((void *) cmd,  cmd_in, cmdlen = COMMAND_SIZE (opcode));
+       memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen);
+       host = dev->host_no;
+
+#ifndef DEBUG_NO_CMD
+       do {
+               cli();
+               if (the_result[host]) {
+                       sti();
+                       while(the_result[host])
+                               /* nothing */;
+               } else {
+                       the_result[host]=-1;
+                       sti();
+                       break;
+               }
+       } while (1);
+       
+       scsi_do_cmd(host,  dev->id, cmd, buf, ((outlen > MAX_BUF) ? 
+                       MAX_BUF : outlen),  scsi_ioctl_done, MAX_TIMEOUT, 
+                       buf, MAX_RETRIES);
+
+       while (the_result[host] == -1)
+               /* nothing */;
+       temp = the_result[host];
+       the_result[host]=0;
+       memcpy_tofs (buffer, buf, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+       return temp;
+#else
+       {
+       int i;
+       printk("scsi_ioctl : device %d.  command = ", dev);
+       for (i = 0; i < 10; ++i)
+               printk("%02x ", cmd[i]);
+       printk("\r\nbuffer =");
+       for (i = 0; i < 20; ++i)
+               printk("%02x ", buf[i]);
+       printk("\r\n");
+       }
+       return 0;
+#endif
+}
+
+       
+/*
+       the scsi_ioctl() function differs from most ioctls in that it does
+       not take a major/minor number as the dev filed.  Rather, it takes
+       an index in scsi_devices[] 
+*/
+int scsi_ioctl (int dev, int cmd, void *arg)
+{
+       if ((cmd != 0 && dev > NR_SCSI_DEVICES) || dev < 0)
+               return -ENODEV;
+       if ((cmd == 0 && dev > MAX_SCSI_HOSTS))
+               return -ENODEV;
+       
+       switch (cmd) {
+               case SCSI_IOCTL_PROBE_HOST:
+                       return ioctl_probe(dev, arg);
+               case SCSI_IOCTL_SEND_COMMAND:
+                       return ioctl_command((Scsi_Device *) dev, arg);
+               default :                       
+                       return -EINVAL;
+       }
+}
+#endif
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.h b/kernel/blk_drv/scsi/scsi_ioctl.h
new file mode 100644 (file)
index 0000000..2acdb55
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _SCSI_IOCTL_H
+#define _SCSI_IOCTL_H 
+
+#ifndef _CONFIG_H
+#include <linux/config.h>
+#endif
+
+#define SCSI_IOCTL_PROBE_HOST 0
+#define SCSI_IOCTL_SEND_COMMAND 1
+
+#ifdef CONFIG_BLK_DEV_SD
+/*     Should start at 128     */
+#endif
+
+#ifdef CONFIG_BLK_DEV_SD
+/*     Should start at 256     */
+#endif
+
+#endif
+
+
diff --git a/kernel/blk_drv/scsi/sd.c b/kernel/blk_drv/scsi/sd.c
new file mode 100644 (file)
index 0000000..0ad47d3
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ *     sd.c Copyright (C) 1992 Drew Eckhardt 
+ *     Linux scsi disk driver by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_BLK_DEV_SD
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include "sd.h"
+
+#define MAJOR_NR 8
+
+#include "../blk.h"
+
+/*
+static const char RCSid[] = "$Header:";
+*/
+
+#define MAX_RETRIES 5
+
+/*
+ *     Time out in seconds
+ */
+
+#define SD_TIMEOUT 100
+
+Partition scsi_disks[MAX_SD << 4];
+int NR_SD=0;
+Scsi_Disk rscsi_disks[MAX_SD];
+static int sd_sizes[MAX_SD << 4];
+static int this_count;
+static int the_result;
+
+extern int sd_ioctl(struct inode *, struct file *, unsigned long, unsigned long);
+
+static void sd_release(struct inode * inode, struct file * file)
+{
+       sync_dev(inode->i_rdev);
+}
+
+static struct file_operations sd_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       sd_ioctl,               /* ioctl */
+       NULL,                   /* no special open code */
+       sd_release              /* release */
+};
+
+/*
+       The sense_buffer is where we put data for all mode sense commands 
+       performed.
+*/
+
+static unsigned char sense_buffer[255];
+
+/*
+       rw_intr is the interrupt routine for the device driver.  It will
+       be notified on the end of a SCSI read / write, and 
+       will take on of several actions based on success or failure.
+*/
+
+static void rw_intr (int host, int result)
+{
+       if (HOST != host)
+               panic ("sd.o : rw_intr() recieving interrupt for different host.");
+
+/*
+       First case : we assume that the command succeeded.  One of two things will
+       happen here.  Either we will be finished, or there will be more 
+       sectors that we were unable to read last time.
+*/
+
+       if (!result)
+               if (!(CURRENT->nr_sectors -= this_count)) {
+                       end_request(1);
+                       do_sd_request();
+               } else {                        
+                       CURRENT->nr_sectors -= this_count;
+/*
+       The CURRENT->nr_sectors field is always done in 512 byte sectors,
+       even if this really isn't the case.
+*/
+       
+                       (char *) CURRENT->buffer += this_count << 9;
+                       CURRENT->sector += this_count;
+                       CURRENT->errors = 0;
+                       do_sd_request();                         
+               }
+
+/*
+       Now, if we were good little boys and girls, Santa left us a request 
+       sense buffer.  We can extract information from this, so we 
+       can choose a block to remap, etc.
+*/
+
+       else if (driver_byte(result) & DRIVER_SENSE) {
+               if (sugestion(result) == SUGGEST_REMAP) {
+#ifdef REMAP
+/*
+       Not yet implemented.  A read will fail after being remapped,
+       a write will call the strategy routine again.
+*/
+
+                       if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
+                               {
+                               result = 0;
+                               }
+                       else
+                       
+#endif
+               }
+/*
+       If we had an ILLEGAL REQUEST returned, then we may have performed
+       an unsupported command.  The only thing this should be would be a  ten
+       byte read where only a six byte read was supportted.  Also, on a 
+       system where READ CAPACITY failed, we mave have read past the end of the
+       disk.
+*/
+       
+               else if (sense_buffer[7] == ILLEGAL_REQUEST) {
+                       if (rscsi_disks[DEVICE_NR(CURRENT->dev)].ten) {
+                               rscsi_disks[DEVICE_NR(CURRENT->dev)].ten = 0;
+                               do_sd_request();
+                               result = 0;
+                       } else {
+                       }
+               }
+       }
+       if (result) {
+               printk("SCSI disk error : host %d id %d lun %d return code = %03x\n", 
+                      rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no, 
+                      rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id,
+                      rscsi_disks[DEVICE_NR(CURRENT->dev)].device->lun);
+
+               if (driver_byte(result) & DRIVER_SENSE) 
+                       printk("\tSense class %x, sense error %x, extended sense %x\n",
+                               sense_class(sense_buffer[0]), 
+                               sense_error(sense_buffer[0]),
+                               sense_buffer[2] & 0xf);
+       
+               end_request(0);
+       }
+}
+
+/*
+       do_sd_request() is the request handler function for the sd driver.  
+       Its function in life is to take block device requests, and translate 
+       them to SCSI commands.
+*/
+       
+void do_sd_request (void)
+{
+       int dev, block;
+       unsigned char cmd[10];
+
+       INIT_REQUEST;
+       dev =  MINOR(CURRENT->dev);
+       block = CURRENT->sector;
+
+#ifdef DEBUG
+       printk("Doing sd request, dev = %d, block = %d\n", dev, block);
+#endif
+
+       if (dev >= (NR_SD << 4) || block + 2 > scsi_disks[dev].nr_sects || 
+               (dev % 16) > 5)
+               {
+               end_request(0); 
+               goto repeat;
+               }
+       
+       block += scsi_disks[dev].start_sect;
+       dev = DEVICE_NR(dev);
+
+#ifdef DEBUG
+       printk("Real dev = %d, block = %d\n", dev, block);
+#endif
+
+       if (!rscsi_disks[dev].use)
+               {
+               end_request(0);
+               goto repeat;
+               }
+       
+       this_count = CURRENT->nr_sectors;
+       switch (CURRENT->cmd)
+               {
+               case WRITE : 
+                       if (!rscsi_disks[dev].device->writeable)
+                               {
+                               end_request(0);
+                               goto repeat;
+                               } 
+                       cmd[0] = WRITE_6;
+                       break;
+               case READ : 
+                       cmd[0] = READ_6;
+                       break;
+               default : 
+                       printk ("Unknown sd command %d\r\n", CURRENT->cmd);
+                       panic("");
+               }
+       
+       cmd[1] = (LUN << 5) & 0xe0;
+
+       if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten) 
+               {
+               if (this_count > 0xffff)
+                       this_count = 0xffff;
+
+               cmd[0] += READ_10 - READ_6 ;
+               cmd[2] = (unsigned char) (block >> 24) & 0xff;
+               cmd[3] = (unsigned char) (block >> 16) & 0xff;
+               cmd[4] = (unsigned char) (block >> 8) & 0xff;
+               cmd[5] = (unsigned char) block & 0xff;
+               cmd[6] = cmd[9] = 0;
+               cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
+               cmd[8] = (unsigned char) this_count & 0xff;
+               }
+       else
+               {
+               if (this_count > 0xff)
+                       this_count = 0xff;
+       
+               cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+               cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+               cmd[3] = (unsigned char) block & 0xff;
+               cmd[4] = (unsigned char) this_count;
+               cmd[5] = 0;
+               }
+                       
+       scsi_do_cmd (HOST, ID, (void *) cmd, CURRENT->buffer, this_count << 9, 
+                    rw_intr, SD_TIMEOUT, sense_buffer, MAX_RETRIES);
+}
+
+static void sd_init_done (int host, int result)
+{
+       the_result = result;
+}
+
+/*
+       The sd_init() function looks at all SCSI drives present, determines 
+       their size, and reads partition table entries for them.
+*/
+
+void sd_init(void)
+{
+       int i,j,k;
+       unsigned char cmd[10];
+       unsigned char buffer[513];
+
+       Partition *p;
+
+       
+       for (i = 0; i < NR_SD; ++i)
+               {
+               cmd[0] = READ_CAPACITY;
+               rscsi_disks[i].use = 1;
+               cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+               memset ((void *) &cmd[2], 0, 8);
+               the_result = -1;
+#ifdef DEBUG
+       printk("Read capacity, disk %d at host = %d, id = %d\n", i, 
+               rscsi_disks[i].device->host_no, rscsi_disks[i].device->id);
+#endif
+               scsi_do_cmd (rscsi_disks[i].device->host_no , 
+                               rscsi_disks[i].device->id, 
+                               (void *) cmd, (void *) buffer,
+                                512, sd_init_done,  SD_TIMEOUT, sense_buffer,
+                                MAX_RETRIES);
+
+               while(the_result < 0);
+/*
+       The SCSI standard says "READ CAPACITY is necessary for self confuring software"
+       While not mandatory, support of READ CAPACITY is strongly encouraged.
+
+       We used to die if we couldn't successfully do a READ CAPACITY.  
+       But, now we go on about our way.  The side effects of this are
+
+       1.  We can't know block size with certainty.  I have said "512 bytes is it"
+               as this is most common.
+
+       2.  Recovery from when some one attempts to read past the end of the raw device will
+           be slower.  
+*/
+
+               if (the_result)
+                       {
+                       printk ("Warning : SCSI device at host %d, id %d, lun %d failed READ CAPACITY.\n"
+                               "status = %x, message = %02x, host = %02x, driver = %02x \n",
+                               rscsi_disks[i].device->host_no, rscsi_disks[i].device->id,
+                               rscsi_disks[i].device->lun,
+                               status_byte(the_result),
+                               msg_byte(the_result),
+                               host_byte(the_result),
+                               driver_byte(the_result)
+                               );
+                       if (driver_byte(the_result)  & DRIVER_SENSE)  
+                               printk("Extended sense code = %1x \n", sense_buffer[2] & 0xf);
+                       else
+                               printk("Sense not available. \n");
+
+                       printk("Block size assumed to be 512 bytes, disk size 1GB.  \n");
+                       rscsi_disks[i].capacity = 0x1fffff;
+                       rscsi_disks[i].sector_size = 512;
+                       }
+               else
+                       {
+                       rscsi_disks[i].capacity = (buffer[0] << 24) |   
+                                                 (buffer[1] << 16) |
+                                                 (buffer[2] << 8) |
+                                                 buffer[3];
+
+                       if ((rscsi_disks[i].sector_size = (buffer[4] << 24) |
+                                                    (buffer[5] << 16) |  
+                                                    (buffer[6] << 8) | 
+                                                    buffer[7]) != 512)
+                               {
+                               printk ("Unsupported sector size %d for sd %d",
+                                        rscsi_disks[i].sector_size, i);
+                               rscsi_disks[i].use = 0;
+                               }
+                       }
+
+               if (rscsi_disks[i].use)
+                       {
+                       scsi_disks[j = (i << 4)].start_sect = 0;
+
+                       sd_sizes[j]=(scsi_disks[j].nr_sects =  rscsi_disks[i].capacity)>>1;
+#ifdef DEBUG
+                       printk("/dev/sd%1d size = %d\n", j, sd_sizes[j]);
+#endif
+                       cmd[0] = READ_6;
+                       cmd[2] = cmd[3] = cmd[5] = 0; 
+                       cmd[4] = 1;
+                       the_result = -1;
+       
+                       scsi_do_cmd (rscsi_disks[i].device->host_no ,  rscsi_disks[i].device->id, 
+                               (void *) cmd, (void *) buffer, 512, sd_init_done,  SD_TIMEOUT, 
+                               sense_buffer, MAX_RETRIES);
+                                       
+                       while (the_result < 0);
+
+
+                       if (the_result || (0xaa55 != *(unsigned short *)(buffer + 510)))
+                                       {
+                                       printk ("Cannot read partition table for sd %d"
+                                               "\n\r",i);
+                                       rscsi_disks[i].use = 0;                                 
+                                       }
+                       else
+                               for (++j, k=j+4, p=(Partition *) (buffer + 0x1be); j < k; ++j, ++p)
+                                       {
+                                       memcpy ((void *) &scsi_disks[j], (void *) p, sizeof(Partition));        
+                                       sd_sizes[j]=(scsi_disks[j].nr_sects)>>1;
+#ifdef DEBUG
+       printk("/dev/sd%1d size = %d (%d blocks), offset = %d\n", j, scsi_disks[j].nr_sects, sd_sizes[j], scsi_disks[j].start_sect);
+#endif
+                                       }
+               
+                       rscsi_disks[i].ten = 1;
+                       rscsi_disks[i].remap = 1;
+                       }
+               }
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       blk_size[MAJOR_NR] = sd_sizes;  
+       blkdev_fops[MAJOR_NR] = &sd_fops; 
+}      
+#endif
+
diff --git a/kernel/blk_drv/scsi/sd.h b/kernel/blk_drv/scsi/sd.h
new file mode 100644 (file)
index 0000000..e4c4613
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *     sd.h Copyright (C) 1992 Drew Eckhardt 
+ *     SCSI disk driver header file by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+#ifndef _SD_H
+       #define _SD_H
+/*
+       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+*/
+
+#ifndef _SCSI_H
+#include "scsi.h"
+#endif
+
+#define MAX_SD 2
+
+typedef struct partition {
+       unsigned char boot_ind;         /* 0x80 - active (unused) */
+       unsigned char head;             /* ? */
+       unsigned char sector;           /* ? */
+       unsigned char cyl;              /* ? */
+       unsigned char sys_ind;          /* ? */
+       unsigned char end_head;         /* ? */
+       unsigned char end_sector;       /* ? */
+       unsigned char end_cyl;          /* ? */
+       unsigned int start_sect;        /* starting sector counting from 0 */
+       unsigned int nr_sects;          /* nr of sectors in partition */
+} Partition;
+
+extern int NR_SD;
+
+extern Partition scsi_disks[MAX_SD << 4] ;
+
+
+typedef struct {
+               unsigned capacity;              /* size in blocks */
+               unsigned sector_size;           /* size in bytes */
+               Scsi_Device  *device;           
+               unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
+               unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
+               unsigned ten:1;                 /* support ten byte read / write */
+               unsigned remap:1;               /* support remapping */
+               unsigned use:1;                 /* after the initial inquiry, is 
+                                                  the device still supported ? */
+               } Scsi_Disk;
+       
+extern Scsi_Disk rscsi_disks[MAX_SD];
+
+void sd_init(void);
+
+#define HOST (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no)
+#define ID (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id)
+#define LUN (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->lun)
+#endif
diff --git a/kernel/blk_drv/scsi/sd_ioctl.c b/kernel/blk_drv/scsi/sd_ioctl.c
new file mode 100644 (file)
index 0000000..087f870
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/config.h>
+#ifdef CONFIG_BLK_DEV_SD
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include "scsi.h"
+#include "sd.h"
+
+extern int scsi_ioctl (int dev, int cmd, void *arg);
+
+int sd_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsigned long arg)
+{
+       int dev = inode->i_rdev;
+       
+       switch (cmd) {
+               default:
+                       return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device,cmd,(void *) arg);
+       }
+}
+#endif
diff --git a/kernel/blk_drv/scsi/seagate.c b/kernel/blk_drv/scsi/seagate.c
new file mode 100644 (file)
index 0000000..28df162
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ *     seagate.c Copyright (C) 1992 Drew Eckhardt 
+ *     low level scsi driver for ST01/ST02 by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include <linux/sched.h>
+
+#include "seagate.h"
+#include "scsi.h"
+#include "hosts.h"
+
+static int incommand;                  /*
+                                               set if arbitration has finished and we are 
+                                               in some command phase.
+                                       */
+
+static void *base_address = NULL;      /*
+                                               Where the card ROM starts,
+                                               used to calculate memory mapped
+                                               register location.
+                                       */
+static volatile int abort_confirm = 0;
+
+volatile void *st0x_cr_sr;       /*
+                                               control register write,
+                                               status register read.
+                                               256 bytes in length.
+
+                                               Read is status of SCSI BUS,
+                                               as per STAT masks.
+
+                                       */
+
+
+static volatile void *st0x_dr;         /*
+                                               data register, read write
+                                               256 bytes in length.
+                                       */
+
+
+static volatile int st0x_aborted=0;    /* 
+                                               set when we are aborted, ie by a time out, etc.
+                                       */
+
+                                       /*
+                                               In theory, we have a nice auto
+                                               detect routine - but this 
+                                               overides it. 
+                                       */
+
+                       
+#define retcode(result) (((result) << 16) | (message << 8) | status)                   
+#define STATUS (*(unsigned char *) st0x_cr_sr)
+#define CONTROL STATUS 
+#define DATA (*(unsigned char *) st0x_dr)
+
+#ifndef OVERRIDE               
+static const char *  seagate_bases[] = {(char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xce000,
+                                       (char *) 0xdc000, (char *) 0xde000};
+typedef struct 
+       {
+       char *signature ;
+       unsigned offset;
+       unsigned length;
+       } Signature;
+       
+static const Signature signatures[] = {
+{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40},
+{"SEAGATE SCSI BIOS ",16, 17},
+{"SEAGATE SCSI BIOS ",17, 17}};
+/*
+       Note that the last signature handles BIOS revisions 3.0.0 and 
+       3.2 - the real ID's are 
+
+SEAGATE SCSI BIOS REVISION 3.0.0
+SEAGATE SCSI BIOS REVISION 3.2
+
+*/
+
+#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature))
+#endif
+
+int seagate_st0x_detect (int hostnum)
+       {
+       #ifndef OVERRIDE
+               int i,j;
+       #endif
+
+       /*
+               First, we try for the manual override.
+       */
+       #ifdef DEBUG 
+               printk("Autodetecting seagate ST0x\n");
+       #endif
+       
+       base_address = NULL;
+       #ifdef OVERRIDE
+               base_address = (void *) OVERRIDE;       
+               #ifdef DEBUG
+                       printk("Base address overridden to %x\n", base_address);
+               #endif
+       #else   
+       /*
+               To detect this card, we simply look for the SEAGATE SCSI
+               from the BIOS version notice in all the possible locations
+               of the ROM's.
+       */
+
+       for (i = 0; i < (sizeof (seagate_bases) / sizeof (char  * )); ++i)
+               for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)
+               if (!memcmp ((void *) (seagate_bases[i] +
+                   signatures[j].offset), (void *) signatures[j].signature,
+                   signatures[j].length))
+                       base_address = (void *) seagate_bases[i];
+               #endif
+       if (base_address)
+               {
+               st0x_cr_sr =(void *) (((unsigned char *) base_address) + 0x1a00); 
+               st0x_dr = (void *) (((unsigned char *) base_address )+ 0x1c00);
+               #ifdef DEBUG
+                       printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);
+               #endif
+               return -1;
+               }
+       else
+               {
+               #ifdef DEBUG
+                       printk("ST0x not detected.\n");
+               #endif
+               return 0;
+               }
+       }
+        
+       
+
+char *seagate_st0x_info(void)
+{
+       static char buffer[] = "Seagate ST-0X SCSI driver by Drew Eckhardt \n"
+"$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/seagate.c,v 1.1 1992/04/24 18:01:50 root Exp root $\n";
+       return buffer;
+}
+
+
+
+int seagate_st0x_command(unsigned char target, const void *cmnd,
+                        void *buff, int bufflen)
+       {
+       int len;                        
+       unsigned char *data;    
+
+       int clock;                      /*
+                                               We use clock for timeouts, etc.   This replaces the 
+                                               seagate_st0x_timeout that we had been using.
+                                       */
+       #if (DEBUG & PHASE_SELECTION)
+               int temp;
+       #endif
+
+       #if (DEBUG & PHASE_EXIT)
+                void *retaddr, *realretaddr;
+       #endif
+
+       #if ((DEBUG & PHASE_ETC) || (DEBUG & PRINT_COMMAND) || (DEBUG & PHASE_EXIT))    
+               int i;
+       #endif
+
+       #if (DEBUG & PHASE_ETC)
+               int phase=0, newphase;
+       #endif
+
+       int done = 0;
+       unsigned char status = 0;       
+       unsigned char message = 0;
+       register unsigned char status_read;
+
+       #if (DEBUG & PHASE_EXIT)
+                __asm__("
+movl 4(%%ebp), %%eax 
+":"=a" (realretaddr):);
+               printk("return address = %08x\n", realretaddr);
+       #endif
+
+
+       len=bufflen;
+       data=(unsigned char *) buff;
+
+       incommand = 0;
+       st0x_aborted = 0;
+
+       #if (DEBUG & PRINT_COMMAND)
+               printk ("seagate_st0x_command, target = %d, command = ", target);
+               for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i)
+                       printk("%02x ",  ((unsigned char *) cmnd)[i]);
+               printk("\n");
+       #endif
+       
+       if (target > 6)
+               return DID_BAD_TARGET;
+
+       
+       #if (DEBUG & PHASE_BUS_FREE)
+               printk ("SCSI PHASE = BUS FREE \n");
+       #endif
+
+       /*
+
+               BUS FREE PHASE
+
+               On entry, we make sure that the BUS is in a BUS FREE
+               phase, by insuring that both BSY and SEL are low for
+               at least one bus settle delay.  The standard requires a
+               minimum of 400 ns, which is 16 clock cycles on a
+               386-40  .
+
+               This doesn't give us much time - so we'll do two several
+               reads to be sure be sure.
+       */
+
+       clock = jiffies + ST0X_BUS_FREE_DELAY;  
+
+       while (((STATUS |  STATUS | STATUS) & 
+                (STAT_BSY | STAT_SEL)) && 
+                (!st0x_aborted) && (jiffies < clock));
+
+       if (jiffies > clock)
+               return retcode(DID_BUS_BUSY);
+       else if (st0x_aborted)
+               return retcode(st0x_aborted);
+
+       /*
+               Bus free has been detected, within BUS settle.  I used to support an arbitration
+               phase - however, on the seagate, this degraded performance by a factor > 10 - so
+               it is no more.
+       */
+
+       /*
+               SELECTION PHASE
+
+               Now, we select the disk, giving it the SCSI ID at data
+               and a command of PARITY if necessary, plus driver enable,
+               plus raise select signal.
+       */
+
+       #if (DEBUG & PHASE_SELECTION)
+               printk("SCSI PHASE = SELECTION\n");
+       #endif
+
+       clock = jiffies + ST0X_SELECTION_DELAY;
+       DATA = (unsigned char) (1 << target);
+
+       CONTROL =  BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL;
+
+       /*
+               When the SCSI device decides that we're gawking at it, it will respond by asserting BUSY on the bus.
+       */
+       while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock) && !st0x_aborted)
+
+#if (DEBUG & PHASE_SELECTION)
+               {
+               temp = clock - jiffies;
+
+               if (!(jiffies % 5))
+                       printk("seagate_st0x_timeout : %d            \r",temp);
+       
+               }
+               printk("Done.                                             \n\r");
+               printk("Status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", status_read, temp,
+                       st0x_aborted);
+#else
+               ;
+#endif
+       
+
+       if ((jiffies > clock)  || (!st0x_aborted & !(status_read & STAT_BSY)))
+               {
+               #if (DEBUG & PHASE_SELECT)
+                       printk ("NO CONNECT with target %d, status = %x \n", target, STATUS);
+               #endif
+               return retcode(DID_NO_CONNECT);
+               }
+
+       /*
+               If we have been aborted, and we have a command in progress, IE the target still has
+               BSY asserted, then we will reset the bus, and notify the midlevel driver to
+               expect sense.
+       */
+
+       if (st0x_aborted)
+               {
+               CONTROL = BASE_CMD;
+               if (STATUS & STAT_BSY)
+                       {
+                       seagate_st0x_reset();
+                       return retcode(DID_RESET);
+                       }
+               
+               return retcode(st0x_aborted);
+               }       
+       
+       /*
+               COMMAND PHASE
+               The device has responded with a BSY, so we may now enter
+               the information transfer phase, where we will send / recieve
+               data and command as directed by the target.
+
+
+               The nasty looking read / write inline assembler loops we use for 
+               DATAIN and DATAOUT phases are approximately 4-5 times as fast as 
+               the 'C' versions - since we're moving 1024 bytes of data, this
+               really adds up.
+       */
+
+       #if (DEBUG & PHASE_ETC)
+               printk("PHASE = information transfer\n");
+       #endif  
+
+       incommand = 1;
+
+       /*
+               Enable command
+       */
+
+       CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+
+       /*
+               Now, we poll the device for status information,
+               and handle any requests it makes.  Note that since we are unsure of 
+               how much data will be flowing across the system, etc and cannot 
+               make reasonable timeouts, that we will instead have the midlevel
+               driver handle any timeouts that occur in this phase.
+       */
+
+       while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) 
+                       {
+                       #ifdef PARITY
+                               if (status_read & STAT_PARITY)
+                                       {
+                                       done = 1;
+                                       st0x_aborted = DID_PARITY;
+                                       }       
+                       #endif
+
+                       if (status_read & STAT_REQ)
+                               {
+                               #if (DEBUG & PHASE_ETC)
+                                       if ((newphase = (status_read & REQ_MASK)) != phase)
+                                               {
+                                               phase = newphase;
+                                               switch (phase)
+                                                       {
+                                                       case REQ_DATAOUT : printk("SCSI PHASE = DATA OUT\n"); break;
+                                                       case REQ_DATAIN : printk("SCSI PHASE = DATA IN\n"); break;
+                                                       case REQ_CMDOUT : printk("SCSI PHASE = COMMAND OUT\n"); break;
+                                                       case REQ_STATIN : printk("SCSI PHASE = STATUS IN\n"); break;
+                                                       case REQ_MSGOUT : printk("SCSI PHASE = MESSAGE OUT\n"); break;
+                                                       case REQ_MSGIN : printk("SCSI PHASE = MESSAGE IN\n"); break;
+                                                       default : printk("UNKNOWN PHASE"); st0x_aborted = 1; done = 1;
+                                                       }       
+                                               }
+                               #endif
+
+                               switch (status_read & REQ_MASK)
+                                       {                       
+                                       case REQ_DATAOUT : 
+
+       /*
+               We loop as long as we are in a data out phase, there is data to send, and BSY is still
+               active
+       */
+                                                       __asm__ ("
+
+/*
+       Local variables : 
+       len = ecx
+       data = esi
+       st0x_cr_sr = ebx
+       st0x_dr =  edi
+
+       Test for any data here at all.
+*/
+       movl %0, %%esi          /* local value of data */
+       movl %1, %%ecx          /* local value of len */        
+       orl %%ecx, %%ecx
+       jz 2f
+
+       cld
+
+       movl _st0x_cr_sr, %%ebx
+       movl _st0x_dr, %%edi
+       
+1:     movb (%%ebx), %%al
+/*
+       Test for BSY
+*/
+
+       test $1, %%al 
+       jz 2f
+
+/*
+       Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0.
+*/
+       test $0xe, %%al
+       jnz 2f  
+/*
+       Test for REQ
+*/     
+       test $0x10, %%al
+       jz 1b
+       lodsb
+       movb %%al, (%%edi) 
+       loop 1b
+
+2: 
+       movl %%esi, %2
+       movl %%ecx, %3
+                                                                       ":
+/* output */
+"=r" (data), "=r" (len) :
+/* input */
+"0" (data), "1" (len) :
+/* clobbered */
+"ebx", "ecx", "edi", "esi"); 
+
+                                                       break;
+
+                                       case REQ_DATAIN : 
+       /*
+               We loop as long as we are in a data out phase, there is room to read, and BSY is still
+               active
+       */
+                                                       __asm__ ("
+/*
+       Local variables : 
+       ecx = len
+       edi = data
+       esi = st0x_cr_sr
+       ebx = st0x_dr
+
+       Test for room to read
+*/
+
+       movl %0, %%edi          /* data */
+       movl %1, %%ecx          /* len */
+       orl %%ecx, %%ecx
+       jz 2f
+
+       cld
+       movl _st0x_cr_sr, %%esi
+       movl _st0x_dr, %%ebx
+
+1:     movb (%%esi), %%al
+/*
+       Test for BSY
+*/
+
+       test $1, %%al 
+       jz 2f
+
+/*
+       Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4.
+*/
+       movb $0xe, %%ah 
+       andb %%al, %%ah
+       cmpb $0x04, %%ah
+       jne 2f
+               
+/*
+       Test for REQ
+*/     
+       test $0x10, %%al
+       jz 1b
+
+       movb (%%ebx), %%al      
+       stosb   
+       loop 1b
+
+2:     movl %%edi, %2          /* data */
+       movl %%ecx, %3          /* len */
+                                                                       ":
+/* output */
+"=r" (data), "=r" (len) :
+/* input */
+"0" (data), "1" (len) :
+/* clobbered */
+"ebx", "ecx", "edi", "esi"); 
+                                                       break;
+
+                                       case REQ_CMDOUT : 
+                                                       while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) ==
+                                                               REQ_CMDOUT))
+                                                               DATA = *(unsigned char *) cmnd ++;
+                                               break;
+       
+                                       case REQ_STATIN : 
+                                               status = DATA;
+                                               break;
+                               
+                                       case REQ_MSGOUT : 
+                                               DATA = MESSAGE_REJECT;
+                                               break;
+                                       
+                                       case REQ_MSGIN : 
+                                               if ((message = DATA) == COMMAND_COMPLETE)
+                                                       done=1;
+                                               
+                                               break;
+
+                                       default : printk("UNKNOWN PHASE"); st0x_aborted = DID_ERROR; 
+                                       }       
+                               }
+
+               }
+
+#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT))
+       printk("Transfered %d bytes, allowed %d additional bytes\n", (bufflen - len), len);
+#endif
+
+#if (DEBUG & PHASE_EXIT)
+               printk("Buffer : \n");
+               for (i = 0; i < 20; ++i) 
+                       printk ("%02x  ", ((unsigned char *) buff)[i]);
+               printk("\n");
+               printk("Status = %02x, message = %02x\n", status, message);
+#endif
+
+       
+               if (st0x_aborted)
+                       {
+                       if (STATUS & STAT_BSY)
+                               {
+                               seagate_st0x_reset();
+                               st0x_aborted = DID_RESET;
+                               }
+                       abort_confirm = 1;
+                       }       
+                       
+               CONTROL = BASE_CMD;
+
+#if (DEBUG & PHASE_EXIT)
+       __asm__("
+mov 4(%%ebp), %%eax
+":"=a" (retaddr):);
+
+       printk("Exiting seagate_st0x_command() - return address is %08x \n", retaddr);
+       if (retaddr != realretaddr)
+               panic ("Corrupted stack : return address on entry != return address on exit.\n");
+       
+#endif
+
+               return retcode (st0x_aborted);
+       }
+
+int seagate_st0x_abort (int code)
+       {
+       if (code)
+               st0x_aborted = code;
+       else
+               st0x_aborted = DID_ABORT;
+
+               return 0;
+       }
+
+/*
+       the seagate_st0x_reset function resets the SCSI bus
+*/
+       
+int seagate_st0x_reset (void)
+       {
+       unsigned clock;
+       /*
+               No timeouts - this command is going to fail because 
+               it was reset.
+       */
+
+#ifdef DEBUG
+       printk("In seagate_st0x_reset()\n");
+#endif
+
+
+       /* assert  RESET signal on SCSI bus.  */
+               
+       CONTROL = BASE_CMD  | CMD_RST;
+       clock=jiffies+2;
+
+       
+       /* Wait.  */
+       
+       while (jiffies < clock);
+
+       CONTROL = BASE_CMD;
+       
+       st0x_aborted = DID_RESET;
+
+#ifdef DEBUG
+       printk("SCSI bus reset.\n");
+#endif
+       return 0;
+       }
+#endif 
diff --git a/kernel/blk_drv/scsi/seagate.h b/kernel/blk_drv/scsi/seagate.h
new file mode 100644 (file)
index 0000000..d625446
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *     seagate.h Copyright (C) 1992 Drew Eckhardt 
+ *     low level scsi driver header for ST01/ST02 by
+ *             Drew Eckhardt 
+ *
+ *     <drew@colorado.edu>
+ */
+
+#ifndef _SEAGATE_H
+       #define SEAGATE_H
+/*
+       $Header
+*/
+#ifndef ASM
+int seagate_st0x_detect(int);
+int seagate_st0x_command(unsigned char target, const void *cmnd,  void *buff, int bufflen);
+int seagate_st0x_abort(int);
+char *seagate_st0x_info(void);
+int seagate_st0x_reset(void); 
+
+#ifndef NULL
+       #define NULL 0
+#endif
+
+#define SEAGATE_ST0X  {"Seagate ST-01/ST-02", seagate_st0x_detect,     \
+                        seagate_st0x_info, seagate_st0x_command,       \
+                        NULL, seagate_st0x_abort, seagate_st0x_reset,  \
+                        0, 7, 0}
+#endif
+
+
+/*
+       defining PARITY causes parity data to be checked
+*/
+
+#define PARITY
+
+/*
+       defining ARBITRATE causes the arbitration sequence to be used.  And speed to drop by a 
+       factor of ten.
+*/
+
+#undef ARBITRATE
+
+
+/*
+       Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
+               driver, and Mitsugu Suzuki for information on the ST-01
+               SCSI host.
+*/
+
+/*
+       CONTROL defines
+*/
+
+#define CMD_RST                0x01
+#define CMD_SEL                0x02
+#define CMD_BSY                0x04
+#define CMD_ATTN               0x08
+#define CMD_START_ARB          0x10
+#define CMD_EN_PARITY          0x20
+#define CMD_INTR               0x40
+#define CMD_DRVR_ENABLE                0x80
+
+/*
+       STATUS
+*/
+
+#define STAT_BSY               0x01
+#define STAT_MSG               0x02
+#define STAT_IO                        0x04
+#define STAT_CD                        0x08
+#define STAT_REQ               0x10
+#define STAT_SEL               0x20
+#define STAT_PARITY            0x40
+#define STAT_ARB_CMPL          0x80
+
+/* 
+       REQUESTS
+*/
+
+#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
+#define REQ_DATAOUT 0
+#define REQ_DATAIN STAT_IO
+#define REQ_CMDOUT STAT_CD
+#define REQ_STATIN (STAT_CD | STAT_IO)
+#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
+
+extern volatile int seagate_st0x_timeout;
+
+#ifdef PARITY
+       #define BASE_CMD CMD_EN_PARITY
+#else
+       #define BASE_CMD  0
+#endif
+
+/*
+       Debugging code
+*/
+
+#define PHASE_BUS_FREE 1
+#define PHASE_ARBITRATION 2
+#define PHASE_SELECTION 4
+#define PHASE_DATAIN 8 
+#define PHASE_DATAOUT 0x10
+#define PHASE_CMDOUT 0x20
+#define PHASE_MSGIN 0x40
+#define PHASE_MSGOUT 0x80
+#define PHASE_STATUSIN 0x100
+#define PHASE_ETC (PHASE_DATAIN | PHASE_DATA_OUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
+#define PRINT_COMMAND 0x200
+#define PHASE_EXIT 0x400
+
+/* 
+       Control options - these are timeouts specified in .01 seconds.
+*/
+
+#define ST0X_BUS_FREE_DELAY 25
+#define ST0X_SELECTION_DELAY 25
+
+#endif
+
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
new file mode 100644 (file)
index 0000000..bef3ae8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+       The st.c file is a sub-stub file.  I just wanted to have all the detect code, etc in the
+       mid level driver present and working.  If no one else volunteers for this, I'll
+       do it - but it's low on my list of priorities.
+*/
+#include <linux/config.h>
+
+#ifdef CONFIG_BLK_DEV_ST
+#include "scsi.h"
+#include "st.h"
+
+#define MAJOR_NR 9
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include "../blk.h" 
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+Scsi_Tape scsi_tapes[MAX_ST];
+static int st_sizes[MAX_ST];
+int NR_ST=0;
+
+void do_st_request(void)
+{
+       panic("There is no st driver.\n\r");
+}
+
+void st_init(void)
+{
+       blk_dev[MAJOR_NR].request_fn = do_st_request;
+       blk_size[MAJOR_NR] = st_sizes;
+}
+#endif 
diff --git a/kernel/blk_drv/scsi/st.h b/kernel/blk_drv/scsi/st.h
new file mode 100644 (file)
index 0000000..1a7c044
--- /dev/null
@@ -0,0 +1,26 @@
+
+#ifndef _ST_H
+       #define _ST_H
+/*
+       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+*/
+
+#ifndef _SCSI_H
+#include "scsi.h"
+#endif
+
+#define MAX_ST 1
+
+typedef struct 
+       {
+       /*
+               Undecided goodies go here!!!
+       */
+       Scsi_Device* device;    
+       } Scsi_Tape;
+
+
+extern int NR_ST;
+extern Scsi_Tape scsi_tapes[MAX_ST];
+void st_init(void);
+#endif
diff --git a/kernel/blk_drv/scsi/st_ioctl.c b/kernel/blk_drv/scsi/st_ioctl.c
new file mode 100644 (file)
index 0000000..4bc7a39
--- /dev/null
@@ -0,0 +1,19 @@
+#include <linux/config.h>
+#ifdef CONFIG_BLK_DEV_ST
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include "st.h"
+
+extern int scsi_ioctl(int dev, int cmd, void *arg);
+
+int st_ioctl(struct inode * inode,struct file * file, unsigned long cmd, unsigned long arg)
+{
+       int dev = inode->i_rdev;
+
+       switch (cmd) {
+               default:
+                       return scsi_ioctl(scsi_tapes[MINOR(dev)].device,cmd,(void *) arg);
+       }
+}
+#endif
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
new file mode 100644 (file)
index 0000000..049fdd8
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ *     ultrastor.c     (C) 1991 David B. Gentzel
+ *     Low-level scsi driver for UltraStor 14F
+ *     by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *         (gentzel@nova.enet.dec.com)
+ *     Thanks to UltraStor for providing the necessary documentation
+ */
+
+/* ??? Caveats:
+   This driver is VERY stupid.  It takes no advantage of much of the power of
+   the UltraStor controller.  We just sit-and-spin while waiting for commands
+   to complete.  I hope to go back and beat it into shape, but PLEASE, anyone
+   else who would like to, please make improvements! */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+
+#include <stddef.h>
+
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#include "ultrastor.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#define VERSION "1.0 alpha"
+
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+#define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
+
+/* Simply using "unsigned long" in these structures won't work as it causes
+   alignment.  Perhaps the "aligned" attribute may be used in GCC 2.0 to get
+   around this, but for now I use this hack. */
+typedef struct {
+    unsigned char bytes[4];
+} Longword;
+
+/* Used to store configuration info read from config i/o registers.  Most of
+   this is not used yet, but might as well save it. */
+struct config {
+    struct {
+       unsigned char bios_segment: 3;
+       unsigned char reserved: 1;
+       unsigned char interrupt: 2;
+       unsigned char dma_channel: 2;
+    } config_1;
+    struct {
+       unsigned char ha_scsi_id: 3;
+       unsigned char mapping_mode: 2;
+       unsigned char bios_drive_number: 1;
+       unsigned char tfr_port: 2;
+    } config_2;
+};
+
+/* MailBox SCSI Command Packet.  Basic command structure for communicating
+   with controller. */
+struct mscp {
+    unsigned char opcode: 3;           /* type of command */
+    unsigned char xdir: 2;             /* data transfer direction */
+    unsigned char dcn: 1;              /* disable disconnect */
+    unsigned char ca: 1;               /* use cache (if available) */
+    unsigned char sg: 1;               /* scatter/gather operation */
+    unsigned char target_id: 3;                /* target SCSI id */
+    unsigned char ch_no: 2;            /* SCSI channel (always 0 for 14f) */
+    unsigned char lun: 3;              /* logical unit number */
+    Longword transfer_data;            /* transfer data pointer */
+    Longword transfer_data_length;     /* length in bytes */
+    Longword command_link;             /* for linking command chains */
+    unsigned char scsi_command_link_id;        /* identifies command in chain */
+    unsigned char number_of_sg_list;   /* (if sg is set) 8 bytes per list */
+    unsigned char length_of_sense_byte;
+    unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */
+    unsigned char scsi_cdbs[12];       /* SCSI commands */
+    unsigned char adapter_status;      /* non-zero indicates HA error */
+    unsigned char target_status;       /* non-zero indicates target error */
+    Longword sense_data;
+};
+
+/* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
+static const void *const bios_segment_table[8] = {
+    NULL,           (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
+    (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
+};
+
+/* Allowed IRQs for 14f */
+static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
+
+/* Allowed DMA channels for 14f (0 indicates reserved) */
+static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
+
+#if 0  /* Not currently used, head/sector mappings allowed by 14f */
+static const struct {
+    unsigned char heads;
+    unsigned char sectors;
+} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
+#endif
+
+/* Config info */
+static struct config config;
+
+/* Our index in the host adapter array maintained by higher-level driver */
+static int host_number;
+
+/* PORT_ADDRESS is first port address used for i/o of messages. */
+#ifdef PORT_OVERRIDE
+# define PORT_ADDRESS PORT_OVERRIDE
+#else
+static unsigned short port_address = 0;
+# define PORT_ADDRESS port_address
+#endif
+
+static volatile int aborted = 0;
+
+#ifndef PORT_OVERRIDE
+static const unsigned short ultrastor_ports[] = {
+    0x330, 0x340, 0x310, 0x230, 0x240, 0x210, 0x130, 0x140,
+};
+#endif
+
+static const struct {
+    const char *signature;
+    size_t offset;
+    size_t length;
+} signatures[] = {
+    { "SBIOS 1.01 COPYRIGHT (C) UltraStor Corporation,1990-1992.", 0x10, 57 },
+};
+
+int ultrastor_14f_detect(int hostnum)
+{
+    size_t i;
+    unsigned char in_byte;
+    const void *base_address;
+
+#ifdef DEBUG
+    printk("ultrastor_14f_detect: called\n");
+#endif
+
+#ifndef PORT_OVERRIDE
+/* ??? This is easy to implement, but I'm not sure how "friendly" it is to
+   go off and read random i/o ports. */
+# error Not implemented!
+#endif
+
+    if (!PORT_ADDRESS) {
+#ifdef DEBUG
+       printk("ultrastor_14f_detect: no port address found!\n");
+#endif
+       return FALSE;
+    }
+
+#ifdef DEBUG
+    printk("ultrastor_14f_detect: port address = %X\n", PORT_ADDRESS);
+#endif
+
+    in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
+    if (in_byte != US14F_PRODUCT_ID_0) {
+#ifdef DEBUG
+       printk("ultrastor_14f_detect: unknown product ID 0 - %02X\n", in_byte);
+#endif
+       return FALSE;
+    }
+    in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
+    /* Only upper nibble is defined for Product ID 1 */
+    if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
+#ifdef DEBUG
+       printk("ultrastor_14f_detect: unknown product ID 1 - %02X\n", in_byte);
+#endif
+       return FALSE;
+    }
+
+    /* All above tests passed, must be the right thing.  Get some useful
+       info. */
+    *(char *)&config.config_1 = inb(CONFIG(PORT_ADDRESS + 0));
+    *(char *)&config.config_2 = inb(CONFIG(PORT_ADDRESS + 1));
+
+    /* To verify this card, we simply look for the UltraStor SCSI from the
+       BIOS version notice. */
+    base_address = bios_segment_table[config.config_1.bios_segment];
+    if (base_address != NULL) {
+       int found = 0;
+
+       for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
+           if (memcmp((char *)base_address + signatures[i].offset,
+                      signatures[i].signature, signatures[i].length))
+               found = 1;
+       if (!found)
+           base_address = NULL;
+    }
+    if (!base_address) {
+#ifdef DEBUG
+       printk("ultrastor_14f_detect: not detected.\n");
+#endif
+       return FALSE;
+    }
+
+    /* Final consistancy check, verify previous info. */
+    if (!dma_channel_table[config.config_1.dma_channel]
+       || !(config.config_2.tfr_port & 0x2)) {
+#ifdef DEBUG
+       printk("ultrastor_14f_detect: consistancy check failed\n");
+#endif
+       return FALSE;
+    }
+
+    /* If we were TRULY paranoid, we could issue a host adapter inquiry
+       command here and verify the data returned.  But frankly, I'm
+       exhausted! */
+
+    /* Finally!  Now I'm satisfied... */
+#ifdef DEBUG
+    printk("ultrastor_14f_detect: detect succeeded\n"
+          "  BIOS segment: %05X\n"
+          "  Interrupt: %d\n"
+          "  DMA channel: %d\n"
+          "  H/A SCSI ID: %d\n",
+          base_address, interrupt_table[config.config_1.interrupt],
+          dma_channel_table[config.config_1.dma_channel],
+          config.config_2.ha_scsi_id);
+#endif
+    host_number = hostnum;
+    scsi_hosts[hostnum].this_id = config.config_2.ha_scsi_id;
+    return TRUE;
+}
+
+const char *ultrastor_14f_info(void)
+{
+    return "UltraStor 14F SCSI driver version "
+          VERSION
+          " by David B. Gentzel\n";
+}
+
+#if 0
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+                              void *buff, int bufflen, void (*done)(int, int))
+#else
+int ultrastor_14f_command(unsigned char target, const void *cmnd,
+                         void *buff, int bufflen)
+#endif
+{
+    struct mscp mscp = {
+       OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE,
+       target, 0, 0 /* LUN??? */,
+       *(Longword *)&buff,
+       *(Longword *)&bufflen,
+       { 0, 0, 0, 0 },
+       0,
+       0,
+       0,
+       ((*(char *)cmnd <= 0x1F) ? 6 : 10),
+       { 0 },  /* Filled in via memcpy below */
+       0,
+       0,
+       { 0, 0, 0, 0 }
+    };
+    unsigned char in_byte;
+
+    memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
+
+    /* Find free OGM slot (OGMINT bit is 0) */
+    do
+       in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS));
+    while (!aborted && (in_byte & 1));
+    if (aborted)
+       /* ??? is this right? */
+       return (aborted << 16);
+
+    /* Store pointer in OGM address bytes */
+    outb(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
+    outb(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
+    outb(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
+    outb(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
+
+    /* Issue OGM interrupt */
+    outb(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
+
+    /* Wait for ICM interrupt */
+    do
+       in_byte = inb(SYS_DOORBELL_INTR(PORT_ADDRESS));
+    while (!aborted && !(in_byte & 1));
+    if (aborted)
+       /* ??? is this right? */
+       return (aborted << 16);
+
+    /* Clean ICM slot (set ICMINT bit to 0) */
+    outb(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
+
+    /* ??? not right, but okay for now? */
+    return (mscp.adapter_status << 16) | mscp.target_status;
+}
+
+int ultrastor_14f_abort(int code)
+{
+    aborted = (code ? code : DID_ABORT);
+    return 0;
+}
+
+int ultrastor_14f_reset(void)
+{
+    unsigned char in_byte;
+
+#ifdef DEBUG
+    printk("ultrastor_14f_reset: called\n");
+#endif
+
+    /* Issue SCSI BUS reset */
+    outb(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
+    /* Wait for completion... */
+    do
+       in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS));
+    while (in_byte & 0x20);
+
+    aborted = DID_RESET;
+
+#ifdef DEBUG
+    printk("ultrastor_14f_reset: returning\n");
+#endif
+    return 0;
+}
+
+#endif
diff --git a/kernel/blk_drv/scsi/ultrastor.h b/kernel/blk_drv/scsi/ultrastor.h
new file mode 100644 (file)
index 0000000..13ded23
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *     ultrastor.c     (C) 1991 David B. Gentzel
+ *     Low-level scsi driver for UltraStor 14F
+ *     by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *         (gentzel@nova.enet.dec.com)
+ *     Thanks to UltraStor for providing the necessary documentation
+ */
+
+#ifndef _ULTRASTOR_H
+#define _ULTRASTOR_H
+
+/* ??? Some of the stuff in this file is really private to ultrastor.c and
+   should be moved elsewhere (as this file is included by higher-level driver
+   files). */
+
+/* ??? These don't really belong here */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+int ultrastor_14f_detect(int);
+const char *ultrastor_14f_info(void);
+#if 0  /* ??? Future direction... */
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+                              void *buff, int bufflen,
+                              void (*done)(int, int));
+#else
+int ultrastor_14f_command(unsigned char target, const void *cmnd,
+                         void *buff, int bufflen);
+#endif
+int ultrastor_14f_abort(int);
+int ultrastor_14f_reset(void);
+
+#if 0  /* ??? Future direction... */
+# define ULTRASTOR_14F \
+    { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, 0, \
+      ultrastor_14f_queuecommand, ultrastor_14f_abort, ultrastor_14f_reset, \
+      TRUE, 0, 0 }
+#else
+# define ULTRASTOR_14F \
+    { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \
+      ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \
+      FALSE, 0, 0 }
+#endif
+
+#define PORT_OVERRIDE 0x330
+
+/* Port addresses (relative to the base address) */
+#define LCL_DOORBELL_MASK(port) ((port) + 0x0)
+#define LCL_DOORBELL_INTR(port) ((port) + 0x1)
+#define SYS_DOORBELL_MASK(port) ((port) + 0x2)
+#define SYS_DOORBELL_INTR(port) ((port) + 0x3)
+#define PRODUCT_ID(port) ((port) + 0x4)
+#define CONFIG(port) ((port) + 0x6)
+#define OGM_DATA_PTR(port) ((port) + 0x8)
+#define ICM_DATA_PTR(port) ((port) + 0xC)
+
+/* Values for the PRODUCT_ID ports for the 14F */
+#define US14F_PRODUCT_ID_0 0x56
+#define US14F_PRODUCT_ID_1 0x40                /* NOTE: Only upper nibble is used */
+
+/* MSCP field values */
+
+/* Opcode */
+#define OP_HOST_ADAPTER 0x1
+#define OP_SCSI 0x2
+#define OP_RESET 0x4
+
+/* Date Transfer Direction */
+#define DTD_SCSI 0x0
+#define DTD_IN 0x1
+#define DTD_OUT 0x2
+#define DTD_NONE 0x3
+
+/* Host Adapter command subcodes */
+#define HA_CMD_INQUIRY 0x1
+#define HA_CMD_SELF_DIAG 0x2
+#define HA_CMD_READ_BUFF 0x3
+#define HA_CMD_WRITE_BUFF 0x4
+
+#endif
index 0246fc78d5006be763b851479e4b16a7cf93f98b..9eb9435558d8e885a69ef9731324a87ae1870f38 100644 (file)
@@ -25,15 +25,15 @@ CPP =cpp -nostdinc -I../../include
        $(CC) $(CFLAGS) \
        -c -o $*.o $<
 
-OBJS  = tty_io.o console.o keyboard.o serial.o rs_io.o \
-       tty_ioctl.o pty.o lp.o
+OBJS  = tty_io.o console.o keyboard.o serial.o \
+       tty_ioctl.o pty.o lp.o vt.o mem.o
 
 chr_drv.a: $(OBJS)
        $(AR) rcs chr_drv.a $(OBJS)
        sync
 
-keyboard.s: keyboard.S
-       $(CPP) $(KEYBOARD) -traditional keyboard.S -o keyboard.s
+keyboard.o: keyboard.c
+       $(CC) $(CFLAGS) $(KEYBOARD) -c -o keyboard.o keyboard.c
 
 clean:
        rm -f core *.o *.a tmp_make keyboard.s
@@ -42,62 +42,66 @@ clean:
 dep:
        sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
        (for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
-               $(CPP) -M $$i;done) >> tmp_make
+               $(CPP) -M -DKBD_FINNISH $$i;done) >> tmp_make
        cp tmp_make Makefile
 
 ### Dependencies:
-console.s console.o : console.c ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
+console.s console.o : console.c ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/timer.h ../../include/linux/tty.h \
+  ../../include/asm/system.h ../../include/termios.h ../../include/linux/config.h \
+  ../../include/linux/config_rel.h ../../include/linux/config_ver.h ../../include/linux/config.dist.h \
+  ../../include/asm/io.h ../../include/asm/segment.h ../../include/linux/string.h \
+  ../../include/errno.h ../../include/sys/kd.h vt_kern.h 
+keyboard.s keyboard.o : keyboard.c ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/ctype.h ../../include/linux/tty.h \
+  ../../include/asm/system.h ../../include/termios.h ../../include/asm/io.h 
+lp.s lp.o : lp.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
-  ../../include/time.h ../../include/sys/resource.h \
-  ../../include/linux/timer.h ../../include/linux/tty.h \
-  ../../include/termios.h ../../include/linux/config.h \
-  ../../include/linux/config_rel.h ../../include/linux/config_ver.h \
-  ../../include/asm/io.h ../../include/asm/system.h \
-  ../../include/asm/segment.h ../../include/string.h ../../include/errno.h 
-lp.s lp.o : lp.c ../../include/linux/lp.h ../../include/errno.h \
-  ../../include/linux/kernel.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/lp.h ../../include/errno.h ../../include/asm/io.h ../../include/asm/segment.h 
+mem.s mem.o : mem.c ../../include/errno.h ../../include/sys/types.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/termios.h ../../include/asm/segment.h ../../include/asm/io.h 
+pty.s pty.o : pty.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
   ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
-  ../../include/linux/mm.h ../../include/signal.h ../../include/sys/param.h \
-  ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
-  ../../include/asm/io.h ../../include/asm/segment.h \
-  ../../include/checkpoint.h 
-pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \
-  ../../include/sys/types.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/asm/system.h \
+  ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/tty.h ../../include/asm/system.h ../../include/termios.h \
   ../../include/asm/io.h 
-serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \
-  ../../include/sys/types.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/timer.h \
-  ../../include/asm/system.h ../../include/asm/io.h 
-tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
-  ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \
-  ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/times.h ../../include/sys/utsname.h \
-  ../../include/sys/param.h ../../include/sys/resource.h \
-  ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/linux/tty.h \
-  ../../include/termios.h ../../include/asm/segment.h \
-  ../../include/asm/system.h 
-tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
-  ../../include/sys/types.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/linux/tty.h \
-  ../../include/asm/io.h ../../include/asm/segment.h \
-  ../../include/asm/system.h 
+serial.s serial.o : serial.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/linux/timer.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/termios.h ../../include/asm/io.h 
+tty_io.s tty_io.o : tty_io.c ../../include/linux/ctype.h ../../include/errno.h ../../include/signal.h \
+  ../../include/sys/types.h ../../include/unistd.h ../../include/sys/stat.h ../../include/sys/time.h \
+  ../../include/time.h ../../include/sys/times.h ../../include/sys/utsname.h ../../include/sys/param.h \
+  ../../include/sys/resource.h ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/linux/tty.h ../../include/asm/system.h ../../include/termios.h \
+  ../../include/asm/io.h ../../include/asm/segment.h 
+tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h ../../include/sys/types.h \
+  ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/asm/io.h ../../include/asm/segment.h 
+vt.s vt.o : vt.c ../../include/errno.h ../../include/sys/types.h ../../include/sys/kd.h \
+  ../../include/sys/vt.h ../../include/asm/io.h ../../include/asm/segment.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+  ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+  ../../include/termios.h vt_kern.h 
index 2d62be345b5b69317e7032468f704a7273499291..824f1ad6410929ca8ec6172fd1248a4944affbe0 100644 (file)
 #include <asm/system.h>
 #include <asm/segment.h>
 
-#include <string.h>
+#include <linux/string.h>
 #include <errno.h>
 
+#include <sys/kd.h>
+#include "vt_kern.h"
+
 #define DEF_TERMIOS \
 (struct termios) { \
        ICRNL, \
@@ -79,11 +82,14 @@ static void unblank_screen(void);
 
 int NR_CONSOLES = 0;
 
+extern void vt_init(void);
 extern void keyboard_interrupt(void);
 extern void set_leds(void);
 extern unsigned char kapplic;
 extern unsigned char kleds;
 extern unsigned char kmode;
+extern unsigned char kraw;
+extern unsigned char ke0;
 
 unsigned long  video_num_columns;              /* Number of text columns       */
 unsigned long  video_num_lines;                /* Number of test lines         */
@@ -118,9 +124,9 @@ static struct {
        unsigned int    vc_saved_y;
        unsigned int    vc_iscolor;
        unsigned char   vc_kbdapplic;
-       unsigned char   vc_kbdleds;
        unsigned char   vc_kbdmode;
        char *          vc_translate;
+       /* additional information is in vt_kern.h */
 } vc_cons [MAX_CONSOLES];
 
 #define MEM_BUFFER_SIZE (2*80*50*8) 
@@ -153,7 +159,9 @@ static int console_blanked = 0;
 #define iscolor                (vc_cons[currcons].vc_iscolor)
 #define kbdapplic      (vc_cons[currcons].vc_kbdapplic)
 #define kbdmode                (vc_cons[currcons].vc_kbdmode)
-#define kbdleds                (vc_cons[currcons].vc_kbdleds)
+#define kbdraw         (vt_cons[currcons].vc_kbdraw)
+#define kbde0          (vt_cons[currcons].vc_kbde0)
+#define kbdleds                (vt_cons[currcons].vc_kbdleds)
 
 int blankinterval = 5*60*HZ;
 static int screen_size = 0;
@@ -465,12 +473,10 @@ static void respond(int currcons, struct tty_struct * tty)
 {
        char * p = RESPONSE;
 
-       cli();
        while (*p) {
                PUTCH(*p,tty->read_q);
                p++;
        }
-       sti();
        TTY_READ_FLUSH(tty);
 }
 
@@ -569,7 +575,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
 
 void con_write(struct tty_struct * tty)
 {
-       unsigned char c;
+       int c;
        unsigned int currcons;
 
        wake_up(&tty->write_q->proc_list);
@@ -578,10 +584,11 @@ void con_write(struct tty_struct * tty)
                printk("con_write: illegal tty\n\r");
                return;
        }
-       while (!EMPTY(tty->write_q)) {
-               if (tty->stopped)
-                       break;
-               GETCH(tty->write_q,c);
+       if (vt_cons[currcons].vt_mode == KD_GRAPHICS) {
+               flush(tty->write_q);
+               return;                 /* no output in graphics mode */
+       }
+       while (!tty->stopped && (c = GETCH(tty->write_q)) >= 0) {
                if (c == 24 || c == 26)
                        state = ESnormal;
                switch(state) {
@@ -778,6 +785,7 @@ void con_write(struct tty_struct * tty)
                                                    par[1] <= video_num_lines) {
                                                        top=par[0];
                                                        bottom=par[1];
+                                                       gotoxy(currcons,0,0);
                                                }
                                                break;
                                        case 's':
@@ -828,19 +836,22 @@ void con_write(struct tty_struct * tty)
        }
        set_cursor(currcons);
        timer_active &= ~(1<<BLANK_TIMER);
-       if (console_blanked) {
-               timer_table[BLANK_TIMER].expires = 0;
-               timer_active |= 1<<BLANK_TIMER;
-       } else if (blankinterval) {
-               timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
-               timer_active |= 1<<BLANK_TIMER;
-       }
+       if (currcons == fg_console)
+               if (console_blanked) {
+                       timer_table[BLANK_TIMER].expires = 0;
+                       timer_active |= 1<<BLANK_TIMER;
+               } else if (blankinterval) {
+                       timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+                       timer_active |= 1<<BLANK_TIMER;
+               }
 }
 
 void do_keyboard_interrupt(void)
 {
        TTY_READ_FLUSH(TTY_TABLE(0));
        timer_active &= ~(1<<BLANK_TIMER);
+       if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+               return;
        if (console_blanked) {
                timer_table[BLANK_TIMER].expires = 0;
                timer_active |= 1<<BLANK_TIMER;
@@ -876,9 +887,7 @@ void con_init(void)
        char *display_desc = "????";
        char *display_ptr;
        int currcons = 0;
-       long base, term;
-       long video_memory;
-       long saveterm, savebase;
+       long base;
 
        video_num_columns = ORIG_VIDEO_COLS;
        video_size_row = video_num_columns * 2;
@@ -939,25 +948,20 @@ void con_init(void)
                display_ptr++;
        }
        
-       savebase = video_mem_base;
-       saveterm = video_mem_term;
        memsetw(vc_scrmembuf,video_erase_char,MEM_BUFFER_SIZE/2);
-       video_mem_base = (long)vc_scrmembuf;
-       video_mem_term = (long)&(vc_scrmembuf[MEM_BUFFER_SIZE/2]);
-       video_memory = video_mem_term - video_mem_base;
+       base = (long)vc_scrmembuf;
        screen_size = (video_num_lines * video_size_row);
-       NR_CONSOLES = video_memory / screen_size;
+       NR_CONSOLES = MEM_BUFFER_SIZE / screen_size;
        if (NR_CONSOLES > MAX_CONSOLES)
                NR_CONSOLES = MAX_CONSOLES;
        if (!NR_CONSOLES)
                NR_CONSOLES = 1;
-       video_memory = screen_size;
        
        /* Initialize the variables used for scrolling (mostly EGA/VGA) */
        
-       base = origin = video_mem_start = video_mem_base;
-       term = video_mem_end = base + video_memory;
-       scr_end = video_mem_start + screen_size;
+       base = origin = video_mem_start = (long)vc_scrmembuf;
+       scr_end = video_mem_end = base + screen_size;
+       vc_scrbuf[0] = (unsigned short *) origin;
        top     = 0;
        bottom  = video_num_lines;
        attr = 0x07;
@@ -970,22 +974,23 @@ void con_init(void)
        translate = NORM_TRANS;
        kbdleds = 2;
        kbdmode = 0;
+       kbdraw = 0;
+       kbde0 = 0;
        kbdapplic = 0;
+       vt_cons[0].vt_mode = KD_TEXT;
         vc_cons[0].vc_bold_attr = -1;
 
        gotoxy(currcons,ORIG_X,ORIG_Y);
        for (currcons = 1; currcons<NR_CONSOLES; currcons++) {
                vc_cons[currcons] = vc_cons[0];
-               origin = video_mem_start = (base += video_memory);
-               scr_end = origin + video_num_lines * video_size_row;
-               video_mem_end = (term += video_memory);
+               vt_cons[currcons] = vt_cons[0];
+               base += screen_size;
+               origin = video_mem_start = base;
+               scr_end = video_mem_end = base + screen_size;
+               vc_scrbuf[currcons] = (unsigned short *) origin;
                gotoxy(currcons,0,0);
        }
-       for (currcons = 0; currcons<NR_CONSOLES; currcons++) 
-               vc_scrbuf[currcons] = (unsigned short *)origin;
        currcons = 0;   
-       video_mem_base = savebase;
-       video_mem_term = saveterm;
        
        video_mem_start = video_mem_base;
        video_mem_end = video_mem_term;
@@ -1006,10 +1011,14 @@ void kbdsave(int new_console)
 {
        int currcons = fg_console;
        kbdmode = kmode;
+       kbdraw = kraw;
+       kbde0 = ke0;
        kbdleds = kleds;
        kbdapplic = kapplic;
        currcons = new_console;
        kmode = (kmode & 0x3F) | (kbdmode & 0xC0);
+       kraw = kbdraw;
+       ke0 = kbde0;
        kleds = kbdleds;
        kapplic = kbdapplic;
        set_leds();
@@ -1120,6 +1129,8 @@ void console_print(const char * b)
 
        if (currcons<0 || currcons>=NR_CONSOLES)
                currcons = 0;
+       if (vt_cons[currcons].vt_mode == KD_GRAPHICS)
+               return; /* no output in graphics mode */
        while (c = *(b++)) {
                if (c == 10) {
                        cr(currcons);
diff --git a/kernel/chr_drv/keyboard.S b/kernel/chr_drv/keyboard.S
deleted file mode 100644 (file)
index fa5e2b5..0000000
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- *  linux/kernel/keyboard.S
- *
- *  (C) 1991  Linus Torvalds
- */
-
-/*
- *     Thanks to Alfred Leung for US keyboard patches
- *             Wolfgang Thiel for German keyboard patches
- *             Marc Corsini for the French keyboard
- *             LeBlanc@mcc.ac.uk for the UK keyboard
- *             Tommy Thorn (tthorn@daimi.aau.dk) for Danish keyboard
- */
-
-/* KBD_FINNISH for Finnish keyboards
- * KBD_US for US-type
- * KBD_GR for German keyboards
- * KBD_FR for Frech keyboard
- * KBD_UK for British extended keyboard
- * KBD_DK for Danish keyboard
- */
-
-.text
-.globl _hard_reset_now
-.globl _keyboard_interrupt
-.globl _kapplic
-.globl _kmode
-.globl _kleds
-.globl _set_leds
-
-/*
- * these are for the keyboard read functions
- */
-size   = 2048          /* must be a power of two ! And MUST be the same
-                          as in tty_io.c !!!! */
-head = 4
-tail = 8
-proc_list = 12
-buf = 16
-
-_kapplic:      .byte 0
-_kmode:        .byte 0         /* caps, alt, ctrl and shift mode */
-_kleds:        .byte 2         /* num-lock, caps, scroll-lock mode (nom-lock on) */
-e0:    .byte 0
-
-/*
- *  con_int is the real interrupt routine that reads the
- *  keyboard scan-code and converts it into the appropriate
- *  ascii character(s).
- */
-_keyboard_interrupt:
-       cld
-       pushl %eax
-       pushl %ebx
-       pushl %ecx
-       pushl %edx
-       push %ds
-       push %es
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       xorl %eax,%eax          /* %eax is scan code */
-       inb $0x60,%al
-       pushl %eax
-       inb $0x61,%al
-       jmp 1f
-1:     jmp 1f
-1:     orb $0x80,%al
-       jmp 1f
-1:     jmp 1f
-1:     outb %al,$0x61
-       jmp 1f
-1:     jmp 1f
-1:     andb $0x7F,%al
-       outb %al,$0x61
-       jmp 1f
-1:     jmp 1f
-1:     movb $0x20,%al
-       outb %al,$0x20
-       popl %eax
-       movl $1,%ebx
-       cmpb $0xE0,%al
-       je end_intr
-       movl $2,%ebx
-       cmpb $0xE1,%al
-       je end_intr
-       sti
-       call key_table(,%eax,4)
-       call _do_keyboard_interrupt
-       movl $0,%ebx
-end_intr:
-       movb %bl,e0
-       pop %es
-       pop %ds
-       popl %edx
-       popl %ecx
-       popl %ebx
-       popl %eax
-       iret
-
-/*
- * This routine fills the buffer with max 8 bytes, taken from
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
-       pushl %ecx
-       pushl %edx
-       movl _table_list,%edx           # read-queue for console
-       movl head(%edx),%ecx
-1:     movb %al,buf(%edx,%ecx)
-       incl %ecx
-       andl $size-1,%ecx
-       cmpl tail(%edx),%ecx            # buffer full - discard everything
-       je 3f
-       shrdl $8,%ebx,%eax
-       je 2f
-       shrl $8,%ebx
-       jmp 1b
-2:     movl %ecx,head(%edx)
-       movl proc_list(%edx),%ecx
-       testl %ecx,%ecx
-       je 3f
-       movl $0,(%ecx)
-3:     popl %edx
-       popl %ecx
-       ret
-
-ctrl:  movb $0x04,%al
-       jmp 1f
-alt:   movb $0x10,%al
-1:     cmpb $0,e0
-       je 2f
-       addb %al,%al
-2:     orb %al,_kmode
-       ret
-unctrl:        movb $0x04,%al
-       jmp 1f
-unalt: movb $0x10,%al
-1:     cmpb $0,e0
-       je 2f
-       addb %al,%al
-2:     notb %al
-       andb %al,_kmode
-       ret
-
-lshift:
-       orb $0x01,_kmode
-       ret
-unlshift:
-       andb $0xfe,_kmode
-       ret
-rshift:
-       orb $0x02,_kmode
-       ret
-unrshift:
-       andb $0xfd,_kmode
-       ret
-
-old_leds:
-       .byte 2
-
-caps:  testb $0x80,_kmode
-       jne 1f
-       xorb $4,_kleds
-       xorb $0x40,_kmode
-       orb $0x80,_kmode
-_set_leds:
-       movb _kleds,%al
-       cmpb old_leds,%al
-       je 1f
-       movb %al,old_leds
-       call kb_wait
-       movb $0xed,%al          /* set leds command */
-       outb %al,$0x60
-       call kb_wait
-       movb _kleds,%al
-       outb %al,$0x60
-1:     ret
-uncaps:        andb $0x7f,_kmode
-       ret
-scroll:
-       testb $0x03,_kmode
-       je 1f
-       call _show_mem
-       jmp 2f
-1:     call _show_state
-2:     xorb $1,_kleds
-       jmp _set_leds
-       
-num:   cmpb $0x01,_kapplic
-       jne notappl
-       movw $0x0050,%ax
-applkey:
-       shll $16,%eax
-       movw $0x4f1b,%ax
-       xorl %ebx,%ebx
-       jmp put_queue
-notappl:
-       xorb $2,_kleds
-       jmp _set_leds
-
-/*
- *  cursor-key/numeric keypad cursor keys are handled here.
- *  checking for numeric keypad etc.
- */
-cursor:
-       subb $0x47,%al
-       jb 1f
-       cmpb $12,%al
-       ja 1f
-       jne cur2                /* check for ctrl-alt-del */
-       testb $0x0c,_kmode
-       je cur2
-       testb $0x30,_kmode
-       jne _ctrl_alt_del
-cur2:  cmpb $0x01,e0           /* e0 forces cursor movement */
-       je cur
-       testb $0x03,_kmode      /* shift forces cursor */
-       jne cur
-       cmpb $0x01,_kapplic
-       jne notcappl
-       movb appl_table(%eax),%al
-       jmp applkey
-notcappl:
-       testb $0x02,_kleds      /* not num-lock forces cursor */
-       je cur
-       xorl %ebx,%ebx
-       movb num_table(%eax),%al
-       jmp put_queue
-1:     ret
-
-/*
- * cursor keys send ^[ [ x if normal, ^[ O x if application mode
- */
-cur:   movb cur_table(%eax),%al
-       cmpb $'9,%al
-       ja ok_cur
-       movb $'~,%ah
-ok_cur:        shll $16,%eax
-       movw $0x5b1b,%ax
-       xorl %ebx,%ebx
-       cmpb $0x01,_kapplic
-       jne put_queue
-       movb $0x4f,%ah
-       jmp put_queue
-
-#if defined(KBD_FR) /* || defined(KBD_DK) correct, but .. */
-num_table:
-       .ascii "789-456+1230."
-#else
-num_table:
-       .ascii "789-456+1230,"
-#endif
-cur_table:
-       .ascii "HA5-DGC+YB623"
-       
-/*     
-    Keypad /                   35      B7      Q
-    Keypad *  (PrtSc)          37      B7      R
-    Keypad NumLock                     45      ??      P
-    Keypad 7  (Home)           47      C7      w
-    Keypad 8  (Up arrow)       48      C8      x
-    Keypad 9  (PgUp)           49      C9      y
-    Keypad -                   4A      CA      S
-    Keypad 4  (Left arrow)     4B      CB      t
-    Keypad 5                   4C      CC      u
-    Keypad 6  (Right arrow)    4D      CD      v
-    Keypad +                   4E      CE      l
-    Keypad 1  (End)            4F      CF      q
-    Keypad 2  (Down arrow)     50      D0      r
-    Keypad 3  (PgDn)           51      D1      s
-    Keypad 0  (Ins)            52      D2      p
-    Keypad .  (Del)            53      D3      n
-*/    
-appl_table:
-       .ascii "wxyStuvlqrspn"
-
-/*
- * this routine handles function keys
- */
-func:
-       subb $0x3B,%al
-       jb end_func
-       cmpb $9,%al
-       jbe ok_func
-       subb $18,%al
-       cmpb $10,%al
-       jb end_func
-       cmpb $11,%al
-       ja end_func
-ok_func:
-       testb $0x10,_kmode
-       jne alt_func
-       cmpl $4,%ecx            /* check that there is enough room */
-       jl end_func
-       movl func_table(,%eax,4),%eax
-       xorl %ebx,%ebx
-       jmp put_queue
-alt_func:
-       pushl %eax
-       call _change_console
-       popl %eax
-end_func:
-       ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
-       .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
-       .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
-       .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if    defined(KBD_FINNISH)
-key_map:
-       .byte 0,27
-       .ascii "1234567890+'"
-       .byte 127,9
-       .ascii "qwertyuiop}"
-       .byte 0,13,0
-       .ascii "asdfghjkl|{"
-       .byte 0,0
-       .ascii "'zxcvbnm,.-"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '<
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "!\"#$%&/()=?`"
-       .byte 127,9
-       .ascii "QWERTYUIOP]^"
-       .byte 13,0
-       .ascii "ASDFGHJKL\\["
-       .byte 0,0
-       .ascii "*ZXCVBNM;:_"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '>
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0@\0$\0\0{[]}\\\0"
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-#elif defined(KBD_US)
-
-key_map:
-       .byte 0,27
-       .ascii "1234567890-="
-       .byte 127,9
-       .ascii "qwertyuiop[]"
-       .byte 13,0
-       .ascii "asdfghjkl;'"
-       .byte '`,0
-       .ascii "\\zxcvbnm,./"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '<
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "!@#$%^&*()_+"
-       .byte 127,9
-       .ascii "QWERTYUIOP{}"
-       .byte 13,0
-       .ascii "ASDFGHJKL:\""
-       .byte '~,0
-       .ascii "|ZXCVBNM<>?"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '>
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0@\0$\0\0{[]}\\\0"
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-#elif defined(KBD_UK)
-
-key_map:
-       .byte 0,27
-       .ascii "1234567890-="
-       .byte 127,9
-       .ascii "qwertyuiop[]"
-       .byte 13,0
-       .ascii "asdfghjkl;'"
-       .byte '`,0
-       .ascii "#zxcvbnm,./"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .ascii "\\"
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "!\"#$%^&*()_+"
-       .byte 127,9
-       .ascii "QWERTYUIOP{}"
-       .byte 13,0
-       .ascii "ASDFGHJKL:@"
-       .byte '~,0
-       .ascii "~ZXCVBNM<>?"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0@\0$\0\0{[]}\\\0"
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-#elif defined(KBD_GR)
-
-key_map:
-       .byte 0,27
-       .ascii "1234567890\\'"
-       .byte 127,9
-       .ascii "qwertzuiop@+"
-       .byte 13,0
-       .ascii "asdfghjkl[]^"
-       .byte 0,'#
-       .ascii "yxcvbnm,.-"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '<
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "!\"#$%&/()=?`"
-       .byte 127,9
-       .ascii "QWERTZUIOP\\*"
-       .byte 13,0
-       .ascii "ASDFGHJKL{}~"
-       .byte 0,''
-       .ascii "YXCVBNM;:_"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '>
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0@\0$\0\0{[]}\\\0"
-       .byte 0,0
-       .byte '@,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-#elif defined(KBD_FR)
-
-key_map:
-       .byte 0,27
-       .ascii "&{\"'(-}_/@)="
-       .byte 127,9
-       .ascii "azertyuiop^$"
-       .byte 13,0
-       .ascii "qsdfghjklm|"
-       .byte '`,0,42           /* coin sup gauche, don't know, [*|mu] */
-       .ascii "wxcvbn,;:!"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '<
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "1234567890]+"
-       .byte 127,9
-       .ascii "AZERTYUIOP<>"
-       .byte 13,0
-       .ascii "QSDFGHJKLM%"
-       .byte '~,0,'#
-       .ascii "WXCVBN?./\\"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '>
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0~#{[|`\\^@]}"
-       .byte 0,0
-       .byte '@,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '|
-       .fill 10,1,0
-
-#elif defined(KBD_DK)
-
-key_map:
-       .byte 0,27
-       .ascii "1234567890+'"
-       .byte 127,9
-       .ascii "qwertyuiop"
-       .byte 134,0,13,0        /* This is IBM-PC, change it to latin-1 */
-       .ascii "asdfghjkl"
-       .byte 145,155,0,0
-       .ascii "'zxcvbnm,.-"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '<
-       .fill 10,1,0
-
-shift_map:
-       .byte 0,27
-       .ascii "!\"#$%&/()=?`"
-       .byte 127,9
-       .ascii "QWERTYUIOP"
-       .byte 143,94,13,0
-       .ascii "ASDFGHJKL"
-       .byte 146,157,0,0
-       .ascii "*ZXCVBNM;:_"
-       .byte 0,'*,0,32         /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte '-,0,0,0,'+       /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .byte '>
-       .fill 10,1,0
-
-alt_map:
-       .byte 0,0
-       .ascii "\0@\0$\0\0{[]}\0"
-       .byte '|,0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte '~,13,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0
-       .byte 0,0,0,0,0,0,0,0,0,0,0
-       .byte 0,0,0,0           /* 36-39 */
-       .fill 16,1,0            /* 3A-49 */
-       .byte 0,0,0,0,0         /* 4A-4E */
-       .byte 0,0,0,0,0,0,0     /* 4F-55 */
-       .ascii "\\"
-       .fill 10,1,0
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
-       lea alt_map,%ebx
-       testb $0x20,_kmode              /* alt-gr */
-       jne 1f
-       lea shift_map,%ebx
-       testb $0x0f,_kmode
-       jne 1f
-       lea key_map,%ebx
-1:     movb (%ebx,%eax),%al
-       orb %al,%al
-       je none
-       testb $0x4c,_kmode              /* ctrl or caps */
-       je 2f
-       cmpb $'a,%al
-       jb 2f
-       cmpb $'},%al
-       ja 2f
-       subb $32,%al
-2:     testb $0x0c,_kmode              /* ctrl */
-       je 3f
-       andb $0x1f,%al
-3:     testb $0x10,_kmode              /* left alt */
-       je 4f
-       orb $0x80,%al
-4:     andl $0xff,%eax
-       xorl %ebx,%ebx
-       call put_queue
-none:  ret
-
-/*
- * slash and star have routines of their own, as a 'E0h' before
- * the scan code for slash means that the numeric keypad
- * slash was pushed.
- */
-slash: cmpb $1,e0
-       jne do_self
-       cmpb $1,_kapplic
-       jne notmapplic
-       movw $'Q,%ax
-       jmp applkey
-       
-notmapplic:
-       movl $'/,%eax
-       xorl %ebx,%ebx
-       jmp put_queue
-
-star:  cmpb $1,_kapplic
-       jne do_self
-       movw $'R,%ax
-       jmp applkey
-       
-notsapplic:
-       movl $'*,%eax
-       xorl %ebx,%ebx
-       jmp put_queue
-
-enter: cmpb $1,e0
-       jne do_self
-       cmpb $1,_kapplic
-       jne do_self
-       movw $'M,%ax
-       jmp applkey
-       
-minus: cmpb $1,_kapplic
-       jne do_self
-       movw $'S,%ax
-       jmp applkey
-       
-plus:  cmpb $1,_kapplic
-       jne do_self
-       movw $'l,%ax
-       jmp applkey
-       
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
-       .long none,do_self,do_self,do_self      /* 00-03 s0 esc 1 2 */
-       .long do_self,do_self,do_self,do_self   /* 04-07 3 4 5 6 */
-       .long do_self,do_self,do_self,do_self   /* 08-0B 7 8 9 0 */
-       .long do_self,do_self,do_self,do_self   /* 0C-0F + ' bs tab */
-       .long do_self,do_self,do_self,do_self   /* 10-13 q w e r */
-       .long do_self,do_self,do_self,do_self   /* 14-17 t y u i */
-       .long do_self,do_self,do_self,do_self   /* 18-1B o p } ^ */
-       .long enter,ctrl,do_self,do_self        /* 1C-1F enter ctrl a s */
-       .long do_self,do_self,do_self,do_self   /* 20-23 d f g h */
-       .long do_self,do_self,do_self,do_self   /* 24-27 j k l | */
-       .long do_self,do_self,lshift,do_self    /* 28-2B { para lshift , */
-       .long do_self,do_self,do_self,do_self   /* 2C-2F z x c v */
-       .long do_self,do_self,do_self,do_self   /* 30-33 b n m , */
-       .long do_self,slash,rshift,star         /* 34-37 . - rshift * */
-       .long alt,do_self,caps,func             /* 38-3B alt sp caps f1 */
-       .long func,func,func,func               /* 3C-3F f2 f3 f4 f5 */
-       .long func,func,func,func               /* 40-43 f6 f7 f8 f9 */
-       .long func,num,scroll,cursor            /* 44-47 f10 num scr home */
-       .long cursor,cursor,minus,cursor        /* 48-4B up pgup - left */
-       .long cursor,cursor,plus,cursor         /* 4C-4F n5 right + end */
-       .long cursor,cursor,cursor,cursor       /* 50-53 dn pgdn ins del */
-       .long none,none,do_self,func            /* 54-57 sysreq ? < f11 */
-       .long func,none,none,none               /* 58-5B f12 ? ? ? */
-       .long none,none,none,none               /* 5C-5F ? ? ? ? */
-       .long none,none,none,none               /* 60-63 ? ? ? ? */
-       .long none,none,none,none               /* 64-67 ? ? ? ? */
-       .long none,none,none,none               /* 68-6B ? ? ? ? */
-       .long none,none,none,none               /* 6C-6F ? ? ? ? */
-       .long none,none,none,none               /* 70-73 ? ? ? ? */
-       .long none,none,none,none               /* 74-77 ? ? ? ? */
-       .long none,none,none,none               /* 78-7B ? ? ? ? */
-       .long none,none,none,none               /* 7C-7F ? ? ? ? */
-       .long none,none,none,none               /* 80-83 ? br br br */
-       .long none,none,none,none               /* 84-87 br br br br */
-       .long none,none,none,none               /* 88-8B br br br br */
-       .long none,none,none,none               /* 8C-8F br br br br */
-       .long none,none,none,none               /* 90-93 br br br br */
-       .long none,none,none,none               /* 94-97 br br br br */
-       .long none,none,none,none               /* 98-9B br br br br */
-       .long none,unctrl,none,none             /* 9C-9F br unctrl br br */
-       .long none,none,none,none               /* A0-A3 br br br br */
-       .long none,none,none,none               /* A4-A7 br br br br */
-       .long none,none,unlshift,none           /* A8-AB br br unlshift br */
-       .long none,none,none,none               /* AC-AF br br br br */
-       .long none,none,none,none               /* B0-B3 br br br br */
-       .long none,none,unrshift,none           /* B4-B7 br br unrshift br */
-       .long unalt,none,uncaps,none            /* B8-BB unalt br uncaps br */
-       .long none,none,none,none               /* BC-BF br br br br */
-       .long none,none,none,none               /* C0-C3 br br br br */
-       .long none,none,none,none               /* C4-C7 br br br br */
-       .long none,none,none,none               /* C8-CB br br br br */
-       .long none,none,none,none               /* CC-CF br br br br */
-       .long none,none,none,none               /* D0-D3 br br br br */
-       .long none,none,none,none               /* D4-D7 br br br br */
-       .long none,none,none,none               /* D8-DB br ? ? ? */
-       .long none,none,none,none               /* DC-DF ? ? ? ? */
-       .long none,none,none,none               /* E0-E3 e0 e1 ? ? */
-       .long none,none,none,none               /* E4-E7 ? ? ? ? */
-       .long none,none,none,none               /* E8-EB ? ? ? ? */
-       .long none,none,none,none               /* EC-EF ? ? ? ? */
-       .long none,none,none,none               /* F0-F3 ? ? ? ? */
-       .long none,none,none,none               /* F4-F7 ? ? ? ? */
-       .long none,none,none,none               /* F8-FB ? ? ? ? */
-       .long none,none,none,none               /* FC-FF ? ? ? ? */
-
-/*
- * kb_wait waits for the keyboard controller buffer to empty.
- */
-kb_wait:
-       pushl %eax
-       pushl %ebx
-       movl $10000,%ebx
-1:     inb $0x64,%al
-       testb $0x02,%al
-       je 2f
-       decl %ebx
-       jne 1b
-2:     popl %ebx
-       popl %eax
-       ret
-
-no_idt:
-       .long 0,0
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low. We try that for a while,
- * and if it doesn't work, we do some other stupid things.
- */
-_hard_reset_now:
-       sti
-       movl $100,%ebx
-1:     call kb_wait
-       movw $0x1234,0x472      /* don't do memory check */
-       movb $0xfe,%al          /* pulse reset low */
-       outb %al,$0x64
-       decl %ebx
-       jne 1b
-       lidt no_idt             /* zero-length idt: should triple-fault */
-       jmp _hard_reset_now
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
new file mode 100644 (file)
index 0000000..1398059
--- /dev/null
@@ -0,0 +1,1107 @@
+/*
+ * linux/kernel/chr_drv/keyboard.c
+ *
+ * Keyboard driver for Linux v0.96 using Latin-1.
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ */
+
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define LSHIFT   0x01
+#define RSHIFT   0x02
+#define LCTRL    0x04
+#define RCTRL    0x08
+#define ALT      0x10
+#define ALTGR    0x20
+#define CAPS     0x40
+#define CAPSDOWN 0x80
+
+#define SCRLED   0x01
+#define NUMLED   0x02
+#define CAPSLED  0x04
+
+#define NO_META_BIT 0x80
+
+unsigned char kapplic = 0;
+unsigned char kmode = 0;
+unsigned char kleds = NUMLED;
+unsigned char ke0 = 0;
+unsigned char kraw = 0;
+unsigned char kbd_flags = KBDFLAGS;
+
+extern void do_keyboard_interrupt(void);
+extern void ctrl_alt_del(void);
+extern void show_mem(void), show_state(void);
+extern void change_console(unsigned int new_console);
+extern struct tty_queue *table_list[];
+
+typedef void (*fptr)(int);
+
+static unsigned char old_leds = 2;
+static int diacr = -1;
+static int npadch = 0;
+fptr key_table[];
+
+static void put_queue(int);
+void set_leds(void);
+static void applkey(int);
+static void cur(int);
+static void kb_wait(void), kb_ack(void);
+static unsigned int handle_diacr(unsigned int);
+
+void do_keyboard(void)
+{
+       unsigned char scancode, x;
+
+       scancode=inb_p(0x60);
+       x=inb_p(0x61);
+       outb_p(x|0x80, 0x61);
+       outb_p(x&0x7f, 0x61);
+       outb(0x20, 0x20);
+       sti();
+
+       if (kraw) {
+               put_queue(scancode);
+               do_keyboard_interrupt();
+       } else if (scancode == 0xe0)
+               ke0 = 1;
+       else if (scancode == 0xe1)
+               ke0 = 2;
+       else {
+               key_table[scancode](scancode);
+               do_keyboard_interrupt();
+               ke0 = 0;
+       }
+}
+
+static void put_queue(int ch)
+{
+       register struct tty_queue *qp = table_list[0];
+       unsigned long new_head;
+
+       qp->buf[qp->head]=ch;
+       if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail)
+               qp->head=new_head;
+       if (qp->proc_list != NULL)
+               qp->proc_list->state=0;
+}
+
+static void puts_queue(char *cp)
+{
+       register struct tty_queue *qp = table_list[0];
+       unsigned long new_head;
+       char ch;
+
+       while (ch=*cp++) {
+               qp->buf[qp->head]=ch;
+               if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1))
+                                != qp->tail)
+                       qp->head=new_head;
+       }
+       if (qp->proc_list != NULL)
+               qp->proc_list->state=0;
+}
+
+static void ctrl(int sc)
+{
+       if (ke0)
+               kmode|=RCTRL;
+       else
+               kmode|=LCTRL;
+}
+
+static void alt(int sc)
+{
+       if (ke0)
+               kmode|=ALTGR;
+       else
+               kmode|=ALT;
+}
+
+static void unctrl(int sc)
+{
+       if (ke0)
+               kmode&=(~RCTRL);
+       else
+               kmode&=(~LCTRL);
+}
+
+static void unalt(int sc)
+{
+       if (ke0)
+               kmode&=(~ALTGR);
+       else {
+               kmode&=(~ALT);
+               if (npadch != 0) {
+                       put_queue(npadch);
+                       npadch=0;
+               }
+       }
+}
+
+static void lshift(int sc)
+{
+       kmode|=LSHIFT;
+}
+
+static void unlshift(int sc)
+{
+       kmode&=(~LSHIFT);
+}
+
+static void rshift(int sc)
+{
+       kmode|=RSHIFT;
+}
+
+static void unrshift(int sc)
+{
+       kmode&=(~RSHIFT);
+}
+
+static void caps(int sc)
+{
+       if (!(kmode&CAPSDOWN)) {
+               kleds^=CAPSLED;
+               kmode^=CAPS;
+               kmode|=CAPSDOWN;
+               set_leds();
+       }
+}
+
+void set_leds(void)
+{
+       if (kleds != old_leds) {
+               old_leds=kleds;
+               kb_wait();
+               outb(0xed, 0x60);       /* set leds command */
+               kb_ack();
+               kb_wait();
+               outb(kleds, 0x60);
+               kb_ack();
+       }
+}
+
+static void uncaps(int sc)
+{
+       kmode&=(~CAPSDOWN);
+}
+
+static void scroll(int sc)
+{
+       if (kmode&(LSHIFT|RSHIFT))
+               show_mem();
+       else
+               show_state();
+       kleds^=SCRLED;
+       set_leds();
+}
+
+static void num(int sc)
+{
+       if (kapplic)
+               applkey(0x50);
+       else {
+               kleds^=NUMLED;
+               set_leds();
+       }
+}
+
+static void applkey(int key)
+{
+       char buf[] = { 0x1b, 0x4f, 0x00, 0x00 };
+
+       buf[2]=key;
+       puts_queue(buf);
+}
+
+
+#if defined KBD_FINNISH
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '+', '\'',  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  '}',    0,   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  '|',
+       '{',    0,    0, '\'',  'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!', '\"',  '#',  '$',  '%',  '&',
+       '/',  '(',  ')',  '=',  '?',  '`',  127,    9, 
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  ']',  '^',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L', '\\',
+       '[',    0,    0,  '*',  'Z',  'X',  'C',  'V',
+        'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',  163,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_FINNISH_LATIN1
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '+',  180,  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+        'o',  'p',  229,  168,   13,    0,  'a',  's',
+        'd',  'f',  'g',  'h',  'j',  'k',  'l',  246,
+       228,  167,    0, '\'',  'z',  'x',  'c',  'v',
+        'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+          0,   32,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+  
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '"',  '#',  '$',  '%',  '&',
+        '/',  '(',  ')',  '=',  '?',  '`',  127,    9,
+        'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  197,  '^',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  214,
+       196,  189,    0,  '*',  'Z',  'X',  'C',  'V',
+       'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',  163,  '$',    0,    0,
+        '{',  '[',  ']',  '}', '\\',    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+#elif defined KBD_US
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '-',  '=',  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  '[',  ']',   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',
+       '\'',  '`',    0, '\\',  'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '/',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0, 
+          0,    0,    0,    0,    0,    0,  '<',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '@',  '#',  '$',  '%',  '^',
+       '&',  '*',  '(',  ')',  '_',  '+',  127,    9,
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  '{',  '}',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',
+        '"',  '~',  '0',  '|',  'Z',  'X',  'C',  'V',
+       'B',  'N',  'M',  '<',  '>',  '?',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0, 
+          0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',    0,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_UK
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '-',  '=',  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  '[',  ']',   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',
+       '\'',  '`',    0,  '#',  'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '/',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0, 
+          0,    0,    0,    0,    0,    0, '\\',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '"',  163,  '$',  '%',  '^',
+       '&',  '*',  '(',  ')',  '_',  '+',  127,    9,
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  '{',  '}',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',
+        '@',  '~',  '0',  '~',  'Z',  'X',  'C',  'V',
+       'B',  'N',  'M',  '<',  '>',  '?',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0, 
+          0,    0,    0,    0,    0,    0,  '|',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',    0,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_GR
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0', '\\', '\'',  127,    9,
+       'q',  'w',  'e',  'r',  't',  'z',  'u',  'i',
+       'o',  'p',  '@',  '+',   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  '[',
+       ']',  '^',    0,  '#',  'y',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '"',  '#',  '$',  '%',  '&',
+       '/',  '(',  ')',  '=',  '?',  '`',  127,    9, 
+       'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I',
+       'O',  'P', '\\',  '*',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  '{',
+       '}',  '~',    0, '\'',  'Y',  'X',  'C',  'V',
+        'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',    0,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+        '@',    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_GR_LATIN1
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0', 223,  180,  127,    9,
+       'q',  'w',  'e',  'r',  't',  'z',  'u',  'i',
+       'o',  'p',  252,  '+',   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l', 246,
+       228,   94,    0,  '#',  'y',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '"',  167,  '$',  '%',  '&',
+       '/',  '(',  ')',  '=',  '?',  '`',  127,    9, 
+       'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I',
+       'O',  'P',  220,  '*',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  214,
+        196,  176,    0, '\'',  'Y',  'X',  'C',  'V',
+        'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  178,  179,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+        '@',    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  181,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_FR
+
+static unsigned char key_map[] = {
+         0,   27,  '&',  '{',  '"', '\'',  '(',  '-',
+       '}',  '_',  '/',  '@',  ')',  '=',  127,    9,
+       'a',  'z',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  '^',  '$',   13,    0,  'q',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  'm',
+       '|',  '`',    0,   42,  'w',  'x',  'c',  'v',
+       'b',  'n',  ',',  ';',  ':',  '!',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  ']',  '+',  127,    9, 
+       'A',  'Z',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  '<',  '>',   13,    0,  'Q',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  'M',
+       '%',  '~',    0,  '#',  'W',  'X',  'C',  'V',
+        'B',  'N',  '?',  '.',  '/', '\\',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '~',  '#',  '{',  '[',  '|',
+        '`', '\\',   '^',  '@', ']',  '}',    0,    0,
+        '@',    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_FR_LATIN1
+
+static unsigned char key_map[] = {
+         0,   27,  '&',  233,  '"', '\'',  '(',  '-',
+        232,  '_',  231,  224,  ')',  '=',  127,    9,
+       'a',  'z',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  '^',  '$',   13,    0,  'q',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  'm',
+       249,  178,    0,   42,  'w',  'x',  'c',  'v',
+       'b',  'n',  ',',  ';',  ':',  '!',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  176,  '+',  127,    9, 
+       'A',  'Z',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  168,  163,   13,    0,  'Q',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  'M',
+       '%',    0,    0,  181,  'W',  'X',  'C',  'V',
+        'B',  'N',  '?',  '.',  '/',  167,    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '~',  '#',  '{',  '[',  '|',
+        '`', '\\',   '^',  '@', ']',  '}',    0,    0,
+        '@',    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  164,   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_DK
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '+', '\'',  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  229,    0,   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  230,
+       162,    0,    0, '\'',  'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!', '\"',  '#',  '$',  '%',  '&',
+       '/',  '(',  ')',  '=',  '?',  '`',  127,    9, 
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  197,  '^',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  198,
+       165,    0,    0,  '*',  'Z',  'X',  'C',  'V',
+        'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',  163,  '$',    0,    0,
+        '{',   '[',  ']', '}',    0,  '|',    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_DK_LATIN1
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0',  '+',  180,  127,    9,
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',
+       'o',  'p',  229,  168,   13,    0,  'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  230,
+       162,  189,    0, '\'',  'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '-',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,  '-',    0,    0,    0,  '+',    0,
+          0,    0,    0,    0,    0,    0,  '<',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!', '\"',  '#',  '$',  '%',  '&',
+       '/',  '(',  ')',  '=',  '?',  '`',  127,    9, 
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',
+       'O',  'P',  197,  '^',   13,    0,  'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  198,
+       165,  167,    0,  '*',  'Z',  'X',  'C',  'V',
+        'B',  'N',  'M',  ';',  ':',  '_',    0,  '*',
+         0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '>',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',  163,  '$',    0,    0,
+        '{',   '[',  ']', '}',    0,  '|',    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0, '\\',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#elif defined KBD_DVORAK
+
+static unsigned char key_map[] = {
+         0,   27,  '1',  '2',  '3',  '4',  '5',  '6',
+       '7',  '8',  '9',  '0', '\\',  '=',  127,    9,
+       '\'',  ',',  '.',  'p',  'y',  'f',  'g',  'c',
+        'r',  'l',  '/',  ']',   13,    0,  'a',  'o',
+       'e',  'u',  'i',  'd',  'h',  't',  'n',  's',
+        '-',  '`',    0,  '[',  ';',  'q',  'j',  'k',
+       'x',  'b',  'm',  'w',  'v',  'z',    0,  '*',
+          0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '<',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char shift_map[] = {
+         0,   27,  '!',  '@',  '#',  '$',  '%',  '^',
+       '&',  '*',  '(',  ')',  '|',  '+',  127,    9,
+        '"',  '<',  '>',  'P',  'Y',  'F',  'G',  'C',
+       'R',  'L',  '?',  '}',   13,    0,  'A',  'O',
+       'E',  'U',  'I',  'D',  'H',  'T',  'N',  'S',
+       '_',  '~',    0,  '{',  ':',  'Q',  'J',  'K',
+       'X',  'B',  'M',  'W',  'V',  'Z',    0,  '*',
+          0,   32,    0,    0,    0,    0,    0,    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+         0,    0,  '-',    0,    0,    0,  '+',    0,
+         0,    0,    0,    0,    0,    0,  '<',    0,
+         0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+static unsigned char alt_map[] = {
+         0,    0,    0,  '@',    0,  '$',    0,    0,
+        '{',   '[',  ']', '}', '\\',    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,  '~',   13,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0,    0,    0,    0,    0,    0,  '|',    0,
+          0,    0,    0,    0,    0,    0,    0,    0,
+          0 };
+
+#else
+#error "KBD-type not defined"
+#endif
+
+static void do_self(int sc)
+{
+       unsigned char ch;
+
+       if (kmode&ALTGR)
+               ch=alt_map[sc];
+       else if (kmode&(LSHIFT|RSHIFT|LCTRL|RCTRL))
+               ch=shift_map[sc];
+       else
+               ch=key_map[sc];
+
+       if (ch == 0)
+               return;
+
+       if ((ch=handle_diacr(ch)) == 0)
+               return;
+
+       if (kmode&(LCTRL|RCTRL|CAPS))           /* ctrl or caps */
+               if ((ch>='a' && ch <='z') || (ch>=224 && ch<=254))
+                       ch -= 32;
+       if (kmode&(LCTRL|RCTRL))                /* ctrl */
+               ch &= 0x1f;
+
+       if (kmode&ALT)
+               if (kbd_flags&NO_META_BIT) {
+                       put_queue('\033');
+                       put_queue(ch);
+               } else
+                       put_queue(ch|0x80);
+       else
+               put_queue(ch);
+}
+
+unsigned char accent_table[5][64] = {
+       " \300BCD\310FGH\314JKLMN\322PQRST\331VWXYZ[\\]^_"
+       "`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~",   /* accent grave */
+
+       " \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_"
+       "`\341bcd\351fgh\355jklmn\363pqrst\372vwxyz{|}~",   /* accent acute */
+
+       " \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
+       "`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~",   /* circumflex */
+
+       " \303BCDEFGHIJKLMN\325PQRSTUVWXYZ[\\]^_"
+       "`\343bcdefghijklm\361\365pqrstuvwxyz{|}~",         /* tilde */
+
+       " \304BCD\313FGH\316JKLMN\326PQRST\334VWXYZ[\\]^_"
+       "`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
+};
+
+
+/*
+ * Check if dead key pressed. If so, check if same key pressed twice;
+ * in that case return the char, otherwise store char and return 0.
+ * If dead key not pressed, check if accented character pending. If
+ * not: return the char, otherwise check if char is a space. If it is
+ * a space return the diacritical. Else combine char with diacritical
+ * mark and return.
+ */
+
+unsigned int handle_diacr(unsigned int ch)
+{
+       static unsigned char diacr_table[] =
+               {'`', 180, '^', '~', 168, 0};           /* Must end with 0 */
+       int i;
+
+       for(i=0; diacr_table[i]; i++)
+               if (ch==diacr_table[i] && ((1<<i)&kbd_flags)) {
+                       if (diacr == i) {
+                               diacr=-1;
+                               return ch;              /* pressed twice */
+                       } else {
+                               diacr=i;                /* key is dead */
+                               return 0;
+                       }
+               }
+       if (diacr == -1)
+               return ch;
+       else if (ch == ' ') {
+               ch=diacr_table[diacr];
+               diacr=-1;
+               return ch;
+       } else if (ch<64 || ch>122) {
+               diacr=-1;
+               return ch;
+       } else {
+               ch=accent_table[diacr][ch-64];
+               diacr=-1;
+               return ch;
+       }
+}
+               
+
+#if defined KBD_FR
+static unsigned char num_table[] = "789-456+1230.";
+#else
+static unsigned char num_table[] = "789-456+1230,";
+#endif
+
+static unsigned char cur_table[] = "HA5-DGC+YB623";
+static unsigned int pad_table[] = { 7,8,9,0,4,5,6,0,1,2,3,0,0 };
+
+/*     
+    Keypad /                   35      B7      Q
+    Keypad *  (PrtSc)          37      B7      R
+    Keypad NumLock                     45      ??      P
+    Keypad 7  (Home)           47      C7      w
+    Keypad 8  (Up arrow)       48      C8      x
+    Keypad 9  (PgUp)           49      C9      y
+    Keypad -                   4A      CA      S
+    Keypad 4  (Left arrow)     4B      CB      t
+    Keypad 5                   4C      CC      u
+    Keypad 6  (Right arrow)    4D      CD      v
+    Keypad +                   4E      CE      l
+    Keypad 1  (End)            4F      CF      q
+    Keypad 2  (Down arrow)     50      D0      r
+    Keypad 3  (PgDn)           51      D1      s
+    Keypad 0  (Ins)            52      D2      p
+    Keypad .  (Del)            53      D3      n
+*/    
+
+static unsigned char appl_table[] = "wxyStuvlqrspn";
+
+static char *func_table[] = {
+       "\033[[A", "\033[[B", "\033[[C", "\033[[D",
+       "\033[[E", "\033[[F", "\033[[G", "\033[[H",
+       "\033[[I", "\033[[J", "\033[[K", "\033[[L" 
+};
+
+
+static void cursor(int sc)
+{
+       if (sc < 0x47 || sc > 0x53)
+               return;
+       sc-=0x47;
+       if (sc == 12 && (kmode&(LCTRL|RCTRL)) && (kmode&(ALT|ALTGR))) {
+               ctrl_alt_del();
+               return;
+       }
+       if (ke0 == 1) {
+               cur(sc);
+               return;
+       }
+
+       if ((kmode&ALT) && sc!=12) {                  /* Alt-numpad */
+               npadch=npadch*10+pad_table[sc];
+               return;
+       }
+
+       if (kapplic && !(kmode&(LSHIFT|RSHIFT))) {    /* shift forces cursor */
+               applkey(appl_table[sc]);
+               return;
+       }
+
+       if (kleds&NUMLED) {
+               put_queue(num_table[sc]);
+       } else
+               cur(sc);
+}
+
+static void cur(int sc)
+{
+       char buf[] = { 0x1b, '[', 0, 0, 0 };          /* must not be static */
+
+       buf[2]=cur_table[sc];
+       if (buf[2] < '9')
+               buf[3]='~';
+       if (kapplic)
+               buf[1]='O';
+       puts_queue(buf);
+}
+
+static void func(int sc)
+{
+       if (sc < 0x3b)
+               return;
+       sc-=0x3b;
+       if (sc > 9) {
+               sc-=18;
+               if (sc < 10 || sc > 11)
+                       return;
+       }
+       if (kmode&ALT)
+               change_console(sc);
+       else
+               puts_queue(func_table[sc]);
+}      
+       
+
+static void slash(int sc)
+{
+       if (ke0 != 1)
+               do_self(sc);
+       else if (kapplic)
+               applkey('Q');
+       else
+               put_queue('/');
+}
+
+static void star(int sc)
+{
+       if (kapplic)
+               applkey('R');
+       else
+               do_self(sc);
+}
+
+static void enter(int sc)
+{
+       if (ke0 != 1)
+               do_self(sc);
+       else if (kapplic)
+               applkey('M');
+       else
+               do_self(sc);
+}
+
+static void minus(int sc)
+{
+       if (kapplic)
+               applkey('S');
+       else
+               do_self(sc);
+}
+
+static void plus(int sc)
+{
+       if (kapplic)
+               applkey('l');
+       else
+               do_self(sc);
+}
+
+
+static void none(int sc)
+{
+}
+
+
+/*
+ * kb_wait waits for the keyboard controller buffer to empty.
+ */
+
+static void kb_wait(void)
+{
+       int i;
+
+       for (i=0; i<0x10000; i++)
+               if ((inb(0x64)&0x02) == 0)
+                       break;
+}
+
+/*
+ * kb_ack waits for 0xfa to appear in port 0x60
+ *
+ * Suggested by Bruce Evans
+ * Added by Niels Skou Olsen [NSO]
+ * April 21, 1992
+ *
+ * Heavily inspired by kb_wait :-)
+ * I don't know how much waiting actually is required,
+ * but this seems to work
+ */
+
+void kb_ack(void)
+{
+       int i;
+
+       for(i=0; i<0x10000; i++)
+               if (inb(0x64) == 0xfa)
+                       break;
+}
+
+long no_idt[2] = {0, 0};
+
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ */
+void hard_reset_now(void)
+{
+       int i;
+
+       sti();
+       for (;;) {
+               for (i=0; i<100; i++) {
+                       kb_wait();
+                       *((unsigned short *)0x472)=0x1234;
+                       outb(0xfe,0x64);         /* pulse reset low */
+               }
+               __asm__("\tlidt _no_idt"::);
+       }
+}
+       
+
+static fptr key_table[] = {
+       none,do_self,do_self,do_self,           /* 00-03 s0 esc 1 2 */
+       do_self,do_self,do_self,do_self,        /* 04-07 3 4 5 6 */
+       do_self,do_self,do_self,do_self,        /* 08-0B 7 8 9 0 */
+       do_self,do_self,do_self,do_self,        /* 0C-0F + ' bs tab */
+       do_self,do_self,do_self,do_self,        /* 10-13 q w e r */
+       do_self,do_self,do_self,do_self,        /* 14-17 t y u i */
+       do_self,do_self,do_self,do_self,        /* 18-1B o p } ^ */
+       enter,ctrl,do_self,do_self,             /* 1C-1F enter ctrl a s */
+       do_self,do_self,do_self,do_self,        /* 20-23 d f g h */
+       do_self,do_self,do_self,do_self,        /* 24-27 j k l | */
+       do_self,do_self,lshift,do_self,         /* 28-2B { para lshift , */
+       do_self,do_self,do_self,do_self,        /* 2C-2F z x c v */
+       do_self,do_self,do_self,do_self,        /* 30-33 b n m , */
+       do_self,slash,rshift,star,              /* 34-37 . - rshift * */
+       alt,do_self,caps,func,                  /* 38-3B alt sp caps f1 */
+       func,func,func,func,                    /* 3C-3F f2 f3 f4 f5 */
+       func,func,func,func,                    /* 40-43 f6 f7 f8 f9 */
+       func,num,scroll,cursor,                 /* 44-47 f10 num scr home */
+       cursor,cursor,minus,cursor,             /* 48-4B up pgup - left */
+       cursor,cursor,plus,cursor,              /* 4C-4F n5 right + end */
+       cursor,cursor,cursor,cursor,            /* 50-53 dn pgdn ins del */
+       none,none,do_self,func,                 /* 54-57 sysreq ? < f11 */
+       func,none,none,none,                    /* 58-5B f12 ? ? ? */
+       none,none,none,none,                    /* 5C-5F ? ? ? ? */
+       none,none,none,none,                    /* 60-63 ? ? ? ? */
+       none,none,none,none,                    /* 64-67 ? ? ? ? */
+       none,none,none,none,                    /* 68-6B ? ? ? ? */
+       none,none,none,none,                    /* 6C-6F ? ? ? ? */
+       none,none,none,none,                    /* 70-73 ? ? ? ? */
+       none,none,none,none,                    /* 74-77 ? ? ? ? */
+       none,none,none,none,                    /* 78-7B ? ? ? ? */
+       none,none,none,none,                    /* 7C-7F ? ? ? ? */
+       none,none,none,none,                    /* 80-83 ? br br br */
+       none,none,none,none,                    /* 84-87 br br br br */
+       none,none,none,none,                    /* 88-8B br br br br */
+       none,none,none,none,                    /* 8C-8F br br br br */
+       none,none,none,none,                    /* 90-93 br br br br */
+       none,none,none,none,                    /* 94-97 br br br br */
+       none,none,none,none,                    /* 98-9B br br br br */
+       none,unctrl,none,none,                  /* 9C-9F br unctrl br br */
+       none,none,none,none,                    /* A0-A3 br br br br */
+       none,none,none,none,                    /* A4-A7 br br br br */
+       none,none,unlshift,none,                /* A8-AB br br unlshift br */
+       none,none,none,none,                    /* AC-AF br br br br */
+       none,none,none,none,                    /* B0-B3 br br br br */
+       none,none,unrshift,none,                /* B4-B7 br br unrshift br */
+       unalt,none,uncaps,none,                 /* B8-BB unalt br uncaps br */
+       none,none,none,none,                    /* BC-BF br br br br */
+       none,none,none,none,                    /* C0-C3 br br br br */
+       none,none,none,none,                    /* C4-C7 br br br br */
+       none,none,none,none,                    /* C8-CB br br br br */
+       none,none,none,none,                    /* CC-CF br br br br */
+       none,none,none,none,                    /* D0-D3 br br br br */
+       none,none,none,none,                    /* D4-D7 br br br br */
+       none,none,none,none,                    /* D8-DB br ? ? ? */
+       none,none,none,none,                    /* DC-DF ? ? ? ? */
+       none,none,none,none,                    /* E0-E3 e0 e1 ? ? */
+       none,none,none,none,                    /* E4-E7 ? ? ? ? */
+       none,none,none,none,                    /* E8-EB ? ? ? ? */
+       none,none,none,none,                    /* EC-EF ? ? ? ? */
+       none,none,none,none,                    /* F0-F3 ? ? ? ? */
+       none,none,none,none,                    /* F4-F7 ? ? ? ? */
+       none,none,none,none,                    /* F8-FB ? ? ? ? */
+       none,none,none,none                     /* FC-FF ? ? ? ? */
+};
index 0f6e88fc35bd473d598ba907f23a52b4fbd6abe9..ed56ce15fbfaf5d3194eccac26914c59f817fa53 100644 (file)
@@ -3,12 +3,16 @@
   james_r_wiegand Exp james_r_wiegand $
 */
 
+/*
+ * Edited by Linus - cleaner interface etc. Still not using interrupts, so
+ * it eats more resources than necessary, but it was easy to code this way...
+ */
+
+#include <linux/sched.h>
 #define __LP_C__
 #include <linux/lp.h>
 
-#include <checkpoint.h>
-
-int lp_reset(int minor)
+static int lp_reset(int minor)
 {
        int testvalue;
 
@@ -20,31 +24,7 @@ int lp_reset(int minor)
        return LP_S(minor);
 }
 
-void lp_init(void)
-{
-       int offset = 0;
-       unsigned int testvalue = 0;
-       int count = 0;
-
-       /* take on all known port values */
-       for (offset = 0; offset < LP_NO; offset++) {
-               /* write to port & read back to check */
-               outb( LP_DUMMY, LP_B(offset));
-               for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
-                       ;
-               testvalue = inb(LP_B(offset));
-               if (testvalue != 255) {
-                       LP_F(offset) |= LP_EXIST;
-                       lp_reset(offset);
-                       printk("lp_init: lp%d exists (%d)\n", offset, testvalue);
-                       count++;
-               }
-       }
-       if (count == 0)
-               printk("lp_init: no lp devices found\n");
-}
-
-int lp_char(char lpchar, int minor)
+static int lp_char(char lpchar, int minor)
 {
        int retval = 0;
        unsigned long count  = 0; 
@@ -67,61 +47,102 @@ int lp_char(char lpchar, int minor)
        return LP_S(minor);
 }
 
-int lp_write(unsigned minor, char *buf, int count)
+static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
 {
        int  retval;
-       int  loop;
-       int  tcount;
+       unsigned int minor = MINOR(inode->i_rdev);
        char c, *temp = buf;
 
-       if (minor > LP_NO - 1)
-               return -ENODEV;
-       if ((LP_F(minor) & LP_EXIST) == 0)
-               return -ENODEV;
-
-/* if we aren't the "owner task", check if the old owner has died... */
-       if (LP_T(minor) != current->pid && (LP_F(minor) & LP_BUSY)) {
-               for(tcount = 0; tcount < NR_TASKS; tcount++) { 
-                       if (!task[tcount])
-                               continue;
-                       if (task[tcount]->state == TASK_ZOMBIE)
-                               continue;
-                       if (task[tcount]->pid == LP_T(minor)) {
-                               tcount = -1;
-                               break;
-                       }
-               }
-               if (tcount == -1)
-                       return -EBUSY;
-       }
-
-       LP_T(minor) = current->pid;
-       LP_F(minor) |= LP_BUSY;
-       LP_R(minor) = count;
        temp = buf;
-
-       for (loop = 0 ; loop < count ; loop++, temp++) {
-               c = get_fs_byte(temp);
+       while (count > 0) {
+               c = get_fs_byte(temp++);
                retval = lp_char(c, minor);
-               LP_R(minor)--;
+               count--;
                if (retval & LP_POUTPA) {
                        LP_F(minor) |= LP_NOPA;
-                       return loop?loop:-ENOSPC;
+                       return temp-buf?temp-buf:-ENOSPC;
                } else
                        LP_F(minor) &= ~LP_NOPA;
 
                if (!(retval & LP_PSELECD)) {
                        LP_F(minor) &= ~LP_SELEC;
-                       return loop?loop:-EFAULT;
+                       return temp-buf?temp-buf:-EFAULT;
                } else
                        LP_F(minor) &= ~LP_SELEC;
 
     /* not offline or out of paper. on fire? */
                if (!(retval & LP_PERRORP)) {
                        LP_F(minor) |= LP_ERR;
-                       return loop?loop:-EIO;
+                       return temp-buf?temp-buf:-EIO;
                } else
                        LP_F(minor) &= ~LP_SELEC;
        }
-       return count;
+       return temp-buf;
+}
+
+static int lp_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+       return -EINVAL;
+}
+
+static int lp_lseek(struct inode * inode, struct file * file, off_t offset, int origin)
+{
+       return -EINVAL;
+}
+
+static int lp_open(struct inode * inode, struct file * file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+
+       if (minor >= LP_NO)
+               return -ENODEV;
+       if ((LP_F(minor) & LP_EXIST) == 0)
+               return -ENODEV;
+       if (LP_F(minor) & LP_BUSY)
+               return -EBUSY;
+       LP_F(minor) |= LP_BUSY;
+       return 0;
+}
+
+static void lp_release(struct inode * inode, struct file * file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+
+       LP_F(minor) &= ~LP_BUSY;
+}
+
+static struct file_operations lp_fops = {
+       lp_lseek,
+       lp_read,
+       lp_write,
+       NULL,           /* lp_readdir */
+       NULL,           /* lp_select */
+       NULL,           /* lp_ioctl */
+       lp_open,
+       lp_release
+};
+
+void lp_init(void)
+{
+       int offset = 0;
+       unsigned int testvalue = 0;
+       int count = 0;
+
+       chrdev_fops[6] = &lp_fops;
+       /* take on all known port values */
+       for (offset = 0; offset < LP_NO; offset++) {
+               /* write to port & read back to check */
+               outb( LP_DUMMY, LP_B(offset));
+               for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
+                       ;
+               testvalue = inb(LP_B(offset));
+               if (testvalue != 255) {
+                       LP_F(offset) |= LP_EXIST;
+                       lp_reset(offset);
+                       printk("lp_init: lp%d exists (%d)\n", offset, testvalue);
+                       count++;
+               }
+       }
+       if (count == 0)
+               printk("lp_init: no lp devices found\n");
 }
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
new file mode 100644 (file)
index 0000000..73758ee
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *  linux/kernel/chr_drv/mem.c
+ *
+ *  (C) 1991  Linus Torvalds
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
+{
+       return -EIO;
+}
+
+static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
+{
+       return -EIO;
+}
+
+static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
+{
+       unsigned long addr;
+       char *tmp;
+       unsigned long pde, pte, page;
+       int i;
+
+       if (count < 0)
+               return -EINVAL;
+       addr = file->f_pos;
+       tmp = buf;
+       while (count > 0) {
+               pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
+               if (!((pte = *((unsigned long *) pde)) & 1))
+                       break;
+               pte &= 0xfffff000;
+               pte += (addr >> 10) & 0xffc;
+               if (((page = *((unsigned long *) pte)) & 1) == 0)
+                       break;
+/*
+               if ((page & 2) == 0)
+                       un_wp_page((unsigned long *) pte);
+*/
+               page &= 0xfffff000;
+               page += addr & 0xfff;
+               i = 4096-(addr & 0xfff);
+               if (i > count)
+                       i = count;
+               memcpy_tofs(tmp,(void *) page,i);
+               addr += i;
+               tmp += i;
+               count -= i;
+       }
+       file->f_pos = addr;
+       return tmp-buf;
+}
+
+static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
+{
+       unsigned long addr;
+       char *tmp;
+       unsigned long pde, pte, page;
+       int i;
+
+       if (count < 0)
+               return -EINVAL;
+       addr = file->f_pos;
+       tmp = buf;
+       while (count > 0) {
+               pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
+               if (!((pte = *((unsigned long *) pde)) & 1))
+                       break;
+               pte &= 0xfffff000;
+               pte += (addr >> 10) & 0xffc;
+               if (((page = *((unsigned long *) pte)) & 1) == 0)
+                       break;
+               if ((page & 2) == 0)
+                       un_wp_page((unsigned long *) pte);
+               page &= 0xfffff000;
+               page += addr & 0xfff;
+               i = 4096-(addr & 0xfff);
+               if (i > count)
+                       i = count;
+               memcpy_fromfs((void *) page,tmp,i);
+               addr += i;
+               tmp += i;
+               count -= i;
+       }
+       file->f_pos = addr;
+       return tmp-buf;
+}
+
+static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
+{
+       unsigned long p = file->f_pos;
+
+       if (count < 0)
+               return -EINVAL;
+       if (p >= HIGH_MEMORY)
+               return 0;
+       if (count > HIGH_MEMORY - p)
+               count = HIGH_MEMORY - p;
+       memcpy_tofs(buf,(void *) p,count);
+       file->f_pos += count;
+       return count;
+}
+
+static int write_kmem(struct inode * inode, struct file * file,char * buf, int count)
+{
+       unsigned long p = file->f_pos;
+
+       if (count < 0)
+               return -EINVAL;
+       if (p >= HIGH_MEMORY)
+               return 0;
+       if (count > HIGH_MEMORY - p)
+               count = HIGH_MEMORY - p;
+       memcpy_fromfs((void *) p,buf,count);
+       file->f_pos += count;
+       return count;
+}
+
+static int read_port(struct inode * inode,struct file * file,char * buf, int count)
+{
+       unsigned int i = file->f_pos;
+       char * tmp = buf;
+
+       while (count-- > 0 && i < 65536) {
+               put_fs_byte(inb(i),tmp);
+               i++;
+               tmp++;
+       }
+       file->f_pos = i;
+       return tmp-buf;
+}
+
+static int write_port(struct inode * inode,struct file * file,char * buf, int count)
+{
+       unsigned int i = file->f_pos;
+       char * tmp = buf;
+
+       while (count-- > 0 && i < 65536) {
+               outb(get_fs_byte(tmp),i);
+               i++;
+               tmp++;
+       }
+       file->f_pos = i;
+       return tmp-buf;
+}
+
+/*
+ * The memory devices use the full 32 bits of the offset, and so we cannot
+ * check against negative addresses: they are ok. The return value is weird,
+ * though, in that case (0).
+ *
+ * also note that seeking relative to the "end of file" isn't supported:
+ * it has no meaning, so it returns -EINVAL.
+ */
+static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+       switch (orig) {
+               case 0:
+                       file->f_pos = offset;
+                       return file->f_pos;
+               case 1:
+                       file->f_pos += offset;
+                       return file->f_pos;
+               default:
+                       return -EINVAL;
+       }
+       if (file->f_pos < 0)
+               return 0;
+       return file->f_pos;
+}
+
+static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+       switch (MINOR(inode->i_rdev)) {
+               case 0:
+                       return read_ram(inode,file,buf,count);
+               case 1:
+                       return read_mem(inode,file,buf,count);
+               case 2:
+                       return read_kmem(inode,file,buf,count);
+               case 3:
+                       return 0;       /* /dev/null */
+               case 4:
+                       return read_port(inode,file,buf,count);
+               default:
+                       return -ENODEV;
+       }
+}
+
+static int mem_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+       switch (MINOR(inode->i_rdev)) {
+               case 0:
+                       return write_ram(inode,file,buf,count);
+               case 1:
+                       return write_mem(inode,file,buf,count);
+               case 2:
+                       return write_kmem(inode,file,buf,count);
+               case 3:
+                       return count;   /* /dev/null */
+               case 4:
+                       return write_port(inode,file,buf,count);
+               default:
+                       return -ENODEV;
+       }
+}
+
+static struct file_operations mem_fops = {
+       mem_lseek,
+       mem_read,
+       mem_write,
+       NULL,           /* mem_readdir */
+       NULL,           /* mem_select */
+       NULL,           /* mem_ioctl */
+       NULL,           /* no special open code */
+       NULL            /* no special release code */
+};
+
+void chr_dev_init(void)
+{
+       chrdev_fops[1] = &mem_fops;
+       tty_init();
+       lp_init();
+}
index aed5b6e169b8609bf85b7c62c8093f87b3fc3c5c..7d2eca6e08a571c666d5c19af77ae59cbc77ea8b 100644 (file)
  *     void spty_write(struct tty_struct * queue);
  */
 
-#include <linux/tty.h>
 #include <linux/sched.h>
+#include <linux/tty.h>
+
 #include <asm/system.h>
 #include <asm/io.h>
 
 static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
 {
-       char c;
+       int c;
 
        while (!from->stopped && !EMPTY(from->write_q)) {
                if (FULL(to->read_q)) {
@@ -28,7 +29,7 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
                        TTY_READ_FLUSH(to);
                        continue;
                }
-               GETCH(from->write_q,c);
+               c = GETCH(from->write_q);
                PUTCH(c,to->read_q);
                if (current->signal & ~current->blocked)
                        break;
diff --git a/kernel/chr_drv/rs_io.s b/kernel/chr_drv/rs_io.s
deleted file mode 100644 (file)
index e74dcd3..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  linux/kernel/rs_io.s
- *
- *  (C) 1991  Linus Torvalds
- */
-
-/*
- *     rs_io.s
- *
- * This module implements the rs232 io interrupts.
- */
-
-.text
-.globl _rs1_interrupt,_rs2_interrupt
-
-size   = 2048                          /* must be power of two !
-                                          and must match the value
-                                          in tty_io.c!!! */
-
-/* these are the offsets into the read/write buffer structures */
-rs_addr = 0
-head = 4
-tail = 8
-proc_list = 12
-buf = 16
-
-startup        = 256           /* chars left in write queue when we restart it */
-
-/*
- * These are the actual interrupt routines. They look where
- * the interrupt is coming from, and take appropriate action.
- *
- * rs1_interrupt (IRQ 4) takes care of com1 and com3
- * rs2_interrupt (IRQ 3) takes care of com2 and com4
- */
-.align 2
-_rs1_interrupt:
-       pushl $_table_list+8
-       pushl $_table_list+24
-       jmp rs_int
-
-.align 2
-_rs2_interrupt:
-       pushl $_table_list+16
-       pushl $_table_list+32
-rs_int:        cld
-       pushl %edx
-       pushl %ecx
-       pushl %ebx
-       pushl %eax
-       push %es
-       push %ds                /* as this is an interrupt, we cannot */
-       pushl $0x10             /* know that bs is ok. Load it */
-       pop %ds
-       pushl $0x10
-       pop %es
-       movl 24(%esp),%edx
-       call do_rs_intr
-       movl 28(%esp),%edx
-       call do_rs_intr
-       movb $0x20,%al
-       outb %al,$0x20          /* EOI */
-       pop %ds
-       pop %es
-       popl %eax
-       popl %ebx
-       popl %ecx
-       popl %edx
-       addl $8,%esp            # jump over the _table_list entries
-       iret
-
-do_rs_intr:
-       pushl %edx
-       movl (%edx),%edx
-       movl rs_addr(%edx),%edx
-       addl $2,%edx            /* interrupt ident. reg */
-1:     xorl %eax,%eax
-       inb %dx,%al
-       testb $1,%al
-       jne 2f
-       cmpb $6,%al             /* this shouldn't happen, but ... */
-       ja 2f
-       movl (%esp),%ecx
-       pushl %edx
-       subl $2,%edx
-       call jmp_table(,%eax,2)         /* NOTE! not *4, bit0 is 0 already */
-       popl %edx
-       jmp 1b
-2:     popl %edx
-       ret
-
-jmp_table:
-       .long modem_status,write_char,read_char,line_status
-
-.align 2
-modem_status:
-       addl $6,%edx            /* clear intr by reading modem status reg */
-       inb %dx,%al
-       ret
-
-.align 2
-line_status:
-       addl $5,%edx            /* clear intr by reading line status reg. */
-       inb %dx,%al
-       ret
-
-.align 2
-read_char:
-       inb %dx,%al
-       movl %ecx,%edx
-       subl $_table_list,%edx
-       shrl $3,%edx
-       movl (%ecx),%ecx                # read-queue
-       movl head(%ecx),%ebx
-       movb %al,buf(%ecx,%ebx)
-       incl %ebx
-       andl $size-1,%ebx
-       cmpl tail(%ecx),%ebx
-       je 1f
-       movl %ebx,head(%ecx)
-1:     movl mask_table(,%edx,4),%edx
-       orl %edx,_timer_active
-       ret
-
-.align 2
-mask_table:
-       .long 0,4,8,16,32
-
-.align 2
-write_char:
-       movl 4(%ecx),%ecx               # write-queue
-       movl head(%ecx),%ebx
-       subl tail(%ecx),%ebx
-       andl $size-1,%ebx               # nr chars in queue
-       je write_buffer_empty
-       cmpl $startup,%ebx
-       ja 1f
-       movl proc_list(%ecx),%ebx       # wake up sleeping process
-       testl %ebx,%ebx                 # is there any?
-       je 1f
-       movl $0,(%ebx)
-1:     movl tail(%ecx),%ebx
-       movb buf(%ecx,%ebx),%al
-       outb %al,%dx
-       incl %ebx
-       andl $size-1,%ebx
-       movl %ebx,tail(%ecx)
-       cmpl head(%ecx),%ebx
-       je write_buffer_empty
-       ret
-
-.align 2
-write_buffer_empty:
-       movl proc_list(%ecx),%ebx       # wake up sleeping process
-       testl %ebx,%ebx                 # is there any?
-       je 1f
-       movl $0,(%ebx)
-1:     incl %edx
-       inb %dx,%al
-       jmp 1f
-1:     jmp 1f
-1:     andb $0xd,%al                   # disable transmit interrupt
-       outb %al,%dx
-       ret
index bd55ec1caf130cce8509c497ad0c433931b4398e..60e704b0bd7f4f8258d53151dd19e1b70336cdf2 100644 (file)
  * and all interrupts pertaining to serial IO.
  */
 
-#include <linux/tty.h>
+#include <signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/tty.h>
+
 #include <asm/system.h>
 #include <asm/io.h>
 
-#define WAKEUP_CHARS (TTY_BUF_SIZE/4)
+#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
+
+extern void IRQ3_interrupt(void);
+extern void IRQ4_interrupt(void);
+
+static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+       unsigned char status = inb(port+6);
+
+       if ((status & 0x88) == 0x08 && tty->pgrp > 0)
+               kill_pg(tty->pgrp,SIGHUP,1);
+}
+
+/*
+ * There are several races here: we avoid most of them by disabling timer_active
+ * for the crucial part of the process.. That's a good idea anyway.
+ *
+ * The problem is that we have to output characters /both/ from interrupts
+ * and from the normal write: the latter to be sure the interrupts start up
+ * again. With serial lines, the interrupts can happen so often that the
+ * races actually are noticeable.
+ */
+static void send_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+       int c;
+
+#define TIMER ((SER1_TIMEOUT-1)+line)
+       timer_active &= ~(1 << TIMER);
+       if ((c = GETCH(tty->write_q)) < 0)
+               return;
+       outb(c,port);
+       timer_table[TIMER].expires = jiffies + 10;
+       timer_active |= 1 << TIMER;
+       if (LEFT(tty->write_q) > WAKEUP_CHARS)
+               wake_up(&tty->write_q->proc_list);
+#undef TIMER
+}
+
+static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+       if (FULL(tty->read_q))
+               return;
+       PUTCH(inb(port),tty->read_q);
+       timer_active |= (1<<(SER1_TIMER-1))<<line;
+}
+
+static void line_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+       unsigned char status = inb(port+5);
+
+/*     printk("line status: %02x\n",status); */
+}
+
+static void (*jmp_table[4])(unsigned,unsigned,struct tty_struct *) = {
+       modem_status_intr,
+       send_intr,
+       receive_intr,
+       line_status_intr
+};
+
+static void check_tty(unsigned line,struct tty_struct * tty)
+{
+       unsigned short port;
+       unsigned char ident;
+
+       if (!(port = tty->read_q->data))
+               return;
+       while (1) {
+               ident = inb(port+2);
+               if (ident & 1)
+                       return;
+               ident >>= 1;
+               if (ident > 3)
+                       return;
+               jmp_table[ident](line,port,tty);
+       }
+}
+
+/*
+ * IRQ3 normally handles com2 and com4
+ */
+void do_IRQ3(void)
+{
+       check_tty(2,tty_table+65);
+       check_tty(4,tty_table+67);
+}
 
-extern void rs1_interrupt(void);
-extern void rs2_interrupt(void);
+/*
+ * IRQ4 normally handles com1 and com2
+ */
+void do_IRQ4(void)
+{
+       check_tty(1,tty_table+64);
+       check_tty(3,tty_table+66);      
+}
 
 static void com1_timer(void)
 {
@@ -44,46 +138,48 @@ static void com4_timer(void)
        TTY_READ_FLUSH(tty_table+67);
 }
 
-static inline void do_rs_write(unsigned int port)
+/*
+ * Again, we disable interrupts to be sure there aren't any races:
+ * see send_intr for details.
+ */
+static inline void do_rs_write(unsigned line, struct tty_struct * tty)
 {
-       char c;
+       int port;
 
-#define TTY (tty_table[64+port].write_q)
-#define TIMER (SER1_TIMEOUT+port)
+#define TIMER ((SER1_TIMEOUT-1)+line)
+       if (!tty || !tty->write_q || EMPTY(tty->write_q))
+               return;
+       if (!(port = tty->write_q->data))
+               return;
        cli();
-       if (!EMPTY(TTY)) {
-               outb_p(inb_p(TTY->data+1)|0x02,TTY->data+1);
-               if (inb(TTY->data+5) & 0x20) {
-                       GETCH(TTY,c);
-                       outb(c,TTY->data);
-               }
-               timer_table[TIMER].expires = jiffies + 50;
+       if (inb_p(port+5) & 0x20)
+               send_intr(line,port,tty);
+       else {
+               timer_table[TIMER].expires = jiffies + 10;
                timer_active |= 1 << TIMER;
-       } else
-               timer_active &= ~(1 << TIMER);
+       }
        sti();
 #undef TIMER
-#undef TTY
 }
 
 static void com1_timeout(void)
 {
-       do_rs_write(0);
+       do_rs_write(1,tty_table+64);
 }
 
 static void com2_timeout(void)
 {
-       do_rs_write(1);
+       do_rs_write(2,tty_table+65);
 }
 
 static void com3_timeout(void)
 {
-       do_rs_write(2);
+       do_rs_write(3,tty_table+66);
 }
 
 static void com4_timeout(void)
 {
-       do_rs_write(3);
+       do_rs_write(4,tty_table+67);
 }
 
 static void init(int port)
@@ -93,7 +189,7 @@ static void init(int port)
        outb_p(0x00,port+1);    /* MS of divisor */
        outb_p(0x03,port+3);    /* reset DLAB */
        outb_p(0x00,port+4);    /* reset DTR,RTS, OUT_2 */
-       outb_p(0x0d,port+1);    /* enable all intrs but writes */
+       outb_p(0x0f,port+1);    /* enable all intrs */
        (void)inb(port);        /* read data port to reset things (?) */
 }
 
@@ -101,7 +197,7 @@ static void init(int port)
  * this routine enables interrupts on 'line', and disables them on
  * 'line ^ 2', as they share the same IRQ. Braindamaged AT hardware.
  */
-void serial_open(unsigned int line)
+void serial_open(unsigned line)
 {
        unsigned short port;
        unsigned short port2;
@@ -117,10 +213,10 @@ void serial_open(unsigned int line)
                outb_p(0x00,port2+4);
        outb_p(0x03,port+3);    /* reset DLAB */
        outb_p(0x0f,port+4);    /* set DTR,RTS, OUT_2 */
-       outb_p(0x0d,port+1);    /* enable all intrs but writes */
+       outb_p(0x0f,port+1);    /* enable all intrs */
        inb_p(port+5);
        inb_p(port+0);
-       inb(port+6);
+       inb_p(port+6);
        inb(port+2);
        sti();
 }
@@ -145,8 +241,8 @@ void rs_init(void)
        timer_table[SER3_TIMEOUT].expires = 0;
        timer_table[SER4_TIMEOUT].fn = com4_timeout;
        timer_table[SER4_TIMEOUT].expires = 0;
-       set_intr_gate(0x24,rs1_interrupt);
-       set_intr_gate(0x23,rs2_interrupt);
+       set_intr_gate(0x23,IRQ3_interrupt);
+       set_intr_gate(0x24,IRQ4_interrupt);
        init(tty_table[64].read_q->data);
        init(tty_table[65].read_q->data);
        init(tty_table[66].read_q->data);
@@ -163,9 +259,7 @@ void rs_init(void)
  */
 void rs_write(struct tty_struct * tty)
 {
-       cli();
-       if (!EMPTY(tty->write_q))
-               outb_p(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
-       timer_active |= 15 << SER1_TIMEOUT;
-       sti();
+       int line = tty - tty_table - 63;
+
+       do_rs_write(line,tty);
 }
index 511860ae79ccd984223a0230745e7c7e004c3722..413ee86f20b66a6b7e26390da7e84c2348913d19 100644 (file)
@@ -11,7 +11,7 @@
  * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  */
 
-#include <ctype.h>
+#include <linux/ctype.h>
 #include <errno.h>
 #include <signal.h>
 #include <unistd.h>
 
 #include <linux/sched.h>
 #include <linux/tty.h>
+#include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 
-int kill_pg(int pgrp, int sig, int priv);
-int is_orphaned_pgrp(int pgrp);
-   
-extern void lp_init(void);   
-
-#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
-#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
-#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
-
-#define L_CANON(tty)   _L_FLAG((tty),ICANON)
-#define L_ISIG(tty)    _L_FLAG((tty),ISIG)
-#define L_ECHO(tty)    _L_FLAG((tty),ECHO)
-#define L_ECHOE(tty)   _L_FLAG((tty),ECHOE)
-#define L_ECHOK(tty)   _L_FLAG((tty),ECHOK)
-#define L_ECHONL(tty)  _L_FLAG((tty),ECHONL)
-#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
-#define L_ECHOKE(tty)  _L_FLAG((tty),ECHOKE)
-#define L_TOSTOP(tty)  _L_FLAG((tty),TOSTOP)
-
-#define I_UCLC(tty)    _I_FLAG((tty),IUCLC)
-#define I_NLCR(tty)    _I_FLAG((tty),INLCR)
-#define I_CRNL(tty)    _I_FLAG((tty),ICRNL)
-#define I_NOCR(tty)    _I_FLAG((tty),IGNCR)
-#define I_IXON(tty)    _I_FLAG((tty),IXON)
-#define I_STRP(tty)    _I_FLAG((tty),ISTRIP)
-
-#define O_POST(tty)    _O_FLAG((tty),OPOST)
-#define O_NLCR(tty)    _O_FLAG((tty),ONLCR)
-#define O_CRNL(tty)    _O_FLAG((tty),OCRNL)
-#define O_NLRET(tty)   _O_FLAG((tty),ONLRET)
-#define O_LCUC(tty)    _O_FLAG((tty),OLCUC)
-
-#define C_SPEED(tty)   ((tty)->termios.c_cflag & CBAUD)
-#define C_HUP(tty)     (C_SPEED((tty)) == B0)
-
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
@@ -77,7 +43,13 @@ struct tty_struct tty_table[256];
 #define mpty_table (128+tty_table)
 #define spty_table (192+tty_table)
 
+/*
+ * fg_console is the current virtual console,
+ * redirect is the pseudo-tty that console output
+ * is redirected to if asked by TIOCCONS.
+ */
 int fg_console = 0;
+struct tty_struct * redirect = NULL;
 
 /*
  * these are the tables used by the machine code handlers.
@@ -89,7 +61,7 @@ struct tty_queue * table_list[]={
        rs_queues + 3, rs_queues + 4,
        rs_queues + 6, rs_queues + 7,
        rs_queues + 9, rs_queues + 10
-       };
+};
 
 void change_console(unsigned int new_console)
 {
@@ -108,16 +80,6 @@ static void sleep_if_empty(struct tty_queue * queue)
        sti();
 }
 
-static void sleep_if_full(struct tty_queue * queue)
-{
-       if (!FULL(queue))
-               return;
-       cli();
-       while (!(current->signal & ~current->blocked) && LEFT(queue)<128)
-               interruptible_sleep_on(&queue->proc_list);
-       sti();
-}
-
 void wait_for_keypress(void)
 {
        sleep_if_empty(tty_table[fg_console].secondary);
@@ -125,7 +87,7 @@ void wait_for_keypress(void)
 
 void copy_to_cooked(struct tty_struct * tty)
 {
-       unsigned char c;
+       int c;
 
        if (!(tty && tty->write && tty->read_q &&
            tty->write_q && tty->secondary)) {
@@ -141,7 +103,7 @@ void copy_to_cooked(struct tty_struct * tty)
                                        current->counter = 0;
                        break;
                }
-               GETCH(tty->read_q,c);
+               c = GETCH(tty->read_q);
                if (I_STRP(tty))
                        c &= 0x7f;
                if (c==13) {
@@ -242,6 +204,12 @@ void copy_to_cooked(struct tty_struct * tty)
                wake_up(&tty->write_q->proc_list);
 }
 
+int is_ignored(int sig)
+{
+       return ((current->blocked & (1<<(sig-1))) ||
+               (current->sigaction[sig-1].sa_handler == SIG_IGN));
+}
+
 /*
  * Called when we need to send a SIGTTIN or SIGTTOU to our process
  * group
@@ -259,24 +227,19 @@ void copy_to_cooked(struct tty_struct * tty)
  */
 int tty_signal(int sig, struct tty_struct *tty)
 {
-       if (is_orphaned_pgrp(current->pgrp))
-               return -EIO;            /* don't stop an orphaned pgrp */
        (void) kill_pg(current->pgrp,sig,1);
-       if ((current->blocked & (1<<(sig-1))) ||
-           ((int) current->sigaction[sig-1].sa_handler == 1)) 
-               return -EIO;            /* Our signal will be ignored */
-       else if (current->sigaction[sig-1].sa_handler)
+       if (current->sigaction[sig-1].sa_handler)
                return -EINTR;          /* We _will_ be interrupted :-) */
        else
                return -ERESTARTSYS;    /* We _will_ be interrupted :-) */
                                        /* (but restart after we continue) */
 }
 
-int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
+static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
 {
        struct tty_struct * tty;
        struct tty_struct * other_tty = NULL;
-       unsigned char c;
+       int c;
        char * b=buf;
        int minimum,time;
 
@@ -285,9 +248,13 @@ int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
        tty = TTY_TABLE(channel);
        if (!(tty->read_q && tty->secondary))
                return -EIO;
-       if ((tty->pgrp > 0) && (current->tty == channel) &&
+       if ((tty->pgrp > 0) &&
+           (current->tty == channel) &&
            (tty->pgrp != current->pgrp))
-               return(tty_signal(SIGTTIN, tty));
+               if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
+                       return -EIO;
+               else
+                       return(tty_signal(SIGTTIN, tty));
        if (channel & 0x80)
                other_tty = tty_table + (channel ^ 0x40);
        time = 10L*tty->termios.c_cc[VTIME];
@@ -304,7 +271,7 @@ int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
                        current->timeout = time + jiffies;
                time = 0;
        }
-       if (flags & O_NONBLOCK)
+       if (file->f_flags & O_NONBLOCK)
                time = current->timeout = 0;
        if (minimum>nr)
                minimum = nr;
@@ -328,7 +295,7 @@ int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
                }
                sti();
                do {
-                       GETCH(tty->secondary,c);
+                       c = GETCH(tty->secondary);
                        if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
                             c==EOF_CHAR(tty)) || c==10)
                                tty->secondary->data--;
@@ -350,17 +317,20 @@ int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
                        current->timeout = time+jiffies;
        }
        sti();
+       TTY_READ_FLUSH(tty);
+       if (other_tty && other_tty->write)
+               TTY_WRITE_FLUSH(other_tty);
        current->timeout = 0;
        if (b-buf)
                return b-buf;
        if (current->signal & ~current->blocked)
                return -ERESTARTSYS;
-       if (flags & O_NONBLOCK)
+       if (file->f_flags & O_NONBLOCK)
                return -EAGAIN;
        return 0;
 }
 
-int tty_write(unsigned channel, char * buf, int nr)
+static int write_chan(unsigned int channel, struct file * file, char * buf, int nr)
 {
        static cr_flag=0;
        struct tty_struct * tty;
@@ -369,19 +339,32 @@ int tty_write(unsigned channel, char * buf, int nr)
        if (channel > 255)
                return -EIO;
        tty = TTY_TABLE(channel);
-       if (!(tty->write_q && tty->write))
-               return -EIO;
-       if (L_TOSTOP(tty) &&  (tty->pgrp > 0) &&
-           (current->tty == channel) && (tty->pgrp != current->pgrp)) 
-               return(tty_signal(SIGTTOU, tty));
+       if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
+           (current->tty == channel) && (tty->pgrp != current->pgrp)) {
+               if (is_orphaned_pgrp(tty->pgrp))
+                       return -EIO;
+               if (!is_ignored(SIGTTOU))
+                       return tty_signal(SIGTTOU, tty);
+       }
        if (nr < 0)
                return -EINVAL;
        if (!nr)
                return 0;
+       if (redirect && tty == TTY_TABLE(0))
+               tty = redirect;
+       if (!(tty->write_q && tty->write))
+               return -EIO;
        while (nr>0) {
-               sleep_if_full(tty->write_q);
                if (current->signal & ~current->blocked)
                        break;
+               if (FULL(tty->write_q)) {
+                       TTY_WRITE_FLUSH(tty);
+                       cli();
+                       if (FULL(tty->write_q))
+                               interruptible_sleep_on(&tty->write_q->proc_list);
+                       sti();
+                       continue;
+               }
                while (nr>0 && !FULL(tty->write_q)) {
                        c=get_fs_byte(b);
                        if (O_POST(tty)) {
@@ -401,10 +384,10 @@ int tty_write(unsigned channel, char * buf, int nr)
                        cr_flag = 0;
                        PUTCH(c,tty->write_q);
                }
-               TTY_WRITE_FLUSH(tty);
                if (nr>0)
                        schedule();
        }
+       TTY_WRITE_FLUSH(tty);
        if (b-buf)
                return b-buf;
        if (current->signal & ~current->blocked)
@@ -412,14 +395,145 @@ int tty_write(unsigned channel, char * buf, int nr)
        return 0;
 }
 
-void chr_dev_init(void)
+static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+       int i;
+       
+       i = read_chan(current->tty,file,buf,count);
+       if (i > 0)
+               inode->i_atime = CURRENT_TIME;
+       return i;
+}
+
+static int ttyx_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+       int i;
+       
+       i = read_chan(MINOR(inode->i_rdev),file,buf,count);
+       if (i > 0)
+               inode->i_atime = CURRENT_TIME;
+       return i;
+}
+
+static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+       int i;
+       
+       i = write_chan(current->tty,file,buf,count);
+       if (i > 0)
+               inode->i_mtime = CURRENT_TIME;
+       return i;
+}
+
+static int ttyx_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+       int i;
+       
+       i = write_chan(MINOR(inode->i_rdev),file,buf,count);
+       if (i > 0)
+               inode->i_mtime = CURRENT_TIME;
+       return i;
+}
+
+static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+       return -EBADF;
+}
+
+/*
+ * tty_open and tty_release keep up the tty count that contains the
+ * number of opens done on a tty. We cannot use the inode-count, as
+ * different inodes might point to the same tty.
+ *
+ * Open-counting is needed for pty masters, as well as for keeping
+ * track of serial lines: DTR is dropped when the last close happens.
+ */
+static int tty_open(struct inode * inode, struct file * filp)
+{
+       struct tty_struct *tty;
+       int dev;
+
+       dev = inode->i_rdev;
+       if (MAJOR(dev) == 5)
+               dev = current->tty;
+       else
+               dev = MINOR(dev);
+       if (dev < 0)
+               return -ENODEV;
+       tty = TTY_TABLE(dev);
+       if (IS_A_PTY_MASTER(dev)) {
+               if (tty->count)
+                       return -EAGAIN;
+       }
+       tty->count++;
+       if (!(filp->f_flags & O_NOCTTY) &&
+           current->leader &&
+           current->tty<0 &&
+           tty->session==0) {
+               current->tty = dev;
+               tty->session = current->session;
+               tty->pgrp = current->pgrp;
+       }
+       if (IS_A_SERIAL(dev))
+               serial_open(dev-64);
+       return 0;
+}
+
+static void tty_release(struct inode * inode, struct file * filp)
 {
+       int dev;
+       unsigned short port;
+       struct tty_struct * tty, * slave;
+
+       dev = inode->i_rdev;
+       if (MAJOR(dev) == 5)
+               dev = current->tty;
+       else
+               dev = MINOR(dev);
+       if (dev < 0)
+               return;
+       tty = TTY_TABLE(dev);
+       if (--tty->count)
+               return;
+       if (tty == redirect)
+               redirect = NULL;
+       if (port = tty->read_q->data)
+               outb(0x0c,port+4);      /* reset DTR, RTS, */
+       if (IS_A_PTY_MASTER(dev)) {
+               slave = tty_table + PTY_OTHER(dev);
+               if (slave->pgrp > 0)
+                       kill_pg(slave->pgrp,SIGHUP,1);
+       }
 }
 
+static struct file_operations tty_fops = {
+       tty_lseek,
+       tty_read,
+       tty_write,
+       NULL,           /* tty_readdir */
+       NULL,           /* tty_select */
+       tty_ioctl,
+       tty_open,
+       tty_release
+};
+
+static struct file_operations ttyx_fops = {
+       tty_lseek,
+       ttyx_read,
+       ttyx_write,
+       NULL,           /* ttyx_readdir */
+       NULL,           /* ttyx_select */
+       tty_ioctl,      /* ttyx_ioctl */
+       tty_open,
+       tty_release
+};
+
 void tty_init(void)
 {
        int i;
 
+       chrdev_fops[4] = &ttyx_fops;
+       chrdev_fops[5] = &tty_fops;
        for (i=0 ; i < QUEUES ; i++)
                tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
        rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
@@ -433,7 +547,7 @@ void tty_init(void)
        for (i=0 ; i<256 ; i++) {
                tty_table[i] =  (struct tty_struct) {
                        {0, 0, 0, 0, 0, INIT_C_CC},
-                       -1, 0, 0, 0, {0,0,0,0},
+                       -1, 0, 0, 0, 0, {0,0,0,0},
                        NULL, NULL, NULL, NULL
                };
        }
@@ -450,6 +564,7 @@ void tty_init(void)
                        0,                      /* initial session */
                        0,                      /* initial stopped */
                        0,                      /* initial busy */
+                       0,                      /* initial count */
                        {video_num_lines,video_num_columns,0,0},
                        con_write,
                        con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
@@ -467,6 +582,7 @@ void tty_init(void)
                        0,
                        0,
                        0,
+                       0,
                        {25,80,0,0},
                        rs_write,
                        rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
@@ -484,6 +600,7 @@ void tty_init(void)
                        0,
                        0,
                        0,
+                       0,
                        {25,80,0,0},
                        mpty_write,
                        mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
@@ -499,6 +616,7 @@ void tty_init(void)
                        0,
                        0,
                        0,
+                       0,
                        {25,80,0,0},
                        spty_write,
                        spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
@@ -507,5 +625,4 @@ void tty_init(void)
        rs_init();
        printk("%d virtual consoles\n\r",NR_CONSOLES);
        printk("%d pty's\n\r",NR_PTYS);
-       lp_init();
 }
index a8594f0f5f8d77809f028a170163ce91e611e900..21818e5c708bf539966ac883928c3e4930b825c9 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <errno.h>
 #include <termios.h>
+#include <sys/types.h>
 
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -18,7 +19,7 @@
 extern int session_of_pgrp(int pgrp);
 extern int do_screendump(int arg);
 extern int kill_pg(int pgrp, int sig, int priv);
-extern int tty_signal(int sig, struct tty_struct *tty);
+extern int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg);
 
 static unsigned short quotient[] = {
        0, 2304, 1536, 1047, 857,
@@ -41,7 +42,7 @@ static void change_speed(struct tty_struct * tty)
        sti();
 }
 
-static void flush(struct tty_queue * queue)
+void flush(struct tty_queue * queue)
 {
        if (queue) {
                cli();
@@ -53,17 +54,31 @@ static void flush(struct tty_queue * queue)
 
 static void wait_until_sent(struct tty_struct * tty)
 {
-       cli();
        while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
+               TTY_WRITE_FLUSH(tty);
                current->counter = 0;
-               interruptible_sleep_on(&tty->write_q->proc_list);
+               cli();
+               if (EMPTY(tty->write_q))
+                       break;
+               else
+                       interruptible_sleep_on(&tty->write_q->proc_list);
+               sti();
        }
        sti();
 }
 
 static void send_break(struct tty_struct * tty)
 {
-       /* do nothing - not implemented */
+       unsigned short port;
+
+       if (!(port = tty->read_q->data))
+               return;
+       port += 3;
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 25;
+       outb_p(inb_p(port) | 0x40,port);
+       schedule();
+       outb_p(inb_p(port) & 0xbf,port);
 }
 
 static int do_get_ps_info(int arg)
@@ -107,15 +122,17 @@ static int get_termios(struct tty_struct * tty, struct termios * termios)
 static int set_termios(struct tty_struct * tty, struct termios * termios,
                        int channel)
 {
-       int i, retsig;
+       int i;
 
        /* If we try to set the state of terminal and we're not in the
           foreground, send a SIGTTOU.  If the signal is blocked or
           ignored, go ahead and perform the operation.  POSIX 7.2) */
-       if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
-               retsig = tty_signal(SIGTTOU, tty);
-               if (retsig == -ERESTARTSYS || retsig == -EINTR)
-                       return retsig;
+       if ((current->tty == channel) &&
+            (tty->pgrp != current->pgrp)) {
+               if (is_orphaned_pgrp(current->pgrp))
+                       return -EIO;
+               if (!is_ignored(SIGTTOU))
+                       return tty_signal(SIGTTOU, tty);
        }
        for (i=0 ; i< (sizeof (*termios)) ; i++)
                ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
@@ -147,13 +164,16 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
 static int set_termio(struct tty_struct * tty, struct termio * termio,
                        int channel)
 {
-       int i, retsig;
+       int i;
        struct termio tmp_termio;
 
-       if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
-               retsig = tty_signal(SIGTTOU, tty);
-               if (retsig == -ERESTARTSYS || retsig == -EINTR)
-                       return retsig;
+       if ((current->tty == channel) &&
+           (tty->pgrp > 0) &&
+           (tty->pgrp != current->pgrp)) {
+               if (is_orphaned_pgrp(current->pgrp))
+                       return -EIO;
+               if (!is_ignored(SIGTTOU))
+                       return tty_signal(SIGTTOU, tty);
        }
        for (i=0 ; i< (sizeof (*termio)) ; i++)
                ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
@@ -203,18 +223,20 @@ static int get_window_size(struct tty_struct * tty, struct winsize * ws)
        return 0;
 }
 
-int tty_ioctl(int dev, int cmd, int arg)
+int tty_ioctl(struct inode * inode, struct file * file,
+       unsigned int cmd, unsigned int arg)
 {
        struct tty_struct * tty;
        struct tty_struct * other_tty;
        int pgrp;
+       int dev;
 
-       if (MAJOR(dev) == 5) {
+       if (MAJOR(inode->i_rdev) == 5) {
                dev = current->tty;
                if (dev<0)
                        return -EINVAL;
        } else
-               dev=MINOR(dev);
+               dev = MINOR(inode->i_rdev);
        tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
 
        if (IS_A_PTY(dev))
@@ -251,10 +273,9 @@ int tty_ioctl(int dev, int cmd, int arg)
                case TCSETA:
                        return set_termio(tty,(struct termio *) arg, dev);
                case TCSBRK:
-                       if (!arg) {
-                               wait_until_sent(tty);
+                       wait_until_sent(tty);
+                       if (!arg)
                                send_break(tty);
-                       }
                        return 0;
                case TCXONC:
                        switch (arg) {
@@ -321,15 +342,18 @@ int tty_ioctl(int dev, int cmd, int arg)
                        return 0;
                case TIOCINQ:
                        verify_area((void *) arg,4);
-                       put_fs_long(CHARS(tty->secondary),
-                               (unsigned long *) arg);
+                       if (L_CANON(tty) && !tty->secondary->data)
+                               put_fs_long(0, (unsigned long *) arg);
+                       else
+                               put_fs_long(CHARS(tty->secondary),
+                                       (unsigned long *) arg);
                        return 0;
                case TIOCSTI:
                        return -EINVAL; /* not implemented */
                case TIOCGWINSZ:
                        return get_window_size(tty,(struct winsize *) arg);
                case TIOCSWINSZ:
-                       if (other_tty)
+                       if (IS_A_PTY_MASTER(dev))
                                set_window_size(other_tty,(struct winsize *) arg);
                        return set_window_size(tty,(struct winsize *) arg);
                case TIOCMGET:
@@ -354,7 +378,19 @@ int tty_ioctl(int dev, int cmd, int arg)
                                default: 
                                        return -EINVAL;
                        }
+               case TIOCCONS:
+                       if (!IS_A_PTY(dev))
+                               return -EINVAL;
+                       if (redirect)
+                               return -EBUSY;
+                       if (!suser())
+                               return -EPERM;
+                       if (IS_A_PTY_MASTER(dev))
+                               redirect = other_tty;
+                       else
+                               redirect = tty;
+                       return 0;
                default:
-                       return -EINVAL;
+                       return vt_ioctl(tty, dev, cmd, arg);
        }
 }
diff --git a/kernel/chr_drv/vt.c b/kernel/chr_drv/vt.c
new file mode 100644 (file)
index 0000000..8bac0fe
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  kernel/chr_drv/vt.c
+ *
+ *  (C) 1992 obz under the linux copyright
+ */
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/kd.h>
+#include <sys/vt.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+
+#include "vt_kern.h"
+
+/*
+ * console (vt and kd) routines, as defined by usl svr4 manual
+ */
+
+struct vt_cons vt_cons[MAX_CONSOLES];
+
+extern int NR_CONSOLES;
+extern unsigned char kleds;
+extern unsigned char kraw;
+extern unsigned char ke0;
+
+extern int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern void set_leds(void);
+
+/*
+ * these are the valid i/o ports we're allowed to change. they map all the
+ * video ports
+ */
+#define GPFIRST 0x3b4
+#define GPLAST 0x3df
+#define GPNUM (GPLAST - GPFIRST + 1)
+
+/*
+ * turns on sound of some freq. 0 turns it off.
+ * stolen from console.c, so i'm not sure if its the correct interpretation
+ */
+static int
+kiocsound(unsigned int freq)
+{
+       if (freq == 0) {
+               /* disable counter 2 */
+               outb(inb_p(0x61)&0xFC, 0x61);
+       }
+       else {
+               /* enable counter 2 */
+               outb_p(inb_p(0x61)|3, 0x61);
+               /* set command for counter 2, 2 byte write */
+               outb_p(0xB6, 0x43);
+               /* select desired HZ */
+               outb_p(freq & 0xff, 0x42);
+               outb((freq >> 8) & 0xff, 0x42);
+       }
+       return 0;
+}
+
+/*
+ * all the vt ioctls affect only consoles, so we reject all other ttys.
+ * we also have the capability to modify any console, not just the fg_console.
+ */
+int
+vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg)
+{
+       int console = dev ? dev - 1 : fg_console;
+       unsigned char ucval;
+
+       if (!IS_A_CONSOLE(dev) || console < 0 || console >= NR_CONSOLES)
+               return -EINVAL;
+
+       switch (cmd) {
+       case KIOCSOUND:
+               return kiocsound((unsigned int)arg);
+
+       case KDGKBTYPE:
+               /*
+                * this is naive.
+                */
+               verify_area((void *) arg, sizeof(unsigned char));
+               put_fs_byte(KB_101, (unsigned char *) arg);
+               return 0;
+
+       case KDADDIO:
+       case KDDELIO:
+               /*
+                * KDADDIO and KDDELIO may be able to add ports beyond what
+                * we reject here, but to be safe...
+                */
+               if (arg < GPFIRST || arg > GPLAST)
+                       return -EINVAL;
+               return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+
+       case KDENABIO:
+       case KDDISABIO:
+               return sys_ioperm(GPFIRST, GPNUM,
+                                 (cmd == KDENABIO)) ? -ENXIO : 0;
+
+       case KDSETMODE:
+               /*
+                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
+                * doesn't do a whole lot. i'm not sure if it should do any
+                * restoration of modes or what...
+                */
+               switch (arg) {
+               case KD_GRAPHICS:
+                       break;
+               case KD_TEXT0:
+               case KD_TEXT1:
+                       arg = KD_TEXT;
+               case KD_TEXT:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               vt_cons[console].vt_mode = arg;
+               return 0;
+       case KDGETMODE:
+               verify_area((void *) arg, sizeof(unsigned long));
+               put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg);
+               return 0;
+
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+               /*
+                * these work like a combination of mmap and KDENABIO.
+                * this could be easily finished.
+                */
+               return -EINVAL;
+
+       case KDSKBMODE:
+               if (arg == K_RAW) {
+                       if (console == fg_console) {
+                               kraw = 1;
+                               ke0 = 0;
+                       } else {
+                               vt_cons[console].vc_kbdraw = 1;
+                               vt_cons[console].vc_kbde0 = 0;
+                       }
+               }
+               else if (arg == K_XLATE) {
+                       if (console == fg_console)
+                               kraw = 0;
+                       else
+                               vt_cons[console].vc_kbdraw = 0;
+               }
+               else
+                       return -EINVAL;
+               flush(tty->read_q);
+               flush(tty->secondary);
+               return 0;
+       case KDGKBMODE:
+               verify_area((void *) arg, sizeof(unsigned long));
+               ucval = (console == fg_console) ? kraw :
+                       vt_cons[console].vc_kbdraw;
+               put_fs_long(ucval ? K_RAW : K_XLATE, (unsigned long *) arg);
+               return 0;
+
+       case KDGETLED:
+               verify_area((void *) arg, sizeof(unsigned char));
+               ucval = (console == fg_console) ? kleds :
+                       vt_cons[console].vc_kbdleds;
+               put_fs_byte((((ucval & 1) ? LED_SCR : 0) |
+                            ((ucval & 2) ? LED_NUM : 0) |
+                            ((ucval & 4) ? LED_CAP : 0)),
+                           (unsigned char *) arg);
+               return 0;
+       case KDSETLED:
+               if (arg & ~7)
+                       return -EINVAL;
+               ucval = (((arg & LED_SCR) ? 1 : 0) |
+                        ((arg & LED_NUM) ? 2 : 0) |
+                        ((arg & LED_CAP) ? 4 : 0));
+               if (console == fg_console) {
+                       kleds = ucval;
+                       set_leds();
+               }
+               else
+                       vt_cons[console].vc_kbdleds = ucval;
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
diff --git a/kernel/chr_drv/vt_kern.h b/kernel/chr_drv/vt_kern.h
new file mode 100644 (file)
index 0000000..2c7116c
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _VT_KERN_H
+#define _VT_KERN_H
+
+/*
+ * this really is an extension of the vc_cons structure in console.c, but
+ * with information needed by the vt package
+ */
+extern struct vt_cons {
+       int             vt_mode;                /* KD_TEXT, ... */
+       unsigned char   vc_kbdraw;
+       unsigned char   vc_kbde0;
+       unsigned char   vc_kbdleds;
+} vt_cons[MAX_CONSOLES];
+
+#endif /* _VT_KERN_H */
index 50f61464b47dc5b2e1647fd16a883af20bbb9270..1e6ec04813ba07b255ea3a9b832dc0f16a1ccc6b 100644 (file)
 
 int sys_close(int fd);
 
-inline int send_sig(long sig,struct task_struct * p,int priv)
+int send_sig(long sig,struct task_struct * p,int priv)
 {
        if (!p || (sig < 0) || (sig > 32))
                return -EINVAL;
-       if (!priv && (current->euid!=p->euid) && !suser())
+       if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
+           (current->euid != p->euid) && !suser())
                return -EPERM;
        if (!sig)
                return 0;
@@ -167,14 +168,26 @@ void audit_ptree()
 }
 #endif /* DEBUG_PROC_TREE */
 
+/*
+ * This checks not only the pgrp, but falls back on the pid if no
+ * satisfactory prgp is found. I dunno - gdb doesn't work correctly
+ * without this...
+ */
 int session_of_pgrp(int pgrp)
 {
        struct task_struct **p;
+       int fallback;
 
-       for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+       fallback = -1;
+       for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+               if (!*p || (*p)->session <= 0)
+                       continue;
                if ((*p)->pgrp == pgrp)
-                       return((*p)->session);
-       return -1;
+                       return (*p)->session;
+               if ((*p)->pid == pgrp)
+                       fallback = (*p)->session;
+       }
+       return fallback;
 }
 
 int kill_pg(int pgrp, int sig, int priv)
@@ -186,7 +199,7 @@ int kill_pg(int pgrp, int sig, int priv)
        if (sig<0 || sig>32 || pgrp<=0)
                return -EINVAL;
        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
-               if ((*p)->pgrp == pgrp) {
+               if (*p && (*p)->pgrp == pgrp) {
                        if (sig && (err = send_sig(sig,*p,priv)))
                                retval = err;
                        else
@@ -202,7 +215,7 @@ int kill_proc(int pid, int sig, int priv)
        if (sig<0 || sig>32)
                return -EINVAL;
        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
-               if ((*p)->pid == pid)
+               if (*p && (*p)->pid == pid)
                        return(sig ? send_sig(sig,*p,priv) : 0);
        return(-ESRCH);
 }
@@ -220,7 +233,7 @@ int sys_kill(int pid,int sig)
                return(kill_pg(current->pgrp,sig,0));
        if (pid == -1) {
                while (--p > &FIRST_TASK)
-                       if ((*p)->pid > 1 && *p != current) {
+                       if (*p && (*p)->pid > 1 && *p != current) {
                                ++count;
                                if ((err = send_sig(sig,*p,0)) != -EPERM)
                                        retval = err;
@@ -263,7 +276,7 @@ static int has_stopped_jobs(int pgrp)
        struct task_struct ** p;
 
        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
-               if ((*p)->pgrp != pgrp)
+               if (!*p || (*p)->pgrp != pgrp)
                        continue;
                if ((*p)->state == TASK_STOPPED)
                        return(1);
@@ -287,8 +300,10 @@ volatile void do_exit(long code)
        current->root = NULL;
        iput(current->executable);
        current->executable = NULL;
-       iput(current->library);
-       current->library = NULL;
+       for (i=0; i < current->numlibraries; i++) {
+               iput(current->libraries[i].library);
+               current->libraries[i].library = NULL;
+       }       
        current->state = TASK_ZOMBIE;
        current->exit_code = code;
        current->rss = 0;
@@ -355,7 +370,7 @@ volatile void do_exit(long code)
                        tty->session = 0;
                }
                for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
-                       if ((*p)->session == current->session)
+                       if (*p && (*p)->session == current->session)
                                (*p)->tty = -1;
        }
        if (last_task_used_math == current)
@@ -394,8 +409,9 @@ repeat:
                }
                switch (p->state) {
                        case TASK_STOPPED:
-                               if (!(options & WUNTRACED) || 
-                                   !p->exit_code)
+                               if (!p->exit_code)
+                                       continue;
+                               if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
                                        continue;
                                if (stat_addr)
                                        put_fs_long((p->exit_code << 8) | 0x7f,
index ad65fb1229be28a1011e0aca7809849d4211d8b3..8a0dbe88772d278513507dcf67ea5b1d335b70ef 100644 (file)
@@ -11,6 +11,7 @@
  * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
  */
 #include <errno.h>
+#include <stddef.h>
 
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -69,7 +70,8 @@ static int find_empty_process(void)
        int i;
 
        repeat:
-               if ((++last_pid)<0) last_pid=1;
+               if ((++last_pid) & 0xffff0000)
+                       last_pid=1;
                for(i=0 ; i<NR_TASKS ; i++)
                        if (task[i] && ((task[i]->pid == last_pid) ||
                                        (task[i]->pgrp == last_pid)))
@@ -106,6 +108,12 @@ int sys_fork(long ebx,long ecx,long edx,
        *p = *current;  /* NOTE! this doesn't copy the supervisor stack */
        p->state = TASK_UNINTERRUPTIBLE;
        p->pid = last_pid;
+       p->p_pptr = current;
+       p->p_cptr = NULL;
+       p->p_ysptr = NULL;
+       if (p->p_osptr = current->p_cptr)
+               p->p_osptr->p_ysptr = p;
+       current->p_cptr = p;
        p->counter = p->priority;
        p->signal = 0;
        p->alarm = 0;
@@ -135,11 +143,19 @@ int sys_fork(long ebx,long ecx,long edx,
        p->tss.fs = fs & 0xffff;
        p->tss.gs = gs & 0xffff;
        p->tss.ldt = _LDT(nr);
-       p->tss.trace_bitmap = 0x80000000;
+       p->tss.trace_bitmap = offsetof(struct tss_struct,io_bitmap) << 16;
+       for (i = 0; i<IO_BITMAP_SIZE ; i++)
+               p->tss.io_bitmap[i] = ~0;
        if (last_task_used_math == current)
                __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
        if (copy_mem(nr,p)) {
                task[nr] = NULL;
+               if (p->p_pptr->p_cptr == p)
+                       p->p_pptr->p_cptr = p->p_osptr;
+               if (p->p_osptr)
+                       p->p_osptr->p_ysptr = p->p_ysptr;
+               if (p->p_ysptr)
+                       p->p_ysptr->p_osptr = p->p_osptr;
                free_page((long) p);
                return -EAGAIN;
        }
@@ -152,17 +168,11 @@ int sys_fork(long ebx,long ecx,long edx,
                current->root->i_count++;
        if (current->executable)
                current->executable->i_count++;
-       if (current->library)
-               current->library->i_count++;
+       for (i=0; i < current->numlibraries ; i++)
+               if (current->libraries[i].library)
+                       current->libraries[i].library->i_count++;
        set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
        set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
-       p->p_pptr = current;
-       p->p_cptr = 0;
-       p->p_ysptr = 0;
-       p->p_osptr = current->p_cptr;
-       if (p->p_osptr)
-               p->p_osptr->p_ysptr = p;
-       current->p_cptr = p;
        p->state = TASK_RUNNING;        /* do this last, just in case */
        return p->pid;
 }
diff --git a/kernel/ioport.c b/kernel/ioport.c
new file mode 100644 (file)
index 0000000..cdca95a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *     linux/kernel/ioport.c
+ *
+ * This contains the io-permission bitmap code - written by obz, with changes
+ * by Linus.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#define _IODEBUG
+
+#ifdef IODEBUG
+static char * ios(unsigned long l)
+{
+       static char str[33] = { '\0' };
+       int i;
+       unsigned long mask;
+
+       for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1)
+               str[i] = (l & mask) ? '1' : '0';
+       return str;
+}
+
+static void dump_io_bitmap(void)
+{
+       int i, j;
+       int numl = sizeof(current->tss.io_bitmap) >> 2;
+
+       for (i = j = 0; j < numl; ++i)
+       {
+               printk("%4d [%3x]: ", 64*i, 64*i);
+               printk("%s ", ios(current->tss.io_bitmap[j++]));
+               if (j < numl)
+                       printk("%s", ios(current->tss.io_bitmap[j++]));
+               printk("\n");
+       }
+}
+#endif
+
+/*
+ * this changes the io permissions bitmap in the current task.
+ */
+int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+       unsigned long froml, lindex, tnum, numl, rindex, mask;
+       unsigned long *iop;
+
+       froml = from >> 5;
+       lindex = from & 0x1f;
+       tnum = lindex + num;
+       numl = (tnum + 0x1f) >> 5;
+       rindex = tnum & 0x1f;
+
+       if (!suser())
+               return -EPERM;
+       if (froml * 32 + tnum > sizeof(current->tss.io_bitmap) * 8 - 8)
+               return -EINVAL;
+
+#ifdef IODEBUG
+       printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
+#endif
+
+       if (numl) {
+               iop = (unsigned long *)current->tss.io_bitmap + froml;
+               if (lindex != 0) {
+                       mask = (~0 << lindex);
+                       if (--numl == 0 && rindex)
+                               mask &= ~(~0 << rindex);
+                       if (turn_on)
+                               *iop++ &= ~mask;
+                       else
+                               *iop++ |= mask;
+               }
+               if (numl) {
+                       if (rindex)
+                               --numl;
+                       mask = (turn_on ? 0 : ~0);
+                       while (numl--)
+                               *iop++ = mask;
+                       if (numl && rindex) {
+                               mask = ~(~0 << rindex);
+                               if (turn_on)
+                                       *iop++ &= ~mask;
+                               else
+                                       *iop++ |= mask;
+                       }
+               }
+       }
+       return 0;
+}
index 3c061837aab6b6a2082af8e5f7d0859c098ea797..79e3276a063ba0650e18de88e74163534dcf3ae4 100644 (file)
@@ -40,51 +40,46 @@ dep:
        cp tmp_make Makefile
 
 ### Dependencies:
-add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h 
-compare.s compare.o : compare.c ../../include/linux/math_emu.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+compare.s compare.o : compare.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h 
-convert.s convert.o : convert.c ../../include/linux/math_emu.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+convert.s convert.o : convert.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h 
-div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h 
-ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h ../../include/asm/segment.h 
-error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
-  ../../include/linux/sched.h ../../include/linux/head.h \
-  ../../include/linux/fs.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/sys/param.h \
-  ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h 
-get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
-  ../../include/linux/math_emu.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/linux/mm.h ../../include/linux/kernel.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
-  ../../include/sys/resource.h ../../include/asm/segment.h 
-emulate.s emulate.o : emulate.c ../../include/linux/config.h 
-mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
-  ../../include/linux/head.h ../../include/linux/fs.h \
-  ../../include/sys/types.h ../../include/linux/mm.h \
-  ../../include/linux/kernel.h ../../include/signal.h \
-  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+emulate.s emulate.o : emulate.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h 
+error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+  ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h 
+get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/math_emu.h \
+  ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+  ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+  ../../include/asm/segment.h 
+mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+  ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+  ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+  ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
   ../../include/sys/resource.h 
index ebce88c6d6d28fa631726d7882464fd0bcd60d18..c4616989582151bfbc2aa4e051b0ddcabf810b62 100644 (file)
  *  (C) 1991  Linus Torvalds
  */
 
-/*
- * When in kernel-mode, we cannot use printf, as fs is liable to
- * point to 'interesting' things. Make a printf with fs-saving, and
- * all is well.
- */
 #include <stdarg.h>
 #include <stddef.h>
+#include <errno.h>
 
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
 #include <linux/kernel.h>
 
 static char buf[1024];
 
 extern int vsprintf(char * buf, const char * fmt, va_list args);
+extern void console_print(const char *);
+
+static unsigned long log_page = 0;
+static unsigned long log_start = 0;
+static unsigned long log_size = 0;
+static struct task_struct * log_wait = NULL;
+
+int sys_syslog(int type, char * buf, int len)
+{
+       unsigned long i;
+       char c;
+
+       if (!suser())
+               return -EPERM;
+       switch (type) {
+               case 0:
+                       i = log_page;
+                       log_page = 0;
+                       free_page(i);
+                       wake_up(&log_wait);
+                       return 0;
+               case 1:
+                       i = get_free_page();
+                       if (log_page) {
+                               free_page(i);
+                               return 0;
+                       } else if (log_page = i) {
+                               log_start = log_size = 0;
+                               return 0;
+                       }
+                       return -ENOMEM;
+               case 2:
+                       if (!buf || len < 0)
+                               return -EINVAL;
+                       if (!len)
+                               return 0;
+                       verify_area(buf,len);
+                       while (!log_size) {
+                               if (!log_page)
+                                       return -EIO;
+                               if (current->signal & ~current->blocked)
+                                       return -ERESTARTSYS;
+                               cli();
+                               if (!log_size)
+                                       interruptible_sleep_on(&log_wait);
+                               sti();
+                       }
+                       i = 0;
+                       while (log_size && len) {
+                               c = *((char *) log_page+log_start);
+                               log_start++;
+                               log_size--;
+                               log_start &= 4095;
+                               put_fs_byte(c,buf);
+                               buf++;
+                               i++;
+                       }
+                       return i;
+       }
+       return -EINVAL;
+}
+                       
 
 int printk(const char *fmt, ...)
 {
        va_list args;
-       int i;
+       int i,j;
+       char * p;
 
        va_start(args, fmt);
        i=vsprintf(buf,fmt,args);
        va_end(args);
+       for (j = 0; j < i && log_page ; j++) {
+               p = (char *) log_page + (4095 & (log_start+log_size));
+               *p = buf[j];
+               if (log_size < 4096)
+                       log_size++;
+               else
+                       log_start++;
+       }
+       if (log_page)
+               wake_up(&log_wait);
        console_print(buf);
        return i;
 }
index 051241dfb336f6e877eac81a96b010da94a14d38..60e3d6d39fb910591078338a09270f4ab6e9835e 100644 (file)
@@ -29,7 +29,7 @@
  */
 #define MAGICNUMBER 68
 
-void do_no_page(unsigned long, unsigned long, struct task_struct *);
+void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned long);
 void write_verify(unsigned long);
 
 /* change a pid into a task struct. */
@@ -100,7 +100,7 @@ repeat:
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0,addr,tsk);
+               do_no_page(0,addr,tsk,0);
                goto repeat;
        }
        page &= 0xfffff000;
@@ -129,7 +129,7 @@ repeat:
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0,addr,tsk);
+               do_no_page(0,addr,tsk,0);
                goto repeat;
        }
        if (!(page & PAGE_RW)) {
@@ -219,19 +219,11 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
        return 0;
 }
 
-/* Perform ptrace(request, pid, addr, data) syscall */
-int sys_ptrace(unsigned long *buffer)
+int sys_ptrace(long request, long pid, long addr, long data)
 {
-       long request, pid, data;
-       long addr;
        struct task_struct *child;
        int childno;
 
-       request = get_fs_long(buffer++);
-       pid = get_fs_long(buffer++);
-       addr = get_fs_long(buffer++); /* assume long = void * */
-       data = get_fs_long(buffer++);
-
        if (request == 0) {
                /* set the ptrace bit in the proccess flags. */
                current->flags |= PF_PTRACED;
index 3c274e64ab7070b2e01bff056dc58851e9730004..01d04a975aa76fdbf5d058af242bc8c9f1595f0f 100644 (file)
@@ -22,6 +22,8 @@
 #include <signal.h>
 #include <errno.h>
 
+int need_resched = 0;
+
 #define _S(nr) (1<<((nr)-1))
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
@@ -46,21 +48,12 @@ void show_task(int nr,struct task_struct * p)
 
 void show_state(void)
 {
-       static int lock = 0;
        int i;
 
-       cli();
-       if (lock) {
-               sti();
-               return;
-       }
-       lock = 1;
-       sti();
        printk("\rTask-info:\n\r");
        for (i=0 ; i<NR_TASKS ; i++)
                if (task[i])
                        show_task(i,task[i]);
-       lock = 0;
 }
 
 #define LATCH (1193180/HZ)
@@ -133,6 +126,7 @@ void schedule(void)
 
 /* check alarm, wake up any interruptible tasks that have got a signal */
 
+       need_resched = 0;
        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                if (*p) {
                        if ((*p)->timeout && (*p)->timeout < jiffies)
@@ -187,6 +181,10 @@ int sys_pause(void)
        return -EINTR;
 }
 
+/*
+ * wake_up doesn't wake up stopped processes - they have to be awakened
+ * with signals or similar.
+ */
 void wake_up(struct task_struct **p)
 {
        struct task_struct * wakeup_ptr, * tmp;
@@ -195,12 +193,13 @@ void wake_up(struct task_struct **p)
                wakeup_ptr = *p;
                *p = NULL;
                while (wakeup_ptr && wakeup_ptr != task[0]) {
-                       if (wakeup_ptr->state == TASK_STOPPED)
-                               printk("wake_up: TASK_STOPPED\n");
-                       else if (wakeup_ptr->state == TASK_ZOMBIE)
+                       if (wakeup_ptr->state == TASK_ZOMBIE)
                                printk("wake_up: TASK_ZOMBIE\n");
-                       else
+                       else if (wakeup_ptr->state != TASK_STOPPED) {
                                wakeup_ptr->state = TASK_RUNNING;
+                               if (wakeup_ptr->counter > current->counter)
+                                       need_resched = 1;
+                       }
                        tmp = wakeup_ptr->next_wait;
                        wakeup_ptr->next_wait = task[0];
                        wakeup_ptr = tmp;
@@ -342,6 +341,34 @@ void add_timer(long jiffies, void (*fn)(void))
        sti();
 }
 
+#define        FSHIFT  11
+#define        FSCALE  (1<<FSHIFT)
+/*
+ * Constants for averages over 1, 5, and 15 minutes
+ * when sampling at 5 second intervals.
+ */
+static unsigned long cexp[3] = {
+       1884,   /* 0.9200444146293232 * FSCALE,  exp(-1/12) */
+       2014,   /* 0.9834714538216174 * FSCALE,  exp(-1/60) */
+       2037,   /* 0.9944598480048967 * FSCALE,  exp(-1/180) */
+};
+unsigned long averunnable[3];  /* fixed point numbers */
+
+void update_avg(void)
+{
+       int i, n=0;
+       struct task_struct **p;
+
+       for(p = &LAST_TASK; p > &FIRST_TASK; --p)
+               if (*p && ((*p)->state == TASK_RUNNING || 
+                          (*p)->state == TASK_UNINTERRUPTIBLE))
+                       ++n;
+       
+       for (i = 0; i < 3; ++i)
+               averunnable[i] = (cexp[i] * averunnable[i] +
+                       n * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
+}
+
 unsigned long timer_active = 0;
 struct timer_struct timer_table[32];
 
@@ -349,6 +376,7 @@ void do_timer(long cpl)
 {
        unsigned long mask;
        struct timer_struct *tp = timer_table+0;
+       static int avg_cnt;
 
        for (mask = 1 ; mask ; tp++,mask += mask) {
                if (mask > timer_active)
@@ -359,6 +387,7 @@ void do_timer(long cpl)
                        continue;
                timer_active &= ~mask;
                tp->fn();
+               sti();
        }
 
        if (cpl)
@@ -379,10 +408,14 @@ void do_timer(long cpl)
        }
        if (current_DOR & 0xf0)
                do_floppy_timer();
-       if ((--current->counter)>0) return;
-       current->counter=0;
-       if (!cpl) return;
-       schedule();
+       if (--avg_cnt < 0) {
+               avg_cnt = 500;
+               update_avg();
+       }
+       if ((--current->counter)<=0) {
+               current->counter=0;
+               need_resched = 1;
+       }
 }
 
 int sys_alarm(long seconds)
@@ -429,7 +462,7 @@ int sys_nice(long increment)
 {
        if (increment < 0 && !suser())
                return -EPERM;
-       if (increment > current->priority)
+       if (increment >= current->priority)
                increment = current->priority-1;
        current->priority -= increment;
        return 0;
index cf0aa01baa96e15371c37cb5faaea88b9f53217d..d1d5afd8df0aeaebf5fab6a0eedfdf1614a04d10 100644 (file)
@@ -11,9 +11,7 @@
 #include <signal.h>
 #include <sys/wait.h>
 #include <errno.h>
-  
-int send_sig (int, struct task_struct *, int);
-  
+
 int sys_sgetmask()
 {
        return current->blocked;
index 4dd1059a37f6bafd35983f3975f2182f9308589e..2318a7ed1bca5397cba3c28766ad6cd5184ea01d 100644 (file)
@@ -15,7 +15,7 @@
 #include <sys/utsname.h>
 #include <sys/param.h>
 #include <sys/resource.h>
-#include <string.h>
+#include <linux/string.h>
 
 /*
  * this indicates wether you can reboot with ctrl-alt-del: the deault is yes
@@ -30,6 +30,79 @@ struct timezone sys_tz = { 0, 0};
 
 extern int session_of_pgrp(int pgrp);
 
+#define        PZERO   15
+
+static int proc_sel(struct task_struct *p, int which, int who)
+{
+       switch (which) {
+               case PRIO_PROCESS:
+                       if (!who && p == current)
+                               return 1;
+                       return(p->pid == who);
+               case PRIO_PGRP:
+                       if (!who)
+                               who = current->pgrp;
+                       return(p->pgrp == who);
+               case PRIO_USER:
+                       if (!who)
+                               who = current->uid;
+                       return(p->uid == who);
+       }
+       return 0;
+}
+
+int sys_setpriority(int which, int who, int niceval)
+{
+       struct task_struct **p;
+       int error = ESRCH;
+       int priority;
+
+       if (which > 2 || which < 0)
+               return -EINVAL;
+
+       if ((priority = PZERO - niceval) <= 0)
+               priority = 1;
+
+       for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
+               if (!*p || !proc_sel(*p, which, who))
+                       continue;
+               if ((*p)->uid != current->euid &&
+                       (*p)->uid != current->uid && !suser()) {
+                       error = EPERM;
+                       continue;
+               }
+               if (error == ESRCH)
+                       error = 0;
+               if (priority > (*p)->priority && !suser())
+                       error = EACCES;
+               else
+                       (*p)->priority = priority;
+       }
+       return -error;
+}
+
+int sys_getpriority(int which, int who)
+{
+       struct task_struct **p;
+       int max_prio = 0;
+
+       if (which > 2 || which < 0)
+               return -EINVAL;
+
+       for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
+               if (!*p || !proc_sel(*p, which, who))
+                       continue;
+               if ((*p)->priority > max_prio)
+                       max_prio = (*p)->priority;
+       }
+       return(max_prio ? max_prio : -ESRCH);
+}
+
+int sys_profil()
+{
+       return -ENOSYS;
+}
+
 int sys_ftime()
 {
        return -ENOSYS;
@@ -378,7 +451,8 @@ int sys_uname(struct utsname * name)
 {
        int i;
 
-       if (!name) return -ERROR;
+       if (!name)
+               return -EINVAL;
        verify_area(name,sizeof *name);
        for(i=0;i<sizeof *name;i++)
                put_fs_byte(((char *) &thisname)[i],i+(char *) name);
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
new file mode 100644 (file)
index 0000000..ad70318
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *  linux/kernel/sys_call.S
+ *
+ *  (C) 1991  Linus Torvalds
+ */
+
+/*
+ * sys_call.S  contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ *     ptrace needs to have all regs on the stack.
+ *     if the order here is changed, it needs to be 
+ *     updated in fork.c:copy_process, signal.c:do_signal,
+ *     ptrace.c and ptrace.h
+ *
+ *      0(%esp) - %ebx
+ *      4(%esp) - %ecx
+ *      8(%esp) - %edx
+ *       C(%esp) - %esi
+ *     10(%esp) - %edi
+ *     14(%esp) - %ebp
+ *     18(%esp) - %eax
+ *     1C(%esp) - %ds
+ *     20(%esp) - %es
+ *      24(%esp) - %fs
+ *     28(%esp) - %gs
+ *     2C(%esp) - orig_eax
+ *     30(%esp) - %eip
+ *     34(%esp) - %cs
+ *     38(%esp) - %eflags
+ *     3C(%esp) - %oldesp
+ *     40(%esp) - %oldss
+ */
+
+SIG_CHLD       = 17
+
+EBX            = 0x00
+ECX            = 0x04
+EDX            = 0x08
+ESI            = 0x0C
+EDI            = 0x10
+EBP            = 0x14
+EAX            = 0x18
+DS             = 0x1C
+ES             = 0x20
+FS             = 0x24
+GS             = 0x28
+ORIG_EAX       = 0x2C
+EIP            = 0x30
+CS             = 0x34
+EFLAGS         = 0x38
+OLDESP         = 0x3C
+OLDSS          = 0x40
+
+/*
+ * these are offsets into the task-struct.
+ */
+state          = 0
+counter                = 4
+priority       = 8
+signal         = 12
+sigaction      = 16            # MUST be 16 (=len of sigaction)
+blocked                = (33*16)
+
+/*
+ * offsets within sigaction
+ */
+sa_handler     = 0
+sa_mask                = 4
+sa_flags       = 8
+sa_restorer    = 12
+
+ENOSYS = 38
+
+/*
+ * Ok, I get parallel printer interrupts while using the floppy for some
+ * strange reason. Urgel. Now I just ignore them.
+ */
+.globl _system_call,_timer_interrupt,_sys_execve
+.globl _device_not_available, _coprocessor_error
+.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
+.globl _double_fault,_coprocessor_segment_overrun
+.globl _invalid_TSS,_segment_not_present,_stack_segment
+.globl _general_protection,_irq13,_reserved
+.globl _alignment_check,_page_fault
+.globl _keyboard_interrupt,_hd_interrupt
+.globl _IRQ3_interrupt,_IRQ4_interrupt
+
+#define SAVE_ALL \
+       cld; \
+       push %gs; \
+       push %fs; \
+       push %es; \
+       push %ds; \
+       pushl %eax; \
+       pushl %ebp; \
+       pushl %edi; \
+       pushl %esi; \
+       pushl %edx; \
+       pushl %ecx; \
+       pushl %ebx; \
+       movl $0x10,%edx; \
+       mov %dx,%ds; \
+       mov %dx,%es; \
+       movl $0x17,%edx; \
+       mov %dx,%fs
+
+#define ACK_FIRST(mask) \
+       inb $0x21,%al; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     orb $(mask),%al; \
+       outb %al,$0x21; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     movb $0x20,%al; \
+       outb %al,$0x20
+
+#define ACK_SECOND(mask) \
+       inb $0xA1,%al; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     orb $(mask),%al; \
+       outb %al,$0xA1; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     movb $0x20,%al; \
+       outb %al,$0xA0 \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     outb %al,$0x20
+
+#define UNBLK_FIRST(mask) \
+       inb $0x21,%al; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     andb $~(mask),%al; \
+       outb %al,$0x21
+
+#define UNBLK_SECOND(mask) \
+       inb $0xA1,%al; \
+       jmp 1f; \
+1:     jmp 1f; \
+1:     andb $~(mask),%al; \
+       outb %al,$0xA1
+
+.align 2
+bad_sys_call:
+       movl $-ENOSYS,EAX(%esp)
+       jmp ret_from_sys_call
+.align 2
+reschedule:
+       pushl $ret_from_sys_call
+       jmp _schedule
+.align 2
+_system_call:
+       pushl %eax              # save orig_eax
+       SAVE_ALL
+       cmpl _NR_syscalls,%eax
+       jae bad_sys_call
+       call _sys_call_table(,%eax,4)
+       movl %eax,EAX(%esp)             # save the return value
+ret_from_sys_call:
+       cmpw $0x0f,CS(%esp)             # was old code segment supervisor ?
+       jne 2f
+       cmpw $0x17,OLDSS(%esp)          # was stack segment = 0x17 ?
+       jne 2f
+1:     movl _current,%eax
+       cmpl _task,%eax                 # task[0] cannot have signals
+       je 2f
+       cmpl $0,_need_resched
+       jne reschedule
+       cmpl $0,state(%eax)             # state
+       jne reschedule
+       cmpl $0,counter(%eax)           # counter
+       je reschedule
+       movl signal(%eax),%ebx
+       movl blocked(%eax),%ecx
+       notl %ecx
+       andl %ebx,%ecx
+       bsfl %ecx,%ecx
+       je 2f
+       btrl %ecx,%ebx
+       movl %ebx,signal(%eax)
+       incl %ecx
+       pushl %ecx
+       call _do_signal
+       popl %ecx
+       testl %eax, %eax
+       jne 1b                  # see if we need to switch tasks, or do more signals
+2:     popl %ebx
+       popl %ecx
+       popl %edx
+       popl %esi
+       popl %edi
+       popl %ebp
+       popl %eax
+       pop %ds
+       pop %es
+       pop %fs
+       pop %gs
+       addl $4,%esp            # skip the orig_eax
+       iret
+
+.align 2
+_irq13:
+       pushl %eax
+       xorb %al,%al
+       outb %al,$0xF0
+       movb $0x20,%al
+       outb %al,$0x20
+       jmp 1f
+1:     jmp 1f
+1:     outb %al,$0xA0
+       popl %eax
+_coprocessor_error:
+       pushl $-1               # mark this as an int. 
+       SAVE_ALL
+       pushl $ret_from_sys_call
+       jmp _math_error
+
+.align 2
+_device_not_available:
+       pushl $-1               # mark this as an int
+       SAVE_ALL
+       pushl $ret_from_sys_call
+       clts                            # clear TS so that we can use math
+       movl %cr0,%eax
+       testl $0x4,%eax                 # EM (math emulation bit)
+       je _math_state_restore
+       pushl $0                # temporary storage for ORIG_EIP
+       call _math_emulate
+       addl $4,%esp
+       ret
+
+.align 2
+_keyboard_interrupt:
+       pushl $-1
+       SAVE_ALL
+       ACK_FIRST(0x02)
+       sti
+       call _do_keyboard
+       cli
+       UNBLK_FIRST(0x02)
+       jmp ret_from_sys_call
+
+.align 2
+_IRQ3_interrupt:
+       pushl $-1
+       SAVE_ALL
+       ACK_FIRST(0x08)
+       sti
+       call _do_IRQ3
+       cli
+       UNBLK_FIRST(0x08)
+       jmp ret_from_sys_call
+
+.align 2
+_IRQ4_interrupt:
+       pushl $-1
+       SAVE_ALL
+       ACK_FIRST(0x10)
+       sti
+       call _do_IRQ4
+       cli
+       UNBLK_FIRST(0x10)
+       jmp ret_from_sys_call
+
+.align 2
+_timer_interrupt:
+       pushl $-1               # mark this as an int
+       SAVE_ALL
+       ACK_FIRST(0x01)
+       sti
+       incl _jiffies
+       movl CS(%esp),%eax
+       andl $3,%eax            # %eax is CPL (0 or 3, 0=supervisor)
+       pushl %eax
+       call _do_timer          # 'do_timer(long CPL)' does everything from
+       addl $4,%esp            # task switching to accounting ...
+       cli
+       UNBLK_FIRST(0x01)
+       jmp ret_from_sys_call
+
+.align 2
+_hd_interrupt:
+       pushl $-1
+       SAVE_ALL
+       ACK_SECOND(0x40)
+       andl $0xfffeffff,_timer_active
+       xorl %edx,%edx
+       xchgl _do_hd,%edx
+       testl %edx,%edx
+       jne 1f
+       movl $_unexpected_hd_interrupt,%edx
+1:     call *%edx              # "interesting" way of handling intr.
+       cli
+       UNBLK_SECOND(0x40)
+       jmp ret_from_sys_call
+
+.align 2
+_sys_execve:
+       lea (EIP+4)(%esp),%eax  # don't forget about the return address.
+       pushl %eax
+       call _do_execve
+       addl $4,%esp
+       ret
+
+_divide_error:
+       pushl $0                # no error code
+       pushl $_do_divide_error
+error_code:
+       push %fs
+       push %es
+       push %ds
+       pushl %eax
+       pushl %ebp
+       pushl %edi
+       pushl %esi
+       pushl %edx
+       pushl %ecx
+       pushl %ebx
+       cld
+       movl $-1, %eax
+       xchgl %eax, ORIG_EAX(%esp)      # orig_eax (get the error code. )
+       xorl %ebx,%ebx                  # zero ebx
+       mov %gs,%bx                     # get the lower order bits of gs
+       xchgl %ebx, GS(%esp)            # get the address and save gs.
+       pushl %eax                      # push the error code
+       lea 52(%esp),%edx
+       pushl %edx
+       movl $0x10,%edx
+       mov %dx,%ds
+       mov %dx,%es
+       movl $0x17,%edx
+       mov %dx,%fs
+       call *%ebx
+       addl $8,%esp
+       jmp ret_from_sys_call
+
+_debug:
+       pushl $0
+       pushl $_do_int3         # _do_debug
+       jmp error_code
+
+_nmi:
+       pushl $0
+       pushl $_do_nmi
+       jmp error_code
+
+_int3:
+       pushl $0
+       pushl $_do_int3
+       jmp error_code
+
+_overflow:
+       pushl $0
+       pushl $_do_overflow
+       jmp error_code
+
+_bounds:
+       pushl $0
+       pushl $_do_bounds
+       jmp error_code
+
+_invalid_op:
+       pushl $0
+       pushl $_do_invalid_op
+       jmp error_code
+
+_coprocessor_segment_overrun:
+       pushl $0
+       pushl $_do_coprocessor_segment_overrun
+       jmp error_code
+
+_reserved:
+       pushl $0
+       pushl $_do_reserved
+       jmp error_code
+
+_double_fault:
+       pushl $_do_double_fault
+       jmp error_code
+
+_invalid_TSS:
+       pushl $_do_invalid_TSS
+       jmp error_code
+
+_segment_not_present:
+       pushl $_do_segment_not_present
+       jmp error_code
+
+_stack_segment:
+       pushl $_do_stack_segment
+       jmp error_code
+
+_general_protection:
+       pushl $_do_general_protection
+       jmp error_code
+
+_alignment_check:
+       pushl $_do_alignment_check
+       jmp error_code
+
+_page_fault:
+       pushl $_do_page_fault
+       jmp error_code
diff --git a/kernel/sys_call.s b/kernel/sys_call.s
deleted file mode 100644 (file)
index 8d7a982..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- *  linux/kernel/system_call.s
- *
- *  (C) 1991  Linus Torvalds
- */
-
-/*
- *  system_call.s  contains the system-call low-level handling routines.
- * This also contains the timer-interrupt handler, as some of the code is
- * the same. The hd- and flopppy-interrupts are also here.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call. Ordinary interrupts
- * don't handle signal-recognition, as that would clutter them up totally
- * unnecessarily.
- *
- * Stack layout in 'ret_from_system_call':
- *     ptrace needs to have all regs on the stack.
- *     if the order here is changed, it needs to be 
- *     updated in fork.c:copy_process, signal.c:do_signal,
- *     ptrace.c ptrace.h
- *
- *      0(%esp) - %ebx
- *      4(%esp) - %ecx
- *      8(%esp) - %edx
- *       C(%esp) - %esi
- *     10(%esp) - %edi
- *     14(%esp) - %ebp
- *     18(%esp) - %eax
- *     1C(%esp) - %ds
- *     20(%esp) - %es
- *      24(%esp) - %fs
- *     28(%esp) - %gs
- *     2C(%esp) - orig_eax
- *     30(%esp) - %eip
- *     34(%esp) - %cs
- *     38(%esp) - %eflags
- *     3C(%esp) - %oldesp
- *     40(%esp) - %oldss
- */
-
-SIG_CHLD       = 17
-
-EBX            = 0x00
-ECX            = 0x04
-EDX            = 0x08
-ESI            = 0x0C
-EDI            = 0x10
-EBP            = 0x14
-EAX            = 0x18
-DS             = 0x1C
-ES             = 0x20
-FS             = 0x24
-GS             = 0x28
-ORIG_EAX       = 0x2C
-EIP            = 0x30
-CS             = 0x34
-EFLAGS         = 0x38
-OLDESP         = 0x3C
-OLDSS          = 0x40
-
-state  = 0             # these are offsets into the task-struct.
-counter        = 4
-priority = 8
-signal = 12
-sigaction = 16         # MUST be 16 (=len of sigaction)
-blocked = (33*16)
-
-# offsets within sigaction
-sa_handler = 0
-sa_mask = 4
-sa_flags = 8
-sa_restorer = 12
-
-nr_system_calls = 82
-
-ENOSYS = 38
-
-/*
- * Ok, I get parallel printer interrupts while using the floppy for some
- * strange reason. Urgel. Now I just ignore them.
- */
-.globl _system_call,_timer_interrupt,_sys_execve
-.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
-.globl _device_not_available, _coprocessor_error
-
-.align 2
-bad_sys_call:
-       pushl $-ENOSYS
-       jmp ret_from_sys_call
-.align 2
-reschedule:
-       pushl $ret_from_sys_call
-       jmp _schedule
-.align 2
-_system_call:
-       cld
-       pushl %eax              # save orig_eax
-       push %gs
-       push %fs
-       push %es
-       push %ds
-       pushl %eax              # save eax.  The return value will be put here.
-       pushl %ebp
-       pushl %edi
-       pushl %esi
-       pushl %edx              
-       pushl %ecx              # push %ebx,%ecx,%edx as parameters
-       pushl %ebx              # to the system call
-       movl $0x10,%edx         # set up ds,es to kernel space
-       mov %dx,%ds
-       mov %dx,%es
-       movl $0x17,%edx         # fs points to local data space
-       mov %dx,%fs
-       cmpl _NR_syscalls,%eax
-       jae bad_sys_call
-       call _sys_call_table(,%eax,4)
-       movl %eax,EAX(%esp)             # save the return value
-2:     movl _current,%eax
-       cmpl $0,state(%eax)             # state
-       jne reschedule
-       cmpl $0,counter(%eax)           # counter
-       je reschedule
-ret_from_sys_call:
-       movl _current,%eax
-       cmpl _task,%eax                 # task[0] cannot have signals
-       je 3f
-       cmpw $0x0f,CS(%esp)             # was old code segment supervisor ?
-       jne 3f
-       cmpw $0x17,OLDSS(%esp)          # was stack segment = 0x17 ?
-       jne 3f
-       movl signal(%eax),%ebx
-       movl blocked(%eax),%ecx
-       notl %ecx
-       andl %ebx,%ecx
-       bsfl %ecx,%ecx
-       je 3f
-       btrl %ecx,%ebx
-       movl %ebx,signal(%eax)
-       incl %ecx
-       pushl %ecx
-       call _do_signal
-       popl %ecx
-       testl %eax, %eax
-       jne 2b          # see if we need to switch tasks, or do more signals
-3:
-       popl %ebx
-       popl %ecx
-       popl %edx
-       popl %esi
-       popl %edi
-       popl %ebp
-       popl %eax
-       pop %ds
-       pop %es
-       pop %fs
-       pop %gs
-       addl $4,%esp            # skip the orig_eax
-       iret
-
-.align 2
-_coprocessor_error:
-       cld
-       pushl $-1               # mark this as an int. 
-       push %gs
-       push %fs
-       push %es
-       push %ds
-       pushl %eax              # save eax.
-       pushl %ebp
-       pushl %edi
-       pushl %esi
-       pushl %edx
-       pushl %ecx
-       pushl %ebx
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       movl $0x17,%eax
-       mov %ax,%fs
-       pushl $ret_from_sys_call
-       jmp _math_error
-
-.align 2
-_device_not_available:
-       cld
-       pushl $-1               # mark this as an int
-       push %gs
-       push %fs
-       push %es
-       push %ds
-       pushl %eax              
-       pushl %ebp
-       pushl %edi
-       pushl %esi
-       pushl %edx
-       pushl %ecx
-       pushl %ebx
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       movl $0x17,%eax
-       mov %ax,%fs
-       pushl $ret_from_sys_call
-       clts                            # clear TS so that we can use math
-       movl %cr0,%eax
-       testl $0x4,%eax                 # EM (math emulation bit)
-       je _math_state_restore
-       pushl $0                # temporary storage for ORIG_EIP
-       call _math_emulate
-       addl $4,%esp
-       ret
-
-.align 2
-_timer_interrupt:
-       cld
-       pushl $-1               # mark this as an int
-       push %gs
-       push %fs
-       push %es
-       push %ds
-       pushl %eax
-       pushl %ebp
-       pushl %edi
-       pushl %esi
-       pushl %edx              
-       pushl %ecx
-       pushl %ebx
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       movl $0x17,%eax
-       mov %ax,%fs
-       incl _jiffies
-       movb $0x20,%al          # EOI to interrupt controller #1
-       outb %al,$0x20
-       movl CS(%esp),%eax
-       andl $3,%eax            # %eax is CPL (0 or 3, 0=supervisor)
-       pushl %eax
-       call _do_timer          # 'do_timer(long CPL)' does everything from
-       addl $4,%esp            # task switching to accounting ...
-       jmp ret_from_sys_call
-
-.align 2
-_sys_execve:
-       lea (EIP+4)(%esp),%eax  # don't forget about the return address.
-       pushl %eax
-       call _do_execve
-       addl $4,%esp
-       ret
-
-_hd_interrupt:
-       cld
-       pushl %eax
-       pushl %ecx
-       pushl %edx
-       push %ds
-       push %es
-       push %fs
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       movl $0x17,%eax
-       mov %ax,%fs
-       movb $0x20,%al
-       outb %al,$0xA0          # EOI to interrupt controller #1
-       jmp 1f                  # give port chance to breathe
-1:     jmp 1f
-1:     outb %al,$0x20
-       andl $0xfffeffff,_timer_active
-       xorl %edx,%edx
-       xchgl _do_hd,%edx
-       testl %edx,%edx
-       jne 1f
-       movl $_unexpected_hd_interrupt,%edx
-1:     call *%edx              # "interesting" way of handling intr.
-       pop %fs
-       pop %es
-       pop %ds
-       popl %edx
-       popl %ecx
-       popl %eax
-       iret
-
-_floppy_interrupt:
-       cld
-       pushl %eax
-       pushl %ecx
-       pushl %edx
-       push %ds
-       push %es
-       push %fs
-       movl $0x10,%eax
-       mov %ax,%ds
-       mov %ax,%es
-       movl $0x17,%eax
-       mov %ax,%fs
-       movb $0x20,%al
-       outb %al,$0x20          # EOI to interrupt controller #1
-       xorl %eax,%eax
-       xchgl _do_floppy,%eax
-       testl %eax,%eax
-       jne 1f
-       movl $_unexpected_floppy_interrupt,%eax
-1:     call *%eax              # "interesting" way of handling intr.
-       pop %fs
-       pop %es
-       pop %ds
-       popl %edx
-       popl %ecx
-       popl %eax
-       iret
-
-_parallel_interrupt:
-       cld
-       pushl %eax
-       movb $0x20,%al
-       outb %al,$0x20
-       popl %eax
-       iret
index 797bb79d60dc46cf06b84783bfdd37350a56b41b..c05b54949af72fce549a563c696b1bf85116f266 100644 (file)
@@ -10,7 +10,7 @@
  * to mainly kill the offending process (probably by giving it a signal,
  * but possibly by killing it outright if necessary).
  */
-#include <string.h>
+#include <linux/string.h>
 
 #include <linux/head.h>
 #include <linux/sched.h>
@@ -60,7 +60,6 @@ void reserved(void);
 void parallel_interrupt(void);
 void irq13(void);
 void alignment_check(void);
-int send_sig(long, struct task_struct *, int);
 
 static void die(char * str,long esp_ptr,long nr)
 {
@@ -84,7 +83,10 @@ static void die(char * str,long esp_ptr,long nr)
        for(i=0;i<10;i++)
                printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
        printk("\n\r");
-       do_exit(11);            /* play segment exception */
+       if ((0xffff & esp[1]) == 0xf)
+               send_sig(SIGSEGV, current, 0);
+       else
+               do_exit(SIGSEGV);
 }
 
 void do_double_fault(long esp, long error_code)
@@ -99,7 +101,7 @@ void do_general_protection(long esp, long error_code)
 
 void do_alignment_check(long esp, long error_code)
 {
-    die("alignment check",esp,error_code);
+       die("alignment check",esp,error_code);
 }
 
 void do_divide_error(long esp, long error_code)
@@ -119,7 +121,7 @@ void do_nmi(long esp, long error_code)
 
 void do_debug(long esp, long error_code)
 {
-  send_sig(SIGTRAP, current, 0);
+       send_sig(SIGTRAP, current, 0);
 }
 
 void do_overflow(long esp, long error_code)
index 06b910e5a9b7683c973312ec243086c9b6bb6838..8ce9873fa1c5c5b42fe52728bf7caa6ba75b3848 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <stdarg.h>
-#include <string.h>
+#include <linux/string.h>
 
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
index 83a543fa1ed8b29d71c19b79f22b59d75017ce24..94b649f0a68a7162b06be7437bb49580d40104f6 100644 (file)
@@ -11,7 +11,7 @@ AS    =as
 LD     =ld
 LDFLAGS        =-s -x
 CC     =gcc -nostdinc -I../include
-CPP    =cpp -nostdinc -I../include
+CPP    =gcc -E -nostdinc -I../include
 
 .c.s:
        $(CC) $(CFLAGS) \
@@ -40,32 +40,35 @@ dep:
        cp tmp_make Makefile
 
 ### Dependencies:
-_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
-close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
-ctype.s ctype.o : ctype.c ../include/ctype.h 
-dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
+_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
+close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
+ctype.s ctype.o : ctype.c ../include/linux/ctype.h 
+dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
 errno.s errno.o : errno.c 
-execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
-malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \
+execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
+malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h ../include/linux/fs.h \
+  ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/signal.h \
   ../include/asm/system.h 
-open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h ../include/stdarg.h 
-setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
-string.s string.o : string.c ../include/string.h 
-wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h ../include/sys/wait.h 
-write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \
-  ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
-  ../include/utime.h 
+open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h \
+  ../include/stdarg.h 
+setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
+string.s string.o : string.c ../include/linux/string.h 
+wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h \
+  ../include/sys/wait.h 
+write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+  ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h 
index afd8364f6bec674045faf32d985ec1247102a8e6..3ef965d0c52e117fc1896399b0a344d702b5f66d 100644 (file)
@@ -8,3 +8,4 @@
 #include <unistd.h>
 
 _syscall1(int,close,int,fd)
+
index 877e629c0ecb0368fb133810dbf3df8c50f16962..f1103a9fd4c857bc0ce6ac0150cd7400b6cda3e2 100644 (file)
@@ -4,7 +4,7 @@
  *  (C) 1991  Linus Torvalds
  */
 
-#include <ctype.h>
+#include <linux/ctype.h>
 
 char _ctmp;
 unsigned char _ctype[] = {0x00,                        /* EOF */
index dd13414adf60e5e8302b6d4b6be30006af669ecf..495c6e3c5c0db8b20c1ad94c99698d6016086326 100644 (file)
--- a/lib/dup.c
+++ b/lib/dup.c
@@ -8,3 +8,4 @@
 #include <unistd.h>
 
 _syscall1(int,dup,int,fd)
+
index a89726dec77064d6c4f95b345df8aeebdcb0c0d1..7669b50d3f329a73a8a8439c54ce9653fb60d31b 100644 (file)
@@ -8,3 +8,4 @@
 #include <unistd.h>
 
 _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+
index 68516c7e579d05c942b158d48e79c327d2b31c55..601fcfc3e0ec3566edad4800ee18b12d4f0b6204 100644 (file)
@@ -8,3 +8,4 @@
 #include <unistd.h>
 
 _syscall0(pid_t,setsid)
+
index 1182e635f400205a6b182c6ff76d4a6aefa64ab1..ebbdffff404c2ee403ce55497d04933a6580b4ae 100644 (file)
@@ -11,4 +11,4 @@
 #define extern
 #define inline
 #define __LIBRARY__
-#include <string.h>
+#include <linux/string.h>
index 2815c16aeeb578592cfdb17bd69f95eb1311b4d0..e02dfdf64ee1717a844da5b8793f200bce8412a9 100644 (file)
@@ -14,3 +14,4 @@ pid_t wait(int * wait_stat)
 {
        return waitpid(-1,wait_stat,0);
 }
+
index df52e74d6ede3b10fc2c96ca77e9696d432c2de5..69d4ab37461694ac5907fd7ac9e20d9931c04e6a 100644 (file)
@@ -8,3 +8,4 @@
 #include <unistd.h>
 
 _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+
index 27b2f4ec397cc4aefb77f1279136ff61da4c21d0..c60e25bc828450ce85d540f811ff1821c2c83bd6 100644 (file)
@@ -22,7 +22,7 @@ CPP   =cpp -nostdinc -I../include
        $(CC) $(CFLAGS) \
        -S -o $*.s $<
 
-OBJS   = memory.o swap.o
+OBJS   = memory.o swap.o mmap.o
 
 mm.o: $(OBJS)
        $(LD) -r -o mm.o $(OBJS)
@@ -37,14 +37,17 @@ dep:
        cp tmp_make Makefile
 
 ### Dependencies:
-memory.o : memory.c ../include/signal.h ../include/sys/types.h \
-  ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
-  ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
-  ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
+memory.o : memory.c ../include/signal.h ../include/sys/types.h ../include/asm/system.h \
+  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
   ../include/sys/time.h ../include/time.h ../include/sys/resource.h 
-swap.o : swap.c ../include/string.h ../include/errno.h \
-  ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \
-  ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \
-  ../include/signal.h ../include/sys/stat.h ../include/linux/sched.h \
-  ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h \
-  ../include/time.h ../include/sys/resource.h 
+mmap.o : mmap.c ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
+  ../include/asm/system.h ../include/errno.h ../include/sys/mman.h 
+swap.o : swap.c ../include/errno.h ../include/sys/stat.h ../include/sys/types.h \
+  ../include/linux/mm.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+  ../include/linux/kernel.h ../include/signal.h ../include/linux/string.h ../include/linux/sched.h \
+  ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+  ../include/sys/resource.h 
index 8e93a1b8bbe2bb290bfff2ab6c58034ee61a8372..1417bc9c7a45cb51364cf0a0ea7b31a850a980b5 100644 (file)
@@ -185,6 +185,159 @@ int copy_page_tables(unsigned long from,unsigned long to,long size)
        return 0;
 }
 
+/*
+ * a more complete version of free_page_tables which performs with page
+ * granularity.
+ */
+int
+unmap_page_range(unsigned long from, unsigned long size)
+{
+       unsigned long page, page_dir;
+       unsigned long *page_table, *dir;
+       unsigned long poff, pcnt, pc;
+
+       if (from & 0xfff)
+               panic("unmap_page_range called with wrong alignment");
+       if (!from)
+               panic("unmap_page_range trying to free swapper memory space");
+       size = (size + 0xfff) >> 12;
+       dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
+       poff = (from >> 12) & 0x3ff;
+       if ((pcnt = 1024 - poff) > size)
+               pcnt = size;
+
+       for ( ; size > 0; ++dir, size -= pcnt,
+            pcnt = (size > 1024 ? 1024 : size)) {
+               if (!(page_dir = *dir)) {
+                       poff = 0;
+                       continue;
+               }
+               if (!(page_dir & 1)) {
+                       printk("unmap_page_range: bad page directory.");
+                       continue;
+               }
+               page_table = (unsigned long *)(0xfffff000 & page_dir);
+               if (poff) {
+                       page_table += poff;
+                       poff = 0;
+               }
+               for (pc = pcnt; pc--; page_table++) {
+                       if (page = *page_table) {
+                               --current->rss;
+                               *page_table = 0;
+                               if (1 & page)
+                                       free_page(0xfffff000 & page);
+                               else
+                                       swap_free(page >> 1);
+                       }
+               }
+               if (pcnt == 1024) {
+                       free_page(0xfffff000 & page_dir);
+                       *dir = 0;
+               }
+       }
+       invalidate();
+       for (page = 0; page < CHECK_LAST_NR ; page++)
+               last_pages[page] = 0;
+       return 0;
+}
+
+/*
+ * maps a range of physical memory into the requested pages. the old
+ * mappings are removed. any references to nonexistent pages results
+ * in null mappings (currently treated as "copy-on-access")
+ *
+ * permiss is encoded as cxwr (copy,exec,write,read) where copy modifies
+ * the behavior of write to be copy-on-write.
+ *
+ * due to current limitations, we actually have the following
+ *             on              off
+ * read:       yes             yes
+ * write/copy: yes/copy        copy/copy
+ * exec:       yes             yes
+ */
+int
+remap_page_range(unsigned long from, unsigned long to, unsigned long size,
+                int permiss)
+{
+       unsigned long *page_table, *dir;
+       unsigned long poff, pcnt;
+
+       if ((from & 0xfff) || (to & 0xfff))
+               panic("remap_page_range called with wrong alignment");
+       dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
+       size = (size + 0xfff) >> 12;
+       poff = (from >> 12) & 0x3ff;
+       if ((pcnt = 1024 - poff) > size)
+               pcnt = size;
+
+       while (size > 0) {
+               if (!(1 & *dir)) {
+                       if (!(page_table = (unsigned long *)get_free_page())) {
+                               invalidate();
+                               return -1;
+                       }
+                       *dir++ = ((unsigned long) page_table) | 7;
+               }
+               else
+                       page_table = (unsigned long *)(0xfffff000 & *dir++);
+               if (poff) {
+                       page_table += poff;
+                       poff = 0;
+               }
+
+               for (size -= pcnt; pcnt-- ;) {
+                       int mask;
+
+                       mask = 4;
+                       if (permiss & 1)
+                               mask |= 1;
+                       if (permiss & 2) {
+                               if (permiss & 8)
+                                       mask |= 1;
+                               else
+                                       mask |= 3;
+                       }
+                       if (permiss & 4)
+                               mask |= 1;
+
+                       if (*page_table) {
+                               --current->rss;
+                               if (1 & *page_table)
+                                       free_page(0xfffff000 & *page_table);
+                               else
+                                       swap_free(*page_table >> 1);
+                       }
+
+                       /*
+                        * i'm not sure of the second cond here. should we
+                        * report failure?
+                        * the first condition should return an invalid access
+                        * when the page is referenced. current assumptions
+                        * cause it to be treated as demand allocation.
+                        */
+                       if (mask == 4 || to >= HIGH_MEMORY)
+                               *page_table++ = 0;      /* not present */
+                       else {
+                               ++current->rss;
+                               *page_table++ = (to | mask);
+                               if (to > LOW_MEM) {
+                                       unsigned long frame;
+                                       frame = to - LOW_MEM;
+                                       frame >>= 12;
+                                       mem_map[frame]++;
+                               }
+                       }
+                       to += PAGE_SIZE;
+               }
+               pcnt = (size > 1024 ? 1024 : size);
+       }
+       invalidate();
+       for (to = 0; to < CHECK_LAST_NR ; to++)
+               last_pages[to] = 0;
+       return 0;
+}
+
 /*
  * This function puts a page in memory at the wanted address.
  * It returns the physical address of the page gotten, 0 if
@@ -202,7 +355,7 @@ static unsigned long put_page(unsigned long page,unsigned long address)
                return 0;
        }
        if (mem_map[(page-LOW_MEM)>>12] != 1) {
-               printk("mem_map disagrees with %p at %p\n",page,address);
+               printk("put_page: mem_map disagrees with %p at %p\n",page,address);
                return 0;
        }
        page_table = (unsigned long *) ((address>>20) & 0xffc);
@@ -410,6 +563,7 @@ static int try_to_share(unsigned long address, struct task_struct * p)
 static int share_page(struct inode * inode, unsigned long address)
 {
        struct task_struct ** p;
+       int i;
 
        if (inode->i_count < 2 || !inode)
                return 0;
@@ -422,7 +576,10 @@ static int share_page(struct inode * inode, unsigned long address)
                        if (inode != (*p)->executable)
                                continue;
                } else {
-                       if (inode != (*p)->library)
+                       for (i=0; i < (*p)->numlibraries; i++)
+                               if (inode == (*p)->libraries[i].library)
+                                       break;
+                       if (i >= (*p)->numlibraries)
                                continue;
                }
                if (try_to_share(address,*p))
@@ -431,14 +588,39 @@ static int share_page(struct inode * inode, unsigned long address)
        return 0;
 }
 
+/*
+ * fill in an empty page or directory if none exists
+ */
+static unsigned long get_empty(unsigned long * p)
+{
+       unsigned long page = 0;
+
+repeat:
+       if (1 & *p) {
+               free_page(page);
+               return *p;
+       }
+       if (*p) {
+               printk("get_empty: bad page entry \n");
+               *p = 0;
+       }
+       if (page) {
+               *p = page | 7;
+               return *p;
+       }
+       if (!(page = get_free_page()))
+               oom();
+       goto repeat;
+}
+
 void do_no_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk)
+       struct task_struct *tsk, unsigned long user_esp)
 {
        static unsigned int last_checked = 0;
        int nr[4];
        unsigned long tmp;
        unsigned long page;
-       int block,i;
+       unsigned int block,i;
        struct inode * inode;
 
        /* Thrashing ? Make it interruptible, but don't penalize otherwise */
@@ -459,44 +641,50 @@ void do_no_page(unsigned long error_code, unsigned long address,
                printk("Bad things happen: nonexistent page error in do_no_page\n\r");
                do_exit(SIGSEGV);
        }
+       page = get_empty((unsigned long *) ((address >> 20) & 0xffc));
+       page &= 0xfffff000;
+       page += (address >> 10) & 0xffc;
+       tmp = *(unsigned long *) page;
+       if (tmp & 1) {
+               printk("bogus do_no_page\n");
+               return;
+       }
        ++tsk->rss;
-       page = *(unsigned long *) ((address >> 20) & 0xffc);
-/* check the page directory: make a page dir entry if no such exists */
-       if (page & 1) {
-               page &= 0xfffff000;
-               page += (address >> 10) & 0xffc;
-               tmp = *(unsigned long *) page;
-               if (tmp && !(1 & tmp)) {
-                       ++tsk->maj_flt;
-                       swap_in((unsigned long *) page);
-                       return;
-               }
-       } else {
-               if (page)
-                       printk("do_no_page: bad page directory\n");
-               if (!(page = get_free_page()))
-                       oom();
-               page |= 7;
-               *(unsigned long *) ((address >> 20) & 0xffc) = page;
+       if (tmp) {
+               ++tsk->maj_flt;
+               swap_in((unsigned long *) page);
+               return;
        }
        address &= 0xfffff000;
        tmp = address - tsk->start_code;
-       if (tmp >= LIBRARY_OFFSET ) {
-               inode = tsk->library;
-               block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE;
-       } else if (tmp < tsk->end_data) {
+       inode = NULL;
+       block = 0;
+       if (tmp < tsk->end_data) {
                inode = tsk->executable;
                block = 1 + tmp / BLOCK_SIZE;
        } else {
-               inode = NULL;
-               block = 0;
+               i = tsk->numlibraries;
+               while (i-- > 0) {
+                       if (tmp < tsk->libraries[i].start)
+                               continue;
+                       block = tmp - tsk->libraries[i].start;
+                       if (block >= tsk->libraries[i].length)
+                               continue;
+                       inode = tsk->libraries[i].library;
+                       block = 1 + block / BLOCK_SIZE;
+                       break;
+               }
        }
        if (!inode) {
                ++tsk->min_flt;
-               if (tmp > tsk->brk && tsk == current && 
-                       LIBRARY_OFFSET - tmp > tsk->rlim[RLIMIT_STACK].rlim_max)
-                               do_exit(SIGSEGV);
                get_empty_page(address);
+               if (tsk != current)
+                       return;
+               if (tmp >= LIBRARY_OFFSET || tmp < tsk->brk)
+                       return;
+               if (tmp+8192 >= (user_esp & 0xfffff000))
+                       return;
+               send_sig(SIGSEGV,tsk,1);
                return;
        }
        if (tsk == current)
@@ -507,7 +695,6 @@ void do_no_page(unsigned long error_code, unsigned long address,
        ++tsk->maj_flt;
        if (!(page = get_free_page()))
                oom();
-/* remember that 1 block is used for header */
        for (i=0 ; i<4 ; block++,i++)
                nr[i] = bmap(inode,block);
        bread_page(page,inode->i_dev,nr);
@@ -515,7 +702,7 @@ void do_no_page(unsigned long error_code, unsigned long address,
        if (i>4095)
                i = 0;
        tmp = page + 4096;
-       while (i-- > 0) {
+       while (i--) {
                tmp--;
                *(char *)tmp = 0;
        }
@@ -546,15 +733,7 @@ void show_mem(void)
        int i,j,k,free=0,total=0;
        int shared = 0;
        unsigned long * pg_tbl;
-       static int lock = 0;
 
-       cli();
-       if (lock) {
-               sti();
-               return;
-       }
-       lock = 1;
-       sti();
        printk("Mem-info:\n\r");
        for(i=0 ; i<PAGING_PAGES ; i++) {
                if (mem_map[i] == USED)
@@ -595,7 +774,6 @@ void show_mem(void)
                }
        }
        printk("Memory found: %d (%d)\n\r",free-shared,total);
-       lock = 0;
 }
 
 
@@ -605,11 +783,16 @@ void show_mem(void)
 void do_page_fault(unsigned long *esp, unsigned long error_code)
 {
        unsigned long address;
-       /* get the address */
+       unsigned long user_esp;
 
+       if ((0xffff & esp[1]) == 0xf)
+               user_esp = esp[3];
+       else
+               user_esp = 0;
+       /* get the address */
        __asm__("movl %%cr2,%0":"=r" (address));
        if (!(error_code & 1)) {
-               do_no_page(error_code, address, current);
+               do_no_page(error_code, address, current, user_esp);
                return;
        } else {
                do_wp_page(error_code, address);
diff --git a/mm/mmap.c b/mm/mmap.c
new file mode 100644 (file)
index 0000000..a8ea628
--- /dev/null
+++ b/mm/mmap.c
@@ -0,0 +1,196 @@
+/*
+ *     linux/mm/mmap.c
+ *
+ * Written by obz.
+ */
+#include <sys/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+/*
+ * description of effects of mapping type and prot in current implementation.
+ * this is due to the current handling of page faults in memory.c. the expected
+ * behavior is in parens:
+ *
+ * map_type    prot
+ *             PROT_NONE       PROT_READ       PROT_WRITE      PROT_EXEC
+ * MAP_SHARED  r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
+ *             w: (no) yes     w: (no) copy    w: (yes) yes    w: (no) no
+ *             x: (no) no      x: (no) no      x: (no) no      x: (yes) no
+ *             
+ * MAP_PRIVATE r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
+ *             w: (no) copy    w: (no) copy    w: (copy) copy  w: (no) no
+ *             x: (no) no      x: (no) no      x: (no) no      x: (yes) no
+ *
+ * the permissions are encoded as cxwr (copy,exec,write,read)
+ */
+#define MTYP(T) ((T) & MAP_TYPE)
+#define PREAD(T,P) (((P) & PROT_READ) ? 1 : 0)
+#define PWRITE(T,P) (((P) & PROT_WRITE) ? (MTYP(T) == MAP_SHARED ? 2 : 10) : 0)
+#define PEXEC(T,P) (((P) & PROT_EXEC) ? 4 : 0)
+#define PERMISS(T,P) (PREAD(T,P)|PWRITE(T,P)|PEXEC(T,P))
+
+#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
+                         current->start_code + current->end_code)
+
+extern int remap_page_range(unsigned long from, unsigned long to,
+                           unsigned long size, int permiss);
+extern int unmap_page_range(unsigned long from, unsigned long size);
+
+static caddr_t
+mmap_chr(unsigned long addr, size_t len, int prot, int flags,
+        struct inode *inode, unsigned long off)
+{
+       int major, minor;
+       extern unsigned long HIGH_MEMORY;
+
+       major = MAJOR(inode->i_rdev);
+       minor = MINOR(inode->i_rdev);
+
+       /*
+        * for character devices, only /dev/mem may be mapped. when the
+        * swapping code is modified to allow arbitrary sources of pages,
+        * then we can open it up to regular files.
+        */
+
+       if (major != 1 || minor != 1)
+               return (caddr_t)-ENODEV;
+
+       /*
+        * we only allow mappings from address 0 to HIGH_MEMORY, since thats
+        * the range of our memory [actually this is a lie. the buffer cache
+        * and ramdisk occupy higher memory, but the paging stuff won't
+        * let us map to it anyway, so we break it here].
+        *
+        * this call is very dangerous! because of the lack of adequate
+        * tagging of frames, it is possible to mmap over a frame belonging
+        * to another (innocent) process. with MAP_SHARED|MAP_WRITE, this
+        * rogue process can trample over the other's data! we ignore this :{
+        * for now, we hope people will malloc the required amount of space,
+        * then mmap over it. the mm needs serious work before this can be
+        * truly useful.
+        */
+
+       if (len > HIGH_MEMORY || off > HIGH_MEMORY - len) /* avoid overflow */
+               return (caddr_t)-ENXIO;
+
+       if (remap_page_range(addr, off, len, PERMISS(flags, prot)))
+               return (caddr_t)-EAGAIN;
+       
+       return (caddr_t)addr;
+}
+
+caddr_t
+sys_mmap(unsigned long *buffer)
+{
+       unsigned long base, addr;
+       unsigned long len, limit, off;
+       int prot, flags, fd;
+       struct file *file;
+       struct inode *inode;
+
+       addr = (unsigned long)  get_fs_long(buffer);    /* user address space*/
+       len = (size_t)          get_fs_long(buffer+1);  /* nbytes of mapping */
+       prot = (int)            get_fs_long(buffer+2);  /* protection */
+       flags = (int)           get_fs_long(buffer+3);  /* mapping type */
+       fd = (int)              get_fs_long(buffer+4);  /* object to map */
+       off = (unsigned long)   get_fs_long(buffer+5);  /* offset in object */
+
+       if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
+               return (caddr_t) -EBADF;
+       if (addr > TASK_SIZE || (addr+(unsigned long) len) > TASK_SIZE)
+               return (caddr_t) -EINVAL;
+       inode = file->f_inode;
+
+       /*
+        * do simple checking here so the lower-level routines won't have
+        * to. we assume access permissions have been handled by the open
+        * of the memory object, so we don't do any here.
+        */
+
+       switch (flags & MAP_TYPE) {
+       case MAP_SHARED:
+               if ((prot & PROT_WRITE) && !(file->f_mode & 2))
+                       return (caddr_t)-EINVAL;
+               /* fall through */
+       case MAP_PRIVATE:
+               if (!(file->f_mode & 1))
+                       return (caddr_t)-EINVAL;
+               break;
+
+       default:
+               return (caddr_t)-EINVAL;
+       }
+
+       /*
+        * obtain the address to map to. we verify (or select) it and ensure
+        * that it represents a valid section of the address space. we assume
+        * that if PROT_EXEC is specified this should be in the code segment.
+        */
+       if (prot & PROT_EXEC) {
+               base = get_base(current->ldt[1]);       /* cs */
+               limit = get_limit(0x0f);                /* cs limit */
+       } else {
+               base = get_base(current->ldt[2]);       /* ds */
+               limit = get_limit(0x17);                /* ds limit */
+       }
+
+       if (flags & MAP_FIXED) {
+               /*
+                * if MAP_FIXED is specified, we have to map exactly at this
+                * address. it must be page aligned and not ambiguous.
+                */
+               if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
+                   (off & 0xfff))
+                       return (caddr_t)-EINVAL;
+               if (addr + len > limit)
+                       return (caddr_t)-ENOMEM;
+       } else {
+               /*
+                * we're given a hint as to where to put the address.
+                * that we still need to search for a range of pages which
+                * are not mapped and which won't impact the stack or data
+                * segment.
+                * in linux, we only have a code segment and data segment.
+                * since data grows up and stack grows down, we're sort of
+                * stuck. placing above the data will break malloc, below
+                * the stack will cause stack overflow. because of this
+                * we don't allow nonspecified mappings...
+                */
+               return (caddr_t)-ENOMEM;
+       }
+
+       /*
+        * determine the object being mapped and call the appropriate
+        * specific mapper. the address has already been validated, but
+        * not unmapped
+        */
+       if (S_ISCHR(inode->i_mode))
+               addr = (unsigned long)mmap_chr(base + addr, len, prot, flags,
+                                              inode, off);
+       else
+               addr = (unsigned long)-ENODEV;
+       if ((long)addr > 0)
+               addr -= base;
+
+       return (caddr_t)addr;
+}
+
+int sys_munmap(unsigned long addr, size_t len)
+{
+       unsigned long base, limit;
+
+       base = get_base(current->ldt[2]);       /* map into ds */
+       limit = get_limit(0x17);                /* ds limit */
+
+       if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
+           addr + len > limit)
+               return -EINVAL;
+       if (unmap_page_range(base + addr, len))
+               return -EAGAIN; /* should never happen */
+       return 0;
+}
index 819bbe35d80a86ecaabbb8a3d523abd36ad3ea81..fa933e3eafeb0a54a3054ef9c907130220e99e4d 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -9,11 +9,11 @@
  * Started 18.12.91
  */
 
-#include <string.h>
 #include <errno.h>
+#include <sys/stat.h>
 
 #include <linux/mm.h>
-#include <sys/stat.h>
+#include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/head.h>
 #include <linux/kernel.h>
@@ -149,6 +149,12 @@ int try_to_swap_out(unsigned long * table_ptr)
 /*
  * Go through the page tables, searching for a user page that
  * we can swap out.
+ *
+ * Here it's easy to add a check for tasks that may not be swapped out:
+ * loadable device drivers or similar. Just add an entry to the task-struct
+ * and check it at the same time you check for the existence of the task.
+ * The code assumes tasks are page-table aligned, but so do other parts
+ * of the memory manager...
  */
 int swap_out(void)
 {
@@ -156,12 +162,18 @@ int swap_out(void)
        static int page_entry = -1;
        int counter = VM_PAGES;
        int pg_table;
+       struct task_struct * p;
 
 check_dir:
        if (counter < 0)
                goto no_swap;
        if (dir_entry >= 1024)
                dir_entry = FIRST_VM_PAGE>>10;
+       if (!(p = task[dir_entry >> 4])) {
+               counter -= 1024;
+               dir_entry++;
+               goto check_dir;
+       }
        if (!(1 & (pg_table = pg_dir[dir_entry]))) {
                if (pg_table) {
                        printk("bad page-table at pg_dir[%d]: %08x\n\r",
@@ -184,10 +196,7 @@ check_table:
                goto check_dir;
        }
        if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
-               if (! task[dir_entry >> 4])
-                       printk("swapping out page from non-existent task\n\r");
-               else
-                       task[dir_entry >> 4]->rss--;
+               p->rss--;
                return 1;
        }
        goto check_table;
@@ -236,10 +245,10 @@ repeat:
  *
  * The swapon system call
  */
-
 int sys_swapon(const char * specialfile)
 {
        struct inode * swap_inode;
+       char * tmp;
        int i,j;
 
        if (!suser())
@@ -259,38 +268,39 @@ int sys_swapon(const char * specialfile)
                iput(swap_inode);
                return -EINVAL;
        }
-       swap_bitmap = (char *) get_free_page();
-       if (!swap_bitmap) {
+       tmp = (char *) get_free_page();
+       if (!tmp) {
                iput(swap_file);
                swap_device = 0;
                swap_file = NULL;
                printk("Unable to start swapping: out of memory :-)\n");
                return -ENOMEM;
        }
-       read_swap_page(0,swap_bitmap);
-       if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
+       read_swap_page(0,tmp);
+       if (strncmp("SWAP-SPACE",tmp+4086,10)) {
                printk("Unable to find swap-space signature\n\r");
-               free_page((long) swap_bitmap);
+               free_page((long) tmp);
                iput(swap_file);
                swap_device = 0;
                swap_file = NULL;
                swap_bitmap = NULL;
                return -EINVAL;
        }
-       memset(swap_bitmap+4086,0,10);
+       memset(tmp+4086,0,10);
        j = 0;
        for (i = 1 ; i < SWAP_BITS ; i++)
-               if (bit(swap_bitmap,i))
+               if (bit(tmp,i))
                        j++;
        if (!j) {
                printk("Empty swap-file\n");
-               free_page((long) swap_bitmap);
+               free_page((long) tmp);
                iput(swap_file);
                swap_device = 0;
                swap_file = NULL;
                swap_bitmap = NULL;
                return -EINVAL;
        }
+       swap_bitmap = tmp;
        printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
        return 0;
 }
diff --git a/net/Makefile b/net/Makefile
new file mode 100644 (file)
index 0000000..1080839
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Makefile for the linux networking.
+#
+# 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 definition is now in the main makefile...
+
+AS     =as
+AR     =ar
+LD     =ld
+CC     =gcc -nostdinc -I../include -Wall # -DSOCK_DEBUG
+CPP    =cpp -nostdinc -I../include
+
+.c.o:
+       $(CC) $(CFLAGS) \
+       -c -o $*.o $<
+.s.o:
+       $(AS) -o $*.o $<
+.c.s:
+       $(CC) $(CFLAGS) \
+       -S -o $*.s $<
+
+OBJS   =  socket.o unix.o
+
+net.o: $(OBJS)
+       $(LD) -r -o net.o $(OBJS)
+
+clean:
+       rm -f core *.o *.a tmp_make
+       for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+       sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+       (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+       cp tmp_make Makefile
+
+### Dependencies:
+socket.o : socket.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+  ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+  ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
+  ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/system.h \
+  ../include/asm/segment.h ../include/sys/socket.h ../include/sys/stat.h ../include/fcntl.h \
+  ../include/termios.h kern_sock.h socketcall.h 
+unix.o : unix.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+  ../include/linux/string.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+  ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+  ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+  ../include/asm/system.h ../include/asm/segment.h ../include/sys/socket.h ../include/sys/un.h \
+  ../include/sys/stat.h ../include/fcntl.h ../include/termios.h kern_sock.h 
diff --git a/net/kern_sock.h b/net/kern_sock.h
new file mode 100644 (file)
index 0000000..6ec8d1a
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _KERN_SOCK_H
+#define _KERN_SOCK_H
+
+#define NSOCKETS 128                   /* should be dynamic, later... */
+
+typedef enum {
+       SS_FREE = 0,                    /* not allocated */
+       SS_UNCONNECTED,                 /* unconnected to any socket */
+       SS_CONNECTING,                  /* in process of connecting */
+       SS_CONNECTED,                   /* connected to socket */
+       SS_DISCONNECTING,               /* in process of disconnecting */
+} socket_state;
+
+#define SO_ACCEPTCON   (1<<16)         /* performed a listen */
+
+/*
+ * internel representation of a socket. not all the fields are used by
+ * all configurations:
+ *
+ *             server                  client
+ * conn                client connected to     server connected to
+ * iconn       list of clients         -unused-
+ *              awaiting connections
+ * wait                sleep for clients,      sleep for connection,
+ *             sleep for i/o           sleep for i/o
+ */
+struct socket {
+       short type;                     /* SOCK_STREAM, ... */
+       socket_state state;
+       long flags;
+       struct proto_ops *ops;          /* protocols do most everything */
+       char *data;                     /* protocol data */
+       struct socket *conn;            /* server socket connected to */
+       struct socket *iconn;           /* incomplete client connections */
+       struct socket *next;
+       struct task_struct **wait;      /* ptr to place to wait on */
+       void *dummy;
+};
+
+struct proto_ops {
+       int (*init)(void);
+       int (*create)(struct socket *sock, int protocol);
+       int (*dup)(struct socket *newsock, struct socket *oldsock);
+       int (*release)(struct socket *sock, struct socket *peer);
+       int (*bind)(struct socket *sock, struct sockaddr *umyaddr,
+                   int sockaddr_len);
+       int (*connect)(struct socket *sock, struct sockaddr *uservaddr,
+                      int sockaddr_len);
+       int (*socketpair)(struct socket *sock1, struct socket *sock2);
+       int (*accept)(struct socket *sock, struct socket *newsock);
+       int (*getname)(struct socket *sock, struct sockaddr *uaddr,
+                      int *usockaddr_len, int peer);
+       int (*read)(struct socket *sock, char *ubuf, int size, int nonblock);
+       int (*write)(struct socket *sock, char *ubuf, int size, int nonblock);
+       int (*select)(struct socket *sock, int which);
+       int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
+};
+
+extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
+
+#ifdef SOCK_DEBUG
+#define PRINTK printk
+#else
+#define PRINTK (void)
+#endif
+
+#endif /* _KERN_SOCK_H */
diff --git a/net/socket.c b/net/socket.c
new file mode 100644 (file)
index 0000000..70472b5
--- /dev/null
@@ -0,0 +1,761 @@
+#include <signal.h>
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "kern_sock.h"
+#include "socketcall.h"
+
+extern int sys_close(int fd);
+
+extern struct proto_ops unix_proto_ops;
+
+static struct {
+       short family;
+       char *name;
+       struct proto_ops *ops;
+} proto_table[] = {
+       AF_UNIX,        "AF_UNIX",      &unix_proto_ops
+};
+#define NPROTO (sizeof(proto_table) / sizeof(proto_table[0]))
+
+static char *
+family_name(int family)
+{
+       int i;
+
+       for (i = 0; i < NPROTO; ++i)
+               if (proto_table[i].family == family)
+                       return proto_table[i].name;
+       return "UNKNOWN";
+}
+
+static int sock_lseek(struct inode *inode, struct file *file, off_t offset,
+                     int whence);
+static int sock_read(struct inode *inode, struct file *file, char *buf,
+                    int size);
+static int sock_write(struct inode *inode, struct file *file, char *buf,
+                     int size);
+static int sock_readdir(struct inode *inode, struct file *file,
+                       struct dirent *dirent, int count);
+static void sock_close(struct inode *inode, struct file *file);
+/*static*/ int sock_select(struct inode *inode, struct file *file, int which,
+                      select_table *seltable);
+static int sock_ioctl(struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned int arg);
+
+static struct file_operations socket_file_ops = {
+       sock_lseek,
+       sock_read,
+       sock_write,
+       sock_readdir,
+       sock_select,    /* not in vfs yet */
+       sock_ioctl,
+       NULL,           /* no special open code... */
+       sock_close
+};
+
+#define SOCK_INODE(S) ((struct inode *)(S)->dummy)
+
+static struct socket sockets[NSOCKETS];
+#define last_socket (sockets + NSOCKETS - 1)
+static struct task_struct *socket_wait_free = NULL;
+
+/*
+ * obtains the first available file descriptor and sets it up for use
+ */
+static int
+get_fd(struct inode *inode)
+{
+       int fd, i;
+       struct file *file;
+
+       /*
+        * find a file descriptor suitable for return to the user.
+        */
+       for (fd = 0; fd < NR_OPEN; ++fd)
+               if (!current->filp[fd])
+                       break;
+       if (fd == NR_OPEN)
+               return -1;
+       current->close_on_exec &= ~(1 << fd);
+       for (file = file_table, i = 0; i < NR_FILE; ++i, ++file)
+               if (!file->f_count)
+                       break;
+       if (i == NR_FILE)
+               return -1;
+       current->filp[fd] = file;
+       file->f_op = &socket_file_ops;
+       file->f_mode = 3;
+       file->f_flags = 0;
+       file->f_count = 1;
+       file->f_inode = inode;
+       file->f_pos = 0;
+       return fd;
+}
+
+/*
+ * reverses the action of get_fd() by releasing the file. it closes the
+ * descriptor, but makes sure it does nothing more. called when an incomplete
+ * socket must be closed, along with sock_release().
+ */
+static inline void
+toss_fd(int fd)
+{
+       current->filp[fd]->f_inode = NULL;      /* safe from iput */
+       sys_close(fd);
+}
+
+static inline struct socket *
+socki_lookup(struct inode *inode)
+{
+       struct socket *sock;
+
+       for (sock = sockets; sock <= last_socket; ++sock)
+               if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)
+                       return sock;
+       return NULL;
+}
+
+static inline struct socket *
+sockfd_lookup(int fd, struct file **pfile)
+{
+       struct file *file;
+
+       if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd]))
+               return NULL;
+       if (pfile)
+               *pfile = file;
+       return socki_lookup(file->f_inode);
+}
+
+static struct socket *
+sock_alloc(int wait)
+{
+       struct socket *sock;
+
+       while (1) {
+               cli();
+               for (sock = sockets; sock <= last_socket; ++sock)
+                       if (sock->state == SS_FREE) {
+                               sock->state = SS_UNCONNECTED;
+                               sti();
+                               sock->flags = 0;
+                               sock->ops = NULL;
+                               sock->data = NULL;
+                               sock->conn = NULL;
+                               sock->iconn = NULL;
+                               /*
+                                * this really shouldn't be necessary, but
+                                * everything else depends on inodes, so we
+                                * grab it.
+                                * sleeps are also done on the i_wait member
+                                * of this inode.
+                                * the close system call will iput this inode
+                                * for us.
+                                */
+                               if (!(SOCK_INODE(sock) = get_empty_inode())) {
+                                       printk("sock_alloc: no more inodes\n");
+                                       sock->state = SS_FREE;
+                                       return NULL;
+                               }
+                               SOCK_INODE(sock)->i_mode = S_IFSOCK;
+                               sock->wait = &SOCK_INODE(sock)->i_wait;
+                               PRINTK("sock_alloc: socket 0x%x, inode 0x%x\n",
+                                      sock, SOCK_INODE(sock));
+                               return sock;
+                       }
+               sti();
+               if (!wait)
+                       return NULL;
+               PRINTK("sock_alloc: no free sockets, sleeping...\n");
+               interruptible_sleep_on(&socket_wait_free);
+               if (current->signal & ~current->blocked) {
+                       PRINTK("sock_alloc: sleep was interrupted\n");
+                       return NULL;
+               }
+               PRINTK("sock_alloc: wakeup... trying again...\n");
+       }
+}
+
+static inline void
+sock_release_peer(struct socket *peer)
+{
+       peer->state = SS_DISCONNECTING;
+       wake_up(peer->wait);
+}
+
+static void
+sock_release(struct socket *sock)
+{
+       int oldstate;
+       struct socket *peersock, *nextsock;
+
+       PRINTK("sock_release: socket 0x%x, inode 0x%x\n", sock,
+              SOCK_INODE(sock));
+       if ((oldstate = sock->state) != SS_UNCONNECTED)
+               sock->state = SS_DISCONNECTING;
+       /*
+        * wake up anyone waiting for connections
+        */
+       for (peersock = sock->iconn; peersock; peersock = nextsock) {
+               nextsock = peersock->next;
+               sock_release_peer(peersock);
+       }
+       /*
+        * wake up anyone we're connected to. first, we release the
+        * protocol, to give it a chance to flush data, etc.
+        */
+       peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;
+       if (sock->ops)
+               sock->ops->release(sock, peersock);
+       if (peersock)
+               sock_release_peer(peersock);
+       sock->state = SS_FREE;          /* this really releases us */
+       wake_up(&socket_wait_free);
+}
+
+static int
+sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence)
+{
+       PRINTK("sock_lseek: huh?\n");
+       return -EBADF;
+}
+
+static int
+sock_read(struct inode *inode, struct file *file, char *ubuf, int size)
+{
+       struct socket *sock;
+
+       PRINTK("sock_read: buf=0x%x, size=%d\n", ubuf, size);
+       if (!(sock = socki_lookup(inode))) {
+               printk("sock_read: can't find socket for inode!\n");
+               return -EBADF;
+       }
+       if (sock->flags & SO_ACCEPTCON)
+               return -EINVAL;
+       return sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK));
+}
+
+static int
+sock_write(struct inode *inode, struct file *file, char *ubuf, int size)
+{
+       struct socket *sock;
+
+       PRINTK("sock_write: buf=0x%x, size=%d\n", ubuf, size);
+       if (!(sock = socki_lookup(inode))) {
+               printk("sock_write: can't find socket for inode!\n");
+               return -EBADF;
+       }
+       if (sock->flags & SO_ACCEPTCON)
+               return -EINVAL;
+       return sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK));
+}
+
+static int
+sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent,
+            int count)
+{
+       PRINTK("sock_readdir: huh?\n");
+       return -EBADF;
+}
+
+int
+sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+          unsigned int arg)
+{
+       struct socket *sock;
+
+       PRINTK("sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n", inode, cmd, arg);
+       if (!(sock = socki_lookup(inode))) {
+               printk("sock_ioctl: can't find socket for inode!\n");
+               return -EBADF;
+       }
+       switch (cmd) {
+       case TIOCINQ:
+       case TIOCOUTQ:
+               if (sock->flags & SO_ACCEPTCON)
+                       return -EINVAL;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return sock->ops->ioctl(sock, cmd, arg);
+}
+
+/*static*/ int
+sock_select(struct inode *inode, struct file *file, int which,
+           select_table *seltable)
+{
+       struct socket *sock;
+
+       PRINTK("sock_select: inode = 0x%x, kind = %s\n", inode,
+              (which == SEL_IN) ? "in" :
+              (which == SEL_OUT) ? "out" : "ex");
+       if (!(sock = socki_lookup(inode))) {
+               printk("sock_write: can't find socket for inode!\n");
+               return -EBADF;
+       }
+
+       /*
+        * handle server sockets specially
+        */
+       if (sock->flags & SO_ACCEPTCON) {
+               if (which == SEL_IN) {
+                       PRINTK("sock_select: %sconnections pending\n",
+                              sock->iconn ? "" : "no ");
+                       return sock->iconn ? 1 : 0;
+               }
+               PRINTK("sock_select: nothing else for server socket\n");
+               return 0;
+       }
+
+       /*
+        * we can't return errors to select, so its either yes or no.
+        */
+       return sock->ops->select(sock, which) ? 1 : 0;
+}
+
+void
+sock_close(struct inode *inode, struct file *file)
+{
+       struct socket *sock;
+
+       PRINTK("sock_close: inode=0x%x (cnt=%d)\n", inode, inode->i_count);
+       /*
+        * it's possible the inode is NULL if we're closing an unfinished
+        * socket.
+        */
+       if (!inode)
+               return;
+       if (!(sock = socki_lookup(inode))) {
+               printk("sock_close: can't find socket for inode!\n");
+               return;
+       }
+       sock_release(sock);
+}
+
+int
+sock_awaitconn(struct socket *mysock, struct socket *servsock)
+{
+       struct socket *last;
+
+       PRINTK("sock_awaitconn: trying to connect socket 0x%x to 0x%x\n",
+              mysock, servsock);
+       if (!(servsock->flags & SO_ACCEPTCON)) {
+               PRINTK("sock_awaitconn: server not accepting connections\n");
+               return -EINVAL;
+       }
+
+       /*
+        * put ourselves on the server's incomplete connection queue.
+        */
+       mysock->next = NULL;
+       cli();
+       if (!(last = servsock->iconn))
+               servsock->iconn = mysock;
+       else {
+               while (last->next)
+                       last = last->next;
+               last->next = mysock;
+       }
+       mysock->state = SS_CONNECTING;
+       mysock->conn = servsock;
+       sti();
+
+       /*
+        * wake up server, then await connection. server will set state to
+        * SS_CONNECTED if we're connected.
+        */
+       wake_up(servsock->wait);
+       if (mysock->state != SS_CONNECTED) {
+               interruptible_sleep_on(mysock->wait);
+               if (mysock->state != SS_CONNECTED) {
+                       /*
+                        * if we're not connected we could have been
+                        * 1) interrupted, so we need to remove ourselves
+                        *    from the server list
+                        * 2) rejected (mysock->conn == NULL), and have
+                        *    already been removed from the list
+                        */
+                       if (mysock->conn == servsock) {
+                               cli();
+                               if ((last = servsock->iconn) == mysock)
+                                       servsock->iconn = mysock->next;
+                               else {
+                                       while (last->next != mysock)
+                                               last = last->next;
+                                       last->next = mysock->next;
+                               }
+                               sti();
+                       }
+                       return mysock->conn ? -EINTR : -EACCES;
+               }
+       }
+       return 0;
+}
+
+/*
+ * perform the socket system call. we locate the appropriate family, then
+ * create a fresh socket.
+ */
+static int
+sock_socket(int family, int type, int protocol)
+{
+       int i, fd;
+       struct socket *sock;
+       struct proto_ops *ops;
+
+       PRINTK("sys_socket: family = %d (%s), type = %d, protocol = %d\n",
+              family, family_name(family), type, protocol);
+
+       /*
+        * locate the correct protocol family
+        */
+       for (i = 0; i < NPROTO; ++i)
+               if (proto_table[i].family == family)
+                       break;
+       if (i == NPROTO) {
+               PRINTK("sys_socket: family not found\n");
+               return -EINVAL;
+       }
+       ops = proto_table[i].ops;
+
+       /*
+        * check that this is a type that we know how to manipulate and
+        * the protocol makes sense here. the family can still reject the
+        * protocol later.
+        */
+       if ((type != SOCK_STREAM &&
+            type != SOCK_DGRAM &&
+            type != SOCK_SEQPACKET &&
+            type != SOCK_RAW) ||
+           protocol < 0)
+               return -EINVAL;
+
+       /*
+        * allocate the socket and allow the family to set things up. if
+        * the protocol is 0, the family is instructed to select an appropriate
+        * default.
+        */
+       if (!(sock = sock_alloc(1))) {
+               printk("sys_socket: no more sockets\n");
+               return -EAGAIN;
+       }
+       sock->type = type;
+       sock->ops = ops;
+       if ((i = sock->ops->create(sock, protocol)) < 0) {
+               sock_release(sock);
+               return i;
+       }
+
+       if ((fd = get_fd(SOCK_INODE(sock))) < 0) {
+               sock_release(sock);
+               return -EINVAL;
+       }
+
+       return fd;
+}
+
+static int
+sock_socketpair(int family, int type, int protocol, int usockvec[2])
+{
+       int fd1, fd2, i;
+       struct socket *sock1, *sock2;
+
+       PRINTK("sys_socketpair: family = %d, type = %d, protocol = %d\n",
+              family, type, protocol);
+
+       /*
+        * obtain the first socket and check if the underlying protocol
+        * supports the socketpair call
+        */
+       if ((fd1 = sock_socket(family, type, protocol)) < 0)
+               return fd1;
+       sock1 = sockfd_lookup(fd1, NULL);
+       if (!sock1->ops->socketpair) {
+               sys_close(fd1);
+               return -EINVAL;
+       }
+
+       /*
+        * now grab another socket and try to connect the two together
+        */
+       if ((fd2 = sock_socket(family, type, protocol)) < 0) {
+               sys_close(fd1);
+               return -EINVAL;
+       }
+       sock2 = sockfd_lookup(fd2, NULL);
+       if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) {
+               sys_close(fd1);
+               sys_close(fd2);
+               return i;
+       }
+       sock1->conn = sock2;
+       sock2->conn = sock1;
+       sock1->state = SS_CONNECTED;
+       sock2->state = SS_CONNECTED;
+
+       verify_area(usockvec, 2 * sizeof(int));
+       put_fs_long(fd1, &usockvec[0]);
+       put_fs_long(fd2, &usockvec[1]);
+
+       return 0;
+}
+
+/*
+ * binds a name to a socket. nothing much to do here since its the
+ * protocol's responsibility to handle the local address
+ */
+static int
+sock_bind(int fd, struct sockaddr *umyaddr, int addrlen)
+{
+       struct socket *sock;
+       int i;
+
+       PRINTK("sys_bind: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, NULL)))
+               return -EBADF;
+       if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) {
+               PRINTK("sys_bind: bind failed\n");
+               return i;
+       }
+       return 0;
+}
+
+/*
+ * perform a listen. basically, we allow the protocol to do anything
+ * necessary for a listen, and if that works, we mark the socket as
+ * ready for listening.
+ */
+static int
+sock_listen(int fd, int backlog)
+{
+       struct socket *sock;
+
+       PRINTK("sys_listen: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, NULL)))
+               return -EBADF;
+       if (sock->state != SS_UNCONNECTED) {
+               PRINTK("sys_listen: socket isn't unconnected\n");
+               return -EINVAL;
+       }
+       if (sock->flags & SO_ACCEPTCON) {
+               PRINTK("sys_listen: socket already accepting connections!\n");
+               return -EINVAL;
+       }
+       sock->flags |= SO_ACCEPTCON;
+       return 0;
+}
+
+/*
+ * for accept, we attempt to create a new socket, set up the link with the
+ * client, wake up the client, then return the new connected fd.
+ */
+static int
+sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
+{
+       struct file *file;
+       struct socket *sock, *clientsock, *newsock;
+       int i;
+
+       PRINTK("sys_accept: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, &file)))
+               return -EBADF;
+       if (sock->state != SS_UNCONNECTED) {
+               PRINTK("sys_accept: socket isn't unconnected\n");
+               return -EINVAL;
+       }
+       if (!(sock->flags & SO_ACCEPTCON)) {
+               PRINTK("sys_accept: socket not accepting connections!\n");
+               return -EINVAL;
+       }
+
+       /*
+        * if there aren't any sockets awaiting connection, then wait for
+        * one, unless nonblocking
+        */
+       while (!(clientsock = sock->iconn)) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               interruptible_sleep_on(sock->wait);
+               if (current->signal & ~current->blocked) {
+                       PRINTK("sys_accept: sleep was interrupted\n");
+                       return -EINTR;
+               }
+       }
+
+       if (!(newsock = sock_alloc(0))) {
+               printk("sys_accept: no more sockets\n");
+               return -EINVAL;
+       }
+       newsock->type = sock->type;
+       newsock->ops = sock->ops;
+       if ((i = sock->ops->dup(newsock, sock)) < 0) {
+               sock_release(newsock);
+               return i;
+       }
+
+       if ((fd = get_fd(SOCK_INODE(newsock))) < 0) {
+               sock_release(newsock);
+               return -EINVAL;
+       }
+
+       /*
+        * great. finish the connection relative to server and client,
+        * wake up the client and return the new fd to the server
+        */
+       sock->iconn = clientsock->next;
+       clientsock->next = NULL;
+       newsock->conn = clientsock;
+       clientsock->conn = newsock;
+       clientsock->state = SS_CONNECTED;
+       newsock->state = SS_CONNECTED;
+       newsock->ops->accept(sock, newsock);
+       PRINTK("sys_accept: connected socket 0x%x via 0x%x to 0x%x\n",
+              sock, newsock, clientsock);
+       if (upeer_sockaddr)
+               newsock->ops->getname(newsock, upeer_sockaddr,
+                                     upeer_addrlen, 1);
+       wake_up(clientsock->wait);
+
+       return fd;
+}
+
+/*
+ * attempt to connect to a socket with the server address.
+ */
+static int
+sock_connect(int fd, struct sockaddr *uservaddr, int addrlen)
+{
+       struct socket *sock;
+       int i;
+
+       PRINTK("sys_connect: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, NULL)))
+               return -EBADF;
+       if (sock->state != SS_UNCONNECTED) {
+               PRINTK("sys_connect: socket not unconnected\n");
+               return -EINVAL;
+       }
+       if ((i = sock->ops->connect(sock, uservaddr, addrlen)) < 0) {
+               PRINTK("sys_connect: connect failed\n");
+               return i;
+       }
+       return 0;
+}
+
+static int
+sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+{
+       struct socket *sock;
+
+       PRINTK("sys_getsockname: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, NULL)))
+               return -EBADF;
+       return sock->ops->getname(sock, usockaddr, usockaddr_len, 0);
+}
+
+static int
+sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+{
+       struct socket *sock;
+
+       PRINTK("sys_getpeername: fd = %d\n", fd);
+       if (!(sock = sockfd_lookup(fd, NULL)))
+               return -EBADF;
+       return sock->ops->getname(sock, usockaddr, usockaddr_len, 1);
+}
+
+/*
+ * system call vectors. since i want to rewrite sockets as streams, we have
+ * this level of indirection. not a lot of overhead, since more of the work is
+ * done via read/write/select directly
+ */
+int
+sys_socketcall(int call, unsigned long *args)
+{
+       switch (call) {
+       case SYS_SOCKET:
+               verify_area(args, 3 * sizeof(long));
+               return sock_socket(get_fs_long(args+0),
+                                  get_fs_long(args+1),
+                                  get_fs_long(args+2));
+
+       case SYS_BIND:
+               verify_area(args, 3 * sizeof(long));
+               return sock_bind(get_fs_long(args+0),
+                                (struct sockaddr *)get_fs_long(args+1),
+                                get_fs_long(args+2));
+
+       case SYS_CONNECT:
+               verify_area(args, 3 * sizeof(long));
+               return sock_connect(get_fs_long(args+0),
+                                   (struct sockaddr *)get_fs_long(args+1),
+                                   get_fs_long(args+2));
+
+       case SYS_LISTEN:
+               verify_area(args, 2 * sizeof(long));
+               return sock_listen(get_fs_long(args+0),
+                                  get_fs_long(args+1));
+
+       case SYS_ACCEPT:
+               verify_area(args, 3 * sizeof(long));
+               return sock_accept(get_fs_long(args+0),
+                                  (struct sockaddr *)get_fs_long(args+1),
+                                  (int *)get_fs_long(args+2));
+
+       case SYS_GETSOCKNAME:
+               verify_area(args, 3 * sizeof(long));
+               return sock_getsockname(get_fs_long(args+0),
+                                       (struct sockaddr *)get_fs_long(args+1),
+                                       (int *)get_fs_long(args+2));
+
+       case SYS_GETPEERNAME:
+               verify_area(args, 3 * sizeof(long));
+               return sock_getpeername(get_fs_long(args+0),
+                                       (struct sockaddr *)get_fs_long(args+1),
+                                       (int *)get_fs_long(args+2));
+
+       case SYS_SOCKETPAIR:
+               verify_area(args, 4 * sizeof(long));
+               return sock_socketpair(get_fs_long(args+0),
+                                      get_fs_long(args+1),
+                                      get_fs_long(args+2),
+                                      (int *)get_fs_long(args+3));
+
+       default:
+               return -EINVAL;
+       }
+}
+
+void
+sock_init(void)
+{
+       struct socket *sock;
+       int i, ok;
+
+       for (sock = sockets; sock <= last_socket; ++sock)
+               sock->state = SS_FREE;
+       for (i = ok = 0; i < NPROTO; ++i) {
+               printk("sock_init: initializing family %d (%s)\n",
+                      proto_table[i].family, proto_table[i].name);
+               if ((*proto_table[i].ops->init)() < 0) {
+                       printk("sock_init: init failed.\n",
+                              proto_table[i].family);
+                       proto_table[i].family = -1;
+               }
+               else
+                       ++ok;
+       }
+       if (!ok)
+               printk("sock_init: warning: no protocols initialized\n");
+       return;
+}
+
diff --git a/net/socketcall.h b/net/socketcall.h
new file mode 100644 (file)
index 0000000..4b48562
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _SOCKETCALL_
+#define _SOCKETCALL_
+
+#define SYS_SOCKET 1
+#define SYS_BIND 2
+#define SYS_CONNECT 3
+#define SYS_LISTEN 4
+#define SYS_ACCEPT 5
+#define SYS_GETSOCKNAME 6
+#define SYS_GETPEERNAME 7
+#define SYS_SOCKETPAIR 8
+
+#endif _SOCKETCALL_
diff --git a/net/unix.c b/net/unix.c
new file mode 100644 (file)
index 0000000..5a03b91
--- /dev/null
@@ -0,0 +1,606 @@
+#include <signal.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "kern_sock.h"
+
+static struct unix_proto_data {
+       int refcnt;                     /* cnt of reference 0=free */
+       struct socket *socket;          /* socket we're bound to */
+       int protocol;
+       struct sockaddr_un sockaddr_un;
+       short sockaddr_len;             /* >0 if name bound */
+       char *buf;
+       int bp_head, bp_tail;
+       struct inode *inode;
+       struct unix_proto_data *peerupd;
+} unix_datas[NSOCKETS];
+#define last_unix_data (unix_datas + NSOCKETS - 1)
+
+#define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data)
+#define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0)->sun_path)
+
+/*
+ * buffer size must be power of 2. buffer mgmt inspired by pipe code.
+ * note that buffer contents can wraparound, and we can write one byte less
+ * than full size to discern full vs empty.
+ */
+#define BUF_SIZE PAGE_SIZE
+#define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & (BUF_SIZE-1))
+#define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD))
+
+static int unix_proto_init(void);
+static int unix_proto_create(struct socket *sock, int protocol);
+static int unix_proto_dup(struct socket *newsock, struct socket *oldsock);
+static int unix_proto_release(struct socket *sock, struct socket *peer);
+static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+                          int sockaddr_len);
+static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+                             int sockaddr_len);
+static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2);
+static int unix_proto_accept(struct socket *sock, struct socket *newsock);
+static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+                             int *usockaddr_len, int peer);
+static int unix_proto_read(struct socket *sock, char *ubuf, int size,
+                          int nonblock);
+static int unix_proto_write(struct socket *sock, char *ubuf, int size,
+                           int nonblock);
+static int unix_proto_select(struct socket *sock, int which);
+static int unix_proto_ioctl(struct socket *sock, unsigned int cmd,
+                           unsigned long arg);
+
+struct proto_ops unix_proto_ops = {
+       unix_proto_init,
+       unix_proto_create,
+       unix_proto_dup,
+       unix_proto_release,
+       unix_proto_bind,
+       unix_proto_connect,
+       unix_proto_socketpair,
+       unix_proto_accept,
+       unix_proto_getname,
+       unix_proto_read,
+       unix_proto_write,
+       unix_proto_select,
+       unix_proto_ioctl
+};
+
+#ifdef SOCK_DEBUG
+void
+sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
+{
+       char buf[sizeof(sockun->sun_path) + 1];
+
+       sockaddr_len -= UN_PATH_OFFSET;
+       if (sockun->sun_family != AF_UNIX)
+               printk("sockaddr_un: <BAD FAMILY: %d>\n", sockun->sun_family);
+       else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)-1)
+               printk("sockaddr_un: <BAD LENGTH: %d>\n", sockaddr_len);
+       else {
+               memcpy(buf, sockun->sun_path, sockaddr_len);
+               buf[sockaddr_len] = '\0';
+               printk("sockaddr_un: '%s'[%d]\n", buf,
+                      sockaddr_len + UN_PATH_OFFSET);
+       }
+}
+#endif
+
+static struct unix_proto_data *
+unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
+{
+       struct unix_proto_data *upd;
+
+       for (upd = unix_datas; upd <= last_unix_data; ++upd) {
+               if (upd->refcnt && upd->socket &&
+                   upd->sockaddr_len == sockaddr_len &&
+                   memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0)
+                       return upd;
+       }
+       return NULL;
+}
+
+static struct unix_proto_data *
+unix_data_alloc(void)
+{
+       struct unix_proto_data *upd;
+
+       cli();
+       for (upd = unix_datas; upd <= last_unix_data; ++upd) {
+               if (!upd->refcnt) {
+                       upd->refcnt = 1;
+                       sti();
+                       upd->socket = NULL;
+                       upd->sockaddr_len = 0;
+                       upd->buf = NULL;
+                       upd->bp_head = upd->bp_tail = 0;
+                       upd->inode = NULL;
+                       upd->peerupd = NULL;
+                       return upd;
+               }
+       }
+       sti();
+       return NULL;
+}
+
+static inline void
+unix_data_ref(struct unix_proto_data *upd)
+{
+       ++upd->refcnt;
+       PRINTK("unix_data_ref: refing data 0x%x (%d)\n", upd, upd->refcnt);
+}
+
+static void
+unix_data_deref(struct unix_proto_data *upd)
+{
+       if (upd->refcnt == 1) {
+               PRINTK("unix_data_deref: releasing data 0x%x\n", upd);
+               if (upd->buf) {
+                       free_page((unsigned long)upd->buf);
+                       upd->buf = NULL;
+                       upd->bp_head = upd->bp_tail = 0;
+               }
+       }
+       --upd->refcnt;
+}
+
+/*
+ * upon a create, we allocate an empty protocol data, and grab a page to
+ * buffer writes
+ */
+static int
+unix_proto_create(struct socket *sock, int protocol)
+{
+       struct unix_proto_data *upd;
+
+       PRINTK("unix_proto_create: socket 0x%x, proto %d\n", sock, protocol);
+       if (protocol != 0) {
+               PRINTK("unix_proto_create: protocol != 0\n");
+               return -EINVAL;
+       }
+       if (!(upd = unix_data_alloc())) {
+               printk("unix_proto_create: can't allocate buffer\n");
+               return -ENOMEM;
+       }
+       if (!(upd->buf = (char *)get_free_page())) {
+               printk("unix_proto_create: can't get page!\n");
+               unix_data_deref(upd);
+               return -ENOMEM;
+       }
+       upd->protocol = protocol;
+       upd->socket = sock;
+       UN_DATA(sock) = upd;
+       PRINTK("unix_proto_create: allocated data 0x%x\n", upd);
+       return 0;
+}
+
+static int
+unix_proto_dup(struct socket *newsock, struct socket *oldsock)
+{
+       struct unix_proto_data *upd = UN_DATA(oldsock);
+
+       return unix_proto_create(newsock, upd->protocol);
+}
+
+static int
+unix_proto_release(struct socket *sock, struct socket *peer)
+{
+       struct unix_proto_data *upd = UN_DATA(sock);
+
+       PRINTK("unix_proto_release: socket 0x%x, unix_data 0x%x\n",
+              sock, upd);
+       if (!upd)
+               return 0;
+       if (upd->socket != sock) {
+               printk("unix_proto_release: socket link mismatch!\n");
+               return -EINVAL;
+       }
+       if (upd->inode) {
+               PRINTK("unix_proto_release: releasing inode 0x%x\n",
+                      upd->inode);
+               iput(upd->inode);
+               upd->inode = NULL;
+       }
+       UN_DATA(sock) = NULL;
+       upd->socket = NULL;
+       if (upd->peerupd)
+               unix_data_deref(upd->peerupd);
+       unix_data_deref(upd);
+       return 0;
+}
+
+/*
+ * bind a name to a socket. this is where much of the work is done. we
+ * allocate a fresh page for the buffer, grab the appropriate inode and
+ * set things up.
+ *
+ * XXX what should we do if an address is already bound? here we return
+ * EINVAL, but it may be necessary to re-bind. i think thats what bsd does
+ * in the case of datagram sockets
+ */
+static int
+unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+               int sockaddr_len)
+{
+       struct unix_proto_data *upd = UN_DATA(sock);
+       char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+       int i;
+       unsigned long old_fs;
+       unsigned short old_euid;
+
+       PRINTK("unix_proto_bind: socket 0x%x, len=%d\n", sock,
+              sockaddr_len);
+       if (sockaddr_len <= UN_PATH_OFFSET ||
+           sockaddr_len >= sizeof(struct sockaddr_un)) {
+               PRINTK("unix_proto_bind: bad length %d\n", sockaddr_len);
+               return -EINVAL;
+       }
+       if (upd->sockaddr_len || upd->inode) {
+               printk("unix_proto_bind: already bound!\n");
+               return -EINVAL;
+       }
+       verify_area(umyaddr, sockaddr_len);
+       memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
+       if (upd->sockaddr_un.sun_family != AF_UNIX) {
+               PRINTK("unix_proto_bind: family is %d, not AF_UNIX (%d)\n",
+                      upd->sockaddr_un.sun_family, AF_UNIX);
+               return -EINVAL;
+       }
+
+       /*
+        *              W A R N I N G
+        * this is a terrible hack. i want to create a socket in the
+        * filesystem and get its inode. sys_mknod() can create one for
+        * me, but it needs superuser privs and doesn't give me the inode.
+        * we fake suser here and get the file created... ugh.
+        */
+       memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
+       fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+       old_fs = get_fs();
+       set_fs(get_ds());
+       old_euid = current->euid;
+       current->euid = 0;
+       i = sys_mknod(fname, S_IFSOCK, 0);
+       current->euid = old_euid;
+       if (i == 0)
+               i = open_namei(fname, 0, S_IFSOCK, &upd->inode);
+       set_fs(old_fs);
+       if (i < 0) {
+               printk("unix_proto_bind: can't open socket %s\n", fname);
+               return i;
+       }
+
+       upd->sockaddr_len = sockaddr_len;       /* now its legal */
+       PRINTK("unix_proto_bind: bound socket address: ");
+#ifdef SOCK_DEBUG
+       sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
+#endif
+       return 0;
+}
+
+/*
+ * perform a connection. we can only connect to unix sockets (i can't for
+ * the life of me find an application where that wouldn't be the case!)
+ */
+static int
+unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+                  int sockaddr_len)
+{
+       int i;
+       struct unix_proto_data *serv_upd;
+       struct sockaddr_un sockun;
+
+       PRINTK("unix_proto_connect: socket 0x%x, servlen=%d\n", sock,
+              sockaddr_len);
+       if (sockaddr_len <= UN_PATH_OFFSET ||
+           sockaddr_len >= sizeof(struct sockaddr_un)) {
+               PRINTK("unix_proto_connect: bad length %d\n", sockaddr_len);
+               return -EINVAL;
+       }
+       verify_area(uservaddr, sockaddr_len);
+       memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
+       if (sockun.sun_family != AF_UNIX) {
+               PRINTK("unix_proto_connect: family is %d, not AF_UNIX (%d)\n",
+                      sockun.sun_family, AF_UNIX);
+               return -EINVAL;
+       }
+       if (!(serv_upd = unix_data_lookup(&sockun, sockaddr_len))) {
+               PRINTK("unix_proto_connect: can't locate peer\n");
+               return -EINVAL;
+       }
+       if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
+               PRINTK("unix_proto_connect: can't await connection\n");
+               return i;
+       }
+       unix_data_ref(UN_DATA(sock->conn));
+       UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
+       return 0;
+}
+
+/*
+ * to do a socketpair, we make just connect the two datas, easy! since we
+ * always wait on the socket inode, they're no contention for a wait area,
+ * and deadlock prevention in the case of a process writing to itself is,
+ * ignored, in true unix fashion!
+ */
+static int
+unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
+{
+       struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
+
+       unix_data_ref(upd1);
+       unix_data_ref(upd2);
+       upd1->peerupd = upd2;
+       upd2->peerupd = upd1;
+       return 0;
+}
+
+/*
+ * on accept, we ref the peer's data for safe writes
+ */
+static int
+unix_proto_accept(struct socket *sock, struct socket *newsock)
+{
+       PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n",
+              sock, newsock);
+       unix_data_ref(UN_DATA(newsock->conn));
+       UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn);
+       return 0;
+}
+
+/*
+ * gets the current name or the name of the connected socket.
+ */
+static int
+unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+                  int *usockaddr_len, int peer)
+{
+       struct unix_proto_data *upd;
+       int len;
+
+       PRINTK("unix_proto_getname: socket 0x%x for %s\n", sock,
+              peer ? "peer" : "self");
+       if (peer) {
+               if (sock->state != SS_CONNECTED) {
+                       PRINTK("unix_proto_getname: socket not connected\n");
+                       return -EINVAL;
+               }
+               upd = UN_DATA(sock->conn);
+       }
+       else
+               upd = UN_DATA(sock);
+       verify_area(usockaddr_len, sizeof(*usockaddr_len));
+       if ((len = get_fs_long(usockaddr_len)) <= 0)
+               return -EINVAL;
+       if (len > upd->sockaddr_len)
+               len = upd->sockaddr_len;
+       if (len) {
+               verify_area(usockaddr, len);
+               memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
+       }
+       put_fs_long(len, usockaddr_len);
+       return 0;
+}
+
+/*
+ * we read from our own buf.
+ */
+static int
+unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+       struct unix_proto_data *upd;
+       int todo, avail;
+
+       if ((todo = size) <= 0)
+               return 0;
+       upd = UN_DATA(sock);
+       while (!(avail = UN_BUF_AVAIL(upd))) {
+               if (sock->state != SS_CONNECTED) {
+                       PRINTK("unix_proto_read: socket not connected\n");
+                       return (sock->state == SS_DISCONNECTING) ? 0 : -EINVAL;
+               }
+               PRINTK("unix_proto_read: no data available...\n");
+               if (nonblock)
+                       return -EAGAIN;
+               interruptible_sleep_on(sock->wait);
+               if (current->signal & ~current->blocked) {
+                       PRINTK("unix_proto_read: interrupted\n");
+                       return -ERESTARTSYS;
+               }
+               if (sock->state == SS_DISCONNECTING) {
+                       PRINTK("unix_proto_read: disconnected\n");
+                       return 0;
+               }
+       }
+
+       /*
+        * copy from the read buffer into the user's buffer, watching for
+        * wraparound. then we wake up the writer
+        */
+       do {
+               int part, cando;
+
+               if (avail <= 0) {
+                       PRINTK("unix_proto_read: AVAIL IS NEGATIVE!!!\n");
+                       current->signal |= (1 << (SIGKILL-1));
+                       return -EINTR;
+               }
+
+               if ((cando = todo) > avail)
+                       cando = avail;
+               if (cando > (part = BUF_SIZE - upd->bp_tail))
+                       cando = part;
+               PRINTK("unix_proto_read: avail=%d, todo=%d, cando=%d\n",
+                      avail, todo, cando);
+               verify_area(ubuf, cando);
+               memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
+               upd->bp_tail = (upd->bp_tail + cando) & (BUF_SIZE-1);
+               ubuf += cando;
+               todo -= cando;
+               if (sock->state == SS_CONNECTED)
+                       wake_up(sock->conn->wait);
+               avail = UN_BUF_AVAIL(upd);
+       } while (todo && avail);
+       return size - todo;
+}
+
+/*
+ * we write to our peer's buf. when we connected we ref'd this peer so we
+ * are safe that the buffer remains, even after the peer has disconnected,
+ * which we check other ways.
+ */
+static int
+unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+       struct unix_proto_data *pupd;
+       int todo, space;
+
+       if ((todo = size) <= 0)
+               return 0;
+       if (sock->state != SS_CONNECTED) {
+               PRINTK("unix_proto_write: socket not connected\n");
+               if (sock->state == SS_DISCONNECTING) {
+                       current->signal |= (1 << (SIGPIPE-1));
+                       return -EINTR;
+               }
+               return -EINVAL;
+       }
+       pupd = UN_DATA(sock)->peerupd;  /* safer than sock->conn */
+
+       while (!(space = UN_BUF_SPACE(pupd))) {
+               PRINTK("unix_proto_write: no space left...\n");
+               if (nonblock)
+                       return 0;
+               interruptible_sleep_on(sock->wait);
+               if (current->signal & ~current->blocked) {
+                       PRINTK("unix_proto_write: interrupted\n");
+                       return -EINTR;
+               }
+               if (sock->state == SS_DISCONNECTING) {
+                       PRINTK("unix_proto_write: disconnected (SIGPIPE)\n");
+                       current->signal |= (1 << (SIGPIPE-1));
+                       return -EINTR;
+               }
+       }
+
+       /*
+        * copy from the user's buffer to the write buffer, watching for
+        * wraparound. then we wake up the reader
+        */
+       do {
+               int part, cando;
+
+               if (space <= 0) {
+                       PRINTK("unix_proto_write: SPACE IS NEGATIVE!!!\n");
+                       current->signal |= (1 << (SIGKILL-1));
+                       return -EINTR;
+               }
+
+               /*
+                * we may become disconnected inside this loop, so watch
+                * for it (peerupd is safe until we close)
+                */
+               if (sock->state == SS_DISCONNECTING) {
+                       current->signal |= (1 << (SIGPIPE-1));
+                       return -EINTR;
+               }
+               if ((cando = todo) > space)
+                       cando = space;
+               if (cando > (part = BUF_SIZE - pupd->bp_head))
+                       cando = part;
+               PRINTK("unix_proto_write: space=%d, todo=%d, cando=%d\n",
+                      space, todo, cando);
+               verify_area(ubuf, cando);
+               memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
+               pupd->bp_head = (pupd->bp_head + cando) & (BUF_SIZE-1);
+               ubuf += cando;
+               todo -= cando;
+               if (sock->state == SS_CONNECTED)
+                       wake_up(sock->conn->wait);
+               space = UN_BUF_SPACE(pupd);
+       } while (todo && space);
+       return size - todo;
+}
+
+static int
+unix_proto_select(struct socket *sock, int which)
+{
+       struct unix_proto_data *upd, *peerupd;
+
+       if (which == SEL_IN) {
+               upd = UN_DATA(sock);
+               PRINTK("unix_proto_select: there is%s data available\n",
+                      UN_BUF_AVAIL(upd) ? "" : " no");
+               if (UN_BUF_AVAIL(upd))  /* even if disconnected */
+                       return 1;
+               else if (sock->state != SS_CONNECTED) {
+                       PRINTK("unix_proto_select: socket not connected (read EOF)\n");
+                       return 1;
+               }
+               else
+                       return 0;
+       }
+       if (which == SEL_OUT) {
+               if (sock->state != SS_CONNECTED) {
+                       PRINTK("unix_proto_select: socket not connected (write EOF)\n");
+                       return 1;
+               }
+               peerupd = UN_DATA(sock->conn);
+               PRINTK("unix_proto_select: there is%s space available\n",
+                      UN_BUF_SPACE(peerupd) ? "" : " no");
+               return (UN_BUF_SPACE(peerupd) > 0);
+       }
+       /* SEL_EX */
+       PRINTK("unix_proto_select: there are no exceptions here?!\n");
+       return 0;
+}
+
+static int
+unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct unix_proto_data *upd, *peerupd;
+
+       upd = UN_DATA(sock);
+       peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
+
+       switch (cmd) {
+       case TIOCINQ:
+               verify_area((void *)arg, sizeof(unsigned long));
+               if (UN_BUF_AVAIL(upd) || peerupd)
+                       put_fs_long(UN_BUF_AVAIL(upd), (unsigned long *)arg);
+               else
+                       put_fs_long(1, (unsigned long *)arg); /* read EOF */
+               break;
+
+       case TIOCOUTQ:
+               verify_area((void *)arg, sizeof(unsigned long));
+               if (peerupd)
+                       put_fs_long(UN_BUF_SPACE(peerupd),
+                                   (unsigned long *)arg);
+               else
+                       put_fs_long(0, (unsigned long *)arg);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int
+unix_proto_init(void)
+{
+       struct unix_proto_data *upd;
+
+       PRINTK("unix_proto_init: initializing...\n");
+       for (upd = unix_datas; upd <= last_unix_data; ++upd)
+               upd->refcnt = 0;
+       return 0;
+}