#
-# 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:
#
-
-KEYBOARD = -DKBD_FINNISH
-# KEYBOARD = -DKBD_US
-# KEYBOARD = -DKBD_GR
-# KEYBOARD = -DKBD_FR
-# KEYBOARD = -DKBD_UK
-# KEYBOARD = -DKBD_DK
-
-#
-# uncomment this line if you are using gcc-1.40
-#
-#GCC_OPT = -fcombine-regs -fstrength-reduce
+# 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_SG -DKBDFLAGS=0
+# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKDB_NO
#
-# standard CFLAGS
+# comment this line if you don't want the emulation-code
#
-CFLAGS =-Wall -O6 -fomit-frame-pointer $(GCC_OPT)
+MATH_EMULATION = -DKERNEL_MATH_EMULATION
#
-# 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'.
+# standard CFLAGS
#
-ROOT_DEV = /dev/hdb1
+CFLAGS =-Wall -O6 -fomit-frame-pointer
#
# if you want the ram-disk device, define this to be the
AS86 =as86 -0 -a
LD86 =ld86 -0
+#
+# If you want to preset the SVGA mode, uncomment the next line and
+# set SVGA_MODE to whatever number you want.
+# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
+# The number is the same as you would ordinarily press at bootup.
+#
+#SVGA_MODE= -DSVGA_MODE=1
+
AS =as
LD =ld
-#LDFLAGS =-s -x -M
-LDFLAGS = -M
-CC =gcc $(RAMDISK)
-MAKE =make CFLAGS="$(CFLAGS)"
-CPP =cpp -nostdinc -Iinclude
-
-ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o
-FILESYSTEMS =fs/minix/minix.o
-DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
+HOSTCC =gcc -static
+CC =gcc -nostdinc -I$(KERNELHDRS)
+MAKE =make
+CPP =$(CC) -E
+AR =ar
+
+ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
+FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o
+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
+SUBDIRS =kernel mm fs net lib
+
+KERNELHDRS =/usr/src/linux/include
.c.s:
- $(CC) $(CFLAGS) \
- -nostdinc -Iinclude -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) \
- -nostdinc -Iinclude -c -o $*.o $<
+ $(CC) $(CFLAGS) -c -o $*.o $<
all: Version Image
+linuxsubdirs: dummy
+ @for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
+
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.95c-`cat .version`\" > include/linux/config_rel.h
+ @echo \#define UTS_RELEASE \"0.97-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
sync
disk: Image
- dd bs=8192 if=Image of=/dev/PS0
+ dd bs=8192 if=Image of=/dev/fd0
tools/build: tools/build.c
- $(CC) -static $(CFLAGS) \
+ $(HOSTCC) $(CFLAGS) \
-o tools/build tools/build.c
boot/head.o: boot/head.s
-tools/system: boot/head.o init/main.o \
- $(ARCHIVES) $(FILESYSTEMS) $(DRIVERS) $(MATH) $(LIBS)
- $(LD) $(LDFLAGS) boot/head.o init/main.o \
- $(ARCHIVES) \
- $(FILESYSTEMS) \
- $(DRIVERS) \
- $(MATH) \
- $(LIBS) \
- -o tools/system > System.map
-
-kernel/math/math.a: dummy
- (cd kernel/math; $(MAKE) MATH_EMULATION="$(MATH_EMULATION)")
-
-kernel/blk_drv/blk_drv.a: dummy
- (cd kernel/blk_drv; $(MAKE))
-
-kernel/chr_drv/chr_drv.a: dummy
- (cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)")
-
-kernel/kernel.o: dummy
- (cd kernel; $(MAKE))
-
-mm/mm.o: dummy
- (cd mm; $(MAKE))
-
-fs/fs.o: dummy
- (cd fs; $(MAKE))
-
-fs/minix/minix.o: dummy
- (cd fs/minix; $(MAKE))
-
-lib/lib.a: dummy
- (cd lib; $(MAKE))
+tools/system: boot/head.o init/main.o linuxsubdirs
+ $(LD) $(LDFLAGS) -M boot/head.o init/main.o \
+ $(ARCHIVES) \
+ $(FILESYSTEMS) \
+ $(DRIVERS) \
+ $(MATH) \
+ $(LIBS) \
+ -o tools/system > System.map
boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
boot/setup.s: boot/setup.S include/linux/config.h
- $(CPP) -traditional boot/setup.S -o boot/setup.s
+ $(CPP) -traditional $(SVGA_MODE) boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h
$(CPP) -traditional boot/bootsect.S -o boot/bootsect.s
$(AS86) -o boot/bootsect.o boot/bootsect.s
$(LD86) -s -o boot/bootsect boot/bootsect.o
+fs: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=fs
+
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s init/main.s
rm -f init/*.o tools/system tools/build boot/*.o
- (cd mm;make clean)
- (cd fs;make clean)
- (cd kernel;make clean)
- (cd lib;make clean)
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
backup: clean
- (cd .. ; tar cf - linux | compress - > backup.Z)
+ cd .. ; tar cf - linux | compress - > backup.Z
sync
-dep:
+depend dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
- (for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make
+ for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
- (cd fs; make dep)
- (cd kernel; make dep)
- (cd mm; make dep)
- (cd lib; make dep)
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep) || exit; done
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/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/linux/tty.h \
- include/termios.h include/linux/string.h include/asm/system.h include/asm/io.h \
- include/stddef.h include/stdarg.h include/fcntl.h
+init/main.o : init/main.c /usr/src/linux/include/stdarg.h /usr/src/linux/include/time.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/linux/unistd.h
#include <linux/config.h>
SYSSIZE = DEF_SYSSIZE
!
-! bootsect.s (C) 1991 Linus Torvalds
+! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
! modified by Drew Eckhardt
! modified by Bruce Evans (bde)
!
mov ax,#0x021c ! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
-undef_root:
- jmp undef_root
+ mov ax,#0x0200 ! /dev/fd0 - autodetect
root_defined:
seg cs
mov root_dev,ax
/*
* linux/boot/head.s
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
*/
.text
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area,_floppy_track_buffer
+/*
+ * pg_dir is the main page directory, address 0x00000000
+ */
_pg_dir:
startup_32:
cld
pg3:
.org 0x5000
+/*
+ * empty_bad_page is a bogus page that will be used when out of memory,
+ * so that a process isn't accidentally killed due to a page fault when
+ * it is running in kernel mode..
+ */
+.globl _empty_bad_page
+_empty_bad_page:
+
+.org 0x6000
+/*
+ * empty_bad_page_table is similar to the above, but is used when the
+ * system needs a bogus page-table
+ */
+.globl _empty_bad_page_table
+_empty_bad_page_table:
+
+.org 0x7000
/*
* tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't
!
-! setup.s (C) 1991 Linus Torvalds
+! setup.s Copyright (C) 1991, 1992 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! NOTE! These had better be the same as in bootsect.s!
#include <linux/config.h>
+#define NORMAL_VGA 0xffff
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF ! mask off all interrupts for now
- out #0x21,al
- .word 0x00eb,0x00eb
out #0xA1,al
+ .word 0x00eb,0x00eb
+ mov al,#0xFB ! mask all irq's but irq2 which
+ out #0x21,al ! is cascaded
! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
mov es,ax
lea si,msg1
call prtstr
+#ifndef SVGA_MODE
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
jb nokey
ja nokey
cmp al,#0x9c
je svga
+#endif
+#if !defined(SVGA_MODE) || SVGA_MODE == NORMAL_VGA
mov ax,#0x5019
pop ds
ret
+#endif
svga: cld
lea si,idati ! Check ATI 'clues'
mov di,#0x31
call prtstr
pop si
add cl,#0x80
+#if defined(SVGA_MODE) && SVGA_MODE != NORMAL_VGA
+ mov al,#SVGA_MODE ! Preset SVGA mode
+#else
nonum: call getkey
cmp al,#0x82
jb nonum
zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
+#endif
xor ah,ah
add di,ax
inc di
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-AR =ar
-AS =as
-LD =ld
-CC =gcc -nostdinc -I../include
-CPP =cpp -nostdinc -I../include
+SUBDIRS =minix ext msdos
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
- select.o
+ select.o fifo.o
+
+all: fs.o fssubdirs
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
+fssubdirs: dummy
+ @for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
+
clean:
rm -f core *.o *.a tmp_make
- for i in *.c;do rm -f `basename $$i .c`.s;done
- cd minix; make clean
+ for i in *.c; do rm -f `basename $$i .c`.s;done
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
-dep:
+depend dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
- (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
- cd minix; make dep
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep) || exit; done
+
+dummy:
### 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/config_rel.h \
- ../include/linux/config_ver.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/linux/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/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
-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
-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/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/asm/system.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
-super.o : super.c ../include/linux/config.h ../include/linux/config_rel.h ../include/linux/config_ver.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
+block_dev.o : block_dev.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h
+buffer.o : buffer.c /usr/src/linux/include/stdarg.h /usr/src/linux/include/linux/config.h \
+ /usr/src/linux/include/linux/config_rel.h /usr/src/linux/include/linux/config_ver.h \
+ /usr/src/linux/include/linux/config.dist.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h
+exec.o : exec.c /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/a.out.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/ptrace.h \
+ /usr/src/linux/include/linux/user.h /usr/src/linux/include/asm/segment.h
+fcntl.o : fcntl.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/string.h
+fifo.o : fifo.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/fcntl.h
+file_table.o : file_table.c /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/string.h
+inode.o : inode.c /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/system.h
+ioctl.o : ioctl.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h
+namei.o : namei.c /usr/src/linux/include/const.h /usr/src/linux/include/asm/segment.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/stat.h
+open.o : open.c /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/utime.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/segment.h
+pipe.o : pipe.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/termios.h
+read_write.o : read_write.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/linux/minix_fs.h \
+ /usr/src/linux/include/asm/segment.h
+select.o : select.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/segment.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/const.h
+stat.o : stat.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/stat.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/asm/segment.h
+super.o : super.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/ext_fs.h \
+ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/stat.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h
/*
* linux/fs/block_dev.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
if (chars > count)
chars=count;
if (chars == BLOCK_SIZE)
- bh = getblk(dev,block);
+ bh = getblk(dev, block, BLOCK_SIZE);
else
bh = breada(dev,block,block+1,block+2,-1);
block++;
/*
* linux/fs/buffer.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/string.h>
+
#include <asm/system.h>
#include <asm/io.h>
-extern int end;
-static struct buffer_head * start_buffer = (struct buffer_head *) &end;
static struct buffer_head * hash_table[NR_HASH];
-static struct buffer_head * free_list;
-static struct task_struct * buffer_wait = NULL;
-int NR_BUFFERS = 0;
+static struct buffer_head * free_list = NULL;
+static struct buffer_head * unused_list = NULL;
+static struct wait_queue * buffer_wait = NULL;
+
+int nr_buffers = 0;
+int nr_buffer_heads = 0;
static inline void wait_on_buffer(struct buffer_head * bh)
{
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);
}
}
int sys_sync(void)
{
+ int i;
+
+ for (i=0 ; i<NR_SUPER ; i++)
+ if (super_block[i].s_dev
+ && super_block[i].s_op
+ && super_block[i].s_op->write_super
+ && super_block[i].s_dirt)
+ super_block[i].s_op->write_super(&super_block[i]);
sync_inodes(); /* write out inodes into buffers */
sync_buffers(0);
return 0;
int sync_dev(int dev)
{
+ struct super_block * sb;
+
+ if (sb = get_super (dev))
+ if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
+ sb->s_op->write_super (sb);
sync_buffers(dev);
sync_inodes();
sync_buffers(dev);
int i;
struct buffer_head * bh;
- bh = start_buffer;
- for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
+ bh = free_list;
+ for (i = nr_buffers*2 ; --i > 0 ; bh = bh->b_next_free) {
if (bh->b_dev != dev)
continue;
wait_on_buffer(bh);
if (MAJOR(dev) != 2)
return;
- if (!(bh = getblk(dev,0)))
+ if (!(bh = getblk(dev,0,1024)))
return;
i = floppy_change(bh);
brelse(bh);
bh->b_next->b_prev = bh;
}
-static struct buffer_head * find_buffer(int dev, int block)
+static struct buffer_head * find_buffer(int dev, int block, int size)
{
struct buffer_head * tmp;
for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
if (tmp->b_dev==dev && tmp->b_blocknr==block)
- return tmp;
+ if (tmp->b_size == size)
+ return tmp;
+ else {
+ printk("wrong block-size on device %04x\n",dev);
+ return NULL;
+ }
return NULL;
}
* will force it bad). This shouldn't really happen currently, but
* the code is ready.
*/
-struct buffer_head * get_hash_table(int dev, int block)
+struct buffer_head * get_hash_table(int dev, int block, int size)
{
struct buffer_head * bh;
for (;;) {
- if (!(bh=find_buffer(dev,block)))
+ if (!(bh=find_buffer(dev,block,size)))
return NULL;
bh->b_count++;
wait_on_buffer(bh);
- if (bh->b_dev == dev && bh->b_blocknr == block) {
+ if (bh->b_dev == dev && bh->b_blocknr == block && bh->b_size == size) {
put_last_free(bh);
return bh;
}
* when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
-struct buffer_head * getblk(int dev,int block)
+struct buffer_head * getblk(int dev, int block, int size)
{
struct buffer_head * bh, * tmp;
int buffers;
repeat:
- if (bh = get_hash_table(dev,block))
+ if (bh = get_hash_table(dev, block, size))
return bh;
- buffers = NR_BUFFERS;
- tmp = free_list;
- do {
- tmp = tmp->b_next_free;
- if (tmp->b_count)
+
+ if (nr_free_pages > 30)
+ grow_buffers(size);
+
+ buffers = nr_buffers;
+ bh = NULL;
+
+ for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) {
+ if (tmp->b_count || tmp->b_size != size)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
bh = tmp;
if (!BADNESS(tmp))
break;
}
+#if 0
if (tmp->b_dirt)
ll_rw_block(WRITEA,tmp);
+#endif
+ }
+
+ if (!bh && nr_free_pages > 5) {
+ grow_buffers(size);
+ goto repeat;
+ }
+
/* and repeat until we find something good */
- } while (buffers--);
if (!bh) {
sleep_on(&buffer_wait);
goto repeat;
}
wait_on_buffer(bh);
- if (bh->b_count)
+ if (bh->b_count || bh->b_size != size)
+ goto repeat;
+ if (bh->b_dirt) {
+ sync_buffers(bh->b_dev);
goto repeat;
- while (bh->b_dirt) {
- sync_dev(bh->b_dev);
- wait_on_buffer(bh);
- if (bh->b_count)
- goto repeat;
}
/* NOTE!! While we slept waiting for this block, somebody else might */
/* already have added "this" block to the cache. check it */
- if (find_buffer(dev,block))
+ if (find_buffer(dev,block,size))
goto repeat;
/* OK, FINALLY we know that this buffer is the only one of it's kind, */
/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
* bread() reads a specified block and returns the buffer that contains
* it. It returns NULL if the block was unreadable.
*/
-struct buffer_head * bread(int dev,int block)
+struct buffer_head * bread(int dev, int block, int size)
{
struct buffer_head * bh;
- if (!(bh=getblk(dev,block)))
- panic("bread: getblk returned NULL\n");
+ if (!(bh = getblk(dev, block, size))) {
+ printk("bread: getblk returned NULL\n");
+ return NULL;
+ }
if (bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
for (i=0 ; i<4 ; i++)
if (b[i]) {
- if (bh[i] = getblk(dev,b[i]))
+ if (bh[i] = getblk(dev, b[i], 1024))
if (!bh[i]->b_uptodate)
ll_rw_block(READ,bh[i]);
} else
struct buffer_head * bh, *tmp;
va_start(args,first);
- if (!(bh=getblk(dev,first)))
- panic("bread: getblk returned NULL\n");
+ if (!(bh = getblk(dev, first, 1024))) {
+ printk("breada: getblk returned NULL\n");
+ return NULL;
+ }
if (!bh->b_uptodate)
ll_rw_block(READ,bh);
while ((first=va_arg(args,int))>=0) {
- tmp=getblk(dev,first);
+ tmp = getblk(dev, first, 1024);
if (tmp) {
if (!tmp->b_uptodate)
- ll_rw_block(READA,bh);
+ ll_rw_block(READA,tmp);
tmp->b_count--;
}
}
return (NULL);
}
-void buffer_init(long buffer_end)
+static void put_unused_buffer_head(struct buffer_head * bh)
+{
+ memset((void *) bh,0,sizeof(*bh));
+ bh->b_next_free = unused_list;
+ unused_list = bh;
+}
+
+static void get_more_buffer_heads(void)
+{
+ unsigned long page;
+ struct buffer_head * bh;
+
+ if (unused_list)
+ return;
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return;
+ bh = (struct buffer_head *) page;
+ while ((unsigned long) (bh+1) <= page+4096) {
+ put_unused_buffer_head(bh);
+ bh++;
+ nr_buffer_heads++;
+ }
+}
+
+static struct buffer_head * get_unused_buffer_head(void)
+{
+ struct buffer_head * bh;
+
+ get_more_buffer_heads();
+ if (!unused_list)
+ return NULL;
+ bh = unused_list;
+ unused_list = bh->b_next_free;
+ bh->b_next_free = NULL;
+ bh->b_data = NULL;
+ bh->b_size = 0;
+ return bh;
+}
+
+/*
+ * Try to increase the number of buffers available: the size argument
+ * is used to determine what kind of buffers we want. Currently only
+ * 1024-byte buffers are supported by the rest of the system, but I
+ * think this will change eventually.
+ */
+void grow_buffers(int size)
{
- struct buffer_head * h = start_buffer;
- void * b;
+ unsigned long page;
int i;
+ struct buffer_head *bh, *tmp;
- if (buffer_end == 1<<20)
- b = (void *) (640*1024);
- else
- b = (void *) buffer_end;
- while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
- if (((unsigned long) (h+1)) > 0xA0000) {
- printk("buffer-list doesn't fit in low meg - contact Linus\n");
+ if ((size & 511) || (size > 4096)) {
+ printk("grow_buffers: size = %d\n",size);
+ return;
+ }
+ page = get_free_page(GFP_BUFFER);
+ if (!page)
+ return;
+ tmp = NULL;
+ i = 0;
+ for (i = 0 ; i+size <= 4096 ; i += size) {
+ bh = get_unused_buffer_head();
+ if (!bh)
+ goto no_grow;
+ bh->b_this_page = tmp;
+ tmp = bh;
+ bh->b_data = (char * ) (page+i);
+ bh->b_size = size;
+ i += size;
+ }
+ tmp = bh;
+ while (1) {
+ tmp->b_next_free = free_list;
+ tmp->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = tmp;
+ free_list->b_prev_free = tmp;
+ free_list = tmp;
+ ++nr_buffers;
+ if (tmp->b_this_page)
+ tmp = tmp->b_this_page;
+ else
break;
+ }
+ tmp->b_this_page = bh;
+ return;
+/*
+ * In case anything failed, we just free everything we got.
+ */
+no_grow:
+ bh = tmp;
+ while (bh) {
+ tmp = bh;
+ bh = bh->b_this_page;
+ put_unused_buffer_head(tmp);
+ }
+ free_page(page);
+}
+
+/*
+ * try_to_free() checks if all the buffers on this particular page
+ * are unused, and free's the page if so.
+ */
+static int try_to_free(struct buffer_head * bh)
+{
+ unsigned long page;
+ struct buffer_head * tmp, * p;
+
+ tmp = bh;
+ do {
+ if (!tmp)
+ return 0;
+ if (tmp->b_count || tmp->b_dirt || tmp->b_lock)
+ return 0;
+ tmp = tmp->b_this_page;
+ } while (tmp != bh);
+ page = (unsigned long) bh->b_data;
+ page &= 0xfffff000;
+ tmp = bh;
+ do {
+ p = tmp;
+ tmp = tmp->b_this_page;
+ nr_buffers--;
+ remove_from_queues(p);
+ put_unused_buffer_head(p);
+ } while (tmp != bh);
+ free_page(page);
+ return 1;
+}
+
+/*
+ * Try to free up some pages by shrinking the buffer-cache
+ */
+int shrink_buffers(void)
+{
+ struct buffer_head *bh;
+ int i;
+
+ bh = free_list;
+ for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) {
+ wait_on_buffer(bh);
+ if (bh->b_count || !bh->b_this_page)
+ continue;
+ if (bh->b_dirt) {
+ ll_rw_block(WRITEA,bh);
+ continue;
}
- h->b_dev = 0;
- h->b_dirt = 0;
- h->b_count = 0;
- h->b_lock = 0;
- h->b_uptodate = 0;
- h->b_wait = NULL;
- h->b_next = NULL;
- h->b_prev = NULL;
- h->b_data = (char *) b;
- h->b_prev_free = h-1;
- h->b_next_free = h+1;
- h++;
- NR_BUFFERS++;
- if (b == (void *) 0x100000)
- b = (void *) 0xA0000;
+ if (try_to_free(bh))
+ return 1;
}
- h--;
- free_list = start_buffer;
- free_list->b_prev_free = h;
- h->b_next_free = free_list;
- for (i=0;i<NR_HASH;i++)
+ return 0;
+}
+
+/*
+ * This initializes the low 1M that isn't used by the kernel to buffer
+ * cache. It should really be used for paging memory, but it takes a lot
+ * of special-casing, which I don't want to do.
+ *
+ * The biggest problem with this approach is that all low-mem buffers
+ * have a fixed size of 1024 chars: not good if/when the other sizes
+ * are implemented.
+ */
+void buffer_init(void)
+{
+ struct buffer_head * bh;
+ extern int end;
+ unsigned long mem;
+ int i;
+
+ for (i = 0 ; i < NR_HASH ; i++)
hash_table[i] = NULL;
-}
+ mem = (unsigned long) & end;
+ mem += BLOCK_SIZE-1;
+ mem &= ~(BLOCK_SIZE-1);
+ free_list = get_unused_buffer_head();
+ if (!free_list)
+ panic("unable to get a single buffer-head");
+ free_list->b_prev_free = free_list;
+ free_list->b_next_free = free_list;
+ free_list->b_data = (char *) mem;
+ free_list->b_size = BLOCK_SIZE;
+ mem += BLOCK_SIZE;
+ while (mem + 1024 < 0xA0000) {
+ bh = get_unused_buffer_head();
+ if (!bh)
+ break;
+ bh->b_data = (char *) mem;
+ bh->b_size = BLOCK_SIZE;
+ mem += BLOCK_SIZE;
+ bh->b_next_free = free_list;
+ bh->b_prev_free = free_list->b_prev_free;
+ free_list->b_prev_free->b_next_free = bh;
+ free_list->b_prev_free = bh;
+ free_list = bh;
+ ++nr_buffers;
+ }
+ return;
+}
/*
* linux/fs/exec.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* was less than 2 hours work to get demand-loading completely implemented.
*/
-#include <signal.h>
-#include <errno.h>
-#include <linux/string.h>
-#include <sys/stat.h>
-#include <a.out.h>
-
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
#include <asm/segment.h>
extern int sys_exit(int exit_code);
*/
#define MAX_ARG_PAGES 32
+/*
+ * These are the only things you should do on a core-file: use only these
+ * macros to write out all the necessary info.
+ */
+#define DUMP_WRITE(addr,nr) \
+while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+
+#define DUMP_SEEK(offset) \
+if (file.f_op->lseek) { \
+ if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
+ goto close_coredump; \
+} else file.f_pos = (offset)
+
+/*
+ * Routine writes a core dump image in the current directory.
+ * Currently only a stub-function.
+ *
+ * Note that setuid/setgid files won't make a core-dump if the uid/gid
+ * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
+ * field, which also makes sure the core-dumps won't be recursive if the
+ * dumping of the process results in another error..
+ */
+int core_dump(long signr, struct pt_regs * regs)
+{
+ struct inode * inode = NULL;
+ struct file file;
+ unsigned short fs;
+ int has_dumped = 0;
+ register int dump_start, dump_size;
+ struct user dump;
+
+ if (!current->dumpable)
+ return 0;
+ current->dumpable = 0;
+/* See if we have enough room to write the upage. */
+ if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
+ __asm__("mov %%fs,%0":"=r" (fs));
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode))
+ goto end_coredump;
+ if (!S_ISREG(inode->i_mode))
+ goto end_coredump;
+ if (!inode->i_op || !inode->i_op->default_file_ops)
+ goto end_coredump;
+ file.f_mode = 3;
+ file.f_flags = 0;
+ file.f_count = 1;
+ file.f_inode = inode;
+ file.f_pos = 0;
+ file.f_reada = 0;
+ file.f_op = inode->i_op->default_file_ops;
+ if (file.f_op->open)
+ if (file.f_op->open(inode,&file))
+ goto end_coredump;
+ if (!file.f_op->write)
+ goto close_coredump;
+ has_dumped = 1;
+/* write and seek example: from kernel space */
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ dump.magic = CMAGIC;
+ dump.u_tsize = current->end_code / PAGE_SIZE;
+ dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
+ dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
+ (regs->esp/ PAGE_SIZE);
+/* If the size of the dump file exceeds the rlimit, then see what would happen
+ if we wrote the stack, but not the data area. */
+ if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
+ current->rlim[RLIMIT_CORE].rlim_cur)
+ dump.u_dsize = 0;
+/* Make sure we have enough room to write the stack and data areas. */
+ if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
+ current->rlim[RLIMIT_CORE].rlim_cur)
+ dump.u_ssize = 0;
+ dump.u_comm = 0;
+ dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
+ dump.signal = signr;
+ dump.regs = *regs;
+ dump.start_code = 0;
+ dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
+/* Flag indicating the math stuff is valid. */
+ if (dump.u_fpvalid = current->used_math) {
+ if (last_task_used_math == current)
+ __asm__("clts ; fnsave %0"::"m" (dump.i387));
+ else
+ memcpy(&dump.i387,¤t->tss.i387,sizeof(dump.i387));
+ };
+ DUMP_WRITE(&dump,sizeof(dump));
+ DUMP_SEEK(sizeof(dump));
+ /* Dump the task struct. Not be used by gdb, but could be useful */
+ DUMP_WRITE(current,sizeof(*current));
+/* Now dump all of the user data. Include malloced stuff as well */
+ DUMP_SEEK(PAGE_SIZE);
+/* now we start writing out the user space info */
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
+/* Dump the data area */
+ if (dump.u_dsize != 0) {
+ dump_start = current->end_code;
+ dump_size = current->brk - current->end_code;
+ DUMP_WRITE(dump_start,dump_size);
+ };
+/* Now prepare to dump the stack area */
+ if (dump.u_ssize != 0) {
+ dump_start = regs->esp & ~(PAGE_SIZE - 1);
+ dump_size = dump.u_ssize * PAGE_SIZE;
+ DUMP_WRITE(dump_start,dump_size);
+ };
+close_coredump:
+ if (file.f_op->release)
+ file.f_op->release(inode,&file);
+end_coredump:
+ __asm__("mov %0,%%fs"::"r" (fs));
+ iput(inode);
+ return has_dumped;
+}
+
/*
* Note that a shared library must be both readable and executable due to
* security reasons.
inode = NULL;
if (!inode)
return -ENOENT;
- if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ|MAY_EXEC)) {
+ if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
iput(inode);
return -EACCES;
}
- if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
iput(inode);
return -EACCES;
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
ex = *(struct exec *) bh->b_data;
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
unsigned long p, int from_kmem)
{
- char *tmp, *pag;
+ char *tmp, *pag = NULL;
int len, offset = 0;
unsigned long old_fs, new_fs;
set_fs(old_fs);
if (!(pag = (char *) page[p/PAGE_SIZE]) &&
!(pag = (char *) page[p/PAGE_SIZE] =
- (unsigned long *) get_free_page()))
+ (unsigned long *) get_free_page(GFP_USER)))
return 0;
if (from_kmem==2)
set_fs(new_fs);
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;
+ unsigned int block_size;
+
+ block_size = 1024;
+ if (inode->i_sb)
+ block_size = inode->i_sb->s_blocksize;
+ while (bytes > 0) {
+ if (!(blkno = bmap(inode, blk)))
+ sys_exit(-1);
+ if (!(bh = bread(inode->i_dev, blkno, block_size)))
+ 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.
*
retval = -EACCES;
goto exec_error2;
}
+ if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
+ retval = -EPERM;
+ goto exec_error2;
+ }
+ if (!inode->i_sb) {
+ retval = -EACCES;
+ goto exec_error2;
+ }
i = inode->i_mode;
+ if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current->
+ euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) &&
+ !suser()) {
+ retval = -EPERM;
+ goto exec_error2;
+ }
/* make sure we don't let suid, sgid files be ptraced. */
if (current->flags & PF_PTRACED) {
e_uid = current->euid;
retval = -EACCES;
goto exec_error2;
}
- if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
retval = -EACCES;
goto exec_error2;
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
ex = *((struct exec *) bh->b_data); /* read exec-header */
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
/*
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;
}
}
/* OK, This is the point of no return */
+ current->dumpable = 1;
for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
if (ch == '/')
i = 0;
iput(current->libraries[i].library);
current->libraries[i].library = NULL;
}
+ if (e_uid != current->euid || e_gid != current->egid ||
+ !permission(inode,MAY_READ))
+ current->dumpable = 0;
current->numlibraries = 0;
current->executable = inode;
current->signal = 0;
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)
- send_sig(SIGTRAP, current, 0);
+ send_sig(SIGTRAP, current, 0);
return 0;
exec_error2:
iput(inode);
--- /dev/null
+#
+# Makefile for the linux ext-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= bitmap.o freelists.o truncate.o namei.o inode.o \
+ file.o dir.o symlink.o blkdev.o chrdev.o fifo.o
+
+ext.o: $(OBJS)
+ $(LD) -r -o ext.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:
+bitmap.o : bitmap.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/string.h
+blkdev.o : blkdev.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/errno.h
+chrdev.o : chrdev.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/errno.h
+dir.o : dir.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/ext_fs.h \
+ /usr/src/linux/include/linux/stat.h
+fifo.o : fifo.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h
+file.o : file.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/stat.h
+freelists.o : freelists.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/string.h
+inode.o : inode.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h
+namei.o : namei.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/const.h
+symlink.o : symlink.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/stat.h
+truncate.o : truncate.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/errno.h
--- /dev/null
+/*
+ * linux/fs/ext/bitmap.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/bitmap.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#ifdef EXTFS_BITMAP
+
+#define clear_block(addr) \
+__asm__("cld\n\t" \
+ "rep\n\t" \
+ "stosl" \
+ ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+
+#define set_bit(nr,addr) ({\
+char res; \
+__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \
+"=q" (res):"r" (nr),"m" (*(addr))); \
+res;})
+
+#define clear_bit(nr,addr) ({\
+char res; \
+__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \
+"=q" (res):"r" (nr),"m" (*(addr))); \
+res;})
+
+#define find_first_zero(addr) ({ \
+int __res; \
+__asm__("cld\n" \
+ "1:\tlodsl\n\t" \
+ "notl %%eax\n\t" \
+ "bsfl %%eax,%%edx\n\t" \
+ "jne 2f\n\t" \
+ "addl $32,%%ecx\n\t" \
+ "cmpl $8192,%%ecx\n\t" \
+ "jl 1b\n\t" \
+ "xorl %%edx,%%edx\n" \
+ "2:\taddl %%edx,%%ecx" \
+ :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
+__res;})
+
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
+ unsigned numbits)
+{
+ unsigned i, j, end, sum = 0;
+ struct buffer_head *bh;
+
+ for (i=0; (i<numblocks) && numbits; i++) {
+ if (!(bh=map[i]))
+ return(0);
+ if (numbits >= (8*BLOCK_SIZE)) {
+ end = BLOCK_SIZE;
+ numbits -= 8*BLOCK_SIZE;
+ } else {
+ int tmp;
+ end = numbits >> 3;
+ numbits &= 0x7;
+ tmp = bh->b_data[end] & ((1<<numbits)-1);
+ sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf];
+ numbits = 0;
+ }
+ for (j=0; j<end; j++)
+ sum += nibblemap[bh->b_data[j] & 0xf]
+ + nibblemap[(bh->b_data[j]>>4)&0xf];
+ }
+ return(sum);
+}
+
+int ext_free_block(int dev, int block)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+ unsigned int bit,zone;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to free block on nonexistent device");
+ if (block < sb->s_firstdatazone || block >= sb->s_nzones)
+ panic("trying to free block not in datazone");
+ bh = get_hash_table(dev,block);
+ if (bh) {
+ if (bh->b_count > 1) {
+ brelse(bh);
+ return 0;
+ }
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ if (bh->b_count)
+ brelse(bh);
+ }
+ zone = block - sb->s_firstdatazone + 1;
+ bit = zone & 8191;
+ zone >>= 13;
+ bh = sb->s_zmap[zone];
+ if (clear_bit(bit,bh->b_data))
+ printk("free_block (%04x:%d): bit already cleared\n",dev,block);
+ bh->b_dirt = 1;
+ return 1;
+}
+
+int ext_new_block(int dev)
+{
+ struct buffer_head * bh;
+ struct super_block * sb;
+ int i,j;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to get new block from nonexistant device");
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=sb->s_zmap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (i>=8 || !bh || j>=8192)
+ return 0;
+ if (set_bit(j,bh->b_data))
+ panic("new_block: bit already set");
+ bh->b_dirt = 1;
+ j += i*8192 + sb->s_firstdatazone-1;
+ if (j >= sb->s_nzones)
+ return 0;
+ if (!(bh=getblk(dev,j)))
+ panic("new_block: cannot get block");
+ if (bh->b_count != 1)
+ panic("new block: count is != 1");
+ clear_block(bh->b_data);
+ bh->b_uptodate = 1;
+ bh->b_dirt = 1;
+ brelse(bh);
+#ifdef EXTFS_DEBUG
+printk("ext_new_block: allocating block %d\n", j);
+#endif
+ return j;
+}
+
+unsigned long ext_count_free_blocks(struct super_block *sb)
+{
+ return (sb->s_nzones - count_used(sb->s_zmap,sb->s_zmap_blocks,sb->s_nzones))
+ << sb->s_log_zone_size;
+}
+
+void ext_free_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+
+ if (!inode)
+ return;
+ if (!inode->i_dev) {
+ memset(inode,0,sizeof(*inode));
+ return;
+ }
+ if (inode->i_count>1) {
+ printk("free_inode: inode has count=%d\n",inode->i_count);
+ return;
+ }
+ if (inode->i_nlink) {
+ printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
+ return;
+ }
+ if (!inode->i_sb) {
+ printk("free_inode: inode on nonexistent device\n");
+ return;
+ }
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
+ printk("free_inode: inode 0 or nonexistent inode\n");
+ return;
+ }
+ if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
+ printk("free_inode: nonexistent imap in superblock\n");
+ return;
+ }
+ if (clear_bit(inode->i_ino&8191,bh->b_data))
+ printk("free_inode: bit already cleared.\n\r");
+ bh->b_dirt = 1;
+ memset(inode,0,sizeof(*inode));
+}
+
+struct inode * ext_new_inode(int dev)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ int i,j;
+
+ if (!(inode=get_empty_inode()))
+ return NULL;
+ if (!(inode->i_sb = get_super(dev))) {
+ printk("new_inode: unknown device\n");
+ iput(inode);
+ return NULL;
+ }
+ inode->i_flags = inode->i_sb->s_flags;
+ j = 8192;
+ for (i=0 ; i<8 ; i++)
+ if (bh=inode->i_sb->s_imap[i])
+ if ((j=find_first_zero(bh->b_data))<8192)
+ break;
+ if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
+ iput(inode);
+ return NULL;
+ }
+ if (set_bit(j,bh->b_data)) { /* shouldn't happen */
+ printk("new_inode: bit already set");
+ iput(inode);
+ return NULL;
+ }
+ bh->b_dirt = 1;
+ inode->i_count = 1;
+ inode->i_nlink = 1;
+ inode->i_dev = dev;
+ inode->i_uid = current->euid;
+ inode->i_gid = current->egid;
+ inode->i_dirt = 1;
+ inode->i_ino = j + i*8192;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = NULL;
+#ifdef EXTFS_DEBUG
+ printk("ext_new_inode : allocating inode %d\n", inode->i_ino);
+#endif
+ return inode;
+}
+
+unsigned long ext_count_free_inodes(struct super_block *sb)
+{
+ return sb->s_ninodes - count_used(sb->s_imap,sb->s_imap_blocks,sb->s_ninodes);
+}
+
+#endif
--- /dev/null
+/*
+ * linux/fs/ext/blkdev.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/blkdev.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/tty.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+/*
+ * Called every time an ext block special file is opened
+ */
+static int blkdev_open(struct inode * inode, struct file * filp)
+{
+ int i;
+
+ 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 ext_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 */
+ ext_bmap, /* bmap */
+ ext_truncate /* truncate */
+};
--- /dev/null
+/*
+ * linux/fs/ext/chrdev.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/chrdev.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/tty.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+/*
+ * Called every time an ext 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 ext_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 */
+ ext_bmap, /* bmap */
+ ext_truncate /* truncate */
+};
+
--- /dev/null
+/*
+ * linux/fs/ext/dir.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/dir.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext_fs.h>
+#include <linux/stat.h>
+
+static int ext_readdir(struct inode *, struct file *, struct dirent *, int);
+
+static struct file_operations ext_dir_operations = {
+ NULL, /* lseek - default */
+ NULL, /* read */
+ NULL, /* write - bad */
+ ext_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 ext_dir_inode_operations = {
+ &ext_dir_operations, /* default directory file-ops */
+ ext_create, /* create */
+ ext_lookup, /* lookup */
+ ext_link, /* link */
+ ext_unlink, /* unlink */
+ ext_symlink, /* symlink */
+ ext_mkdir, /* mkdir */
+ ext_rmdir, /* rmdir */
+ ext_mknod, /* mknod */
+ ext_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ ext_bmap, /* bmap */
+ ext_truncate /* truncate */
+};
+
+static int ext_readdir(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ unsigned int block,offset,i;
+ char c;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+/* if (filp->f_pos & (sizeof (struct ext_dir_entry) - 1))
+ return -EBADF; */
+ while (filp->f_pos < inode->i_size) {
+ offset = filp->f_pos & 1023;
+ block = ext_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
+ if (!block || !(bh = bread(inode->i_dev, block, BLOCK_SIZE))) {
+ filp->f_pos += 1024-offset;
+ continue;
+ }
+ de = (struct ext_dir_entry *) (offset + bh->b_data);
+ while (offset < 1024 && filp->f_pos < inode->i_size) {
+ offset += de->rec_len;
+ filp->f_pos += de->rec_len;
+ if (de->inode) {
+ for (i = 0; i < de->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++; */
+ de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+ }
+ brelse(bh);
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * linux/fs/fifo.c
+ *
+ * written by Paul H. Hargrove.
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+
+extern struct file_operations def_fifo_fops;
+
+struct inode_operations ext_fifo_inode_operations = {
+ &def_fifo_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 */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
--- /dev/null
+/*
+ * linux/fs/ext/file.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/file.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext regular file handling primitives
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.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/ext_fs.h>
+
+static int ext_file_read(struct inode *, struct file *, char *, int);
+static int ext_file_write(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the ext filesystem.
+ */
+static struct file_operations ext_file_operations = {
+ NULL, /* lseek - default */
+ ext_file_read, /* read */
+ ext_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open is needed */
+ NULL /* release */
+};
+
+struct inode_operations ext_file_inode_operations = {
+ &ext_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 */
+ ext_bmap, /* bmap */
+ ext_truncate /* truncate */
+};
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
+static int ext_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("ext_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
+ printk("ext_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 = ext_bmap(inode,block++)) {
+ *bhb = getblk(inode->i_dev, nr, BLOCK_SIZE);
+ 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;
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+ return read;
+}
+
+static int ext_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("ext_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("ext_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 = ext_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, BLOCK_SIZE);
+ else
+ bh = bread(inode->i_dev, block, BLOCK_SIZE);
+ 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;
+ inode->i_ctime = CURRENT_TIME;
+ filp->f_pos = pos;
+ inode->i_dirt = 1;
+ return written;
+}
--- /dev/null
+/*
+ * linux/fs/ext/freelists.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ */
+
+/* freelists.c contains the code that handles the inode and block free lists */
+
+
+/*
+
+ The free blocks are managed by a linked list. The super block contains the
+ number of the first free block. This block contains 254 numbers of other
+ free blocks and the number of the next block in the list.
+
+ When an ext fs is mounted, the number of the first free block is stored
+ in s->u.ext_sb.s_zmap[0] and the block header is stored in s->u.ext_sb.s_zmap[1]. u.ext_sb.s_zmap[2]
+ contains the count of free blocks.
+
+ Currently, it is a hack to allow this kind of management with the super_block
+ structure.
+ Perhaps, in the future, we may have to change the super_block structure to
+ include dedicated fields.
+
+ The free inodes are also managed by a linked list in a similar way. The
+ super block contains the number of the first free inode. This inode contains
+ 14 numbers of other free inodes and the number of the next inode in the list.
+
+ The number of the first free inode is stored in s->u.ext_sb.s_imap[0] and the header
+ of the block containing the inode is stored in s->u.ext_sb.s_imap[1]. u.ext_sb.s_imap[2] contains
+ the count of free inodes.
+
+*/
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#ifdef EXTFS_FREELIST
+
+#define clear_block(addr) \
+__asm__("cld\n\t" \
+ "rep\n\t" \
+ "stosl" \
+ ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
+
+int ext_free_block(int dev, int block)
+{
+ struct super_block * sb;
+ struct buffer_head * bh;
+ struct ext_free_block * efb;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to free block on nonexistent device");
+ lock_super (sb);
+ if (block < sb->u.ext_sb.s_firstdatazone || block >= sb->u.ext_sb.s_nzones)
+ panic("trying to free block not in datazone");
+ bh = get_hash_table(dev, block, sb->s_blocksize);
+ if (bh) {
+ if (bh->b_count > 1) {
+ brelse(bh);
+ free_super (sb);
+ return 0;
+ }
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ if (bh->b_count)
+ brelse(bh);
+ }
+ if (sb->u.ext_sb.s_zmap[1])
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ if (!sb->u.ext_sb.s_zmap[1] || efb->count == 254) {
+#ifdef EXTFS_DEBUG
+printk("ext_free_block: block full, skipping to %d\n", block);
+#endif
+ if (sb->u.ext_sb.s_zmap[1])
+ brelse (sb->u.ext_sb.s_zmap[1]);
+ if (!(sb->u.ext_sb.s_zmap[1] = bread (dev, block, sb->s_blocksize)))
+ panic ("ext_free_block: unable to read block to free\n");
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ efb->next = (unsigned long) sb->u.ext_sb.s_zmap[0];
+ efb->count = 0;
+ sb->u.ext_sb.s_zmap[0] = (struct buffer_head *) block;
+ } else {
+ efb->free[efb->count++] = block;
+ }
+ sb->u.ext_sb.s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->u.ext_sb.s_zmap[2]) + 1);
+ sb->s_dirt = 1;
+ sb->u.ext_sb.s_zmap[1]->b_dirt = 1;
+ free_super (sb);
+ return 1;
+}
+
+int ext_new_block(int dev)
+{
+ struct buffer_head * bh;
+ struct super_block * sb;
+ struct ext_free_block * efb;
+ int /* i, */ j;
+
+ if (!(sb = get_super(dev)))
+ panic("trying to get new block from nonexistant device");
+ if (!sb->u.ext_sb.s_zmap[1])
+ return 0;
+ lock_super (sb);
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ if (efb->count) {
+ j = efb->free[--efb->count];
+ sb->u.ext_sb.s_zmap[1]->b_dirt = 1;
+ } else {
+#ifdef EXTFS_DEBUG
+printk("ext_new_block: block empty, skipping to %d\n", efb->next);
+#endif
+ j = (unsigned long) sb->u.ext_sb.s_zmap[0];
+ sb->u.ext_sb.s_zmap[0] = (struct buffer_head *) efb->next;
+ brelse (sb->u.ext_sb.s_zmap[1]);
+ if (!sb->u.ext_sb.s_zmap[0]) {
+ sb->u.ext_sb.s_zmap[1] = NULL;
+ } else {
+ if (!(sb->u.ext_sb.s_zmap[1] = bread (dev, (unsigned long) sb->u.ext_sb.s_zmap[0], sb->s_blocksize)))
+ panic ("ext_new_block: unable to read next free block\n");
+ }
+ }
+ if (j < sb->u.ext_sb.s_firstdatazone || j > sb->u.ext_sb.s_nzones) {
+ printk ("ext_new_block: blk = %d\n", j);
+ panic ("allocating block not in data zone\n");
+ }
+ sb->u.ext_sb.s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->u.ext_sb.s_zmap[2]) - 1);
+ sb->s_dirt = 1;
+
+ if (!(bh=getblk(dev, j, sb->s_blocksize)))
+ panic("new_block: cannot get block");
+ if (bh->b_count != 1)
+ panic("new block: count is != 1");
+ clear_block(bh->b_data);
+ bh->b_uptodate = 1;
+ bh->b_dirt = 1;
+ brelse(bh);
+#ifdef EXTFS_DEBUG
+printk("ext_new_block: allocating block %d\n", j);
+#endif
+ free_super (sb);
+ return j;
+}
+
+unsigned long ext_count_free_blocks(struct super_block *sb)
+{
+#ifdef EXTFS_DEBUG
+ struct buffer_head * bh;
+ struct ext_free_block * efb;
+ unsigned long count, block;
+
+ lock_super (sb);
+ if (!sb->u.ext_sb.s_zmap[1])
+ count = 0;
+ else {
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ count = efb->count + 1;
+ block = efb->next;
+ while (block) {
+ if (!(bh = bread (sb->s_dev, block, sb->s_blocksize))) {
+ printk ("ext_count_free: error while reading free blocks list\n");
+ block = 0;
+ } else {
+ efb = (struct ext_free_block *) bh->b_data;
+ count += efb->count + 1;
+ block = efb->next;
+ brelse (bh);
+ }
+ }
+ }
+printk("ext_count_free_blocks: stored = %d, computed = %d\n",
+ (unsigned long) sb->u.ext_sb.s_zmap[2], count);
+ free_super (sb);
+ return count;
+#else
+ return (unsigned long) sb->u.ext_sb.s_zmap[2];
+#endif
+}
+
+void ext_free_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct ext_free_inode * efi;
+ unsigned long block;
+
+ if (!inode)
+ return;
+ if (!inode->i_dev) {
+ memset(inode,0,sizeof(*inode));
+ return;
+ }
+ if (inode->i_count>1) {
+ printk("free_inode: inode has count=%d\n",inode->i_count);
+ return;
+ }
+ if (inode->i_nlink) {
+ printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
+ return;
+ }
+ if (!inode->i_sb) {
+ printk("free_inode: inode on nonexistent device\n");
+ return;
+ }
+ lock_super (inode->i_sb);
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.ext_sb.s_ninodes) {
+ printk("free_inode: inode 0 or nonexistent inode\n");
+ free_super (inode->i_sb);
+ return;
+ }
+ if (inode->i_sb->u.ext_sb.s_imap[1])
+ efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_imap[1]->b_data) +
+ (((unsigned long) inode->i_sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK;
+ if (!inode->i_sb->u.ext_sb.s_imap[1] || efi->count == 14) {
+#ifdef EXTFS_DEBUG
+printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
+#endif
+ if (inode->i_sb->u.ext_sb.s_imap[1])
+ brelse (inode->i_sb->u.ext_sb.s_imap[1]);
+ block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK;
+ if (!(bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize)))
+ panic("ext_free_inode: unable to read inode block\n");
+ efi = ((struct ext_free_inode *) bh->b_data) +
+ (inode->i_ino - 1) % EXT_INODES_PER_BLOCK;
+ efi->next = (unsigned long) inode->i_sb->u.ext_sb.s_imap[0];
+ efi->count = 0;
+ inode->i_sb->u.ext_sb.s_imap[0] = (struct buffer_head *) inode->i_ino;
+ inode->i_sb->u.ext_sb.s_imap[1] = bh;
+ } else {
+ efi->free[efi->count++] = inode->i_ino;
+ }
+ inode->i_sb->u.ext_sb.s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->u.ext_sb.s_imap[2]) + 1);
+ inode->i_sb->s_dirt = 1;
+ inode->i_sb->u.ext_sb.s_imap[1]->b_dirt = 1;
+ free_super (inode->i_sb);
+ memset(inode,0,sizeof(*inode));
+}
+
+struct inode * ext_new_inode(int dev)
+{
+ struct inode * inode;
+ struct ext_free_inode * efi;
+ unsigned long block;
+ int /* i, */ j;
+
+ if (!(inode=get_empty_inode()))
+ return NULL;
+ if (!(inode->i_sb = get_super(dev))) {
+ printk("new_inode: unknown device\n");
+ iput(inode);
+ return NULL;
+ }
+ inode->i_flags = inode->i_sb->s_flags;
+ if (!inode->i_sb->u.ext_sb.s_imap[1])
+ return 0;
+ lock_super (inode->i_sb);
+ efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_imap[1]->b_data) +
+ (((unsigned long) inode->i_sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK;
+ if (efi->count) {
+ j = efi->free[--efi->count];
+ inode->i_sb->u.ext_sb.s_imap[1]->b_dirt = 1;
+ } else {
+#ifdef EXTFS_DEBUG
+printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
+#endif
+ j = (unsigned long) inode->i_sb->u.ext_sb.s_imap[0];
+ if (efi->next > inode->i_sb->u.ext_sb.s_ninodes) {
+ printk ("efi->next = %d\n", efi->next);
+ panic ("ext_new_inode: bad inode number in free list\n");
+ }
+ inode->i_sb->u.ext_sb.s_imap[0] = (struct buffer_head *) efi->next;
+ block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK;
+ brelse (inode->i_sb->u.ext_sb.s_imap[1]);
+ if (!inode->i_sb->u.ext_sb.s_imap[0]) {
+ inode->i_sb->u.ext_sb.s_imap[1] = NULL;
+ } else {
+ if (!(inode->i_sb->u.ext_sb.s_imap[1] = bread (dev, block, inode->i_sb->s_blocksize)))
+ panic ("ext_new_inode: unable to read next free inode block\n");
+ }
+ }
+ inode->i_sb->u.ext_sb.s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->u.ext_sb.s_imap[2]) - 1);
+ inode->i_sb->s_dirt = 1;
+ inode->i_count = 1;
+ inode->i_nlink = 1;
+ inode->i_dev = dev;
+ inode->i_uid = current->euid;
+ inode->i_gid = current->egid;
+ inode->i_dirt = 1;
+ inode->i_ino = j;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = NULL;
+#ifdef EXTFS_DEBUG
+printk("ext_new_inode : allocating inode %d\n", inode->i_ino);
+#endif
+ free_super (inode->i_sb);
+ return inode;
+}
+
+unsigned long ext_count_free_inodes(struct super_block *sb)
+{
+#ifdef EXTFS_DEBUG
+ struct buffer_head * bh;
+ struct ext_free_inode * efi;
+ unsigned long count, block, ino;
+
+ lock_super (sb);
+ if (!sb->u.ext_sb.s_imap[1])
+ count = 0;
+ else {
+ efi = ((struct ext_free_inode *) sb->u.ext_sb.s_imap[1]->b_data) +
+ ((((unsigned long) sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK);
+ count = efi->count + 1;
+ ino = efi->next;
+ while (ino) {
+ if (ino < 1 || ino > sb->u.ext_sb.s_ninodes) {
+ printk ("u.ext_sb.s_imap[0] = %d, ino = %d\n",
+ (int) sb->u.ext_sb.s_imap[0],ino);
+ panic ("ext_count_fre_inodes: bad inode number in free list\n");
+ }
+ block = 2 + ((ino - 1) / EXT_INODES_PER_BLOCK);
+ if (!(bh = bread (sb->s_dev, block, sb->s_blocksize))) {
+ printk ("ext_count_free_inodes: error while reading free inodes list\n");
+ block = 0;
+ } else {
+ efi = ((struct ext_free_inode *) bh->b_data) +
+ ((ino - 1) % EXT_INODES_PER_BLOCK);
+ count += efi->count + 1;
+ ino = efi->next;
+ brelse (bh);
+ }
+ }
+ }
+printk("ext_count_free_inodes: stored = %d, computed = %d\n",
+ (unsigned long) sb->u.ext_sb.s_imap[2], count);
+ free_super (sb);
+ return count;
+#else
+ return (unsigned long) sb->u.ext_sb.s_imap[2];
+#endif
+}
+
+#endif
--- /dev/null
+/*
+ * linux/fs/ext/inode.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+int sync_dev(int dev);
+
+void ext_put_inode(struct inode *inode)
+{
+ inode->i_size = 0;
+ ext_truncate(inode);
+ ext_free_inode(inode);
+}
+
+void ext_put_super(struct super_block *sb)
+{
+#ifdef EXTFS_BITMAP
+ int i;
+#endif
+
+ lock_super(sb);
+ sb->s_dev = 0;
+#ifdef EXTFS_BITMAP
+ for(i = 0 ; i < EXT_I_MAP_SLOTS ; i++)
+ brelse(sb->u.ext_sb.s_imap[i]);
+ for(i = 0 ; i < EXT_Z_MAP_SLOTS ; i++)
+ brelse(sb->u.ext_sb.s_zmap[i]);
+#endif
+#ifdef EXTFS_FREELIST
+ if (sb->u.ext_sb.s_imap[1])
+ brelse (sb->u.ext_sb.s_imap[1]);
+ if (sb->u.ext_sb.s_zmap[1])
+ brelse (sb->u.ext_sb.s_zmap[1]);
+#endif
+ free_super(sb);
+ return;
+}
+
+static struct super_operations ext_sops = {
+ ext_read_inode,
+ ext_write_inode,
+ ext_put_inode,
+ ext_put_super,
+ ext_write_super,
+ ext_statfs
+};
+
+struct super_block *ext_read_super(struct super_block *s,void *data)
+{
+ struct buffer_head *bh;
+ struct ext_super_block *es;
+ int dev = s->s_dev,block;
+#ifdef EXTFS_BITMAP
+ int i;
+#endif
+
+ lock_super(s);
+ if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
+ s->s_dev=0;
+ free_super(s);
+ printk("bread failed\n");
+ return NULL;
+ }
+/* *((struct ext_super_block *) s) =
+ *((struct ext_super_block *) bh->b_data); */
+ es = (struct ext_super_block *) bh->b_data;
+ s->s_blocksize = 1024;
+ s->u.ext_sb.s_ninodes = es->s_ninodes;
+ s->u.ext_sb.s_nzones = es->s_nzones;
+#ifdef EXTFS_BITMAP
+ s->u.ext_sb.s_imap_blocks = es->s_imap_blocks;
+ s->u.ext_sb.s_zmap_blocks = es->s_zmap_blocks;
+#endif
+ s->u.ext_sb.s_firstdatazone = es->s_firstdatazone;
+ s->u.ext_sb.s_log_zone_size = es->s_log_zone_size;
+ s->u.ext_sb.s_max_size = es->s_max_size;
+ s->s_magic = es->s_magic;
+#ifdef EXTFS_FREELIST
+ s->u.ext_sb.s_zmap[0] = (struct buffer_head *) es->s_firstfreeblock;
+ s->u.ext_sb.s_zmap[2] = (struct buffer_head *) es->s_freeblockscount;
+ s->u.ext_sb.s_imap[0] = (struct buffer_head *) es->s_firstfreeinode;
+ s->u.ext_sb.s_imap[2] = (struct buffer_head *) es->s_freeinodescount;
+#endif
+ brelse(bh);
+ if (s->s_magic != EXT_SUPER_MAGIC) {
+ s->s_dev = 0;
+ free_super(s);
+ printk("magic match failed\n");
+ return NULL;
+ }
+#ifdef EXTFS_BITMAP
+ for (i=0;i < EXT_I_MAP_SLOTS;i++)
+ s->u.ext_sb.s_imap[i] = NULL;
+ for (i=0;i < EXT_Z_MAP_SLOTS;i++)
+ s->u.ext_sb.s_zmap[i] = NULL;
+ block=2;
+ for (i=0 ; i < s->u.ext_sb.s_imap_blocks ; i++)
+ if (s->u.ext_sb.s_imap[i]=bread(dev, block, BLOCK_SIZE))
+ block++;
+ else
+ break;
+ for (i=0 ; i < s->u.ext_sb.s_zmap_blocks ; i++)
+ if (s->u.ext_sb.s_zmap[i]=bread(dev, block, BLOCK_SIZE))
+ block++;
+ else
+ break;
+ if (block != 2+s->u.ext_sb.s_imap_blocks+s->u.ext_sb.s_zmap_blocks) {
+ for(i=0;i<EXT_I_MAP_SLOTS;i++)
+ brelse(s->u.ext_sb.s_imap[i]);
+ for(i=0;i<EXT_Z_MAP_SLOTS;i++)
+ brelse(s->u.ext_sb.s_zmap[i]);
+ s->s_dev=0;
+ free_super(s);
+ printk("block failed\n");
+ return NULL;
+ }
+ s->u.ext_sb.s_imap[0]->b_data[0] |= 1;
+ s->u.ext_sb.s_zmap[0]->b_data[0] |= 1;
+#endif
+#ifdef EXTFS_FREELIST
+ if (!s->u.ext_sb.s_zmap[0])
+ s->u.ext_sb.s_zmap[1] = NULL;
+ else
+ if (!(s->u.ext_sb.s_zmap[1] = bread(dev, (unsigned long) s->u.ext_sb.s_zmap[0], BLOCK_SIZE))) {
+ printk ("ext_read_super: unable to read first free block\n");
+ s->s_dev = 0;
+ free_super(s);
+ return NULL;
+ }
+ if (!s->u.ext_sb.s_imap[0])
+ s->u.ext_sb.s_imap[1] = NULL;
+ else {
+ block = 2 + (((unsigned long) s->u.ext_sb.s_imap[0]) - 1) / EXT_INODES_PER_BLOCK;
+ if (!(s->u.ext_sb.s_imap[1] = bread(dev, block, BLOCK_SIZE))) {
+ printk ("ext_read_super: unable to read first free inode block\n");
+ brelse(s->u.ext_sb.s_zmap[1]);
+ s->s_dev = 0;
+ free_super (s);
+ return NULL;
+ }
+ }
+#endif
+
+ free_super(s);
+ /* set up enough so that it can read an inode */
+ s->s_dev = dev;
+ s->s_op = &ext_sops;
+ if (!(s->s_mounted = iget(dev,EXT_ROOT_INO))) {
+ s->s_dev=0;
+ printk("get root inode failed\n");
+ return NULL;
+ }
+ return s;
+}
+
+void ext_write_super (struct super_block *sb)
+{
+#ifdef EXTFS_FREELIST
+ struct buffer_head * bh;
+ struct ext_super_block * es;
+
+#ifdef EXTFS_DEBUG
+ printk ("ext_write_super called\n");
+#endif
+ if (!(bh = bread(sb->s_dev, 1, BLOCK_SIZE))) {
+ printk ("ext_write_super: bread failed\n");
+ return;
+ }
+ es = (struct ext_super_block *) bh->b_data;
+ es->s_firstfreeblock = (unsigned long) sb->u.ext_sb.s_zmap[0];
+ es->s_freeblockscount = (unsigned long) sb->u.ext_sb.s_zmap[2];
+ es->s_firstfreeinode = (unsigned long) sb->u.ext_sb.s_imap[0];
+ es->s_freeinodescount = (unsigned long) sb->u.ext_sb.s_imap[2];
+ bh->b_dirt = 1;
+ brelse (bh);
+ sb->s_dirt = 0;
+#endif
+}
+
+void ext_statfs (struct super_block *sb, struct statfs *buf)
+{
+ long tmp;
+
+ put_fs_long(EXT_SUPER_MAGIC, &buf->f_type);
+ put_fs_long(1024, &buf->f_bsize);
+ put_fs_long(sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size, &buf->f_blocks);
+ tmp = ext_count_free_blocks(sb);
+ put_fs_long(tmp, &buf->f_bfree);
+ put_fs_long(tmp, &buf->f_bavail);
+ put_fs_long(sb->u.ext_sb.s_ninodes, &buf->f_files);
+ put_fs_long(ext_count_free_inodes(sb), &buf->f_ffree);
+ /* Don't know what value to put in buf->f_fsid */
+}
+
+static int _ext_bmap(struct inode * inode,int block,int create)
+{
+ struct buffer_head * bh;
+ int i;
+
+ if (block<0) {
+ printk("_ext_bmap: block<0");
+ return 0;
+ }
+ if (block >= 9+256+256*256+256*256*256) {
+ printk("_ext_bmap: block>big");
+ return 0;
+ }
+ if (block<9) {
+ if (create && !inode->i_data[block])
+ if (inode->i_data[block]=ext_new_block(inode->i_dev)) {
+ inode->i_ctime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
+ return inode->i_data[block];
+ }
+ block -= 9;
+ if (block<256) {
+ if (create && !inode->i_data[9])
+ if (inode->i_data[9]=ext_new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_data[9])
+ return 0;
+ if (!(bh = bread(inode->i_dev, inode->i_data[9], BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *) (bh->b_data))[block];
+ if (create && !i)
+ if (i=ext_new_block(inode->i_dev)) {
+ ((unsigned long *) (bh->b_data))[block]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+ }
+ block -= 256;
+ if (block<256*256) {
+ if (create && !inode->i_data[10])
+ if (inode->i_data[10]=ext_new_block(inode->i_dev)) {
+ inode->i_dirt=1;
+ inode->i_ctime=CURRENT_TIME;
+ }
+ if (!inode->i_data[10])
+ return 0;
+ if (!(bh=bread(inode->i_dev, inode->i_data[10], BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *)bh->b_data)[block>>8];
+ if (create && !i)
+ if (i=ext_new_block(inode->i_dev)) {
+ ((unsigned long *) (bh->b_data))[block>>8]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ if (!i)
+ return 0;
+ if (!(bh=bread(inode->i_dev, i, BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *)bh->b_data)[block&255];
+ if (create && !i)
+ if (i=ext_new_block(inode->i_dev)) {
+ ((unsigned long *) (bh->b_data))[block&255]=i;
+ bh->b_dirt=1;
+ }
+ brelse(bh);
+ return i;
+ }
+ if (create && !inode->i_data[11])
+ if (inode->i_data[11] = ext_new_block(inode->i_dev)) {
+ inode->i_dirt = 1;
+ inode->i_ctime = CURRENT_TIME;
+ }
+ if (!inode->i_data[11])
+ return 0;
+ if (!(bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *) bh->b_data)[block >> 16];
+ if (create && !i)
+ if (i = ext_new_block(inode->i_dev)) {
+ ((unsigned long *) bh->b_data)[block >> 16] = i;
+ bh->b_dirt = 1;
+ }
+ brelse (bh);
+ if (!i)
+ return 0;
+ if (!(bh = bread(inode->i_dev, i, BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *) bh->b_data)[(block >> 8) & 255];
+ if (create && !i)
+ if (i = ext_new_block(inode->i_dev)) {
+ ((unsigned long *) bh->b_data)[(block >> 8) & 255] = i;
+ bh->b_dirt = 1;
+ }
+ brelse (bh);
+ if (!i)
+ return 0;
+ if (!(bh = bread(inode->i_dev, i, BLOCK_SIZE)))
+ return 0;
+ i = ((unsigned long *) bh->b_data)[block & 255];
+ if (create && !i)
+ if (i = ext_new_block(inode->i_dev)) {
+ ((unsigned long *) bh->b_data)[block & 255] = i;
+ bh->b_dirt = 1;
+ }
+ brelse (bh);
+ return i;
+
+ printk("ext_bmap: triple indirection not yet implemented\n");
+ return 0;
+}
+
+int ext_bmap(struct inode * inode,int block)
+{
+ return _ext_bmap(inode,block,0);
+}
+
+int ext_create_block(struct inode * inode, int block)
+{
+ return _ext_bmap(inode,block,1);
+}
+
+void ext_read_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct ext_inode * raw_inode;
+ int block;
+
+#ifdef EXTFS_BITMAP
+ block = 2 + inode->i_sb->u.ext_sb.s_imap_blocks + inode->i_sb->u.ext_sb.s_zmap_blocks +
+ (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
+#endif
+#ifdef EXTFS_FREELIST
+ block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
+#endif
+ if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
+ panic("unable to read i-node block");
+ raw_inode = ((struct ext_inode *) bh->b_data) +
+ (inode->i_ino-1)%EXT_INODES_PER_BLOCK;
+ inode->i_mode = raw_inode->i_mode;
+ inode->i_uid = raw_inode->i_uid;
+ inode->i_gid = raw_inode->i_gid;
+ inode->i_nlink = raw_inode->i_nlinks;
+ inode->i_size = raw_inode->i_size;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = raw_inode->i_zone[0];
+ else for (block = 0; block < 12; block++)
+ inode->i_data[block] = raw_inode->i_zone[block];
+ brelse(bh);
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &ext_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &ext_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &ext_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &ext_chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &ext_blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode)) {
+ inode->i_op = &ext_fifo_inode_operations;
+ inode->i_size = 0;
+ inode->i_pipe = 1;
+ PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+ }
+}
+
+void ext_write_inode(struct inode * inode)
+{
+ struct buffer_head * bh;
+ struct ext_inode * raw_inode;
+ int block;
+
+#ifdef EXTFS_BITMAP
+ block = 2 + inode->i_sb->u.ext_sb.s_imap_blocks + inode->i_sb->u.ext_sb.s_zmap_blocks +
+ (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
+#endif
+#ifdef EXTFS_FREELIST
+ block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
+#endif
+ if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
+ panic("unable to read i-node block");
+ raw_inode = ((struct ext_inode *)bh->b_data) +
+ (inode->i_ino-1)%EXT_INODES_PER_BLOCK;
+ raw_inode->i_mode = inode->i_mode;
+ raw_inode->i_uid = inode->i_uid;
+ raw_inode->i_gid = inode->i_gid;
+ raw_inode->i_nlinks = inode->i_nlink;
+ raw_inode->i_size = inode->i_size;
+ raw_inode->i_time = inode->i_mtime;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ raw_inode->i_zone[0] = inode->i_rdev;
+ else for (block = 0; block < 12; block++)
+ raw_inode->i_zone[block] = inode->i_data[block];
+ bh->b_dirt=1;
+ inode->i_dirt=0;
+ brelse(bh);
+}
--- /dev/null
+/*
+ * linux/fs/ext/namei.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/namei.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+#include <asm/segment.h>
+
+#include <const.h>
+
+/*
+ * comment out this line if you want names > EXT_NAME_LEN chars to be
+ * truncated. Else they will be disallowed.
+ */
+/* #define NO_TRUNCATE */
+
+/*
+ * EXT_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a power of 2 and must be greater or equal than 8
+ * because a directory entry needs 8 bytes for its fixed part
+ * (4 bytes for the inode, 2 bytes for the entry length and 2 bytes
+ * for the name length)
+ */
+#define EXT_DIR_PAD 8
+
+/*
+ *
+ * EXT_DIR_MIN_SIZE is the minimal size of a directory entry
+ *
+ * During allocations, a directory entry is split into 2 ones
+ * *ONLY* if the size of the unused part is greater than or
+ * equal to EXT_DIR_MIN_SIZE
+ */
+#define EXT_DIR_MIN_SIZE 12
+
+/*
+ * ok, we cannot use strncmp, as the name is not in our data space.
+ * Thus we'll have to use ext_match. No big problem. Match also makes
+ * some sanity tests.
+ *
+ * NOTE! unlike strncmp, ext_match returns 1 for success, 0 for failure.
+ */
+static int ext_match(int len,const char * name,struct ext_dir_entry * de)
+{
+ register int same __asm__("ax");
+
+ if (!de || !de->inode || len > EXT_NAME_LEN)
+ return 0;
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+ if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
+ return 1;
+/* if (len < EXT_NAME_LEN && de->name[len])
+ return 0; */
+ if (len < EXT_NAME_LEN && len != de->name_len)
+ return 0;
+ __asm__("cld\n\t"
+ "fs ; repe ; cmpsb\n\t"
+ "setz %%al"
+ :"=a" (same)
+ :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
+ :"cx","di","si");
+ return same;
+}
+
+/*
+ * ext_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ *
+ * addition for the ext file system : this function returns the previous
+ * and next directory entries in the parameters prev_dir and next_dir
+ */
+static struct buffer_head * ext_find_entry(struct inode * dir,
+ const char * name, int namelen, struct ext_dir_entry ** res_dir,
+ struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
+{
+/* int entries; */
+ int block /* ,i */;
+ long offset;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de;
+
+ *res_dir = NULL;
+ if (!dir)
+ return NULL;
+#ifdef NO_TRUNCATE
+ if (namelen > EXT_NAME_LEN)
+ return NULL;
+#else
+ if (namelen > EXT_NAME_LEN)
+ namelen = EXT_NAME_LEN;
+#endif
+/* entries = dir->i_size / (sizeof (struct ext_dir_entry)); */
+ if (!(block = dir->i_data[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
+ return NULL;
+ if (prev_dir)
+ *prev_dir = NULL;
+ if (next_dir)
+ *next_dir = NULL;
+/* i = 0; */
+ offset = 0;
+ de = (struct ext_dir_entry *) bh->b_data;
+ while (offset < dir->i_size) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data) {
+ brelse(bh);
+ bh = NULL;
+ if (!(block = ext_bmap(dir,offset>>BLOCK_SIZE_BITS)) ||
+ !(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
+/* i += EXT_DIR_ENTRIES_PER_BLOCK; */
+/* offset += BLOCK_SIZE; */
+ continue;
+ }
+ de = (struct ext_dir_entry *) bh->b_data;
+ if (prev_dir)
+ *prev_dir = NULL;
+ }
+ if (ext_match(namelen,name,de)) {
+ *res_dir = de;
+ if (next_dir)
+ if (offset + de->rec_len < dir->i_size)
+ *next_dir = (struct ext_dir_entry *)
+ ((char *) de + de->rec_len);
+ else
+ *next_dir = NULL;
+ return bh;
+ }
+ offset += de->rec_len;
+ if (prev_dir)
+ *prev_dir = de;
+ de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+/* i++; */
+ }
+ brelse(bh);
+ return NULL;
+}
+
+int ext_lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ int ino;
+ struct ext_dir_entry * de;
+ struct buffer_head * bh;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
+ iput(dir);
+ return -ENOENT;
+ }
+ ino = de->inode;
+ brelse(bh);
+ if (!(*result = iget(dir->i_dev,ino))) {
+ iput(dir);
+ return -EACCES;
+ }
+ iput(dir);
+ return 0;
+}
+
+/*
+ * ext_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ext_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * ext_add_entry(struct inode * dir,
+ const char * name, int namelen, struct ext_dir_entry ** res_dir)
+{
+ int block,i;
+ long offset;
+ unsigned short rec_len;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de, * de1;
+
+ *res_dir = NULL;
+ if (!dir)
+ return NULL;
+#ifdef NO_TRUNCATE
+ if (namelen > EXT_NAME_LEN)
+ return NULL;
+#else
+ if (namelen > EXT_NAME_LEN)
+ namelen = EXT_NAME_LEN;
+#endif
+ if (!namelen)
+ return NULL;
+ if (!(block = dir->i_data[0]))
+ return NULL;
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
+ return NULL;
+ rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
+/* i = 0; */
+ offset = 0;
+ de = (struct ext_dir_entry *) bh->b_data;
+ while (1) {
+ if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
+#ifdef EXTFS_DEBUG
+printk ("ext_add_entry: skipping to next block\n");
+#endif
+ brelse(bh);
+ bh = NULL;
+ block = ext_create_block(dir,offset>>BLOCK_SIZE_BITS);
+ if (!block)
+ return NULL;
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
+/* i += EXT_DIR_ENTRIES_PER_BLOCK; */
+ offset += BLOCK_SIZE;
+ continue;
+ }
+ de = (struct ext_dir_entry *) bh->b_data;
+ }
+ if (offset >= dir->i_size) {
+ /* Check that the directory entry fits in the block */
+ if (offset % BLOCK_SIZE == 0
+ || (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
+ if ((offset % BLOCK_SIZE) != 0) {
+ /* If the entry does not fit in the
+ block, the remainder of the block
+ becomes an unused entry */
+ de->inode = 0;
+ de->rec_len = BLOCK_SIZE
+ - (offset & (BLOCK_SIZE - 1));
+ de->name_len = 0;
+ offset += de->rec_len;
+ dir->i_size += de->rec_len;
+ dir->i_dirt = 1;
+ dir->i_ctime = CURRENT_TIME;
+ bh->b_dirt = 1;
+ }
+ brelse (bh);
+ bh = NULL;
+ block = ext_create_block (dir,offset>>BLOCK_SIZE_BITS);
+#ifdef EXTFS_DEBUG
+printk ("ext_add_entry : creating next block\n");
+#endif
+ if (!block)
+ return NULL;
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
+ return NULL; /* Other thing to do ??? */
+ de = (struct ext_dir_entry *) bh->b_data;
+ }
+ /* Allocate the entry */
+ de->inode=0;
+ de->rec_len = rec_len;
+/* dir->i_size = (i+1)*sizeof(struct ext_dir_entry); */
+ dir->i_size += de->rec_len;
+ dir->i_dirt = 1;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ if (!de->inode && de->rec_len >= rec_len) {
+ if (de->rec_len > rec_len
+ && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
+ /* The found entry is too big : it is split
+ into 2 ones :
+ - the 1st one will be used to hold the name,
+ - the 2nd one is unused */
+ de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
+ de1->inode = 0;
+ de1->rec_len = de->rec_len - rec_len;
+ de1->name_len = 0;
+ de->rec_len = rec_len;
+ }
+ dir->i_mtime = CURRENT_TIME;
+ de->name_len = namelen;
+ for (i=0; i < namelen ; i++)
+ de->name[i]=/*(i<namelen)?*/get_fs_byte(name+i)/*:0*/;
+ bh->b_dirt = 1;
+ *res_dir = de;
+ return bh;
+ }
+ offset += de->rec_len;
+ de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+ }
+ brelse(bh);
+ return NULL;
+}
+
+int ext_create(struct inode * dir,const char * name, int len, int mode,
+ struct inode ** result)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de;
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+ inode = ext_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &ext_file_inode_operations;
+ inode->i_mode = mode;
+ inode->i_dirt = 1;
+ bh = ext_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ *result = inode;
+ return 0;
+}
+
+int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+{
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de;
+
+ if (!dir)
+ return -ENOENT;
+ bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = ext_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_uid = current->euid;
+ inode->i_mode = mode;
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &ext_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &ext_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &ext_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &ext_chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &ext_blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode)) {
+ inode->i_op = &ext_fifo_inode_operations;
+ inode->i_size = 0;
+ inode->i_pipe = 1;
+ PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+ }
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_rdev = rdev;
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ bh = ext_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
+{
+ struct inode * inode;
+ struct buffer_head * bh, *dir_block;
+ struct ext_dir_entry * de;
+
+ bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = ext_new_inode(dir->i_dev);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &ext_dir_inode_operations;
+ inode->i_size = 2 * 16; /* Each entry is coded on 16 bytes for "." and ".."
+ - 4 bytes for the inode number,
+ - 2 bytes for the record length
+ - 2 bytes for the name length
+ - 8 bytes for the name */
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ if (!(inode->i_data[0] = ext_new_block(inode->i_dev))) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->i_dirt = 1;
+ if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -EIO;
+ }
+ de = (struct ext_dir_entry *) dir_block->b_data;
+ de->inode=inode->i_ino;
+ de->rec_len=16;
+ de->name_len=1;
+ strcpy(de->name,".");
+/* de++; */
+ de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+ de->inode = dir->i_ino;
+ de->rec_len=16;
+ de->name_len=2;
+ strcpy(de->name,"..");
+ inode->i_nlink = 2;
+ dir_block->b_dirt = 1;
+ brelse(dir_block);
+ inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
+ inode->i_dirt = 1;
+ bh = ext_add_entry(dir,name,len,&de);
+ if (!bh) {
+ iput(dir);
+ inode->i_nlink=0;
+ iput(inode);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ dir->i_nlink++;
+ dir->i_dirt = 1;
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return 0;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir(struct inode * inode)
+{
+ int /* nr, */ block;
+/* int len; */
+ unsigned long offset;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de, * de1;
+
+/* len = inode->i_size / sizeof (struct ext_dir_entry); */
+ if (inode->i_size < 2 * 12 || !inode->i_data[0] ||
+ !(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+ de = (struct ext_dir_entry *) bh->b_data;
+ de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+ if (de->inode != inode->i_ino || !de1->inode ||
+ strcmp(".",de->name) || strcmp("..",de1->name)) {
+ printk("warning - bad directory on dev %04x\n",inode->i_dev);
+ return 0;
+ }
+/* nr = 2; */
+ offset = de->rec_len + de1->rec_len;
+ de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
+ while (offset < inode->i_size ) {
+ if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
+ brelse(bh);
+ block = ext_bmap(inode, offset >> BLOCK_SIZE_BITS);
+ if (!block) {
+ offset += BLOCK_SIZE;
+ continue;
+ }
+ if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
+ return 0;
+ de = (struct ext_dir_entry *) bh->b_data;
+ }
+ if (de->inode) {
+ brelse(bh);
+ return 0;
+ }
+ offset += de->rec_len;
+ de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
+ }
+ brelse(bh);
+ return 1;
+}
+
+static inline void ext_merge_entries (struct ext_dir_entry * de,
+ struct ext_dir_entry * pde, struct ext_dir_entry * nde)
+{
+ if (! nde->inode)
+ de->rec_len += nde->rec_len;
+ if (! pde->inode)
+ pde->rec_len += de->rec_len;
+}
+
+int ext_rmdir(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de, * pde, * nde;
+
+ inode = NULL;
+ bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
+ retval = -ENOENT;
+ if (!bh)
+ goto end_rmdir;
+ retval = -EPERM;
+ if (!(inode = iget(dir->i_dev, de->inode)))
+ goto end_rmdir;
+ if ((dir->i_mode & S_ISVTX) && current->euid &&
+ inode->i_uid != current->euid)
+ goto end_rmdir;
+ if (inode->i_dev != dir->i_dev)
+ goto end_rmdir;
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
+ goto end_rmdir;
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = -ENOTDIR;
+ goto end_rmdir;
+ }
+ if (!empty_dir(inode)) {
+ retval = -ENOTEMPTY;
+ goto end_rmdir;
+ }
+ if (inode->i_count > 1) {
+ retval = -EBUSY;
+ goto end_rmdir;
+ }
+ if (inode->i_nlink != 2)
+ printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
+ de->inode = 0;
+ de->name_len = 0;
+ ext_merge_entries (de, pde, nde);
+ bh->b_dirt = 1;
+ inode->i_nlink=0;
+ inode->i_dirt=1;
+ dir->i_nlink--;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_dirt=1;
+ retval = 0;
+end_rmdir:
+ iput(dir);
+ iput(inode);
+ brelse(bh);
+ return retval;
+}
+
+int ext_unlink(struct inode * dir, const char * name, int len)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext_dir_entry * de, * pde, * nde;
+
+ retval = -ENOENT;
+ inode = NULL;
+ bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
+ if (!bh)
+ goto end_unlink;
+ if (!(inode = iget(dir->i_dev, de->inode)))
+ goto end_unlink;
+ retval = -EPERM;
+ if ((dir->i_mode & S_ISVTX) && !suser() &&
+ current->euid != inode->i_uid &&
+ current->euid != dir->i_uid)
+ goto end_unlink;
+ if (S_ISDIR(inode->i_mode))
+ goto end_unlink;
+ if (!inode->i_nlink) {
+ printk("Deleting nonexistent file (%04x:%d), %d\n",
+ inode->i_dev,inode->i_ino,inode->i_nlink);
+ inode->i_nlink=1;
+ }
+ de->inode = 0;
+ de->name_len = 0;
+ ext_merge_entries (de, pde, nde);
+ bh->b_dirt = 1;
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ inode->i_ctime = CURRENT_TIME;
+ retval = 0;
+end_unlink:
+ brelse(bh);
+ iput(inode);
+ iput(dir);
+ return retval;
+}
+
+int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
+{
+ struct ext_dir_entry * de;
+ struct inode * inode = NULL;
+ struct buffer_head * bh = NULL, * name_block = NULL;
+ int i;
+ char c;
+
+ if (!(inode = ext_new_inode(dir->i_dev))) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_mode = S_IFLNK | 0777;
+ inode->i_op = &ext_symlink_inode_operations;
+ if (!(inode->i_data[0] = ext_new_block(inode->i_dev))) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->i_dirt = 1;
+ if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
+ iput(dir);
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -EIO;
+ }
+ i = 0;
+ while (i < 1023 && (c=get_fs_byte(symname++)))
+ name_block->b_data[i++] = c;
+ name_block->b_data[i] = 0;
+ name_block->b_dirt = 1;
+ brelse(name_block);
+ inode->i_size = i;
+ inode->i_dirt = 1;
+ bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
+ if (bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ bh = ext_add_entry(dir,name,len,&de);
+ if (!bh) {
+ inode->i_nlink--;
+ inode->i_dirt = 1;
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ de->inode = inode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return 0;
+}
+
+int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+{
+ struct ext_dir_entry * de;
+ struct buffer_head * bh;
+
+ if (S_ISDIR(oldinode->i_mode)) {
+ iput(oldinode);
+ iput(dir);
+ return -EPERM;
+ }
+ bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
+ if (bh) {
+ brelse(bh);
+ iput(dir);
+ iput(oldinode);
+ return -EEXIST;
+ }
+ bh = ext_add_entry(dir,name,len,&de);
+ if (!bh) {
+ iput(dir);
+ iput(oldinode);
+ return -ENOSPC;
+ }
+ de->inode = oldinode->i_ino;
+ bh->b_dirt = 1;
+ brelse(bh);
+ iput(dir);
+ oldinode->i_nlink++;
+ oldinode->i_ctime = CURRENT_TIME;
+ oldinode->i_dirt = 1;
+ iput(oldinode);
+ return 0;
+}
+
+static int subdir(struct inode * new, struct inode * old)
+{
+ unsigned short fs;
+ int ino;
+ int result;
+
+ __asm__("mov %%fs,%0":"=r" (fs));
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ new->i_count++;
+ result = 0;
+ for (;;) {
+ if (new == old) {
+ result = 1;
+ break;
+ }
+ if (new->i_dev != old->i_dev)
+ break;
+ ino = new->i_ino;
+ if (ext_lookup(new,"..",2,&new))
+ break;
+ if (new->i_ino == ino)
+ break;
+ }
+ iput(new);
+ __asm__("mov %0,%%fs"::"r" (fs));
+ return result;
+}
+
+#define PARENT_INO(buffer) \
+((struct ext_dir_entry *) ((char *) buffer + \
+((struct ext_dir_entry *) buffer)->rec_len))->inode
+/* (((struct ext_dir_entry *) (buffer))[1].inode) */
+
+#define PARENT_NAME(buffer) \
+((struct ext_dir_entry *) ((char *) buffer + \
+((struct ext_dir_entry *) buffer)->rec_len))->name
+/* (((struct ext_dir_entry *) (buffer))[1].name) */
+
+/*
+ * rename uses retrying to avoid race-conditions: at least they should be minimal.
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
+ * checks fail, it tries to restart itself again. Very practical - no changes
+ * are done until we know everything works ok.. and then all the changes can be
+ * done in one fell swoop when we have claimed all the buffers needed.
+ *
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct ext_dir_entry * old_de, * new_de, * pde, * nde;
+ int retval;
+
+ goto start_up;
+try_again:
+ brelse(old_bh);
+ brelse(new_bh);
+ brelse(dir_bh);
+ iput(old_inode);
+ iput(new_inode);
+ current->counter = 0;
+ schedule();
+start_up:
+ old_inode = new_inode = NULL;
+ old_bh = new_bh = dir_bh = NULL;
+ old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
+ retval = -ENOENT;
+ if (!old_bh)
+ goto end_rename;
+ 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 = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
+ if (new_bh) {
+ new_inode = iget(new_dir->i_dev, new_de->inode);
+ if (!new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ }
+ if (new_inode == old_inode) {
+ retval = 0;
+ goto end_rename;
+ }
+ if (S_ISDIR(new_inode->i_mode)) {
+ retval = -EEXIST;
+ goto end_rename;
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ retval = -EEXIST;
+ if (new_bh)
+ goto end_rename;
+ retval = -EACCES;
+ if (!permission(old_inode, MAY_WRITE))
+ goto end_rename;
+ retval = -EINVAL;
+ if (subdir(new_dir, old_inode))
+ goto end_rename;
+ retval = -EIO;
+ if (!old_inode->i_data[0])
+ goto end_rename;
+ if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE)))
+ goto end_rename;
+ if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
+ goto end_rename;
+ }
+ if (!new_bh)
+ new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
+ retval = -ENOSPC;
+ if (!new_bh)
+ goto end_rename;
+/* sanity checking before doing the rename - avoid races */
+ if (new_inode && (new_de->inode != new_inode->i_ino))
+ goto try_again;
+ if (new_de->inode && !new_inode)
+ goto try_again;
+ if (old_de->inode != old_inode->i_ino)
+ goto try_again;
+/* ok, that's it */
+ old_de->inode = 0;
+ old_de->name_len = 0;
+ new_de->inode = old_inode->i_ino;
+ ext_merge_entries (old_de, pde, nde);
+ 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) {
+ PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
+ dir_bh->b_dirt = 1;
+ old_dir->i_nlink--;
+ new_dir->i_nlink++;
+ old_dir->i_dirt = 1;
+ new_dir->i_dirt = 1;
+ }
+ retval = 0;
+end_rename:
+ brelse(dir_bh);
+ brelse(old_bh);
+ brelse(new_bh);
+ iput(old_inode);
+ iput(new_inode);
+ iput(old_dir);
+ iput(new_dir);
+ return retval;
+}
+
+/*
+ * Ok, rename also locks out other renames, as they can change the parent of
+ * a directory, and we don't want any races. Other races are checked for by
+ * "do_rename()", which restarts if there are inconsistencies.
+ *
+ * Note that there is no race between different filesystems: it's only within
+ * the same device that races occur: many renames can happen at once, as long
+ * as they are on different partitions.
+ */
+int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len)
+{
+ static struct wait_queue * wait = NULL;
+ static int lock = 0;
+ int result;
+
+ while (lock)
+ sleep_on(&wait);
+ lock = 1;
+ result = do_ext_rename(old_dir, old_name, old_len,
+ new_dir, new_name, new_len);
+ lock = 0;
+ wake_up(&wait);
+ return result;
+}
--- /dev/null
+/*
+ * linux/fs/ext/symlink.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/symlink.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext symlink handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/ext_fs.h>
+#include <linux/stat.h>
+
+static int ext_readlink(struct inode *, char *, int);
+static struct inode * ext_follow_link(struct inode *, struct inode *);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ext_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 */
+ ext_readlink, /* readlink */
+ ext_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static struct inode * ext_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], BLOCK_SIZE))) {
+ 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 ext_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], BLOCK_SIZE);
+ 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;
+}
--- /dev/null
+/*
+ * linux/fs/ext/truncate.c
+ *
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ *
+ * from
+ *
+ * linux/fs/minix/truncate.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/ext_fs.h>
+#include <linux/tty.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
+/*
+ * 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)
+{
+ int i;
+ int result = 0;
+#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
+
+repeat:
+ for (i = DIRECT_BLOCK ; i < 9 ; i++) {
+ if (i < DIRECT_BLOCK)
+ goto repeat;
+ if (!inode->i_data[i])
+ continue;
+ result = 1;
+ if (ext_free_block(inode->i_dev,inode->i_data[i]))
+ inode->i_data[i] = 0;
+ }
+ return result;
+}
+
+static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
+{
+ int i;
+ struct buffer_head * bh = NULL;
+ unsigned long * ind;
+ int result = 0;
+#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
+
+ if (*p)
+ bh = bread(inode->i_dev, *p, BLOCK_SIZE);
+ if (!bh)
+ return 0;
+repeat:
+ for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
+ if (i < 0)
+ i = 0;
+ if (i < INDIRECT_BLOCK)
+ goto repeat;
+ ind = i+(unsigned long *) bh->b_data;
+ if (!*ind)
+ continue;
+ result = 1;
+ if (ext_free_block(inode->i_dev,*ind))
+ *ind = 0;
+ }
+ ind = (unsigned long *) bh->b_data;
+ for (i = 0; i < 256; i++)
+ if (*(ind++))
+ break;
+ brelse(bh);
+ if (i >= 256) {
+ result = 1;
+ if (ext_free_block(inode->i_dev,*p))
+ *p = 0;
+ }
+ return result;
+}
+
+static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
+{
+ int i;
+ struct buffer_head * bh = NULL;
+ unsigned long * dind;
+ int result = 0;
+#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
+
+ if (*p)
+ bh = bread(inode->i_dev, *p, BLOCK_SIZE);
+ if (!bh)
+ return 0;
+repeat:
+ for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
+ if (i < 0)
+ i = 0;
+ if (i < DINDIRECT_BLOCK)
+ goto repeat;
+ dind = i+(unsigned long *) bh->b_data;
+ if (!*dind)
+ continue;
+ result |= trunc_indirect(inode,offset+(i<<8),dind);
+ }
+ dind = (unsigned long *) bh->b_data;
+ for (i = 0; i < 256; i++)
+ if (*(dind++))
+ break;
+ brelse(bh);
+ if (i >= 256) {
+ result = 1;
+ if (ext_free_block(inode->i_dev,*p))
+ *p = 0;
+ }
+ return result;
+}
+
+static int trunc_tindirect(struct inode * inode)
+{
+ int i;
+ struct buffer_head * bh = NULL;
+ unsigned long * tind;
+ int result = 0;
+#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
+
+ if (inode->i_data[11])
+ bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE);
+ if (!bh)
+ return 0;
+repeat:
+ for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
+ if (i < 0)
+ i = 0;
+ if (i < TINDIRECT_BLOCK)
+ goto repeat;
+ tind = i+(unsigned long *) bh->b_data;
+ if (!*tind)
+ continue;
+ result |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
+ }
+ tind = (unsigned long *) bh->b_data;
+ for (i = 0; i < 256; i++)
+ if (*(tind++))
+ break;
+ brelse(bh);
+ if (i >= 256) {
+ result = 1;
+ if (ext_free_block(inode->i_dev,inode->i_data[11]))
+ inode->i_data[11] = 0;
+ }
+ return result;
+}
+
+void ext_truncate(struct inode * inode)
+{
+ int flag;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+/* if (inode->i_data[7] & 0xffff0000)
+ printk("BAD! ext inode has 16 high bits set\n"); */
+ while (1) {
+ flag = trunc_direct(inode);
+ flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]);
+ flag |= trunc_dindirect(inode,9+256,(unsigned long *)&inode->i_data[10]);
+ flag |= trunc_tindirect(inode);
+ if (!flag)
+ break;
+ current->counter = 0;
+ schedule();
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
+}
+
+/*
+ * Called when a inode is released. Note that this is different
+ * from ext_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+void ext_release(struct inode * inode, struct file * filp)
+{
+ printk("ext_release not implemented\n");
+}
/*
* linux/fs/fcntl.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/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 <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
extern int sys_close(int fd);
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
+ if (oldfd >= NR_OPEN || !current->filp[oldfd])
+ return -EBADF;
if (newfd == oldfd)
return newfd;
sys_close(newfd);
--- /dev/null
+/*
+ * linux/fs/fifo.c
+ *
+ * written by Paul H. Hargrove
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+
+extern struct file_operations read_pipe_fops;
+extern struct file_operations write_pipe_fops;
+extern struct file_operations rdwr_pipe_fops;
+
+static int fifo_open(struct inode * inode,struct file * filp)
+{
+ int retval = 0;
+ unsigned long page;
+
+ switch( filp->f_mode ) {
+
+ case 1:
+ /*
+ * O_RDONLY
+ * POSIX.1 says that O_NONBLOCK means return with the FIFO
+ * opened, even when there is no process writing the FIFO.
+ */
+ filp->f_op = &read_pipe_fops;
+ PIPE_READERS(*inode)++;
+ if (!(filp->f_flags & O_NONBLOCK))
+ while (!PIPE_WRITERS(*inode)) {
+ if (PIPE_HEAD(*inode) != PIPE_TAIL(*inode))
+ break;
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
+ }
+ if (retval)
+ PIPE_READERS(*inode)--;
+ break;
+
+ case 2:
+ /*
+ * O_WRONLY
+ * POSIX.1 says that O_NONBLOCK means return -1 with
+ * errno=ENXIO when there is no process reading the FIFO.
+ */
+ if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) {
+ retval = -ENXIO;
+ break;
+ }
+ filp->f_op = &write_pipe_fops;
+ PIPE_WRITERS(*inode)++;
+ while (!PIPE_READERS(*inode)) {
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
+ }
+ if (retval)
+ PIPE_WRITERS(*inode)--;
+ break;
+
+ case 3:
+ /*
+ * O_RDWR
+ * POSIX.1 leaves this case "undefined" when O_NONBLOCK is set.
+ * This implementation will NEVER block on a O_RDWR open, since
+ * the process can at least talk to itself.
+ */
+ filp->f_op = &rdwr_pipe_fops;
+ PIPE_WRITERS(*inode) += 1;
+ PIPE_READERS(*inode) += 1;
+ break;
+
+ default:
+ retval = -EINVAL;
+ }
+ if (PIPE_WRITERS(*inode))
+ wake_up(&PIPE_READ_WAIT(*inode));
+ if (PIPE_READERS(*inode))
+ wake_up(&PIPE_WRITE_WAIT(*inode));
+ if (retval || inode->i_size)
+ return retval;
+ page = get_free_page(GFP_KERNEL);
+ if (inode->i_size) {
+ free_page(page);
+ return 0;
+ }
+ if (!page)
+ return -ENOMEM;
+ inode->i_size = page;
+ 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 access mode of the file...
+ */
+struct file_operations def_fifo_fops = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ fifo_open, /* will set read or write pipe_fops */
+ NULL
+};
/*
* linux/fs/file_table.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/fs.h>
+#include <linux/string.h>
struct file file_table[NR_FILE];
+
+struct file * get_empty_filp(void)
+{
+ int i;
+ struct file * f = file_table+0;
+
+ for (i = 0; i++ < NR_FILE; f++)
+ if (!f->f_count) {
+ memset(f,0,sizeof(*f));
+ f->f_count = 1;
+ return f;
+ }
+ return NULL;
+}
/*
* linux/fs/inode.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/string.h>
-#include <sys/stat.h>
-
+#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/string.h>
+
#include <asm/system.h>
struct inode inode_table[NR_INODE]={{0,},};
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);
}
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
- if (inode->i_dirt && !inode->i_pipe)
+ if (inode->i_dirt)
write_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);
- if (--inode->i_count)
- return;
- free_page(inode->i_size);
- inode->i_count=0;
- inode->i_dirt=0;
- inode->i_pipe=0;
- return;
}
- if (!inode->i_dev) {
+repeat:
+ if (inode->i_count>1) {
inode->i_count--;
return;
}
- if (S_ISBLK(inode->i_mode)) {
- sync_dev(inode->i_rdev);
- wait_on_inode(inode);
+ if (inode->i_pipe) {
+ free_page(inode->i_size);
+ inode->i_size = 0;
}
-repeat:
- if (inode->i_count>1) {
+ if (!inode->i_dev) {
inode->i_count--;
return;
}
if (!inode->i_nlink) {
- if (inode->i_op && inode->i_op->put_inode)
- inode->i_op->put_inode(inode);
- return;
+ 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) {
write_inode(inode); /* we can sleep - so do again */
if (!(inode = get_empty_inode()))
return NULL;
- if (!(inode->i_size=get_free_page())) {
+ if (!(inode->i_size = get_free_page(GFP_USER))) {
inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_pipe = 1;
return inode;
}
}
inode->i_dev = dev;
inode->i_ino = nr;
+ inode->i_flags = inode->i_sb->s_flags;
read_inode(inode);
return inode;
}
/*
* linux/fs/ioctl.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/string.h>
-#include <errno.h>
-#include <sys/stat.h>
+#include <asm/segment.h>
#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
+ int block;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
+ if (S_ISREG(filp->f_inode->i_mode) && cmd == BMAP_IOCTL &&
+ filp->f_inode->i_op->bmap) {
+ block = get_fs_long((long *) arg);
+ block = filp->f_inode->i_op->bmap(filp->f_inode,block);
+ put_fs_long(block,(long *) arg);
+ return 0;
+ }
if (filp->f_op && filp->f_op->ioctl)
return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
return -EINVAL;
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-AR =ar
-AS =as
-LD =ld
-CC =gcc -nostdinc -I../../include
-CPP =cpp -nostdinc -I../../include
-
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
.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 fifo.o
minix.o: $(OBJS)
$(LD) -r -o minix.o $(OBJS)
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
- (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
### Dependencies:
-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
-file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.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/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
-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/linux/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/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/sys/stat.h
+bitmap.o : bitmap.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/string.h
+blkdev.o : blkdev.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h
+chrdev.o : chrdev.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h
+dir.o : dir.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/minix_fs.h \
+ /usr/src/linux/include/linux/stat.h
+fifo.o : fifo.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h
+file.o : file.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/stat.h
+inode.o : inode.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h
+namei.o : namei.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/const.h
+symlink.o : symlink.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/stat.h
+truncate.o : truncate.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/minix_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h
/*
- * linux/fs/bitmap.c
+ * linux/fs/minix/bitmap.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
-#include <linux/string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
+#include <linux/string.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
:"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
__res;})
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
+ unsigned numbits)
+{
+ unsigned i, j, end, sum = 0;
+ struct buffer_head *bh;
+
+ for (i=0; (i<numblocks) && numbits; i++) {
+ if (!(bh=map[i]))
+ return(0);
+ if (numbits >= (8*BLOCK_SIZE)) {
+ end = BLOCK_SIZE;
+ numbits -= 8*BLOCK_SIZE;
+ } else {
+ int tmp;
+ end = numbits >> 3;
+ numbits &= 0x7;
+ tmp = bh->b_data[end] & ((1<<numbits)-1);
+ sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf];
+ numbits = 0;
+ }
+ for (j=0; j<end; j++)
+ sum += nibblemap[bh->b_data[j] & 0xf]
+ + nibblemap[(bh->b_data[j]>>4)&0xf];
+ }
+ return(sum);
+}
+
int minix_free_block(int dev, int block)
{
struct super_block * sb;
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
- if (block < sb->s_firstdatazone || block >= sb->s_nzones)
+ if (block < sb->u.minix_sb.s_firstdatazone || block >= sb->u.minix_sb.s_nzones)
panic("trying to free block not in datazone");
- bh = get_hash_table(dev,block);
+ bh = get_hash_table(dev,block,BLOCK_SIZE);
if (bh) {
if (bh->b_count > 1) {
brelse(bh);
if (bh->b_count)
brelse(bh);
}
- zone = block - sb->s_firstdatazone + 1;
+ zone = block - sb->u.minix_sb.s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
- bh = sb->s_zmap[zone];
+ bh = sb->u.minix_sb.s_zmap[zone];
if (clear_bit(bit,bh->b_data))
printk("free_block (%04x:%d): bit already cleared\n",dev,block);
bh->b_dirt = 1;
panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++)
- if (bh=sb->s_zmap[i])
+ if (bh=sb->u.minix_sb.s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
- if (set_bit(j,bh->b_data))
+ if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
bh->b_dirt = 1;
- j += i*8192 + sb->s_firstdatazone-1;
- if (j >= sb->s_nzones)
+ j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
+ if (j >= sb->u.minix_sb.s_nzones)
return 0;
- if (!(bh=getblk(dev,j)))
+ if (!(bh=getblk(dev,j,BLOCK_SIZE)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
return j;
}
+unsigned long minix_count_free_blocks(struct super_block *sb)
+{
+ return (sb->u.minix_sb.s_nzones - count_used(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks,sb->u.minix_sb.s_nzones))
+ << sb->u.minix_sb.s_log_zone_size;
+}
+
void minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
printk("free_inode: inode on nonexistent device\n");
return;
}
- if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
- if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
+ if (!(bh=inode->i_sb->u.minix_sb.s_imap[inode->i_ino>>13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
iput(inode);
return NULL;
}
+ inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
- if (bh=inode->i_sb->s_imap[i])
+ if (bh=inode->i_sb->u.minix_sb.s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
- if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
+ if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
return NULL;
}
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;
}
+
+unsigned long minix_count_free_inodes(struct super_block *sb)
+{
+ return sb->u.minix_sb.s_ninodes - count_used(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks,sb->u.minix_sb.s_ninodes);
+}
--- /dev/null
+/*
+ * linux/fs/minix/blkdev.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+
+/*
+ * Called every time a minix block special file is opened
+ */
+static int blkdev_open(struct inode * inode, struct file * filp)
+{
+ int i;
+
+ 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 */
+};
--- /dev/null
+/*
+ * linux/fs/minix/chrdev.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+#include <linux/stat.h>
+#include <linux/fcntl.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 */
+};
+
--- /dev/null
+/*
+ * linux/fs/minix/dir.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * minix directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+#include <linux/stat.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,BLOCK_SIZE))) {
+ 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;
+}
--- /dev/null
+/*
+ * linux/fs/fifo.c
+ *
+ * written by Paul H. Hargrove
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+
+extern struct file_operations def_fifo_fops;
+
+struct inode_operations minix_fifo_inode_operations = {
+ &def_fifo_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 */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
--- /dev/null
+/*
+ * linux/fs/minix/file.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * minix regular file handling primitives
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.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,BLOCK_SIZE);
+ 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;
+ if (!IS_RDONLY(inode)) {
+ 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, BLOCK_SIZE);
+ else
+ bh = bread(inode->i_dev,block, BLOCK_SIZE);
+ 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;
+ inode->i_ctime = CURRENT_TIME;
+ filp->f_pos = pos;
+ inode->i_dirt = 1;
+ return written;
+}
+++ /dev/null
-/*
- * 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, 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;
-}
-
-int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
-{
- int read,left,chars,nr;
- struct buffer_head * bh;
-
- 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;
- 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;
-
- 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;
-}
/*
* linux/fs/minix/inode.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/string.h>
-#include <sys/stat.h>
-
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
#include <asm/system.h>
+#include <asm/segment.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;
lock_super(sb);
sb->s_dev = 0;
for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
- brelse(sb->s_imap[i]);
+ brelse(sb->u.minix_sb.s_imap[i]);
for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
- brelse(sb->s_zmap[i]);
+ brelse(sb->u.minix_sb.s_zmap[i]);
free_super(sb);
return;
}
static struct super_operations minix_sops = {
minix_read_inode,
- minix_put_super
+ minix_write_inode,
+ minix_put_inode,
+ minix_put_super,
+ NULL,
+ minix_statfs
};
struct super_block *minix_read_super(struct super_block *s,void *data)
{
struct buffer_head *bh;
+ struct minix_super_block *ms;
int i,dev=s->s_dev,block;
lock_super(s);
- if (!(bh = bread(dev,1))) {
+ if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0;
free_super(s);
printk("bread failed\n");
return NULL;
}
- *((struct minix_super_block *) s) =
- *((struct minix_super_block *) bh->b_data);
+ ms = (struct minix_super_block *) bh->b_data;
+ s->s_blocksize = 1024;
+ s->u.minix_sb.s_ninodes = ms->s_ninodes;
+ s->u.minix_sb.s_nzones = ms->s_nzones;
+ s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks;
+ s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks;
+ s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone;
+ s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size;
+ s->u.minix_sb.s_max_size = ms->s_max_size;
+ s->s_magic = ms->s_magic;
brelse(bh);
if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
- s->s_imap[i] = NULL;
+ s->u.minix_sb.s_imap[i] = NULL;
for (i=0;i < MINIX_Z_MAP_SLOTS;i++)
- s->s_zmap[i] = NULL;
+ s->u.minix_sb.s_zmap[i] = NULL;
block=2;
- for (i=0 ; i < s->s_imap_blocks ; i++)
- if (s->s_imap[i]=bread(dev,block))
+ for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++)
+ if (s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE))
block++;
else
break;
- for (i=0 ; i < s->s_zmap_blocks ; i++)
- if (s->s_zmap[i]=bread(dev,block))
+ for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++)
+ if (s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE))
block++;
else
break;
- if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
+ if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) {
for(i=0;i<MINIX_I_MAP_SLOTS;i++)
- brelse(s->s_imap[i]);
+ brelse(s->u.minix_sb.s_imap[i]);
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
- brelse(s->s_zmap[i]);
+ brelse(s->u.minix_sb.s_zmap[i]);
s->s_dev=0;
free_super(s);
printk("block failed\n");
return NULL;
}
- s->s_imap[0]->b_data[0] |= 1;
- s->s_zmap[0]->b_data[0] |= 1;
+ s->u.minix_sb.s_imap[0]->b_data[0] |= 1;
+ s->u.minix_sb.s_zmap[0]->b_data[0] |= 1;
free_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
return s;
}
+void minix_statfs (struct super_block *sb, struct statfs *buf)
+{
+ long tmp;
+
+ put_fs_long(MINIX_SUPER_MAGIC, &buf->f_type);
+ put_fs_long(1024, &buf->f_bsize);
+ put_fs_long(sb->u.minix_sb.s_nzones << sb->u.minix_sb.s_log_zone_size, &buf->f_blocks);
+ tmp = minix_count_free_blocks(sb);
+ put_fs_long(tmp, &buf->f_bfree);
+ put_fs_long(tmp, &buf->f_bavail);
+ put_fs_long(sb->u.minix_sb.s_ninodes, &buf->f_files);
+ put_fs_long(minix_count_free_inodes(sb), &buf->f_ffree);
+ /* Don't know what value to put in buf->f_fsid */
+}
+
static int _minix_bmap(struct inode * inode,int block,int create)
{
struct buffer_head * bh;
}
if (!inode->i_data[7])
return 0;
- if (!(bh = bread(inode->i_dev,inode->i_data[7])))
+ if (!(bh = bread(inode->i_dev,inode->i_data[7],BLOCK_SIZE)))
return 0;
i = ((unsigned short *) (bh->b_data))[block];
if (create && !i)
}
if (!inode->i_data[8])
return 0;
- if (!(bh=bread(inode->i_dev,inode->i_data[8])))
+ if (!(bh=bread(inode->i_dev,inode->i_data[8], BLOCK_SIZE)))
return 0;
i = ((unsigned short *)bh->b_data)[block>>9];
if (create && !i)
brelse(bh);
if (!i)
return 0;
- if (!(bh=bread(inode->i_dev,i)))
+ if (!(bh=bread(inode->i_dev,i,BLOCK_SIZE)))
return 0;
i = ((unsigned short *)bh->b_data)[block&511];
if (create && !i)
struct minix_inode * raw_inode;
int block;
- block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
+ block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
+ if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE)))
panic("unable to read i-node block");
raw_inode = ((struct minix_inode *) bh->b_data) +
(inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
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;
+ else if (S_ISFIFO(inode->i_mode)) {
+ inode->i_op = &minix_fifo_inode_operations;
+ inode->i_size = 0;
+ inode->i_pipe = 1;
+ PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+ }
}
void minix_write_inode(struct inode * inode)
struct minix_inode * raw_inode;
int block;
- block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
+ block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(inode->i_ino-1)/MINIX_INODES_PER_BLOCK;
- if (!(bh=bread(inode->i_dev,block)))
+ if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
panic("unable to read i-node block");
raw_inode = ((struct minix_inode *)bh->b_data) +
(inode->i_ino-1)%MINIX_INODES_PER_BLOCK;
+++ /dev/null
-/*
- * 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)
-{
- inode->i_size = 0;
- 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 - default */
- minix_file_read, /* read */
- minix_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* close - default */
- NULL, /* select - default */
- NULL /* ioctl - default */
-};
-
-struct file_operations minix_dir_operations = {
- NULL, /* lseek - default */
- minix_file_read, /* read */
- NULL, /* write - bad */
- minix_readdir, /* readdir */
- NULL, /* close - default */
- NULL, /* select - default */
- NULL /* ioctl - default */
-};
/*
* linux/fs/minix/namei.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+
#include <asm/segment.h>
-#include <linux/string.h>
-#include <fcntl.h>
-#include <errno.h>
#include <const.h>
-#include <sys/stat.h>
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
entries = dir->i_size / (sizeof (struct minix_dir_entry));
if (!(block = dir->i_data[0]))
return NULL;
- if (!(bh = bread(dir->i_dev,block)))
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
brelse(bh);
bh = NULL;
if (!(block = minix_bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
- !(bh = bread(dir->i_dev,block))) {
+ !(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
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)
{
return NULL;
if (!(block = dir->i_data[0]))
return NULL;
- if (!(bh = bread(dir->i_dev,block)))
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
if (!block)
return NULL;
- if (!(bh = bread(dir->i_dev,block))) {
+ if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
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;
}
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;
+ else if (S_ISFIFO(inode->i_mode)) {
+ inode->i_op = &minix_fifo_inode_operations;
+ inode->i_size = 0;
+ inode->i_pipe = 1;
+ PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+ }
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
iput(dir);
return -ENOSPC;
iput(dir);
return -ENOSPC;
}
+ inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * sizeof (struct minix_dir_entry);
- inode->i_dirt = 1;
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;
}
inode->i_dirt = 1;
- if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
iput(dir);
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
return -EIO;
}
len = inode->i_size / sizeof (struct minix_dir_entry);
if (len<2 || !inode->i_data[0] ||
- !(bh=bread(inode->i_dev,inode->i_data[0]))) {
+ !(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
}
nr += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
- if (!(bh=bread(inode->i_dev,block)))
+ if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
return 0;
de = (struct minix_dir_entry *) bh->b_data;
}
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;
}
inode->i_dirt = 1;
- if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
+ if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
iput(dir);
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
return -EIO;
}
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
brelse(bh);
iput(dir);
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
iput(dir);
return -ENOSPC;
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);
retval = 0;
goto end_rename;
}
+ if (S_ISDIR(new_inode->i_mode)) {
+ retval = -EEXIST;
+ goto end_rename;
+ }
if (S_ISDIR(old_inode->i_mode)) {
retval = -EEXIST;
if (new_bh)
retval = -EIO;
if (!old_inode->i_data[0])
goto end_rename;
- if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0])))
+ if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE)))
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
/* 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) {
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)
{
- static struct task_struct * wait = NULL;
+ static struct wait_queue * wait = NULL;
static int lock = 0;
int result;
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;
-}
--- /dev/null
+/*
+ * linux/fs/minix/symlink.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * minix symlink handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+#include <linux/stat.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], BLOCK_SIZE))) {
+ 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], BLOCK_SIZE);
+ 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;
+}
/*
* linux/fs/truncate.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/tty.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
/*
* Truncate has the most races in the whole filesystem: coding it is
#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
if (*p)
- bh = bread(inode->i_dev,*p);
+ bh = bread(inode->i_dev, *p, BLOCK_SIZE);
if (!bh)
return 0;
repeat:
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
if (inode->i_data[8])
- bh = bread(inode->i_dev,inode->i_data[8]);
+ bh = bread(inode->i_dev, inode->i_data[8], BLOCK_SIZE);
if (!bh)
return 0;
repeat:
{
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);
- else if (S_ISREG(inode->i_mode))
- filp->f_op = &minix_file_operations;
- else if (S_ISDIR(inode->i_mode))
- filp->f_op = &minix_dir_operations;
- return 0;
-}
--- /dev/null
+#
+# Makefile for the linux MS-DOS-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+.c.o:
+ $(CC) $(CFLAGS) -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+
+OBJS= namei.o inode.o file.o dir.o misc.o fat.o
+
+msdos.o: $(OBJS)
+ $(LD) -r -o msdos.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:
+dir.o : dir.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/stat.h
+fat.o : fat.c /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/stat.h
+file.o : file.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/stat.h
+inode.o : inode.c /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h \
+ /usr/src/linux/include/asm/segment.h
+misc.o : misc.c /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h
+namei.o : namei.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/msdos_fs.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h
--- /dev/null
+/*
+ * linux/fs/msdos/dir.c
+ *
+ * Written 1992 by Werner Almesberger
+ *
+ * MS-DOS directory handling functions
+ */
+
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+
+static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf,
+ int count);
+static int msdos_readdir(struct inode *inode,struct file *filp,
+ struct dirent *dirent,int count);
+
+
+static struct file_operations msdos_dir_operations = {
+ NULL, /* lseek - default */
+ msdos_dummy_read, /* read */
+ NULL, /* write - bad */
+ msdos_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+struct inode_operations msdos_dir_inode_operations = {
+ &msdos_dir_operations, /* default directory file-ops */
+ msdos_create, /* create */
+ msdos_lookup, /* lookup */
+ NULL, /* link */
+ msdos_unlink, /* unlink */
+ NULL, /* symlink */
+ msdos_mkdir, /* mkdir */
+ msdos_rmdir, /* rmdir */
+ NULL, /* mknod */
+ msdos_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ msdos_bmap, /* bmap */
+ NULL /* truncate */
+};
+
+
+/* So grep * doesn't complain in the presence of directories. */
+
+static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf,
+ int count)
+{
+ static long last_warning = 0;
+
+ if (CURRENT_TIME-last_warning >= 10) {
+ printk("COMPATIBILITY WARNING: reading a directory\r\n");
+ last_warning = CURRENT_TIME;
+ }
+ return 0;
+}
+
+
+static int msdos_readdir(struct inode *inode,struct file *filp,
+ struct dirent *dirent,int count)
+{
+ int ino,i,i2,last;
+ char c,*walk;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+
+ if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF;
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+/* Fake . and .. for the root directory. */
+ if (filp->f_pos == 2) filp->f_pos = 0;
+ else if (filp->f_pos < 2) {
+ walk = filp->f_pos++ ? ".." : ".";
+ for (i = 0; *walk; walk++)
+ put_fs_byte(*walk,dirent->d_name+i++);
+ put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
+ put_fs_byte(0,dirent->d_name+i);
+ put_fs_word(i,&dirent->d_reclen);
+ return i;
+ }
+ }
+ if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT;
+ bh = NULL;
+ while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
+ if (de->name[0] && ((unsigned char *) (de->name))[0] !=
+ DELETED_FLAG && !(de->attr & ATTR_VOLUME)) {
+ for (i = last = 0; i < 8; i++) {
+ if (!(c = de->name[i])) break;
+ if (c >= 'A' && c <= 'Z') c += 32;
+ if (c != ' ') last = i+1;
+ put_fs_byte(c,i+dirent->d_name);
+ }
+ i = last;
+ if (de->ext[0] && de->ext[0] != ' ') {
+ put_fs_byte('.',i+dirent->d_name);
+ i++;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!(c = de->ext[i2])) break;
+ if (c >= 'A' && c <= 'Z') c += 32;
+ put_fs_byte(c,i+dirent->d_name);
+ i++;
+ if (c != ' ') last = i;
+ }
+ }
+ if (i = last) {
+ if (!strcmp(de->name,MSDOS_DOT))
+ ino = inode->i_ino;
+ else if (!strcmp(de->name,MSDOS_DOTDOT))
+ ino = msdos_parent_ino(inode,0);
+ put_fs_long(ino,&dirent->d_ino);
+ put_fs_byte(0,i+dirent->d_name);
+ put_fs_word(i,&dirent->d_reclen);
+ brelse(bh);
+ return i;
+ }
+ }
+ }
+ if (bh) brelse(bh);
+ return 0;
+}
--- /dev/null
+/*
+ * linux/fs/msdos/fat.c
+ *
+ * Written 1992 by Werner Almesberger
+ */
+
+#include <linux/msdos_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+
+static struct fat_cache *fat_cache,cache[FAT_CACHE];
+
+/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
+ new_value is != -1, that FAT entry is replaced by it. */
+
+int fat_access(struct super_block *sb,int this,int new_value)
+{
+ struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
+ unsigned char *p_first,*p_last;
+ void *data,*data2,*c_data,*c_data2;
+ int first,last,next,copy;
+
+ if (MSDOS_SB(sb)->fat_bits == 16) first = last = this*2;
+ else {
+ first = this*3/2;
+ last = first+1;
+ }
+ if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
+ SECTOR_BITS),&data))) {
+ printk("bread in fat_access failed\r\n");
+ return 0;
+ }
+ if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
+ bh2 = bh;
+ data2 = data;
+ }
+ else {
+ if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
+ >> SECTOR_BITS),&data2))) {
+ brelse(bh);
+ printk("bread in fat_access failed\r\n");
+ return 0;
+ }
+ }
+ if (MSDOS_SB(sb)->fat_bits == 16) {
+ next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1))
+ >> 1];
+ if (next >= 0xfff8) next = -1;
+ }
+ else {
+ p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)];
+ p_last = &((unsigned char *) data2)[(first+1) &
+ (SECTOR_SIZE-1)];
+ if (this & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
+ else next = (*p_first+(*p_last << 8)) & 0xfff;
+ if (next >= 0xff8) next = -1;
+ }
+ if (new_value != -1) {
+ if (MSDOS_SB(sb)->fat_bits == 16)
+ ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >>
+ 1] = new_value;
+ else {
+ if (this & 1) {
+ *p_first = (*p_first & 0xf) | (new_value << 4);
+ *p_last = new_value >> 4;
+ }
+ else {
+ *p_first = new_value & 0xff;
+ *p_last = (*p_last & 0xf0) | (new_value >> 8);
+ }
+ bh2->b_dirt = 1;
+ }
+ bh->b_dirt = 1;
+ for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
+ if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
+ fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
+ fat_length*copy,&c_data))) break;
+ memcpy(c_data,data,SECTOR_SIZE);
+ c_bh->b_dirt = 1;
+ if (data != data2 || bh != bh2) {
+ if (!(c_bh2 = msdos_sread(sb->s_dev,
+ MSDOS_SB(sb)->fat_start+(first >>
+ SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
+ +1,&c_data2))) {
+ brelse(c_bh);
+ break;
+ }
+ memcpy(c_data2,data2,SECTOR_SIZE);
+ brelse(c_bh2);
+ }
+ brelse(c_bh);
+ }
+ }
+ brelse(bh);
+ if (data != data2) brelse(bh2);
+ return next;
+}
+
+
+void cache_init(void)
+{
+ static int initialized = 0;
+ int count;
+
+ if (initialized) return;
+ fat_cache = &cache[0];
+ for (count = 0; count < FAT_CACHE; count++) {
+ cache[count].device = 0;
+ cache[count].next = count == FAT_CACHE-1 ? NULL :
+ &cache[count+1];
+ }
+ initialized = 1;
+}
+
+
+void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
+{
+ struct fat_cache *walk;
+
+#ifdef DEBUG
+printk("cache lookup: %d\r\n",*f_clu);
+#endif
+ for (walk = fat_cache; walk; walk = walk->next)
+ if (inode->i_dev == walk->device && walk->ino == inode->i_ino &&
+ walk->file_cluster <= cluster && walk->file_cluster >
+ *f_clu) {
+ *d_clu = walk->disk_cluster;
+#ifdef DEBUG
+printk("cache hit: %d (%d)\r\n",walk->file_cluster,*d_clu);
+#endif
+ if ((*f_clu = walk->file_cluster) == cluster) return;
+ }
+}
+
+
+#ifdef DEBUG
+static void list_cache(void)
+{
+ struct fat_cache *walk;
+
+ for (walk = fat_cache; walk; walk = walk->next) {
+ if (walk->device) printk("(%d,%d) ",walk->file_cluster,
+ walk->disk_cluster);
+ else printk("-- ");
+ }
+ printk("\r\n");
+}
+#endif
+
+
+void cache_add(struct inode *inode,int f_clu,int d_clu)
+{
+ struct fat_cache *walk,*last;
+
+#ifdef DEBUG
+printk("cache add: %d (%d)\r\n",f_clu,d_clu);
+#endif
+ last = NULL;
+ for (walk = fat_cache; walk->next; walk = (last = walk)->next)
+ if (inode->i_dev == walk->device && walk->ino == inode->i_ino &&
+ walk->file_cluster == f_clu) {
+ if (walk->disk_cluster != d_clu)
+ panic("FAT cache corruption");
+ /* update LRU */
+ if (last == NULL) return;
+ last->next = walk->next;
+ walk->next = fat_cache;
+ fat_cache = walk;
+#ifdef DEBUG
+list_cache();
+#endif
+ return;
+ }
+ walk->device = inode->i_dev;
+ walk->ino = inode->i_ino;
+ walk->file_cluster = f_clu;
+ walk->disk_cluster = d_clu;
+ last->next = NULL;
+ walk->next = fat_cache;
+ fat_cache = walk;
+#ifdef DEBUG
+list_cache();
+#endif
+}
+
+
+/* Cache invalidation occurs rarely, thus the LRU chain is not updated. It
+ fixes itself after a while. */
+
+void cache_inval_inode(struct inode *inode)
+{
+ struct fat_cache *walk;
+
+ for (walk = fat_cache; walk; walk = walk->next)
+ if (walk->device == inode->i_dev && walk->ino == inode->i_ino)
+ walk->device = 0;
+}
+
+
+void cache_inval_dev(int device)
+{
+ struct fat_cache *walk;
+
+ for (walk = fat_cache; walk; walk = walk->next)
+ if (walk->device == device) walk->device = 0;
+}
+
+
+int get_cluster(struct inode *inode,int cluster)
+{
+ int this,count;
+
+ if (!(this = inode->i_data[D_START])) return 0;
+ if (!cluster) return this;
+ count = 0;
+ for (cache_lookup(inode,cluster,&count,&this); count < cluster;
+ count++) {
+ if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
+ if (!this) return 0;
+ }
+ cache_add(inode,cluster,this);
+ return this;
+}
+
+
+int msdos_smap(struct inode *inode,int sector)
+{
+ struct msdos_sb_info *sb;
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
+ if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+ !inode->i_data[D_START])) {
+ if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
+ return sector+sb->dir_start;
+ }
+ cluster = sector/sb->cluster_size;
+ offset = sector % sb->cluster_size;
+ if (!(cluster = get_cluster(inode,cluster))) return 0;
+ return (cluster-2)*sb->cluster_size+sb->data_start+offset;
+}
+
+
+/* Free all clusters after the skip'th cluster. Doesn't use the cache,
+ because this way we get an additional sanity check. */
+
+int fat_free(struct inode *inode,int skip)
+{
+ int this,last;
+
+ if (!(this = inode->i_data[D_START])) return 0;
+ last = 0;
+ while (skip--) {
+ last = this;
+ if ((this = fat_access(inode->i_sb,this,-1)) == -1)
+ return 0;
+ if (!this) {
+ printk("fat_free: skipped EOF\r\n");
+ return -EIO;
+ }
+ }
+ if (last)
+ fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
+ 12 ? 0xff8 : 0xfff8);
+ else {
+ inode->i_data[D_START] = 0;
+ inode->i_dirt = 1;
+ }
+ while (this != -1)
+ if (!(this = fat_access(inode->i_sb,this,0)))
+ panic("fat_free: deleting beyond EOF");
+ cache_inval_inode(inode);
+ return 0;
+}
--- /dev/null
+/*
+ * linux/fs/msdos/file.c
+ *
+ * Written 1992 by Werner Almesberger
+ *
+ * MS-DOS regular file handling primitives
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
+ int count);
+static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
+ int count);
+
+
+static struct file_operations msdos_file_operations = {
+ NULL, /* lseek - default */
+ msdos_file_read, /* read */
+ msdos_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open is needed */
+ NULL /* release */
+};
+
+struct inode_operations msdos_file_inode_operations = {
+ &msdos_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 */
+ msdos_bmap, /* bmap */
+ msdos_truncate /* truncate */
+};
+
+/* No bmap for MS-DOS FS' that don't align data at kByte boundaries. */
+
+struct inode_operations msdos_file_inode_operations_no_bmap = {
+ &msdos_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 */
+ NULL, /* bmap */
+ msdos_truncate /* truncate */
+};
+
+
+static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
+ int count)
+{
+ char *start;
+ int left,offset,size,sector,cnt;
+ char ch;
+ struct buffer_head *bh;
+ void *data;
+
+/* printk("msdos_file_read\r\n"); */
+ if (!inode) {
+ printk("msdos_file_read: inode = NULL\r\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("msdos_file_read: mode = %07o\n",inode->i_mode);
+ return -EINVAL;
+ }
+ if (filp->f_pos >= inode->i_size || count <= 0) return 0;
+ start = buf;
+ while (left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) {
+ if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
+ break;
+ offset = filp->f_pos & (SECTOR_SIZE-1);
+ if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
+ filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
+ if (inode->i_data[D_BINARY]) {
+ memcpy_tofs(buf,data+offset,size);
+ buf += size;
+ }
+ else for (cnt = size; cnt; cnt--) {
+ if ((ch = *((char *) data+offset++)) == '\r')
+ size--;
+ else {
+ if (ch != 26) put_fs_byte(ch,buf++);
+ else {
+ filp->f_pos = inode->i_size;
+ brelse(bh);
+ return buf-start;
+ }
+ }
+ }
+ brelse(bh);
+ }
+ if (start == buf) return -EIO;
+ return buf-start;
+}
+
+
+static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
+ int count)
+{
+ int sector,offset,size,left,written;
+ int error,carry;
+ char *start,*to,ch;
+ struct buffer_head *bh;
+ void *data;
+
+ if (!inode) {
+ printk("msdos_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("msdos_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) filp->f_pos = inode->i_size;
+ if (count <= 0) return 0;
+ error = carry = 0;
+ for (start = buf; count || carry; count -= size) {
+ while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
+ if ((error = msdos_add_cluster(inode)) < 0) break;
+ if (error) break;
+ offset = filp->f_pos & (SECTOR_SIZE-1);
+ size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
+ if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
+ error = -EIO;
+ break;
+ }
+ if (inode->i_data[D_BINARY]) {
+ memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
+ buf,written = size);
+ buf += size;
+ }
+ else {
+ written = left = SECTOR_SIZE-offset;
+ to = data+(filp->f_pos & (SECTOR_SIZE-1));
+ if (carry) {
+ *to++ = '\n';
+ left--;
+ carry = 0;
+ }
+ for (size = 0; size < count && left; size++) {
+ if ((ch = get_fs_byte(buf++)) == '\n') {
+ *to++ = '\r';
+ left--;
+ }
+ if (!left) carry = 1;
+ else {
+ *to++ = ch;
+ left--;
+ }
+ }
+ written -= left;
+ }
+ filp->f_pos += written;
+ if (filp->f_pos > inode->i_size) {
+ inode->i_size = filp->f_pos;
+ inode->i_dirt = 1;
+ }
+ bh->b_dirt = 1;
+ brelse(bh);
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_data[D_ATTRS] |= ATTR_ARCH;
+ inode->i_dirt = 1;
+ return start == buf ? error : buf-start;
+}
+
+
+void msdos_truncate(struct inode *inode)
+{
+ int cluster;
+
+ cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+ (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
+ inode->i_data[D_ATTRS] |= ATTR_ARCH;
+ inode->i_dirt = 1;
+}
--- /dev/null
+/*
+ * linux/fs/msdos/inode.c
+ *
+ * Written 1992 by Werner Almesberger
+ */
+
+#include <linux/msdos_fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+#include <asm/segment.h>
+
+void msdos_put_inode(struct inode *inode)
+{
+ struct inode *depend;
+
+ inode->i_size = 0;
+ msdos_truncate(inode);
+ depend = (struct inode *) inode->i_data[D_DEPEND];
+ memset(inode,0,sizeof(struct inode));
+ if (depend) {
+ if ((struct inode *) depend->i_data[D_OLD] != inode) {
+ printk("Invalid link (0x%X): expected 0x%X, got "
+ "0x%X\r\n",(int) depend,(int) inode,
+ depend->i_data[D_OLD]);
+ panic("That's fatal");
+ }
+ depend->i_data[D_OLD] = 0;
+ iput(depend);
+ }
+}
+
+
+void msdos_put_super(struct super_block *sb)
+{
+ cache_inval_dev(sb->s_dev);
+ lock_super(sb);
+ sb->s_dev = 0;
+ free_super(sb);
+ return;
+}
+
+
+static struct super_operations msdos_sops = {
+ msdos_read_inode,
+ msdos_write_inode,
+ msdos_put_inode,
+ msdos_put_super,
+ NULL, /* added in 0.96c */
+ msdos_statfs
+};
+
+
+static int parse_options(char *options,char *check,char *conversion)
+{
+ char *this,*value;
+
+ *check = 'n';
+ *conversion = 'b';
+ if (!options) return 1;
+ for (this = strtok(options,","); this; this = strtok(NULL,",")) {
+ if (value = strchr(this,'=')) *value++ = 0;
+ if (!strcmp(this,"check") && value) {
+ if (value[0] && !value[1] && strchr("rns",*value))
+ *check = *value;
+ else if (!strcmp(value,"relaxed")) *check = 'r';
+ else if (!strcmp(value,"normal")) *check = 'n';
+ else if (!strcmp(value,"strict")) *check = 's';
+ else return 0;
+ }
+ else if (!strcmp(this,"conv") && value) {
+ if (value[0] && !value[1] && strchr("bta",*value))
+ *conversion = *value;
+ else if (!strcmp(value,"binary")) *conversion = 'b';
+ else if (!strcmp(value,"text")) *conversion = 't';
+ else if (!strcmp(value,"auto")) *conversion = 'a';
+ else return 0;
+ }
+ else return 0;
+ }
+ return 1;
+}
+
+
+/* Read the super block of an MS-DOS FS. */
+
+struct super_block *msdos_read_super(struct super_block *s,void *data)
+{
+ struct buffer_head *bh;
+ struct msdos_boot_sector *b;
+ int data_sectors;
+ char check,conversion;
+
+ if (!parse_options((char *) data,&check,&conversion)) {
+ s->s_dev = 0;
+ return NULL;
+ }
+ cache_init();
+ lock_super(s);
+ bh = bread(s->s_dev, 0, BLOCK_SIZE);
+ free_super(s);
+ if (bh == NULL) {
+ s->s_dev = 0;
+ printk("MSDOS bread failed\r\n");
+ return NULL;
+ }
+ b = (struct msdos_boot_sector *) bh->b_data;
+ s->s_blocksize = 1024; /* we cannot handle anything else yet */
+ MSDOS_SB(s)->cluster_size = b->cluster_size;
+ MSDOS_SB(s)->fats = b->fats;
+ MSDOS_SB(s)->fat_start = b->reserved;
+ MSDOS_SB(s)->fat_length = b->fat_length;
+ MSDOS_SB(s)->dir_start = b->reserved+b->fats*b->fat_length;
+ MSDOS_SB(s)->dir_entries = *((unsigned short *) &b->dir_entries);
+ MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+((MSDOS_SB(s)->
+ dir_entries << 5) >> 9);
+ data_sectors = (*((unsigned short *) &b->sectors) ? *((unsigned short *)
+ &b->sectors) : b->total_sect)-MSDOS_SB(s)->data_start;
+ MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/b->cluster_size :
+ 0;
+ MSDOS_SB(s)->fat_bits = MSDOS_SB(s)->clusters > MSDOS_FAT12 ? 16 : 12;
+ brelse(bh);
+printk("[MS-DOS FS Rel. alpha.6, FAT %d, check=%c, conv=%c]\r\n",
+ MSDOS_SB(s)->fat_bits,check,conversion);
+printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
+ b->media,MSDOS_SB(s)->cluster_size,MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,
+ MSDOS_SB(s)->fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
+ MSDOS_SB(s)->data_start,*(unsigned short *) &b->sectors,b->total_sect);
+ if (!MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & (MSDOS_DPS-1))
+ || !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
+ fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits) {
+ s->s_dev = 0;
+ printk("Unsupported FS parameters\r\n");
+ return NULL;
+ }
+ if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\r\n");
+ s->s_magic = MSDOS_SUPER_MAGIC;
+ MSDOS_SB(s)->name_check = check;
+ MSDOS_SB(s)->conversion = conversion;
+ /* set up enough so that it can read an inode */
+ s->s_op = &msdos_sops;
+ MSDOS_SB(s)->fs_uid = current->uid;
+ MSDOS_SB(s)->fs_gid = current->gid;
+ MSDOS_SB(s)->fs_umask = current->umask;
+ if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) {
+ s->s_dev = 0;
+ printk("get root inode failed\n");
+ return NULL;
+ }
+ return s;
+}
+
+
+void msdos_statfs(struct super_block *sb,struct statfs *buf)
+{
+ int cluster_size,free,this;
+
+ cluster_size = MSDOS_SB(sb)->cluster_size;
+ put_fs_long(sb->s_magic,&buf->f_type);
+ put_fs_long(SECTOR_SIZE,&buf->f_bsize);
+ put_fs_long(MSDOS_SB(sb)->clusters*cluster_size,&buf->f_blocks);
+ free = 0;
+ for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
+ if (!fat_access(sb,this,-1)) free++;
+ free *= cluster_size;
+ put_fs_long(free,&buf->f_bfree);
+ put_fs_long(free,&buf->f_bavail);
+ put_fs_long(0,&buf->f_files);
+ put_fs_long(0,&buf->f_ffree);
+}
+
+
+int msdos_bmap(struct inode *inode,int block)
+{
+ struct msdos_sb_info *sb;
+ int cluster,offset;
+
+ sb = MSDOS_SB(inode->i_sb);
+ if ((sb->cluster_size & 1) || (sb->data_start & 1)) return 0;
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+ if (sb->dir_start & 1) return 0;
+ return (sb->dir_start >> 1)+block;
+ }
+ cluster = (block*2)/sb->cluster_size;
+ offset = (block*2) % sb->cluster_size;
+ if (!(cluster = get_cluster(inode,cluster))) return 0;
+ return ((cluster-2)*sb->cluster_size+sb->data_start+offset) >> 1;
+}
+
+
+void msdos_read_inode(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *raw_entry;
+ int this;
+
+/* printk("read inode %d\r\n",inode->i_ino); */
+ inode->i_data[D_BUSY] = inode->i_data[D_DEPEND] =
+ inode->i_data[D_OLD] = 0;
+ inode->i_data[D_BINARY] = 1;
+ inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid;
+ inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid;
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+ inode->i_mode = (0777 & ~MSDOS_SB(inode->i_sb)->fs_umask) |
+ S_IFDIR;
+ inode->i_op = &msdos_dir_inode_operations;
+ inode->i_nlink = 1;
+ inode->i_size = MSDOS_SB(inode->i_sb)->dir_entries*
+ sizeof(struct msdos_dir_entry);
+ inode->i_data[D_START] = 0;
+ inode->i_data[D_ATTRS] = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
+ return;
+ }
+ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, BLOCK_SIZE)))
+ panic("unable to read i-node block");
+ raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
+ [inode->i_ino & (MSDOS_DPB-1)];
+ if (raw_entry->attr & ATTR_DIR) {
+ inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 &
+ ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
+ inode->i_op = &msdos_dir_inode_operations;
+ inode->i_nlink = 3;
+ inode->i_size = 0;
+ for (this = raw_entry->start; this && this != -1; this =
+ fat_access(inode->i_sb,this,-1))
+ inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
+ cluster_size;
+ }
+ else {
+ inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0666 &
+ ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFREG;
+ inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ?
+ &msdos_file_inode_operations :
+ &msdos_file_inode_operations_no_bmap;
+ inode->i_nlink = 1;
+ inode->i_size = raw_entry->size;
+ }
+ inode->i_data[D_BINARY] = is_binary(MSDOS_SB(inode->i_sb)->conversion,
+ raw_entry->ext);
+ inode->i_data[D_START] = raw_entry->start;
+ inode->i_data[D_ATTRS] = raw_entry->attr & ATTR_UNUSED;
+ inode->i_mtime = inode->i_atime = inode->i_ctime =
+ date_dos2unix(raw_entry->time,raw_entry->date);
+ brelse(bh);
+}
+
+
+void msdos_write_inode(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *raw_entry;
+
+ inode->i_dirt = 0;
+ if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return;
+ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, BLOCK_SIZE)))
+ panic("unable to read i-node block");
+ raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
+ [inode->i_ino & (MSDOS_DPB-1)];
+ if (S_ISDIR(inode->i_mode)) {
+ raw_entry->attr = ATTR_DIR;
+ raw_entry->size = 0;
+ }
+ else {
+ raw_entry->attr = ATTR_NONE;
+ raw_entry->size = inode->i_size;
+ }
+ raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | inode->i_data[D_ATTRS];
+ raw_entry->start = inode->i_data[D_START];
+ date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
+ bh->b_dirt = 1;
+ brelse(bh);
+}
--- /dev/null
+/*
+ * linux/fs/msdos/misc.c
+ *
+ * Written 1992 by Werner Almesberger
+ */
+
+#include <linux/msdos_fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+static char bin_extensions[] =
+ "EXECOMAPPSYSOVLOBJLIB" /* program code */
+ "ARCZIPLHALZHZOOTARZ ARJTZ " /* common archivers */
+ "GIFBMPTIFGL JPGPCX" /* graphics */
+ "TFMVF GF PK PXLDVI"; /* TeX */
+
+
+/* Select binary/text conversion */
+
+int is_binary(char conversion,char *extension)
+{
+ char *walk;
+
+ switch (conversion) {
+ case 'b':
+ return 1;
+ case 't':
+ return 0;
+ case 'a':
+ for (walk = bin_extensions; *walk; walk += 3)
+ if (!strncmp(extension,walk,3)) return 1;
+ return 0;
+ default:
+ panic("Invalid conversion mode");
+ }
+}
+
+
+static struct wait_queue *creation_wait = NULL;
+static creation_lock = 0;
+
+
+void lock_creation(void)
+{
+ while (creation_lock) sleep_on(&creation_wait);
+ creation_lock = 1;
+}
+
+
+void unlock_creation(void)
+{
+ creation_lock = 0;
+ wake_up(&creation_wait);
+}
+
+
+int msdos_add_cluster(struct inode *inode)
+{
+ static struct wait_queue *wait = NULL;
+ static int lock = 0;
+ static int previous = 0; /* works best if one FS is being used */
+ int count,this,limit,last,current,sector;
+ void *data;
+ struct buffer_head *bh;
+
+ if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ while (lock) sleep_on(&wait);
+ lock = 1;
+ limit = MSDOS_SB(inode->i_sb)->clusters;
+ this = limit; /* to keep GCC happy */
+ for (count = 0; count < limit; count++) {
+ this = ((count+previous) % limit)+2;
+ if (fat_access(inode->i_sb,this,-1) == 0) break;
+ }
+#ifdef DEBUG
+printk("free cluster: %d\r\n",this);
+#endif
+ previous = (count+previous+1) % limit;
+ if (count >= limit) {
+ lock = 0;
+ wake_up(&wait);
+ return -ENOSPC;
+ }
+ fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
+ 0xff8 : 0xfff8);
+ lock = 0;
+ wake_up(&wait);
+#ifdef DEBUG
+printk("set to %x\r\n",fat_access(inode->i_sb,this,-1));
+#endif
+ if (!S_ISDIR(inode->i_mode)) {
+ last = inode->i_size ? get_cluster(inode,(inode->i_size-1)/
+ SECTOR_SIZE/MSDOS_SB(inode->i_sb)->cluster_size) : 0;
+ }
+ else {
+ last = 0;
+ if (current = inode->i_data[D_START]) {
+ cache_lookup(inode,0x7fffffff,&last,¤t);
+ while (current && current != -1)
+ if (!(current = fat_access(inode->i_sb,
+ last = current,-1)))
+ panic("File without EOF");
+ }
+ }
+#ifdef DEBUG
+printk("last = %d\r\n",last);
+#endif
+ if (last) fat_access(inode->i_sb,last,this);
+ else {
+ inode->i_data[D_START] = this;
+ inode->i_dirt = 1;
+ }
+#ifdef DEBUG
+if (last) printk("next set to %d\r\n",fat_access(inode->i_sb,last,-1));
+#endif
+ for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
+ current++) {
+ sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
+ MSDOS_SB(inode->i_sb)->cluster_size+current;
+#ifdef DEBUG
+printk("zeroing sector %d\r\n",sector);
+#endif
+ if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
+ !(sector & 1)) {
+ if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
+ printk("getblk failed\r\n");
+ else {
+ memset(bh->b_data,0,BLOCK_SIZE);
+ bh->b_uptodate = 1;
+ }
+ current++;
+ }
+ else {
+ if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
+ printk("msdos_sread failed\r\n");
+ else memset(data,0,SECTOR_SIZE);
+ }
+ if (bh) {
+ bh->b_dirt = 1;
+ brelse(bh);
+ }
+ }
+ if (S_ISDIR(inode->i_mode)) {
+ if (inode->i_size & (SECTOR_SIZE-1))
+ panic("Odd directory size");
+ inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
+ cluster_size;
+#ifdef DEBUG
+printk("size is %d now (%x)\r\n",inode->i_size,inode);
+#endif
+ inode->i_dirt = 1;
+ }
+ return 0;
+}
+
+
+/* Linear day numbers of the respective 1sts in non-leap years. */
+
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
+
+int date_dos2unix(unsigned short time,unsigned short date)
+{
+ int month,year;
+
+ month = ((date >> 5) & 15)-1;
+ year = date >> 9;
+ return (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
+ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+}
+
+
+/* Convert linear UNIX date to a MS-DOS time/date pair. */
+
+void date_unix2dos(int unix_date,unsigned short *time,
+ unsigned short *date)
+{
+ int day,year,nl_day,month;
+
+ *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11);
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+}
+
+
+/* Returns the inode number of the directory entry at offset pos. If bh is
+ non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
+ returned in bh. */
+
+int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
+ struct msdos_dir_entry **de)
+{
+ int sector,offset;
+ void *data;
+
+ while (1) {
+ offset = *pos;
+ if ((sector = msdos_smap(dir,*pos >> SECTOR_BITS)) == -1)
+ return -1;
+ if (!sector)
+ return -1; /* FAT error ... */
+ *pos += sizeof(struct msdos_dir_entry);
+ if (*bh)
+ brelse(*bh);
+ if (!(*bh = msdos_sread(dir->i_dev,sector,&data)))
+ continue;
+ *de = (struct msdos_dir_entry *) (data+(offset &
+ (SECTOR_SIZE-1)));
+ return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
+ MSDOS_DIR_BITS);
+ }
+}
+
+
+/* Scans a directory for a given file (name points to its formatted name) or
+ for an empty directory slot (name is NULL). Returns the inode number. */
+
+int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
+ struct msdos_dir_entry **res_de,int *ino)
+{
+ int pos;
+ struct msdos_dir_entry *de;
+ struct inode *inode;
+
+ pos = 0;
+ *res_bh = NULL;
+ while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
+ if (name) {
+ if (de->name[0] && ((unsigned char *) (de->name))[0]
+ != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
+ !strncmp(de->name,name,MSDOS_NAME)) break;
+ }
+ else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
+ DELETED_FLAG) {
+ if (!(inode = iget(dir->i_dev,*ino))) break;
+ if (!inode->i_data[D_BUSY]) {
+ iput(inode);
+ break;
+ }
+ /* skip deleted files that haven't been closed yet */
+ iput(inode);
+ }
+ }
+ if (*ino == -1) {
+ if (*res_bh) brelse(*res_bh);
+ *res_bh = NULL;
+ return name ? -ENOENT : -ENOSPC;
+ }
+ *res_de = de;
+ return 0;
+}
+
+
+/* Now an ugly part: this set of directory scan routines works on clusters
+ rather than on inodes and sectors. They are necessary to locate the '..'
+ directory "inode". */
+
+
+static int raw_found(struct super_block *sb,int sector,char *name,int number,
+ int *ino)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *data;
+ int entry,start;
+
+ if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
+ for (entry = 0; entry < MSDOS_DPS; entry++)
+ if (name ? !strncmp(data[entry].name,name,MSDOS_NAME) :
+ *(unsigned char *) data[entry].name != DELETED_FLAG &&
+ data[entry].start == number) {
+ if (ino) *ino = sector*MSDOS_DPS+entry;
+ start = data[entry].start;
+ brelse(bh);
+ return start;
+ }
+ brelse(bh);
+ return -1;
+}
+
+
+static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino)
+{
+ int count,cluster;
+
+ for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
+ if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
+ number,ino)) >= 0) return cluster;
+ }
+ return -ENOENT;
+}
+
+
+static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
+ int number,int *ino)
+{
+ int count,cluster;
+
+ do {
+ for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
+ if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
+ cluster_size+MSDOS_SB(sb)->data_start+count,name,
+ number,ino)) >= 0) return cluster;
+ }
+ if (!(start = fat_access(sb,start,-1))) panic("FAT error");
+ }
+ while (start != -1);
+ return -ENOENT;
+}
+
+
+static int raw_scan(struct super_block *sb,int start,char *name,int number,
+ int *ino)
+{
+ if (start) return raw_scan_nonroot(sb,start,name,number,ino);
+ else return raw_scan_root(sb,name,number,ino);
+}
+
+
+int msdos_parent_ino(struct inode *dir,int locked)
+{
+ int error,current,prev,this;
+
+ if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
+ if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
+ if (!locked) lock_creation(); /* prevent renames */
+ if ((current = raw_scan(dir->i_sb,dir->i_data[D_START],MSDOS_DOTDOT,0,
+ NULL)) < 0) {
+ if (!locked) unlock_creation();
+ return current;
+ }
+ if (!current) this = MSDOS_ROOT_INO;
+ else {
+ if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
+ 0) {
+ if (!locked) unlock_creation();
+ return prev;
+ }
+ if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
+ if (!locked) unlock_creation();
+ return error;
+ }
+ }
+ if (!locked) unlock_creation();
+ return this;
+}
--- /dev/null
+/*
+ * linux/fs/msdos/namei.c
+ *
+ * Written 1992 by Werner Almesberger
+ */
+
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/msdos_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+/* MS-DOS "device special files" */
+
+static char *reserved_names[] = {
+ "CON ","PRN ","NUL ","AUX ",
+ "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
+ "COM1 ","COM2 ","COM3 ","COM4 ",
+ NULL };
+
+
+/* Formats an MS-DOS file name. Rejects invalid names. */
+
+static int msdos_format_name(char conv,const char *name,int len,char *res)
+{
+ char *walk,**reserved;
+ char c;
+ int space;
+
+ if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
+ if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
+ get_fs_byte(name+1) == '.'))) {
+ memset(res+1,' ',10);
+ while (len--) *res++ = '.';
+ return 0;
+ }
+ space = 0; /* to make GCC happy */
+ c = 0;
+ for (walk = res; len && walk-res < 8; walk++) {
+ c = get_fs_byte(name++);
+ len--;
+ if (c == ' ' && conv != 'r') return -EINVAL;
+ if (c >= 'A' && c <= 'Z') {
+ if (conv != 'r') return -EINVAL;
+ c += 32;
+ }
+ if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
+ if (c == '.') break;
+ space = c == ' ';
+ *walk = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len && c != '.') {
+ c = get_fs_byte(name++);
+ len--;
+ if (c != '.') return -EINVAL;
+ }
+ while (c != '.' && len--) c = get_fs_byte(name++);
+ if (walk == res) return -EINVAL;
+ if (c == '.') {
+ while (walk-res < 8) *walk++ = ' ';
+ while (len > 0 && walk-res < MSDOS_NAME) {
+ c = get_fs_byte(name++);
+ len--;
+ if (c == ' ' && conv != 'r') return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\' || c == '.')
+ return -EINVAL;
+ if (c >= 'A' && c <= 'Z') {
+ if (conv != 'r') return -EINVAL;
+ c += 32;
+ }
+ space = c == ' ';
+ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len) return -EINVAL;
+ }
+ while (walk-res < MSDOS_NAME) *walk++ = ' ';
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
+ return 0;
+}
+
+
+/* Locates a directory entry. */
+
+static int msdos_find(struct inode *dir,const char *name,int len,
+ struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+{
+ char msdos_name[MSDOS_NAME];
+ int res;
+
+ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
+ msdos_name)) < 0) return res;
+ return msdos_scan(dir,msdos_name,bh,de,ino);
+}
+
+
+int msdos_lookup(struct inode *dir,const char *name,int len,
+ struct inode **result)
+{
+ int ino,res;
+ struct msdos_dir_entry *de;
+ struct buffer_head *bh;
+ struct inode *next;
+
+ *result = NULL;
+ if (!dir) return -ENOENT;
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len == 1 && get_fs_byte(name) == '.') {
+ *result = dir;
+ return 0;
+ }
+ if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
+ {
+ ino = msdos_parent_ino(dir,0);
+ iput(dir);
+ if (ino < 0) return ino;
+ if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
+ return 0;
+ }
+ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
+ iput(dir);
+ return res;
+ }
+ if (bh) brelse(bh);
+/* printk("lookup: ino=%d\r\n",ino); */
+ if (!(*result = iget(dir->i_dev,ino))) {
+ iput(dir);
+ return -EACCES;
+ }
+ if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
+ iput(*result);
+ iput(dir);
+ return -ENOENT;
+ }
+ while ((*result)->i_data[D_OLD]) {
+ next = (struct inode *) ((*result)->i_data[D_OLD]);
+ iput(*result);
+ if (!(*result = iget(next->i_dev,next->i_ino)))
+ panic("msdos_lookup: Can't happen");
+ }
+ iput(dir);
+ return 0;
+}
+
+
+/* Creates a directory entry (name is already formatted). */
+
+static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
+ struct inode **result)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ int res,ino;
+
+ if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
+ if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if ((res = msdos_add_cluster(dir)) < 0) return res;
+ if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
+ }
+ memcpy(de->name,name,MSDOS_NAME);
+ de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
+ de->start = 0;
+ date_unix2dos(CURRENT_TIME,&de->time,&de->date);
+ de->size = 0;
+ bh->b_dirt = 1;
+ if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
+ brelse(bh);
+ if (!*result) return -EIO;
+ (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
+ CURRENT_TIME;
+ (*result)->i_dirt = 1;
+ return 0;
+}
+
+
+int msdos_create(struct inode *dir,const char *name,int len,int mode,
+ struct inode **result)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ char msdos_name[MSDOS_NAME];
+ int ino,res;
+
+ if (!dir) return -ENOENT;
+ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
+ msdos_name)) < 0) {
+ iput(dir);
+ return res;
+ }
+ lock_creation();
+ if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
+ unlock_creation();
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
+ unlock_creation();
+ iput(dir);
+ return res;
+}
+
+
+int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
+{
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ struct inode *inode,*dot;
+ char msdos_name[MSDOS_NAME];
+ int ino,res;
+
+ if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
+ msdos_name)) < 0) {
+ iput(dir);
+ return res;
+ }
+ lock_creation();
+ if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
+ unlock_creation();
+ brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
+ unlock_creation();
+ iput(dir);
+ return res;
+ }
+ inode->i_data[D_BUSY] = 1; /* prevent lookups */
+ if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
+ if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
+ goto mkdir_error;
+ dot->i_size = inode->i_size;
+ dot->i_data[D_START] = inode->i_data[D_START];
+ dot->i_dirt = 1;
+ iput(dot);
+ if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
+ goto mkdir_error;
+ unlock_creation();
+ dot->i_size = dir->i_size;
+ dot->i_data[D_START] = dir->i_data[D_START];
+ dot->i_dirt = 1;
+ inode->i_data[D_BUSY] = 0;
+ iput(dot);
+ iput(inode);
+ iput(dir);
+ return 0;
+mkdir_error:
+ iput(inode);
+ if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
+ unlock_creation();
+ return res;
+}
+
+
+int msdos_rmdir(struct inode *dir,const char *name,int len)
+{
+ int res,ino,pos;
+ struct buffer_head *bh,*dbh;
+ struct msdos_dir_entry *de,*dde;
+ struct inode *inode;
+
+ bh = NULL;
+ inode = NULL;
+ res = -EINVAL;
+ if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
+ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
+ res = -ENOENT;
+ if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
+ res = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
+ res = -EBUSY;
+ if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
+ if (inode->i_count > 1) goto rmdir_done;
+ if (inode->i_data[D_START]) { /* may be zero in mkdir */
+ res = -ENOTEMPTY;
+ pos = 0;
+ dbh = NULL;
+ while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
+ if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
+ DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
+ MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
+ MSDOS_NAME)) goto rmdir_done;
+ if (dbh) brelse(dbh);
+ }
+ inode->i_nlink = 0;
+ dir->i_mtime = CURRENT_TIME;
+ inode->i_dirt = dir->i_dirt = 1;
+ de->name[0] = DELETED_FLAG;
+ bh->b_dirt = 1;
+ res = 0;
+rmdir_done:
+ brelse(bh);
+ iput(dir);
+ iput(inode);
+ return res;
+}
+
+
+int msdos_unlink(struct inode *dir,const char *name,int len)
+{
+ int res,ino;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ struct inode *inode;
+
+ bh = NULL;
+ inode = NULL;
+ if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
+ goto unlink_done;
+ if (!(inode = iget(dir->i_dev,ino))) {
+ res = -ENOENT;
+ goto unlink_done;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ res = -EPERM;
+ goto unlink_done;
+ }
+ inode->i_nlink = 0;
+ inode->i_data[D_BUSY] = 1;
+ inode->i_dirt = 1;
+ de->name[0] = DELETED_FLAG;
+ bh->b_dirt = 1;
+unlink_done:
+ brelse(bh);
+ iput(inode);
+ iput(dir);
+ return res;
+}
+
+
+static int rename_same_dir(struct inode *old_dir,char *old_name,
+ struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
+ struct msdos_dir_entry *old_de,int old_ino)
+{
+ struct buffer_head *new_bh;
+ struct msdos_dir_entry *new_de;
+ struct inode *new_inode,*old_inode;
+ int new_ino;
+ int exists;
+
+ if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
+ exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
+ if (*(unsigned char *) old_de->name == DELETED_FLAG) {
+ if (exists) brelse(new_bh);
+ return -ENOENT;
+ }
+ if (exists) {
+ if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ brelse(new_bh);
+ return -EIO;
+ }
+ if (S_ISDIR(new_inode->i_mode)) {
+ iput(new_inode);
+ brelse(new_bh);
+ return -EPERM;
+ }
+ new_inode->i_nlink = 0;
+ new_inode->i_data[D_BUSY] = 1;
+ new_inode->i_dirt = 1;
+ new_de->name[0] = DELETED_FLAG;
+ new_bh->b_dirt = 1;
+ iput(new_inode);
+ brelse(new_bh);
+ }
+ memcpy(old_de->name,new_name,MSDOS_NAME);
+ old_bh->b_dirt = 1;
+ if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
+ if (old_inode = iget(old_dir->i_dev,old_ino)) {
+ msdos_read_inode(old_inode);
+ iput(old_inode);
+ }
+ return 0;
+}
+
+
+static int rename_diff_dir(struct inode *old_dir,char *old_name,
+ struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
+ struct msdos_dir_entry *old_de,int old_ino)
+{
+ struct buffer_head *new_bh,*free_bh,*dotdot_bh;
+ struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
+ struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
+ int new_ino,free_ino,dotdot_ino;
+ int error,exists,ino;
+
+ if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
+ if (old_ino == new_dir->i_ino) return -EINVAL;
+ if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
+ while (walk->i_ino != MSDOS_ROOT_INO) {
+ ino = msdos_parent_ino(walk,1);
+ iput(walk);
+ if (ino < 0) return ino;
+ if (ino == old_ino) return -EINVAL;
+ if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
+ }
+ iput(walk);
+ if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
+ return error;
+ exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
+ >= 0;
+ if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
+ brelse(free_bh);
+ if (exists) brelse(new_bh);
+ return -EIO;
+ }
+ if (*(unsigned char *) old_de->name == DELETED_FLAG) {
+ iput(old_inode);
+ brelse(free_bh);
+ if (exists) brelse(new_bh);
+ return -ENOENT;
+ }
+ new_inode = NULL; /* to make GCC happy */
+ if (exists) {
+ if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ iput(old_inode);
+ brelse(new_bh);
+ return -EIO;
+ }
+ if (S_ISDIR(new_inode->i_mode)) {
+ iput(new_inode);
+ iput(old_inode);
+ brelse(new_bh);
+ return -EPERM;
+ }
+ new_inode->i_nlink = 0;
+ new_inode->i_data[D_BUSY] = 1;
+ new_inode->i_dirt = 1;
+ new_de->name[0] = DELETED_FLAG;
+ new_bh->b_dirt = 1;
+ }
+ memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
+ memcpy(free_de->name,new_name,MSDOS_NAME);
+ if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
+ free_de->name[0] = DELETED_FLAG;
+/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
+ brelse(free_bh);
+ if (exists) {
+ iput(new_inode);
+ brelse(new_bh);
+ }
+ return -EIO;
+ }
+ msdos_read_inode(free_inode);
+ old_inode->i_data[D_BUSY] = 1;
+ old_inode->i_dirt = 1;
+ old_de->name[0] = DELETED_FLAG;
+ old_bh->b_dirt = 1;
+ free_bh->b_dirt = 1;
+ if (!exists) iput(free_inode);
+ else {
+ new_inode->i_data[D_DEPEND] = (int) free_inode;
+ free_inode->i_data[D_OLD] = (int) new_inode;
+ /* free_inode is put when putting new_inode */
+ iput(new_inode);
+ brelse(new_bh);
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
+ &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
+ if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
+ brelse(dotdot_bh);
+ error = -EIO;
+ goto rename_done;
+ }
+ dotdot_de->start = dotdot_inode->i_data[D_START] =
+ new_dir->i_data[D_START];
+ dotdot_inode->i_dirt = 1;
+ dotdot_bh->b_dirt = 1;
+ iput(dotdot_inode);
+ brelse(dotdot_bh);
+ }
+ error = 0;
+rename_done:
+ brelse(free_bh);
+ iput(old_inode);
+ return error;
+}
+
+
+int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
+ struct inode *new_dir,const char *new_name,int new_len)
+{
+ char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
+ struct buffer_head *old_bh;
+ struct msdos_dir_entry *old_de;
+ int old_ino,error;
+
+ if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
+ old_name,old_len,old_msdos_name)) < 0) goto rename_done;
+ if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
+ new_name,new_len,new_msdos_name)) < 0) goto rename_done;
+ if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
+ &old_ino)) < 0) goto rename_done;
+ lock_creation();
+ if (old_dir == new_dir)
+ error = rename_same_dir(old_dir,old_msdos_name,new_dir,
+ new_msdos_name,old_bh,old_de,old_ino);
+ else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
+ new_msdos_name,old_bh,old_de,old_ino);
+ unlock_creation();
+ brelse(old_bh);
+rename_done:
+ iput(old_dir);
+ iput(new_dir);
+ return error;
+}
/*
* linux/fs/namei.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Some corrections by tytso.
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
+#include <const.h>
+
#include <asm/segment.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
#include <linux/string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <const.h>
-#include <sys/stat.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
struct inode * _namei(const char * filename, struct inode * base,
int follow_links);
inode = follow_link(base,inode);
else
iput(base);
- if (inode) {
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
- }
return inode;
}
struct inode ** res_inode)
{
const char * basename;
- int namelen,error;
+ int namelen,error,i;
struct inode * dir, *inode;
+ struct task_struct ** p;
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
flag |= O_WRONLY;
- mode &= 0777 & ~current->umask;
+ mode &= 07777 & ~current->umask;
mode |= I_REGULAR;
if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
return -ENOENT;
iput(dir);
return -EACCES;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
return dir->i_op->create(dir,basename,namelen,mode,res_inode);
}
if (flag & O_EXCL) {
}
if (!(inode = follow_link(dir,inode)))
return -ELOOP;
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ } else {
+ if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) {
+ iput(inode);
+ return -EROFS;
+ }
+ }
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EPERM;
}
- inode->i_atime = CURRENT_TIME;
+ if ((inode->i_count > 1) && (flag & O_ACCMODE))
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if (!*p)
+ continue;
+ if (inode == (*p)->executable) {
+ iput(inode);
+ return -ETXTBSY;
+ }
+ for (i=0; i < (*p)->numlibraries; i++)
+ if (inode == (*p)->libraries[i].library) {
+ iput(inode);
+ return -ETXTBSY;
+ }
+ }
if (flag & O_TRUNC)
if (inode->i_op && inode->i_op->truncate) {
inode->i_size = 0;
inode->i_op->truncate(inode);
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
*res_inode = inode;
return 0;
}
-int sys_mknod(const char * filename, int mode, int dev)
+int do_mknod(const char * filename, int mode, int dev)
{
const char * basename;
int namelen;
struct inode * dir;
- if (!suser())
- return -EPERM;
if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
+int sys_mknod(const char * filename, int mode, int dev)
+{
+ if (S_ISFIFO(mode) || suser())
+ return do_mknod(filename,mode,dev);
+ return -EPERM;
+}
+
int sys_mkdir(const char * pathname, int mode)
{
const char * basename;
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
iput(dir);
return -EPERM;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
iput(dir);
return -ENOENT;
}
+ if (IS_RDONLY(dir)) {
+ iput(dir);
+ return -EROFS;
+ }
if (!permission(dir,MAY_WRITE)) {
iput(dir);
return -EACCES;
iput(dir);
return -EPERM;
}
+ if (IS_RDONLY(dir)) {
+ iput(oldinode);
+ iput(dir);
+ return -EROFS;
+ }
if (dir->i_dev != oldinode->i_dev) {
iput(dir);
iput(oldinode);
iput(new_dir);
return -EXDEV;
}
+ if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
+ iput(old_dir);
+ iput(new_dir);
+ return -EROFS;
+ }
if (!old_dir->i_op || !old_dir->i_op->rename) {
iput(old_dir);
iput(new_dir);
/*
* linux/fs/open.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <utime.h>
-
-#include <sys/stat.h>
-#include <sys/vfs.h>
-
+#include <linux/vfs.h>
+#include <linux/types.h>
+#include <linux/utime.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/signal.h>
#include <asm/segment.h>
int sys_statfs(const char * path, struct statfs * buf)
{
- printk("statfs not implemented\n");
- return -ENOSYS;
+ struct inode * inode;
+
+ verify_area(buf, sizeof(struct statfs));
+ if (!(inode = namei(path)))
+ return -ENOENT;
+ if (!inode->i_sb->s_op->statfs) {
+ iput(inode);
+ return -ENOSYS;
+ }
+ inode->i_sb->s_op->statfs(inode->i_sb, buf);
+ iput(inode);
+ return 0;
}
int sys_fstatfs(unsigned int fd, struct statfs * buf)
{
- printk("fstatfs not implemented\n");
- return -ENOSYS;
+ struct inode * inode;
+ struct file * file;
+
+ verify_area(buf, sizeof(struct statfs));
+ if (fd >= NR_OPEN || !(file = current->filp[fd]))
+ return -EBADF;
+ if (!(inode = file->f_inode))
+ return -ENOENT;
+ if (!inode->i_sb->s_op->statfs)
+ return -ENOSYS;
+ inode->i_sb->s_op->statfs(inode->i_sb, buf);
+ return 0;
}
int sys_truncate(const char * path, unsigned int length)
if (!(inode = namei(path)))
return -ENOENT;
- if (!permission(inode,MAY_WRITE)) {
+ if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
iput(inode);
- return -EPERM;
+ return -EACCES;
+ }
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
}
inode->i_size = length;
if (inode->i_op && inode->i_op->truncate)
return -EBADF;
if (!(inode = file->f_inode))
return -ENOENT;
- if (!(file->f_flags & 2))
- return -EPERM;
+ if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
+ return -EACCES;
inode->i_size = length;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
return 0;
}
+/* If times==NULL, set access and modification to current time,
+ * must be owner or have write permission.
+ * Else, update from *times, must be owner or super user.
+ */
int sys_utime(char * filename, struct utimbuf * times)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
if (times) {
- if (current->euid != inode->i_uid &&
- !permission(inode,MAY_WRITE)) {
+ if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
return -EPERM;
}
actime = get_fs_long((unsigned long *) ×->actime);
modtime = get_fs_long((unsigned long *) ×->modtime);
- } else
+ } else {
+ if ((current->euid != inode->i_uid) &&
+ !permission(inode,MAY_WRITE)) {
+ iput(inode);
+ return -EACCES;
+ }
actime = modtime = CURRENT_TIME;
+ }
inode->i_atime = actime;
inode->i_mtime = modtime;
inode->i_dirt = 1;
iput(inode);
if (current->uid == inode->i_uid)
res >>= 6;
- else if (current->gid == inode->i_gid)
- res >>= 6;
+ else if (in_group_p(inode->i_gid))
+ res >>= 3;
if ((res & 0007 & mode) == mode)
return 0;
/*
iput(inode);
return -ENOTDIR;
}
+ if (!permission(inode,MAY_EXEC)) {
+ iput(inode);
+ return -EACCES;
+ }
iput(current->pwd);
current->pwd = inode;
return (0);
iput(inode);
return -ENOTDIR;
}
+ if (!suser()) {
+ iput(inode);
+ return -EPERM;
+ }
iput(current->root);
current->root = inode;
return (0);
if (!(inode = file->f_inode))
return -ENOENT;
if ((current->euid != inode->i_uid) && !suser())
- return -EACCES;
+ return -EPERM;
+ if (IS_RDONLY(inode))
+ return -EROFS;
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
return 0;
return -ENOENT;
if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
- return -EACCES;
+ return -EPERM;
+ }
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
}
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
return -EBADF;
if (!(inode = file->f_inode))
return -ENOENT;
- if (!suser())
- return -EACCES;
- inode->i_uid = user;
- inode->i_gid = group;
- inode->i_dirt=1;
- return 0;
+ if (IS_RDONLY(inode))
+ return -EROFS;
+ 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 = namei(filename)))
+ if (!(inode = lnamei(filename)))
return -ENOENT;
- if (!suser()) {
+ if (IS_RDONLY(inode)) {
iput(inode);
- return -EACCES;
+ return -EROFS;
+ }
+ 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 0;
}
- inode->i_uid = user;
- inode->i_gid = group;
- inode->i_dirt = 1;
iput(inode);
- return 0;
+ return -EPERM;
}
int sys_open(const char * filename,int flag,int mode)
if (!current->filp[fd])
break;
if (fd>=NR_OPEN)
- return -EINVAL;
+ return -EMFILE;
current->close_on_exec &= ~(1<<fd);
- f=0+file_table;
- for (i=0 ; i<NR_FILE ; i++,f++)
- if (!f->f_count) break;
- if (i>=NR_FILE)
- return -EINVAL;
- (current->filp[fd] = f)->f_count++;
+ f = get_empty_filp();
+ if (!f)
+ return -ENFILE;
+ current->filp[fd] = f;
if ((i = open_namei(filename,flag,mode,&inode))<0) {
current->filp[fd]=NULL;
- f->f_count=0;
+ f->f_count--;
return i;
}
- f->f_op = NULL;
- if (inode)
- if (S_ISCHR(inode->i_mode)) {
- i = MAJOR(inode->i_rdev);
- if (i < MAX_CHRDEV)
- f->f_op = chrdev_fops[i];
- } else if (S_ISBLK(inode->i_mode)) {
- i = MAJOR(inode->i_rdev);
- if (i < MAX_CHRDEV)
- f->f_op = blkdev_fops[i];
- }
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;
+ f->f_count--;
current->filp[fd]=NULL;
return i;
}
int sys_close(unsigned int fd)
{
struct file * filp;
+ struct inode * inode;
if (fd >= NR_OPEN)
return -EINVAL;
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_op && filp->f_op->close)
- return filp->f_op->close(filp->f_inode,filp);
- iput(filp->f_inode);
+ if (filp->f_count == 0) {
+ printk("Close: file count is 0\n");
+ return 0;
+ }
+ if (filp->f_count > 1) {
+ filp->f_count--;
+ return 0;
+ }
+ inode = filp->f_inode;
+ if (filp->f_op && filp->f_op->release)
+ filp->f_op->release(inode,filp);
+ filp->f_count--;
+ filp->f_inode = NULL;
+ iput(inode);
return 0;
}
+
+int sys_vhangup(void)
+{
+ return -ENOSYS;
+}
/*
* linux/fs/pipe.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <signal.h>
-#include <errno.h>
-#include <termios.h>
-#include <fcntl.h>
-
#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
{
if (!(filp->f_flags & O_NONBLOCK))
while (!PIPE_SIZE(*inode)) {
wake_up(& PIPE_WRITE_WAIT(*inode));
- if (inode->i_count != 2) /* are there any writers? */
+ if (!PIPE_WRITERS(*inode)) /* are there any writers? */
return 0;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
chars = count;
if (chars > size)
chars = size;
- count -= chars;
+ memcpy_tofs(buf, (char *)inode->i_size+PIPE_TAIL(*inode), chars );
read += chars;
- size = PIPE_TAIL(*inode);
PIPE_TAIL(*inode) += chars;
PIPE_TAIL(*inode) &= (PAGE_SIZE-1);
- while (chars-->0)
- put_fs_byte(((char *)inode->i_size)[size++],buf++);
+ count -= chars;
+ buf += chars;
}
wake_up(& PIPE_WRITE_WAIT(*inode));
return read?read:-EAGAIN;
{
int chars, size, written = 0;
+ if (!PIPE_READERS(*inode)) { /* no readers */
+ send_sig(SIGPIPE,current,0);
+ return -EPIPE;
+ }
+/* if count < PAGE_SIZE, we have to make it atomic */
+ if (count < PAGE_SIZE)
+ size = PAGE_SIZE-count;
+ else
+ size = PAGE_SIZE-1;
while (count>0) {
- while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
- wake_up(& PIPE_READ_WAIT(*inode));
- if (inode->i_count != 2) { /* no readers */
- current->signal |= (1<<(SIGPIPE-1));
- return written?written:-EINTR;
+ while (PIPE_SIZE(*inode) >= size) {
+ if (!PIPE_READERS(*inode)) { /* no readers */
+ send_sig(SIGPIPE,current,0);
+ return written?written:-EPIPE;
}
if (current->signal & ~current->blocked)
- return written?written:-EINTR;
- interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
+ return written?written:-ERESTARTSYS;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ else
+ interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
}
- chars = PAGE_SIZE-PIPE_HEAD(*inode);
- if (chars > count)
- chars = count;
- if (chars > size)
- chars = size;
- count -= chars;
- written += chars;
- size = PIPE_HEAD(*inode);
- PIPE_HEAD(*inode) += chars;
- PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
- while (chars-->0)
- ((char *)inode->i_size)[size++]=get_fs_byte(buf++);
+ while (count>0 && (size = (PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
+ chars = PAGE_SIZE-PIPE_HEAD(*inode);
+ if (chars > count)
+ chars = count;
+ if (chars > size)
+ chars = size;
+ memcpy_fromfs((char *)inode->i_size+PIPE_HEAD(*inode), buf, chars );
+ written += chars;
+ PIPE_HEAD(*inode) += chars;
+ PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
+ count -= chars;
+ buf += chars;
+ }
+ wake_up(& PIPE_READ_WAIT(*inode));
+ size = PAGE_SIZE-1;
}
- wake_up(& PIPE_READ_WAIT(*inode));
return written;
}
}
}
-static struct file_operations read_pipe_fops = {
+static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+{
+ switch (sel_type) {
+ case SEL_IN:
+ if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
+ return 1;
+ select_wait(&PIPE_READ_WAIT(*inode), wait);
+ return 0;
+ case SEL_OUT:
+ if (!PIPE_FULL(*inode) || !PIPE_WRITERS(*inode))
+ return 1;
+ select_wait(&PIPE_WRITE_WAIT(*inode), wait);
+ return 0;
+ case SEL_EX:
+ if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
+ return 1;
+ select_wait(&inode->i_wait,wait);
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * Ok, these three routines NOW keep track of readers/writers,
+ * Linus previously did it with inode->i_count checking.
+ */
+static void pipe_read_release(struct inode * inode, struct file * filp)
+{
+ PIPE_READERS(*inode)--;
+ wake_up(&PIPE_WRITE_WAIT(*inode));
+}
+
+static void pipe_write_release(struct inode * inode, struct file * filp)
+{
+ PIPE_WRITERS(*inode)--;
+ wake_up(&PIPE_READ_WAIT(*inode));
+}
+
+static void pipe_rdwr_release(struct inode * inode, struct file * filp)
+{
+ PIPE_READERS(*inode)--;
+ PIPE_WRITERS(*inode)--;
+ wake_up(&PIPE_READ_WAIT(*inode));
+ wake_up(&PIPE_WRITE_WAIT(*inode));
+}
+
+/*
+ * The three file_operations structs are not static because they
+ * are also used in linux/fs/fifo.c to do operations on fifo's.
+ */
+struct file_operations read_pipe_fops = {
pipe_lseek,
pipe_read,
bad_pipe_rw,
pipe_readdir,
- NULL, /* pipe_close */
- NULL, /* pipe_select */
- pipe_ioctl
+ pipe_select,
+ pipe_ioctl,
+ NULL, /* no special open code */
+ pipe_read_release
};
-static struct file_operations write_pipe_fops = {
+struct file_operations write_pipe_fops = {
pipe_lseek,
bad_pipe_rw,
pipe_write,
pipe_readdir,
- NULL, /* pipe_close */
- NULL, /* pipe_select */
- pipe_ioctl
+ pipe_select,
+ pipe_ioctl,
+ NULL, /* no special open code */
+ pipe_write_release
+};
+
+struct file_operations rdwr_pipe_fops = {
+ pipe_lseek,
+ pipe_read,
+ pipe_write,
+ pipe_readdir,
+ pipe_select,
+ pipe_ioctl,
+ NULL, /* no special open code */
+ pipe_rdwr_release
};
int sys_pipe(unsigned long * fildes)
int fd[2];
int i,j;
- j=0;
- for(i=0;j<2 && i<NR_FILE;i++)
- if (!file_table[i].f_count)
- (f[j++]=i+file_table)->f_count++;
+ verify_area(fildes,8);
+ for(j=0 ; j<2 ; j++)
+ if (!(f[j] = get_empty_filp()))
+ break;
if (j==1)
- f[0]->f_count=0;
+ f[0]->f_count--;
if (j<2)
- return -1;
+ return -ENFILE;
j=0;
for(i=0;j<2 && i<NR_OPEN;i++)
if (!current->filp[i]) {
if (j==1)
current->filp[fd[0]]=NULL;
if (j<2) {
- f[0]->f_count=f[1]->f_count=0;
- return -1;
+ f[0]->f_count--;
+ f[1]->f_count--;
+ return -EMFILE;
}
if (!(inode=get_pipe_inode())) {
- current->filp[fd[0]] =
- current->filp[fd[1]] = NULL;
- f[0]->f_count = f[1]->f_count = 0;
- return -1;
+ current->filp[fd[0]] = NULL;
+ current->filp[fd[1]] = NULL;
+ f[0]->f_count--;
+ f[1]->f_count--;
+ return -ENFILE;
}
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
+ f[0]->f_flags = f[1]->f_flags = 0;
f[0]->f_op = &read_pipe_fops;
f[0]->f_mode = 1; /* read */
f[1]->f_op = &write_pipe_fops;
/*
* linux/fs/read_write.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/dirent.h>
-
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
+
#include <asm/segment.h>
/*
int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
struct file * file;
- int tmp;
+ int tmp = -1;
if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode))
return -EBADF;
if (tmp < 0)
return -EINVAL;
file->f_pos = tmp;
+ file->f_reada = 0;
return file->f_pos;
}
verify_area(buf,count);
if (file->f_op && file->f_op->read)
return file->f_op->read(inode,file,buf,count);
- printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
return 0;
if (file->f_op && file->f_op->write)
return file->f_op->write(inode,file,buf,count);
- printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
* patches by Peter MacDonald. Heavily edited by Linus.
*/
+#include <linux/types.h>
+#include <linux/time.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
#include <asm/segment.h>
#include <asm/system.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-
#include <const.h>
-#include <errno.h>
-#include <signal.h>
/*
* Ok, Peter made a complicated, but straightforward multiple_wait() function.
* understand what I'm doing here, then you understand how the linux sleep/wakeup
* mechanism works.
*
- * Two very simple procedures, add_wait() and free_wait() make all the work. We
- * have to have interrupts disabled throughout the select, but that's not really
- * such a loss: sleeping automatically frees interrupts when we aren't in this
- * task.
+ * Two very simple procedures, select_wait() and free_wait() make all the work.
+ * select_wait() is a inline-function defined in <linux/fs.h>, as all select
+ * functions have to call it to add an entry to the select table.
*/
-static select_table * sel_tables = NULL;
-
-static void add_wait(struct task_struct ** wait_address, select_table * p)
-{
- int i;
-
- if (!wait_address)
- return;
- for (i = 0 ; i < p->nr ; i++)
- if (p->entry[i].wait_address == wait_address)
- return;
- current->next_wait = NULL;
- p->entry[p->nr].wait_address = wait_address;
- p->entry[p->nr].old_task = *wait_address;
- *wait_address = current;
- p->nr++;
-}
-
-/*
- * free_wait removes the current task from any wait-queues and then
- * wakes up the queues.
- */
-static void free_one_table(select_table * p)
-{
- int i;
- struct task_struct ** tpp;
-
- for(tpp = &LAST_TASK ; tpp > &FIRST_TASK ; --tpp)
- if (*tpp && ((*tpp)->next_wait == p->current))
- (*tpp)->next_wait = NULL;
- if (!p->nr)
- return;
- for (i = 0; i < p->nr ; i++) {
- wake_up(p->entry[i].wait_address);
- wake_up(&p->entry[i].old_task);
- }
- p->nr = 0;
-}
-
static void free_wait(select_table * p)
{
- select_table * tmp;
+ struct select_table_entry * entry = p->entry + p->nr;
- if (p->woken)
- return;
- p = sel_tables;
- sel_tables = NULL;
- while (p) {
- wake_up(&p->current);
- p->woken = 1;
- tmp = p->next_table;
- p->next_table = NULL;
- free_one_table(p);
- p = tmp;
+ while (p->nr > 0) {
+ p->nr--;
+ entry--;
+ remove_wait_queue(entry->wait_address,&entry->wait);
}
}
-static struct tty_struct * get_tty(struct inode * inode)
-{
- int major, minor;
-
- if (!S_ISCHR(inode->i_mode))
- return NULL;
- if ((major = MAJOR(inode->i_rdev)) != 5 && major != 4)
- return NULL;
- if (major == 5)
- minor = current->tty;
- else
- minor = MINOR(inode->i_rdev);
- if (minor < 0)
- return NULL;
- return TTY_TABLE(minor);
-}
-
/*
* The check_XX functions check out a file. We know it's either
- * a pipe, a character device or a fifo (fifo's not implemented)
+ * a pipe, a character device or a fifo
*/
-static int check_in(select_table * wait, struct inode * inode)
+static int check_in(select_table * wait, struct inode * inode, struct file * file)
{
- struct tty_struct * tty;
-
- if (tty = get_tty(inode))
- if (!EMPTY(tty->secondary))
- return 1;
- else
- add_wait(&tty->secondary->proc_list, wait);
- else if (inode->i_pipe)
- if (!PIPE_EMPTY(*inode) || inode->i_count < 2)
- return 1;
- else
- add_wait(&inode->i_wait, wait);
+ if (file->f_op && file->f_op->select)
+ return file->f_op->select(inode,file,SEL_IN,wait);
return 0;
}
-static int check_out(select_table * wait, struct inode * inode)
+static int check_out(select_table * wait, struct inode * inode, struct file * file)
{
- struct tty_struct * tty;
-
- if (tty = get_tty(inode))
- if (!FULL(tty->write_q))
- return 1;
- else
- add_wait(&tty->write_q->proc_list, wait);
- else if (inode->i_pipe)
- if (!PIPE_FULL(*inode))
- return 1;
- else
- add_wait(&inode->i_wait, wait);
+ if (file->f_op && file->f_op->select)
+ return file->f_op->select(inode,file,SEL_OUT,wait);
return 0;
}
-static int check_ex(select_table * wait, struct inode * inode)
+static int check_ex(select_table * wait, struct inode * inode, struct file * file)
{
- struct tty_struct * tty;
-
- if (tty = get_tty(inode))
- if (!FULL(tty->write_q))
- return 0;
- else
- return 0;
- else if (inode->i_pipe)
- if (inode->i_count < 2)
- return 1;
- else
- add_wait(&inode->i_wait,wait);
+ if (file->f_op && file->f_op->select)
+ return file->f_op->select(inode,file,SEL_EX,wait);
return 0;
}
{
int count;
select_table wait_table;
+ struct file * file;
int i;
fd_set mask;
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:
wait_table.nr = 0;
- wait_table.woken = 0;
- wait_table.current = current;
- wait_table.next_table = sel_tables;
- 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) {
+ file = current->filp[i];
if (mask & in)
- if (check_in(&wait_table,current->filp[i]->f_inode)) {
+ if (check_in(&wait_table,file->f_inode,file)) {
*inp |= mask;
count++;
}
if (mask & out)
- if (check_out(&wait_table,current->filp[i]->f_inode)) {
+ if (check_out(&wait_table,file->f_inode,file)) {
*outp |= mask;
count++;
}
if (mask & ex)
- if (check_ex(&wait_table,current->filp[i]->f_inode)) {
+ if (check_ex(&wait_table,file->f_inode,file)) {
*exp |= mask;
count++;
}
}
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;
}
/*
- * Note that we cannot return -ERESTARTSYS, as we change our input
- * parameters. Sad, but there you are. We could do some tweaking in
- * the library function ...
+ * We can actually return ERESTARTSYS insetad of EINTR, but I'd
+ * like to be certain this leads to no problems. So I return
+ * EINTR just for safety.
*/
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 (tvp) {
+ verify_area(tvp, sizeof(*tvp));
+ put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
+ timeout %= HZ;
+ timeout *= (1000000/HZ);
+ put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
+ }
if (i < 0)
return i;
+ if (!i && (current->signal & ~current->blocked))
+ return -EINTR;
if (inp) {
verify_area(inp, 4);
put_fs_long(res_in,inp);
verify_area(exp,4);
put_fs_long(res_ex,exp);
}
- if (tvp) {
- verify_area(tvp, sizeof(*tvp));
- put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
- timeout %= HZ;
- timeout *= (1000000/HZ);
- put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
- }
- if (i)
- return i;
- if (current->signal & ~current->blocked)
- return -EINTR;
- return 0;
+ return i;
}
/*
* linux/fs/stat.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-#include <sys/stat.h>
-
+#include <linux/errno.h>
+#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
-static void cp_stat(struct inode * inode, struct stat * statbuf)
+static void cp_old_stat(struct inode * inode, struct old_stat * statbuf)
{
- struct stat tmp;
- int i;
+ struct old_stat tmp;
- verify_area(statbuf,sizeof (struct stat));
+ if (inode->i_ino & 0xffff0000)
+ printk("Warning: using old stat() call on bigfs\n");
+ verify_area(statbuf,sizeof (*statbuf));
tmp.st_dev = inode->i_dev;
tmp.st_ino = inode->i_ino;
tmp.st_mode = inode->i_mode;
tmp.st_uid = inode->i_uid;
tmp.st_gid = inode->i_gid;
tmp.st_rdev = inode->i_rdev;
- tmp.st_size = inode->i_size;
+ if( S_ISFIFO(inode->i_mode) )
+ tmp.st_size = 0;
+ else
+ tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
- for (i=0 ; i<sizeof (tmp) ; i++)
- put_fs_byte(((char *) &tmp)[i],i + (char *) statbuf);
+ memcpy_tofs(statbuf,&tmp,sizeof(tmp));
+}
+
+static void cp_new_stat(struct inode * inode, struct new_stat * statbuf)
+{
+ struct new_stat tmp = {0, };
+ unsigned int blocks, indirect;
+
+ verify_area(statbuf,sizeof (*statbuf));
+ tmp.st_dev = inode->i_dev;
+ tmp.st_ino = inode->i_ino;
+ tmp.st_mode = inode->i_mode;
+ tmp.st_nlink = inode->i_nlink;
+ tmp.st_uid = inode->i_uid;
+ tmp.st_gid = inode->i_gid;
+ tmp.st_rdev = inode->i_rdev;
+ if( S_ISFIFO(inode->i_mode) )
+ tmp.st_size = 0;
+ else
+ tmp.st_size = inode->i_size;
+ tmp.st_atime = inode->i_atime;
+ tmp.st_mtime = inode->i_mtime;
+ tmp.st_ctime = inode->i_ctime;
+/*
+ * Right now we fake the st_blocks numbers: we'll eventually have to
+ * add st_blocks to the inode, and let the vfs routines keep track of
+ * it all. This algorithm doesn't guarantee correct block numbers, but
+ * at least it tries to come up with a plausible answer...
+ *
+ * In fact, the minix fs doesn't use these numbers (it uses 7 and 512
+ * instead of 10 and 256), but who cares... It's not that exact anyway.
+ */
+ blocks = (tmp.st_size + 1023) / 1024;
+ if (blocks > 10) {
+ indirect = (blocks - 11)/256+1;
+ if (blocks > 10+256) {
+ indirect += (blocks - 267)/(256*256)+1;
+ if (blocks > 10+256+256*256)
+ indirect++;
+ }
+ blocks += indirect;
+ }
+ tmp.st_blksize = 1024;
+ tmp.st_blocks = blocks;
+ memcpy_tofs(statbuf,&tmp,sizeof(tmp));
+}
+
+int sys_stat(char * filename, struct old_stat * statbuf)
+{
+ struct inode * inode;
+
+ if (!(inode=namei(filename)))
+ return -ENOENT;
+ cp_old_stat(inode,statbuf);
+ iput(inode);
+ return 0;
}
-int sys_stat(char * filename, struct stat * statbuf)
+int sys_newstat(char * filename, struct new_stat * statbuf)
{
struct inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
- cp_stat(inode,statbuf);
+ cp_new_stat(inode,statbuf);
iput(inode);
return 0;
}
-int sys_lstat(char * filename, struct stat * statbuf)
+int sys_lstat(char * filename, struct old_stat * statbuf)
{
struct inode * inode;
if (!(inode = lnamei(filename)))
return -ENOENT;
- cp_stat(inode,statbuf);
+ cp_old_stat(inode,statbuf);
iput(inode);
return 0;
}
-int sys_fstat(unsigned int fd, struct stat * statbuf)
+int sys_newlstat(char * filename, struct new_stat * statbuf)
+{
+ struct inode * inode;
+
+ if (!(inode = lnamei(filename)))
+ return -ENOENT;
+ cp_new_stat(inode,statbuf);
+ iput(inode);
+ return 0;
+}
+
+int sys_fstat(unsigned int fd, struct old_stat * statbuf)
+{
+ struct file * f;
+ struct inode * inode;
+
+ if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
+ return -EBADF;
+ cp_old_stat(inode,statbuf);
+ return 0;
+}
+
+int sys_newfstat(unsigned int fd, struct new_stat * statbuf)
{
struct file * f;
struct inode * inode;
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
return -EBADF;
- cp_stat(inode,statbuf);
+ cp_new_stat(inode,statbuf);
return 0;
}
/*
* linux/fs/super.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
+#include <linux/ext_fs.h>
+#include <linux/msdos_fs.h>
#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+
#include <asm/system.h>
#include <asm/segment.h>
-#include <errno.h>
-#include <sys/stat.h>
-
int sync_dev(int dev);
void wait_for_keypress(void);
static struct file_system_type file_systems[] = {
{minix_read_super,"minix"},
+ {ext_read_super,"ext"},
+ {msdos_read_super,"msdos"},
{NULL,NULL}
};
void free_super(struct super_block * sb)
{
- cli();
sb->s_lock = 0;
wake_up(&(sb->s_wait));
- sti();
}
void wait_on_super(struct super_block * sb)
sb->s_op->put_super(sb);
}
-static struct super_block * read_super(int dev,char *name,void *data)
+static struct super_block * read_super(int dev,char *name,int flags,void *data)
{
struct super_block * s;
struct file_system_type *type;
break;
}
s->s_dev = dev;
+ s->s_flags = flags;
if (!type->read_super(s,data))
return(NULL);
s->s_dev = dev;
s->s_covered = NULL;
- s->s_time = 0;
s->s_rd_only = 0;
s->s_dirt = 0;
return(s);
}
-int sys_umount(char * dev_name)
+static int do_umount(int dev)
{
- struct inode * inode;
struct super_block * sb;
- int dev;
+ struct inode * inode;
- if (!suser())
- return -EPERM;
- if (!(inode = namei(dev_name)))
- return -ENOENT;
- dev = inode->i_rdev;
- if (!S_ISBLK(inode->i_mode)) {
- iput(inode);
- return -ENOTBLK;
- }
- iput(inode);
if (dev==ROOT_DEV)
return -EBUSY;
if (!(sb=get_super(dev)) || !(sb->s_covered))
sb->s_covered = NULL;
iput(sb->s_mounted);
sb->s_mounted = NULL;
+ if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
+ sb->s_op->write_super (sb);
put_super(dev);
- sync_dev(dev);
return 0;
}
-int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag)
+int sys_umount(char * dev_name)
{
- struct inode * dev_i, * dir_i;
- struct super_block * sb;
- int dev;
- char tmp[100],*t;
- int i;
+ struct inode * inode;
+ int dev,retval;
if (!suser())
return -EPERM;
- if (!(dev_i = namei(dev_name)))
+ if (!(inode = namei(dev_name)))
return -ENOENT;
- dev = dev_i->i_rdev;
- if (!S_ISBLK(dev_i->i_mode)) {
- iput(dev_i);
- return -EPERM;
+ dev = inode->i_rdev;
+ if (!S_ISBLK(inode->i_mode)) {
+ iput(inode);
+ return -ENOTBLK;
}
- iput(dev_i);
- if (!(dir_i=namei(dir_name)))
+ retval = do_umount(dev);
+ if (!retval && MAJOR(dev) < MAX_BLKDEV &&
+ blkdev_fops[MAJOR(dev)]->release)
+ blkdev_fops[MAJOR(dev)]->release(inode,NULL);
+ iput(inode);
+ if (retval) return retval;
+ sync_dev(dev);
+ return 0;
+}
+
+/*
+ * do_mount() does the actual mounting after sys_mount has done the ugly
+ * parameter parsing. When enough time has gone by, and everything uses the
+ * new mount() parameters, sys_mount() can then be cleaned up.
+ *
+ * We cannot mount a filesystem if it has active, used, or dirty inodes.
+ * We also have to flush all inode-data for this device, as the new mount
+ * might need new info.
+ */
+static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
+{
+ struct inode * inode, * dir_i;
+ struct super_block * sb;
+
+ if (!(dir_i = namei(dir)))
return -ENOENT;
- if (dir_i->i_count != 1 || dir_i->i_ino == MINIX_ROOT_INO) {
+ if (dir_i->i_count != 1 || dir_i->i_mount) {
iput(dir_i);
return -EBUSY;
}
iput(dir_i);
return -EPERM;
}
- if (dir_i->i_mount) {
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
+ if (inode->i_dev != dev)
+ continue;
+ if (inode->i_count || inode->i_dirt || inode->i_lock) {
+ iput(dir_i);
+ return -EBUSY;
+ }
+ inode->i_dev = 0;
+ }
+ sb = read_super(dev,type,flags,data);
+ if (!sb || sb->s_covered) {
iput(dir_i);
+ return -EBUSY;
+ }
+ sb->s_flags = flags;
+ sb->s_covered = dir_i;
+ dir_i->i_mount = 1;
+ return 0; /* we don't iput(dir_i) - see umount */
+}
+
+/*
+ * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
+ * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
+ *
+ * data is a (void *) that can point to any structure up to 4095 bytes, which
+ * can contain arbitrary fs-dependent information (or be NULL).
+ *
+ * NOTE! As old versions of mount() didn't use this setup, the flags has to have
+ * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word
+ * isn't present, the flags and data info isn't used, as the syscall assumes we
+ * are talking to an older version that didn't understand them.
+ */
+int sys_mount(char * dev_name, char * dir_name, char * type,
+ unsigned long new_flags, void *data)
+{
+ struct inode * inode;
+ int dev;
+ int retval = 0;
+ char tmp[100],*t;
+ int i;
+ unsigned long flags = 0;
+ unsigned long page = 0;
+
+ if (!suser())
return -EPERM;
+ if (!(inode = namei(dev_name)))
+ return -ENOENT;
+ dev = inode->i_rdev;
+ if (!S_ISBLK(inode->i_mode))
+ retval = -EPERM;
+ else if (IS_NODEV(inode))
+ retval = -EACCES;
+ if (!retval && blkdev_fops[MAJOR(dev)]->open)
+ retval = blkdev_fops[MAJOR(dev)]->open(inode,NULL);
+ if (retval) {
+ iput(inode);
+ return retval;
+ }
+ if ((new_flags & 0xffff0000) == 0xC0ED0000) {
+ flags = new_flags & 0xffff;
+ if (data && (unsigned long) data < TASK_SIZE)
+ page = get_free_page(GFP_KERNEL);
+ }
+ if (page) {
+ i = TASK_SIZE - (unsigned long) data;
+ if (i < 0 || i > 4095)
+ i = 4095;
+ memcpy_fromfs((void *) page,data,i);
}
if (type) {
- i = 0;
- while (i < 100 && (tmp[i] = get_fs_byte(type++)))
- i++;
+ for (i = 0 ; i < 100 ; i++)
+ if (!(tmp[i] = get_fs_byte(type++)))
+ break;
t = tmp;
} else
t = "minix";
- if (!(sb = read_super(dev,t,NULL))) {
- iput(dir_i);
- return -EBUSY;
- }
- if (sb->s_covered) {
- iput(dir_i);
- return -EBUSY;
- }
- sb->s_covered = dir_i;
- dir_i->i_mount = 1;
- dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */
- return 0; /* we do that in umount */
+ retval = do_mount(dev,dir_name,t,flags,(void *) page);
+ free_page(page);
+ if (retval && blkdev_fops[MAJOR(dev)]->release)
+ blkdev_fops[MAJOR(dev)]->release(inode,NULL);
+ iput(inode);
+ return retval;
}
void mount_root(void)
{
- int i,free;
+ int i;
+ struct file_system_type * fs_type = file_systems;
struct super_block * p;
struct inode * mi;
}
for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
p->s_dev = 0;
+ p->s_blocksize = 0;
p->s_lock = 0;
p->s_wait = NULL;
+ p->s_mounted = p->s_covered = NULL;
+ }
+ while (fs_type->read_super && fs_type->name) {
+ p = read_super(ROOT_DEV,fs_type->name,0,NULL);
+ if (p) {
+ mi = p->s_mounted;
+ mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
+ p->s_covered = mi;
+ p->s_flags = 0;
+ current->pwd = mi;
+ current->root = mi;
+ return;
+ }
+ fs_type++;
}
- if (!(p=read_super(ROOT_DEV,"minix",NULL)))
- panic("Unable to mount root");
- /*wait_for_keypress();
- if (!(mi=iget(ROOT_DEV,MINIX_ROOT_INO)))
- panic("Unable to read root i-node");
- wait_for_keypress();*/
- mi=p->s_mounted;
- mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
- p->s_mounted = p->s_covered = mi;
- current->pwd = mi;
- current->root = mi;
- free=0;
- i=p->s_nzones;
- while (-- i >= 0)
- if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
- free++;
- printk("%d/%d free blocks\n\r",free,p->s_nzones);
- free=0;
- i=p->s_ninodes+1;
- while (-- i >= 0)
- if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
- free++;
- printk("%d/%d free inodes\n\r",free,p->s_ninodes);
+ panic("Unable to mount root");
}
+++ /dev/null
-#ifndef __A_OUT_GNU_H__
-#define __A_OUT_GNU_H__
-
-#define __GNU_EXEC_MACROS__
-
-#ifndef __STRUCT_EXEC_OVERRIDE__
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#endif /* __STRUCT_EXEC_OVERRIDE__ */
-
-/* these go in the N_MACHTYPE field */
-enum machine_type {
-#if defined (M_OLDSUN2)
- M__OLDSUN2 = M_OLDSUN2,
-#else
- M_OLDSUN2 = 0,
-#endif
-#if defined (M_68010)
- M__68010 = M_68010,
-#else
- M_68010 = 1,
-#endif
-#if defined (M_68020)
- M__68020 = M_68020,
-#else
- M_68020 = 2,
-#endif
-#if defined (M_SPARC)
- M__SPARC = M_SPARC,
-#else
- M_SPARC = 3,
-#endif
- /* skip a bunch so we don't run into any of sun's numbers */
- M_386 = 100,
-};
-
-#if !defined (N_MAGIC)
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#endif
-#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
-#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
-#define N_SET_INFO(exec, magic, type, flags) \
- ((exec).a_info = ((magic) & 0xffff) \
- | (((int)(type) & 0xff) << 16) \
- | (((flags) & 0xff) << 24))
-#define N_SET_MAGIC(exec, magic) \
- ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
-
-#define N_SET_MACHTYPE(exec, machtype) \
- ((exec).a_info = \
- ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
-
-#define N_SET_FLAGS(exec, flags) \
- ((exec).a_info = \
- ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
-
-/* Code indicating object file or impure executable. */
-#define OMAGIC 0407
-/* Code indicating pure executable. */
-#define NMAGIC 0410
-/* Code indicating demand-paged executable. */
-#define ZMAGIC 0413
-
-#if !defined (N_BADMAG)
-#define N_BADMAG(x) \
- (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
- && N_MAGIC(x) != ZMAGIC)
-#endif
-
-#define _N_BADMAG(x) \
- (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
- && N_MAGIC(x) != ZMAGIC)
-
-#define _N_HDROFF(x) (1024 - sizeof (struct exec))
-
-#if !defined (N_TXTOFF)
-#define N_TXTOFF(x) \
- (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
-#endif
-
-#if !defined (N_DATOFF)
-#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
-#endif
-
-#if !defined (N_TRELOFF)
-#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
-#endif
-
-#if !defined (N_DRELOFF)
-#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
-#endif
-
-#if !defined (N_SYMOFF)
-#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
-#endif
-
-#if !defined (N_STROFF)
-#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
-#endif
-
-/* Address of text segment in memory after it is loaded. */
-#if !defined (N_TXTADDR)
-#define N_TXTADDR(x) 0
-#endif
-
-/* Address of data segment in memory after it is loaded.
- Note that it is up to you to define SEGMENT_SIZE
- on machines not listed here. */
-#if defined(vax) || defined(hp300) || defined(pyr)
-#define SEGMENT_SIZE page_size
-#endif
-#ifdef sony
-#define SEGMENT_SIZE 0x2000
-#endif /* Sony. */
-#ifdef is68k
-#define SEGMENT_SIZE 0x20000
-#endif
-#if defined(m68k) && defined(PORTAR)
-#define PAGE_SIZE 0x400
-#define SEGMENT_SIZE PAGE_SIZE
-#endif
-
-#ifdef linux
-#define PAGE_SIZE 4096
-#define SEGMENT_SIZE 1024
-#endif
-
-#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
-
-#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
-
-#ifndef N_DATADDR
-#define N_DATADDR(x) \
- (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
- : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
-#endif
-
-/* Address of bss segment in memory after it is loaded. */
-#if !defined (N_BSSADDR)
-#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
-#endif
-\f
-#if !defined (N_NLIST_DECLARED)
-struct nlist {
- union {
- char *n_name;
- struct nlist *n_next;
- long n_strx;
- } n_un;
- unsigned char n_type;
- char n_other;
- short n_desc;
- unsigned long n_value;
-};
-#endif /* no N_NLIST_DECLARED. */
-
-#if !defined (N_UNDF)
-#define N_UNDF 0
-#endif
-#if !defined (N_ABS)
-#define N_ABS 2
-#endif
-#if !defined (N_TEXT)
-#define N_TEXT 4
-#endif
-#if !defined (N_DATA)
-#define N_DATA 6
-#endif
-#if !defined (N_BSS)
-#define N_BSS 8
-#endif
-#if !defined (N_FN)
-#define N_FN 15
-#endif
-
-#if !defined (N_EXT)
-#define N_EXT 1
-#endif
-#if !defined (N_TYPE)
-#define N_TYPE 036
-#endif
-#if !defined (N_STAB)
-#define N_STAB 0340
-#endif
-
-/* The following type indicates the definition of a symbol as being
- an indirect reference to another symbol. The other symbol
- appears as an undefined reference, immediately following this symbol.
-
- Indirection is asymmetrical. The other symbol's value will be used
- to satisfy requests for the indirect symbol, but not vice versa.
- If the other symbol does not have a definition, libraries will
- be searched to find a definition. */
-#define N_INDR 0xa
-
-/* The following symbols refer to set elements.
- All the N_SET[ATDB] symbols with the same name form one set.
- Space is allocated for the set in the text section, and each set
- element's value is stored into one word of the space.
- The first word of the space is the length of the set (number of elements).
-
- The address of the set is made into an N_SETV symbol
- whose name is the same as the name of the set.
- This symbol acts like a N_DATA global symbol
- in that it can satisfy undefined external references. */
-
-/* These appear as input to LD, in a .o file. */
-#define N_SETA 0x14 /* Absolute set element symbol */
-#define N_SETT 0x16 /* Text set element symbol */
-#define N_SETD 0x18 /* Data set element symbol */
-#define N_SETB 0x1A /* Bss set element symbol */
-
-/* This is output from LD. */
-#define N_SETV 0x1C /* Pointer to set vector in data area. */
-\f
-#if !defined (N_RELOCATION_INFO_DECLARED)
-/* This structure describes a single relocation to be performed.
- The text-relocation section of the file is a vector of these structures,
- all of which apply to the text section.
- Likewise, the data-relocation section applies to the data section. */
-
-struct relocation_info
-{
- /* Address (within segment) to be relocated. */
- int r_address;
- /* The meaning of r_symbolnum depends on r_extern. */
- unsigned int r_symbolnum:24;
- /* Nonzero means value is a pc-relative offset
- and it should be relocated for changes in its own address
- as well as for changes in the symbol or section specified. */
- unsigned int r_pcrel:1;
- /* Length (as exponent of 2) of the field to be relocated.
- Thus, a value of 2 indicates 1<<2 bytes. */
- unsigned int r_length:2;
- /* 1 => relocate with value of symbol.
- r_symbolnum is the index of the symbol
- in file's the symbol table.
- 0 => relocate with the address of a segment.
- r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
- (the N_EXT bit may be set also, but signifies nothing). */
- unsigned int r_extern:1;
- /* Four bits that aren't used, but when writing an object file
- it is desirable to clear them. */
-#ifdef NS32K
- unsigned r_bsr:1;
- unsigned r_disp:1;
- unsigned r_pad:2;
-#else
- unsigned int r_pad:4;
-#endif
-};
-#endif /* no N_RELOCATION_INFO_DECLARED. */
-
-
-#endif /* __A_OUT_GNU_H__ */
#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"
+__asm__ __volatile__ ("outb %0,%1"
::"a" ((char) value),"d" ((unsigned short) port));
}
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"
+#ifdef REALLY_SLOW_IO
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+#endif
+ "outb %0,$0x80"
::"a" ((char) value),"d" ((unsigned short) port));
}
extern unsigned char inline inb(unsigned short port)
{
unsigned char _v;
-__asm__ volatile ("inb %1,%0"
+__asm__ __volatile__ ("inb %1,%0"
:"=a" (_v):"d" ((unsigned short) port));
return _v;
}
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"
+#ifdef REALLY_SLOW_IO
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+#endif
+ "outb %0,$0x80"
:"=a" (_v):"d" ((unsigned short) port));
return _v;
}
--- /dev/null
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+/*
+ * linux/include/asm/irq.h
+ *
+ * (C) 1992 Linus Torvalds
+ */
+
+#define SAVE_ALL \
+ "cld\n\t" \
+ "push %gs\n\t" \
+ "push %fs\n\t" \
+ "push %es\n\t" \
+ "push %ds\n\t" \
+ "pushl %eax\n\t" \
+ "pushl %ebp\n\t" \
+ "pushl %edi\n\t" \
+ "pushl %esi\n\t" \
+ "pushl %edx\n\t" \
+ "pushl %ecx\n\t" \
+ "pushl %ebx\n\t" \
+ "movl $0x10,%edx\n\t" \
+ "mov %dx,%ds\n\t" \
+ "mov %dx,%es\n\t" \
+ "movl $0x17,%edx\n\t" \
+ "mov %dx,%fs\n\t"
+
+/*
+ * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
+ * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
+ * call the routines that do signal handling etc on return, and can have
+ * more relaxed register-saving etc. They are also atomic, and are thus
+ * suited for small, fast interrupts like the serial lines or the harddisk
+ * drivers, which don't actually need signal handling etc.
+ *
+ * Also note that we actually save only those registers that are used in
+ * C subroutines (%eax, %edx and %ecx), so if you do something weird,
+ * you're on your own. The only segments that are saved (not counting the
+ * automatic stack and code segment handling) are %ds and %es, and they
+ * point to kernel space. No messing around with %fs here.
+ */
+#define SAVE_MOST \
+ "cld\n\t" \
+ "push %es\n\t" \
+ "push %ds\n\t" \
+ "pushl %eax\n\t" \
+ "pushl %edx\n\t" \
+ "pushl %ecx\n\t" \
+ "movl $0x10,%edx\n\t" \
+ "mov %dx,%ds\n\t" \
+ "mov %dx,%es\n\t"
+
+#define RESTORE_MOST \
+ "popl %ecx\n\t" \
+ "popl %edx\n\t" \
+ "popl %eax\n\t" \
+ "pop %ds\n\t" \
+ "pop %es\n\t" \
+ "iret"
+
+#define ACK_FIRST(mask) \
+ "inb $0x21,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ",%al\n\t" \
+ "outb %al,$0x21\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0x20\n\t"
+
+#define ACK_SECOND(mask) \
+ "inb $0xA1,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ",%al\n\t" \
+ "outb %al,$0xA1\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0xA0\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\toutb %al,$0x20\n\t"
+
+#define UNBLK_FIRST(mask) \
+ "inb $0x21,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tandb $~(" #mask "),%al\n\t" \
+ "outb %al,$0x21\n\t"
+
+#define UNBLK_SECOND(mask) \
+ "inb $0xA1,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tandb $~(" #mask "),%al\n\t" \
+ "outb %al,$0xA1\n\t"
+
+#define IRQ_NAME2(nr) nr##_interrupt()
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
+#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
+
+#define BUILD_IRQ(chip,nr,mask) \
+void IRQ_NAME(nr); \
+void FAST_IRQ_NAME(nr); \
+void BAD_IRQ_NAME(nr); \
+__asm__( \
+"\n.align 2\n" \
+"_IRQ" #nr "_interrupt:\n\t" \
+ "pushl $-1\n\t" \
+ SAVE_ALL \
+ ACK_##chip(mask) \
+ "sti\n\t" \
+ "movl %esp,%ebx\n\t" \
+ "pushl %ebx\n\t" \
+ "pushl $" #nr "\n\t" \
+ "call _do_IRQ\n\t" \
+ "addl $8,%esp\n\t" \
+ "testl %eax,%eax\n\t" \
+ "jne ret_from_sys_call\n\t" \
+ "cli\n\t" \
+ UNBLK_##chip(mask) \
+ "jmp ret_from_sys_call\n" \
+"\n.align 2\n" \
+"_fast_IRQ" #nr "_interrupt:\n\t" \
+ SAVE_MOST \
+ ACK_##chip(mask) \
+ "pushl $" #nr "\n\t" \
+ "call _do_fast_IRQ\n\t" \
+ "addl $4,%esp\n\t" \
+ "testl %eax,%eax\n\t" \
+ "jne 2f\n\t" \
+ "cli\n\t" \
+ UNBLK_##chip(mask) \
+ "\n2:\t" \
+ RESTORE_MOST \
+"\n\n.align 2\n" \
+"_bad_IRQ" #nr "_interrupt:\n\t" \
+ "pushl %eax\n\t" \
+ ACK_##chip(mask) \
+ "popl %eax\n\t" \
+ "iret");
+
+#endif
*/
#define memcpy(dest,src,n) ({ \
void * _res = dest; \
-__asm__ ("cld;rep;movsb" \
+__asm__ __volatile__ ("cld;rep;movsb" \
::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
:"di","si","cx"); \
_res; \
extern inline void set_fs(unsigned long val)
{
- __asm__("mov %0,%%fs"::"r" ((unsigned short) val));
+ __asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val));
}
#define move_to_user_mode() \
-__asm__ ("movl %%esp,%%eax\n\t" \
+__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
"pushl $0x17\n\t" \
"pushl %%eax\n\t" \
"pushfl\n\t" \
"mov %%ax,%%gs" \
:::"ax")
-#define sti() __asm__ ("sti"::)
-#define cli() __asm__ ("cli"::)
-#define nop() __asm__ ("nop"::)
+#define sti() __asm__ __volatile__ ("sti"::)
+#define cli() __asm__ __volatile__ ("cli"::)
+#define nop() __asm__ __volatile__ ("nop"::)
-#define iret() __asm__ ("iret"::)
+#define iret() __asm__ __volatile__ ("iret"::)
#define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ ("movw %%dx,%%ax\n\t" \
+__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \
"movl %%eax,%1\n\t" \
"movl %%edx,%2" \
((limit) & 0x0ffff); }
#define _set_tssldt_desc(n,addr,type) \
-__asm__ ("movw $232,%1\n\t" \
+__asm__ __volatile__ ("movw $232,%1\n\t" \
"movw %%ax,%2\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,%3\n\t" \
+++ /dev/null
-#ifndef _ERRNO_H
-#define _ERRNO_H
-
-/*
- * ok, as I hadn't got any other source of information about
- * possible error numbers, I was forced to use the same numbers
- * as minix.
- * Hopefully these are posix or something. I wouldn't know (and posix
- * isn't telling me - they want $$$ for their f***ing standard).
- *
- * We don't use the _SIGN cludge of minix, so kernel returns must
- * see to the sign by themselves.
- *
- * NOTE! Remember to change strerror() if you change this file!
- */
-
-extern int errno;
-
-#define EPERM 1
-#define ENOENT 2
-#define ESRCH 3
-#define EINTR 4
-#define EIO 5
-#define ENXIO 6
-#define E2BIG 7
-#define ENOEXEC 8
-#define EBADF 9
-#define ECHILD 10
-#define EAGAIN 11
-#define ENOMEM 12
-#define EACCES 13
-#define EFAULT 14
-#define ENOTBLK 15
-#define EBUSY 16
-#define EEXIST 17
-#define EXDEV 18
-#define ENODEV 19
-#define ENOTDIR 20
-#define EISDIR 21
-#define EINVAL 22
-#define ENFILE 23
-#define EMFILE 24
-#define ENOTTY 25
-#define ETXTBSY 26
-#define EFBIG 27
-#define ENOSPC 28
-#define ESPIPE 29
-#define EROFS 30
-#define EMLINK 31
-#define EPIPE 32
-#define EDOM 33
-#define ERANGE 34
-#define EDEADLK 35
-#define ENAMETOOLONG 36
-#define ENOLCK 37
-#define ENOSYS 38
-#define ENOTEMPTY 39
-#define ELOOP 40
-
-/* Should never be seen by user programs */
-#define ERESTARTSYS 512
-#define ERESTARTNOINTR 513
-
-#endif
+++ /dev/null
-#ifndef _FCNTL_H
-#define _FCNTL_H
-
-#include <sys/types.h>
-
-/* open/fcntl - NOCTTY, NDELAY isn't implemented yet */
-#define O_ACCMODE 00003
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 00100 /* not fcntl */
-#define O_EXCL 00200 /* not fcntl */
-#define O_NOCTTY 00400 /* not fcntl */
-#define O_TRUNC 01000 /* not fcntl */
-#define O_APPEND 02000
-#define O_NONBLOCK 04000
-#define O_NDELAY O_NONBLOCK
-
-/* Defines for fcntl-commands. Note that currently
- * locking isn't supported, and other things aren't really
- * tested.
- */
-#define F_DUPFD 0 /* dup */
-#define F_GETFD 1 /* get f_flags */
-#define F_SETFD 2 /* set f_flags */
-#define F_GETFL 3 /* more flags (cloexec) */
-#define F_SETFL 4
-#define F_GETLK 5 /* not implemented */
-#define F_SETLK 6
-#define F_SETLKW 7
-
-/* for F_[GET|SET]FL */
-#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-
-/* Ok, these are locking features, and aren't implemented at any
- * level. POSIX wants them.
- */
-#define F_RDLCK 0
-#define F_WRLCK 1
-#define F_UNLCK 2
-
-/* Once again - not implemented, but ... */
-struct flock {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
-};
-
-extern int creat(const char * filename,mode_t mode);
-extern int fcntl(int fildes,int cmd, ...);
-extern int open(const char * filename, int flags, ...);
-
-#endif
+++ /dev/null
-#ifndef _LIMITS_H
-#define _LIMITS_H
-
-#define RAND_MAX 0x7ffffffd /* don't ask - see rand.c */
-
-#define CHAR_BIT 8
-#define MB_LEN_MAX 1
-
-#define SCHAR_MIN (-128)
-#define SCHAR_MAX 127
-
-#define UCHAR_MAX 255U
-
-#ifdef __CHAR_UNSIGNED__
-#define CHAR_MIN 0
-#define CHAR_MAX UCHAR_MAX
-#else
-#define CHAR_MIN SCHAR_MIN
-#define CHAR_MAX SCHAR_MAX
-#endif
-
-#define SHRT_MIN (-32768)
-#define SHRT_MAX 32767
-
-#define USHRT_MAX 65535U
-
-#define INT_MIN (-2147483648)
-#define INT_MAX 2147483647
-
-#define UINT_MAX 4294967295U
-
-#define LONG_MIN (-2147483648)
-#define LONG_MAX 2147483647
-
-#define ULONG_MAX 4294967295U
-
-/*
- * Why are these different from the section below? -- TYT
- */
-#define _POSIX_ARG_MAX 40960 /* exec() may have 40K worth of args */
-#define _POSIX_CHILD_MAX 6 /* a process may have 6 children */
-#define _POSIX_LINK_MAX 8 /* a file may have 8 links */
-#define _POSIX_MAX_CANON 255 /* size of the canonical input queue */
-#define _POSIX_MAX_INPUT 255 /* you can type 255 chars ahead */
-#define _POSIX_NAME_MAX 14 /* a file name may have 14 chars */
-#define _POSIX_NGROUPS_MAX 32 /* supplementary group IDs are optional */
-#define _POSIX_OPEN_MAX 16 /* a process may have 16 files open */
-#define _POSIX_PATH_MAX 255 /* a pathname may contain 255 chars */
-#define _POSIX_PIPE_BUF 512 /* pipes writes of 512 bytes must be atomic */
-
-#define NGROUPS_MAX 32 /* supplemental group IDs are available */
-#define ARG_MAX 40960 /* # bytes of args + environ for exec() */
-#define CHILD_MAX 999 /* no limit :-) */
-#define OPEN_MAX 20 /* # open files a process may have */
-#define LINK_MAX 127 /* # links a file may have */
-#define MAX_CANON 255 /* size of the canonical input queue */
-#define MAX_INPUT 255 /* size of the type-ahead buffer */
-#define NAME_MAX 255 /* # chars in a file name */
-#define PATH_MAX 1024 /* # chars in a path name */
-#define PIPE_BUF 4095 /* # bytes in atomic write to a pipe */
-
-#endif
--- /dev/null
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+struct exec
+{
+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+enum machine_type {
+#if defined (M_OLDSUN2)
+ M__OLDSUN2 = M_OLDSUN2,
+#else
+ M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+ M__68010 = M_68010,
+#else
+ M_68010 = 1,
+#endif
+#if defined (M_68020)
+ M__68020 = M_68020,
+#else
+ M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+ M__SPARC = M_SPARC,
+#else
+ M_SPARC = 3,
+#endif
+ /* skip a bunch so we don't run into any of sun's numbers */
+ M_386 = 100,
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+ ((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+ ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+ ((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+ ((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+/* Code indicating object file or impure executable. */
+#define OMAGIC 0407
+/* Code indicating pure executable. */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable. */
+#define ZMAGIC 0413
+
+/* Code indicating core file. */
+#define CMAGIC 0421
+#if !defined (N_BADMAG)
+#define N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x) \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+ Note that it is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE page_size
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x2000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#ifdef linux
+#define PAGE_SIZE 4096
+#define SEGMENT_SIZE 1024
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+\f
+#if !defined (N_NLIST_DECLARED)
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ char n_other;
+ short n_desc;
+ unsigned long n_value;
+};
+#endif /* no N_NLIST_DECLARED. */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+\f
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct relocation_info
+{
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in file's the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* Four bits that aren't used, but when writing an object file
+ it is desirable to clear them. */
+#ifdef NS32K
+ unsigned r_bsr:1;
+ unsigned r_disp:1;
+ unsigned r_pad:2;
+#else
+ unsigned int r_pad:4;
+#endif
+};
+#endif /* no N_RELOCATION_INFO_DECLARED. */
+
+
+#endif /* __A_OUT_GNU_H__ */
--- /dev/null
+#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_SCSI_7000FASST
+#define CONFIG_SCSI_7000FASST
+
+#undef CONFIG_BLK_DEV_HD
+#define CONFIG_BLK_DEV_HD
+#undef CONFIG_BLK_DEV_SD
+#define CONFIG_BLK_DEV_SD
+#undef CONFIG_BLK_DEV_ST
+#define CONFIG_BLK_DEV_ST
+
+#endif
+#endif
#ifndef _CONFIG_H
#define _CONFIG_H
+#define CONFIG_DISTRIBUTION
+
/*
* Defines for what uname() should return
*/
#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x4000
+#define DEF_SYSSIZE 0x5000
/*
* The root-device is no longer hard-coded. You can change the default
leave HD_TYPE undefined. This is the normal thing to do.
*/
+#undef HD_TYPE
+
+#define CONFIG_BLK_DEV_HD
+#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
+#undef CONFIG_SCSI_7000FASST
+
+#if defined(CONFIG_BLK_DEV_SD) || defined(CONFIG_BLK_DEV_CD) || \
+defined(CONFIG_CHR_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) && \
+ !defined(CONFIG_SCSI_7000FASST)
+#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
--- /dev/null
+#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
-#define UTS_RELEASE "0.95c-54"
+#define UTS_RELEASE "0.97-11"
-#define UTS_VERSION "04/22/92"
+#define UTS_VERSION "08/01/92"
--- /dev/null
+#ifndef _LINUX_DIRENT_H
+#define _LINUX_DIRENT_H
+
+struct dirent {
+ long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ char d_name[NAME_MAX+1];
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_ERRNO_H
+#define _LINUX_ERRNO_H
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Arg list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Function not implemented */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK 41 /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+#define EDEADLOCK 58 /* File locking deadlock error */
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale NFS file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+
+/* Should never be seen by user programs */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+
+#endif
--- /dev/null
+#ifndef _EXT_FS_H
+#define _EXT_FS_H
+
+/*
+ * The ext filesystem constants/structures
+ */
+
+/*
+ * Free blocks/inodes management style
+ *
+ * One of these two constants must be defined
+ *
+ */
+/* #define EXTFS_BITMAP */ /* use a bitmap */
+#define EXTFS_FREELIST /* use a linked list */
+
+#define EXT_NAME_LEN 255
+#define EXT_ROOT_INO 1
+
+#define EXT_I_MAP_SLOTS 8
+#define EXT_Z_MAP_SLOTS 8
+#define EXT_SUPER_MAGIC 0x137D
+
+#define EXT_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct ext_inode)))
+/* #define EXT_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct ext_dir_entry))) */
+
+struct ext_inode {
+ unsigned short i_mode;
+ unsigned short i_uid;
+ unsigned long i_size;
+ unsigned long i_time;
+ unsigned short i_gid;
+ unsigned short i_nlinks;
+ unsigned long i_zone[12];
+};
+
+struct ext_free_inode {
+ unsigned long count;
+ unsigned long free[14];
+ unsigned long next;
+};
+
+struct ext_free_block {
+ unsigned long count;
+ unsigned long free[254];
+ unsigned long next;
+};
+
+struct ext_super_block {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+#ifdef EXTFS_BITMAP
+ unsigned long s_imap_blocks;
+ unsigned long s_zmap_blocks;
+#endif
+#ifdef EXTFS_FREELIST
+ unsigned long s_firstfreeblock;
+ unsigned long s_freeblockscount;
+ unsigned long s_firstfreeinode;
+ unsigned long s_freeinodescount;
+#endif
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+ unsigned long s_reserved1;
+ unsigned long s_reserved2;
+ unsigned long s_reserved3;
+ unsigned long s_reserved4;
+ unsigned long s_reserved5;
+ unsigned short s_magic;
+};
+
+struct ext_dir_entry {
+ unsigned long inode;
+ unsigned short rec_len;
+ unsigned short name_len;
+ char name[EXT_NAME_LEN];
+};
+
+extern int ext_open(struct inode * inode, struct file * filp);
+extern void ext_release(struct inode * inode, struct file * filp);
+extern int ext_lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result);
+extern int ext_create(struct inode * dir,const char * name, int len, int mode,
+ struct inode ** result);
+extern int ext_mkdir(struct inode * dir, const char * name, int len, int mode);
+extern int ext_rmdir(struct inode * dir, const char * name, int len);
+extern int ext_unlink(struct inode * dir, const char * name, int len);
+extern int ext_symlink(struct inode * inode, const char * name, int len,
+ const char * symname);
+extern int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
+extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
+extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
+ struct inode * new_dir, const char * new_name, int new_len);
+extern struct inode * ext_new_inode(int dev);
+extern void ext_free_inode(struct inode * inode);
+extern unsigned long ext_count_free_inodes(struct super_block *sb);
+extern int ext_new_block(int dev);
+extern int ext_free_block(int dev, int block);
+extern unsigned long ext_count_free_blocks(struct super_block *sb);
+
+extern int ext_create_block(struct inode *, int);
+extern int ext_bmap(struct inode *,int);
+
+extern void ext_truncate(struct inode *);
+extern void ext_put_super(struct super_block *);
+extern void ext_write_super(struct super_block *);
+extern struct super_block *ext_read_super(struct super_block *,void *);
+extern void ext_read_inode(struct inode *);
+extern void ext_write_inode(struct inode *);
+extern void ext_put_inode(struct inode *);
+extern void ext_statfs(struct super_block *, struct statfs *);
+
+extern int ext_lseek(struct inode *, struct file *, off_t, int);
+extern int ext_read(struct inode *, struct file *, char *, int);
+extern int ext_write(struct inode *, struct file *, char *, int);
+
+extern struct inode_operations ext_file_inode_operations;
+extern struct inode_operations ext_dir_inode_operations;
+extern struct inode_operations ext_symlink_inode_operations;
+extern struct inode_operations ext_chrdev_inode_operations;
+extern struct inode_operations ext_blkdev_inode_operations;
+extern struct inode_operations ext_fifo_inode_operations;
+
+extern struct file_operations ext_file_operations;
+extern struct file_operations ext_dir_operations;
+
+#endif
--- /dev/null
+#ifndef _EXT_FS_SB
+#define _EXT_FS_SB
+
+/*
+ * extended-fs super-block data in memory (same as minix: has to change)
+ */
+struct ext_sb_info {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+ unsigned long s_imap_blocks;
+ unsigned long s_zmap_blocks;
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+ struct buffer_head * s_imap[8];
+ struct buffer_head * s_zmap[8];
+};
+
+#endif
--- /dev/null
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+/* open/fcntl - O_SYNC isn't implemented yet */
+#define O_ACCMODE 0003
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 0100 /* not fcntl */
+#define O_EXCL 0200 /* not fcntl */
+#define O_NOCTTY 0400 /* not fcntl */
+#define O_TRUNC 01000 /* not fcntl */
+#define O_APPEND 02000
+#define O_NONBLOCK 04000
+#define O_NDELAY O_NONBLOCK
+#define O_SYNC 010000
+
+/* Defines for fcntl-commands. Note that currently
+ * locking isn't supported, and other things aren't really
+ * tested.
+ */
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get f_flags */
+#define F_SETFD 2 /* set f_flags */
+#define F_GETFL 3 /* more flags (cloexec) */
+#define F_SETFL 4
+#define F_GETLK 5 /* not implemented */
+#define F_SETLK 6
+#define F_SETLKW 7
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* Ok, these are locking features, and aren't implemented at any
+ * level. POSIX wants them.
+ */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* Once again - not implemented, but ... */
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_FD_H
+#define _LINUX_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 FDSETEMSGTRESH 10 /* set fdc error reporting treshold */
+
+#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, /* nr of 512-byte sectors total */
+ sect, /* sectors per track */
+ head, /* nr of heads */
+ track, /* nr of tracks */
+ stretch; /* !=0 means double track steps */
+ unsigned char gap, /* gap1 size */
+ rate, /* data rate. |= 0x40 for perpendicular */
+ spec1, /* stepping rate, head unload time */
+ fmt_gap; /* gap2 size */
+ char * name; /* used only for predefined formats */
+};
+
+struct format_descr {
+ unsigned int device,head,track;
+};
+
+#endif
+#ifndef _LINUX_FDREG_H
+#define _LINUX_FDREG_H
/*
* This file contains some defines for the floppy disk controller.
* Various sources. Mostly "IBM Microcomputers: A Programmers
* Handbook", Sanches and Canton.
*/
-#ifndef _FDREG_H
-#define _FDREG_H
extern int ticks_to_floppy_on(unsigned int nr);
extern void floppy_on(unsigned int nr);
#define ST3_WP 0x40 /* Write Protect */
/* Values for FD_COMMAND */
-#define FD_RECALIBRATE 0x07 /* move to track 0 */
-#define FD_SEEK 0x0F /* seek track */
-#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
-#define FD_WRITE 0xC5 /* write with MT, MFM */
-#define FD_SENSEI 0x08 /* Sense Interrupt Status */
-#define FD_SPECIFY 0x03 /* specify HUT etc */
+#define FD_RECALIBRATE 0x07 /* move to track 0 */
+#define FD_SEEK 0x0F /* seek track */
+#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
+#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 */
+#define FD_VERSION 0x10 /* get version code */
+#define FD_CONFIGURE 0x13 /* configure FIFO operation */
+#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
/* DMA commands */
#define DMA_READ 0x46
#define DMA_WRITE 0x4A
+/* FDC version return types */
+#define FDC_TYPE_STD 0x80 /* normal 8272A clone FDC */
+#define FDC_TYPE_82077 0x90 /* FIFO + perpendicular support */
+
#endif
+#ifndef _LINUX_FS_H
+#define _LINUX_FS_H
+
/*
* This file has definitions for some important file table
* structures etc.
*/
-#ifndef _FS_H
-#define _FS_H
-
-#include <sys/types.h>
-#include <sys/dirent.h>
+#include <linux/limits.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/dirent.h>
+#include <linux/vfs.h>
/* devices are as follows: (same as minix, so we can use the minix
* file system. These are major numbers.)
* 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
#define READA 2 /* read-ahead - don't pause */
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
-void buffer_init(long buffer_end);
+extern void buffer_init(void);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
-#define NR_OPEN 20
-#define NR_INODE 128
-#define NR_FILE 64
-#define NR_SUPER 8
-#define NR_HASH 307
-#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
#define PIPE_WRITE_WAIT(inode) ((inode).i_wait2)
#define PIPE_HEAD(inode) ((inode).i_data[0])
#define PIPE_TAIL(inode) ((inode).i_data[1])
+#define PIPE_READERS(inode) ((inode).i_data[2])
+#define PIPE_WRITERS(inode) ((inode).i_data[3])
#define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1))
#define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode))
#define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1))
#define SEL_OUT 2
#define SEL_EX 4
+/*
+ * These are the fs-independent mount-flags: up to 16 flags are supported
+ */
+#define MS_RDONLY 1 /* mount read-only */
+#define MS_NOSUID 2 /* ignore suid and sgid bits */
+#define MS_NODEV 4 /* disallow access to device special files */
+#define MS_NOEXEC 8 /* disallow program execution */
+#define MS_SYNC 16 /* writes are synced at once */
+
+/*
+ * Note that read-only etc flags are inode-specific: setting some file-system
+ * flags just means all the inodes inherit those flags by default. It might be
+ * possible to overrride it sevelctively if you really wanted to with some
+ * ioctl() that is not currently implemented.
+ */
+#define IS_RDONLY(inode) ((inode)->i_flags & MS_RDONLY)
+#define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
+#define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
+#define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
+#define IS_SYNC(inode) ((inode)->i_flags & MS_SYNC)
+
+/* the read-only stuff doesn't really belong here, but any other place is
+ probably as bad and I don't want to create yet another include file. */
+
+#define BLKROSET 4701 /* set device read-only (0 = read-write) */
+#define BLKROGET 4702 /* get read-only status (0 = read_write) */
+
+#define BMAP_IOCTL 1
+
typedef char buffer_block[BLOCK_SIZE];
struct buffer_head {
char * b_data; /* pointer to data block (1024 bytes) */
+ unsigned long b_size; /* block size */
unsigned long b_blocknr; /* block number */
unsigned short b_dev; /* device (0 = free) */
+ unsigned short b_count; /* users using this block */
unsigned char b_uptodate;
unsigned char b_dirt; /* 0-clean,1-dirty */
- unsigned char b_count; /* users using this block */
unsigned char b_lock; /* 0 - ok, 1 -locked */
- struct task_struct * b_wait;
- struct buffer_head * b_prev;
+ struct wait_queue * b_wait;
+ struct buffer_head * b_prev; /* doubly linked list of hash-queue */
struct buffer_head * b_next;
- struct buffer_head * b_prev_free;
+ struct buffer_head * b_prev_free; /* doubly linked list of buffers */
struct buffer_head * b_next_free;
+ struct buffer_head * b_this_page; /* circular list of buffers in one page */
+ struct buffer_head * b_reqnext; /* request queue */
};
struct inode {
- dev_t i_dev;
- ino_t i_ino;
- umode_t i_mode;
- nlink_t i_nlink;
- uid_t i_uid;
- gid_t i_gid;
- dev_t i_rdev;
- off_t i_size;
- time_t i_atime;
- time_t i_mtime;
- time_t i_ctime;
+ dev_t i_dev;
+ unsigned long i_ino;
+ umode_t i_mode;
+ nlink_t i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ dev_t i_rdev;
+ off_t i_size;
+ time_t i_atime;
+ time_t i_mtime;
+ time_t i_ctime;
unsigned long i_data[16];
struct inode_operations * i_op;
struct super_block * i_sb;
- struct task_struct * i_wait;
- struct task_struct * i_wait2; /* for pipes */
+ struct wait_queue * i_wait;
+ struct wait_queue * i_wait2; /* for pipes */
unsigned short i_count;
+ unsigned short i_flags;
unsigned char i_lock;
unsigned char i_dirt;
unsigned char i_pipe;
unsigned short f_mode;
unsigned short f_flags;
unsigned short f_count;
+ unsigned short f_reada;
+ unsigned short f_rdev; /* needed for /dev/tty */
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;
+#include <linux/minix_fs_sb.h>
+#include <linux/ext_fs_sb.h>
+#include <linux/msdos_fs_sb.h>
struct super_block {
- unsigned short s_ninodes;
- unsigned short s_nzones;
- unsigned short s_imap_blocks;
- unsigned short s_zmap_blocks;
- unsigned short s_firstdatazone;
- unsigned short s_log_zone_size;
- unsigned long s_max_size;
- unsigned short s_magic;
-/* These are only in memory */
- struct buffer_head * s_imap[8];
- struct buffer_head * s_zmap[8];
unsigned short s_dev;
- struct inode * s_covered;
- struct inode * s_mounted;
- unsigned long s_time;
- struct task_struct * s_wait;
+ unsigned long s_blocksize;
unsigned char s_lock;
unsigned char s_rd_only;
unsigned char s_dirt;
- /* TUBE */
struct super_operations *s_op;
+ unsigned long s_flags;
+ unsigned long s_magic;
+ unsigned long s_time;
+ struct inode * s_covered;
+ struct inode * s_mounted;
+ struct wait_queue * s_wait;
+ union {
+ struct minix_sb_info minix_sb;
+ struct ext_sb_info ext_sb;
+ struct msdos_sb_info msdos_sb;
+ } u;
};
struct file_operations {
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 count);
- int (*close) (struct inode *, struct file *);
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);
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);
+ void (*write_super) (struct super_block *sb);
+ void (*statfs) (struct super_block *sb, struct statfs *buf);
};
struct file_system_type {
extern struct inode inode_table[NR_INODE];
extern struct file file_table[NR_FILE];
extern struct super_block super_block[NR_SUPER];
-extern struct buffer_head * start_buffer;
+
+extern void grow_buffers(int size);
+extern int shrink_buffers(void);
+
extern int nr_buffers;
+extern int nr_buffer_heads;
extern void check_disk_change(int dev);
+extern void invalidate_inodes(int dev);
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);
int follow_links);
extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode);
+extern int do_mknod(const char * filename, int mode, int dev);
extern void iput(struct inode * inode);
extern struct inode * iget(int dev,int nr);
extern struct inode * get_empty_inode(void);
extern struct inode * get_pipe_inode(void);
-extern struct buffer_head * get_hash_table(int dev, int block);
-extern struct buffer_head * getblk(int dev, int block);
+extern struct file * get_empty_filp(void);
+extern struct buffer_head * get_hash_table(int dev, int block, int size);
+extern struct buffer_head * getblk(int dev, int block, int size);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
-extern struct buffer_head * bread(int dev,int block);
+extern struct buffer_head * bread(int dev, int block, int size);
extern void bread_page(unsigned long addr,int dev,int b[4]);
extern struct buffer_head * breada(int dev,int block,...);
extern int sync_dev(int dev);
extern struct super_block * get_super(int dev);
+extern void put_super(int dev);
extern int ROOT_DEV;
extern void mount_root(void);
--- /dev/null
+#ifndef _GENHD_H
+#define _GENHD_H
+
+/*
+ * genhd.h Copyright (C) 1992 Drew Eckhardt
+ * Generic hard disk header file by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+
+#define EXTENDED_PARTITION 5
+
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+};
+
+struct hd_struct {
+ long start_sect;
+ long nr_sects;
+};
+
+struct gendisk {
+ int major; /* major number of driver */
+ char *major_name; /* name of major driver */
+ int minor_shift; /* number of times minor is shifted to
+ get real minor */
+ int max_p; /* maximum partitions per device */
+ int max_nr; /* maximum number of real devices */
+
+ void (*init)(void); /* Initialization called before we do our thing */
+ struct hd_struct *part; /* partition table */
+ int *sizes; /* block sizes */
+ int nr_real; /* number of real devices */
+
+ void *real_devices; /* internal use */
+ struct gendisk *next;
+};
+
+extern int NR_GENDISKS; /* total */
+extern struct gendisk *gendisk_head; /* linked list of disks */
+
+#endif
+#ifndef _LINUX_HDREG_H
+#define _LINUX_HDREG_H
+
/*
* This file contains some defines for the AT-hd-controller.
* Various sources. Check out some definitions (see comments with
* a ques).
*/
-#ifndef _HDREG_H
-#define _HDREG_H
/* Hd controller regs. Ref: IBM AT Bios-listing */
#define HD_DATA 0x1f0 /* _CTL when writing */
#define ECC_ERR 0x40 /* ? */
#define BBD_ERR 0x80 /* ? */
-#define EXTENDED_PARTITION 5
-
-struct partition {
- unsigned char boot_ind; /* 0x80 - active */
- unsigned char head; /* starting head */
- unsigned char sector; /* starting sector */
- unsigned char cyl; /* starting cylinder */
- unsigned char sys_ind; /* What partition type */
- unsigned char end_head; /* end head */
- unsigned char end_sector; /* end sector */
- unsigned char end_cyl; /* end cylinder */
- unsigned int start_sect; /* starting sector counting from 0 */
- unsigned int nr_sects; /* nr of sectors in partition */
-};
#define HDIO_REQ 0x301
struct hd_geometry {
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
+ unsigned long start;
};
#endif
-#ifndef _HEAD_H
-#define _HEAD_H
+#ifndef _LINUX_HEAD_H
+#define _LINUX_HEAD_H
typedef struct desc_struct {
unsigned long a,b;
+#ifndef _LINUX_KERNEL_H
+#define _LINUX_KERNEL_H
+
/*
* 'kernel.h' contains some often-used function prototypes etc
*/
+
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);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
*/
#define suser() (current->euid == 0)
+#endif
--- /dev/null
+#ifndef _LINUX_LIMITS_H
+#define _LINUX_LIMITS_H
+
+#define NAME_MAX 255
+
+#define NR_OPEN 32
+#define NR_INODE 128
+#define NR_FILE 128
+#define NR_SUPER 8
+#define NR_HASH 307
+#define BLOCK_SIZE 1024
+#define BLOCK_SIZE_BITS 10
+#define MAX_CHRDEV 16
+#define MAX_BLKDEV 16
+
+#define NGROUPS_MAX 32 /* supplemental group IDs are available */
+#define ARG_MAX 40960 /* # bytes of args + environ for exec() */
+#define CHILD_MAX 999 /* no limit :-) */
+#define OPEN_MAX 32 /* # open files a process may have */
+#define LINK_MAX 127 /* # links a file may have */
+#define MAX_CANON 255 /* size of the canonical input queue */
+#define MAX_INPUT 255 /* size of the type-ahead buffer */
+#define NAME_MAX 255 /* # chars in a file name */
+#define PATH_MAX 1024 /* # chars in a path name */
+#define PIPE_BUF 4095 /* # bytes in atomic write to a pipe */
+
+#endif
+#ifndef _LINUX_LP_H
+#define _LINUX_LP_H
+
/*
$Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wiegand Exp james_r_wiegand $
*/
-#include <errno.h>
+#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+
#include <asm/io.h>
#include <asm/segment.h>
#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
I don't see the need for a queue
*/
-#ifndef __LP_C__
- extern
-#endif
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;
};
/*
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
-#ifndef __LP_C__
- extern
-#endif
struct lp_struct lp_table[] = {
{ 0x3bc, 0, },
{ 0x378, 0, },
* function prototypes
*/
-extern void lp_init(void);
+extern long lp_init(long);
+
+#endif
-/*
- * linux/include/linux/math_emu.h
- *
- * (C) 1991 Linus Torvalds
- */
#ifndef _LINUX_MATH_EMU_H
#define _LINUX_MATH_EMU_H
void fdiv(const temp_real *, const temp_real *, temp_real *);
+/* sqrt.c */
+
+void fsqrt(const temp_real *, temp_real *);
+
/* compare.c */
void fcom(const temp_real *, const temp_real *);
-/*
- * The minix filesystem constants/structures
- */
-
#ifndef _MINIX_FS_H
#define _MINIX_FS_H
-#include <sys/types.h>
+/*
+ * The minix filesystem constants/structures
+ */
#define MINIX_NAME_LEN 14
#define MINIX_ROOT_INO 1
unsigned short i_zone[9];
};
+/*
+ * minix super-block data on disk
+ */
struct minix_super_block {
unsigned short s_ninodes;
unsigned short s_nzones;
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,
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 unsigned long minix_count_free_inodes(struct super_block *sb);
extern int minix_new_block(int dev);
extern int minix_free_block(int dev, int block);
+extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_create_block(struct inode *, int);
extern int minix_bmap(struct inode *,int);
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 void minix_statfs(struct super_block *, struct statfs *);
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_readdir(struct inode *, struct file *, struct dirent *, 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 inode_operations minix_fifo_inode_operations;
extern struct file_operations minix_file_operations;
extern struct file_operations minix_dir_operations;
--- /dev/null
+#ifndef _MINIX_FS_SB
+#define _MINIX_FS_SB
+
+/*
+ * minix super-block data in memory
+ */
+struct minix_sb_info {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+ unsigned long s_imap_blocks;
+ unsigned long s_zmap_blocks;
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+ struct buffer_head * s_imap[8];
+ struct buffer_head * s_zmap[8];
+};
+
+#endif
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <signal.h>
+#include <linux/signal.h>
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ */
+extern unsigned long inline __bad_page(void)
+{
+ extern char empty_bad_page[PAGE_SIZE];
+
+ __asm__ __volatile__("cld ; rep ; stosl"
+ ::"a" (0),
+ "D" ((long) empty_bad_page),
+ "c" (1024)
+ :"di","cx");
+ return (unsigned long) empty_bad_page;
+}
+#define BAD_PAGE __bad_page()
+
+extern unsigned long inline __bad_pagetable(void)
+{
+ extern char empty_bad_page_table[PAGE_SIZE];
+
+ __asm__ __volatile__("cld ; rep ; stosl"
+ ::"a" (7+BAD_PAGE),
+ "D" ((long) empty_bad_page_table),
+ "c" (1024)
+ :"di","cx");
+ return (unsigned long) empty_bad_page_table;
+}
+#define BAD_PAGETABLE __bad_pagetable()
extern unsigned int swap_device;
extern struct inode * swap_file;
+extern int nr_free_pages;
+
extern void rw_swap_page(int rw, unsigned int nr, char * buf);
#define read_swap_page(nr,buf) \
#define write_swap_page(nr,buf) \
rw_swap_page(WRITE,(nr),(buf))
-extern unsigned long get_free_page(void);
+/* memory.c */
+
+extern unsigned long get_free_page(int priority);
extern unsigned long put_dirty_page(unsigned long page,unsigned long address);
extern void free_page(unsigned long addr);
-void swap_free(int page_nr);
-void swap_in(unsigned long *table_ptr);
+extern int free_page_tables(unsigned long from,unsigned long size);
+extern int copy_page_tables(unsigned long from,unsigned long to,long size);
+extern int unmap_page_range(unsigned long from, unsigned long size);
+extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
+ int permiss);
+extern void write_verify(unsigned long address);
-extern inline volatile void oom(void)
-{
- printk("out of memory\n\r");
- do_exit(SIGSEGV);
-}
+extern void do_wp_page(unsigned long error_code, unsigned long address,
+ struct task_struct *tsk, unsigned long user_esp);
+extern void do_no_page(unsigned long error_code, unsigned long address,
+ struct task_struct *tsk, unsigned long user_esp);
+
+extern unsigned long mem_init(unsigned long start_mem, unsigned long end_mem);
+extern void show_mem(void);
+extern void do_page_fault(unsigned long *esp, unsigned long error_code);
+extern void oom(struct task_struct * task);
+
+/* swap.c */
+
+extern void swap_free(unsigned int page_nr);
+extern void swap_in(unsigned long *table_ptr);
#define invalidate() \
__asm__("movl %%eax,%%cr3"::"a" (0))
-/* these are not to be changed without changing head.s etc */
-#define LOW_MEM 0x100000
-extern unsigned long HIGH_MEMORY;
-#define PAGING_MEMORY (15*1024*1024)
-#define PAGING_PAGES (PAGING_MEMORY>>12)
-#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
+extern unsigned long low_memory;
+extern unsigned long high_memory;
+extern unsigned long paging_pages;
+
+#define MAP_NR(addr) (((addr)-low_memory)>>12)
#define USED 100
-extern unsigned char mem_map [ PAGING_PAGES ];
+extern unsigned char * mem_map;
#define PAGE_DIRTY 0x40
#define PAGE_ACCESSED 0x20
#define PAGE_RW 0x02
#define PAGE_PRESENT 0x01
+#define GFP_BUFFER 0x00
+#define GFP_USER 0x01
+#define GFP_KERNEL 0x02
+
#endif
--- /dev/null
+#ifndef _LINUX_MOUSE_H
+#define _LINUX_MOUSE_H
+
+/*
+ * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
+ * by James Banks
+ *
+ * based on information gleamed from various mouse drivers on the net
+ *
+ * Heavily modified by David giller (rafetmad@oxy.edu)
+ *
+ * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
+ * gt7080a@prism.gatech.edu (13JUL92)
+ *
+ */
+
+#define MOUSE_IRQ 5
+
+#define MSE_DATA_PORT 0x23c
+#define MSE_SIGNATURE_PORT 0x23d
+#define MSE_CONTROL_PORT 0x23e
+#define MSE_INTERRUPT_PORT 0x23e
+#define MSE_CONFIG_PORT 0x23f
+
+#define MSE_ENABLE_INTERRUPTS 0x00
+#define MSE_DISABLE_INTERRUPTS 0x10
+
+#define MSE_READ_X_LOW 0x80
+#define MSE_READ_X_HIGH 0xa0
+#define MSE_READ_Y_LOW 0xc0
+#define MSE_READ_Y_HIGH 0xe0
+
+/* Magic number used to check if the mouse exists */
+#define MSE_CONFIG_BYTE 0x91
+#define MSE_DEFAULT_MODE 0x90
+#define MSE_SIGNATURE_BYTE 0xa5
+
+/* useful macros */
+
+#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
+#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
+
+struct mouse_status
+ {
+ char buttons;
+ char latch_buttons;
+ int dx;
+ int dy;
+
+ int present;
+ int ready;
+ int active;
+
+ struct inode *inode;
+ };
+
+/* Function Prototypes */
+extern long mouse_init(long);
+
+#endif
+
--- /dev/null
+#ifndef _MSDOS_FS_H
+#define _MSDOS_FS_H
+
+/*
+ * The MS-DOS filesystem constants/structures
+ */
+
+#include <linux/fs.h>
+
+#define MSDOS_ROOT_INO 1 /* == MINIX_ROOT_INO */
+#define SECTOR_SIZE 512 /* sector size (bytes) */
+#define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */
+#define MSDOS_DPB (MSDOS_DPS*2) /* dir entries per block */
+#define MSDOS_DPB_BITS 5 /* log2(MSDOS_DPB) */
+#define MSDOS_DPS (SECTOR_SIZE/sizeof(struct msdos_dir_entry))
+#define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */
+#define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */
+
+#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
+
+#define FAT_CACHE 8 /* FAT cache size */
+
+#define ATTR_RO 1 /* read-only */
+#define ATTR_HIDDEN 2 /* hidden */
+#define ATTR_SYS 4 /* system */
+#define ATTR_VOLUME 8 /* volume label */
+#define ATTR_DIR 16 /* directory */
+#define ATTR_ARCH 32 /* archived */
+
+#define ATTR_NONE 0 /* no attribute bits */
+#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
+ /* attribute bits that are copied "as is" */
+
+#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
+
+#define D_START 0 /* i_data[0]: first cluster or 0 */
+#define D_ATTRS 1 /* i_data[1]: unused attribute bits */
+#define D_BUSY 2 /* i_data[2]: file is either deleted but still open, or
+ inconsistent (mkdir) */
+#define D_DEPEND 3 /* i_data[3]: pointer to inode that depends on the current
+ inode */
+#define D_OLD 4 /* i_data[4]: pointer to the old inode this inode depends
+ on */
+#define D_BINARY 5 /* i_data[5]: file contains non-text data */
+
+#define MSDOS_SB(s) (&((s)->u.msdos_sb))
+
+#define MSDOS_NAME 11 /* maximum name length */
+#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */
+
+#define MSDOS_FAT12 4086 /* maximum number of clusters in a 12 bit FAT */
+
+struct msdos_boot_sector {
+ char ignored[13];
+ unsigned char cluster_size; /* sectors/cluster */
+ unsigned short reserved; /* reserved sectors */
+ unsigned char fats; /* number of FATs */
+ unsigned char dir_entries[2];/* root directory entries */
+ unsigned char sectors[2]; /* number of sectors */
+ unsigned char media; /* media code (unused) */
+ unsigned short fat_length; /* sectors/FAT */
+ unsigned short secs_track; /* sectors per track (unused) */
+ unsigned short heads; /* number of heads (unused) */
+ unsigned long hidden; /* hidden sectors (unused) */
+ unsigned long total_sect; /* number of sectors (if sectors == 0) */
+};
+
+struct msdos_dir_entry {
+ char name[8],ext[3]; /* name and extension */
+ unsigned char attr; /* attribute bits */
+ char unused[10];
+ unsigned short time,date,start; /* time, date and first cluster */
+ unsigned long size; /* file size (in bytes) */
+};
+
+struct fat_cache {
+ int device; /* device number. 0 means unused. */
+ int ino; /* inode number. */
+ int file_cluster; /* cluster number in the file. */
+ int disk_cluster; /* cluster number on disk. */
+ struct fat_cache *next; /* next cache entry */
+};
+
+/* Determine whether this FS has kB-aligned data. */
+
+#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \
+ ((mib)->data_start & 1)))
+
+/* Convert attribute bits and a mask to the UNIX mode. */
+
+#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? 0444 : 0777))
+
+/* Convert the UNIX mode to MS-DOS attribute bits. */
+
+#define MSDOS_MKATTR(m) (!(m & 0200) ? ATTR_RO : ATTR_NONE)
+
+
+static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
+{
+ struct buffer_head *bh;
+
+ if (!(bh = bread(dev,sector >> 1, 1024)))
+ return NULL;
+ *start = bh->b_data+((sector & 1) << SECTOR_BITS);
+ return bh;
+}
+
+
+/* misc.c */
+
+extern int is_binary(char conversion,char *extension);
+extern void lock_creation(void);
+extern void unlock_creation(void);
+extern int msdos_add_cluster(struct inode *inode);
+extern int date_dos2unix(unsigned short time,unsigned short date);
+extern void date_unix2dos(int unix_date,unsigned short *time,
+ unsigned short *date);
+extern int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
+ struct msdos_dir_entry **de);
+extern int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
+ struct msdos_dir_entry **res_de,int *ino);
+extern int msdos_parent_ino(struct inode *dir,int locked);
+
+/* fat.c */
+
+extern int fat_access(struct super_block *sb,int this,int new_value);
+extern int msdos_smap(struct inode *inode,int sector);
+extern int fat_free(struct inode *inode,int skip);
+extern void cache_init(void);
+void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu);
+void cache_add(struct inode *inode,int f_clu,int d_clu);
+void cache_inval_inode(struct inode *inode);
+void cache_inval_dev(int device);
+int get_cluster(struct inode *inode,int cluster);
+
+/* namei.c */
+
+extern int msdos_lookup(struct inode *dir,const char *name,int len,
+ struct inode **result);
+extern int msdos_create(struct inode *dir,const char *name,int len,int mode,
+ struct inode **result);
+extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode);
+extern int msdos_rmdir(struct inode *dir,const char *name,int len);
+extern int msdos_unlink(struct inode *dir,const char *name,int len);
+extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
+ struct inode *new_dir,const char *new_name,int new_len);
+
+/* inode.c */
+
+extern void msdos_put_inode(struct inode *inode);
+extern void msdos_put_super(struct super_block *sb);
+extern struct super_block *msdos_read_super(struct super_block *s,void *data);
+extern void msdos_statfs(struct super_block *sb,struct statfs *buf);
+extern int msdos_bmap(struct inode *inode,int block);
+extern void msdos_read_inode(struct inode *inode);
+extern void msdos_write_inode(struct inode *inode);
+
+/* dir.c */
+
+extern struct file_operations msdos_dir_operations;
+extern struct inode_operations msdos_dir_inode_operations;
+
+/* file.c */
+
+extern struct file_operations msdos_file_operations;
+extern struct inode_operations msdos_file_inode_operations;
+extern struct inode_operations msdos_file_inode_operations_no_bmap;
+
+extern void msdos_truncate(struct inode *inode);
+
+#endif
--- /dev/null
+#ifndef _MSDOS_FS_SB
+#define _MSDOS_FS_SB
+
+struct msdos_sb_info { /* space in struct super_block is 28 bytes */
+ unsigned short cluster_size; /* sectors/cluster */
+ unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
+ unsigned short fat_start,fat_length; /* FAT start & length (sec.) */
+ unsigned short dir_start,dir_entries; /* root dir start & entries */
+ unsigned short data_start; /* first data sector */
+ unsigned long clusters; /* number of clusters */
+ uid_t fs_uid;
+ gid_t fs_gid;
+ unsigned short fs_umask;
+ unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+ unsigned char conversion; /* b = binary, t = text, a = auto */
+};
+
+#endif
--- /dev/null
+#ifndef _SYS_PARAM_H
+#define _SYS_PARAM_H
+
+#define HZ 100
+#define EXEC_PAGESIZE 4096
+
+#define NGROUPS 32 /* Max number of groups per user */
+#define NOGROUP -1
+
+#define MAXHOSTNAMELEN 8
+
+#endif
--- /dev/null
+#ifndef _LINUX_PTRACE_H
+#define _LINUX_PTRACE_H
+/* ptrace.h */
+/* structs and defines to help the user use the ptrace system call. */
+
+/* has the defines to get at the registers. */
+
+#define PTRACE_TRACEME 0
+#define PTRACE_PEEKTEXT 1
+#define PTRACE_PEEKDATA 2
+#define PTRACE_PEEKUSR 3
+#define PTRACE_POKETEXT 4
+#define PTRACE_POKEDATA 5
+#define PTRACE_POKEUSR 6
+#define PTRACE_CONT 7
+#define PTRACE_KILL 8
+#define PTRACE_SINGLESTEP 9
+
+#define PTRACE_ATTACH 0x10
+#define PTRACE_DETACH 0x11
+
+/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
+ the processes registers. */
+
+#define EBX 0
+#define ECX 1
+#define EDX 2
+#define ESI 3
+#define EDI 4
+#define EBP 5
+#define EAX 6
+#define DS 7
+#define ES 8
+#define FS 9
+#define GS 10
+#define ORIG_EAX 11
+#define EIP 12
+#define CS 13
+#define EFL 14
+#define UESP 15
+#define SS 16
+
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call. */
+
+struct pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ long ds;
+ long es;
+ long fs;
+ long gs;
+ long orig_eax;
+ long eip;
+ long cs;
+ long eflags;
+ long esp;
+ long ss;
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_RESOURCE_H
+#define _LINUX_RESOURCE_H
+
+/*
+ * Resource control/accounting header file for linux
+ */
+
+/*
+ * Definition of struct rusage taken from BSD 4.3 Reno
+ *
+ * We don't support all of these yet, but we might as well have them....
+ * Otherwise, each time we add new items, programs which depend on this
+ * structure will lose. This reduces the chances of that happening.
+ */
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
+
+struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ long ru_maxrss; /* maximum resident set size */
+ long ru_ixrss; /* integral shared memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
+};
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU 0 /* CPU time in ms */
+#define RLIMIT_FSIZE 1 /* Maximum filesize */
+#define RLIMIT_DATA 2 /* max data size */
+#define RLIMIT_STACK 3 /* max stack size */
+#define RLIMIT_CORE 4 /* max core file size */
+#define RLIMIT_RSS 5 /* max resident set size */
+
+#ifdef notdef
+#define RLIMIT_MEMLOCK 6 /* max locked-in-memory address space*/
+#define RLIMIT_NPROC 7 /* max number of processes */
+#define RLIMIT_OFILE 8 /* max number of open files */
+#endif
+
+#define RLIM_NLIMITS 6
+
+#define RLIM_INFINITY 0x7fffffff
+
+struct rlimit {
+ int rlim_cur;
+ int rlim_max;
+};
+
+#define PRIO_MIN -99
+#define PRIO_MAX 14
+
+#define PRIO_PROCESS 0
+#define PRIO_PGRP 1
+#define PRIO_USER 2
+
+#endif
-#ifndef _SCHED_H
-#define _SCHED_H
+#ifndef _LINUX_SCHED_H
+#define _LINUX_SCHED_H
#define HZ 100
#include <linux/head.h>
#include <linux/fs.h>
#include <linux/mm.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <signal.h>
+#include <linux/signal.h>
+#include <linux/time.h>
+#include <linux/param.h>
+#include <linux/resource.h>
#if (NR_OPEN > 32)
#error "Currently the close-on-exec-flags and select masks are in one long, max 32 files/proc"
#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);
-
extern void sched_init(void);
+extern void show_state(void);
extern void schedule(void);
extern void trap_init(void);
extern void panic(const char * str);
long blocked; /* bitmap of masked signals */
/* various fields */
int exit_code;
+ int dumpable:1;
+ int swappable:1;
unsigned long start_code,end_code,end_data,brk,start_stack;
long pid,pgrp,session,leader;
int groups[NGROUPS];
/*
- * pointers to parent process, youngest child, younger sibling,
+ * pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
- struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+ struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr;
/*
- * sleep makes a singly linked list with this.
+ * For ease of programming... Normal sleeps don't need to
+ * keep track of a wait-queue: every task has an entry of it's own
*/
- struct task_struct *next_wait;
+ struct wait_queue wait;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
- unsigned long timeout,alarm;
+ unsigned long timeout;
+ unsigned long it_real_value, it_prof_value, it_virt_value;
+ unsigned long it_real_incr, it_prof_incr, it_virt_incr;
long utime,stime,cutime,cstime,start_time;
unsigned long min_flt, maj_flt;
unsigned long cmin_flt, cmaj_flt;
#define INIT_TASK \
/* state etc */ { 0,15,15, \
/* signals */ 0,{{},},0, \
-/* ec,brk... */ 0,0,0,0,0,0, \
+/* ec,brk... */ 0,0,0,0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \
-/* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \
+/* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL, \
+/* wait queue*/ {&init_task.task,NULL}, \
/* uid etc */ 0,0,0,0,0,0, \
-/* timeout */ 0,0,0,0,0,0,0, \
+/* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \
/* min_flt */ 0,0,0,0, \
/* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \
{0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}, \
#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ)
extern void add_timer(long jiffies, void (*fn)(void));
-extern void sleep_on(struct task_struct ** p);
-extern void interruptible_sleep_on(struct task_struct ** p);
-extern void wake_up(struct task_struct ** p);
+
+extern void sleep_on(struct wait_queue ** p);
+extern void interruptible_sleep_on(struct wait_queue ** p);
+extern void wake_up(struct wait_queue ** p);
+extern void wake_one_task(struct task_struct * p);
+
+extern int send_sig(long sig,struct task_struct * p,int priv);
extern int in_group_p(gid_t grp);
+extern int request_irq(unsigned int irq,void (*handler)(int));
+extern void free_irq(unsigned int irq);
+extern int irqaction(unsigned int irq,struct sigaction * new);
+
/*
* Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
* 4-TSS0, 5-LDT0, 6-TSS1 etc ...
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
"movw %%dx,%1\n\t" \
+ "cli\n\t" \
"xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
+ "sti\n\t" \
"cmpl %%ecx,_last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ unsigned long flags;
+ struct wait_queue * tmp;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ wait->next = *p;
+ tmp = wait;
+ while (tmp->next)
+ if ((tmp = tmp->next)->next == *p)
+ break;
+ *p = tmp->next = wait;
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+}
+
+extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ unsigned long flags;
+ struct wait_queue * tmp;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ if (*p == wait)
+ if ((*p = wait->next) == wait)
+ *p = NULL;
+ tmp = wait;
+ while (tmp && tmp->next != wait)
+ tmp = tmp->next;
+ if (tmp)
+ tmp->next = wait->next;
+ wait->next = NULL;
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+}
+
+extern inline void select_wait(struct wait_queue ** wait_address, select_table * p)
+{
+ struct select_table_entry * entry = p->entry + p->nr;
+
+ if (!wait_address)
+ return;
+ entry->wait_address = wait_address;
+ entry->wait.task = current;
+ add_wait_queue(wait_address,&entry->wait);
+ p->nr++;
+}
+
static unsigned long inline _get_base(char * addr)
{
unsigned long __base;
return __limit+1;
}
+#define REMOVE_LINKS(p) \
+ if ((p)->p_osptr) \
+ (p)->p_osptr->p_ysptr = (p)->p_ysptr; \
+ if ((p)->p_ysptr) \
+ (p)->p_ysptr->p_osptr = (p)->p_osptr; \
+ else \
+ (p)->p_pptr->p_cptr = (p)->p_osptr
+
+#define SET_LINKS(p) \
+ (p)->p_ysptr = NULL; \
+ if ((p)->p_osptr = (p)->p_pptr->p_cptr) \
+ (p)->p_osptr->p_ysptr = p; \
+ (p)->p_pptr->p_cptr = p
+
#endif
--- /dev/null
+#ifndef _LINUX_SIGNAL_H
+#define _LINUX_SIGNAL_H
+
+typedef unsigned int sigset_t; /* 32 bits */
+
+#define _NSIG 32
+#define NSIG _NSIG
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGUNUSED 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+
+/*
+ * Most of these aren't used yet (and perhaps never will),
+ * so they are commented out.
+ */
+
+/*
+#define SIGIO 23
+#define SIGPOLL SIGIO
+#define SIGXCPU 24
+#define SIGXFSZ 25
+*/
+
+#define SIGVTALRM 26
+#define SIGPROF 27
+
+#define SIGWINCH 28
+
+/*
+#define SIGLOST 29
+*/
+
+#define SA_NOCLDSTOP 1
+#define SA_INTERRUPT 0x20000000
+#define SA_NOMASK 0x40000000
+#define SA_ONESHOT 0x80000000
+
+#define SIG_BLOCK 0 /* for blocking signals */
+#define SIG_UNBLOCK 1 /* for unblocking signals */
+#define SIG_SETMASK 2 /* for setting the signal mask */
+
+#define SIG_DFL ((void (*)(int))0) /* default signal handling */
+#define SIG_IGN ((void (*)(int))1) /* ignore signal */
+#define SIG_ERR ((void (*)(int))-1) /* error return from signal */
+
+struct sigaction {
+ void (*sa_handler)(int);
+ sigset_t sa_mask;
+ int sa_flags;
+ void (*sa_restorer)(void);
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_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
+
+#endif
--- /dev/null
+#ifndef _LINUX_STAT_H
+#define _LINUX_STAT_H
+
+struct old_stat {
+ unsigned short st_dev;
+ unsigned short st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned long st_size;
+ unsigned long st_atime;
+ unsigned long st_mtime;
+ unsigned long st_ctime;
+};
+
+struct new_stat {
+ unsigned short st_dev;
+ unsigned short __pad1;
+ unsigned long st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned short __pad2;
+ unsigned long st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ unsigned long st_atime;
+ unsigned long __unused1;
+ unsigned long st_mtime;
+ unsigned long __unused2;
+ unsigned long st_ctime;
+ unsigned long __unused3;
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#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
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#endif
--- /dev/null
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#undef NULL
+#define NULL ((void *)0)
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif
-#ifndef _STRING_H_
-#define _STRING_H_
+#ifndef _LINUX_STRING_H_
+#define _LINUX_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
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
extern inline char * strcpy(char * dest,const char *src)
extern inline char * strtok(char * s,const char * ct)
{
-register char * __res __asm__("si");
+register char * __res;
__asm__("testl %1,%1\n\t"
"jne 1f\n\t"
"testl %0,%0\n\t"
"jne 8f\n\t"
"movl %0,%1\n"
"8:"
-#if __GNUC__ == 2
- :"=r" (__res)
-#else
- :"=b" (__res)
-#endif
- ,"=S" (___strtok)
+ :"=b" (__res),"=S" (___strtok)
:"0" (___strtok),"1" (s),"g" (ct)
:"ax","cx","dx","di");
return __res;
extern int sys_statfs();
extern int sys_fstatfs();
extern int sys_ioperm();
+extern int sys_socketcall();
+extern int sys_syslog();
+extern int sys_getitimer();
+extern int sys_setitimer();
+extern int sys_newstat();
+extern int sys_newlstat();
+extern int sys_newfstat();
+extern int sys_newuname();
+extern int sys_iopl();
+extern int sys_vhangup();
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,
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_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
+sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat,
+sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
--- /dev/null
+#ifndef _LINUX_TERMIOS_H
+#define _LINUX_TERMIOS_H
+
+/* 0x54 is just a magic number to make these relatively uniqe ('T') */
+
+#define TCGETS 0x5401
+#define TCSETS 0x5402
+#define TCSETSW 0x5403
+#define TCSETSF 0x5404
+#define TCGETA 0x5405
+#define TCSETA 0x5406
+#define TCSETAW 0x5407
+#define TCSETAF 0x5408
+#define TCSBRK 0x5409
+#define TCXONC 0x540A
+#define TCFLSH 0x540B
+#define TIOCEXCL 0x540C
+#define TIOCNXCL 0x540D
+#define TIOCSCTTY 0x540E
+#define TIOCGPGRP 0x540F
+#define TIOCSPGRP 0x5410
+#define TIOCOUTQ 0x5411
+#define TIOCSTI 0x5412
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+#define TIOCMGET 0x5415
+#define TIOCMBIS 0x5416
+#define TIOCMBIC 0x5417
+#define TIOCMSET 0x5418
+#define TIOCGSOFTCAR 0x5419
+#define TIOCSSOFTCAR 0x541A
+#define FIONREAD 0x541B
+#define TIOCINQ FIONREAD
+#define TIOCLINUX 0x541C
+#define TIOCCONS 0x541D
+#define TIOCGSERIAL 0x541E
+#define TIOCSSERIAL 0x541F
+#define TIOCPKT 0x5420
+#define FIONBIO 0x5421
+#define TIOCNOTTY 0x5422
+
+/* Used for packet mode */
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_DOSTOP 16
+#define TIOCPKT_NOSTOP 32
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+#define NCCS 17
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+
+/* c_oflag bits */
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0040000
+#define FF0 0000000
+#define FF1 0040000
+
+/* c_cflag bit meaning */
+#define CBAUD 0000017
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#define CIBAUD 03600000 /* input baud rate (not used) */
+#define CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+#endif
--- /dev/null
+#ifndef _LINUX_TIME_H
+#define _LINUX_TIME_H
+
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+#define FD_SETSIZE (8*sizeof(fd_set))
+#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd)))
+#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd)))
+#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1)
+#define FD_ZERO(fdsetp) (*(fdsetp) = 0)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+#endif
-#ifndef _TIMER_H
-#define _TIMER_H
+#ifndef _LINUX_TIMER_H
+#define _LINUX_TIMER_H
/*
* DON'T CHANGE THESE!! Most of them are hardcoded into some assembly language
* HD_TIMER harddisk timer
*
* FLOPPY_TIMER floppy disk timer (not used right now)
+ *
+ * SCSI_TIMER scsi.c timeout timer
*/
#define BLANK_TIMER 0
#define HD_TIMER 16
#define FLOPPY_TIMER 17
+#define SCSI_TIMER 18
struct timer_struct {
unsigned long expires;
--- /dev/null
+#ifndef _LINUX_TIMES_H
+#define _LINUX_TIMES_H
+
+struct tms {
+ time_t tms_utime;
+ time_t tms_stime;
+ time_t tms_cutime;
+ time_t tms_cstime;
+};
+
+#endif
+#ifndef _LINUX_TTY_H
+#define _LINUX_TTY_H
+
/*
* 'tty.h' defines some structures used by tty_io.c and some defines.
*
* offsets into 'tty_queue'
*/
-#ifndef _TTY_H
-#define _TTY_H
+#include <linux/termios.h>
+
+#include <asm/system.h>
-#define MAX_CONSOLES 8
+#define NR_CONSOLES 8
#define NR_SERIALS 4
#define NR_PTYS 4
-extern int NR_CONSOLES;
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+
+struct screen_info {
+ unsigned char orig_x;
+ unsigned char orig_y;
+ unsigned char unused1[2];
+ unsigned short orig_video_page;
+ unsigned char orig_video_mode;
+ unsigned char orig_video_cols;
+ unsigned short orig_video_ega_ax;
+ unsigned short orig_video_ega_bx;
+ unsigned short orig_video_ega_cx;
+ unsigned char orig_video_lines;
+};
+
+extern struct screen_info screen_info;
+
+#define ORIG_X (screen_info.orig_x)
+#define ORIG_Y (screen_info.orig_y)
+#define ORIG_VIDEO_PAGE (screen_info.orig_video_page)
+#define ORIG_VIDEO_MODE (screen_info.orig_video_mode)
+#define ORIG_VIDEO_COLS (screen_info.orig_video_cols)
+#define ORIG_VIDEO_EGA_AX (screen_info.orig_video_ega_ax)
+#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx)
+#define ORIG_VIDEO_EGA_CX (screen_info.orig_video_ega_cx)
+#define ORIG_VIDEO_LINES (screen_info.orig_video_lines)
+
+#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
+#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
+#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
+#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
-#include <termios.h>
+/*
+ * This character is the same as _POSIX_VDISABLE: it cannot be used as
+ * a c_cc[] character, but indicates that a particular special character
+ * isn't in use (eg VINTR ahs no character etc)
+ */
+#define __DISABLED_CHAR '\0'
#define TTY_BUF_SIZE 2048
unsigned long data;
unsigned long head;
unsigned long tail;
- struct task_struct * proc_list;
- char buf[TTY_BUF_SIZE];
+ struct wait_queue * proc_list;
+ unsigned char buf[TTY_BUF_SIZE];
};
+struct serial_struct {
+ unsigned short type;
+ unsigned short line;
+ unsigned short port;
+ unsigned short irq;
+ struct tty_struct * tty;
+};
+
+/*
+ * These are the supported serial types.
+ */
+#define PORT_UNKNOWN 0
+#define PORT_8250 1
+#define PORT_16450 2
+#define PORT_16550 3
+#define PORT_16550A 4
+
#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00)
#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40)
#define IS_A_PTY(min) ((min) & 0x80)
#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);})
+
+extern void put_tty_queue(char c, struct tty_queue * queue);
+extern int get_tty_queue(struct tty_queue * queue);
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
#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 flags;
+ int count;
struct winsize winsize;
void (*write)(struct tty_struct * tty);
+ struct tty_struct *link;
struct tty_queue *read_q;
struct tty_queue *write_q;
struct tty_queue *secondary;
/*
* so that interrupts won't be able to mess up the
* queues, copy_to_cooked must be atomic with repect
- * to itself, as must tty->write.
+ * to itself, as must tty->write. These are the flag
+ * bit-numbers. Use the set_bit() and clear_bit()
+ * macros to make it all atomic.
*/
-#define TTY_WRITE_BUSY 1
-#define TTY_READ_BUSY 2
-
-#define TTY_WRITE_FLUSH(tty) \
-do { \
- cli(); \
- if (!EMPTY((tty)->write_q) && !(TTY_WRITE_BUSY & (tty)->busy)) { \
- (tty)->busy |= TTY_WRITE_BUSY; \
- sti(); \
- (tty)->write((tty)); \
- cli(); \
- (tty)->busy &= ~TTY_WRITE_BUSY; \
- } \
- sti(); \
-} while (0)
-
-#define TTY_READ_FLUSH(tty) \
-do { \
- cli(); \
- if (!EMPTY((tty)->read_q) && !(TTY_READ_BUSY & (tty)->busy)) { \
- (tty)->busy |= TTY_READ_BUSY; \
- sti(); \
- copy_to_cooked((tty)); \
- cli(); \
- (tty)->busy &= ~TTY_READ_BUSY; \
- } \
- sti(); \
-} while (0)
+#define TTY_WRITE_BUSY 0
+#define TTY_READ_BUSY 1
+#define TTY_CR_PENDING 2
+
+/*
+ * These have to be done with inline assembly: that way the bit-setting
+ * is guaranteed to be atomic. Both set_bit and clear_bit return 0
+ * if the bit-setting went ok, != 0 if the bit already was set/cleared.
+ */
+extern inline int set_bit(int nr,int * addr)
+{
+ char ok;
+
+ __asm__ __volatile__("btsl %1,%2\n\tsetb %0":
+ "=q" (ok):"r" (nr),"m" (*(addr)));
+ return ok;
+}
+
+extern inline int clear_bit(int nr, int * addr)
+{
+ char ok;
+
+ __asm__ __volatile__("btrl %1,%2\n\tsetnb %0":
+ "=q" (ok):"r" (nr),"m" (*(addr)));
+ return ok;
+}
+
+#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
+#define TTY_READ_FLUSH(tty) tty_read_flush((tty))
+
+extern void tty_write_flush(struct tty_struct *);
+extern void tty_read_flush(struct tty_struct *);
extern struct tty_struct tty_table[];
+extern struct serial_struct serial_table[];
+extern struct tty_struct * redirect;
extern int fg_console;
extern unsigned long video_num_columns;
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"
-extern void rs_init(void);
-extern void lp_init(void);
-extern void con_init(void);
-extern void tty_init(void);
+extern long rs_init(long);
+extern long lp_init(long);
+extern long con_init(long);
+extern long tty_init(long);
+
+extern void flush_input(struct tty_struct * tty);
+extern void flush_output(struct tty_struct * tty);
+extern void wait_until_sent(struct tty_struct * tty);
+extern void copy_to_cooked(struct tty_struct * tty);
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);
+extern int kill_pg(int pgrp, int sig, int priv);
+
+/* tty write functions */
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);
+/* serial.c */
+
+extern int serial_open(unsigned int line, struct file * filp);
+extern void serial_close(unsigned int line, struct file * filp);
+extern void change_speed(unsigned int line);
+extern void send_break(unsigned int line);
+extern int get_serial_info(unsigned int, struct serial_struct *);
+extern int set_serial_info(unsigned int, struct serial_struct *);
+
+/* pty.c */
+
+extern int pty_open(unsigned int dev, struct file * filp);
+extern void pty_close(unsigned int dev, struct file * filp);
-void copy_to_cooked(struct tty_struct * tty);
+/* console.c */
void update_screen(int new_console);
+void blank_screen(void);
+void unblank_screen(void);
#endif
--- /dev/null
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef int ssize_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef long ptrdiff_t;
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+typedef int pid_t;
+typedef unsigned short uid_t;
+typedef unsigned short gid_t;
+typedef unsigned short dev_t;
+#ifdef OLD_LINUX
+typedef unsigned short ino_t;
+#else
+typedef unsigned long ino_t;
+#endif
+typedef unsigned short mode_t;
+typedef unsigned short umode_t;
+typedef unsigned short nlink_t;
+typedef int daddr_t;
+typedef long off_t;
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+typedef char *caddr_t;
+
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+typedef unsigned long tcflag_t;
+
+typedef unsigned long fd_set;
+
+typedef struct { int quot,rem; } div_t;
+typedef struct { long quot,rem; } ldiv_t;
+
+struct ustat {
+ daddr_t f_tfree;
+ ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_UN_H
+#define _LINUX_UN_H
+
+struct sockaddr_un {
+ u_short sun_family; /* AF_UNIX */
+ char sun_path[108]; /* pathname */
+};
+
+#endif /* _UN_H */
--- /dev/null
+#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_oldstat 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_oldfstat 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_olduname 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_oldlstat 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
+#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
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+#define __NR_uname 109
+#define __NR_iopl 110
+
+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 */
--- /dev/null
+#ifndef _LINUX_USER_H
+#define _LINUX_USER_H
+
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+ this will be used by gdb to figure out where the data and stack segments
+ are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+ from the ptrace(3,...) function. */
+ struct pt_regs regs; /* Where the registers are actually stored */
+/* ptrace does not yet supply these. Someday.... */
+ int u_fpvalid; /* True if math co-processor being used. */
+ /* for this mess. Not yet used. */
+ struct user_i387_struct i387; /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int signal; /* Signal that caused the core dump. */
+ char * u_comm; /* User command that was responsible */
+ struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
+ unsigned long magic; /* To uniquely identify a core file */
+};
+#define NBPG 4096
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif
--- /dev/null
+#ifndef _LINUX_UTIME_H
+#define _LINUX_UTIME_H
+
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_UTSNAME_H
+#define _LINUX_UTSNAME_H
+
+#define __OLD_UTS_LEN 8
+
+struct old_utsname {
+ char sysname[9];
+ char nodename[9];
+ char release[9];
+ char version[9];
+ char machine[9];
+};
+
+#define __NEW_UTS_LEN 64
+
+struct new_utsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+};
+
+#endif
--- /dev/null
+#ifndef _LINUX_VFS_H
+#define _LINUX_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
--- /dev/null
+#ifndef _LINUX_WAIT_H
+#define _LINUX_WAIT_H
+
+#include <linux/limits.h>
+
+#define WNOHANG 1
+#define WUNTRACED 2
+
+struct wait_queue {
+ struct task_struct * task;
+ struct wait_queue * next;
+};
+
+typedef struct select_table_struct {
+ int nr;
+ struct select_table_entry {
+ struct wait_queue wait;
+ struct wait_queue ** wait_address;
+ } entry[NR_OPEN*3];
+} select_table;
+
+#endif
+++ /dev/null
-#ifndef _SIGNAL_H
-#define _SIGNAL_H
-
-#include <sys/types.h>
-
-typedef int sig_atomic_t;
-typedef unsigned int sigset_t; /* 32 bits */
-
-#define _NSIG 32
-#define NSIG _NSIG
-
-#define SIGHUP 1
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGILL 4
-#define SIGTRAP 5
-#define SIGABRT 6
-#define SIGIOT 6
-#define SIGUNUSED 7
-#define SIGFPE 8
-#define SIGKILL 9
-#define SIGUSR1 10
-#define SIGSEGV 11
-#define SIGUSR2 12
-#define SIGPIPE 13
-#define SIGALRM 14
-#define SIGTERM 15
-#define SIGSTKFLT 16
-#define SIGCHLD 17
-#define SIGCONT 18
-#define SIGSTOP 19
-#define SIGTSTP 20
-#define SIGTTIN 21
-#define SIGTTOU 22
-
-/*
- * Most of these aren't used yet (and perhaps never will),
- * so they are commented out.
- */
-
-/*
-#define SIGIO 23
-#define SIGPOLL SIGIO
-#define SIGXCPU 24
-#define SIGXFSZ 25
-#define SIGVTALRM 26
-#define SIGPROF 27
-*/
-
-#define SIGWINCH 28
-
-/*
-#define SIGLOST 29
-*/
-
-/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
-#define SA_NOCLDSTOP 1
-#define SA_INTERRUPT 0x20000000
-#define SA_NOMASK 0x40000000
-#define SA_ONESHOT 0x80000000
-
-#define SIG_BLOCK 0 /* for blocking signals */
-#define SIG_UNBLOCK 1 /* for unblocking signals */
-#define SIG_SETMASK 2 /* for setting the signal mask */
-
-#define SIG_DFL ((void (*)(int))0) /* default signal handling */
-#define SIG_IGN ((void (*)(int))1) /* ignore signal */
-#define SIG_ERR ((void (*)(int))-1) /* error return from signal */
-
-#ifdef notdef
-#define sigemptyset(mask) ((*(mask) = 0), 1)
-#define sigfillset(mask) ((*(mask) = ~0), 1)
-#endif
-
-struct sigaction {
- void (*sa_handler)(int);
- sigset_t sa_mask;
- int sa_flags;
- void (*sa_restorer)(void);
-};
-
-void (*signal(int _sig, void (*_func)(int)))(int);
-int raise(int sig);
-int kill(pid_t pid, int sig);
-int sigaddset(sigset_t *mask, int signo);
-int sigdelset(sigset_t *mask, int signo);
-int sigemptyset(sigset_t *mask);
-int sigfillset(sigset_t *mask);
-int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */
-int sigpending(sigset_t *set);
-int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
-int sigsuspend(sigset_t *sigmask);
-int sigaction(int sig, struct sigaction *act, struct sigaction *oldact);
-
-#endif /* _SIGNAL_H */
+++ /dev/null
-#ifndef _STDDEF_H
-#define _STDDEF_H
-
-#ifndef _PTRDIFF_T
-#define _PTRDIFF_T
-typedef long ptrdiff_t;
-#endif
-
-#ifndef _SIZE_T
-#define _SIZE_T
-typedef unsigned long size_t;
-#endif
-
-#undef NULL
-#define NULL ((void *)0)
-
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
+++ /dev/null
-#ifndef _SYS_DIRENT_H
-#define _SYS_DIRENT_H
-
-#include <limits.h>
-
-struct dirent {
- long d_ino;
- off_t d_off;
- unsigned short d_reclen;
- char d_name[NAME_MAX+1];
-};
-
-#endif
+++ /dev/null
-#ifndef _SYS_PARAM_H
-#define _SYS_PARAM_H
-
-#define HZ 100
-#define EXEC_PAGESIZE 4096
-
-#define NGROUPS 32 /* Max number of groups per user */
-#define NOGROUP -1
-
-#define MAXHOSTNAMELEN 8
-
-#endif
+++ /dev/null
-/* ptrace.h */
-/* structs and defines to help the user use the ptrace system call. */
-
-#ifndef _SYS_PTRACE_H
-#define _SYS_PTRACE_H
-/* has the defines to get at the registers. */
-/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
- the processes registers. */
-
-#define EBX 0
-#define ECX 1
-#define EDX 2
-#define ESI 3
-#define EDI 4
-#define EBP 5
-#define EAX 6
-#define DS 7
-#define ES 8
-#define FS 9
-#define GS 10
-#define ORIG_EAX 11
-#define EIP 12
-#define CS 13
-#define EFL 14
-#define UESP 15
-#define SS 16
-
-
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- long ds;
- long es;
- long fs;
- long gs;
- long orig_eax;
- long eip;
- long cs;
- long eflags;
- long esp;
- long ss;
-};
-
-#endif /* _SYS_PTRACE_H */
+++ /dev/null
-/*
- * Resource control/accounting header file for linux
- */
-
-#ifndef _SYS_RESOURCE_H
-#define _SYS_RESOURCE_H
-
-/*
- * Definition of struct rusage taken from BSD 4.3 Reno
- *
- * We don't support all of these yet, but we might as well have them....
- * Otherwise, each time we add new items, programs which depend on this
- * structure will lose. This reduces the chances of that happening.
- */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
-
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
- long ru_maxrss; /* maximum resident set size */
- long ru_ixrss; /* integral shared memory size */
- long ru_idrss; /* integral unshared data size */
- long ru_isrss; /* integral unshared stack size */
- long ru_minflt; /* page reclaims */
- long ru_majflt; /* page faults */
- long ru_nswap; /* swaps */
- long ru_inblock; /* block input operations */
- long ru_oublock; /* block output operations */
- long ru_msgsnd; /* messages sent */
- long ru_msgrcv; /* messages received */
- long ru_nsignals; /* signals received */
- long ru_nvcsw; /* voluntary context switches */
- long ru_nivcsw; /* involuntary " */
-};
-
-/*
- * Resource limits
- */
-
-#define RLIMIT_CPU 0 /* CPU time in ms */
-#define RLIMIT_FSIZE 1 /* Maximum filesize */
-#define RLIMIT_DATA 2 /* max data size */
-#define RLIMIT_STACK 3 /* max stack size */
-#define RLIMIT_CORE 4 /* max core file size */
-#define RLIMIT_RSS 5 /* max resident set size */
-
-#ifdef notdef
-#define RLIMIT_MEMLOCK 6 /* max locked-in-memory address space*/
-#define RLIMIT_NPROC 7 /* max number of processes */
-#define RLIMIT_OFILE 8 /* max number of open files */
-#endif
-
-#define RLIM_NLIMITS 6
-
-#define RLIM_INFINITY 0x7fffffff
-
-struct rlimit {
- int rlim_cur;
- int rlim_max;
-};
-
-#endif /* _SYS_RESOURCE_H */
+++ /dev/null
-#ifndef _SYS_STAT_H
-#define _SYS_STAT_H
-
-#include <sys/types.h>
-
-struct stat {
- dev_t st_dev;
- ino_t st_ino;
- umode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- off_t st_size;
- time_t st_atime;
- time_t st_mtime;
- time_t st_ctime;
-};
-
-#define S_IFMT 00170000
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-#define S_IFREG 0100000
-#define S_IFBLK 0060000
-#define S_IFDIR 0040000
-#define S_IFCHR 0020000
-#define S_IFIFO 0010000
-#define S_ISUID 0004000
-#define S_ISGID 0002000
-#define S_ISVTX 0001000
-
-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#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
-#define S_IWUSR 00200
-#define S_IXUSR 00100
-
-#define S_IRWXG 00070
-#define S_IRGRP 00040
-#define S_IWGRP 00020
-#define S_IXGRP 00010
-
-#define S_IRWXO 00007
-#define S_IROTH 00004
-#define S_IWOTH 00002
-#define S_IXOTH 00001
-
-extern int chmod(const char *_path, mode_t mode);
-extern int fstat(int fildes, struct stat *stat_buf);
-extern int mkdir(const char *_path, mode_t mode);
-extern int mkfifo(const char *_path, mode_t mode);
-extern int stat(const char *filename, struct stat *stat_buf);
-extern mode_t umask(mode_t mask);
-
-#endif
+++ /dev/null
-#ifndef _SYS_TIME_H
-#define _SYS_TIME_H
-
-/* gettimofday returns this */
-struct timeval {
- long tv_sec; /* seconds */
- long tv_usec; /* microseconds */
-};
-
-struct timezone {
- int tz_minuteswest; /* minutes west of Greenwich */
- int tz_dsttime; /* type of dst correction */
-};
-
-#define DST_NONE 0 /* not on dst */
-#define DST_USA 1 /* USA style dst */
-#define DST_AUST 2 /* Australian style dst */
-#define DST_WET 3 /* Western European dst */
-#define DST_MET 4 /* Middle European dst */
-#define DST_EET 5 /* Eastern European dst */
-#define DST_CAN 6 /* Canada */
-#define DST_GB 7 /* Great Britain and Eire */
-#define DST_RUM 8 /* Rumania */
-#define DST_TUR 9 /* Turkey */
-#define DST_AUSTALT 10 /* Australian style with shift in 1986 */
-
-#define FD_SETSIZE (8*sizeof(fd_set))
-#define FD_SET(fd,fdsetp) (*(fdsetp) |= (1 << (fd)))
-#define FD_CLR(fd,fdsetp) (*(fdsetp) &= ~(1 << (fd)))
-#define FD_ISSET(fd,fdsetp) ((*(fdsetp) >> fd) & 1)
-#define FD_ZERO(fdsetp) (*(fdsetp) = 0)
-
-/*
- * Operations on timevals.
- *
- * NB: timercmp does not work for >= or <=.
- */
-#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
-#define timercmp(tvp, uvp, cmp) \
- ((tvp)->tv_sec cmp (uvp)->tv_sec || \
- (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
-#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
-
-/*
- * Names of the interval timers, and structure
- * defining a timer setting.
- */
-#define ITIMER_REAL 0
-#define ITIMER_VIRTUAL 1
-#define ITIMER_PROF 2
-
-struct itimerval {
- struct timeval it_interval; /* timer interval */
- struct timeval it_value; /* current value */
-};
-
-#include <time.h>
-#include <sys/types.h>
-
-int gettimeofday(struct timeval * tp, struct timezone * tz);
-int select(int width, fd_set * readfds, fd_set * writefds,
- fd_set * exceptfds, struct timeval * timeout);
-
-#endif /*_SYS_TIME_H*/
+++ /dev/null
-#ifndef _TIMES_H
-#define _TIMES_H
-
-#include <sys/types.h>
-
-struct tms {
- time_t tms_utime;
- time_t tms_stime;
- time_t tms_cutime;
- time_t tms_cstime;
-};
-
-extern time_t times(struct tms * tp);
-
-#endif
+++ /dev/null
-#ifndef _SYS_TYPES_H
-#define _SYS_TYPES_H
-
-#ifndef _SIZE_T
-#define _SIZE_T
-typedef unsigned int size_t;
-#endif
-
-#ifndef _TIME_T
-#define _TIME_T
-typedef long time_t;
-#endif
-
-#ifndef _PTRDIFF_T
-#define _PTRDIFF_T
-typedef long ptrdiff_t;
-#endif
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-typedef int pid_t;
-typedef unsigned short uid_t;
-typedef unsigned short gid_t;
-typedef unsigned short dev_t;
-typedef unsigned short ino_t;
-typedef unsigned short mode_t;
-typedef unsigned short umode_t;
-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;
-
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-typedef unsigned long tcflag_t;
-
-typedef unsigned long fd_set;
-
-typedef struct { int quot,rem; } div_t;
-typedef struct { long quot,rem; } ldiv_t;
-
-struct ustat {
- daddr_t f_tfree;
- ino_t f_tinode;
- char f_fname[6];
- char f_fpack[6];
-};
-
-#endif
+++ /dev/null
-#ifndef _SYS_UTSNAME_H
-#define _SYS_UTSNAME_H
-
-#include <sys/types.h>
-#include <sys/param.h>
-
-struct utsname {
- char sysname[9];
- char nodename[MAXHOSTNAMELEN+1];
- char release[9];
- char version[9];
- char machine[9];
-};
-
-extern int uname(struct utsname * utsbuf);
-
-#endif
+++ /dev/null
-#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
+++ /dev/null
-#ifndef _SYS_WAIT_H
-#define _SYS_WAIT_H
-
-#include <sys/types.h>
-
-#define _LOW(v) ( (v) & 0377)
-#define _HIGH(v) ( ((v) >> 8) & 0377)
-
-/* options for waitpid, WUNTRACED not supported */
-#define WNOHANG 1
-#define WUNTRACED 2
-
-#define WIFEXITED(s) (!((s)&0xFF))
-#define WIFSTOPPED(s) (((s)&0xFF)==0x7F)
-#define WEXITSTATUS(s) (((s)>>8)&0xFF)
-#define WTERMSIG(s) ((s)&0x7F)
-#define WCOREDUMP(s) ((s)&0x80)
-#define WSTOPSIG(s) (((s)>>8)&0xFF)
-#define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF)
-
-pid_t wait(int *stat_loc);
-pid_t waitpid(pid_t pid, int *stat_loc, int options);
-
-#endif
+++ /dev/null
-#ifndef _TERMIOS_H
-#define _TERMIOS_H
-
-#include <sys/types.h>
-
-/* 0x54 is just a magic number to make these relatively uniqe ('T') */
-
-#define TCGETS 0x5401
-#define TCSETS 0x5402
-#define TCSETSW 0x5403
-#define TCSETSF 0x5404
-#define TCGETA 0x5405
-#define TCSETA 0x5406
-#define TCSETAW 0x5407
-#define TCSETAF 0x5408
-#define TCSBRK 0x5409
-#define TCXONC 0x540A
-#define TCFLSH 0x540B
-#define TIOCEXCL 0x540C
-#define TIOCNXCL 0x540D
-#define TIOCSCTTY 0x540E
-#define TIOCGPGRP 0x540F
-#define TIOCSPGRP 0x5410
-#define TIOCOUTQ 0x5411
-#define TIOCSTI 0x5412
-#define TIOCGWINSZ 0x5413
-#define TIOCSWINSZ 0x5414
-#define TIOCMGET 0x5415
-#define TIOCMBIS 0x5416
-#define TIOCMBIC 0x5417
-#define TIOCMSET 0x5418
-#define TIOCGSOFTCAR 0x5419
-#define TIOCSSOFTCAR 0x541A
-#define FIONREAD 0x541B
-#define TIOCINQ FIONREAD
-#define TIOCLINUX 0x541C
-
-struct winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[NCC]; /* control characters */
-};
-
-#define NCCS 17
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IUCLC 0001000
-#define IXON 0002000
-#define IXANY 0004000
-#define IXOFF 0010000
-#define IMAXBEL 0020000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define OLCUC 0000002
-#define ONLCR 0000004
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-#define OFILL 0000100
-#define OFDEL 0000200
-#define NLDLY 0000400
-#define NL0 0000000
-#define NL1 0000400
-#define CRDLY 0003000
-#define CR0 0000000
-#define CR1 0001000
-#define CR2 0002000
-#define CR3 0003000
-#define TABDLY 0014000
-#define TAB0 0000000
-#define TAB1 0004000
-#define TAB2 0010000
-#define TAB3 0014000
-#define XTABS 0014000
-#define BSDLY 0020000
-#define BS0 0000000
-#define BS1 0020000
-#define VTDLY 0040000
-#define VT0 0000000
-#define VT1 0040000
-#define FFDLY 0040000
-#define FF0 0000000
-#define FF1 0040000
-
-/* c_cflag bit meaning */
-#define CBAUD 0000017
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE 0000060
-#define CS5 0000000
-#define CS6 0000020
-#define CS7 0000040
-#define CS8 0000060
-#define CSTOPB 0000100
-#define CREAD 0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL 0002000
-#define CLOCAL 0004000
-#define CIBAUD 03600000 /* input baud rate (not used) */
-#define CRTSCTS 020000000000 /* flow control */
-
-/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* modem lines */
-#define TIOCM_LE 0x001
-#define TIOCM_DTR 0x002
-#define TIOCM_RTS 0x004
-#define TIOCM_ST 0x008
-#define TIOCM_SR 0x010
-#define TIOCM_CTS 0x020
-#define TIOCM_CAR 0x040
-#define TIOCM_RNG 0x080
-#define TIOCM_DSR 0x100
-#define TIOCM_CD TIOCM_CAR
-#define TIOCM_RI TIOCM_RNG
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
-extern speed_t cfgetispeed(struct termios *termios_p);
-extern speed_t cfgetospeed(struct termios *termios_p);
-extern int cfsetispeed(struct termios *termios_p, speed_t speed);
-extern int cfsetospeed(struct termios *termios_p, speed_t speed);
-extern int tcdrain(int fildes);
-extern int tcflow(int fildes, int action);
-extern int tcflush(int fildes, int queue_selector);
-extern int tcgetattr(int fildes, struct termios *termios_p);
-extern int tcsendbreak(int fildes, int duration);
-extern int tcsetattr(int fildes, int optional_actions,
- struct termios *termios_p);
-
-#endif
#define CLOCKS_PER_SEC 100
+#ifndef _CLOCK_T
+#define _CLOCK_T
typedef long clock_t;
+#endif
struct tm {
int tm_sec;
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#ifdef __cplusplus
+extern "C" {
+#endif
+
clock_t clock(void);
time_t time(time_t * tp);
double difftime(time_t time2, time_t time1);
size_t strftime(char * s, size_t smax, const char * fmt, const struct tm * tp);
void tzset(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif
+++ /dev/null
-#ifndef _UNISTD_H
-#define _UNISTD_H
-
-/* ok, this may be a joke, but I'm working on it */
-#define _POSIX_VERSION 198808L
-
-#define _POSIX_CHOWN_RESTRICTED 1 /* only root can do a chown (I think..) */
-#define _POSIX_NO_TRUNC 1 /* no pathname truncation (but see kernel) */
-#define _POSIX_VDISABLE '\0' /* character to disable things like ^C */
-#define _POSIX_JOB_CONTROL 1
-#define _POSIX_SAVED_IDS 1 /* Implemented, for whatever good it is */
-
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-/* access */
-#define F_OK 0
-#define X_OK 1
-#define W_OK 2
-#define R_OK 4
-
-/* lseek */
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
-/* _SC stands for System Configuration. We don't use them much */
-#define _SC_ARG_MAX 1
-#define _SC_CHILD_MAX 2
-#define _SC_CLOCKS_PER_SEC 3
-#define _SC_NGROUPS_MAX 4
-#define _SC_OPEN_MAX 5
-#define _SC_JOB_CONTROL 6
-#define _SC_SAVED_IDS 7
-#define _SC_VERSION 8
-
-/* more (possibly) configurable things - now pathnames */
-#define _PC_LINK_MAX 1
-#define _PC_MAX_CANON 2
-#define _PC_MAX_INPUT 3
-#define _PC_NAME_MAX 4
-#define _PC_PATH_MAX 5
-#define _PC_PIPE_BUF 6
-#define _PC_NO_TRUNC 7
-#define _PC_VDISABLE 8
-#define _PC_CHOWN_RESTRICTED 9
-
-#if 0
-/* XXX - <sys/stat.h> illegally <sys/types.h> already.
- * The rest of these includes are also illegal (too much pollution).
- */
-#include <sys/types.h>
-#endif
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/utsname.h>
-#include <sys/resource.h>
-#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
-#define __NR_mmap 90
-#define __NR_munmap 91
-/*
- * Not all of these are implemented yet, but these are the
- * numbers they will use.
- */
-#define __NR_truncate 92
-#define __NR_ftruncate 93
-#define __NR_fchmod 94
-#define __NR_fchown 95
-#define __NR_getpriority 96
-#define __NR_setpriority 97
-#define __NR_profil 98
-#define __NR_statfs 99
-#define __NR_fstatfs 100
-#define __NR_ioperm 101
-
-/* 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 /* __LIBRARY__ */
-
-/* XXX - illegal. */
-extern int errno;
-
-/* XXX - several non-POSIX functions here, and POSIX functions that are
- * supposed to be declared elsewhere. Non-promotion of short types in
- * prototypes may cause trouble. Arg names should be prefixed by
- * underscores.
- */
-int access(const char * filename, mode_t mode); /* XXX - short type */
-int acct(const char * filename);
-int brk(void * end_data_segment);
-/* XXX - POSIX says unsigned alarm(unsigned sec) */
-int alarm(int sec);
-void * sbrk(ptrdiff_t increment);
-int chdir(const char * filename);
-int chmod(const char * filename, mode_t mode); /* XXX - short type */
-int chown(const char * filename, uid_t owner, gid_t group); /* XXX - shorts */
-int chroot(const char * filename);
-int close(int fildes);
-int creat(const char * filename, mode_t mode); /* XXX - short type */
-int dup(int fildes);
-int execve(const char * filename, char ** argv, char ** envp);
-int execv(const char * pathname, char ** argv);
-int execvp(const char * file, char ** argv);
-int execl(const char * pathname, char * arg0, ...);
-int execlp(const char * file, char * arg0, ...);
-int execle(const char * pathname, char * arg0, ...);
-volatile void exit(int status);
-volatile void _exit(int status);
-int fcntl(int fildes, int cmd, ...);
-pid_t fork(void);
-pid_t getpid(void);
-uid_t getuid(void);
-uid_t geteuid(void);
-gid_t getgid(void);
-gid_t getegid(void);
-int ioctl(int fildes, int cmd, ...);
-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, const char * type, int rwflag);
-int nice(int val);
-int open(const char * filename, int flag, ...);
-int pause(void);
-int pipe(int * fildes);
-/* XXX**2 - POSIX says unsigned count */
-int read(int fildes, char * buf, off_t count);
-int setpgrp(void);
-int setpgid(pid_t pid,pid_t pgid); /* XXX - short types */
-int setuid(uid_t uid); /* XXX - short type */
-int setgid(gid_t gid); /* XXX - short type */
-void (*signal(int sig, void (*fn)(int)))(int);
-int stat(const char * filename, struct stat * stat_buf);
-int fstat(int fildes, struct stat * stat_buf);
-int stime(time_t * tptr);
-int sync(void);
-time_t time(time_t * tloc);
-time_t times(struct tms * tbuf);
-int ulimit(int cmd, long limit);
-mode_t umask(mode_t mask);
-int umount(const char * specialfile);
-int uname(struct utsname * name);
-int unlink(const char * filename);
-int ustat(dev_t dev, struct ustat * ubuf);
-int utime(const char * filename, struct utimbuf * times);
-pid_t waitpid(pid_t pid,int * wait_stat,int options);
-pid_t wait(int * wait_stat);
-/* XXX**2 - POSIX says unsigned count */
-int write(int fildes, const char * buf, off_t count);
-int dup2(int oldfd, int newfd);
-int getppid(void);
-pid_t getpgrp(void);
-pid_t setsid(void);
-int sethostname(char *name, int len);
-int setrlimit(int resource, struct rlimit *rlp);
-int getrlimit(int resource, struct rlimit *rlp);
-int getrusage(int who, struct rusage *rusage);
-int gettimeofday(struct timeval *tv, struct timezone *tz);
-int settimeofday(struct timeval *tv, struct timezone *tz);
-int getgroups(int gidsetlen, gid_t *gidset);
-int setgroups(int gidsetlen, gid_t *gidset);
-int select(int width, fd_set * readfds, fd_set * writefds,
- fd_set * exceptfds, struct timeval * timeout);
-int swapon(const char * specialfile);
-#endif
+++ /dev/null
-#ifndef _UTIME_H
-#define _UTIME_H
-
-#include <sys/types.h> /* I know - shouldn't do this, but .. */
-
-struct utimbuf {
- time_t actime;
- time_t modtime;
-};
-
-extern int utime(const char *filename, struct utimbuf *times);
-
-#endif
/*
* linux/init/main.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#define __LIBRARY__
-#include <unistd.h>
+#include <stdarg.h>
#include <time.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include <linux/fcntl.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
static inline _syscall0(int,pause)
static inline _syscall1(int,setup,void *,BIOS)
static inline _syscall0(int,sync)
-
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/head.h>
-#include <linux/string.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>
+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 _syscall3(int,open,const char *,file,int,flag,int,mode)
+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 init_IRQ(void);
+extern long blk_dev_init(long,long);
+extern long chr_dev_init(long,long);
extern void hd_init(void);
extern void floppy_init(void);
-extern void mem_init(long start, long end);
+extern void sock_init(void);
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;
* This is set up by the setup-routine at boot-time
*/
#define EXT_MEM_K (*(unsigned short *)0x90002)
-#define CON_ROWS ((*(unsigned short *)0x9000e) & 0xff)
-#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
+#define SCREEN_INFO (*(struct screen_info *)0x90000)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
/*
startup_time = kernel_mktime(&time);
}
-static long memory_end = 0;
-static long buffer_memory_end = 0;
-static long main_memory_start = 0;
+static unsigned long memory_start = 0;
+static unsigned long memory_end = 0;
+
static char term[32];
static char * argv_init[] = { "/bin/init", NULL };
static char * envp[] = { "HOME=/usr/root", NULL, NULL };
struct drive_info { char dummy[32]; } drive_info;
+struct screen_info screen_info;
void start_kernel(void)
{
* enable them
*/
ROOT_DEV = ORIG_ROOT_DEV;
- sprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS);
+ drive_info = DRIVE_INFO;
+ screen_info = SCREEN_INFO;
+ sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
envp[1] = term;
envp_rc[1] = term;
envp_init[1] = term;
- drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
- if (memory_end >= 12*1024*1024)
- buffer_memory_end = 4*1024*1024;
- else if (memory_end >= 6*1024*1024)
- buffer_memory_end = 2*1024*1024;
- else if (memory_end >= 4*1024*1024)
- buffer_memory_end = 3*512*1024;
- else
- buffer_memory_end = 1*1024*1024;
- main_memory_start = buffer_memory_end;
-#ifdef RAMDISK
- main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
-#endif
- mem_init(main_memory_start,memory_end);
+ memory_start = 1024*1024;
trap_init();
- chr_dev_init();
- blk_dev_init();
- time_init();
+ init_IRQ();
sched_init();
- buffer_init(buffer_memory_end);
+ memory_start = chr_dev_init(memory_start,memory_end);
+ memory_start = blk_dev_init(memory_start,memory_end);
+ memory_start = mem_init(memory_start,memory_end);
+ buffer_init();
+ time_init();
+ printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
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();
}
/*
- * NOTE!! For any other task 'pause()' would mean we have to get a
- * signal to awaken, but task0 is the sole exception (see 'schedule()')
- * as task 0 gets activated at every idle moment (when no other tasks
- * can run). For task0 'pause()' just means we go check if some other
- * task can run, and if not we return here.
+ * task[0] is meant to be used as an "idle" task: it may not sleep, but
+ * it might do some general things like count free pages or it could be
+ * used to implement a reasonable LRU algorithm for the paging routines:
+ * anything that can be useful, but shouldn't take time from the real
+ * processes.
+ *
+ * Right now task[0] just does a infinite loop in user mode.
*/
for(;;)
- __asm__("int $0x80"::"a" (__NR_pause):"ax");
+ /* nothing */ ;
}
static int printf(const char *fmt, ...)
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
- printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
- NR_BUFFERS*BLOCK_SIZE);
- printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
+ printf("%d buffers = %d bytes buffer space\n\r",nr_buffers,
+ nr_buffers*BLOCK_SIZE);
+ printf("Free mem: %d bytes\n\r",memory_end-memory_start);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-AR =ar
-AS =as
-LD =ld
-LDFLAGS =-s -x
-CC =gcc -nostdinc -I../include
-CPP =cpp -nostdinc -I../include
-
-
.S.s:
$(CPP) -traditional $< -o $*.s
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
+
+SUBDIRS = chr_drv blk_drv math
-OBJS = sched.o sys_call.o traps.o asm.o fork.o \
+OBJS = sched.o sys_call.o traps.o irq.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
- signal.o mktime.o ptrace.o ioport.o
+ signal.o mktime.o ptrace.o ioport.o itimer.o
+
+all: kernel.o kernelsubdirs
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
sync
+kernelsubdirs: dummy
+ @for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
+
sys_call.s: sys_call.S
sys_call.o: sys_call.s
clean:
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)
- (cd math; make clean)
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
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
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
- (cd chr_drv; make dep)
- (cd blk_drv; make dep)
- (cd math; make dep)
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep) || exit; done
+
+dummy:
### 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/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 \
- ../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/linux/config_rel.h \
- ../include/linux/config_ver.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
+exit.o : exit.c /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/asm/segment.h
+fork.o : fork.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/stddef.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h
+ioport.o : ioport.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h
+irq.o : irq.c /usr/src/linux/include/linux/ptrace.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/irq.h
+itimer.o : itimer.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/segment.h
+mktime.o : mktime.c /usr/src/linux/include/time.h
+panic.o : panic.c /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+printk.o : printk.c /usr/src/linux/include/stdarg.h /usr/src/linux/include/asm/segment.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+ptrace.o : ptrace.c /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/kernel.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/ptrace.h /usr/src/linux/include/asm/segment.h \
+ /usr/src/linux/include/asm/system.h
+sched.o : sched.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/sys.h /usr/src/linux/include/linux/fdreg.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/ptrace.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h
+signal.o : signal.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/ptrace.h /usr/src/linux/include/asm/segment.h
+sys.o : sys.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/times.h /usr/src/linux/include/linux/utsname.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/segment.h
+traps.o : traps.c /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/io.h
+vsprintf.o : vsprintf.c /usr/src/linux/include/stdarg.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/string.h
+++ /dev/null
-/*
- * linux/kernel/asm.s
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * 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 _hd_interrupt,_floppy_interrupt,_parallel_interrupt
-
-_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
# parent makefile.
#
-AR =ar
-AS =as
-LD =ld
-LDFLAGS =-s -x
-CC =gcc -nostdinc -I../../include
-CPP =cpp -nostdinc -I../../include
-
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) $(RAMDISK) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) $(RAMDISK) -c $<
+
+SUBDIRS = scsi
+
+OBJS = hd.o ll_rw_blk.o floppy.o ramdisk.o genhd.o
-OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o
+all: blk_drv.a scsisubdirs
blk_drv.a: $(OBJS)
+ rm -f blk_drv.a
$(AR) rcs blk_drv.a $(OBJS)
sync
+scsisubdirs: dummy
+ @for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
+
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
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
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
+ for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep); done
+
+dummy:
### 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/config_rel.h \
- ../../include/linux/config_ver.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 \
+floppy.o : floppy.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/fdreg.h /usr/src/linux/include/linux/fd.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h \
+ /usr/src/linux/include/asm/segment.h blk.h
+genhd.o : genhd.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/genhd.h \
+ /usr/src/linux/include/linux/kernel.h
+hd.o : hd.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/hdreg.h /usr/src/linux/include/linux/genhd.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h \
+ blk.h
+ll_rw_blk.o : ll_rw_blk.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/system.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/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/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/asm/memory.h blk.h
+ramdisk.o : ramdisk.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h
#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
int errors;
unsigned long sector;
unsigned long nr_sectors;
+ unsigned long current_nr_sectors;
char * buffer;
- struct task_struct * waiting;
+ struct wait_queue * waiting;
struct buffer_head * bh;
+ struct buffer_head * bhtail;
struct request * next;
};
* are much more time-critical than writes.
*/
#define IN_ORDER(s1,s2) \
-((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd && \
+((s1)->cmd < (s2)->cmd || ((s1)->cmd == (s2)->cmd && \
((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \
(s1)->sector < (s2)->sector)))))
struct request * current_request;
};
+
+struct sec_size {
+ unsigned block_size;
+ unsigned block_size_bits;
+};
+
+/*
+ * These will have to be changed to be aware of different buffer
+ * sizes etc..
+ */
+#define SECTOR_MASK ((1 << (BLOCK_SIZE_BITS - 9)) -1)
+#define SUBSECTOR(block) ((block) & SECTOR_MASK)
+
+extern struct sec_size * blk_sec[NR_BLK_DEV];
extern struct blk_dev_struct blk_dev[NR_BLK_DEV];
extern struct request request[NR_REQUEST];
-extern struct task_struct * wait_for_request;
+extern struct wait_queue * wait_for_request;
extern int * blk_size[NR_BLK_DEV];
+extern int is_read_only(int dev);
+extern void set_device_ro(int dev,int flag);
+
+#define RO_IOCTLS(dev,where) \
+ case BLKROSET: if (!suser()) return -EPERM; \
+ set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
+ case BLKROGET: verify_area((void *) (where), sizeof(long)); \
+ put_fs_long(is_read_only(dev),(long *) (where)); return 0;
+
#ifdef MAJOR_NR
/*
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == 8)
+/* scsi disk */
+#define DEVICE_NAME "scsidisk"
+#define DEVICE_INTR do_sd
+#define TIMEOUT_VALUE 200
+#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"
#endif
+#ifndef CURRENT
#define CURRENT (blk_dev[MAJOR_NR].current_request)
+#endif
+
#define CURRENT_DEV DEVICE_NR(CURRENT->dev)
#ifdef DEVICE_INTR
wake_up(&bh->b_wait);
}
-extern inline void end_request(int uptodate)
+static void end_request(int uptodate)
{
- DEVICE_OFF(CURRENT->dev);
- if (CURRENT->bh) {
- CURRENT->bh->b_uptodate = uptodate;
- unlock_buffer(CURRENT->bh);
- }
+ struct request * req;
+ struct buffer_head * bh;
+
+ req = CURRENT;
+ req->errors = 0;
if (!uptodate) {
printk(DEVICE_NAME " I/O error\n\r");
- printk("dev %04x, block %d\n\r",CURRENT->dev,
- CURRENT->bh->b_blocknr);
+ printk("dev %04x, sector %d\n\r",req->dev,req->sector);
+ req->nr_sectors--;
+ req->nr_sectors &= ~SECTOR_MASK;
+ req->sector += (BLOCK_SIZE / 512);
+ req->sector &= ~SECTOR_MASK;
+ }
+
+ if (bh = req->bh) {
+ req->bh = bh->b_reqnext;
+ bh->b_reqnext = NULL;
+ bh->b_uptodate = uptodate;
+ unlock_buffer(bh);
+ if (bh = req->bh) {
+ req->current_nr_sectors = bh->b_size >> 9;
+ if (req->nr_sectors < req->current_nr_sectors) {
+ req->nr_sectors = req->current_nr_sectors;
+ printk("end_request: buffer-list destroyed\n");
+ }
+ req->buffer = bh->b_data;
+ return;
+ }
}
- wake_up(&CURRENT->waiting);
+ DEVICE_OFF(req->dev);
+ CURRENT = req->next;
+ wake_up(&req->waiting);
+ req->dev = -1;
wake_up(&wait_for_request);
- CURRENT->dev = -1;
- CURRENT = CURRENT->next;
}
#ifdef DEVICE_INTR
#endif
#define INIT_REQUEST \
-repeat: \
if (!CURRENT) {\
CLEAR_INTR; \
return; \
/*
* linux/kernel/floppy.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* 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 signal detection.
+ */
+
+/*
+ * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
+ * FDC data overrun bug, added some preliminary stuff for vertical
+ * recording support.
+ * TODO: Errors are still not counted properly.
+ */
+
+#define REALLY_SLOW_IO
+#define FLOPPY_IRQ 6
+
#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 <linux/errno.h>
+#ifdef HHB_SYSMACROS
+#include <linux/system.h>
+#endif
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.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;
#define TYPE(x) ((x)>>2)
#define DRIVE(x) ((x)&0x03)
+
/*
* Note that MAX_ERRORS=X doesn't imply that we retry every bad read
* max X times - some types of errors increase the errorcount by 2 or
*/
#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
+
+/*
+ * The DMA channel used by the floppy controller cannot access data at
+ * addresses >= 1MB
+ */
+#define LAST_DMA_ADDR (0x100000 - BLOCK_SIZE)
+
/*
* globals used by 'result()'
*/
#define ST3 (reply_buffer[3])
/*
- * This struct defines the different floppy types. Unlike minix
- * linux doesn't have a "search for right type"-type, as the code
- * for that is convoluted and weird. I've got enough problems with
- * this driver as it is.
+ * This struct defines the different floppy types.
*
- * The 'stretch' tells if the tracks need to be boubled for some
+ * The 'stretch' tells if the tracks need to be doubled for some
* 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,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 */
};
-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 */
+/*
+ * Auto-detection. Each drive type has a pair of formats which are
+ * used in succession to try to read the disk. If the FDC cannot lock onto
+ * the disk, the next format is tried. This uses the variable 'probing'.
+ */
+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];
+
/*
- * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
+ * 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_interrupt() 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 };
+
+/* Prevent "aliased" accesses. */
+
+static fd_ref[4] = { 0,0,0,0 };
+static fd_device[4] = { 0,0,0,0 };
+
+/* Synchronization of FDC access. */
+static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
+static struct wait_queue *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))
+
+/*
+ * Treshold for reporting FDC errors to the console.
+ * Setting this to zero may flood your screen when using
+ * ultra cheap floppies ;-)
+ */
+static unsigned short min_report_error_cnt[4] = {2, 2, 2, 2};
+
+/*
+ * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
* Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
* H is head unload time (1=16ms, 2=32ms, etc)
*
* and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
*/
-extern void floppy_interrupt(void);
-extern char tmp_floppy_area[1024];
-extern char floppy_track_buffer[512*2*18];
+/*
+ * Track buffer and block buffer (in case track buffering doesn't work).
+ * Because these are written to by the DMA controller, they must
+ * not contain a 64k byte boundary crossing, or data will be
+ * corrupted/lost. Alignment of these is enforced in boot/head.s.
+ * Note that you must not change the sizes below without updating head.s.
+ */
+extern char tmp_floppy_area[BLOCK_SIZE];
+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
*/
#define NO_TRACK 255
-static int read_track = 0; /* flag to indicate if we want to read all track */
+static int read_track = 0; /* flag to indicate if we want to read entire track */
static int buffer_track = -1;
static int buffer_drive = -1;
static int cur_spec1 = -1;
static unsigned char seek_track = 0;
static unsigned char current_track = NO_TRACK;
static unsigned char command = 0;
+static unsigned char fdc_version = FDC_TYPE_STD; /* FDC version code */
unsigned char selected = 0;
-struct task_struct * wait_on_floppy_select = NULL;
+struct wait_queue * wait_on_floppy_select = NULL;
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
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;
changed_floppies &= ~mask;
recalibrate = 1;
return 1;
- }
+ }
return 0;
}
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;
count = floppy->sect*2*512;
addr = (long) floppy_track_buffer;
- } else if (addr >= 0x100000) {
+ } else if (addr >= LAST_DMA_ADDR) {
addr = (long) tmp_floppy_area;
if (command == FD_WRITE)
copy_buffer(CURRENT->buffer,tmp_floppy_area);
}
/* mask DMA 2 */
+ cli();
+#ifndef HHB_SYSMACROS
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 */
immoutb_p(count,5);
/* activate DMA 2 */
immoutb_p(0|2,10);
+#else /* just to show off my macros -- hhb */
+ DISABLE_DMA(DMA2);
+ CLEAR_DMA_FF(DMA2);
+ SET_DMA_MODE(DMA2, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
+ SET_DMA_ADDR(DMA2, addr);
+ SET_DMA_COUNT(DMA2, count);
+ ENABLE_DMA(DMA2);
+#endif
sti();
}
return -1;
for (counter = 0 ; counter < 10000 ; counter++) {
status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
- if (status == STATUS_READY)
+ if (status == STATUS_READY) {
return i;
+ }
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
- if (i >= MAX_REPLIES)
+ if (i >= MAX_REPLIES) {
+ printk("floppy_stat reply overrun\n");
break;
+ }
reply_buffer[i++] = inb_p(FD_DATA);
}
}
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;
}
/*
- * Ok, this interrupt is called after a DMA read/write has succeeded,
- * so we check the results, and copy any buffers.
+ * This has only been tested for the case fdc_version == FDC_TYPE_STD.
+ * In case you have a 82077 and want to test it, you'll have to compile
+ * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for
+ * recognizing drives with vertical recording support.
+ */
+static void configure_fdc_mode(void)
+{
+ if (fdc_version == FDC_TYPE_82077) {
+ /* Enhanced version with FIFO & vertical recording. */
+ output_byte(FD_CONFIGURE);
+ output_byte(0);
+ output_byte(0x1A); /* FIFO on, polling off, 10 byte treshold */
+ output_byte(0); /* precompensation from track 0 upwards */
+ printk(DEVICE_NAME ": FIFO enabled\n");
+ }
+} /* configure_fdc_mode */
+
+
+static void tell_sector(int nr)
+{
+ if (nr!=7) {
+ printk(" -- FDC reply errror");
+ reset = 1;
+ } else
+ printk(": track %d, head %d, sector %d", reply_buffer[3],
+ reply_buffer[4], reply_buffer[5]);
+} /* tell_sector */
+
+
+/*
+ * Ok, this interrupt is called after a DMA read/write has succeeded
+ * or failed, so we check the results, and copy any buffers.
+ * hhb: Added better error reporting.
*/
static void rw_interrupt(void)
{
char * buffer_area;
+ int nr;
+ char bad;
- if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
- if (ST1 & 0x02) {
- printk("Drive %d is write protected\n\r",current_drive);
- floppy_deselect(current_drive);
- end_request(0);
- } else
+ nr = result();
+ /* check IC to find cause of interrupt */
+ switch ((ST0 & ST0_INTR)>>6) {
+ case 1: /* error occured during command execution */
+ bad = 1;
+ if (ST1 & ST1_WP) {
+ printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive);
+ floppy_deselect(current_drive);
+ request_done(0);
+ bad = 0;
+ } else if (ST1 & ST1_OR) {
+ printk(DEVICE_NAME ": Over/Underrun - retrying\n");
+ /* could continue from where we stopped, but ... */
+ bad = 0;
+ } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {
+ printk(DEVICE_NAME " %d: ", ST0 & ST0_DS);
+ if (ST0 & ST0_ECE) {
+ printk("Recalibrate failed!");
+ } else if (ST2 & ST2_CRC) {
+ printk("data CRC error");
+ tell_sector(nr);
+ } else if (ST1 & ST1_CRC) {
+ printk("CRC error");
+ tell_sector(nr);
+ } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) {
+ if (!probing) {
+ printk("sector not found");
+ tell_sector(nr);
+ } else
+ printk("probe failed...");
+ } else if (ST2 & ST2_WC) { /* seek error */
+ printk("wrong cylinder");
+ } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
+ printk("bad cylinder");
+ } else {
+ printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3);
+ }
+ printk("\n");
+
+ }
+ if (bad)
+ bad_flp_intr();
+ redo_fd_request();
+ return;
+ case 2: /* invalid command given */
+ printk(DEVICE_NAME ": Invalid FDC command given!\n");
+ request_done(0);
+ return;
+ case 3:
+ printk(DEVICE_NAME ": Abnormal termination caused by polling\n");
bad_flp_intr();
- do_fd_request();
- return;
+ redo_fd_request();
+ return;
+ default: /* (0) Normal command termination */
+ break;
+ }
+
+ 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;
((sector-1 + head*floppy->sect)<<9);
copy_buffer(buffer_area,CURRENT->buffer);
} else if (command == FD_READ &&
- (unsigned long)(CURRENT->buffer) >= 0x100000)
+ (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR)
copy_buffer(tmp_floppy_area,CURRENT->buffer);
floppy_deselect(current_drive);
- end_request(1);
- do_fd_request();
+ request_done(1);
+ redo_fd_request();
}
/*
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); /* sector size = 512 */
- output_byte(floppy->sect);
- output_byte(floppy->gap);
- output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
+ output_byte(2);
+ output_byte(floppy->sect);
+ output_byte(floppy->fmt_gap);
+ output_byte(FD_FILL_BYTE);
+ }
if (reset)
- do_fd_request();
+ redo_fd_request();
}
/*
/* sense drive status */
output_byte(FD_SENSEI);
if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
+ printk(DEVICE_NAME ": seek failed\n");
recalibrate = 1;
bad_flp_intr();
- do_fd_request();
+ redo_fd_request();
return;
}
current_track = ST1;
setup_rw_floppy();
}
+/* Set perpendicular mode as required, based on data rate, if supported.
+ * 80277: 1Mbps data rate only possible with 82077-1.
+ * Untested!! TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
+ */
+static void inline perpendicular_mode(unsigned char rate)
+{
+ if (fdc_version == FDC_TYPE_82077) {
+ output_byte(FD_PERPENDICULAR);
+ if (rate & 0x40) {
+ unsigned char r = rate & 0x03;
+ if (r == 0)
+ output_byte(2); /* perpendicular, 500 kbps */
+ else if (r == 3)
+ output_byte(3); /* perpendicular, 1Mbps */
+ else {
+ printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
+ reset = 1;
+ }
+ } else
+ output_byte(0); /* conventional mode */
+ } else {
+ if (rate & 0x40) {
+ printk(DEVICE_NAME ": perpendicular mode not supported by FDC.\n");
+ reset = 1;
+ }
+ }
+} /* perpendicular_mode */
+
/*
* This routine is called when everything should be correctly set up
* for the transfer (ie floppy motor is on and the correct floppy is
*/
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);
output_byte(cur_spec1); /* hut etc */
output_byte(6); /* Head load time =6ms, DMA */
}
- if (cur_rate != floppy->rate)
- outb_p(cur_rate = floppy->rate,FD_DCR);
+ if (cur_rate != floppy->rate) {
+ /* use bit 6 of floppy->rate to indicate perpendicular mode */
+ perpendicular_mode(floppy->rate);
+ outb_p(cur_rate = ((floppy->rate)) & ~0x40, FD_DCR);
+ }
if (reset) {
- do_fd_request();
+ redo_fd_request();
return;
}
if (!seek) {
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(void);
+
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)
+static void unexpected_floppy_interrupt(void)
{
current_track = NO_TRACK;
output_byte(FD_SENSEI);
+ printk(DEVICE_NAME ": unexpected interrupt\n");
if (result()!=2 || (ST0 & 0xE0) == 0x60)
reset = 1;
else
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
if (reset)
- do_fd_request();
+ redo_fd_request();
}
+/*
+ * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
+ */
static void reset_interrupt(void)
{
- output_byte(FD_SENSEI);
- (void) result();
+ short i;
+
+ for (i=0; i<4; i++) {
+ output_byte(FD_SENSEI);
+ (void) result();
+ }
output_byte(FD_SPECIFY);
output_byte(cur_spec1); /* hut etc */
output_byte(6); /* Head load time =6ms, DMA */
- do_fd_request();
+ configure_fdc_mode(); /* reprogram if smart fdc */
+ if (!recover) redo_fd_request();
+ else {
+ recalibrate_floppy();
+ recover = 0;
+ }
}
/*
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();
transfer();
}
-void do_fd_request(void)
+static void setup_format_params(void)
+{
+ unsigned char *here = (unsigned char *) tmp_floppy_area;
+ int count;
+
+ /* XXX: should do a check to see this fits in tmp_floppy_area!! */
+ 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;
+ int device;
- INIT_REQUEST;
+repeat:
+ if (format_status == FORMAT_WAIT)
+ format_status = FORMAT_BUSY;
+ if (format_status != FORMAT_BUSY) {
+ if (!CURRENT) {
+ if (!fdc_busy)
+ printk("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;
- }
- 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;
+ 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;
+ }
+ } else {
+ if (current_drive != (format_req.device & 3))
+ current_track = NO_TRACK;
+ current_drive = format_req.device & 3;
+ if (((unsigned) 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)
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;
+
+ switch (cmd) {
+ RO_IOCTLS(inode->i_rdev,param);
+ }
+ 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;
+ case FDSETEMSGTRESH:
+ min_report_error_cnt[drive] = (unsigned short) (param & 0x0f);
+ 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[1] = NULL;
+ else {
+ printk(", ");
+ base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
+ }
+ base_type[2] = base_type[3] = NULL;
+ printk("\r\n");
+}
+
+/*
+ * floppy_open check for aliasing (/dev/fd0 can be the same as
+ * /dev/PS0 etc), and disallows simultaneous access to the same
+ * drive with different device numbers.
+ */
+static int floppy_open(struct inode * inode, struct file * filp)
+{
+ int drive;
+ int old_dev;
+
+ drive = inode->i_rdev & 3;
+ old_dev = fd_device[drive];
+ if (fd_ref[drive])
+ if (old_dev != inode->i_rdev)
+ return -EBUSY;
+ fd_ref[drive]++;
+ fd_device[drive] = inode->i_rdev;
+ if (old_dev && old_dev != inode->i_rdev)
+ invalidate_buffers(old_dev);
+ if (filp && 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);
+ if (!fd_ref[inode->i_rdev & 3]--) {
+ printk("floppy_release with fd_ref == 0");
+ fd_ref[inode->i_rdev & 3] = 0;
+ }
+}
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, /* close - default */
NULL, /* select */
- NULL /* ioctl */
+ fd_ioctl, /* ioctl */
+ floppy_open, /* open */
+ floppy_release /* release */
+};
+
+
+/*
+ * The version command is not supposed to generate an interrupt, but
+ * my FDC does, except when booting in SVGA screen mode.
+ * When it does generate an interrupt, it doesn't return any status bytes.
+ * It appears to have something to do with the version command...
+ */
+static void ignore_interrupt(void)
+{
+ if (result() != 0) {
+ printk(DEVICE_NAME ": weird interrupt ignored\n");
+ reset = 1;
+ }
+ CLEAR_INTR; /* ignore only once */
+}
+
+
+static void floppy_interrupt(int unused)
+{
+ void (*handler)(void) = DEVICE_INTR;
+
+ DEVICE_INTR = NULL;
+ if (!handler)
+ handler = unexpected_floppy_interrupt;
+ handler();
+}
+
+/*
+ * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled.
+ */
+static struct sigaction floppy_sigaction = {
+ floppy_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
};
void floppy_init(void)
blk_size[MAJOR_NR] = floppy_sizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blkdev_fops[MAJOR_NR] = &floppy_fops;
- set_intr_gate(0x26,&floppy_interrupt);
- outb(inb_p(0x21)&~0x40,0x21);
+ timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
+ timer_active &= ~(1 << FLOPPY_TIMER);
+ config_types();
+ if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
+ printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ);
+
+ /* Try to determine the floppy controller type */
+ DEVICE_INTR = ignore_interrupt; /* don't ask ... */
+ output_byte(FD_VERSION); /* get FDC version code */
+ if (result() != 1) {
+ printk(DEVICE_NAME ": FDC failed to return version byte\n");
+ fdc_version = FDC_TYPE_STD;
+ } else
+ fdc_version = reply_buffer[0];
+ if (fdc_version != FDC_TYPE_STD)
+ printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);
+#ifndef FDC_FIFO_UNTESTED
+ fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */
+#endif
+ configure_fdc_mode();
}
--- /dev/null
+/*
+ * Code extracted from
+ * linux/kernel/hd.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ * in the early extended-partition checks and added DM partitions
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+struct gendisk *gendisk_head = NULL;
+
+static int current_minor = 0;
+extern int *blk_size[];
+/*
+ * Create devices for each logical partition in an extended partition.
+ * The logical partitions form a linked list, with each entry being
+ * a partition table with two entries. The first entry
+ * is the real data partition (with a start relative to the partition
+ * table start). The second is a pointer to the next logical partition
+ * (with a start relative to the entire extended partition).
+ * We do not create a Linux partition for the partition tables, but
+ * only for the actual data partitions.
+ */
+
+static void extended_partition(struct gendisk *hd, int dev)
+{
+ struct buffer_head *bh;
+ struct partition *p;
+ unsigned long first_sector, this_sector;
+ int mask = (1 << hd->minor_shift) - 1;
+
+ first_sector = hd->part[MINOR(dev)].start_sect;
+ this_sector = first_sector;
+
+ while (1) {
+ if ((current_minor & mask) >= (4 + hd->max_p))
+ return;
+ if (!(bh = bread(dev,0,1024))) {
+ printk("Unable to read partition table of device %04x\n",dev);
+ return;
+ }
+ /*
+ * This block is from a device that we're about to stomp on.
+ * So make sure nobody thinks this block is usable.
+ */
+ bh->b_dirt=0;
+ bh->b_uptodate=0;
+ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+ p = 0x1BE + (void *)bh->b_data;
+ /*
+ * Process the first entry, which should be the real
+ * data partition.
+ */
+ if (p->sys_ind == EXTENDED_PARTITION ||
+ !(hd->part[current_minor].nr_sects = p->nr_sects))
+ goto done; /* shouldn't happen */
+ hd->part[current_minor].start_sect = this_sector + p->start_sect;
+ printk(" Logical part %d start %d size %d end %d\n\r",
+ current_minor, hd->part[current_minor].start_sect,
+ hd->part[current_minor].nr_sects,
+ hd->part[current_minor].start_sect +
+ hd->part[current_minor].nr_sects - 1);
+ current_minor++;
+ p++;
+ /*
+ * Process the second entry, which should be a link
+ * to the next logical partition. Create a minor
+ * for this just long enough to get the next partition
+ * table. The minor will be reused for the real
+ * data partition.
+ */
+ if (p->sys_ind != EXTENDED_PARTITION ||
+ !(hd->part[current_minor].nr_sects = p->nr_sects))
+ goto done; /* no more logicals in this partition */
+ hd->part[current_minor].start_sect = first_sector + p->start_sect;
+ this_sector = first_sector + p->start_sect;
+ dev = ((hd->major) << 8) | current_minor;
+ brelse(bh);
+ } else
+ goto done;
+ }
+done:
+ brelse(bh);
+}
+
+static void check_partition(struct gendisk *hd, unsigned int dev)
+{
+ int i, minor = current_minor;
+ struct buffer_head *bh;
+ struct partition *p;
+ unsigned long first_sector;
+
+ first_sector = hd->part[MINOR(dev)].start_sect;
+
+ if (!(bh = bread(dev,0,1024))) {
+ printk("Unable to read partition table of device %04x\n",dev);
+ return;
+ }
+ printk("%s%d :\n\r", hd->major_name, minor >> hd->minor_shift);
+ current_minor += 4; /* first "extra" minor */
+ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+ p = 0x1BE + (void *)bh->b_data;
+ for (i=1 ; i<=4 ; minor++,i++,p++) {
+ if (!(hd->part[minor].nr_sects = p->nr_sects))
+ continue;
+ hd->part[minor].start_sect = first_sector + p->start_sect;
+ printk(" part %d start %d size %d end %d \n\r", i,
+ hd->part[minor].start_sect, hd->part[minor].nr_sects,
+ hd->part[minor].start_sect + hd->part[minor].nr_sects - 1);
+ if ((current_minor & 0x3f) >= 60)
+ continue;
+ if (p->sys_ind == EXTENDED_PARTITION) {
+ extended_partition(hd, (hd->major << 8) | minor);
+ }
+ }
+ /*
+ * check for Disk Manager partition table
+ */
+ if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
+ p = 0x1BE + (void *)bh->b_data;
+ for (i = 4 ; i < 16 ; i++, current_minor++) {
+ p--;
+ if ((current_minor & 0x3f) >= 60)
+ break;
+ if (!(p->start_sect && p->nr_sects))
+ continue;
+ hd->part[current_minor].start_sect = p->start_sect;
+ hd->part[current_minor].nr_sects = p->nr_sects;
+ printk(" DM part %d start %d size %d end %d\n\r",
+ current_minor,
+ hd->part[current_minor].start_sect,
+ hd->part[current_minor].nr_sects,
+ hd->part[current_minor].start_sect +
+ hd->part[current_minor].nr_sects - 1);
+ }
+ }
+ } else
+ printk("Bad partition table on dev %04x\n",dev);
+ brelse(bh);
+}
+
+static void setup_dev(struct gendisk *dev)
+{
+ int i;
+ int j = dev->max_nr * dev->max_p;
+ int major = dev->major << 8;
+ int drive;
+
+
+ for (i = 0 ; i < j; i++) {
+ dev->part[i].start_sect = 0;
+ dev->part[i].nr_sects = 0;
+ }
+ dev->init();
+ for (drive=0 ; drive<dev->nr_real ; drive++) {
+ current_minor = 1+(drive<<dev->minor_shift);
+ check_partition(dev, major+(drive<<dev->minor_shift));
+ }
+ for (i=0 ; i < j ; i++)
+ dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+ blk_size[dev->major] = dev->sizes;
+}
+
+/* This may be used only once, enforced by 'static int callable' */
+int sys_setup(void * BIOS)
+{
+ static int callable = 1;
+ struct gendisk *p;
+ int nr=0;
+
+ if (!callable)
+ return -1;
+ callable = 0;
+
+ for (p = gendisk_head ; p ; p=p->next) {
+ setup_dev(p);
+ nr += p->nr_real;
+ }
+
+ if (nr)
+ printk("Partition table%s ok.\n\r",(nr>1)?"s":"");
+
+#ifdef RAMDISK
+ rd_load();
+#endif
+ mount_root();
+ return (0);
+}
/*
* linux/kernel/hd.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* in the early extended-partition checks and added DM partitions
*/
-#include <errno.h>
-
#include <linux/config.h>
+#ifdef CONFIG_BLK_DEV_HD
+
+#define HD_IRQ 14
+
+#include <linux/errno.h>
+#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
+#include <linux/genhd.h>
+
+#define REALLY_SLOW_IO
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
return inb_p(0x71);
}
+#define HD_DELAY 0
+
/* Max read/write errors/sector */
#define MAX_ERRORS 7
#define MAX_HD 2
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.
*/
static int NR_HD = 0;
#endif
-static struct hd_struct {
- long start_sect;
- long nr_sects;
-} hd[MAX_HD<<6]={{0,0},};
-
+static struct hd_struct hd[MAX_HD<<6]={{0,0},};
static int hd_sizes[MAX_HD<<6] = {0, };
#define port_read(port,buf,nr) \
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
-extern void hd_interrupt(void);
-extern void rd_load(void);
-
-static unsigned int current_minor;
-
-/*
- * Create devices for each logical partition in an extended partition.
- * The logical partitions form a linked list, with each entry being
- * a partition table with two entries. The first entry
- * is the real data partition (with a start relative to the partition
- * table start). The second is a pointer to the next logical partition
- * (with a start relative to the entire extended partition).
- * We do not create a Linux partition for the partition tables, but
- * only for the actual data partitions.
- */
-static void extended_partition(unsigned int dev)
+#if (HD_DELAY > 0)
+unsigned long read_timer(void)
{
- struct buffer_head *bh;
- struct partition *p;
- unsigned long first_sector, this_sector;
-
- first_sector = hd[MINOR(dev)].start_sect;
- this_sector = first_sector;
-
- while (1) {
- if ((current_minor & 0x3f) >= 60)
- return;
- if (!(bh = bread(dev,0))) {
- printk("Unable to read partition table of device %04x\n",dev);
- return;
- }
- /*
- * This block is from a device that we're about to stomp on.
- * So make sure nobody thinks this block is usable.
- */
- bh->b_dirt=0;
- bh->b_uptodate=0;
- if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
- p = 0x1BE + (void *)bh->b_data;
- /*
- * Process the first entry, which should be the real
- * data partition.
- */
- if (p->sys_ind == EXTENDED_PARTITION ||
- !(hd[current_minor].nr_sects = p->nr_sects))
- goto done; /* shouldn't happen */
- hd[current_minor].start_sect = this_sector + p->start_sect;
- printk(" Logical part %d start %d size %d end %d\n\r",
- current_minor, hd[current_minor].start_sect,
- hd[current_minor].nr_sects,
- hd[current_minor].start_sect +
- hd[current_minor].nr_sects - 1);
- current_minor++;
- p++;
- /*
- * Process the second entry, which should be a link
- * to the next logical partition. Create a minor
- * for this just long enough to get the next partition
- * table. The minor will be reused for the real
- * data partition.
- */
- if (p->sys_ind != EXTENDED_PARTITION ||
- !(hd[current_minor].nr_sects = p->nr_sects))
- goto done; /* no more logicals in this partition */
- hd[current_minor].start_sect = first_sector + p->start_sect;
- this_sector = first_sector + p->start_sect;
- dev = 0x0300 | current_minor;
- brelse(bh);
- } else
- goto done;
- }
-done:
- brelse(bh);
-}
+ unsigned long t;
+ int i;
-static void check_partition(unsigned int dev)
-{
- int i, minor = current_minor;
- struct buffer_head *bh;
- struct partition *p;
- unsigned long first_sector;
-
- first_sector = hd[MINOR(dev)].start_sect;
- if (!(bh = bread(dev,0))) {
- printk("Unable to read partition table of device %04x\n",dev);
- return;
- }
- printk("Drive %d:\n\r",minor >> 6);
- current_minor += 4; /* first "extra" minor */
- if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
- p = 0x1BE + (void *)bh->b_data;
- for (i=1 ; i<=4 ; minor++,i++,p++) {
- if (!(hd[minor].nr_sects = p->nr_sects))
- continue;
- 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 - 1);
- if ((current_minor & 0x3f) >= 60)
- continue;
- if (p->sys_ind == EXTENDED_PARTITION) {
- extended_partition(0x0300 | minor);
- }
- }
- /*
- * check for Disk Manager partition table
- */
- if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
- p = 0x1BE + (void *)bh->b_data;
- for (i = 4 ; i < 16 ; i++, current_minor++) {
- p--;
- if ((current_minor & 0x3f) >= 60)
- break;
- if (!(p->start_sect && p->nr_sects))
- continue;
- hd[current_minor].start_sect = p->start_sect;
- hd[current_minor].nr_sects = p->nr_sects;
- printk(" DM part %d start %d size %d end %d\n\r",
- current_minor,
- hd[current_minor].start_sect,
- hd[current_minor].nr_sects,
- hd[current_minor].start_sect +
- hd[current_minor].nr_sects - 1);
- }
- }
- } else
- printk("Bad partition table on dev %04x\n",dev);
- brelse(bh);
+ 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);
}
-
-/* This may be used only once, enforced by 'static int callable' */
-int sys_setup(void * BIOS)
-{
- static int callable = 1;
- int i,drive;
- unsigned char cmos_disks;
-
- if (!callable)
- return -1;
- callable = 0;
-#ifndef HD_TYPE
- for (drive=0 ; drive<2 ; drive++) {
- hd_info[drive].cyl = *(unsigned short *) BIOS;
- hd_info[drive].head = *(unsigned char *) (2+BIOS);
- hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
- hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
- hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
- hd_info[drive].sect = *(unsigned char *) (14+BIOS);
- BIOS += 16;
- }
-
- /*
- We querry CMOS about hard disks : it could be that
- we have a SCSI/ESDI/etc controller that is BIOS
- compatable with ST-506, and thus showing up in our
- BIOS table, but not register compatable, and therefore
- not present in CMOS.
-
- Furthurmore, we will assume that our ST-506 drives
- <if any> are the primary drives in the system, and
- the ones reflected as drive 1 or 2.
-
- The first drive is stored in the high nibble of CMOS
- byte 0x12, the second in the low nibble. This will be
- either a 4 bit drive type or 0xf indicating use byte 0x19
- for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
- Needless to say, a non-zero value means we have
- an AT controller hard disk for that drive.
-
-
- */
-
- if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
- if (cmos_disks & 0x0f)
- NR_HD = 2;
- else
- NR_HD = 1;
- else
- NR_HD = 0;
#endif
- for (i = 0 ; i < (MAX_HD<<6) ; i++) {
- hd[i].start_sect = 0;
- hd[i].nr_sects = 0;
- }
- for (i = 0 ; i < NR_HD ; i++)
- hd[i<<6].nr_sects = hd_info[i].head*
- hd_info[i].sect*hd_info[i].cyl;
- for (drive=0 ; drive<NR_HD ; drive++) {
- current_minor = 1+(drive<<6);
- check_partition(0x0300+(drive<<6));
- }
- for (i=0 ; i<(MAX_HD<<6) ; i++)
- hd_sizes[i] = hd[i].nr_sects>>1 ;
- blk_size[MAJOR_NR] = hd_sizes;
- if (NR_HD)
- printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
- rd_load();
- mount_root();
- return (0);
-}
static int controller_ready(void)
{
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
== (READY_STAT | SEEK_STAT))
- return(0); /* ok */
- if (i&1)
+ return 0; /* ok */
+ printk("HD: win_result: status = 0x%02x\n",i);
+ if (i&1) {
i=inb(HD_ERROR);
- return (1);
+ printk("HD: win_result: error = 0x%02x\n",i);
+ }
+ return 1;
}
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;
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)
if (c == (READY_STAT | SEEK_STAT))
return 0;
}
- printk("HD controller times out, c=%02x\n\r",c);
+ printk("HD controller times out, status = 0x%02x\n\r",c);
return(1);
}
{
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);
*/
void unexpected_hd_interrupt(void)
{
+ sti();
printk("Unexpected HD interrupt\n\r");
SET_TIMER;
-#if 0
- reset = 1;
- do_hd_request();
-#endif
}
static void bad_rw_intr(void)
return;
if (++CURRENT->errors >= MAX_ERRORS)
end_request(0);
- if (CURRENT->errors > MAX_ERRORS/2)
+ else if (CURRENT->errors > MAX_ERRORS/2)
reset = 1;
else
recalibrate = 1;
}
+static inline int wait_DRQ(void)
+{
+ int retries = 100000;
+
+ while (--retries > 0)
+ if (inb_p(HD_STATUS) & DRQ_STAT)
+ return 0;
+ return -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 & STAT_MASK) != STAT_OK) {
+ printk("HD: read_intr: status = 0x%02x\n",i);
+ goto bad_read;
+ }
+ if (wait_DRQ()) {
+ printk("HD: read_intr: no DRQ\n");
+ 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) {
+ printk("HD: read_intr: second status = 0x%02x\n",i);
+ goto bad_read;
+ }
CURRENT->errors = 0;
CURRENT->buffer += 512;
CURRENT->sector++;
- if (--CURRENT->nr_sectors)
+ i = --CURRENT->nr_sectors;
+ --CURRENT->current_nr_sectors;
+#ifdef DEBUG
+ printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
+ MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
+ buffer);
+#endif
+ if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+ end_request(1);
+ if (i > 0) {
+ SET_INTR(&read_intr);
+ sti();
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);
+ printk("HD: read_intr: error = 0x%02x\n",i);
+ }
+ bad_rw_intr();
do_hd_request();
+ return;
}
static void write_intr(void)
{
- if (win_result()) {
- bad_rw_intr();
- do_hd_request();
- return;
+ int i;
+
+ i = (unsigned) inb_p(HD_STATUS);
+ if ((i & STAT_MASK) != STAT_OK) {
+ printk("HD: write_intr: status = 0x%02x\n",i);
+ goto bad_write;
+ }
+ if (CURRENT->nr_sectors > 1 && wait_DRQ()) {
+ printk("HD: write_intr: no DRQ\n");
+ goto bad_write;
}
- if (--CURRENT->nr_sectors) {
- CURRENT->sector++;
- CURRENT->buffer += 512;
+ CURRENT->sector++;
+ i = --CURRENT->nr_sectors;
+ --CURRENT->current_nr_sectors;
+ CURRENT->buffer += 512;
+ if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+ end_request(1);
+ if (i > 0) {
SET_INTR(&write_intr);
port_write(HD_DATA,CURRENT->buffer,256);
- return;
+ sti();
+ } else {
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ do_hd_request();
+ }
+ return;
+bad_write:
+ sti();
+ if (i & ERR_STAT) {
+ i = (unsigned) inb(HD_ERROR);
+ printk("HD: write_intr: error = 0x%02x\n",i);
}
- end_request(1);
+ bad_rw_intr();
+ cli();
do_hd_request();
+ return;
}
static void recal_intr(void)
* best idea seems to just set reset, and start all over again.
*/
static void hd_times_out(void)
-{
- do_hd = NULL;
+{
+ sti();
+ DEVICE_INTR = NULL;
reset = 1;
if (!CURRENT)
return;
printk("HD timeout\n\r");
cli();
- if (++CURRENT->errors >= MAX_ERRORS)
+ if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+ printk("hd : too many errors.\n");
+#endif
end_request(0);
+ }
+
do_hd_request();
}
+/*
+ * The driver has been modified to enable interrupts a bit more: in order to
+ * do this we first (a) disable the timeout-interrupt and (b) clear the
+ * device-interrupt. This way the interrupts won't mess with out code (the
+ * worst that can happen is that an unexpected HD-interrupt comes in and
+ * sets the "reset" variable and starts the timer)
+ */
static void do_hd_request(void)
{
- int i,r;
unsigned int block,dev;
unsigned int sec,head,cyl;
unsigned int nsect;
+repeat:
+ DEVICE_INTR = NULL;
+ timer_active &= ~(1<<HD_TIMER);
+ sti();
INIT_REQUEST;
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
- if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) {
+ if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
+#ifdef DEBUG
+ printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
+ block, hd[dev].nr_sects);
+#endif
end_request(0);
goto repeat;
}
head = block % hd_info[dev].head;
cyl = block / hd_info[dev].head;
sec++;
+#ifdef DEBUG
+ printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
+ dev, cyl, head, sec, CURRENT->buffer);
+#endif
+ cli();
if (reset) {
recalibrate = 1;
reset_hd();
+ sti();
return;
}
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;
+ sti();
return;
}
if (CURRENT->cmd == WRITE) {
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
if (reset)
goto repeat;
- for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
- /* nothing */ ;
- if (!r) {
+ if (wait_DRQ()) {
+ printk("HD: do_hd_request: no DRQ\n");
bad_rw_intr();
goto repeat;
}
port_write(HD_DATA,CURRENT->buffer,256);
+ sti();
} else if (CURRENT->cmd == READ) {
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
if (reset)
goto repeat;
+ sti();
} else
panic("unknown hd-command");
}
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,
(char *) &loc->sectors);
put_fs_word(hd_info[dev].cyl,
(short *) &loc->cylinders);
+ put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
+ (long *) &loc->start);
return 0;
+ RO_IOCTLS(inode->i_rdev,arg);
default:
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 void hd_geninit();
+
+static struct gendisk hd_gendisk = {
+ MAJOR_NR, /* Major number */
+ "hd", /* Major name */
+ 6, /* Bits to shift to get real from partition */
+ 1 << 6, /* Number of partitions per real */
+ MAX_HD, /* maximum number of real */
+ hd_geninit, /* init function */
+ hd, /* hd struct */
+ hd_sizes, /* block sizes */
+ 0, /* number */
+ (void *) hd_info, /* internal */
+ NULL /* next */
+};
+
+static void hd_geninit(void)
+{
+ int drive;
+#ifndef HD_TYPE
+ extern struct drive_info drive_info;
+ void *BIOS = (void *) &drive_info;
+ int cmos_disks, i;
+
+ for (drive=0 ; drive<2 ; drive++) {
+ hd_info[drive].cyl = *(unsigned short *) BIOS;
+ hd_info[drive].head = *(unsigned char *) (2+BIOS);
+ hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+ hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
+ hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+ hd_info[drive].sect = *(unsigned char *) (14+BIOS);
+ BIOS += 16;
+ }
+
+ /*
+ We querry CMOS about hard disks : it could be that
+ we have a SCSI/ESDI/etc controller that is BIOS
+ compatable with ST-506, and thus showing up in our
+ BIOS table, but not register compatable, and therefore
+ not present in CMOS.
+
+ Furthurmore, we will assume that our ST-506 drives
+ <if any> are the primary drives in the system, and
+ the ones reflected as drive 1 or 2.
+
+ The first drive is stored in the high nibble of CMOS
+ byte 0x12, the second in the low nibble. This will be
+ either a 4 bit drive type or 0xf indicating use byte 0x19
+ for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+ Needless to say, a non-zero value means we have
+ an AT controller hard disk for that drive.
+
+
+ */
+
+ if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
+ if (cmos_disks & 0x0f)
+ NR_HD = 2;
+ else
+ NR_HD = 1;
+ else
+ NR_HD = 0;
+#endif
+
+ for (i = 0 ; i < NR_HD ; i++)
+ hd[i<<6].nr_sects = hd_info[i].head*
+ hd_info[i].sect*hd_info[i].cyl;
+
+ hd_gendisk.nr_real = NR_HD;
+}
+
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, /* close - default */
NULL, /* select */
- hd_ioctl /* ioctl */
+ hd_ioctl, /* ioctl */
+ NULL, /* no special open code */
+ hd_release /* release */
+};
+
+static void hd_interrupt(int unused)
+{
+ void (*handler)(void) = DEVICE_INTR;
+
+ DEVICE_INTR = NULL;
+ timer_active &= ~(1<<HD_TIMER);
+ if (!handler)
+ handler = unexpected_hd_interrupt;
+ handler();
+ sti();
+}
+
+/*
+ * This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines...
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+static struct sigaction hd_sigaction = {
+ hd_interrupt,
+ 0,
+ SA_INTERRUPT,
+ NULL
};
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);
+ hd_gendisk.next = gendisk_head;
+ gendisk_head = &hd_gendisk;
+ if (irqaction(HD_IRQ,&hd_sigaction))
+ printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
timer_table[HD_TIMER].fn = hd_times_out;
}
+
+#endif
/*
* linux/kernel/blk_dev/ll_rw.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* This handles all read/write requests to block devices
*/
-#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
#include <asm/system.h>
#include "blk.h"
+extern long rd_init(long mem_start, int length);
+
/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
/*
* used to wait on when there are no free requests
*/
-struct task_struct * wait_for_request = NULL;
+struct wait_queue * wait_for_request = NULL;
/* blk_dev_struct is:
* do_request-address
{ 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 */
};
/*
wake_up(&bh->b_wait);
}
+/* RO fail safe mechanism */
+
+static long ro_bits[NR_BLK_DEV][8];
+
+int is_read_only(int dev)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= NR_BLK_DEV) return 0;
+ return ro_bits[major][minor >> 5] & (1 << (minor & 31));
+}
+
+void set_device_ro(int dev,int flag)
+{
+ int minor,major;
+
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ if (major < 0 || major >= NR_BLK_DEV) return;
+ if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
+ else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
+}
+
/*
* add-request adds a request to the linked list.
* It disables interrupts so that it can muck with the
static void make_request(int major,int rw, struct buffer_head * bh)
{
+ unsigned int sector, count;
struct request * req;
int rw_ahead;
printk("Bad block dev command, must be R/W/RA/WA\n");
return;
}
+ count = bh->b_size >> 9;
+ sector = bh->b_blocknr * count;
+ if (blk_size[major])
+ if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
+ bh->b_dirt = bh->b_uptodate = 0;
+ return;
+ }
lock_buffer(bh);
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
unlock_buffer(bh);
return;
}
repeat:
+ cli();
+ if ((major == 3 || major == 8 )&& (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 == sector &&
+ req->nr_sectors < 254) {
+ req->bhtail->b_reqnext = bh;
+ req->bhtail = bh;
+ req->nr_sectors += count;
+ 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.
else
req = request+(NR_REQUEST/2);
/* find an empty request */
- cli();
while (--req >= request)
if (req->dev < 0)
goto found;
/* fill up the request-info, and add it to the queue */
req->dev = bh->b_dev;
req->cmd = rw;
- req->errors=0;
- req->sector = bh->b_blocknr<<1;
- req->nr_sectors = 2;
+ req->errors = 0;
+ req->sector = sector;
+ req->nr_sectors = count;
+ req->current_nr_sectors = count;
req->buffer = bh->b_data;
req->waiting = NULL;
req->bh = bh;
+ req->bhtail = bh;
req->next = NULL;
add_request(major+blk_dev,req);
}
unsigned int major = MAJOR(dev);
if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
- printk("Trying to read nonexistent block-device\n\r");
+ printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
return;
}
if (rw!=READ && rw!=WRITE)
panic("Bad block dev command, must be R/W");
+ if (rw == WRITE && is_read_only(dev)) {
+ printk("Can't page to read-only device 0x%X\n\r",dev);
+ return;
+ }
cli();
repeat:
req = request+NR_REQUEST;
req->errors = 0;
req->sector = page<<3;
req->nr_sectors = 8;
+ req->current_nr_sectors = 8;
req->buffer = buffer;
- req->waiting = current;
+ req->waiting = ¤t->wait;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
{
unsigned int major;
+ if (!bh)
+ return;
+ if (bh->b_size != 1024) {
+ printk("ll_rw_block: only 1024-char blocks implemented (%d)\n",bh->b_size);
+ bh->b_dirt = bh->b_uptodate = 0;
+ 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");
+ printk("ll_rw_block: Trying to read nonexistent block-device %04x (%d)\n",bh->b_dev,bh->b_blocknr);
+ bh->b_dirt = bh->b_uptodate = 0;
+ return;
+ }
+ if ((rw == WRITE || rw == WRITEA) && is_read_only(bh->b_dev)) {
+ printk("Can't write to read-only device 0x%X\n\r",bh->b_dev);
+ bh->b_dirt = bh->b_uptodate = 0;
return;
}
make_request(major,rw,bh);
}
-void blk_dev_init(void)
+long blk_dev_init(long mem_start, long mem_end)
{
int i;
request[i].dev = -1;
request[i].next = NULL;
}
+ memset(ro_bits,0,sizeof(ro_bits));
+#ifdef RAMDISK
+ mem_start += rd_init(mem_start, RAMDISK*1024);
+#endif
+ return mem_start;
}
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
printk("ll_rw_swap: bad block dev command, must be R/W");
return;
}
+ if (rw == WRITE && is_read_only(dev)) {
+ printk("Can't swap to read-only device 0x%X\n\r",dev);
+ return;
+ }
for (i=0; i<nb; i++, buf += BLOCK_SIZE)
{
req->errors = 0;
req->sector = b[i] << 1;
req->nr_sectors = 2;
+ req->current_nr_sectors = 2;
req->buffer = buf;
- req->waiting = current;
+ req->waiting = ¤t->wait;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
* Written by Theodore Ts'o, 12/2/91
*/
-#include <linux/string.h>
#include <linux/config.h>
+#ifdef RAMDISK
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/fs.h>
char *rd_start;
int rd_length = 0;
-void do_rd_request(void)
+static void do_rd_request(void)
{
int len;
char *addr;
+repeat:
INIT_REQUEST;
addr = rd_start + (CURRENT->sector << 9);
len = CURRENT->nr_sectors << 9;
block_read, /* read - general block-dev read */
block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
- NULL, /* close - default */
NULL, /* select */
- NULL /* ioctl */
+ NULL, /* ioctl */
+ NULL, /* no special open code */
+ NULL /* no special release code */
};
/*
void rd_load(void)
{
struct buffer_head *bh;
- struct super_block s;
+ struct minix_super_block s;
int block = 256; /* Start at block 256 */
int i = 1;
int nblocks;
nblocks, rd_length >> BLOCK_SIZE_BITS);
return;
}
- printk("Loading %d bytes into ram disk... 0000k",
+ printk("Loading %d bytes into ram disk\n",
nblocks << BLOCK_SIZE_BITS);
cp = rd_start;
while (nblocks) {
if (nblocks > 2)
bh = breada(ROOT_DEV, block, block+1, block+2, -1);
else
- bh = bread(ROOT_DEV, block);
+ bh = bread(ROOT_DEV, block, BLOCK_SIZE);
if (!bh) {
printk("I/O error on block %d, aborting load\n",
block);
}
(void) memcpy(cp, bh->b_data, BLOCK_SIZE);
brelse(bh);
- printk("\010\010\010\010\010%4dk",i);
+ if (!(nblocks-- & 15))
+ printk(".");
cp += BLOCK_SIZE;
block++;
- nblocks--;
i++;
}
- printk("\010\010\010\010\010done \n");
+ printk("\ndone\n");
ROOT_DEV=0x0101;
}
+#endif
--- /dev/null
+/* $Id: 7000fasst.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+ * linux/kernel/7000fasst.c
+ *
+ * Copyright (C) 1992 Thomas Wuensche
+ * closely related to the aha1542 driver from Tommy Thorn
+ * ( as close as different hardware allows on a lowlevel-driver :-) )
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include "hosts.h"
+
+struct mailbox{
+ unchar status;
+ unchar scbptr[3];
+};
+
+/* #define DEBUG */
+
+#include "7000fasst.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/7000fasst.c,v 1.1 1992/07/24 06:27:38 root Exp root $";*/
+
+static struct scb scbs[OGMB_CNT];
+
+long wd7000fasst_WAITnexttimeout = 3000000;
+
+void (*wd7000fasst_do_done)() = NULL;
+extern void wd7000fasst_interrupt();
+void wd7000fasst_call_buh();
+
+static unchar controlstat = 0;
+static unchar wd7000fasst_hostno;
+
+#define wd7000fasst_intr_reset() outb(0,INTR_ACK)
+#define PC_IMR 0x21
+#define AT_IMR 0xa1
+
+#define wd7000fasst_enable_intr(){\
+ controlstat |= INT_EN;\
+ outb(controlstat,CONTROL);\
+ outb((inb((intr_chan<=7)?PC_IMR:AT_IMR))& ~0xff,(intr_chan<=7)?PC_IMR:AT_IMR);}
+
+#define wd7000fasst_disable_intr() outb(controlstat |= INT_EN, CONTROL)
+#define wd7000fasst_enable_dma() {\
+ controlstat |= DMA_EN;\
+ outb(controlstat,CONTROL);\
+ outb((DMA_CH|CASCADE),DMA_MODE_REG);\
+ outb(DMA_CH,DMA_MASK_REG);}
+
+#define wd7000fasst_disable_dma() {\
+ outb(DMA_CH|S_DMA_MASK,DMA_MASK_REG);\
+ controlstat &= ~DMA_EN;\
+ outb(controlstat,CONTROL);}
+
+#define WAIT(port, mask, allof, noneof) \
+ { register WAITbits; \
+ register WAITtimeout = wd7000fasst_WAITnexttimeout; \
+ while (1) { \
+ WAITbits = inb(port) & (mask); \
+ if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+ break; \
+ if (--WAITtimeout == 0) goto fail; \
+ } \
+ }
+
+static void wd7000fasst_stat(void)
+{
+/* int s = inb(ASC_STAT), i = inb(INTR_STAT);*/
+/* printk("status = %x, intrflags = %x served %d last %x\n", s, i, intr_flag, intr_last);
+ printk("status=%x intrflags=%x\n", s, i);
+*/}
+
+static int wd7000fasst_out(unchar *cmdp, int len)
+{
+ while (len--)
+ {
+ WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
+ outb(*cmdp++, COMMAND);
+ }
+ return 0;
+ fail:
+ printk("wd7000fasst_out failed(%d): ", len+1); wd7000fasst_stat();
+ return 1;
+}
+
+int wd7000fasst_make_error_code(unsigned hosterr, unsigned scsierr)
+{
+#ifdef DEBUG
+ int in_error=hosterr;
+#endif
+ switch ((hosterr&0xff00)>>8){
+ case 0: /* It is reserved, should never happen */
+ hosterr=DID_ERROR;
+ break;
+ case 1: hosterr=DID_OK;
+ break;
+ case 2: /* Command complete with logged error */
+ /* My actual copies of the manual pages are unreadable
+ * For now we simply tell there is an error */
+ DEB(printk("Hosterror: VUE = %x\n",hosterr&0xff);)
+ switch (hosterr&0xff) {
+ default: DEB(printk("wd7000fasst_make_error_code: unknown hoststatus %x\n", hosterr);)
+ hosterr=DID_ERROR;
+ break;
+ }
+ break;
+ case 4: hosterr=DID_BAD_TARGET; /* Command failed to complete without SCSI status */
+ break;
+ case 5: hosterr=DID_RESET; /* Cmd terminated; Bus reset by external device */
+ break;
+ case 6: hosterr=DID_ERROR;/* Hardware Failure, requires host reset */
+ break;
+ case 7: hosterr=DID_RESET;
+ break;
+ case 8: hosterr=DID_OK;
+ printk("wd7000fasst: Linked command not implemented\n");
+ break;
+ }
+#ifdef DEBUG
+ if (scsierr||hosterr) printk("SCSI-Command error: SCSI %x HOST %x RETURN %x\n",scsierr,in_error,hosterr);
+#endif
+ return scsierr|(hosterr << 16);
+}
+
+/* The following is space for the Mailboxes */
+struct{ struct mailbox ombox[OGMB_CNT];
+ struct mailbox imbox[ICMB_CNT]; } mbstruct;
+
+int wd7000fasst_init(void)
+{ int i;
+ volatile int debug = 0;
+ /* Page 47 */
+ unchar init_block[]={ 1, 7, 0x18, 0x18, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT };
+ /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
+
+ DEB(printk("wd7000fasst_init called \n"));
+
+ outb(SCSI_RES|ASC_RES, CONTROL);
+ /* Wait at least 25 us */
+ for (i=0; i< 1000; i++) inb(ASC_STAT);
+ /* Now reset the reset */
+ outb(0,CONTROL);
+ debug = 1;
+ /* Expect Command Port Ready */
+ WAIT(ASC_STAT, STATMASK, CMD_RDY, 0);
+ DEB(printk("wd7000fasst_init: Power on Diagnostics finished\n"));
+ if ((i=inb(INTR_STAT))!=1)
+ printk("Power on Diagnostics error %x\n",i);
+
+ debug = 2;
+ /* Clear mbstruct */
+ memset(&mbstruct,0,sizeof (mbstruct));
+ /* Set up init block */
+ any2scsi(init_block+5,&mbstruct);
+ /* Execute init command */
+ wd7000fasst_out(init_block,sizeof(init_block));
+ DEB(printk("Init-Block :");
+ for (i=0;i<sizeof(init_block);i++) printk(" %x",init_block[i]);
+ printk("\n");)
+ /* Wait until init finished */
+ WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
+ outb(2,COMMAND);
+ WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0);
+ /* Enable Interrupt and DMA */
+ wd7000fasst_enable_dma();
+ wd7000fasst_call_buh();
+ DEB(printk("wd7000fasst_detect: enable interrupt channel %d\n", intr_chan));
+ wd7000fasst_enable_intr();
+ printk("wd7000fasst_init: Controller initialized\n");
+ return 1;
+ fail:
+ return 0; /* 0 = not ok */
+}
+
+/* What's this little function for? */
+char *wd7000fasst_info(void)
+{
+ static char buffer[] = "Western Digital 7000-FASST";
+ return buffer;
+}
+
+/* A "high" level interrupt handler */
+void wd7000fasst_intr_handle(void)
+{ struct scb * scbptr;
+ DEB(int len=sizeof (struct scb);)
+ DEB(int k;)
+ unsigned host_error,scsi_error;
+ int flag = inb(INTR_STAT);
+ void (*my_done)() = wd7000fasst_do_done;
+ int errstatus;
+ DEB(printk("WD Interrupt aufgetreten\n"));
+ if (!(inb(ASC_STAT)&0x80)){
+ printk("Interrupt without Interrupt\n");
+ wd7000fasst_intr_reset();
+ return;
+ }
+ wd7000fasst_do_done = NULL;
+ if (!my_done) {
+ printk("wd7000fasst_intr_handle: Unexpected interrupt\n");
+ wd7000fasst_intr_reset();
+ return;
+ }
+
+ /* is there mail for me :-) */
+ if ((flag&0xc0)==0xc0){
+ /* Ok, the interrupt is for an incoming mailbox */
+ /* We make the content available for the starter of the command */
+ DEB(if ((flag&0xc0)==0xc0) printk("INTR_STAT: %x mbstat: %x\n",flag,mbstruct.imbox[flag&0x3f].status));
+ if (mbstruct.imbox[flag&0x3f].status==0){
+ /* Something strange happened */
+ wd7000fasst_intr_reset();
+ return;
+ ;
+ }
+ scbptr=(struct scb *)scsi2int(mbstruct.imbox[flag&0x3f].scbptr);
+ DEB(printk("Datenbereiche aus %x ein %x \n",scbptr,&(scbs[flag&0x3f]));
+ printk("SCB after return:\n");
+ k=0;
+ while (len-- >0){
+ printk("%x ",*((unchar *)scbptr));
+ ((unchar *)scbptr)++;
+ if (++k==16){ printk("\n"); k=0; }
+ });
+ }
+ else { printk("Error in interrupt\n"); return; }
+ /* more error checking left out here */
+
+ scbptr=(struct scb *)scsi2int(mbstruct.imbox[flag&0x3f].scbptr);
+ host_error=scbptr->vue | mbstruct.imbox[flag&0x3f].status<<8;
+ scsi_error=scbptr->sretstat;
+ errstatus=wd7000fasst_make_error_code(host_error,scsi_error);
+ DEB(if (errstatus) printk("Target was %x\n",scbptr->idlun>>5);)
+ DEB(if (errstatus) printk("wd7000fasst_intr_handle: returning %6x\n", errstatus));
+ DEB(printk("wd7000fasst_intr_handle: Status of the finished command: %x\n",mbstruct.imbox[flag&0x3f].status));
+ /* I make a SCSI reset */
+ /* Left out */
+ my_done(wd7000fasst_hostno,errstatus);
+ wd7000fasst_intr_reset();
+ return;
+}
+
+volatile static int internal_done_flag = 0;
+volatile static int internal_done_errcode = 0;
+
+/* The following code queues a SCSI command */
+int wd7000fasst_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen,
+ void (*done)(int, int))
+{
+ int i;
+#ifdef DEBUG
+ int j;
+#endif
+ unchar *cmd = (unchar *) cmnd;
+/* We first look for a free outgoing mailbox */
+ for (i=0;i<OGMB_CNT;i++){
+ if (mbstruct.ombox[i].status==0){
+ /* We found one, now set up the scb */
+ DEB(printk("Found outgoing mbox %x\n",i));
+ memset(&scbs[i], 0, sizeof(struct scb));
+ /* scbs[i].cdblen = (*cmd<=0x1f)?6:10; */ /* SCSI Command Descriptor Block Length */
+ memcpy(scbs[i].scbdata, cmd, (*cmd<=0x1f)?6:10);
+ scbs[i].op = 0; /* SCSI Initiator Command */
+ scbs[i].idlun = (target<<5)&0xe0; /* SCSI Target Id Bit 7-5 Target Id*/
+ any2scsi(scbs[i].dataptr,buff);
+ any2scsi(scbs[i].maxdata,bufflen);
+ scbs[i].direc=0x40; /* Disable direction check */
+ DEB(printk("Kommando fuer target %x ist: ",target);
+ for (j=0;j<12;j++) printk(" %x",scbs[i].scbdata[j]);
+ printk("\n"));
+ /* Now we set up the pointer to scb, then the status of the mbox */
+ any2scsi((mbstruct.ombox[i].scbptr),&(scbs[i]));
+ mbstruct.ombox[i].status=1;
+ /* Everything set up, start the command */
+ break;
+ }
+ }
+ if (i==OGMB_CNT){
+ /* No free mbox, send command "Interrupt on free OGMB" */
+ DEB(printk("No free Mailbox\n"));
+ return 0;
+ }
+ { int len,k;
+ struct scb * scbptr;
+ DEB(printk("Found outgoing mbox %x\n",i));
+ scbptr=&(scbs[i]);
+ len=sizeof(struct scb);
+ k=0;
+ DEB(printk("SCB before execute:\n");
+ while (len-- >0){
+ printk("%x ",*((unchar *)scbptr));
+ ((unchar *)scbptr)++;
+ if (++k==16){ printk("\n"); k=0; }
+ };)
+ }
+ /* Set up the "done" response function */
+ if (done) {
+ DEB(printk("wd7000fasst_queuecommand: now waiting for interrupt ");
+ wd7000fasst_stat());
+ if (wd7000fasst_do_done)
+ printk("wd7000fasst_queuecommand: Two concurrent queuecommand?\n");
+ else
+ wd7000fasst_do_done = done;
+ DEB(wd7000fasst_stat());
+ wd7000fasst_enable_intr();
+ }
+ else{
+ printk("wd7000fasst_queuecommand: done can't be NULL\n");
+ return 0;
+ }
+ /* Now we initialize execution */
+retry: WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
+ outb(0x80+i,COMMAND);
+ WAIT(ASC_STAT,STATMASK,CMD_RDY,0);
+ if (inb(ASC_STAT)&CMD_REJ) goto retry;
+ return 1;
+ /* Wait until done */
+
+fail:
+ return 0;
+}
+
+/* We use this function for queueing a command from wd7000fasst_command */
+static void internal_done(int host, int errcode)
+{
+ internal_done_errcode = errcode;
+ ++internal_done_flag;
+}
+
+int wd7000fasst_command(unchar target, const void *cmnd, void *buff, int bufflen)
+{
+#ifdef DEBUG
+ int k;
+#endif
+ wd7000fasst_queuecommand(target, cmnd, buff, bufflen, internal_done);
+
+ while (!internal_done_flag);
+ internal_done_flag = 0;
+ DEB(printk("wd7000fasst_command finished: ..leaving with errcode %x\n",
+ internal_done_errcode));
+ DEB(for (k=0;k<5000000;k++) inb(INTR_STAT));
+ return internal_done_errcode;
+}
+
+/* a hack to avoid a strange compilation error */
+
+void wd7000fasst_call_buh()
+{
+ set_intr_gate((intr_chan<=7)?intr_chan+8:intr_chan+0x20,&wd7000fasst_interrupt);
+}
+
+/* return non-zero on detection */
+static const char *wd_bases[] = {(char *)0xce000};
+typedef struct {char * signature;
+ unsigned offset;
+ unsigned length;
+ }Signature;
+
+static const Signature signatures[] =
+ {{"SSTBIOS",0xd,0x7}};
+
+#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
+
+int wd7000fasst_detect(int hostnum) /* hostnum ignored for now */
+{
+ int i,j;
+ char const * base_address = 0;
+ /* Store our host number */
+ wd7000fasst_hostno=hostnum;
+ DEB(printk("wd7000fasst_detect: \n"));
+
+ for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){
+ for(j=0;j<NUM_SIGNATURES;j++){
+ if(!memcmp((void *)(wd_bases[i] + signatures[j].offset),
+ (void *) signatures[j].signature,signatures[j].length)){
+ base_address=wd_bases[i];
+ printk("WD 7000-FASST detected\n");
+ }
+ }
+ }
+ if (!base_address) return 0;
+ wd7000fasst_init();
+
+ /* Set the Bus on/off-times as not to ruin floppy performens */
+
+ wd7000fasst_stat();
+
+ printk(" *** READ CAPACITY ***\n");
+
+ { unchar rstat;
+ 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 < 3; ++i){
+ rstat=0;
+ while (rstat<2){
+ if (wd7000fasst_command(i, cmd, buf, sizeof(buf))) rstat++;
+ else break;
+ }
+ if (rstat<2)
+ printk("wd7000fasst_detect: LU %d sector_size 0x%x device_size 0x%x capacity %d\n",
+ i, xscsi2int(buf+4), xscsi2int(buf), xscsi2int(buf+4)*xscsi2int(buf));
+ }
+ }
+
+ return 1;
+}
+
+int wd7000fasst_abort(int i)
+{
+ printk("wd7000fasst_abort\n");
+ return 0;
+}
+
+int wd7000fasst_reset(void)
+{
+ printk("wd7000fasst_reset called\n");
+ return 0;
+}
+
+__asm__("
+_wd7000fasst_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
+# Please, someone, change this to use the timer
+# andl $0xfffeffff,_timer_active
+ movl $_wd7000fasst_intr_handle,%edx
+ call *%edx # ``interesting'' way of handling intr.
+# Free the interrupt only after resetting the host interrupt
+ 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
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+");
--- /dev/null
+#ifndef _WD7000FASST_H
+
+/* $Id: 7000fasst.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ *
+ * Header file for the WD 7000-FASST driver for Linux
+ *
+ * $Log: 7000fasst.h,v $
+ * Revision 1.1 1992/07/24 06:27:38 root
+ * Initial revision
+ *
+ * Revision 1.1 1992/07/05 08:32:32 root
+ * Initial revision
+ *
+ * Revision 1.1 1992/05/15 18:38:05 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 ***
+ *
+ */
+
+#include <linux/types.h>
+
+#undef STATMASK
+#undef CONTROL
+
+#define io_base 0x350
+#define intr_chan 15
+#define dma_chan 6
+#define OGMB_CNT 8
+#define ICMB_CNT 8
+
+/* I/O Port interface 4.2 */
+/* READ */
+#define ASC_STAT io_base
+#define INT_IM 0x80 /* Interrupt Image Flag */
+#define CMD_RDY 0x40 /* Command Port Ready */
+#define CMD_REJ 0x20 /* Command Port Byte Rejected */
+#define ASC_INI 0x10 /* ASC Initialized Flag */
+#define STATMASK 0xf0 /* The lower 4 Bytes are reserved */
+
+/* This register saves two purposes
+ * Diagnostics error
+ * Interrupt Status
+ */
+#define INTR_STAT ASC_STAT+1
+#define ANYINTR 0x80 /* Mailbox Service possible/required */
+#define IMB 0x40 /* 1 Incoming / 0 Outgoing */
+#define MBMASK 0x3f
+/* if MSB is zero, the content of the lower ones keeps Diagnostic State *
+ * 00 Power-on, no diagnostics executed
+ * 01 No diagnostic Error Occured
+ * 02 RAM Failed
+ * 03 FIFO R/W Failed
+ * ...
+*/
+
+/* WRITE */
+#define COMMAND ASC_STAT
+
+#define INTR_ACK ASC_STAT+1
+
+
+#define CONTROL ASC_STAT+2
+#define INT_EN 0x08 /* Interrupt Enable */
+#define DMA_EN 0x04 /* DMA Enable */
+#define SCSI_RES 0x02 /* SCSI Reset */
+#define ASC_RES 0x01 /* ASC Reset */
+
+/* The DMA-Controller */
+#define DMA_MODE_REG 0xd6
+#define DMA_MASK_REG 0xd4
+#define S_DMA_MSK 0x04
+#define DMA_CH 0x02
+#define CASCADE 0xc0
+
+/* Mailbox Definition 5.3 */
+
+/* These belong in scsi.h also */
+#undef any2scsi
+#define any2scsi(up, p) \
+(up)[0] = (((long)(p)) >> 16); \
+(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 scb { /* Command Control Block 5.4.1 */
+ 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 scbdata[12]; /* SCSI Command Block */
+ unchar sretstat; /* SCSI Return Status */
+ unchar vue; /* Vendor Unique Error Code */
+ unchar maxdata[3]; /* Maximum Data Transfer Length */
+ unchar dataptr[3]; /* SCSI Data Block Pointer */
+ unchar linkptr[3]; /* Next Command Link Pointer */
+ unchar direc; /* Transfer Direction */
+ unchar reserved2[6]; /* SCSI Command Descriptor Block */
+ /* REQUEST SENSE */
+};
+
+int wd7000fasst_detect(int);
+int wd7000fasst_command(unsigned char target, const void *cmnd, void *buff, int bufflen);
+int wd7000fasst_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int,int));
+int wd7000fasst_abort(int);
+char *wd7000fasst_info(void);
+int wd7000fasst_reset(void);
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+#define WD7000FASST {"Western Digital 7000FASST", wd7000fasst_detect, \
+ wd7000fasst_info, wd7000fasst_command, \
+ wd7000fasst_queuecommand, \
+ wd7000fasst_abort, \
+ wd7000fasst_reset, \
+ 1, 7, 0}
+#endif
--- /dev/null
+#
+# 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
+
+.c.s:
+ $(CC) $(CFLAGS) $(DEBUG) -S $<
+
+.s.o:
+ $(AS) -c -o $*.o $<
+
+.c.o:
+ $(CC) $(CFLAGS) $(DEBUG) -c $<
+
+
+LOWLEVELSSRC = seagate2.s
+LOWLEVELCSRC = aha1542.c fdomain.c seagate.c ultrastor.c 7000fasst.c
+LOWLEVELHSRC = aha1542.h fdomain.h seagate.h ultrastor.h 7000fasst.o
+
+CSRC = hosts.c sd.c sd_ioctl.c st.c st_ioctl.c scsi.c scsi_ioctl.c $(LOWLEVELCSRC)
+HSRC = hosts.h sd.h st.h scsi.h scsi_ioctl.h $(LOWLEVELHSRC)
+
+OBJS = scsi.o hosts.o scsi_ioctl.o sd.o sd_ioctl.o st.o st_ioctl.o \
+ aha1542.o fdomain.o seagate.o seagate2.o ultrastor.o 7000fasst.o
+
+all: scsi.a
+
+figure : hosts.h $(KERNELHDRS)/linux/config.h hosts.c
+ $(HOSTCC) -N -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
+
+clean:
+ rm -f core *.o *.a tmp_make tmp_max figure max_hosts.h
+
+seagate2.o : seagate2.s
+
+seagate.o: seagate.c
+ $(CC) -Wall -c seagate.c
+
+dep:
+ touch max_hosts.h
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
+ rm max_hosts.h
+ cp tmp_make Makefile
+
+### Dependencies:
+7000fasst.o : 7000fasst.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h \
+ scsi.h hosts.h max_hosts.h 7000fasst.h
+aha1542.o : aha1542.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h \
+ scsi.h hosts.h max_hosts.h aha1542.h
+fdomain.o : fdomain.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/io.h fdomain.h scsi.h hosts.h max_hosts.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/errno.h
+hosts.o : hosts.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/kernel.h scsi.h hosts.h max_hosts.h aha1542.h /usr/src/linux/include/linux/types.h \
+ fdomain.h seagate.h ultrastor.h 7000fasst.h
+scsi.o : scsi.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/string.h scsi.h \
+ hosts.h max_hosts.h sd.h /usr/src/linux/include/linux/genhd.h st.h
+scsi_ioctl.o : scsi_ioctl.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h scsi.h hosts.h max_hosts.h scsi_ioctl.h
+sd.o : sd.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/kernel.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/linux/string.h \
+ scsi.h sd.h /usr/src/linux/include/linux/genhd.h ../blk.h
+sd_ioctl.o : sd_ioctl.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h scsi.h sd.h /usr/src/linux/include/linux/genhd.h
+seagate.o : seagate.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ seagate.h scsi.h hosts.h max_hosts.h
+st.o : st.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ scsi.h st.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ ../blk.h
+st_ioctl.o : st_ioctl.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h st.h scsi.h
+ultrastor.o : ultrastor.c /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/stddef.h /usr/src/linux/include/linux/string.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/system.h ultrastor.h \
+ scsi.h hosts.h max_hosts.h
--- /dev/null
+/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+ * linux/kernel/aha1542.c
+ *
+ * Copyright (C) 1992 Tommy Thorn
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.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/07/24 06:27:38 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)(int, int) = NULL;
+int aha1542_host = 0;
+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\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)
+{
+ void (*my_done)(int, int) = 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(aha1542_host, 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(aha1542_host, errstatus);
+ return;
+}
+
+int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int, int))
+{
+ unchar ahacmd = CMD_START_SCSI;
+ unchar *cmd = (unchar *) cmnd;
+ DEB(int i);
+
+ DEB(if (target > 1) {done(aha1542_host, 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 host, 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)
+{
+ 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
+ aha1542_host = hostnum;
+ 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
+");
--- /dev/null
+#ifndef _AHA1542_H
+
+/* $Id: aha1542.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ *
+ * Header file for the adaptec 1542 driver for Linux
+ *
+ * $Log: aha1542.h,v $
+ * Revision 1.1 1992/07/24 06:27:38 root
+ * Initial revision
+ *
+ * Revision 1.2 1992/07/04 18:41:49 root
+ * Replaced distribution with current drivers
+ *
+ * Revision 1.3 1992/06/23 23:58:20 root
+ * Fixes.
+ *
+ * Revision 1.2 1992/05/26 22:13:23 root
+ * Changed bug that prevented DMA above first 2 mbytes.
+ *
+ * Revision 1.1 1992/05/22 21:00:29 root
+ * Initial revision
+ *
+ * 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 ***
+ *
+ */
+
+#include <linux/types.h>
+
+/* 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] = (((unsigned long)(p)) >> 16) ; \
+(up)[1] = (((unsigned long)(p)) >> 8); \
+(up)[2] = ((unsigned 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));
+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, \
+ aha1542_abort, \
+ aha1542_reset, \
+ 1, 7, 0}
+#endif
--- /dev/null
+#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
--- /dev/null
+scsi.o
+hosts.o
+scsi_ioctl.o
+sd.o
+sd_ioctl.o
+st.o
+st_ioctl.o
+aha1542.o
+seagate.o
+ultrastor.o
--- /dev/null
+/* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver
+ * Created: Sun May 3 18:53:19 1992
+ * Revised: Tue Jul 28 19:45:25 1992 by root
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992 Rickard E. Faith
+ *
+ * $Log$
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
+ * WARNING: THIS IS A BETA VERSION!
+ * USE AT YOUR OWN RISK!
+ * BACKUP YOUR SYSTEM BEFORE USING!
+
+ * I would like to thank Maxtor, whose *free* 206 page manual on the LXT
+ * drives was very helpful: "LXT SCSI Products: Specifications and OEM
+ * Technical Manual (Revision B/September 1991)"
+
+ * I wish that I could thank Future Domain for the necessary documentation,
+ * but I can't. I used the $25 "TMC-1800 SCSI Chip Specification" document
+ * (FDC-1800T), which documents the *chip* and not the board. Without it,
+ * I would have been totally lost, but it would have been nice to have some
+ * example source. (The DOS BIOS source cost $250 and the UN*X driver
+ * source was $750 [both required a non-disclosure agreement]. Ever wonder
+ * why there are no freely available Future Domain drivers?)
+
+ * Thanks to Todd Carrico (todd@wutc.wustl.edu), Dan Poirier
+ * (poirier@cs.unc.edu ), Ken Corey (kenc@sol.acs.unt.edu), and C. de Bruin
+ * (bruin@dutiba.tudelft.nl) for alpha testing. Also thanks to Drew
+ * Eckhardt (drew@cs.colorado.edu) for answering questions. */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_FUTURE_DOMAIN
+
+#include <linux/sched.h>
+#include <asm/io.h>
+#include "fdomain.h"
+#include "scsi.h"
+#include "hosts.h"
+#if QUEUE
+#include <asm/system.h>
+#include <linux/errno.h>
+#endif
+
+#define VERSION "1.9" /* Change with each revision */
+#define DEBUG 1 /* Enable debugging output */
+#define SEND_IDENTIFY 0 /* Send IDENTIFY message -- DOESN'T WORK! */
+#define USE_FIFO 1 /* Use the FIFO buffer for I/O */
+#define FAST_SYNCH 1 /* Enable Fast Synchronous */
+#define ALLOW_ALL_IRQ 0 /* Allow all IRQ's -- NOT RECOMMENDED */
+#define NEW_IRQ 1 /* Enable new IRQ handling */
+#define DECREASE_IL 1 /* Try to decrease interrupt latency */
+
+#if DEBUG
+#define EVERY_ACCESS 0 /* Write a line on every scsi access */
+#define ERRORS_ONLY 1 /* Only write a line if there is an error */
+#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */
+#else
+#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
+#define ERRORS_ONLY 0
+#define DEBUG_DETECT 0
+#endif
+
+/* Errors are reported on the line, so we don't need to report them again */
+#if EVERY_ACCESS
+#undef ERRORS_ONLY
+#define ERRORS_ONLY 0
+#endif
+
+static int port_base = 0;
+static void *bios_base = NULL;
+static int interrupt_level = 0;
+static volatile int aborted = 0;
+
+static int Data_Mode_Cntl_port;
+static int FIFO_Data_Count_port;
+static int Interrupt_Cntl_port;
+static int Read_FIFO_port;
+static int Read_SCSI_Data_port;
+static int SCSI_Cntl_port;
+static int SCSI_Status_port;
+static int TMC_Cntl_port;
+static int TMC_Status_port;
+static int Write_FIFO_port;
+static int Write_SCSI_Data_port;
+
+#if QUEUE
+static unsigned char current_target = 0;
+static unsigned char current_cmnd[10] = { 0, };
+static void *current_buff = NULL;
+static int current_bufflen = 0;
+static void (*current_done)(int,int) = NULL;
+
+volatile static int in_command = 0;
+volatile static int current_phase;
+static int this_host = 0;
+
+enum { in_arbitration, in_selection, in_other };
+
+#if NEW_IRQ
+extern void fdomain_16x0_intr( int unused );
+#else
+extern void fdomain_16x0_interrupt();
+#endif
+
+static const char *cmd_pt;
+static const char *the_command;
+static unsigned char *out_buf_pt;
+static unsigned char *in_buf_pt;
+volatile static int Status;
+volatile static int Message;
+volatile static unsigned data_sent;
+volatile static int have_data_in;
+
+volatile static int in_interrupt_code = 0;
+
+#endif
+
+
+enum in_port_type { Read_SCSI_Data = 0, SCSI_Status = 1, TMC_Status = 2,
+ LSB_ID_Code = 5, MSB_ID_Code = 6, Read_Loopback = 7,
+ SCSI_Data_NoACK = 8, Option_Select = 10,
+ Read_FIFO = 12, FIFO_Data_Count = 14 };
+
+enum out_port_type { Write_SCSI_Data = 0, SCSI_Cntl = 1, Interrupt_Cntl = 2,
+ Data_Mode_Cntl = 3, TMC_Cntl = 4, Write_Loopback = 7,
+ Write_FIFO = 12 };
+
+static void *addresses[] = {
+ (void *)0xc8000,
+ (void *)0xca000,
+ (void *)0xce000,
+ (void *)0xde000 };
+#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
+
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/*
+
+ READ THIS BEFORE YOU ADD A SIGNATURE!
+
+ READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
+
+ READ EVERY WORD, ESPECIALLY THE WORD *NOT*
+
+ This driver works *ONLY* for Future Domain cards using the
+ TMC-1600 chip. This includes models TMC-1660 and TMC-1680
+ *ONLY*.
+
+ The following is a BIOS signature for a TMC-950 board, which
+ looks like it is a 16 bit board (based on card edge), but
+ which only uses the extra lines for IRQ's (not for data):
+
+ FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+
+ THIS WILL *NOT* WORK WITH THIS DRIVER!
+
+ Here is another BIOS signature for yet another Future
+ Domain board WHICH WILL *NOT* WORK WITH THIS DRIVER:
+
+ FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+
+ Here is another BIOS signature for the TMC-88x series:
+
+ FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90
+
+ THIS WILL *NOT* WORK WITH THIS DRIVER, but it *WILL*
+ work with the *SEAGATE* ST-01/ST-02 driver.
+
+ */
+
+struct signature {
+ char *signature;
+ int sig_offset;
+ int sig_length;
+} signatures[] = {
+ { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0 7/28/89", 5, 50 },
+ { "FUTURE DOMAIN CORP. (C) 1986-1990 1800", 5, 37 },
+ /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */
+};
+
+#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+
+
+/* These functions are based on include/asm/io.h */
+
+#if 1
+static unsigned short inline inw( unsigned short port )
+{
+ unsigned short _v;
+
+ __asm__ volatile ("inw %1,%0"
+ :"=a" (_v):"d" ((unsigned short) port));
+ return _v;
+}
+
+static void inline outw( unsigned short value, unsigned short port )
+{
+ __asm__ volatile ("outw %0,%1"
+ ::"a" ((unsigned short) value),
+ "d" ((unsigned short) port));
+}
+#else
+
+#define inw( port ) \
+ ({ unsigned short _v; \
+ __asm__ volatile ("inw %1,%0" \
+ : "=a" (_v) : "d" ((unsigned short) port)); \
+ _v; })
+
+#define outw( value ) \
+ __asm__ volatile \
+ ("outw %0,%1" : : "a" ((unsigned short) value), \
+ "d" ((unsigned short) port))
+#endif
+
+
+/* These defines are copied from kernel/blk_drv/hd.c */
+
+#define insw( buf, count, port ) \
+ __asm__ volatile \
+ ( "cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )
+
+#define outsw( buf, count, port) \
+ __asm__ volatile \
+ ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")
+
+
+static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
+{
+ unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
+
+ while (jiffies < the_time);
+}
+
+static void inline fdomain_make_bus_idle( void )
+{
+ outb( 0, SCSI_Cntl_port );
+ outb( 0, Data_Mode_Cntl_port );
+ outb( 1, TMC_Cntl_port );
+}
+
+static int fdomain_is_valid_port( int port )
+{
+ int options;
+
+#if DEBUG_DETECT
+ printk( " (%x%x),",
+ inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
+#endif
+
+ /* The MCA ID is a unique id for each MCA compatible board. We
+ are using ISA boards, but Future Domain provides the MCA ID
+ anyway. We can use this ID to ensure that this is a Future
+ Domain TMC-1660/TMC-1680.
+ */
+
+ if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
+ if (inb( port + LSB_ID_Code ) != 0x27) return 0;
+ if (inb( port + MSB_ID_Code ) != 0x61) return 0;
+ } else { /* test for 0xe960 id */
+ if (inb( port + MSB_ID_Code ) != 0x60) return 0;
+ }
+
+ /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
+ Now, check to be sure the bios_base matches these ports.
+ If someone was unlucky enough to have purchased more than one
+ Future Domain board, then they will have to modify this code, as
+ we only detect one board here. [The one with the lowest bios_base].
+ */
+
+ options = inb( port + Option_Select );
+
+#if DEBUG_DETECT
+ printk( " Options = %x,", options );
+#endif
+
+ if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
+ interrupt_level = ints[ (options & 0x0e) >> 1 ];
+
+ return 1;
+}
+
+static int fdomain_test_loopback( void )
+{
+ int i;
+ int result;
+
+ for (i = 0; i < 255; i++) {
+ outb( i, port_base + Write_Loopback );
+ result = inb( port_base + Read_Loopback );
+ if (i != result) return 1;
+ }
+ return 0;
+}
+
+#if !NEW_IRQ
+static void fdomain_enable_interrupt( void )
+{
+ if (!interrupt_level) return;
+
+#if ALLOW_ALL_IRQ
+ if (interrupt_level < 8) {
+ outb( inb_p( 0x21 ) & ~(1 << interrupt_level), 0x21 );
+ } else
+#endif
+ {
+ outb( inb_p( 0xa1 ) & ~(1 << (interrupt_level - 8)), 0xa1 );
+ }
+}
+
+static void fdomain_disable_interrupt( void )
+{
+ if (!interrupt_level) return;
+
+#if ALLOW_ALL_IRQ
+ if (interrupt_level < 8) {
+ outb( inb_p( 0x21 ) | (1 << interrupt_level), 0x21 );
+ } else
+#endif
+ {
+ outb( inb_p( 0xa1 ) | (1 << (interrupt_level - 8)), 0xa1 );
+ }
+}
+#endif
+
+int fdomain_16x0_detect( int hostnum )
+{
+ int i, j;
+ int flag;
+ unsigned char do_inquiry[] = { 0x12, 0, 0, 0, 255, 0 };
+ unsigned char do_request_sense[] = { 0x03, 0, 0, 0, 255, 0 };
+ unsigned char do_read_capacity[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ unsigned char buf[256];
+ unsigned retcode;
+
+#if DEBUG_DETECT
+ printk( "SCSI: fdomain_16x0_detect()," );
+#endif
+
+ for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
+#if DEBUG_DETECT
+ printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
+#endif
+ for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
+ if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
+ signatures[j].signature, signatures[j].sig_length )) {
+ bios_base = addresses[i];
+ }
+ }
+ }
+
+ if (!bios_base) {
+#if DEBUG_DETECT
+ printk( " FAILED: NO BIOS\n" );
+#endif
+ return 0;
+ }
+
+ /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
+ Assuming the ROM is enabled (otherwise we wouldn't have been
+ able to read the ROM signature :-), then the ROM set up the
+ RAM area with some magic numbers, such as a list of port
+ base addresses and a list of the disk "geometry" reported to
+ DOS (this geometry has nothing to do with physical geometry).
+ */
+
+ port_base = *((char *)bios_base + 0x1fcc)
+ + (*((char *)bios_base + 0x1fcd) << 8);
+
+#if DEBUG_DETECT
+ printk( " %x,", port_base );
+#endif
+
+ for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
+ if (port_base == ports[i]) ++flag;
+ }
+
+ if (flag) flag = fdomain_is_valid_port( port_base );
+
+ if (!flag) { /* Cannot get port base from BIOS RAM */
+
+ /* This is a bad sign. It usually means that someone patched the
+ BIOS signature list (the signatures variable) to contain a BIOS
+ signature for a board *OTHER THAN* the TMC-1660/TMC-1680.
+ */
+
+#if DEBUG_DETECT
+ printk( " RAM FAILED, " );
+#endif
+ /* Anyway, the alternative to finding the address in the RAM is
+ to just search through every possible port address for one
+ that is attached to the Future Domain card. Don't panic,
+ though, about reading all these random port addresses--there
+ are rumors that the Future Domain BIOS does something very
+ similar.
+ */
+
+ for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
+ port_base = ports[i];
+#if DEBUG_DETECT
+ printk( " %x,", port_base );
+#endif
+ flag = fdomain_is_valid_port( port_base );
+ }
+ }
+
+ if (!flag) {
+#if DEBUG_DETECT
+ printk( " FAILED: NO PORT\n" );
+#endif
+ return 0; /* Cannot find valid set of ports */
+ }
+
+#if DEBUG_DETECT
+ printk( "\n" );
+ printk( "SCSI: bios_base = %x, port_base = %x, interrupt_level = %d\n",
+ (unsigned)bios_base, port_base, interrupt_level );
+#endif
+
+ if (interrupt_level) {
+ printk( "Future Domain BIOS at %x; port base at %x; using IRQ %d\n",
+ (unsigned)bios_base, port_base, interrupt_level );
+ } else {
+ printk( "Future Domain BIOS at %x; port base at %x; *NO* IRQ\n",
+ (unsigned)bios_base, port_base );
+ }
+
+ Data_Mode_Cntl_port = port_base + Data_Mode_Cntl;
+ FIFO_Data_Count_port = port_base + FIFO_Data_Count;
+ Interrupt_Cntl_port = port_base + Interrupt_Cntl;
+ Read_FIFO_port = port_base + Read_FIFO;
+ Read_SCSI_Data_port = port_base + Read_SCSI_Data;
+ SCSI_Cntl_port = port_base + SCSI_Cntl;
+ SCSI_Status_port = port_base + SCSI_Status;
+ TMC_Cntl_port = port_base + TMC_Cntl;
+ TMC_Status_port = port_base + TMC_Status;
+ Write_FIFO_port = port_base + Write_FIFO;
+ Write_SCSI_Data_port = port_base + Write_SCSI_Data;
+
+ fdomain_16x0_reset();
+
+ if (fdomain_test_loopback()) {
+#if DEBUG_DETECT
+ printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
+#endif
+ return 0;
+ }
+
+ /* These routines are here because of the way the SCSI bus behaves
+ after a reset. This appropriate behavior was not handled correctly
+ by the higher level SCSI routines when I first wrote this driver.
+ */
+
+ printk( "Future Domain detection routine scanning for devices:\n" );
+ for (i = 0; i < 8; i++) {
+ if (i == 6) continue; /* The host adapter is at SCSI ID 6 */
+ retcode = fdomain_16x0_command( i, do_request_sense, buf, 255 );
+ if (!retcode) {
+ retcode = fdomain_16x0_command( i, do_inquiry, buf, 255 );
+ if (!retcode) {
+ printk( " SCSI ID %d: ", i );
+ for (j = 8; j < 32; j++) printk( "%c", buf[j] );
+ retcode = fdomain_16x0_command( i, do_read_capacity, buf, 255 );
+ if (!retcode) {
+ unsigned long blocks, size, capacity;
+
+ blocks = (buf[0] << 24) | (buf[1] << 16)
+ | (buf[2] << 8) | buf[3];
+ size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+ capacity = +(blocks * size * 10) / +(1024L * 1024L);
+
+ printk( "%lu MB (%lu byte blocks)",
+ ((capacity + 5L) / 10L), size );
+ }
+ printk ("\n" );
+ }
+ }
+ }
+
+#if QUEUE
+#if !ALLOW_ALL_IRQ
+ if (interrupt_level < 8) {
+ printk( "Future Domain: WILL NOT USE IRQ LESS THAN 8 FOR QUEUEING!\n" );
+ scsi_hosts[hostnum].can_queue = 0;
+ } else
+#endif
+#if NEW_IRQ
+ {
+ int retcode;
+ struct sigaction sa;
+
+ this_host = hostnum;
+
+ sa.sa_handler = fdomain_16x0_intr;
+ sa.sa_flags = SA_INTERRUPT;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+
+ retcode = irqaction( interrupt_level, &sa );
+
+ if (retcode < 0) {
+ if (retcode == -EINVAL) {
+ printk( "Future Domain: IRQ %d is bad!\n", interrupt_level );
+ printk( " This shouldn't happen: REPORT TO RIK!\n" );
+ } else if (retcode == -EBUSY) {
+ printk( "Future Domain: IRQ %d is already in use!\n",
+ interrupt_level );
+ printk( " Please use another IRQ for the FD card!\n" );
+ } else {
+ printk( "Future Domain: Error getting IRQ %d\n",
+ interrupt_level );
+ printk( " This shouldn't happen: REPORT TO RIK!\n" );
+ }
+ printk( " IRQs WILL NOT BE USED!\n" );
+
+ scsi_hosts[this_host].can_queue = 0;
+ } else {
+ printk( "Future Domain: IRQ %d selected with retcode = %d\n",
+ interrupt_level, retcode );
+ }
+ }
+#else
+ {
+ this_host = hostnum;
+ set_intr_gate( 0x20 + interrupt_level, &fdomain_16x0_interrupt );
+ fdomain_enable_interrupt();
+ }
+#endif
+#endif
+
+ return 1;
+}
+
+char *fdomain_16x0_info(void)
+{
+ static char buffer[] =
+ "Future Domain TMC-1660/TMC-1680 SCSI driver version "
+ VERSION
+ "\n";
+ return buffer;
+}
+
+static int fdomain_arbitrate( void )
+{
+ int status = 0;
+ unsigned long timeout;
+
+#if VERBOSE
+ printk( "SCSI: fdomain_arbitrate()\n" );
+#endif
+
+ outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
+ outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
+ outb( 0x04, TMC_Cntl_port ); /* Start arbitration */
+
+ timeout = jiffies + 50; /* 500 mS */
+ while (jiffies < timeout) {
+ status = inb( TMC_Status_port ); /* Read adapter status */
+ if (status & 0x02) return 0; /* Arbitration complete */
+ }
+
+ /* Make bus idle */
+ fdomain_make_bus_idle();
+
+#if EVERY_ACCESS
+ printk( "Arbitration failed, status = %x\n", status );
+#endif
+#if ERRORS_ONLY
+ printk( "SCSI: Arbitration failed, status = %x", status );
+#endif
+ return 1;
+}
+
+static int fdomain_select( int target )
+{
+ int status;
+ unsigned long timeout;
+
+ outb( 0x80, SCSI_Cntl_port ); /* Bus Enable */
+ outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
+
+ /* Send our address OR'd with target address */
+#if SEND_IDENTIFY
+ outb( 0x40 | (1 << target), port_base + SCSI_Data_NoACK );
+#else
+ outb( (1 << target), port_base + SCSI_Data_NoACK );
+#endif
+
+ /* Stop arbitration (also set FIFO for output and enable parity) */
+ outb( 0xc8, TMC_Cntl_port );
+
+ timeout = jiffies + 25; /* 250mS */
+ while (jiffies < timeout) {
+ status = inb( SCSI_Status_port ); /* Read adapter status */
+ if (status & 1) { /* Busy asserted */
+ /* Enable SCSI Bus (on error, should make bus idle with 0) */
+#if SEND_IDENTIFY
+ /* Also, set ATN so that the drive will make a MESSAGE OUT phase */
+ outb( 0x88, SCSI_Cntl_port );
+#else
+ outb( 0x80, SCSI_Cntl_port );
+#endif
+ return 0;
+ }
+ }
+ /* Make bus idle */
+ fdomain_make_bus_idle();
+#if EVERY_ACCESS
+ if (!target) printk( "Select failed\n" );
+#endif
+#if ERRORS_ONLY
+ if (!target) printk( "SCSI: Select failed" );
+#endif
+ return 1;
+}
+
+#if QUEUE
+
+#if !USE_FIFO
+#pragma error QUEUE requires USE_FIFO
+#endif
+
+void my_done( int error )
+{
+ if (in_command) {
+ in_command = 0;
+ in_interrupt_code = 0;
+ outb( 0x00, Interrupt_Cntl_port );
+ fdomain_make_bus_idle();
+ if (current_done) current_done( this_host, error );
+ else panic( "SCSI (Future Domain): current_done() == NULL" );
+ } else {
+ panic( "SCSI (Future Domain): my_done() called outside of command\n" );
+ }
+}
+
+#if NEW_IRQ
+void fdomain_16x0_intr( int unused )
+#else
+void fdomain_16x0_intr( void )
+#endif
+{
+ int status;
+ int done = 0;
+ unsigned data_count;
+
+#if NEW_IRQ
+ sti();
+#endif
+
+ if (in_interrupt_code)
+ panic( "SCSI (Future Domain): fdomain_16x0_intr() NOT REENTRANT!\n" );
+ else
+ ++in_interrupt_code;
+
+ outb( 0x00, Interrupt_Cntl_port );
+
+#if EVERY_ACCESS
+ printk( "aborted = %d, ", aborted );
+#endif
+
+ if (aborted) {
+ /* Force retry for timeouts after selection complete */
+ if (current_phase == in_other)
+ my_done( DID_BUS_BUSY << 16 );
+ else
+ my_done( aborted << 16 );
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ }
+
+ /* We usually have one spurious interrupt after each command. Ignore it. */
+ if (!in_command) { /* Spurious interrupt */
+ in_interrupt_code = 0;
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ }
+
+ if (current_phase == in_arbitration) {
+ status = inb( TMC_Status_port ); /* Read adapter status */
+ if (!(status & 0x02)) {
+#if EVERY_ACCESS
+ printk( " AFAIL " );
+#endif
+ my_done( DID_TIME_OUT << 16 );
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ }
+ current_phase = in_selection;
+
+ outb( 0x80, SCSI_Cntl_port ); /* Bus Enable */
+ outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
+
+ outb( (1 << current_target), port_base + SCSI_Data_NoACK );
+
+ outb( 0x40, Interrupt_Cntl_port );
+ /* Stop arbitration (also set FIFO for output and enable parity) */
+ in_interrupt_code = 0;
+ outb( 0xd8, TMC_Cntl_port );
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ } else if (current_phase == in_selection) {
+ status = inb( SCSI_Status_port );
+ if (!(status & 0x01)) {
+#if EVERY_ACCESS
+ printk( " SFAIL " );
+#endif
+ my_done( DID_NO_CONNECT << 16 );
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ }
+ current_phase = in_other;
+#if FAST_SYNCH
+ outb( 0xc0, Data_Mode_Cntl_port );
+#endif
+ in_interrupt_code = 0;
+ outb( 0x90, Interrupt_Cntl_port );
+ outb( 0x80, SCSI_Cntl_port );
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+ }
+
+ /* current_phase == in_other: this is the body of the routine */
+
+ switch ((unsigned char)*the_command) {
+ case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
+ case 0x2e: case 0x3b: case 0xea: case 0x3f:
+ data_count = 0x2000 - inw( FIFO_Data_Count_port );
+ if (current_bufflen - data_sent < data_count)
+ data_count = current_bufflen - data_sent;
+ if (data_count > 0) {
+/* if (data_count > 512) data_count = 512; */
+#if EVERY_ACCESS
+ printk( "%d OUT, ", data_count );
+#endif
+ if (data_count == 1) {
+ outb( *out_buf_pt++, Write_FIFO_port );
+ ++data_sent;
+ } else {
+ data_count >>= 1;
+ outsw( out_buf_pt, data_count, Write_FIFO_port );
+ out_buf_pt += 2 * data_count;
+ data_sent += 2 * data_count;
+ }
+ }
+ break;
+ default:
+ if (!have_data_in) {
+ outb( 0x98, TMC_Cntl_port );
+ ++have_data_in;
+ } else {
+ data_count = inw( FIFO_Data_Count_port );
+/* if (data_count > 512) data_count = 512; */
+ if (data_count) {
+#if EVERY_ACCESS
+ printk( "%d IN, ", data_count );
+#endif
+ if (data_count == 1) {
+ *in_buf_pt++ = inb( Read_FIFO_port );
+ } else {
+ data_count >>= 1; /* Number of words */
+ insw( in_buf_pt, data_count, Read_FIFO_port );
+ in_buf_pt += 2 * data_count;
+ }
+ }
+ }
+ break;
+ }
+
+ status = inb( SCSI_Status_port );
+
+ if (status & 0x10) { /* REQ */
+
+ switch (status & 0x0e) {
+ case 0x08: /* COMMAND OUT */
+ outb( *cmd_pt++, Write_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "CMD = %x,", (unsigned char)cmd_pt[-1] );
+#endif
+ break;
+ case 0x0c: /* STATUS IN */
+ Status = inb( Read_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "Status = %x, ", Status );
+#endif
+#if ERRORS_ONLY
+ if (Status) {
+ printk( "SCSI: target = %d, command = %x, Status = %x\n",
+ current_target, (unsigned char)*the_command, Status );
+ }
+#endif
+ break;
+ case 0x0a: /* MESSAGE OUT */
+#if SEND_IDENTIFY
+ /* On the first request, send an Identify message */
+ if (!sent_identify) {
+ outb( 0x80, SCSI_Cntl_port ); /* Lower ATN */
+ outb( 0x80, Write_SCSI_Data_port ); /* Identify */
+ ++sent_identify;
+ } else
+#else
+ outb( 0x07, Write_SCSI_Data_port ); /* Reject */
+#endif
+ break;
+ case 0x0e: /* MESSAGE IN */
+ Message = inb( Read_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "Message = %x, ", Message );
+#endif
+ if (!Message) ++done;
+ break;
+ }
+ }
+
+ if (done) {
+#if EVERY_ACCESS
+ printk( " ** IN DONE ** " );
+#endif
+
+ if (have_data_in) {
+ while (data_count = inw( FIFO_Data_Count_port )) {
+ if (data_count == 1) {
+ *in_buf_pt++ = inb( Read_FIFO_port );
+ } else {
+ data_count >>= 1; /* Number of words */
+ insw( in_buf_pt, data_count, Read_FIFO_port );
+ in_buf_pt += 2 * data_count;
+ }
+ }
+ }
+#if EVERY_ACCESS
+ printk( "AFTER DATA GET\n" );
+#endif
+
+#if ERRORS_ONLY
+ if (*the_command == REQUEST_SENSE && !Status) {
+ if ((unsigned char)(*((char *)current_buff + 2)) & 0x0f) {
+ printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
+ (unsigned char)(*((char *)current_buff + 2)) & 0x0f,
+ (unsigned char)(*((char *)current_buff + 12)) );
+ }
+ }
+#endif
+#if EVERY_ACCESS
+ printk( "BEFORE MY_DONE\n" );
+#endif
+ my_done( (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
+ } else {
+ in_interrupt_code = 0;
+ outb( 0x90, Interrupt_Cntl_port );
+ }
+
+#if NEW_IRQ && !DECREASE_IL
+ cli();
+#endif
+ return;
+}
+
+int fdomain_16x0_queue( unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int,int) )
+{
+ if (in_command) {
+ panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" );
+ }
+#if EVERY_ACCESS
+ printk( "queue %d %x\n", target, *(unsigned char *)cmnd );
+#endif
+
+ fdomain_make_bus_idle();
+
+ aborted = 0;
+ current_target = target;
+ memcpy( current_cmnd, cmnd, ((*(unsigned char *)cmnd) <= 0x1f ? 6 : 10 ) );
+ current_buff = buff;
+ current_bufflen = bufflen;
+ current_done = done;
+
+ /* Initialize static data */
+ cmd_pt = current_cmnd;
+ the_command = current_cmnd;
+ out_buf_pt = current_buff;
+ in_buf_pt = current_buff;
+
+ Status = 0;
+ Message = 0;
+ data_sent = 0;
+ have_data_in = 0;
+
+ /* Start arbitration */
+ current_phase = in_arbitration;
+ outb( 0x00, Interrupt_Cntl_port );
+ outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
+ outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
+ ++in_command;
+ outb( 0x20, Interrupt_Cntl_port );
+ outb( 0x1c, TMC_Cntl_port ); /* Start arbitration */
+
+ return 0;
+}
+#endif
+
+int fdomain_16x0_command( unsigned char target, const void *cmnd,
+ void *buff, int bufflen )
+{
+ const char *cmd_pt = cmnd;
+ const char *the_command = cmnd;
+ unsigned char *out_buf_pt = buff;
+ unsigned char *in_buf_pt = buff;
+ int Status = 0;
+ int Message = 0;
+ int status;
+ int done = 0;
+ unsigned long timeout;
+ unsigned data_sent = 0;
+ unsigned data_count;
+#if USE_FIFO
+ int have_data_in = 0;
+#endif
+#if SEND_IDENTITY
+ int sent_identify = 0;
+#endif
+
+#if EVERY_ACCESS
+ printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command );
+#endif
+
+ if (fdomain_arbitrate()) {
+#if ERRORS_ONLY
+ printk( ", target = %d, command = %x\n",
+ target, (unsigned char)*the_command );
+#endif
+ return DID_TIME_OUT << 16;
+ }
+
+ if (fdomain_select( target )) {
+#if ERRORS_ONLY
+ if (!target) printk( ", target = %d, command = %x\n",
+ target, (unsigned char)*the_command );
+#endif
+ return DID_NO_CONNECT << 16;
+ }
+
+ timeout = jiffies + 500; /* 5000 mS -- For Maxtor after a RST */
+ aborted = 0; /* How is this supposed to get reset??? */
+
+#if FAST_SYNCH
+ outb( 0xc0, Data_Mode_Cntl_port );
+#endif
+
+#if USE_FIFO
+ switch ((unsigned char)*the_command) {
+ case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
+ case 0x2e: case 0x3b: case 0xea: case 0x3f:
+ data_count = 0x2000 - inw( FIFO_Data_Count_port );
+ if (bufflen - data_sent < data_count)
+ data_count = bufflen - data_sent;
+ if (data_count == 1) {
+ outb( *out_buf_pt++, Write_FIFO_port );
+ ++data_sent;
+ } else {
+ data_count >>= 1;
+ outsw( out_buf_pt, data_count, Write_FIFO_port );
+ out_buf_pt += 2 * data_count;
+ data_sent += 2 * data_count;
+ }
+ break;
+ default:
+ outb( 0x88, TMC_Cntl_port );
+ ++have_data_in;
+ break;
+ }
+#endif
+
+ while (((status = inb( SCSI_Status_port )) & 1)
+ && !done && !aborted && jiffies < timeout) {
+
+ if (status & 0x10) { /* REQ */
+
+ switch (status & 0x0e) {
+ case 0x00: /* DATA OUT */
+#if USE_FIFO
+ data_count = 0x2000 - inw( FIFO_Data_Count_port );
+ if (bufflen - data_sent < data_count)
+ data_count = bufflen - data_sent;
+ if (data_count == 1) {
+ outb( *out_buf_pt++, Write_FIFO_port );
+ ++data_sent;
+ } else {
+ data_count >>= 1;
+ outsw( out_buf_pt, data_count, Write_FIFO_port );
+ out_buf_pt += 2 * data_count;
+ data_sent += 2 * data_count;
+ }
+#else
+ outb( *out_buf_pt++, Write_SCSI_Data_port );
+#endif
+ break;
+ case 0x04: /* DATA IN */
+#if USE_FIFO
+ if (!have_data_in) {
+ outb( 0x88, TMC_Cntl_port );
+ ++have_data_in;
+ }
+ data_count = inw( FIFO_Data_Count_port );
+ if (data_count == 1) {
+ *in_buf_pt++ = inb( Read_FIFO_port );
+ } else {
+ data_count >>= 1; /* Number of words */
+ insw( in_buf_pt, data_count, Read_FIFO_port );
+ in_buf_pt += 2 * data_count;
+ }
+#else
+ *in_buf_pt++ = inb( Read_SCSI_Data_port );
+#endif
+ break;
+ case 0x08: /* COMMAND OUT */
+ outb( *cmd_pt++, Write_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "%x,", (unsigned char)cmd_pt[-1] );
+#endif
+ break;
+ case 0x0c: /* STATUS IN */
+ Status = inb( Read_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "Status = %x, ", Status );
+#endif
+#if ERRORS_ONLY
+ if (Status) {
+ printk( "SCSI: target = %d, command = %x, Status = %x\n",
+ target, (unsigned char)*the_command, Status );
+ }
+#endif
+ break;
+ case 0x0a: /* MESSAGE OUT */
+#if SEND_IDENTIFY
+ /* On the first request, send an Identify message */
+ if (!sent_identify) {
+ outb( 0x80, SCSI_Cntl_port ); /* Lower ATN */
+ outb( 0x80, Write_SCSI_Data_port ); /* Identify */
+ ++sent_identify;
+ } else
+#else
+ outb( 0x07, Write_SCSI_Data_port ); /* Reject */
+#endif
+ break;
+ case 0x0e: /* MESSAGE IN */
+ Message = inb( Read_SCSI_Data_port );
+#if EVERY_ACCESS
+ printk( "Message = %x, ", Message );
+#endif
+ if (!Message) ++done;
+ break;
+ }
+ }
+ }
+
+ if (jiffies >= timeout) {
+#if EVERY_ACCESS
+ printk( "Time out, status = %x\n", status );
+#endif
+#if ERRORS_ONLY
+ printk( "SCSI: Time out, status = %x (target = %d, command = %x)\n",
+ status, target, (unsigned char)*the_command );
+#endif
+ fdomain_make_bus_idle();
+ return DID_BUS_BUSY << 16;
+ }
+
+ if (aborted) {
+#if EVERY_ACCESS
+ printk( "Aborted\n" );
+#endif
+#if ONLY_ERRORS
+ printk( "SCSI: Aborted (command = %x)\n", (unsigned char)*the_command );
+#endif
+ fdomain_16x0_reset();
+ return DID_ABORT << 16;
+ }
+
+#if USE_FIFO
+ if (have_data_in) {
+ while (data_count = inw( FIFO_Data_Count_port )) {
+ if (data_count == 1) {
+ *in_buf_pt++ = inb( Read_FIFO_port );
+ } else {
+ data_count >>= 1; /* Number of words */
+ insw( in_buf_pt, data_count, Read_FIFO_port );
+ in_buf_pt += 2 * data_count;
+ }
+ }
+ }
+#endif
+
+ fdomain_make_bus_idle();
+
+#if EVERY_ACCESS
+ printk( "Retcode = %x\n",
+ (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
+#endif
+#if ERRORS_ONLY
+ if (*the_command == REQUEST_SENSE && !Status) {
+ if ((unsigned char)(*((char *)buff + 2)) & 0x0f) {
+ printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
+ (unsigned char)(*((char *)buff + 2)) & 0x0f,
+ (unsigned char)(*((char *)buff + 12)) );
+ }
+ }
+#endif
+
+ return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16);
+}
+
+int fdomain_16x0_abort( int code )
+{
+
+#if EVERY_ACCESS
+ printk( " ABORT " );
+#endif
+
+#if QUEUE
+ cli();
+ if (!in_command) {
+ sti();
+ return 0;
+ }
+
+ aborted = code ? code : DID_ABORT;
+
+ sti();
+ fdomain_make_bus_idle();
+#else
+ aborted = code ? code : DID_ABORT;
+#endif
+
+ return 0;
+}
+
+int fdomain_16x0_reset( void )
+{
+ outb( 1, SCSI_Cntl_port );
+ do_pause( 2 );
+ outb( 0, SCSI_Cntl_port );
+ do_pause( 115 );
+ outb( 0, Data_Mode_Cntl_port );
+ outb( 0, TMC_Cntl_port );
+
+ aborted = DID_RESET;
+
+ return 0;
+}
+
+#if QUEUE && !NEW_IRQ
+
+/* This is copied from kernel/sys_calls.s
+ and from kernel/blk_drv/scsi/aha1542.c */
+
+__asm__("
+_fdomain_16x0_interrupt:
+ 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
+
+ movl $_fdomain_disable_interrupt,%edx
+ call *%edx
+
+ 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
+
+ sti
+ movl $_fdomain_16x0_intr,%edx
+ call *%edx # ``interesting'' way of handling intr.
+ cli
+
+ movl $_fdomain_enable_interrupt,%edx
+ call *%edx
+
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ pop %ds
+ pop %es
+ pop %fs
+ pop %gs
+ iret
+");
+#endif
+
+#endif
--- /dev/null
+/* fdomain.h -- Header for Future Domain TMC-1660/TMC-1680 driver
+ * Created: Sun May 3 18:47:33 1992
+ * Revised: Sat May 23 22:42:55 1992 by root
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992 Rickard E. Faith
+ * This program comes with ABSOLUTELY NO WARRANTY.
+ *
+ * $Log$
+ */
+
+#ifndef _FDOMAIN_H
+#define _FDOMAIN_H
+
+#define QUEUE 1 /* Enable command queueing */
+
+int fdomain_16x0_detect( int );
+int fdomain_16x0_command( unsigned char target, const void *cmnd,
+ void *buff, int bufflen);
+int fdomain_16x0_abort( int );
+char *fdomain_16x0_info( void );
+int fdomain_16x0_reset( void );
+
+#if QUEUE
+int fdomain_16x0_queue( unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int,int) );
+
+#define FDOMAIN_16X0 { "Future Domain TMC-1660/TMC-1680", \
+ fdomain_16x0_detect, \
+ fdomain_16x0_info, \
+ fdomain_16x0_command, \
+ fdomain_16x0_queue, \
+ fdomain_16x0_abort, \
+ fdomain_16x0_reset, \
+ 1, 6, 0 }
+#else
+#define FDOMAIN_16X0 { "Future Domain TMC-1660/TMC-1680", \
+ fdomain_16x0_detect, \
+ fdomain_16x0_info, \
+ fdomain_16x0_command, \
+ NULL, \
+ fdomain_16x0_abort, \
+ fdomain_16x0_reset, \
+ 0, 6, 0 }
+#endif
+#endif
--- /dev/null
+/*
+ * 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_FUTURE_DOMAIN
+#include "fdomain.h"
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include "seagate.h"
+#endif
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+#include "ultrastor.h"
+#endif
+
+#ifdef CONFIG_SCSI_7000FASST
+#include "7000fasst.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.1 1992/07/24 06:27:38 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_FUTURE_DOMAIN
+ BLANKIFY(FDOMAIN_16X0),
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+ BLANKIFY(SEAGATE_ST0X),
+#endif
+#ifdef CONFIG_SCSI_ULTRASTOR
+ BLANKIFY(ULTRASTOR_14F),
+#endif
+#ifdef CONFIG_SCSI_7000FASST
+ BLANKIFY(WD7000FASST),
+#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];
+
+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 ("scsi%d : %s.\n\r",
+ count, scsi_hosts[i].name);
+ printk ("%s", scsi_hosts[i].info());
+ ++count;
+ }
+ }
+ printk ("scsi : %d hosts. \n\r", count);
+ }
+
+ }
+
+#endif
+#else
+void main(void) {
+ printf("0\n");
+ }
+#endif
--- /dev/null
+/*
+ * 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/07/24 06:27:38 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
--- /dev/null
+/*
+ * scsi.c Copyright (C) 1992 Drew Eckhardt
+ * generic mid-level SCSI driver by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ *
+ * Bug correction thanks go to :
+ * Rik Faith <faith@cs.unc.edu>
+ * Tommy Thorn <tthorn>
+ * Thomas Wuensche <tw@fgb1.fgb.mw.tu-meunchen.de>
+ */
+
+#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/07/24 06:27:38 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.
+ */
+
+volatile static int in_scan = 0;
+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, slave;
+ static unsigned char scsi_cmd [12];
+ static unsigned char scsi_result [256];
+
+ ++in_scan;
+
+ for (slave = host_nr = 0; host_nr < MAX_SCSI_HOSTS; ++host_nr,
+ slave = 0)
+ 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 :
+#ifdef DEBUG
+ printk("Detected scsi tape at host %d, ID %d, lun %d \n", host_nr, dev, lun);
+#endif
+#ifdef CONFIG_BLK_DEV_ST
+ if (!(maxed = (NR_ST == MAX_ST)))
+ scsi_tapes[NR_ST].device = &scsi_devices[NR_SCSI_DEVICES];
+#endif
+ break;
+ default :
+#ifdef DEBUG
+ printk("Detected scsi disk at host %d, ID %d, lun %d \n", host_nr, dev, lun);
+#endif
+#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 ("scsi : 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)
+ {
+ char *p;
+ char str[25];
+memcpy((void *) str, (void *) &scsi_result[8], 8);
+for (p = str; (p < (str + 8)) && (*p != ' '); ++p);
+*p++ = ' ';
+memcpy((void *) p, (void *) &scsi_result[16], 16);
+for (; *p != ' '; ++p);
+*p = 0;
+
+printk("s%c%d at scsi%d, id %d, lun %d : %s\n",
+ (type == TYPE_TAPE) ? 't' : 'd',
+ (type == TYPE_TAPE) ?
+#ifdef CONFIG_BLK_DEV_ST
+ NR_ST
+#else
+ -1
+#endif
+ :
+#ifdef CONFIG_BLK_DEV_SD
+ NR_SD
+#else
+ -1
+#endif
+ ,host_nr , dev, lun, p);
+ if (type == TYPE_TAPE)
+#ifdef CONFIG_BLK_DEV_ST
+ ++NR_ST;
+#else
+;
+#endif
+
+ else
+#ifdef CONFIG_BLK_DEV_SD
+ ++NR_SD;
+#else
+;
+#endif
+ }
+ ++slave;
+ ++NR_SCSI_DEVICES;
+ } /* if result == DID_OK ends */
+ } /* for lun ends */
+ } /* if present */
+
+ printk("scsi : detected "
+#ifdef CONFIG_BLK_DEV_SD
+ "%d SCSI 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
+ );
+ in_scan = 0;
+ } /* 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:
+ if (!in_scan)
+ 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", host);
+#endif
+ while (host_busy[host]);
+#ifdef DEBUG
+ printk("Host %d is no longer busy.\n", host);
+#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
+ host_busy[host] = 0;
+ last_cmnd[host].done (host, (result | ((exit & 0xff) << 24)));
+ }
+
+
+#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
+ {
+ oldto = host_timeout[host];
+ internal_timeout[host] |= IN_ABORT;
+ host_timeout[host] = ABORT_TIMEOUT;
+ update_timeout();
+
+
+ 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)
+ {
+ unsigned 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
--- /dev/null
+/*
+ * 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/07/24 06:27:38 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_BASE 0x80
+#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
+ ((can_disconnect) ? 0x40 : 0) |\
+ ((lun) & 0x07))
+
+
+/*
+ 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
+/*
+ Got an interrupt we weren't expecting.
+*/
+#define DID_BAD_INTR 0x09
+
+/*
+ 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 4
+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);
+
+extern int scsi_reset (int host);
+#endif
--- /dev/null
+#include <linux/config.h>
+#ifdef CONFIG_SCSI
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/errno.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 8192
+
+#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 struct ptr, *(int *) arg is the length of the
+ * input data, if any, not including the command string & counts,
+ * *((int *)arg + 1) is the output buffer size in bytes.
+ *
+ * *(char *) ((int *) arg)[2] the actual command byte.
+ *
+ * Note that no more than MAX_BUF data bytes will be transfered. Since
+ * SCSI block device size is 512 bytes, I figured 1K was good.
+ * but (WDE) changed it to 8192 to handle large bad track buffers.
+ *
+ * This size *does not* include the initial lengths that were passed.
+ *
+ * The SCSI command is read from the memory location immediately after the
+ * length words, and the input data is right after the command. The SCSI
+ * routines know the command size based on the opcode decode.
+ *
+ * The output area is then filled in starting from the command byte.
+ */
+
+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 ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
+ return temp;
+#else
+ {
+ int i;
+ printk("scsi_ioctl : device %d. command = ", dev->id);
+ 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");
+ printk("inlen = %d, outlen = %d, cmdlen = %d\n",
+ inlen, outlen, cmdlen);
+ printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
+ }
+ 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
+ a pointer to a scsi_devices[] element, a structure.
+*/
+int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+{
+ if ((cmd != 0 && dev->id > NR_SCSI_DEVICES))
+ return -ENODEV;
+ if ((cmd == 0 && dev->host_no > MAX_SCSI_HOSTS))
+ return -ENODEV;
+
+ switch (cmd) {
+ case SCSI_IOCTL_PROBE_HOST:
+ return ioctl_probe(dev->host_no, arg);
+ case SCSI_IOCTL_SEND_COMMAND:
+ return ioctl_command((Scsi_Device *) dev, arg);
+ default :
+ return -EINVAL;
+ }
+}
+#endif
--- /dev/null
+#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
+
+
--- /dev/null
+/*
+ * 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/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+
+#include "scsi.h"
+#include "sd.h"
+
+#define MAJOR_NR 8
+
+#include "../blk.h"
+#include <linux/genhd.h>
+
+/*
+static const char RCSid[] = "$Header:";
+*/
+
+#define MAX_RETRIES 5
+
+/*
+ * Time out in seconds
+ */
+
+#define SD_TIMEOUT 200
+
+struct hd_struct sd[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;
+
+static char sense_buffer[255];
+
+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 gendisk sd_gendisk;
+
+static void sd_geninit (void) {
+ int i;
+ for (i = 0; i < NR_SD; ++i)
+ sd_sizes[i << 4] =
+ (sd[i << 4].nr_sects = rscsi_disks[i].capacity) >>
+ (BLOCK_SIZE_BITS - 9);
+ sd_gendisk.nr_real = NR_SD;
+}
+
+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 */
+};
+
+static struct gendisk sd_gendisk = {
+ MAJOR_NR, /* Major number */
+ "sd", /* Major name */
+ 4, /* Bits to shift to get real from partition */
+ 1 << 4, /* Number of partitions per real */
+ MAX_SD, /* maximum number of real */
+ sd_geninit, /* init function */
+ sd, /* hd struct */
+ sd_sizes, /* block sizes */
+ 0, /* number */
+ (void *) rscsi_disks, /* internal */
+ NULL /* next */
+};
+
+/*
+ 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.");
+
+#ifdef DEBUG
+ printk("sd%d : rw_intr(%d, %x)\n", MINOR(CURRENT->dev), host, result);
+#endif
+
+/*
+ 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) {
+ CURRENT->nr_sectors -= this_count;
+
+#ifdef DEBUG
+ printk("sd%d : %d sectors remain.\n", MINOR(CURRENT->dev), CURRENT->nr_sectors);
+#endif
+
+/*
+ * If multiple sectors are requested in one buffer, then
+ * they will have been finished off by the first command. If
+ * not, then we have a multi-buffer command.
+ */
+ if (CURRENT->nr_sectors)
+ {
+ CURRENT->sector += this_count;
+ CURRENT->errors = 0;
+
+ if (!CURRENT->bh)
+ {
+#ifdef DEBUG
+ printk("sd%d : handling page request, no buffer\n",
+ MINOR(CURRENT->dev));
+#endif
+
+/*
+ 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;
+ }
+ else
+ {
+#ifdef DEBUG
+ printk("sd%d : handling linked buffer request\n", MINOR(CURRENT->dev));
+#endif
+ end_request(1);
+ }
+ }
+ else
+ end_request(1);
+ do_sd_request();
+ }
+
+/*
+ * Of course, the error handling code is a little Fubar down in scsi.c.
+ * Version 2 of the drivers will fix that, and we will *really* recover
+ * from errors.
+ */
+
+/*
+ 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.
+*/
+
+static void do_sd_request (void)
+{
+ int dev, block;
+ unsigned char cmd[10];
+
+repeat:
+ 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 + CURRENT->nr_sectors > sd[dev].nr_sects)
+ {
+ end_request(0);
+ goto repeat;
+ }
+
+ block += sd[dev].start_sect;
+ dev = DEVICE_NR(dev);
+
+#ifdef DEBUG
+ printk("sd%d : real dev = /dev/sd%d, block = %d\n", MINOR(CURRENT->dev), dev, block);
+#endif
+
+
+ if (!CURRENT->bh)
+ this_count = CURRENT->nr_sectors;
+ else
+ this_count = (BLOCK_SIZE / 512);
+
+#ifdef DEBUG
+ printk("sd%d : %s %d/%d 512 byte blocks.\n", MINOR(CURRENT->dev),
+ (CURRENT->cmd == WRITE) ? "writing" : "reading",
+ this_count, CURRENT->nr_sectors);
+#endif
+
+ 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;
+ unsigned char cmd[10];
+ unsigned char buffer[513];
+ int try_again;
+
+
+ for (i = 0; i < NR_SD; ++i)
+ {
+ try_again=2;
+ cmd[0] = READ_CAPACITY;
+ cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ memset ((void *) &cmd[2], 0, 8);
+
+/*
+ * Super Kludge - since the midlevel error handling code doesn't work
+ * Version 2 will - it's under development 8^)
+ *
+ * We manually retry
+ */
+
+
+ do {
+ the_result = -1;
+#ifdef DEBUG
+ printk("sd%d : READ CAPACITY\n ", i);
+#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);
+ } while (try_again && the_result);
+/*
+ * 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 ("sd%d : READ CAPACITY failed.\n"
+ "sd%d : status = %x, message = %02x, host = %02x, driver = %02x \n",
+ i,i,
+ 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("sd%d : extended sense code = %1x \n", i, sense_buffer[2] & 0xf);
+ else
+ printk("sd%d : sense not available. \n", i);
+
+ printk("sd%d : block size assumed to be 512 bytes, disk size 1GB. \n", i);
+ 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 ("sd%d : unsupported sector size %d.\n",
+ i, rscsi_disks[i].sector_size);
+ printk ("scsi : deleting disk entry.\n");
+ for (j=i; j < NR_SD;)
+ rscsi_disks[j] = rscsi_disks[++j];
+ --i;
+ continue;
+ }
+ }
+
+ 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;
+ sd_gendisk.next = gendisk_head;
+ gendisk_head = &sd_gendisk;
+}
+#endif
--- /dev/null
+/*
+ * 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/07/24 06:27:38 root Exp root $
+*/
+
+#ifndef _SCSI_H
+#include "scsi.h"
+#endif
+
+#ifndef _GENDISK_H
+#include <linux/genhd.h>
+#endif
+
+/*
+ This is an arbitrary constant, and may be changed to whatever
+ suits your purposes. Note that smaller will get you a few bytes
+ more in kernel space if that is your thing.
+*/
+
+#define MAX_SD 4
+extern int NR_SD;
+
+extern struct hd_struct sd[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 */
+ } 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
--- /dev/null
+#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 (Scsi_Device *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
--- /dev/null
+/*
+ * seagate.c Copyright (C) 1992 Drew Eckhardt
+ * low level scsi driver for ST01/ST02 by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_88x)
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include "seagate.h"
+#include "scsi.h"
+#include "hosts.h"
+
+extern void seagate_intr(void);
+static int internal_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, int reselect);
+void (*do_seagate)(void) = NULL;
+
+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;
+
+static 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[] = {
+#ifdef CONFIG_SCSI_SEAGATE
+{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40},
+
+/*
+ The following two lines are NOT mistakes. One detects
+ ROM revision 3.0.0, the other 3.2. Since seagate
+ has only one type of SCSI adapter, and this is not
+ going to change, the "SEAGATE" and "SCSI" together
+ are probably "good enough"
+*/
+
+{"SEAGATE SCSI BIOS ",16, 17},
+{"SEAGATE SCSI BIOS ",17, 17},
+#endif
+
+/*
+ This is for the Future Domain 88x series. I've been told that
+ the Seagate controllers are just repackages of these, and seeing
+ early seagate BIOS bearing the Future Domain copyright,
+ I believe it.
+*/
+
+#ifdef CONFIG_SCSI_FD_88x
+{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/90", 5, 46},
+#endif
+}
+;
+/*
+ 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
+
+/*
+ * hostno stores the hostnumber, as told to us by the init routine.
+ */
+
+static int hostno = -1;
+
+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
+
+ if (hostno != -1)
+ {
+ printk ("ERROR : seagate_st0x_detect() called twice.\n");
+ return 0;
+ }
+
+ 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 signature
+ * from the BIOS version notice in all the possible locations
+ * of the ROM's. This has a nice sideeffect of not trashing
+ * any register locations that might be used by something else.
+ */
+
+ 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
+ hostno = hostnum;
+
+/*
+ * At all times, we will use IRQ 5.
+ */
+
+#if 1
+ set_intr_gate (0x25, seagate_intr);
+ __asm__("
+ inb $0x21, %%al
+ andb $0xdf, %%al
+ outb %%al, $0x21"::);
+#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/07/24 06:27:38 root Exp root $\n";
+ return buffer;
+}
+
+/*
+ * These are our saved pointers for the outstanding command that is
+ * waiting for a reconnect
+ */
+
+static unsigned char current_target;
+static unsigned char *current_cmnd, *current_data;
+static int current_bufflen;
+static void (*done_fn)(int, int) = NULL;
+
+/*
+ * These control weather or not disconnect / reconnect will be attempted,
+ * or are being attempted.
+ */
+
+#define NO_RECONNECT 0
+#define RECONNECT_NOW 1
+#define CAN_RECONNECT 2
+
+/*
+ * This determines if we are expecting to reconnect or not.
+ */
+
+static int should_reconnect = 0;
+
+void seagate_unexpected_intr (void)
+ {
+ printk("scsi%d: unexpected interrupt.\n", hostno);
+ }
+
+/*
+ * The seagate_reconnect_intr routine is called when a target reselects the
+ * host adapter. This occurs on the interrupt triggered by the target
+ * asserting SEL.
+ */
+
+void seagate_reconnect_intr (void)
+ {
+ int temp;
+
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : seagate_reconnect_intr() called\n", hostno);
+#endif
+
+ if (!should_reconnect)
+ seagate_unexpected_intr();
+ else
+ {
+ should_reconnect = 0;
+
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : internal_command("
+ "%d, %08x, %08x, %d, RECONNECT_NOW\n", hostno,
+ current_target, current_data, current_bufflen);
+#endif
+
+ temp = internal_command (current_target,
+ current_cmnd, current_data, current_bufflen,
+ RECONNECT_NOW);
+
+ if (msg_byte(temp) != DISCONNECT)
+ {
+ if (done_fn)
+ {
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : done_fn(%d,%08x)", hostno,
+ hostno, temp);
+#endif
+ done_fn (hostno, temp);
+ }
+ else
+ printk("done_fn() not defined.\n");
+ }
+ }
+ }
+
+/*
+ * The seagate_st0x_queue_command() function provides a queued interface
+ * to the seagate SCSI driver. Basically, it just passes control onto the
+ * seagate_command() function, after fixing it so that the done_fn()
+ * is set to the one passed to the function.
+ */
+
+int seagate_st0x_queue_command (unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*fn)(int,
+ int))
+ {
+ int result;
+
+ done_fn = fn;
+ current_target = target;
+ (const void *) current_cmnd = cmnd;
+ current_data = buff;
+ current_bufflen = bufflen;
+
+ result = internal_command (target, cmnd, buff, bufflen,
+ CAN_RECONNECT);
+ if (msg_byte(result) == DISCONNECT)
+ return 0;
+ else
+ {
+ done_fn (hostno, result);
+ return 1;
+ }
+ }
+
+int seagate_st0x_command (unsigned char target, const void *cmnd,
+ void *buff, int bufflen)
+ {
+ return internal_command (target, cmnd, buff, bufflen,
+ (int) NO_RECONNECT);
+ }
+
+static int internal_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, int reselect)
+ {
+ int len;
+ unsigned char *data;
+ int clock;
+ int temp;
+
+
+#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;
+
+ do_seagate = seagate_unexpected_intr;
+
+ len=bufflen;
+ data=(unsigned char *) buff;
+
+ incommand = 0;
+ st0x_aborted = 0;
+
+#if (DEBUG & PRINT_COMMAND)
+ printk ("scsi%d : target = %d, command = ", hostno, target);
+ for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i)
+ printk("%02x ", ((unsigned char *) cmnd)[i]);
+ printk("\n");
+#endif
+
+#if (DEBUG & PHASE_RESELECT)
+ switch (reselect)
+ {
+ case RECONNECT_NOW :
+ printk("scsi%d : reconnecting\n", hostno);
+ break;
+ case CAN_RECONNECT :
+ printk("scsi%d : allowed to reconnect\n", hostno);
+ break;
+ default :
+ printk("scsi%d : not allowed to reconnect\n", hostno);
+ }
+#endif
+
+
+ if (target > 6)
+ {
+ if (reselect == RECONNECT_NOW)
+ eoi();
+ return DID_BAD_TARGET;
+ }
+
+/*
+ * We work it differently depending on if this is is "the first time,"
+ * or a reconnect. If this is a reselct phase, then SEL will
+ * be asserted, and we must skip selection / arbitration phases.
+ */
+
+ if (reselect == RECONNECT_NOW)
+ {
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : phase RESELECT \n", hostno);
+#endif
+
+/*
+ * At this point, we should find the logical or of our ID and the original
+ * target's ID on the BUS, with BSY, SEL, and I/O signals asserted.
+ *
+ * After ARBITRATION phase is completed, only SEL, BSY, and the
+ * target ID are asserted. A valid initator ID is not on the bus
+ * until IO is asserted, so we must wait for that.
+ */
+
+ for (clock = jiffies + 10, temp = 0; (jiffies < clock) &&
+ !(STATUS & STAT_IO););
+
+ if (jiffies >= clock)
+ {
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : RESELECT timed out while waiting for IO .\n",
+ hostno);
+#endif
+ eoi();
+ return (DID_BAD_INTR << 16);
+ }
+
+/*
+ * After I/O is asserted by the target, we can read our ID and its
+ * ID off of the BUS.
+ */
+
+ if (!((temp = DATA) & 0x80))
+ {
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : detected reconnect request to different target.\n"
+ "\tData bus = %d\n", hostno, temp);
+#endif
+ eoi();
+ return (DID_BAD_INTR << 16);
+ }
+
+ if (!(temp & (1 << current_target)))
+ {
+ printk("scsi%d : Unexpected reselect interrupt. Data bus = %d\n",
+ hostno, temp);
+ eoi();
+ return (DID_BAD_INTR << 16);
+ }
+ data=current_data; /* WDE add */
+ cmnd=current_cmnd; /* WDE add */
+ len=current_bufflen; /* WDE add */
+
+/*
+ * We have determined that we have been selected. At this point,
+ * we must respond to the reselection by asserting BSY ourselves
+ */
+
+ CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
+
+/*
+ * The target will drop SEL, and raise BSY, at which time we must drop
+ * BSY.
+ */
+
+ for (clock = jiffies + 10; (jiffies < clock) && (STATUS & STAT_SEL););
+
+ if (jiffies >= clock)
+ {
+ CONTROL = (BASE_CMD | CMD_INTR);
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : RESELECT timed out while waiting for SEL.\n",
+ hostno);
+#endif
+ eoi();
+ return (DID_BAD_INTR << 16);
+ }
+
+ CONTROL = BASE_CMD;
+
+/*
+ * At this point, we have connected with the target and can get
+ * on with our lives.
+ */
+ eoi();
+ }
+ else
+ {
+#if (DEBUG & PHASE_BUS_FREE)
+ printk ("scsi%d : phase = BUS FREE \n", hostno);
+#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. Several reads help
+ * eliminate wire glitch.
+ */
+
+ 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, and we raise SEL.
+ */
+
+#if (DEBUG & PHASE_SELECTION)
+ printk("scsi%d : phase = SELECTION\n", hostno);
+#endif
+
+ clock = jiffies + ST0X_SELECTION_DELAY;
+
+/*
+ * If we wish to disconnect, we should request a MESSAGE OUT
+ * at this point. Technically, ATTN should be raised before
+ * SEL = true and BSY = false (from arbitration), but I think this
+ * should do.
+ */
+ if (reselect)
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE |
+ CMD_ATTN;
+
+/*
+ * We must assert both our ID and our target's ID on the bus.
+ */
+ DATA = (unsigned char) ((1 << target) | 0x80);
+
+/*
+ * If we are allowing ourselves to reconnect, then I will keep
+ * ATTN raised so we get MSG OUT.
+ */
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
+ (reselect ? CMD_ATTN : 0);
+
+/*
+ * 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("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n",
+ hostno, status_read, temp, st0x_aborted);
+#else
+ ;
+#endif
+
+
+ if ((jiffies > clock) || (!st0x_aborted &&
+ !(status_read & STAT_BSY)))
+ {
+#if (DEBUG & PHASE_SELECT)
+ printk ("scsi%d : NO CONNECT with target %d, status = %x \n",
+ hostno, 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);
+ }
+ }
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE |
+ ((reselect == CAN_RECONNECT) ? CMD_ATTN : 0) ;
+
+/*
+ * INFORMATION TRANSFER PHASE
+ *
+ * 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("scsi%d : phase = INFORMATION TRANSFER\n", hostno);
+#endif
+
+ incommand = 1;
+
+
+/*
+ * 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%d : phase = DATA OUT\n",
+ hostno);
+ break;
+ case REQ_DATAIN :
+ printk("scsi%d : phase = DATA IN\n",
+ hostno);
+ break;
+ case REQ_CMDOUT :
+ printk("scsi%d : phase = COMMAND OUT\n",
+ hostno);
+ break;
+ case REQ_STATIN :
+ printk("scsi%d : phase = STATUS IN\n",
+ hostno);
+ break;
+ case REQ_MSGOUT :
+ printk("scsi%d : phase = MESSAGE OUT\n",
+ hostno);
+ break;
+ case REQ_MSGIN :
+ printk("scsi%d : phase = MESSAGE IN\n",
+ hostno);
+ break;
+ default :
+ printk("scsi%d : phase = UNKNOWN\n",
+ hostno);
+ 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 in 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))
+ if (status_read & STAT_REQ)
+ DATA = *(unsigned char *) cmnd ++;
+ break;
+
+ case REQ_STATIN :
+ status = DATA;
+ break;
+
+ case REQ_MSGOUT :
+/*
+ * We can only have sent a MSG OUT if we requested to do this
+ * by raising ATTN. So, we must drop ATTN.
+ */
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+/*
+ * If we are reconecting, then we must send an IDENTIFY message in
+ * response to MSGOUT.
+ */
+ if (reselect)
+ {
+ DATA = IDENTIFY(1,0);
+#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT))
+ printk("scsi%d : sent IDENTIFY message.\n", hostno);
+#endif
+ }
+ else
+ {
+ DATA = MESSAGE_REJECT;
+
+#if (DEBUG & PHASE_MSGOUT)
+ printk("scsi%d : sent MESSAGE REJECT message.\n", hostno);
+#endif
+ }
+ break;
+
+ case REQ_MSGIN :
+ switch (message = DATA)
+ {
+ case DISCONNECT :
+ should_reconnect = 1;
+ current_data = data; /* WDE add */
+ current_bufflen = len; /* WDE add */
+#if (DEBUG & (PHASE_RESELECT | PHASE_MSGIN))
+ printk("scsi%d : disconnected.\n", hostno);
+ done=1;
+ break;
+#endif
+ case COMMAND_COMPLETE :
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : command complete.\n", hostno);
+ done=1;
+ break;
+#endif
+ case ABORT :
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : abort message.\n", hostno);
+#endif
+ done=1;
+ break;
+ case SAVE_POINTERS :
+ current_data = data; /* WDE mod */
+ current_bufflen = len; /* WDE add */
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : pointers saved.\n", hostno);
+#endif
+ break;
+ case RESTORE_POINTERS:
+ data=current_data; /* WDE mod */
+ cmnd=current_cmnd;
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : pointers restored.\n", hostno);
+#endif
+ break;
+ default:
+
+/*
+ * IDENTIFY distinguishes itself from the other messages by setting the
+ * high byte.
+ */
+
+ if (message & 0x80)
+ {
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : IDENTIFY message received from id %d, lun %d.\n",
+ hostno, target, message & 7);
+#endif
+ }
+ else
+ {
+
+#if (DEBUG & PHASE_MSGIN)
+ printk("scsi%d : unknown message %d from target %d.\n",
+ hostno, message, target);
+#endif
+ }
+ }
+ break;
+
+ default :
+ printk("scsi%d : unknown phase.\n", hostno);
+ st0x_aborted = DID_ERROR;
+ }
+ } /* while ends */
+ } /* if ends */
+
+#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 *) data)[i]); /* WDE mod */
+ 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;
+ }
+
+ if (should_reconnect)
+ {
+#if (DEBUG & PHASE_RESELECT)
+ printk("scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n",
+ hostno);
+#endif
+ do_seagate = seagate_reconnect_intr;
+ CONTROL = BASE_CMD | CMD_INTR ;
+ }
+ else
+ CONTROL = BASE_CMD;
+
+ 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
+
--- /dev/null
+/*
+ * 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_queue_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int, int));
+
+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, \
+ seagate_st0x_queue_command, seagate_st0x_abort, \
+ seagate_st0x_reset, 1, 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
+#define PHASE_RESELECT 0x800
+
+/*
+ * Control options - these are timeouts specified in .01 seconds.
+ */
+
+#define ST0X_BUS_FREE_DELAY 25
+#define ST0X_SELECTION_DELAY 3
+
+#define eoi() __asm__("push %%eax\nmovb $0x20, %%al\noutb %%al, $0x20\npop %%eax"::)
+
+
+#endif
+
--- /dev/null
+/*
+ * seagate2.S
+ * low level scsi driver for ST01/ST02 by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+.text
+.globl _seagate_intr
+_seagate_intr:
+ cld # GCC thing
+
+ pushal
+ push %ds
+ push %es
+
+ mov $0x10, %ax # switch to kernel space
+ mov %ax, %ds
+ mov %ax, %es
+
+
+
+ xor %eax, %eax
+ xchg _do_seagate, %eax
+ test %eax, %eax
+ jnz 1f
+ mov $_seagate_unexpected_intr, %eax
+1: call *%eax
+
+ mov $0x20, %al # non-specific EOI
+ out %al, $0x20
+
+ pop %es
+ pop %ds
+ popal
+ iret
--- /dev/null
+/*
+ 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"
+
+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
--- /dev/null
+
+#ifndef _ST_H
+ #define _ST_H
+/*
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/07/24 06:27:38 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
--- /dev/null
+#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(Scsi_Device *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
--- /dev/null
+/*
+ * ultrastor.c Copyright (C) 1991, 1992 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
+ */
+
+/*
+ * NOTES:
+ * The UltraStor 14F is an intelligent, high performance ISA SCSI-2 host
+ * adapter. It is essentially an ISA version of the UltraStor 24F EISA
+ * adapter. It supports first-party DMA, command queueing, and
+ * scatter/gather I/O. It can also emulate the standard AT MFM/RLL/IDE
+ * interface for use with OS's which don't support SCSI.
+ *
+ * This driver may also work (with some small changes) with the UltraStor
+ * 24F. I have no way of confirming this...
+ *
+ * Places flagged with a triple question-mark are things which are either
+ * unfinished, questionable, or wrong.
+ */
+
+/*
+ * 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!
+ *
+ * By defining NO_QUEUEING in ultrastor.h, you disable the queueing feature
+ * of the mid-level SCSI driver. Once I'm satisfied that the queueing
+ * version is as stable as the non-queueing version, I'll eliminate this
+ * option.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
+#include "ultrastor.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#define VERSION "1.0 beta"
+
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+#define BIT(n) (1ul << (n))
+#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 fetch the configuration info from the config i/o registers. We
+ then store (in a friendlier format) in config. */
+struct config_1 {
+ unsigned char bios_segment: 3;
+ unsigned char reserved: 1;
+ unsigned char interrupt: 2;
+ unsigned char dma_channel: 2;
+};
+struct config_2 {
+ unsigned char ha_scsi_id: 3;
+ unsigned char mapping_mode: 2;
+ unsigned char bios_drive_number: 1;
+ unsigned char tfr_port: 2;
+};
+
+/* 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 {
+ unsigned short port_address;
+ const void *bios_segment;
+ unsigned char interrupt: 4;
+ unsigned char dma_channel: 3;
+ unsigned char ha_scsi_id: 3;
+ unsigned char heads: 6;
+ unsigned char sectors: 6;
+ unsigned char bios_drive_number: 1;
+};
+
+/* 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 };
+
+/* 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 } };
+
+/* 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
+# define PORT_ADDRESS (config.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
+
+void ultrastor_interrupt(void);
+
+static void (*ultrastor_done)(int, int) = 0;
+
+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;
+ struct config_1 config_1;
+ struct config_2 config_2;
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: called\n");
+#endif
+
+#ifndef PORT_OVERRIDE
+ PORT_ADDRESS = 0;
+ for (i = 0; i < ARRAY_SIZE(ultrastor_ports); i++) {
+ PORT_ADDRESS = ultrastor_ports[i];
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
+#endif
+
+ in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
+ if (in_byte != US14F_PRODUCT_ID_0) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+ printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
+# else
+ printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+ return FALSE;
+#else
+ continue;
+#endif
+ }
+ 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) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+ printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
+# else
+ printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+ return FALSE;
+#else
+ continue;
+#endif
+ }
+#ifndef PORT_OVERRIDE
+ break;
+ }
+ if (i == ARRAY_SIZE(ultrastor_ports)) {
+# if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: no port address found!\n");
+# endif
+ return FALSE;
+ }
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: adapter found at port address %03X\n",
+ PORT_ADDRESS);
+#endif
+
+ /* All above tests passed, must be the right thing. Get some useful
+ info. */
+ *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
+ *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
+ config.bios_segment = bios_segment_table[config_1.bios_segment];
+ config.interrupt = interrupt_table[config_1.interrupt];
+ config.dma_channel = dma_channel_table[config_1.dma_channel];
+ config.ha_scsi_id = config_2.ha_scsi_id;
+ config.heads = mapping_table[config_2.mapping_mode].heads;
+ config.sectors = mapping_table[config_2.mapping_mode].sectors;
+ config.bios_drive_number = config_2.bios_drive_number;
+
+ /* To verify this card, we simply look for the UltraStor SCSI from the
+ BIOS version notice. */
+ if (config.bios_segment != NULL) {
+ int found = 0;
+
+ for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
+ if (memcmp((char *)config.bios_segment + signatures[i].offset,
+ signatures[i].signature, signatures[i].length))
+ found = 1;
+ if (!found)
+ config.bios_segment = NULL;
+ }
+ if (!config.bios_segment) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: not detected.\n");
+#endif
+ return FALSE;
+ }
+
+ /* Final consistancy check, verify previous info. */
+ if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: 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... */
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: detect succeeded\n"
+ " Port address: %03X\n"
+ " BIOS segment: %05X\n"
+ " Interrupt: %u\n"
+ " DMA channel: %u\n"
+ " H/A SCSI ID: %u\n",
+ PORT_ADDRESS, config.bios_segment, config.interrupt,
+ config.dma_channel, config.ha_scsi_id);
+#endif
+ host_number = hostnum;
+ scsi_hosts[hostnum].this_id = config.ha_scsi_id;
+#ifndef NO_QUEUEING
+ set_intr_gate(0x20 + config.interrupt, ultrastor_interrupt);
+ /* gate to PIC 2 */
+ outb_p(inb_p(0x21) & ~BIT(2), 0x21);
+ /* enable the interrupt */
+ outb(inb_p(0xA1) & ~BIT(config.interrupt - 8), 0xA1);
+#endif
+ return TRUE;
+}
+
+const char *ultrastor_14f_info(void)
+{
+ return "UltraStor 14F SCSI driver version "
+ VERSION
+ " by David B. Gentzel\n";
+}
+
+static struct mscp mscp = {
+ OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE /* This stuff doesn't change */
+};
+
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int, int))
+{
+ unsigned char in_byte;
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+ printk("US14F: queuecommand: called\n");
+#endif
+
+ /* Skip first (constant) byte */
+ memset((char *)&mscp + 1, 0, sizeof (struct mscp) - 1);
+ mscp.target_id = target;
+ /* mscp.lun = ???; */
+ mscp.transfer_data = *(Longword *)&buff;
+ mscp.transfer_data_length = *(Longword *)&bufflen,
+ mscp.length_of_scsi_cdbs = ((*(unsigned char *)cmnd <= 0x1F) ? 6 : 10);
+ memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
+
+ /* Find free OGM slot (OGMINT bit is 0) */
+ do
+ in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
+ while (!aborted && (in_byte & 1));
+ if (aborted) {
+#if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
+ printk("US14F: queuecommand: aborted\n");
+#endif
+ /* ??? is this right? */
+ return (aborted << 16);
+ }
+
+ /* Store pointer in OGM address bytes */
+ outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
+ outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
+ outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
+ outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
+
+ /* Issue OGM interrupt */
+ outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
+
+ ultrastor_done = done;
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+ printk("US14F: queuecommand: returning\n");
+#endif
+
+ return 0;
+}
+
+#ifdef NO_QUEUEING
+int ultrastor_14f_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen)
+{
+ unsigned char in_byte;
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+ printk("US14F: command: called\n");
+#endif
+
+ (void)ultrastor_14f_queuecommand(target, cmnd, buff, bufflen, 0);
+
+ /* Wait for ICM interrupt */
+ do
+ in_byte = inb_p(SYS_DOORBELL_INTR(PORT_ADDRESS));
+ while (!aborted && !(in_byte & 1));
+ if (aborted) {
+#if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
+ printk("US14F: command: aborted\n");
+#endif
+ /* ??? is this right? */
+ return (aborted << 16);
+ }
+
+ /* Clean ICM slot (set ICMINT bit to 0) */
+ outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+ printk("US14F: command: returning %08X\n",
+ (mscp.adapter_status << 16) | mscp.target_status);
+#endif
+
+ /* ??? not right, but okay for now? */
+ return (mscp.adapter_status << 16) | mscp.target_status;
+}
+#endif
+
+int ultrastor_14f_abort(int code)
+{
+#if (ULTRASTOR_DEBUG & UD_ABORT)
+ printk("US14F: abort: called\n");
+#endif
+
+ aborted = (code ? code : DID_ABORT);
+
+#if (ULTRASTOR_DEBUG & UD_ABORT)
+ printk("US14F: abort: returning\n");
+#endif
+
+ return 0;
+}
+
+int ultrastor_14f_reset(void)
+{
+ unsigned char in_byte;
+
+#if (ULTRASTOR_DEBUG & UD_RESET)
+ printk("US14F: reset: called\n");
+#endif
+
+ /* Issue SCSI BUS reset */
+ outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
+
+ /* Wait for completion... */
+ do
+ in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
+ while (in_byte & 0x20);
+
+ aborted = DID_RESET;
+
+#if (ULTRASTOR_DEBUG & UD_RESET)
+ printk("US14F: reset: returning\n");
+#endif
+ return 0;
+}
+
+#ifndef NO_QUEUEING
+void ultrastor_interrupt_service(void)
+{
+#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
+ printk("US14F: interrupt_service: called: status = %08X\n",
+ (mscp.adapter_status << 16) | mscp.target_status);
+#endif
+
+ if (ultrastor_done == 0)
+ panic("US14F: interrupt_service: unexpected interrupt!\n");
+ else {
+ void (*done)(int, int);
+
+ /* Save ultrastor_done locally and zero before calling. This is needed
+ as once we call done, we may get another command queued before this
+ interrupt service routine can return. */
+ done = ultrastor_done;
+ ultrastor_done = 0;
+
+ /* Clean ICM slot (set ICMINT bit to 0) */
+ outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
+
+ /* Let the higher levels know that we're done */
+ /* ??? status is wrong here... */
+ done(host_number, (mscp.adapter_status << 16) | mscp.target_status);
+ }
+
+#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
+ printk("US14F: interrupt_service: returning\n");
+#endif
+}
+
+__asm__("
+_ultrastor_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
+ outb %al,$0x80 # give port chance to breathe
+ outb %al,$0x80
+ outb %al,$0x80
+ outb %al,$0x80
+ outb %al,$0x20
+ call _ultrastor_interrupt_service
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+");
+#endif
+
+#endif
--- /dev/null
+/*
+ * 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
+
+/* ??? These don't really belong here */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* ??? This should go eventually, once I'm convinced the queueing stuff is
+ stable enough... */
+/* #define NO_QUEUEING */
+
+int ultrastor_14f_detect(int);
+const char *ultrastor_14f_info(void);
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+ void *buff, int bufflen,
+ void (*done)(int, int));
+#ifdef NO_QUEUEING
+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);
+
+#ifndef NO_QUEUEING
+#define ULTRASTOR_14F \
+ { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, 0, \
+ ultrastor_14f_queuecommand, ultrastor_14f_abort, ultrastor_14f_reset, \
+ 1, 0, 0 }
+ /* ??? What should can_queue be set to? Currently 1... */
+#else
+#define ULTRASTOR_14F \
+ { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \
+ ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \
+ 0, 0, 0 }
+#endif
+
+#define UD_ABORT 0x0001
+#define UD_COMMAND 0x0002
+#define UD_DETECT 0x0004
+#define UD_INTERRUPT 0x0008
+#define UD_RESET 0x0010
+
+#ifdef ULTRASTOR_PRIVATE
+
+/* #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
+
+#endif
# parent makes..
#
-AR =ar
-AS =as
-LD =ld
-LDFLAGS =-s -x
-CC =gcc -nostdinc -I../../include
-CPP =cpp -nostdinc -I../../include
-
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
-OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \
- tty_ioctl.o pty.o lp.o vt.o mem.o
+OBJS = tty_io.o console.o keyboard.o serial.o \
+ tty_ioctl.o pty.o lp.o vt.o mem.o mouse.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
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
+ for i in *.c;do $(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 ../../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/linux/string.h ../../include/errno.h \
- ../../include/sys/kd.h vt_kern.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/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/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/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/asm/system.h \
- ../../include/asm/io.h
-serial.s serial.o : serial.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/asm/system.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/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
-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/termios.h \
- vt_kern.h
+console.o : console.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
+ /usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.h \
+ /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/io.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/sys/kd.h vt_kern.h
+keyboard.o : keyboard.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/ctype.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/ptrace.h /usr/src/linux/include/asm/io.h
+lp.o : lp.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/lp.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/io.h \
+ /usr/src/linux/include/asm/segment.h
+mem.o : mem.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/mouse.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/io.h
+mouse.o : mouse.c /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/mouse.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/io.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/irq.h
+pty.o : pty.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/asm/io.h
+serial.o : serial.c /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h
+tty_io.o : tty_io.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h \
+ /usr/src/linux/include/linux/resource.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/ctype.h /usr/src/linux/include/asm/io.h \
+ /usr/src/linux/include/asm/segment.h /usr/src/linux/include/sys/kd.h vt_kern.h
+tty_ioctl.o : tty_ioctl.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/termios.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h
+vt.o : vt.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/linux/timer.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/asm/segment.h \
+ vt_kern.h /usr/src/linux/include/sys/kd.h /usr/src/linux/include/sys/vt.h
/*
* linux/kernel/console.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* console.c
*
* This module implements the console io functions
- * 'void con_init(void)'
+ * 'long con_init(long)'
* 'void con_write(struct tty_queue * queue)'
* Hopefully this will be a rather complete VT102 implementation.
*
* <g-hunt@ee.utah.edu>
*/
+#define KEYBOARD_IRQ 1
+
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <linux/string.h>
-#include <errno.h>
-
#include <sys/kd.h>
#include "vt_kern.h"
-#define DEF_TERMIOS \
-(struct termios) { \
- ICRNL, \
- OPOST | ONLCR, \
- 0, \
- IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, \
- 0, \
- INIT_C_CC \
-}
-
-static void blank_screen(void);
-static void unblank_screen(void);
-
-/*
- * These are set up by the setup-routine at boot-time:
- */
-
-#define ORIG_X (*(unsigned char *)0x90000)
-#define ORIG_Y (*(unsigned char *)0x90001)
-#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)
-#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)
-#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)
-#define ORIG_VIDEO_LINES ((*(unsigned short *)0x9000e) & 0xff)
-#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)
-#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)
-#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)
-
-#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
-#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
-#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
-#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
-
#define NPAR 16
-int NR_CONSOLES = 0;
-
extern void vt_init(void);
-extern void keyboard_interrupt(void);
+extern void keyboard_interrupt(int pt_regs);
extern void set_leds(void);
extern unsigned char kapplic;
+extern unsigned char ckmode;
+extern unsigned char krepeat;
extern unsigned char kleds;
extern unsigned char kmode;
extern unsigned char kraw;
extern unsigned char ke0;
+extern unsigned char lfnlmode;
unsigned long video_num_columns; /* Number of text columns */
unsigned long video_num_lines; /* Number of test lines */
static unsigned char video_page; /* Initial video page */
static unsigned short video_port_reg; /* Video register select port */
static unsigned short video_port_val; /* Video register value port */
-static int can_do_colour = 0;
+static int can_do_color = 0;
static struct {
- unsigned short vc_video_erase_char;
- unsigned char vc_attr;
- unsigned char vc_def_attr;
- int vc_bold_attr;
- unsigned long vc_ques;
- unsigned long vc_state;
- char * vc_restate;
- unsigned long vc_checkin;
+ unsigned short vc_video_erase_char; /* Background erase character */
+ unsigned char vc_attr; /* Current attributes */
+ unsigned char vc_def_color; /* Default colors */
+ unsigned char vc_color; /* Foreground & background */
+ unsigned char vc_s_color; /* Saved foreground & background */
+ unsigned char vc_ulcolor; /* Colour for underline mode */
+ unsigned char vc_halfcolor; /* Colour for half intensity mode */
unsigned long vc_origin; /* Used for EGA/VGA fast scroll */
unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */
unsigned long vc_pos;
unsigned long vc_x,vc_y;
unsigned long vc_top,vc_bottom;
+ unsigned long vc_state;
unsigned long vc_npar,vc_par[NPAR];
unsigned long vc_video_mem_start; /* Start of video RAM */
unsigned long vc_video_mem_end; /* End of video RAM (sort of) */
- unsigned int vc_saved_x;
- unsigned int vc_saved_y;
- unsigned int vc_iscolor;
- unsigned char vc_kbdapplic;
- unsigned char vc_kbdleds;
+ unsigned long vc_saved_x;
+ unsigned long vc_saved_y;
+ /* mode flags */
+ unsigned long vc_kbdapplic : 1; /* Application keyboard */
+ unsigned long vc_charset : 1; /* Character set G0 / G1 */
+ unsigned long vc_s_charset : 1; /* Saved character set */
+ unsigned long vc_decckm : 1; /* Cursor Keys Mode */
+ unsigned long vc_decscnm : 1; /* Screen Mode */
+ unsigned long vc_decom : 1; /* Origin Mode */
+ unsigned long vc_decawm : 1; /* Autowrap Mode */
+ unsigned long vc_decarm : 1; /* Autorepeat Mode */
+ unsigned long vc_deccm : 1; /* Cursor Visible */
+ unsigned long vc_decim : 1; /* Insert Mode */
+ unsigned long vc_lnm : 1; /* Line feed New line Mode */
+ /* attribute flags */
+ unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
+ unsigned long vc_underline : 1;
+ unsigned long vc_blink : 1;
+ unsigned long vc_reverse : 1;
+ unsigned long vc_s_intensity : 2; /* saved rendition */
+ unsigned long vc_s_underline : 1;
+ unsigned long vc_s_blink : 1;
+ unsigned long vc_s_reverse : 1;
+ /* misc */
+ unsigned long vc_ques : 1;
+ unsigned long vc_need_wrap : 1;
+ unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
unsigned char vc_kbdmode;
- unsigned char vc_kbdraw;
- unsigned char vc_kbde0;
char * vc_translate;
-} vc_cons [MAX_CONSOLES];
+ char * vc_G0_charset;
+ char * vc_G1_charset;
+ char * vc_saved_G0;
+ char * vc_saved_G1;
+ /* additional information is in vt_kern.h */
+} vc_cons [NR_CONSOLES];
#define MEM_BUFFER_SIZE (2*80*50*8)
-unsigned short *vc_scrbuf[MAX_CONSOLES];
-unsigned short vc_scrmembuf[MEM_BUFFER_SIZE/2];
+unsigned short *vc_scrbuf[NR_CONSOLES];
+static unsigned short * vc_scrmembuf;
static int console_blanked = 0;
#define origin (vc_cons[currcons].vc_origin)
#define x (vc_cons[currcons].vc_x)
#define y (vc_cons[currcons].vc_y)
#define state (vc_cons[currcons].vc_state)
-#define restate (vc_cons[currcons].vc_restate)
-#define checkin (vc_cons[currcons].vc_checkin)
#define npar (vc_cons[currcons].vc_npar)
#define par (vc_cons[currcons].vc_par)
#define ques (vc_cons[currcons].vc_ques)
#define saved_x (vc_cons[currcons].vc_saved_x)
#define saved_y (vc_cons[currcons].vc_saved_y)
#define translate (vc_cons[currcons].vc_translate)
+#define G0_charset (vc_cons[currcons].vc_G0_charset)
+#define G1_charset (vc_cons[currcons].vc_G1_charset)
+#define saved_G0 (vc_cons[currcons].vc_saved_G0)
+#define saved_G1 (vc_cons[currcons].vc_saved_G1)
#define video_mem_start (vc_cons[currcons].vc_video_mem_start)
#define video_mem_end (vc_cons[currcons].vc_video_mem_end)
-#define def_attr (vc_cons[currcons].vc_def_attr)
-#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
-#define iscolor (vc_cons[currcons].vc_iscolor)
+#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
+#define decckm (vc_cons[currcons].vc_decckm)
+#define decscnm (vc_cons[currcons].vc_decscnm)
+#define decom (vc_cons[currcons].vc_decom)
+#define decawm (vc_cons[currcons].vc_decawm)
+#define decarm (vc_cons[currcons].vc_decarm)
+#define deccm (vc_cons[currcons].vc_deccm)
+#define decim (vc_cons[currcons].vc_decim)
+#define lnm (vc_cons[currcons].vc_lnm)
#define kbdapplic (vc_cons[currcons].vc_kbdapplic)
+#define need_wrap (vc_cons[currcons].vc_need_wrap)
+#define color (vc_cons[currcons].vc_color)
+#define s_color (vc_cons[currcons].vc_s_color)
+#define def_color (vc_cons[currcons].vc_def_color)
+#define foreground (color & 0x0f)
+#define background (color & 0xf0)
+#define charset (vc_cons[currcons].vc_charset)
+#define s_charset (vc_cons[currcons].vc_s_charset)
+#define intensity (vc_cons[currcons].vc_intensity)
+#define underline (vc_cons[currcons].vc_underline)
+#define blink (vc_cons[currcons].vc_blink)
+#define reverse (vc_cons[currcons].vc_reverse)
+#define s_intensity (vc_cons[currcons].vc_s_intensity)
+#define s_underline (vc_cons[currcons].vc_s_underline)
+#define s_blink (vc_cons[currcons].vc_s_blink)
+#define s_reverse (vc_cons[currcons].vc_s_reverse)
+#define ulcolor (vc_cons[currcons].vc_ulcolor)
+#define halfcolor (vc_cons[currcons].vc_halfcolor)
#define kbdmode (vc_cons[currcons].vc_kbdmode)
-#define kbdraw (vc_cons[currcons].vc_kbdraw)
-#define kbde0 (vc_cons[currcons].vc_kbde0)
-#define kbdleds (vc_cons[currcons].vc_kbdleds)
+#define tab_stop (vc_cons[currcons].vc_tab_stop)
+#define kbdraw (vt_cons[currcons].vc_kbdraw)
+#define kbdleds (vt_cons[currcons].vc_kbdleds)
+#define vtmode (vt_cons[currcons].vt_mode)
-int blankinterval = 5*60*HZ;
+#define SET(mode,fg,v) \
+ (mode) = (v); \
+ if (currcons == fg_console) \
+ (fg) = (v)
+
+int blankinterval = 10*60*HZ;
static int screen_size = 0;
static void sysbeep(void);
/*
- * this is what the terminal answers to a ESC-Z or csi0c
- * query (= vt100 response).
+ * this is what the terminal answers to a ESC-Z or csi0c query.
*/
-#define RESPONSE "\033[?1;2c"
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
static char * translations[] = {
/* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
- "\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304"
- "\304\304\304\304\307\266\320\322\272\363\362\343\007\234\007\0"
+ "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007"
+ "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
- "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230"
+ "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
+/* IBM grapgics: minimal translations (CR, LF, LL and ESC) */
+ "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
+ "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
+ "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
+ "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
+ "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
+ "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
+ "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
+ "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
};
#define NORM_TRANS (translations[0])
#define GRAF_TRANS (translations[1])
+#define NULL_TRANS (translations[2])
-/* NOTE! gotoxy thinks x==video_num_columns is ok */
-static inline void gotoxy(int currcons, unsigned int new_x,unsigned int new_y)
+static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+ 8,12,10,14, 9,13,11,15 };
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(int currcons, int new_x, int new_y)
{
- if (new_x > video_num_columns || new_y >= video_num_lines)
- return;
- x = new_x;
- y = new_y;
+ int max_y;
+
+ if (new_x < 0)
+ x = 0;
+ else
+ if (new_x >= video_num_columns)
+ x = video_num_columns - 1;
+ else
+ x = new_x;
+ if (decom) {
+ new_y += top;
+ max_y = bottom;
+ } else
+ max_y = video_num_lines;
+ if (new_y < 0)
+ y = 0;
+ else
+ if (new_y >= max_y)
+ y = max_y - 1;
+ else
+ y = new_y;
pos = origin + y*video_size_row + (x<<1);
+ need_wrap = 0;
}
-static inline void set_origin(int currcons)
+static void set_origin(int currcons)
{
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
return;
- if (currcons != fg_console)
+ if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS)
return;
cli();
outb_p(12, video_port_reg);
return;
} else
scrup(currcons,top,bottom);
+ need_wrap = 0;
}
static void ri(int currcons)
return;
} else
scrdown(currcons,top,bottom);
+ need_wrap = 0;
}
-static void cr(int currcons)
+static inline void cr(int currcons)
{
pos -= x<<1;
- x=0;
+ need_wrap = x = 0;
}
-static void del(int currcons)
+static inline void bs(int currcons)
+{
+ if (x) {
+ pos -= 2;
+ x--;
+ need_wrap = 0;
+ }
+}
+
+static inline void del(int currcons)
{
if (x) {
pos -= 2;
x--;
*(unsigned short *)pos = video_erase_char;
+ need_wrap = 0;
}
}
start = pos;
break;
case 1: /* erase from start to cursor */
- count = (pos-origin)>>1;
+ count = ((pos-origin)>>1)+1;
start = origin;
break;
case 2: /* erase whole display */
::"c" (count),
"D" (start),"a" (video_erase_char)
:"cx","di");
+ need_wrap = 0;
}
static void csi_K(int currcons, int vpar)
switch (vpar) {
case 0: /* erase from cursor to end of line */
- if (x>=video_num_columns)
- return;
count = video_num_columns-x;
start = pos;
break;
case 1: /* erase from start of line to cursor */
start = pos - (x<<1);
- count = (x<video_num_columns)?x:video_num_columns;
+ count = x+1;
break;
case 2: /* erase whole line */
start = pos - (x<<1);
::"c" (count),
"D" (start),"a" (video_erase_char)
:"cx","di");
+ need_wrap = 0;
+}
+
+/*
+ * I hope this works. The monochrome part is untested.
+ */
+static void update_attr(int currcons)
+{
+ attr = color;
+ if (can_do_color) {
+ if (underline)
+ attr = (attr & 0xf0) | ulcolor;
+ else if (intensity == 0)
+ attr = (attr & 0xf0) | halfcolor;
+ }
+ if (reverse ^ decscnm)
+ attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77);
+ if (blink)
+ attr ^= 0x80;
+ if (intensity == 2)
+ attr ^= 0x08;
+ if (!can_do_color) {
+ if (underline)
+ attr = (attr & 0xf8) | 0x01;
+ else if (intensity == 0)
+ attr = (attr & 0xf0) | 0x08;
+ }
+ if (decscnm)
+ video_erase_char = ((color & 0x88) | (((color >> 4) |
+ (color << 4)) & 0x77) << 8) | ' ';
+ else
+ video_erase_char = (color << 8) | ' ';
+}
+
+static void default_attr(int currcons) {
+ intensity = 1;
+ underline = 0;
+ reverse = 0;
+ blink = 0;
+ color = def_color;
}
-static void csi_m(int currcons )
+static void csi_m(int currcons)
{
int i;
- static int conv_table[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
for (i=0;i<=npar;i++)
switch (par[i]) {
- case 0: attr=def_attr;break; /* default */
- case 1: attr=(iscolor?attr|0x08:attr|0x0f);break; /* bold */
- /*case 4: attr=attr|0x01;break;*/ /* underline */
- case 4: /* bold */
- if (!iscolor)
- attr |= 0x01;
- else
- { /* check if forground == background */
- if (vc_cons[currcons].vc_bold_attr != -1)
- attr = (vc_cons[currcons].vc_bold_attr&0x0f)|(0xf0&(attr));
- else
- { short newattr = (attr&0xf0)|(0xf&(~attr));
- attr = ((newattr&0xf)==((attr>>4)&0xf)?
- (attr&0xf0)|(((attr&0xf)+1)%0xf):
- newattr);
- }
- }
- break;
- case 5: attr=attr|0x80;break; /* blinking */
- case 7: attr=(attr&0x88)|((attr<<4)&0x70)|
- ((attr>>4)&0x07);break; /* negative */
- case 22: attr=attr&0xf7;break; /* not bold */
- case 24: attr=attr&0xfe;break; /* not underline */
- case 25: attr=attr&0x7f;break; /* not blinking */
- case 27: attr=def_attr;break; /* positive image */
- case 39: attr=(attr & 0xf8)|(def_attr & 0x07); break;
- case 49: attr=(attr & 0x8f)|(def_attr & 0x70); break;
+ case 0: /* all attributes off */
+ default_attr(currcons);
+ break;
+ case 1:
+ intensity = 2;
+ break;
+ case 2:
+ intensity = 0;
+ break;
+ case 4:
+ underline = 1;
+ break;
+ case 5:
+ blink = 1;
+ break;
+ case 7:
+ reverse = 1;
+ break;
+ case 21:
+ case 22:
+ intensity = 1;
+ break;
+ case 24:
+ underline = 0;
+ break;
+ case 25:
+ blink = 0;
+ break;
+ case 27:
+ reverse = 0;
+ break;
+ case 39:
+ color = (def_color & 0x0f) | background;
+ break;
+ case 49:
+ color = (def_color & 0xf0) | foreground;
+ break;
default:
- if (!can_do_colour)
- break;
- iscolor = 1;
- if ((par[i]>=30) && (par[i]<=37))
- attr = (attr & 0xf8) | conv_table[par[i]-30];
- else /* Background color */
- if ((par[i]>=40) && (par[i]<=47))
- attr = (attr & 0x8f) | (conv_table[par[i]-40]<<4);
- else
+ if (par[i] >= 30 && par[i] <= 37)
+ color = color_table[par[i]-30]
+ | background;
+ else if (par[i] >= 40 && par[i] <= 47)
+ color = (color_table[par[i]-40]<<4)
+ | foreground;
break;
}
-}
-
-static inline void set_cursor(int currcons)
-{
- if (currcons != fg_console)
- return;
- cli();
- outb_p(14, video_port_reg);
- outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
- outb_p(15, video_port_reg);
- outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
- sti();
+ update_attr(currcons);
}
static inline void hide_cursor(int currcons)
outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
}
-static void respond(int currcons, struct tty_struct * tty)
+static inline void set_cursor(int currcons)
{
- char * p = RESPONSE;
-
+ if (currcons != fg_console || console_blanked)
+ return;
cli();
+ if (deccm) {
+ outb_p(14, video_port_reg);
+ outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
+ outb_p(15, video_port_reg);
+ outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
+ } else
+ hide_cursor(currcons);
+ sti();
+}
+
+static void respond_string(char * p, int currcons, struct tty_struct * tty)
+{
while (*p) {
- PUTCH(*p,tty->read_q);
+ put_tty_queue(*p,tty->read_q);
p++;
}
- sti();
TTY_READ_FLUSH(tty);
}
+static void respond_num(unsigned int n, int currcons, struct tty_struct * tty)
+{
+ char buff[3];
+ int i = 0;
+
+ do {
+ buff[i++] = (n%10)+'0';
+ n /= 10;
+ } while(n && i < 3); /* We'll take no chances */
+ while (i--) {
+ put_tty_queue(buff[i],tty->read_q);
+ }
+ /* caller must flush */
+}
+
+static void cursor_report(int currcons, struct tty_struct * tty)
+{
+ put_tty_queue('\033', tty->read_q);
+ put_tty_queue('[', tty->read_q);
+ respond_num(y + (decom ? top+1 : 1), currcons, tty);
+ put_tty_queue(';', tty->read_q);
+ respond_num(x+1, currcons, tty);
+ put_tty_queue('R', tty->read_q);
+ TTY_READ_FLUSH(tty);
+}
+
+static inline void status_report(int currcons, struct tty_struct * tty)
+{
+ respond_string("\033[0n", currcons, tty); /* Terminal ok */
+}
+
+static inline void respond_ID(int currcons, struct tty_struct * tty)
+{
+ respond_string(VT102ID, currcons, tty);
+}
+
+static void invert_screen(int currcons) {
+ unsigned char *p;
+
+ if (can_do_color)
+ for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
+ *p = (*p & 0x88) | (((*p >> 4) | (*p << 4)) & 0x77);
+ else
+ for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
+ *p ^= *p & 0x07 == 1 ? 0x70 : 0x77;
+}
+
+static void set_mode(int currcons, int on_off)
+{
+ int i;
+
+ for (i=0; i<=npar; i++)
+ if (ques) switch(par[i]) { /* DEC private modes set/reset */
+ case 1: /* Cursor keys send ^[Ox/^[[x */
+ SET(decckm,ckmode,on_off);
+ break;
+ case 3: /* 80/132 mode switch unimplemented */
+ csi_J(currcons,2);
+ gotoxy(currcons,0,0);
+ break;
+ case 5: /* Inverted screen on/off */
+ if (decscnm != on_off) {
+ decscnm = on_off;
+ invert_screen(currcons);
+ update_attr(currcons);
+ }
+ break;
+ case 6: /* Origin relative/absolute */
+ decom = on_off;
+ gotoxy(currcons,0,0);
+ break;
+ case 7: /* Autowrap on/off */
+ decawm = on_off;
+ break;
+ case 8: /* Autorepeat on/off */
+ SET(decarm,krepeat,on_off);
+ break;
+ case 25: /* Cursor on/off */
+ deccm = on_off;
+ set_cursor(currcons);
+ break;
+ } else switch(par[i]) { /* ANSI modes set/reset */
+ case 4: /* Insert Mode on/off */
+ decim = on_off;
+ break;
+ case 20: /* Lf, Enter == CrLf/Lf */
+ SET(lnm,lfnlmode,on_off);
+ break;
+ }
+}
+
+static void setterm_command(int currcons)
+{
+ switch(par[0]) {
+ case 1: /* set color for underline mode */
+ if (can_do_color && par[1] < 16) {
+ ulcolor = color_table[par[1]];
+ if (underline)
+ update_attr(currcons);
+ }
+ break;
+ case 2: /* set color for half intensity mode */
+ if (can_do_color && par[1] < 16) {
+ halfcolor = color_table[par[1]];
+ if (intensity == 0)
+ update_attr(currcons);
+ }
+ break;
+ case 8: /* store colors as defaults */
+ def_color = attr;
+ default_attr(currcons);
+ update_attr(currcons);
+ break;
+ case 9: /* set blanking interval */
+ blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+ break;
+ }
+}
+
static void insert_char(int currcons)
{
unsigned int i = x;
old = tmp;
p++;
}
+ need_wrap = 0;
}
static void insert_line(int currcons)
{
scrdown(currcons,y,bottom);
+ need_wrap = 0;
}
static void delete_char(int currcons)
unsigned int i = x;
unsigned short * p = (unsigned short *) pos;
- if (x >= video_num_columns)
- return;
while (++i < video_num_columns) {
*p = *(p+1);
p++;
}
*p = video_erase_char;
+ need_wrap = 0;
}
static void delete_line(int currcons)
{
scrup(currcons,y,bottom);
+ need_wrap = 0;
}
static void csi_at(int currcons, unsigned int nr)
static void save_cur(int currcons)
{
- saved_x = x;
- saved_y = y;
+ saved_x = x;
+ saved_y = y;
+ s_intensity = intensity;
+ s_underline = underline;
+ s_blink = blink;
+ s_reverse = reverse;
+ s_charset = charset;
+ s_color = color;
+ saved_G0 = G0_charset;
+ saved_G1 = G1_charset;
}
static void restore_cur(int currcons)
{
- gotoxy(currcons, saved_x, saved_y);
+ gotoxy(currcons,saved_x,saved_y);
+ intensity = s_intensity;
+ underline = s_underline;
+ blink = s_blink;
+ reverse = s_reverse;
+ charset = s_charset;
+ color = s_color;
+ G0_charset = saved_G0;
+ G1_charset = saved_G1;
+ translate = charset ? G1_charset : G0_charset;
+ update_attr(currcons);
+ need_wrap = 0;
}
-
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
- ESsetterm, ESsetgraph, ESgraph, ESgresc, ESignore };
+ EShash, ESsetG0, ESsetG1, ESignore };
+
+static void reset_terminal(int currcons, int do_clear)
+{
+ top = 0;
+ bottom = video_num_lines;
+ state = ESnormal;
+ ques = 0;
+ translate = NORM_TRANS;
+ G0_charset = NORM_TRANS;
+ G1_charset = GRAF_TRANS;
+ charset = 0;
+ need_wrap = 0;
+
+ decscnm = 0;
+ decom = 0;
+ decawm = 1;
+ deccm = 1;
+ decim = 0;
+
+ if (currcons == fg_console) {
+ krepeat = 1;
+ ckmode = 0;
+ kapplic = 0;
+ lfnlmode = 0;
+ kleds = 2;
+ kmode = 0;
+ set_leds();
+ } else {
+ decarm = 1;
+ decckm = 0;
+ kbdapplic = 0;
+ lnm = 0;
+ kbdleds = 2;
+ kbdmode = 0;
+ }
+
+ default_attr(currcons);
+ update_attr(currcons);
+
+ tab_stop[0] = 0x01010100;
+ tab_stop[1] =
+ tab_stop[2] =
+ tab_stop[3] =
+ tab_stop[4] = 0x01010101;
+
+ if (do_clear) {
+ gotoxy(currcons,0,0);
+ csi_J(currcons,2);
+ save_cur(currcons);
+ }
+}
void con_write(struct tty_struct * tty)
{
- unsigned char c;
+ int c;
unsigned int currcons;
wake_up(&tty->write_q->proc_list);
currcons = tty - tty_table;
- if (currcons >= MAX_CONSOLES) {
+ if (currcons >= NR_CONSOLES) {
printk("con_write: illegal tty\n\r");
return;
}
- while (!EMPTY(tty->write_q)) {
- if (tty->stopped)
- break;
- GETCH(tty->write_q,c);
- if (c == 24 || c == 26)
- state = ESnormal;
- switch(state) {
- case ESnormal:
- if (translate[c]) {
- c = translate[c];
- while (x >= video_num_columns) {
- x -= video_num_columns;
- pos -= video_size_row;
- lf(currcons);
- }
- *(char *) pos = c;
- *(char *) (pos+1) = attr;
- pos += 2;
+ while (!tty->stopped && (c = get_tty_queue(tty->write_q)) >= 0) {
+ if (state == ESnormal && translate[c]) {
+ if (need_wrap) {
+ cr(currcons);
+ lf(currcons);
+ }
+ if (decim)
+ insert_char(currcons);
+ c = translate[c];
+ *(char *) pos = c;
+ *(char *) (pos+1) = attr;
+ if (x == video_num_columns - 1)
+ need_wrap = decawm;
+ else {
+ x++;
+ pos+=2;
+ }
+ continue;
+ }
+
+ /*
+ * Control characters can be used in the _middle_
+ * of an escape sequence.
+ */
+ if (c < 32 || c == 127) switch(c) {
+ case 7:
+ sysbeep();
+ break;
+ case 8:
+ bs(currcons);
+ break;
+ case 9:
+ pos -= (x << 1);
+ while (x < video_num_columns - 1) {
x++;
- } else if (c == 27)
- state = ESesc;
- else if (c == 10 || c == 11 || c == 12)
- lf(currcons);
- else if (c == 13)
- cr(currcons);
- else if (c == 127)
- del(currcons);
- else if (c == 8) {
- if (x) {
- x--;
- pos -= 2;
- }
- } else if (c == 9) {
- c = 8-(x&7);
- x += c;
- pos += c<<1;
- if (x > video_num_columns) {
- x -= video_num_columns;
- pos -= video_size_row;
- lf(currcons);
- }
- c = 9;
- } else if (c == 7)
- sysbeep();
- else if (c == 14) {
- checkin = 1;
- translate = restate;
- } else if (c == 15) {
- translate = NORM_TRANS;
- checkin = 0;
- }
+ if (tab_stop[x >> 5] & (1 << (x & 31)))
+ break;
+ }
+ pos += (x << 1);
+ break;
+ case 10: case 11: case 12:
+ lf(currcons);
+ if (!lfnlmode)
+ break;
+ case 13:
+ cr(currcons);
break;
+ case 14:
+ charset = 1;
+ translate = G1_charset;
+ break;
+ case 15:
+ charset = 0;
+ translate = G0_charset;
+ break;
+ case 24: case 26:
+ state = ESnormal;
+ break;
+ case 27:
+ state = ESesc;
+ break;
+ case 127:
+ del(currcons);
+ break;
+ } else switch(state) {
case ESesc:
state = ESnormal;
switch (c) {
state = ESsquare;
break;
case 'E':
- gotoxy(currcons,0,y+1);
+ cr(currcons);
+ lf(currcons);
break;
case 'M':
ri(currcons);
case 'D':
lf(currcons);
break;
+ case 'H':
+ tab_stop[x >> 5] |= (1 << (x & 31));
+ break;
case 'Z':
- respond(currcons,tty);
+ respond_ID(currcons,tty);
break;
case '7':
save_cur(currcons);
restore_cur(currcons);
break;
case '(':
+ state = ESsetG0;
+ break;
case ')':
- state = ESsetgraph;
+ state = ESsetG1;
break;
- case 'P':
- state = ESsetterm;
- break;
case '#':
- state = -1;
- break;
+ state = EShash;
+ break;
case 'c':
- tty->termios = DEF_TERMIOS;
- state = ESnormal;
- restate = NORM_TRANS;
- checkin = 0;
- top = 0;
- bottom = video_num_lines;
- translate = NORM_TRANS;
+ reset_terminal(currcons,1);
+ break;
case '>': /* Numeric keypad */
- kbdapplic = 0;
- if (currcons == fg_console)
- kapplic = 0;
- break;
+ SET(kbdapplic,kapplic,0);
+ break;
case '=': /* Appl. keypad */
- kbdapplic = 1;
- if (currcons == fg_console)
- kapplic = 1;
+ SET(kbdapplic,kapplic,1);
break;
}
break;
if (c == '[') { /* Function key */
state=ESfunckey;
break;
- }
+ }
if (ques=(c=='?'))
break;
case ESgetpars:
} else state=ESgotpars;
case ESgotpars:
state = ESnormal;
+ switch(c) {
+ case 'h':
+ set_mode(currcons,1);
+ break;
+ case 'l':
+ set_mode(currcons,0);
+ break;
+ case 'n':
+ if (!ques)
+ if (par[0] == 5)
+ status_report(currcons,tty);
+ else if (par[0] == 6)
+ cursor_report(currcons,tty);
+ break;
+ }
if (ques) {
ques = 0;
break;
- }
+ }
switch(c) {
case 'G': case '`':
if (par[0]) par[0]--;
case 'P':
csi_P(currcons,par[0]);
break;
- case '@':
- csi_at(currcons,par[0]);
+ case 'c':
+ if (!par[0])
+ respond_ID(currcons,tty);
+ break;
+ case 'g':
+ if (!par[0])
+ tab_stop[x >> 5] &= ~(1 << (x & 31));
+ else if (par[0] == 3) {
+ tab_stop[0] =
+ tab_stop[1] =
+ tab_stop[2] =
+ tab_stop[3] =
+ tab_stop[4] = 0;
+ }
break;
case 'm':
csi_m(currcons);
break;
case 'r':
- if (par[0])
- par[0]--;
+ if (!par[0])
+ par[0]++;
if (!par[1])
par[1] = video_num_lines;
+ /* Minimum allowed region is 2 lines */
if (par[0] < par[1] &&
par[1] <= video_num_lines) {
- top=par[0];
+ top=par[0]-1;
bottom=par[1];
+ gotoxy(currcons,0,0);
}
break;
case 's':
case 'u':
restore_cur(currcons);
break;
- case 'l': /* blank interval */
- case 'b': /* bold attribute */
- if (!((npar >= 2) &&
- ((par[1]-13) == par[0]) &&
- ((par[2]-17) == par[0])))
- break;
- if ((c=='l') && (par[0]<=60)) {
- blankinterval = HZ*60*par[0];
- }
- if (c=='b')
- vc_cons[currcons].vc_bold_attr
- = par[0];
+ case '@':
+ csi_at(currcons,par[0]);
+ break;
+ case ']': /* setterm functions */
+ setterm_command(currcons);
+ break;
}
break;
case ESfunckey:
state = ESnormal;
break;
- case ESsetterm: /* Setterm functions. */
+ case EShash:
+ state = ESnormal;
+ if (c == '8') {
+ /* DEC screen alignment test. kludge :-) */
+ video_erase_char =
+ (video_erase_char & 0xff00) | 'E';
+ csi_J(currcons, 2);
+ video_erase_char =
+ (video_erase_char & 0xff00) | ' ';
+ }
+ break;
+ case ESsetG0:
+ if (c == '0')
+ G0_charset = GRAF_TRANS;
+ else if (c == 'B')
+ G0_charset = NORM_TRANS;
+ else if (c == 'U')
+ G0_charset = NULL_TRANS;
+ if (charset == 0)
+ translate = G0_charset;
state = ESnormal;
- if (c == 'S') {
- def_attr = attr;
- video_erase_char = (video_erase_char&0x0ff) | (def_attr<<8);
- } else if (c == 'L')
- /*linewrap on*/;
- else if (c == 'l')
- /*linewrap off*/;
break;
- case ESsetgraph:
- if (c == '0') {
- if (checkin)
- translate = GRAF_TRANS;
- restate = GRAF_TRANS;
- } else if (c == 'B')
- translate = restate = NORM_TRANS;
+ case ESsetG1:
+ if (c == '0')
+ G1_charset = GRAF_TRANS;
+ else if (c == 'B')
+ G1_charset = NORM_TRANS;
+ else if (c == 'U')
+ G1_charset = NULL_TRANS;
+ if (charset == 1)
+ translate = G1_charset;
state = ESnormal;
break;
default:
state = ESnormal;
}
}
+ if (vtmode == KD_GRAPHICS)
+ return;
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;
- }
}
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;
}
/*
- * void con_init(void);
+ * long con_init(long);
*
* This routine initalizes console interrupts, and does nothing
* else. If you want the screen to clear, call tty_write with
* Reads the information preserved by setup.s to determine the current display
* type and sets everything accordingly.
*/
-void con_init(void)
+long con_init(long kmem_start)
{
register unsigned char a;
char *display_desc = "????";
char *display_ptr;
int currcons = 0;
- long base, term;
- long video_memory;
- long saveterm, savebase;
+ long base;
+ int orig_x = ORIG_X;
+ int orig_y = ORIG_Y;
+ vc_scrmembuf = (unsigned short *) kmem_start;
video_num_columns = ORIG_VIDEO_COLS;
video_size_row = video_num_columns * 2;
video_num_lines = ORIG_VIDEO_LINES;
video_page = ORIG_VIDEO_PAGE;
- video_erase_char = 0x0720;
+ screen_size = (video_num_lines * video_size_row);
+ kmem_start += NR_CONSOLES * screen_size;
timer_table[BLANK_TIMER].fn = blank_screen;
timer_table[BLANK_TIMER].expires = 0;
if (blankinterval) {
}
else /* If not, it is color. */
{
- can_do_colour = 1;
+ can_do_color = 1;
video_mem_base = 0xb8000;
video_port_reg = 0x3d4;
video_port_val = 0x3d5;
}
}
- /* Let the user known what kind of display driver we are using */
+ /* Let the user know what kind of display driver we are using */
display_ptr = ((char *)video_mem_base) + video_size_row - 8;
while (*display_desc)
*display_ptr++ = *display_desc++;
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;
- screen_size = (video_num_lines * video_size_row);
- NR_CONSOLES = video_memory / 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;
- top = 0;
- bottom = video_num_lines;
- attr = 0x07;
- def_attr = 0x07;
- restate = NORM_TRANS;
- state = ESnormal;
- checkin = 0;
- ques = 0;
- iscolor = 0;
- translate = NORM_TRANS;
- kbdleds = 2;
- kbdmode = 0;
- kbdraw = 0;
- kbde0 = 0;
- kbdapplic = 0;
- 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);
- gotoxy(currcons,0,0);
+
+ base = (long)vc_scrmembuf;
+ for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
+ pos = origin = video_mem_start = base;
+ scr_end = video_mem_end = (base += screen_size);
+ vc_scrbuf[currcons] = (unsigned short *) origin;
+ vtmode = KD_TEXT;
+ kbdraw = 0;
+ def_color = 0x07; /* white */
+ ulcolor = 0x0f; /* bold white */
+ halfcolor = 0x08; /* grey */
+ reset_terminal(currcons, currcons);
}
- for (currcons = 0; currcons<NR_CONSOLES; currcons++)
- vc_scrbuf[currcons] = (unsigned short *)origin;
- currcons = 0;
- video_mem_base = savebase;
- video_mem_term = saveterm;
-
+ currcons = fg_console = 0;
+
video_mem_start = video_mem_base;
video_mem_end = video_mem_term;
- origin = video_mem_start;
+ origin = video_mem_start;
scr_end = video_mem_start + video_num_lines * video_size_row;
- top = 0;
- bottom = video_num_lines;
- pos=origin + y*video_size_row + (x<<1);
+ gotoxy(currcons,0,0);
+ save_cur(currcons);
+ gotoxy(currcons,orig_x,orig_y);
update_screen(fg_console);
- set_trap_gate(0x21,&keyboard_interrupt);
- outb_p(inb_p(0x21)&0xfd,0x21);
+
+ if (request_irq(KEYBOARD_IRQ,keyboard_interrupt))
+ printk("Unable to get IRQ%d for keyboard driver\n",KEYBOARD_IRQ);
a=inb_p(0x61);
outb_p(a|0x80,0x61);
outb_p(a,0x61);
-
- vt_init();
+ return kmem_start;
}
void kbdsave(int new_console)
int currcons = fg_console;
kbdmode = kmode;
kbdraw = kraw;
- kbde0 = ke0;
kbdleds = kleds;
kbdapplic = kapplic;
+ decckm = ckmode;
+ decarm = krepeat;
+ lnm = lfnlmode;
currcons = new_console;
kmode = (kmode & 0x3F) | (kbdmode & 0xC0);
kraw = kbdraw;
- ke0 = kbde0;
kleds = kbdleds;
kapplic = kbdapplic;
+ ckmode = decckm;
+ krepeat = decarm;
+ lfnlmode = lnm;
set_leds();
}
{
memcpy((void *)vc_scrbuf[fg_console],(void *)origin, screen_size);
video_mem_start = (unsigned long)vc_scrbuf[fg_console];
- origin = video_mem_start;
+ origin = video_mem_start;
scr_end = video_mem_end = video_mem_start+screen_size;
- pos = origin + y*video_size_row + (x<<1);
+ pos = origin + y*video_size_row + (x<<1);
}
static void set_scrmem(int currcons)
verify_area(buf,2+video_num_columns*video_num_lines);
currcons = get_fs_byte(buf+1);
- if ((currcons<0) || (currcons>NR_CONSOLES))
+ if ((currcons<0) || (currcons>=NR_CONSOLES))
return -EIO;
put_fs_byte((char)(video_num_lines),buf++);
put_fs_byte((char)(video_num_columns),buf++);
if (currcons<0 || currcons>=NR_CONSOLES)
currcons = 0;
- if (vt_info[currcons].mode == KD_GRAPHICS)
- return; /* no output in graphics mode */
while (c = *(b++)) {
- if (c == 10) {
- cr(currcons);
- lf(currcons);
- continue;
- }
- if (c == 13) {
+ if (c == 10 || c == 13 || need_wrap) {
+ if (c != 13)
+ lf(currcons);
cr(currcons);
- continue;
- }
- while (x >= video_num_columns) {
- x -= video_num_columns;
- pos -= video_size_row;
- lf(currcons);
+ if (c == 10 || c == 13)
+ continue;
}
*(char *) pos = c;
*(char *) (pos+1) = attr;
- pos += 2;
+ if (x == video_num_columns - 1) {
+ need_wrap = 1;
+ continue;
+ }
x++;
+ pos+=2;
}
set_cursor(currcons);
+ if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ return;
+ 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;
+ }
}
+++ /dev/null
-/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * NOTE! This file no longer contains the low-level keyboard interrupt:
- * that is now in kernel/sys_call.S. The reason is that the low-level
- * interrupt must keep track of stack frames for signals etc.
- *
- * Thus it should be very easy to rewrite this in C - I just haven't
- * bothered.
- */
-
-/*
- * 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 _do_keyboard_interrupt
-.globl _do_keyboard
-.globl _kapplic
-.globl _kmode
-.globl _kleds
-.globl _set_leds
-.globl _kraw
-.globl _ke0
-
-/*
- * 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) */
-_ke0: .byte 0
-_kraw: .byte 0
-
-/*
- * do_keyboard is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_do_keyboard:
- 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
- cmpb $0,_kraw
- je 1f
- xorl %ebx,%ebx /* if raw kbd, just put scancode */
- popl %eax
- sti
- call put_queue
- jmp postkey
-1: 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)
-postkey:
- call _do_keyboard_interrupt
- movl $0,%ebx
-end_intr:
- movb %bl,_ke0
- ret
-
-/*
- * 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,_ke0
- je 2f
- addb %al,%al
-2: orb %al,_kmode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,_ke0
- 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,_ke0 /* _ke0 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@\243$\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 "!\"\243$%^&*()_+"
- .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,_ke0
- 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,_ke0
- 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
--- /dev/null
+/*
+ * 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 <linux/mm.h>
+#include <linux/ptrace.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 ckmode = 0;
+unsigned char krepeat = 1;
+unsigned char kmode = 0;
+unsigned char kleds = NUMLED;
+unsigned char ke0 = 0;
+unsigned char kraw = 0;
+unsigned char kbd_flags = KBDFLAGS;
+unsigned char lfnlmode = 0;
+
+extern void do_keyboard_interrupt(void);
+extern void ctrl_alt_del(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);
+
+static struct pt_regs * pt_regs;
+
+void keyboard_interrupt(int int_pt_regs)
+{
+ static unsigned char rep = 0xff, repke0 = 0;
+ unsigned char scancode, x;
+ struct tty_struct * tty = TTY_TABLE(0);
+
+ pt_regs = (struct pt_regs *) int_pt_regs;
+ 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();
+ return;
+ }
+ if (scancode == 0xe0) {
+ ke0 = 1;
+ return;
+ }
+ if (scancode == 0xe1) {
+ ke0 = 2;
+ return;
+ }
+ /*
+ * The keyboard maintains its own internal caps lock and num lock
+ * statuses. In caps lock mode E0 AA precedes make code and E0 2A
+ * follows break code. In num lock mode, E0 2A precedes make
+ * code and E0 AA follows break code. We do our own book-keeping,
+ * so we will just ignore these.
+ */
+ if (ke0 == 1 && (scancode == 0x2a || scancode == 0xaa)) {
+ ke0 = 0;
+ return;
+ }
+ /*
+ * Repeat a key only if the input buffers are empty or the
+ * characters get echoed locally. This makes key repeat usable
+ * with slow applications and unders heavy loads.
+ */
+ if (rep == 0xff) {
+ if (scancode < 0x80) {
+ rep = scancode;
+ repke0 = ke0;
+ }
+ } else if (ke0 == repke0 && (scancode & 0x7f) == rep)
+ if (scancode & 0x80)
+ rep = 0xff;
+ else if (!(krepeat && (L_ECHO(tty) || (EMPTY(tty->secondary) &&
+ EMPTY(tty->read_q))))) {
+ ke0 = 0;
+ return;
+ }
+ 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;
+ wake_up(&qp->proc_list);
+}
+
+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;
+ }
+ wake_up(&qp->proc_list);
+}
+
+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 show_ptregs(void)
+{
+ printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
+ if (pt_regs->cs & 3)
+ printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
+ printk(" EFLAGS: %08x",pt_regs->eflags);
+ printk("\nEAX: %08x EBX: %08x ECX: %08x EDX: %08x",
+ pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
+ printk("\nESI: %08x EDI: %08x EBP: %08x",
+ pt_regs->esi, pt_regs->edi, pt_regs->ebp);
+ printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
+ 0xffff & pt_regs->ds,0xffff & pt_regs->es,
+ 0xffff & pt_regs->fs,0xffff & pt_regs->gs);
+}
+
+static void scroll(int sc)
+{
+ if (kmode & (LSHIFT | RSHIFT))
+ show_mem();
+ else if (kmode & (ALT | ALTGR))
+ show_ptregs();
+ else if (kmode & (LCTRL | RCTRL))
+ 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 };
+
+#elif defined KBD_SG
+
+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', 0, 0, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0,
+ 0, 0, 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, '+', '"', '*', 0, '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I',
+ 'O', 'P', 0, '!', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 0,
+ 0, 0, 0, 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, 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 };
+
+#elif defined KBD_SG_LATIN1
+
+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', 252, 0, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246,
+ 228, 167, 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, '+', '"', '*', 231, '%', '&',
+ '/', '(', ')', '=', '?', '`', 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, 163, '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, 172,
+ '|', 162, 0, 0, '\'', '~', 0, 0,
+ '@', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '[', ']', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 233,
+ '{', 0, 0, '}', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 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_NO
+
+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, 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,
+ 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 || defined KBD_US || defined KBD_UK
+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 ((buf[2] >= 'A' && buf[2] <= 'D') ? ckmode : 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 && kapplic)
+ applkey('M');
+ else {
+ put_queue(13);
+ if (lfnlmode)
+ put_queue(10);
+ }
+}
+
+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(0x60) == 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 ? ? ? ? */
+};
*/
#include <linux/sched.h>
-#define __LP_C__
#include <linux/lp.h>
static int lp_reset(int minor)
unsigned int minor = MINOR(inode->i_rdev);
char c, *temp = buf;
- if (minor >= LP_NO)
- return -ENODEV;
- if ((LP_F(minor) & LP_EXIST) == 0)
- return -ENODEV;
- LP_T(minor) = current->pid;
- LP_F(minor) |= LP_BUSY;
- LP_R(minor) = count;
temp = buf;
while (count > 0) {
c = get_fs_byte(temp++);
return -EINVAL;
}
-static int lp_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
+static int lp_open(struct inode * inode, struct file * file)
{
- return -ENOTDIR;
+ 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,
- lp_readdir,
- NULL, /* lp_close */
+ NULL, /* lp_readdir */
NULL, /* lp_select */
- NULL /* lp_ioctl */
+ NULL, /* lp_ioctl */
+ lp_open,
+ lp_release
};
-void lp_init(void)
+long lp_init(long kmem_start)
{
int offset = 0;
unsigned int testvalue = 0;
}
if (count == 0)
printk("lp_init: no lp devices found\n");
+ return kmem_start;
}
/*
* linux/kernel/chr_drv/mem.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-#include <sys/types.h>
-
+#include <linux/types.h>
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/mouse.h>
#include <asm/segment.h>
#include <asm/io.h>
addr = file->f_pos;
tmp = buf;
while (count > 0) {
+ if (current->signal & ~current->blocked)
+ break;
pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
- if (!((pte = *((unsigned long *) pde)) & 1))
+ pte = *(unsigned long *) pde;
+ if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
- if (((page = *((unsigned long *) pte)) & 1) == 0)
+ page = *(unsigned long *) pte;
+ if (!(page & 1))
break;
-/*
- if ((page & 2) == 0)
- un_wp_page((unsigned long *) pte);
-*/
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
addr = file->f_pos;
tmp = buf;
while (count > 0) {
+ if (current->signal & ~current->blocked)
+ break;
pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
- if (!((pte = *((unsigned long *) pde)) & 1))
+ pte = *(unsigned long *) pde;
+ if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
- if (((page = *((unsigned long *) pte)) & 1) == 0)
+ page = *(unsigned long *) pte;
+ if (!(page & PAGE_PRESENT))
break;
- if ((page & 2) == 0)
- un_wp_page((unsigned long *) pte);
+ if (!(page & 2)) {
+ do_wp_page(0,addr,current,0);
+ continue;
+ }
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
count -= i;
}
file->f_pos = addr;
- return tmp-buf;
+ if (tmp != buf)
+ return tmp-buf;
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ return 0;
}
static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
if (count < 0)
return -EINVAL;
- if (p >= HIGH_MEMORY)
+ if (p >= high_memory)
return 0;
- if (count > HIGH_MEMORY - p)
- count = HIGH_MEMORY - p;
+ if (count > high_memory - p)
+ count = high_memory - p;
memcpy_tofs(buf,(void *) p,count);
file->f_pos += count;
return count;
if (count < 0)
return -EINVAL;
- if (p >= HIGH_MEMORY)
+ if (p >= high_memory)
return 0;
- if (count > HIGH_MEMORY - p)
- count = HIGH_MEMORY - p;
+ if (count > high_memory - p)
+ count = high_memory - p;
memcpy_fromfs((void *) p,buf,count);
file->f_pos += count;
return count;
return tmp-buf;
}
+static int read_zero(struct inode *node,struct file *file,char *buf,int count)
+{
+ int left;
+
+ for (left = count; left > 0; left--) {
+ put_fs_byte(0,buf);
+ buf++;
+ }
+ return count;
+}
+
/*
* 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,
return 0; /* /dev/null */
case 4:
return read_port(inode,file,buf,count);
+ case 5:
+ return read_zero(inode,file,buf,count);
default:
return -ENODEV;
}
return count; /* /dev/null */
case 4:
return write_port(inode,file,buf,count);
+ case 5:
+ return count; /* /dev/zero */
default:
return -ENODEV;
}
}
-static int mem_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
-{
- return -ENOTDIR;
-}
-
static struct file_operations mem_fops = {
mem_lseek,
mem_read,
mem_write,
- mem_readdir,
- NULL, /* mem_close */
+ NULL, /* mem_readdir */
NULL, /* mem_select */
- NULL /* mem_ioctl */
+ NULL, /* mem_ioctl */
+ NULL, /* no special open code */
+ NULL /* no special release code */
};
-void chr_dev_init(void)
+long chr_dev_init(long mem_start, long mem_end)
{
chrdev_fops[1] = &mem_fops;
- tty_init();
- lp_init();
+ mem_start = tty_init(mem_start);
+ mem_start = lp_init(mem_start);
+ mem_start = mouse_init(mem_start);
+ return mem_start;
}
--- /dev/null
+/*
+ * Logitech Bus Mouse Driver for Linux
+ * by James Banks
+ *
+ * Heavily modified by David Giller
+ * changed from queue- to counter- driven
+ * hacked out a (probably incorrect) mouse_select
+ *
+ * Modified again by Nathan Laredo to interface with
+ * 0.96c-pl1 IRQ handling changes (13JUL92)
+ * didn't bother touching select code.
+ *
+ * Modified the select() code blindly to conform to the VFS
+ * requirements. 92.07.14 - Linus. Somebody should test it out.
+ *
+ * version 0.1
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mouse.h>
+#include <linux/tty.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+static struct mouse_status mouse;
+
+static void mouse_interrupt(int unused)
+{
+ char dx, dy, buttons;
+
+ MSE_INT_OFF();
+
+ outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
+ dx = (inb(MSE_DATA_PORT) & 0xf);
+
+ outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
+ dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
+
+ outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
+ dy = (inb(MSE_DATA_PORT) & 0xf);
+
+ outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
+ buttons = inb(MSE_DATA_PORT);
+
+ dy |= (buttons & 0xf) << 4;
+ buttons = ((buttons >> 5) & 0x07);
+
+ mouse.buttons = buttons;
+ mouse.latch_buttons |= buttons;
+ mouse.dx += dx;
+ mouse.dy += dy;
+ mouse.ready = 1;
+ if (mouse.inode && mouse.inode->i_wait)
+ wake_up(&mouse.inode->i_wait);
+
+ MSE_INT_ON();
+}
+
+static void release_mouse(struct inode * inode, struct file * file)
+{
+ MSE_INT_OFF();
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.inode = NULL;
+ free_irq(MOUSE_IRQ);
+}
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+ if (mouse.active)
+ return -EBUSY;
+ if (!mouse.present)
+ return -EINVAL;
+ mouse.active = 1;
+ mouse.ready = 0;
+ mouse.inode = inode;
+ mouse.dx = 0;
+ mouse.dy = 0;
+ mouse.buttons = mouse.latch_buttons = 0x80;
+ MSE_INT_ON();
+ if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
+ MSE_INT_OFF();
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.inode = NULL;
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ return -EINVAL;
+}
+
+static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
+{
+ int i;
+
+ if (count < 3) return -EINVAL;
+ if (!mouse.ready) return -EAGAIN;
+
+ MSE_INT_OFF();
+
+ put_fs_byte(mouse.latch_buttons | 0x80, buffer);
+
+ if (mouse.dx < -127) mouse.dx = -127;
+ if (mouse.dx > 127) mouse.dx = 127;
+
+ put_fs_byte((char)mouse.dx, buffer + 1);
+
+ if (mouse.dy < -127) mouse.dy = -127;
+ if (mouse.dy > 127) mouse.dy = 127;
+
+ put_fs_byte((char) -mouse.dy, buffer + 2);
+
+ for (i = 3; i < count; i++)
+ put_fs_byte(0x00, buffer + i);
+
+ mouse.dx = 0;
+ mouse.dy = 0;
+ mouse.latch_buttons = mouse.buttons;
+ mouse.ready = 0;
+
+ MSE_INT_ON();
+ return i;
+}
+
+static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+{
+ if (sel_type != SEL_IN)
+ return 0;
+ if (mouse.ready)
+ return 1;
+ select_wait(&inode->i_wait,wait);
+ return 0;
+}
+
+static struct file_operations mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_select, /* mouse_select */
+ NULL, /* mouse_ioctl */
+ open_mouse,
+ release_mouse,
+};
+
+long mouse_init(long kmem_start)
+{
+ int i;
+
+ outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
+ outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
+
+ for (i = 0; i < 100000; i++); /* busy loop */
+ if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
+ printk("No bus mouse detected.\n");
+ mouse.present = 0;
+ return kmem_start;
+ }
+ chrdev_fops[10] = &mouse_fops;
+ outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
+
+ MSE_INT_OFF();
+
+ mouse.present = 1;
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.dx = 0;
+ mouse.dy = 0;
+ printk("Bus mouse detected and installed.\n");
+ return kmem_start;
+}
/*
* linux/kernel/chr_drv/pty.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* void spty_write(struct tty_struct * queue);
*/
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/io.h>
+int pty_open(unsigned int dev, struct file * filp)
+{
+ struct tty_struct * tty;
+
+ tty = tty_table + dev;
+ if (!tty->link)
+ return -ENODEV;
+ wake_up(&tty->read_q->proc_list);
+ if (filp->f_flags & O_NDELAY)
+ return 0;
+ while (!tty->link->count && !(current->signal & ~current->blocked))
+ interruptible_sleep_on(&tty->link->read_q->proc_list);
+ if (!tty->link->count)
+ return -ERESTARTSYS;
+ return 0;
+}
+
+void pty_close(unsigned int dev, struct file * filp)
+{
+ struct tty_struct * tty;
+
+ tty = tty_table + dev;
+ wake_up(&tty->read_q->proc_list);
+ wake_up(&tty->link->write_q->proc_list);
+ if (IS_A_PTY_MASTER(dev)) {
+ if (tty->link->pgrp > 0)
+ kill_pg(tty->link->pgrp,SIGHUP,1);
+ }
+}
+
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)) {
TTY_READ_FLUSH(to);
continue;
}
- GETCH(from->write_q,c);
- PUTCH(c,to->read_q);
+ c = get_tty_queue(from->write_q);
+ put_tty_queue(c,to->read_q);
if (current->signal & ~current->blocked)
break;
}
*/
void mpty_write(struct tty_struct * tty)
{
- int nr = tty - tty_table;
-
- if ((nr >> 6) != 2)
- printk("bad mpty\n\r");
- else
- pty_copy(tty,tty+64);
+ if (tty->link)
+ pty_copy(tty,tty->link);
}
void spty_write(struct tty_struct * tty)
{
- int nr = tty - tty_table;
-
- if ((nr >> 6) != 3)
- printk("bad spty\n\r");
- else
- pty_copy(tty,tty-64);
+ if (tty->link)
+ pty_copy(tty,tty->link);
}
+++ /dev/null
-/*
- * 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
/*
* linux/kernel/serial.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
*
* This module implements the rs232 io functions
* void rs_write(struct tty_struct * queue);
- * void rs_init(void);
+ * long rs_init(long);
* and all interrupts pertaining to serial IO.
*/
+#include <linux/errno.h>
+#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/segment.h>
-#define WAKEUP_CHARS (TTY_BUF_SIZE/4)
+#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
-extern void rs1_interrupt(void);
-extern void rs2_interrupt(void);
+struct serial_struct serial_table[NR_SERIALS] = {
+ { PORT_UNKNOWN, 0, 0x3F8, 4, NULL},
+ { PORT_UNKNOWN, 1, 0x2F8, 3, NULL},
+ { PORT_UNKNOWN, 2, 0x3E8, 4, NULL},
+ { PORT_UNKNOWN, 3, 0x2E8, 3, NULL},
+};
+void send_break(unsigned int line)
+{
+ unsigned short port;
+ struct serial_struct * info;
+
+ if (line >= NR_SERIALS)
+ return;
+ info = serial_table + line;
+ if (!(port = info->port))
+ 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);
+}
+
+/*
+ * 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(struct serial_struct * info)
+{
+ unsigned short port = info->port;
+ unsigned int timer = SER1_TIMEOUT + info->line;
+ struct tty_queue * queue = info->tty->write_q;
+ int c, i = 0;
+
+ if (info->tty->stopped) return;
+
+ timer_active &= ~(1 << timer);
+ while (inb_p(info->port+5) & 0x20) {
+ if (queue->tail == queue->head)
+ goto end_send;
+ c = queue->buf[queue->tail];
+ queue->tail++;
+ queue->tail &= TTY_BUF_SIZE-1;
+ outb(c,port);
+ if ((info->type != PORT_16550A) || (++i >= 14) || info->tty->stopped)
+ break;
+ }
+ timer_table[timer].expires = jiffies + 10;
+ timer_active |= 1 << timer;
+end_send:
+ if (LEFT(queue) > WAKEUP_CHARS)
+ wake_up(&queue->proc_list);
+}
+
+static void receive_intr(struct serial_struct * info)
+{
+ unsigned short port = info->port;
+ struct tty_queue * queue = info->tty->read_q;
+ int head = queue->head;
+ int maxhead = (queue->tail-1) & (TTY_BUF_SIZE-1);
+
+ timer_active &= ~((1<<SER1_TIMER)<<info->line);
+ do {
+ queue->buf[head] = inb(port);
+ if (head != maxhead) {
+ head++;
+ head &= TTY_BUF_SIZE-1;
+ }
+ } while (inb(port+5) & 1);
+ queue->head = head;
+ timer_active |= (1<<SER1_TIMER)<<info->line;
+}
+
+static void line_status_intr(struct serial_struct * info)
+{
+ unsigned char status = inb(info->port+5);
+
+/* printk("line status: %02x\n",status); */
+}
+
+static void modem_status_intr(struct serial_struct * info)
+{
+ unsigned char status = inb(info->port+6);
+
+ if (!(info->tty->termios.c_cflag & CLOCAL)) {
+ if ((status & 0x88) == 0x08 && info->tty->pgrp > 0)
+ kill_pg(info->tty->pgrp,SIGHUP,1);
+
+ if (info->tty->termios.c_cflag & CRTSCTS)
+ info->tty->stopped = !(status & 0x10);
+
+ if (!info->tty->stopped)
+ send_intr(info);
+ }
+}
+
+static void (*jmp_table[4])(struct serial_struct *) = {
+ modem_status_intr,
+ send_intr,
+ receive_intr,
+ line_status_intr
+};
+
+static void check_tty(struct serial_struct * info)
+{
+ unsigned char ident;
+
+ if (!info || !info->tty || !info->port)
+ return;
+ while (1) {
+ ident = inb(info->port+2) & 7;
+ if (ident & 1)
+ return;
+ ident >>= 1;
+ if (ident > 3)
+ return;
+ jmp_table[ident](info);
+ }
+}
+
+/*
+ * Again, we disable interrupts to be sure there aren't any races:
+ * see send_intr for details.
+ */
+static inline void do_rs_write(struct serial_struct * info)
+{
+ if (!info->tty || !info->port)
+ return;
+ if (!info->tty->write_q || EMPTY(info->tty->write_q))
+ return;
+ cli();
+ send_intr(info);
+ sti();
+}
+
+/*
+ * IRQ routines: one per line
+ */
+static void com1_IRQ(int unused)
+{
+ check_tty(serial_table+0);
+}
+
+static void com2_IRQ(int unused)
+{
+ check_tty(serial_table+1);
+}
+
+static void com3_IRQ(int unused)
+{
+ check_tty(serial_table+2);
+}
+
+static void com4_IRQ(int unused)
+{
+ check_tty(serial_table+3);
+}
+
+/*
+ * Receive timer routines: one per line
+ */
static void com1_timer(void)
{
TTY_READ_FLUSH(tty_table+64);
TTY_READ_FLUSH(tty_table+67);
}
-static inline void do_rs_write(unsigned int port)
-{
- char c;
-
-#define TTY (tty_table[64+port].write_q)
-#define TIMER (SER1_TIMEOUT+port)
- 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;
- timer_active |= 1 << TIMER;
- } else
- timer_active &= ~(1 << TIMER);
- sti();
-#undef TIMER
-#undef TTY
-}
-
+/*
+ * Send timeout routines: one per line
+ */
static void com1_timeout(void)
{
- do_rs_write(0);
+ do_rs_write(serial_table);
}
static void com2_timeout(void)
{
- do_rs_write(1);
+ do_rs_write(serial_table + 1);
}
static void com3_timeout(void)
{
- do_rs_write(2);
+ do_rs_write(serial_table + 2);
}
static void com4_timeout(void)
{
- do_rs_write(3);
+ do_rs_write(serial_table + 3);
}
-static void init(int port)
+static void init(struct serial_struct * info)
{
+ unsigned char status1, status2, scratch;
+ unsigned short port = info->port;
+
+ if (inb(port+5) == 0xff) {
+ info->type = PORT_UNKNOWN;
+ return;
+ }
+
+ scratch = inb(port+7);
+ outb_p(0xa5, port+7);
+ status1 = inb(port+7);
+ outb_p(0x5a, port+7);
+ status2 = inb(port+7);
+ if (status1 == 0xa5 && status2 == 0x5a) {
+ outb_p(scratch, port+7);
+ outb_p(0x01, port+2);
+ scratch = inb(port+2) >> 6;
+ switch (scratch) {
+ case 0:
+ info->type = PORT_16450;
+ break;
+ case 1:
+ info->type = PORT_UNKNOWN;
+ break;
+ case 2:
+ info->type = PORT_16550;
+ outb_p(0x00, port+2);
+ break;
+ case 3:
+ info->type = PORT_16550A;
+ outb_p(0xc7, port+2);
+ break;
+ }
+ } else
+ info->type = PORT_8250;
outb_p(0x80,port+3); /* set DLAB of line control reg */
- outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
+ outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps) */
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(0x00,port+1); /* disable all intrs */
(void)inb(port); /* read data port to reset things (?) */
}
-/*
- * 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_close(unsigned line, struct file * filp)
{
- unsigned short port;
- unsigned short port2;
+ struct serial_struct * info;
+ int irq;
- if (line>3)
+ if (line >= NR_SERIALS)
return;
- port = tty_table[64+line].read_q->data;
- if (!port)
+ info = serial_table + line;
+ if (!info->port)
return;
- port2 = tty_table[64+(line ^ 2)].read_q->data;
- cli();
- if (port2)
- outb_p(0x00,port2+4);
+ outb(0x00,info->port+4); /* reset DTR, RTS, */
+ irq = info->irq;
+ if (irq == 2)
+ irq = 9;
+ free_irq(irq);
+}
+
+static void startup(unsigned short port)
+{
+ int i;
+
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(0x0b,port+4); /* set DTR,RTS, OUT_2 */
+ outb_p(0x0f,port+1); /* enable all intrs */
+ inb_p(port+2);
+ inb_p(port+6);
+ inb_p(port+2);
+ inb_p(port+5);
+ for (i = 0; i < 16 ; i++) {
+ inb_p(port+0);
+ if (!(inb_p(port+5) & 1))
+ break;
+ }
+ inb_p(port+2);
inb_p(port+5);
- inb_p(port+0);
- inb(port+6);
- inb(port+2);
+}
+
+void change_speed(unsigned int line)
+{
+ struct serial_struct * info;
+ unsigned short port,quot;
+ unsigned cflag,cval;
+ static unsigned short quotient[] = {
+ 0, 2304, 1536, 1047, 857,
+ 768, 576, 384, 192, 96,
+ 64, 48, 24, 12, 6, 3
+ };
+
+ if (line >= NR_SERIALS)
+ return;
+ info = serial_table + line;
+ cflag = info->tty->termios.c_cflag;
+ if (!(port = info->port))
+ return;
+ quot = quotient[cflag & CBAUD];
+ if (!quot)
+ outb(0x00,port+4);
+ else if (!inb(port+4))
+ startup(port);
+/* byte size and parity */
+ cval = cflag & (CSIZE | CSTOPB);
+ cval >>= 4;
+ if (cflag & PARENB)
+ cval |= 8;
+ if (!(cflag & PARODD))
+ cval |= 16;
+ cli();
+ outb_p(cval | 0x80,port+3); /* set DLAB */
+ outb_p(quot & 0xff,port); /* LS of divisor */
+ outb_p(quot >> 8,port+1); /* MS of divisor */
+ outb(cval,port+3); /* reset DLAB */
+ sti();
+}
+
+static void (*serial_handler[NR_SERIALS])(int) = {
+ com1_IRQ,com2_IRQ,com3_IRQ,com4_IRQ
+};
+
+/*
+ * this routine enables interrupts on 'line', and disables them for any
+ * other serial line that shared the same IRQ. Braindamaged AT hardware.
+ */
+int serial_open(unsigned line, struct file * filp)
+{
+ struct serial_struct * info;
+ int irq,retval;
+ unsigned short port;
+ struct sigaction sa;
+
+ sa.sa_handler = serial_handler[line];
+ sa.sa_flags = SA_INTERRUPT;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ if (line >= NR_SERIALS)
+ return -ENODEV;
+ info = serial_table + line;
+ if (!(port = info->port))
+ return -ENODEV;
+ irq = info->irq;
+ if (irq == 2)
+ irq = 9;
+ if (retval = irqaction(irq,&sa))
+ return retval;
+ startup(port);
+ return 0;
+}
+
+int get_serial_info(unsigned int line, struct serial_struct * info)
+{
+ if (line >= NR_SERIALS)
+ return -ENODEV;
+ if (!info)
+ return -EFAULT;
+ memcpy_tofs(info,serial_table+line,sizeof(*info));
+ return 0;
+}
+
+int set_serial_info(unsigned int line, struct serial_struct * info)
+{
+ struct serial_struct tmp;
+ unsigned new_port;
+ unsigned irq,new_irq;
+ int retval;
+ void (*handler)(int) = serial_handler[line];
+
+ if (!suser())
+ return -EPERM;
+ if (line >= NR_SERIALS)
+ return -ENODEV;
+ if (!info)
+ return -EFAULT;
+ memcpy_fromfs(&tmp,info,sizeof(tmp));
+ info = serial_table + line;
+ if (!(new_port = tmp.port))
+ new_port = info->port;
+ if (!(new_irq = tmp.irq))
+ new_irq = info->irq;
+ if (new_irq > 15 || new_port > 0xffff)
+ return -EINVAL;
+ if (new_irq == 2)
+ new_irq = 9;
+ irq = info->irq;
+ if (irq == 2)
+ irq = 9;
+ if (irq != new_irq) {
+ retval = request_irq(new_irq,handler);
+ if (retval)
+ return retval;
+ info->irq = new_irq;
+ free_irq(irq);
+ }
+ cli();
+ if (new_port != info->port) {
+ outb(0x00,info->port+4); /* reset DTR, RTS, */
+ info->port = new_port;
+ init(info);
+ startup(new_port);
+ }
sti();
+ return 0;
}
-void rs_init(void)
+long rs_init(long kmem_start)
{
+ int i;
+ struct serial_struct * info;
+
/* SERx_TIMER timers are used for receiving: timeout is always 0 (immediate) */
timer_table[SER1_TIMER].fn = com1_timer;
timer_table[SER1_TIMER].expires = 0;
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);
- init(tty_table[64].read_q->data);
- init(tty_table[65].read_q->data);
- init(tty_table[66].read_q->data);
- init(tty_table[67].read_q->data);
- outb(inb_p(0x21)&0xE7,0x21);
+ for (i = 0, info = serial_table; i < NR_SERIALS; i++,info++) {
+ info->tty = (tty_table+64) + i;
+ init(info);
+ if (info->type == PORT_UNKNOWN)
+ continue;
+ printk("serial port at 0x%04x (irq = %d)",info->port,info->irq);
+ switch (info->type) {
+ case PORT_8250:
+ printk(" is a 8250\n");
+ break;
+ case PORT_16450:
+ printk(" is a 16450\n");
+ break;
+ case PORT_16550:
+ printk(" is a 16550\n");
+ break;
+ case PORT_16550A:
+ printk(" is a 16550A\n");
+ break;
+ default:
+ printk("\n");
+ break;
+ }
+ }
+ return kmem_start;
}
/*
*/
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 - 64;
+
+ do_rs_write(serial_table+line);
}
/*
* linux/kernel/tty_io.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
*/
-#include <linux/ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define ALRMMASK (1<<(SIGALRM-1))
-
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/ctype.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
-
-#define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS))
-static struct tty_queue tty_queues[QUEUES];
+#include <sys/kd.h>
+#include "vt_kern.h"
+
+#define QUEUES (3*(NR_CONSOLES+NR_SERIALS+2*NR_PTYS))
+static struct tty_queue * tty_queues;
struct tty_struct tty_table[256];
#define con_queues tty_queues
-#define rs_queues ((3*MAX_CONSOLES) + tty_queues)
-#define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues)
-#define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
+#define rs_queues ((3*NR_CONSOLES) + tty_queues)
+#define mpty_queues ((3*(NR_CONSOLES+NR_SERIALS)) + tty_queues)
+#define spty_queues ((3*(NR_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
#define con_table tty_table
#define rs_table (64+tty_table)
#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.
* you can implement virtual consoles.
*/
-struct tty_queue * table_list[]={
- con_queues + 0, con_queues + 1,
- rs_queues + 0, rs_queues + 1,
- rs_queues + 3, rs_queues + 4,
- rs_queues + 6, rs_queues + 7,
- rs_queues + 9, rs_queues + 10
- };
+struct tty_queue * table_list[] = { NULL, NULL };
+
+void inline put_tty_queue(char c, struct tty_queue * queue)
+{
+ int head;
+ unsigned long flags;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ head = (queue->head + 1) & (TTY_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->buf[queue->head] = c;
+ queue->head = head;
+ }
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+}
+
+int inline get_tty_queue(struct tty_queue * queue)
+{
+ int result = -1;
+ unsigned long flags;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ if (queue->tail != queue->head) {
+ result = 0xff & queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
+ }
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return result;
+}
+
+void inline tty_write_flush(struct tty_struct * tty)
+{
+ if (EMPTY(tty->write_q))
+ return;
+ if (set_bit(TTY_WRITE_BUSY,&tty->flags))
+ return;
+ tty->write(tty);
+ if (clear_bit(TTY_WRITE_BUSY,&tty->flags))
+ printk("tty_write_flush: bit already cleared\n");
+}
+
+void tty_read_flush(struct tty_struct * tty)
+{
+ if (EMPTY(tty->read_q))
+ return;
+ if (set_bit(TTY_READ_BUSY, &tty->flags))
+ return;
+ copy_to_cooked(tty);
+ if (clear_bit(TTY_READ_BUSY, &tty->flags))
+ printk("tty_read_flush: bit already cleared\n");
+}
void change_console(unsigned int new_console)
{
+ if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ return;
if (new_console == fg_console || new_console >= NR_CONSOLES)
return;
table_list[0] = con_queues + 0 + new_console*3;
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);
+ flush_input(&tty_table[fg_console]);
}
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)) {
return;
}
while (1) {
- if (EMPTY(tty->read_q))
+ if (FULL(tty->secondary))
break;
- if (FULL(tty->secondary)) {
- if (tty->secondary->proc_list)
- if (tty->secondary->proc_list != current)
- current->counter = 0;
+ c = get_tty_queue(tty->read_q);
+ if (c < 0)
break;
- }
- GETCH(tty->read_q,c);
if (I_STRP(tty))
c &= 0x7f;
if (c==13) {
if (I_UCLC(tty))
c=tolower(c);
if (L_CANON(tty)) {
- if ((KILL_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((KILL_CHAR(tty) != __DISABLED_CHAR) &&
(c==KILL_CHAR(tty))) {
/* deal with killing the input line */
while(!(EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
- ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
+ ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
(c==EOF_CHAR(tty))))) {
if (L_ECHO(tty)) {
- if (c<32)
- PUTCH(127,tty->write_q);
- PUTCH(127,tty->write_q);
- TTY_WRITE_FLUSH(tty);
+ if (c<32) {
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ }
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
}
DEC(tty->secondary->head);
}
continue;
}
- if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((ERASE_CHAR(tty) != __DISABLED_CHAR) &&
(c==ERASE_CHAR(tty))) {
if (EMPTY(tty->secondary) ||
(c=LAST(tty->secondary))==10 ||
- ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
+ ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
(c==EOF_CHAR(tty))))
continue;
if (L_ECHO(tty)) {
- if (c<32)
- PUTCH(127,tty->write_q);
- PUTCH(127,tty->write_q);
- TTY_WRITE_FLUSH(tty);
+ if (c<32) {
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(' ',tty->write_q);
+ put_tty_queue(8,tty->write_q);
+ }
+ put_tty_queue(8,tty->write_q);
+ put_tty_queue(32,tty->write_q);
+ put_tty_queue(8,tty->write_q);
}
DEC(tty->secondary->head);
continue;
}
}
if (I_IXON(tty)) {
- if ((STOP_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((STOP_CHAR(tty) != __DISABLED_CHAR) &&
(c==STOP_CHAR(tty))) {
tty->stopped=1;
continue;
}
- if ((START_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((START_CHAR(tty) != __DISABLED_CHAR) &&
(c==START_CHAR(tty))) {
tty->stopped=0;
- TTY_WRITE_FLUSH(tty);
continue;
}
}
if (L_ISIG(tty)) {
- if ((INTR_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((INTR_CHAR(tty) != __DISABLED_CHAR) &&
(c==INTR_CHAR(tty))) {
kill_pg(tty->pgrp, SIGINT, 1);
+ flush_input(tty);
continue;
}
- if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((QUIT_CHAR(tty) != __DISABLED_CHAR) &&
(c==QUIT_CHAR(tty))) {
kill_pg(tty->pgrp, SIGQUIT, 1);
+ flush_input(tty);
continue;
}
- if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) &&
+ if ((SUSPEND_CHAR(tty) != __DISABLED_CHAR) &&
(c==SUSPEND_CHAR(tty))) {
if (!is_orphaned_pgrp(tty->pgrp))
kill_pg(tty->pgrp, SIGTSTP, 1);
continue;
}
}
- if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)))
tty->secondary->data++;
- if ((L_ECHO(tty) || L_ECHONL(tty)) && (c==10)) {
- PUTCH(10,tty->write_q);
- PUTCH(13,tty->write_q);
+ if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
+ put_tty_queue(10,tty->write_q);
+ put_tty_queue(13,tty->write_q);
} else if (L_ECHO(tty)) {
if (c<32 && L_ECHOCTL(tty)) {
- PUTCH('^',tty->write_q);
- PUTCH(c+64,tty->write_q);
+ put_tty_queue('^',tty->write_q);
+ put_tty_queue(c+64,tty->write_q);
} else
- PUTCH(c,tty->write_q);
+ put_tty_queue(c,tty->write_q);
}
- PUTCH(c,tty->secondary);
- TTY_WRITE_FLUSH(tty);
+ put_tty_queue(c,tty->secondary);
}
TTY_WRITE_FLUSH(tty);
if (!EMPTY(tty->secondary))
wake_up(&tty->secondary->proc_list);
- if (LEFT(tty->write_q) > TTY_BUF_SIZE/2)
+ if (tty->write_q->proc_list && LEFT(tty->write_q) > TTY_BUF_SIZE/2)
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
*/
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)
- return -EINTR; /* We _will_ be interrupted :-) */
- else
- return -ERESTARTSYS; /* We _will_ be interrupted :-) */
- /* (but restart after we continue) */
+ return -ERESTARTSYS;
+}
+
+static void wait_for_canon_input(struct tty_struct * tty)
+{
+ while (1) {
+ TTY_READ_FLUSH(tty);
+ if (tty->link)
+ if (tty->link->count)
+ TTY_WRITE_FLUSH(tty->link);
+ else
+ return;
+ if (current->signal & ~current->blocked)
+ return;
+ if (FULL(tty->read_q))
+ return;
+ if (tty->secondary->data)
+ return;
+ cli();
+ if (!tty->secondary->data)
+ interruptible_sleep_on(&tty->secondary->proc_list);
+ sti();
+ }
}
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;
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 (channel & 0x80)
- other_tty = tty_table + (channel ^ 0x40);
- time = 10L*tty->termios.c_cc[VTIME];
- minimum = tty->termios.c_cc[VMIN];
- if (L_CANON(tty)) {
- minimum = nr;
- current->timeout = 0xffffffff;
- time = 0;
- } else if (minimum)
- current->timeout = 0xffffffff;
+ if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ else
+ return(tty_signal(SIGTTIN, tty));
+ if (L_CANON(tty))
+ minimum = time = current->timeout = 0;
else {
- minimum = nr;
- if (time)
- current->timeout = time + jiffies;
- time = 0;
+ time = 10L*tty->termios.c_cc[VTIME];
+ minimum = tty->termios.c_cc[VMIN];
+ if (minimum)
+ current->timeout = 0xffffffff;
+ else {
+ if (time)
+ current->timeout = time + jiffies;
+ else
+ current->timeout = 0;
+ time = 0;
+ minimum = 1;
+ }
}
if (file->f_flags & O_NONBLOCK)
time = current->timeout = 0;
+ else if (L_CANON(tty))
+ wait_for_canon_input(tty);
if (minimum>nr)
minimum = nr;
- TTY_READ_FLUSH(tty);
while (nr>0) {
- if (other_tty && other_tty->write)
- TTY_WRITE_FLUSH(other_tty);
- cli();
- if (EMPTY(tty->secondary) || (L_CANON(tty) &&
- !FULL(tty->read_q) && !tty->secondary->data)) {
- if (!current->timeout)
- break;
- if (current->signal & ~current->blocked)
- break;
- if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
- break;
- interruptible_sleep_on(&tty->secondary->proc_list);
- sti();
- TTY_READ_FLUSH(tty);
- continue;
- }
- sti();
- do {
- GETCH(tty->secondary,c);
- if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ TTY_READ_FLUSH(tty);
+ if (tty->link)
+ TTY_WRITE_FLUSH(tty->link);
+ while (nr > 0 && ((c = get_tty_queue(tty->secondary)) >= 0)) {
+ if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)) || c==10)
tty->secondary->data--;
- if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
+ if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
c==EOF_CHAR(tty)) && L_CANON(tty))
break;
- else {
- put_fs_byte(c,b++);
- if (!--nr)
- break;
- }
+ put_fs_byte(c,b++);
+ nr--;
+ if (time)
+ current->timeout = time+jiffies;
if (c==10 && L_CANON(tty))
break;
- } while (nr>0 && !EMPTY(tty->secondary));
+ };
wake_up(&tty->read_q->proc_list);
- if (L_CANON(tty) || b-buf >= minimum)
+ if (b-buf >= minimum || !current->timeout)
+ break;
+ if (current->signal & ~current->blocked)
break;
- if (time)
- current->timeout = time+jiffies;
+ if (tty->link && !tty->link->count)
+ break;
+ TTY_READ_FLUSH(tty);
+ if (tty->link)
+ TTY_WRITE_FLUSH(tty->link);
+ cli();
+ if (EMPTY(tty->secondary))
+ interruptible_sleep_on(&tty->secondary->proc_list);
+ sti();
}
- sti();
+ TTY_READ_FLUSH(tty);
+ if (tty->link && tty->link->write)
+ TTY_WRITE_FLUSH(tty->link);
current->timeout = 0;
if (b-buf)
return b-buf;
static int write_chan(unsigned int channel, struct file * file, char * buf, int nr)
{
- static cr_flag=0;
struct tty_struct * tty;
char c, *b=buf;
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 (tty->link && !tty->link->count) {
+ send_sig(SIGPIPE,current,0);
+ 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)) {
c='\n';
else if (c=='\n' && O_NLRET(tty))
c='\r';
- if (c=='\n' && !cr_flag && O_NLCR(tty)) {
- cr_flag = 1;
- PUTCH(13,tty->write_q);
+ if (c=='\n' && O_NLCR(tty) &&
+ !set_bit(TTY_CR_PENDING,&tty->flags)) {
+ put_tty_queue(13,tty->write_q);
continue;
}
if (O_LCUC(tty))
c=toupper(c);
}
b++; nr--;
- cr_flag = 0;
- PUTCH(c,tty->write_q);
+ clear_bit(TTY_CR_PENDING,&tty->flags);
+ put_tty_queue(c,tty->write_q);
}
- TTY_WRITE_FLUSH(tty);
if (nr>0)
schedule();
}
+ TTY_WRITE_FLUSH(tty);
if (b-buf)
return b-buf;
+ if (tty->link && !tty->link->count)
+ return -EPIPE;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
{
- return read_chan(current->tty,file,buf,count);
+ int i;
+
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_read: pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ i = read_chan(MINOR(file->f_rdev),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)
+static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
{
- return read_chan(MINOR(inode->i_rdev),file,buf,count);
+ int i;
+
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_write: pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ i = write_chan(MINOR(file->f_rdev),file,buf,count);
+ if (i > 0)
+ inode->i_mtime = CURRENT_TIME;
+ return i;
}
-static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
+static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
- return write_chan(current->tty,file,buf,count);
+ return -EBADF;
}
-static int ttyx_write(struct inode * inode, struct file * file, char * buf, int count)
+/*
+ * 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)
{
- return write_chan(MINOR(inode->i_rdev),file,buf,count);
+ struct tty_struct *tty;
+ int dev, retval;
+
+ dev = inode->i_rdev;
+ if (MAJOR(dev) == 5)
+ dev = current->tty;
+ else
+ dev = MINOR(dev);
+ if (dev < 0)
+ return -ENODEV;
+ filp->f_rdev = 0x0400 | dev;
+ tty = TTY_TABLE(dev);
+ if (!tty->count && !(tty->link && tty->link->count)) {
+ flush_input(tty);
+ flush_output(tty);
+ tty->stopped = 0;
+ }
+ if (IS_A_PTY_MASTER(dev)) {
+ if (tty->count)
+ return -EAGAIN;
+ if (tty->link)
+ tty->link->count++;
+ }
+ tty->count++;
+ retval = 0;
+ 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) && tty->count < 2)
+ retval = serial_open(dev-64,filp);
+ else if (IS_A_PTY(dev))
+ retval = pty_open(dev,filp);
+ if (retval) {
+ tty->count--;
+ if (IS_A_PTY_MASTER(dev) && tty->link)
+ tty->link->count--;
+ }
+ return retval;
}
-static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+/*
+ * Note that releasing a pty master also releases the child, so
+ * we have to make the redirection checks after that and on both
+ * sides of a pty.
+ */
+static void tty_release(struct inode * inode, struct file * filp)
{
- return -EBADF;
+ int dev;
+ struct tty_struct * tty;
+
+ dev = filp->f_rdev;
+ if (MAJOR(dev) != 4) {
+ printk("tty_close: tty pseudo-major != 4\n");
+ return;
+ }
+ dev = MINOR(filp->f_rdev);
+ tty = TTY_TABLE(dev);
+ if (IS_A_PTY_MASTER(dev) && tty->link)
+ tty->link->count--;
+ tty->count--;
+ if (tty->count)
+ return;
+ if (IS_A_SERIAL(dev)) {
+ wait_until_sent(tty);
+ serial_close(dev-64,filp);
+ } else if (IS_A_PTY(dev))
+ pty_close(dev,filp);
+ if (!tty->count && (tty == redirect))
+ redirect = NULL;
+ if (tty = tty->link)
+ if (!tty->count && (tty == redirect))
+ redirect = NULL;
}
-static int tty_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
+static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
{
- return -ENOTDIR;
+ int dev;
+ struct tty_struct * tty;
+
+ dev = filp->f_rdev;
+ if (MAJOR(dev) != 4) {
+ printk("tty_select: tty pseudo-major != 4\n");
+ return 0;
+ }
+ dev = MINOR(filp->f_rdev);
+ tty = TTY_TABLE(dev);
+ switch (sel_type) {
+ case SEL_IN:
+ if (!EMPTY(tty->secondary))
+ return 1;
+ if (tty->link && !tty->link->count)
+ return 1;
+ select_wait(&tty->secondary->proc_list, wait);
+ return 0;
+ case SEL_OUT:
+ if (!FULL(tty->write_q))
+ return 1;
+ select_wait(&tty->write_q->proc_list, wait);
+ return 0;
+ case SEL_EX:
+ if (tty->link && !tty->link->count)
+ return 1;
+ return 0;
+ }
+ return 0;
}
static struct file_operations tty_fops = {
tty_lseek,
tty_read,
tty_write,
- tty_readdir,
- NULL, /* tty_close */
- NULL, /* tty_select */
- tty_ioctl /* tty_ioctl */
-};
-
-static struct file_operations ttyx_fops = {
- tty_lseek,
- ttyx_read,
- ttyx_write,
- tty_readdir,
- NULL, /* ttyx_close */
- NULL, /* ttyx_select */
- tty_ioctl /* ttyx_ioctl */
+ NULL, /* tty_readdir */
+ tty_select,
+ tty_ioctl,
+ tty_open,
+ tty_release
};
-void tty_init(void)
+long tty_init(long kmem_start)
{
int i;
- chrdev_fops[4] = &ttyx_fops;
+ tty_queues = (struct tty_queue *) kmem_start;
+ kmem_start += QUEUES * (sizeof (struct tty_queue));
+ table_list[0] = con_queues + 0;
+ table_list[1] = con_queues + 1;
+ chrdev_fops[4] = &tty_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,""};
- rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};
- rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};
- rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};
- rs_queues[6] = (struct tty_queue) {0x3e8,0,0,0,""};
- rs_queues[7] = (struct tty_queue) {0x3e8,0,0,0,""};
- rs_queues[9] = (struct tty_queue) {0x2e8,0,0,0,""};
- rs_queues[10] = (struct tty_queue) {0x2e8,0,0,0,""};
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},
- NULL, NULL, NULL, NULL
+ -1, 0, 0, 0, 0, {0,0,0,0},
+ NULL, NULL, NULL, NULL, NULL
};
}
- con_init();
+ kmem_start = con_init(kmem_start);
for (i = 0 ; i<NR_CONSOLES ; i++) {
con_table[i] = (struct tty_struct) {
{ICRNL, /* change incoming CR to NL */
-1, /* initial pgrp */
0, /* initial session */
0, /* initial stopped */
- 0, /* initial busy */
+ 0, /* initial flags */
+ 0, /* initial count */
{video_num_lines,video_num_columns,0,0},
con_write,
+ NULL, /* other-tty */
con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
};
}
0,
0,
0,
+ 0,
{25,80,0,0},
rs_write,
+ NULL, /* other-tty */
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
};
}
0,
0,
0,
+ 0,
{25,80,0,0},
mpty_write,
+ spty_table+i,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
};
spty_table[i] = (struct tty_struct) {
0,
0,
0,
+ 0,
{25,80,0,0},
spty_write,
+ mpty_table+i,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
};
}
- rs_init();
+ kmem_start = rs_init(kmem_start);
printk("%d virtual consoles\n\r",NR_CONSOLES);
printk("%d pty's\n\r",NR_PTYS);
+ return kmem_start;
}
/*
* linux/kernel/chr_drv/tty_ioctl.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-#include <termios.h>
-#include <sys/types.h>
-
+#include <linux/types.h>
+#include <linux/termios.h>
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/fcntl.h>
#include <asm/io.h>
#include <asm/segment.h>
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,
- 768, 576, 384, 192, 96,
- 64, 48, 24, 12, 6, 3
-};
-
-static void change_speed(struct tty_struct * tty)
-{
- unsigned short port,quot;
-
- if (!(port = tty->read_q->data))
- return;
- quot = quotient[tty->termios.c_cflag & CBAUD];
- cli();
- outb_p(0x80,port+3); /* set DLAB */
- outb_p(quot & 0xff,port); /* LS of divisor */
- outb_p(quot >> 8,port+1); /* MS of divisor */
- outb(0x03,port+3); /* reset DLAB */
- sti();
-}
-
static void flush(struct tty_queue * queue)
{
if (queue) {
}
}
-static void wait_until_sent(struct tty_struct * tty)
+void flush_input(struct tty_struct * tty)
{
- cli();
- while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
- current->counter = 0;
- interruptible_sleep_on(&tty->write_q->proc_list);
+ if (tty->read_q) {
+ flush(tty->read_q);
+ wake_up(&tty->read_q->proc_list);
+ }
+ if (tty->secondary) {
+ flush(tty->secondary);
+ tty->secondary->data = 0;
+ }
+ if ((tty = tty->link) && tty->write_q) {
+ flush(tty->write_q);
+ wake_up(&tty->write_q->proc_list);
}
- sti();
}
-static void send_break(struct tty_struct * tty)
+void flush_output(struct tty_struct * tty)
{
- /* do nothing - not implemented */
+ if (tty->write_q) {
+ flush(tty->write_q);
+ wake_up(&tty->write_q->proc_list);
+ }
+ if (tty = tty->link) {
+ if (tty->read_q) {
+ flush(tty->read_q);
+ wake_up(&tty->read_q->proc_list);
+ }
+ if (tty->secondary) {
+ flush(tty->secondary);
+ tty->secondary->data = 0;
+ }
+ }
+}
+
+void wait_until_sent(struct tty_struct * tty)
+{
+ while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
+ TTY_WRITE_FLUSH(tty);
+ current->counter = 0;
+ cli();
+ if (EMPTY(tty->write_q))
+ break;
+ else
+ interruptible_sleep_on(&tty->write_q->proc_list);
+ sti();
+ }
+ sti();
}
static int do_get_ps_info(int arg)
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
- int i, retsig;
+ int i;
+ unsigned short old_cflag = tty->termios.c_cflag;
/* 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);
- change_speed(tty);
+ if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
+ change_speed(channel-64);
return 0;
}
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
- int i, retsig;
+ int i;
struct termio tmp_termio;
+ unsigned short old_cflag = tty->termios.c_cflag;
- 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);
tty->termios.c_line = tmp_termio.c_line;
for(i=0 ; i < NCC ; i++)
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
- change_speed(tty);
+ if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
+ change_speed(channel-64);
return 0;
}
int pgrp;
int dev;
- if (MAJOR(inode->i_rdev) == 5) {
- dev = current->tty;
- if (dev<0)
- return -EINVAL;
- } else
- dev = MINOR(inode->i_rdev);
+ if (MAJOR(file->f_rdev) != 4) {
+ printk("tty_ioctl: tty pseudo-major != 4\n");
+ return -EINVAL;
+ }
+ dev = MINOR(file->f_rdev);
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
if (IS_A_PTY(dev))
case TCGETS:
return get_termios(tty,(struct termios *) arg);
case TCSETSF:
- flush(tty->read_q);
- flush(tty->secondary);
- if (other_tty)
- flush(other_tty->write_q);
+ flush_input(tty);
/* fallthrough */
case TCSETSW:
wait_until_sent(tty);
case TCGETA:
return get_termio(tty,(struct termio *) arg);
case TCSETAF:
- flush(tty->read_q);
- flush(tty->secondary);
- if (other_tty)
- flush(other_tty->write_q);
+ flush_input(tty);
/* fallthrough */
case TCSETAW:
wait_until_sent(tty); /* fallthrough */
case TCSETA:
return set_termio(tty,(struct termio *) arg, dev);
case TCSBRK:
- if (!arg) {
- wait_until_sent(tty);
- send_break(tty);
- }
+ if (!IS_A_SERIAL(dev))
+ return -EINVAL;
+ wait_until_sent(tty);
+ if (!arg)
+ send_break(dev-64);
return 0;
case TCXONC:
switch (arg) {
return 0;
case TCIOFF:
if (STOP_CHAR(tty))
- PUTCH(STOP_CHAR(tty),tty->write_q);
+ put_tty_queue(STOP_CHAR(tty),tty->write_q);
return 0;
case TCION:
if (START_CHAR(tty))
- PUTCH(START_CHAR(tty),tty->write_q);
+ put_tty_queue(START_CHAR(tty),tty->write_q);
return 0;
}
return -EINVAL; /* not implemented */
case TCFLSH:
- if (arg==0) {
- flush(tty->read_q);
- flush(tty->secondary);
- if (other_tty)
- flush(other_tty->write_q);
- } else if (arg==1)
- flush(tty->write_q);
+ if (arg==0)
+ flush_input(tty);
+ else if (arg==1)
+ flush_output(tty);
else if (arg==2) {
- flush(tty->read_q);
- flush(tty->secondary);
- flush(tty->write_q);
- if (other_tty)
- flush(other_tty->write_q);
+ flush_input(tty);
+ flush_output(tty);
} else
return -EINVAL;
return 0;
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:
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;
+ case TIOCGSERIAL:
+ if (!IS_A_SERIAL(dev))
+ return -EINVAL;
+ verify_area((void *) arg,sizeof(struct serial_struct));
+ return get_serial_info(dev-64,(struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ if (!IS_A_SERIAL(dev))
+ return -EINVAL;
+ return set_serial_info(dev-64,(struct serial_struct *) arg);
+ case FIONBIO:
+ if (arg)
+ file->f_flags |= O_NONBLOCK;
+ else
+ file->f_flags &= ~O_NONBLOCK;
+ return 0;
+ case TIOCNOTTY:
+ if (MINOR(file->f_rdev) != current->tty)
+ return -EINVAL;
+ current->tty = -1;
+ if (current->leader) {
+ if (tty->pgrp > 0)
+ kill_pg(tty->pgrp, SIGHUP, 0);
+ tty->pgrp = -1;
+ tty->session = 0;
+ }
+ return 0;
default:
return vt_ioctl(tty, dev, cmd, arg);
}
/*
* kernel/chr_drv/vt.c
*
- * (C) 1992 obz under the linux copyright
+ * Copyright (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/types.h>
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/timer.h>
#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
#include "vt_kern.h"
+#include <sys/kd.h>
+#include <sys/vt.h>
/*
* console (vt and kd) routines, as defined by usl svr4 manual
*/
-struct vt_info vt_info[MAX_CONSOLES];
+struct vt_cons vt_cons[NR_CONSOLES];
-extern int NR_CONSOLES;
extern unsigned char kleds;
extern unsigned char kraw;
extern unsigned char ke0;
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 KDENABIO:
case KDDISABIO:
- return sys_ioperm(GPFIRST, GPNUM, (cmd == KDENABIO)) ? -ENXIO : 0;
+ return sys_ioperm(GPFIRST, GPNUM,
+ (cmd == KDENABIO)) ? -ENXIO : 0;
case KDSETMODE:
/*
default:
return -EINVAL;
}
- vt_info[fg_console].mode = arg;
+ if (vt_cons[console].vt_mode == (unsigned char) arg)
+ return 0;
+ vt_cons[console].vt_mode = (unsigned char) arg;
+ if (console != fg_console)
+ return 0;
+ if (arg == KD_TEXT)
+ unblank_screen();
+ else {
+ timer_active &= 1<<BLANK_TIMER;
+ blank_screen();
+ }
return 0;
case KDGETMODE:
verify_area((void *) arg, sizeof(unsigned long));
- put_fs_long(vt_info[fg_console].mode, (unsigned long *) arg);
+ put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg);
return 0;
case KDMAPDISP:
case KDSKBMODE:
if (arg == K_RAW) {
- kraw = 1;
- ke0 = 0;
+ 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) {
- kraw = 0;
+ if (console == fg_console)
+ kraw = 0;
+ else
+ vt_cons[console].vc_kbdraw = 0;
}
else
return -EINVAL;
+ flush_input(tty);
return 0;
case KDGKBMODE:
verify_area((void *) arg, sizeof(unsigned long));
- put_fs_long(kraw ? K_RAW : K_XLATE, (unsigned long *) arg);
+ 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));
- put_fs_byte((((kleds & 1) ? LED_SCR : 0) |
- ((kleds & 2) ? LED_NUM : 0) |
- ((kleds & 4) ? LED_CAP : 0)),
+ 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;
- kleds = (((arg & LED_SCR) ? 1 : 0) |
+ ucval = (((arg & LED_SCR) ? 1 : 0) |
((arg & LED_NUM) ? 2 : 0) |
((arg & LED_CAP) ? 4 : 0));
- set_leds();
+ if (console == fg_console) {
+ kleds = ucval;
+ set_leds();
+ }
+ else
+ vt_cons[console].vc_kbdleds = ucval;
return 0;
default:
return -EINVAL;
}
}
-
-void
-vt_init(void)
-{
- int i;
-
- for (i = 0; i < NR_CONSOLES; ++i) {
- vt_info[i].mode = KD_TEXT;
- }
-}
#ifndef _VT_KERN_H
#define _VT_KERN_H
-extern struct vt_info {
- int mode; /* KD_TEXT, ... */
-} vt_info[MAX_CONSOLES];
+/*
+ * 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[NR_CONSOLES];
#endif /* _VT_KERN_H */
/*
* linux/kernel/exit.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define DEBUG_PROC_TREE
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
#include <linux/tty.h>
+
#include <asm/segment.h>
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) && (current->uid != p->uid) && !suser())
return -EPERM;
if (!sig)
return 0;
/* save the signal number for wait. */
p->exit_code = sig;
- /* we have to make sure the parent is awake. */
+ /* we have to make sure the parent process is awake. */
if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
p->p_pptr->state = TASK_RUNNING;
for (i=1 ; i<NR_TASKS ; i++)
if (task[i] == p) {
task[i] = NULL;
- /* Update links */
- if (p->p_osptr)
- p->p_osptr->p_ysptr = p->p_ysptr;
- if (p->p_ysptr)
- p->p_ysptr->p_osptr = p->p_osptr;
- else
- p->p_pptr->p_cptr = p->p_osptr;
+ REMOVE_LINKS(p);
free_page((long) p);
return;
}
}
#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)
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
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);
}
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;
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);
return(0);
}
+static void forget_original_parent(struct task_struct * father)
+{
+ struct task_struct ** p;
+
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if (*p && (*p)->p_opptr == father)
+ if (task[1])
+ (*p)->p_opptr = task[1];
+ else
+ (*p)->p_opptr = task[0];
+}
+
volatile void do_exit(long code)
{
struct task_struct *p;
int i;
+fake_volatile:
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
+ forget_original_parent(current);
iput(current->pwd);
current->pwd = NULL;
iput(current->root);
current->root = NULL;
iput(current->executable);
current->executable = NULL;
- for (i=0; i<current->numlibraries; i++) {
+ for (i=0; i < current->numlibraries; i++) {
iput(current->libraries[i].library);
current->libraries[i].library = NULL;
}
* A. Make init inherit all the child processes
* B. Check to see if any process groups have become orphaned
* as a result of our exiting, and if they have any stopped
- * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
+ * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
*/
while (p = current->p_cptr) {
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
- p->flags &= ~PF_PTRACED;
- p->p_pptr = task[1];
- p->p_osptr = task[1]->p_cptr;
- task[1]->p_cptr->p_ysptr = p;
- task[1]->p_cptr = p;
+ p->flags &= ~PF_PTRACED;
+ if (task[1])
+ p->p_pptr = task[1];
+ else
+ p->p_pptr = task[0];
+ p->p_osptr = p->p_pptr->p_cptr;
+ p->p_osptr->p_ysptr = p;
+ p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE)
- task[1]->signal |= (1<<(SIGCHLD-1));
+ send_sig(SIGCHLD,p->p_pptr,1);
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
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)
audit_ptree();
#endif
schedule();
+/*
+ * In order to get rid of the "volatile function does return" message
+ * I did this little loop that confuses gcc to think do_exit really
+ * is volatile. In fact it's schedule() that is volatile in some
+ * circumstances: when current->state = ZOMBIE, schedule() never
+ * returns.
+ *
+ * In fact the natural way to do all this is to have the label and the
+ * goto right after each other, but I put the fake_volatile label at
+ * the start of the function just in case something /really/ bad
+ * happens, and the schedule returns. This way we can try again. I'm
+ * not paranoid: it's just that everybody is out to get me.
+ */
+ goto fake_volatile;
}
int sys_exit(int error_code)
if (stat_addr)
verify_area(stat_addr,4);
repeat:
+ current->signal &= ~(1<<(SIGCHLD-1));
flag=0;
- for (p = current->p_cptr ; p ; p = p->p_osptr) {
+ for (p = current->p_cptr ; p ; p = p->p_osptr) {
if (pid>0) {
if (p->pid != pid)
continue;
}
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,
flag = p->pid;
if (stat_addr)
put_fs_long(p->exit_code, stat_addr);
- release(p);
+ if (p->p_opptr != p->p_pptr) {
+ REMOVE_LINKS(p);
+ p->p_pptr = p->p_opptr;
+ SET_LINKS(p);
+ send_sig(SIGCHLD,p->p_pptr,1);
+ } else
+ release(p);
#ifdef DEBUG_PROC_TREE
audit_ptree();
#endif
}
return -ECHILD;
}
-
-
/*
* linux/kernel/fork.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Fork is rather simple, once you get the hang of it, but the memory
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/
-#include <errno.h>
-#include <stddef.h>
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+
#include <asm/segment.h>
#include <asm/system.h>
-extern void write_verify(unsigned long address);
+#define MAX_TASKS_PER_USER ((NR_TASKS/4)*3)
long last_pid=0;
unsigned long old_data_base,new_data_base,data_limit;
unsigned long old_code_base,new_code_base,code_limit;
- code_limit=get_limit(0x0f);
- data_limit=get_limit(0x17);
+ code_limit = get_limit(0x0f);
+ data_limit = get_limit(0x17);
old_code_base = get_base(current->ldt[1]);
old_data_base = get_base(current->ldt[2]);
if (old_data_base != old_code_base) {
static int find_empty_process(void)
{
- int i;
+ int i, task_nr;
+ int this_user_tasks = 0;
- repeat:
- if ((++last_pid)<0) last_pid=1;
- for(i=0 ; i<NR_TASKS ; i++)
- if (task[i] && ((task[i]->pid == last_pid) ||
- (task[i]->pgrp == last_pid)))
- goto repeat;
+repeat:
+ if ((++last_pid) & 0xffff0000)
+ last_pid=1;
+ for(i=0 ; i < NR_TASKS ; i++) {
+ if (!task[i])
+ continue;
+ if (task[i]->uid == current->uid)
+ this_user_tasks++;
+ if (task[i]->pid == last_pid || task[i]->pgrp == last_pid)
+ goto repeat;
+ }
+ if (this_user_tasks > MAX_TASKS_PER_USER && !suser())
+ return -EAGAIN;
+/* Only the super-user can fill the last available slot */
+ task_nr = 0;
for(i=1 ; i<NR_TASKS ; i++)
if (!task[i])
- return i;
+ if (task_nr)
+ return task_nr;
+ else
+ task_nr = i;
+ if (task_nr && suser())
+ return task_nr;
return -EAGAIN;
}
int i,nr;
struct file *f;
- p = (struct task_struct *) get_free_page();
+ p = (struct task_struct *) get_free_page(GFP_KERNEL);
if (!p)
return -EAGAIN;
nr = find_empty_process();
}
task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
+ p->wait.task = p;
+ p->wait.next = NULL;
p->state = TASK_UNINTERRUPTIBLE;
+ p->flags &= ~PF_PTRACED;
p->pid = last_pid;
- p->p_pptr = current;
+ if (p->pid > 1)
+ p->swappable = 1;
+ p->p_pptr = p->p_opptr = 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;
+ SET_LINKS(p);
p->counter = p->priority;
p->signal = 0;
- p->alarm = 0;
+ p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
+ p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;
p->leader = 0; /* process leadership doesn't inherit */
p->utime = p->stime = 0;
p->cutime = p->cstime = 0;
p->tss.esp0 = PAGE_SIZE + (long) p;
p->tss.ss0 = 0x10;
p->tss.eip = eip;
- p->tss.eflags = eflags;
+ p->tss.eflags = eflags & 0xffffcfff; /* iopl is always 0 for a new process */
p->tss.eax = 0;
p->tss.ecx = ecx;
p->tss.edx = edx;
__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;
+ REMOVE_LINKS(p);
free_page((long) p);
return -EAGAIN;
}
#include <linux/sched.h>
#include <linux/kernel.h>
-
-#include <sys/types.h>
-#include <errno.h>
+#include <linux/errno.h>
+#include <linux/types.h>
#define _IODEBUG
}
return 0;
}
+
+unsigned int *stack;
+
+/*
+ * sys_iopl has to be used when you want to access the IO ports
+ * beyond the 0x3ff range: to get the full 65536 ports bitmapped
+ * you'd need 8kB of bitmaps/process, which is a bit excessive.
+ *
+ * Here we just change the eflags value on the stack: we allow
+ * only the super-user to do it. This depends on the stack-layout
+ * on system-call entry - see also fork() and the signal handling
+ * code.
+ */
+int sys_iopl(long ebx,long ecx,long edx,
+ long esi, long edi, long ebp, long eax, long ds,
+ long es, long fs, long gs, long orig_eax,
+ long eip,long cs,long eflags,long esp,long ss)
+{
+ unsigned int level = ebx;
+
+ if (level > 3)
+ return -EINVAL;
+ if (!suser())
+ return -EPERM;
+ *(&eflags) = (eflags & 0xffffcfff) | (level << 12);
+ return 0;
+}
--- /dev/null
+/*
+ * linux/kernel/irq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ * The same sigaction struct is used, and with similar semantics (ie there
+ * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
+ * are similarities.
+ *
+ * sa_handler(int irq_NR) is the default function called.
+ * sa_mask is 0 if nothing uses this IRQ
+ * sa_flags contains various info: SA_INTERRUPT etc
+ * sa_restorer is the unused
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+void irq13(void);
+
+/*
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that do all
+ * the operations that are needed to keep the AT interrupt-controller
+ * happy. They are also written to be fast - and to disable interrupts
+ * as little as humanly possible.
+ *
+ * NOTE! These macros expand to three different handlers for each line: one
+ * complete handler that does all the fancy stuff (including signal handling),
+ * and one fast handler that is meant for simple IRQ's that want to be
+ * atomic. The specific handler is chosen depending on the SA_INTERRUPT
+ * flag when installing a handler. Finally, one "bad interrupt" handler, that
+ * is used when no handler is present.
+ */
+BUILD_IRQ(FIRST,0,0x01)
+BUILD_IRQ(FIRST,1,0x02)
+BUILD_IRQ(FIRST,2,0x04)
+BUILD_IRQ(FIRST,3,0x08)
+BUILD_IRQ(FIRST,4,0x10)
+BUILD_IRQ(FIRST,5,0x20)
+BUILD_IRQ(FIRST,6,0x40)
+BUILD_IRQ(FIRST,7,0x80)
+BUILD_IRQ(SECOND,8,0x01)
+BUILD_IRQ(SECOND,9,0x02)
+BUILD_IRQ(SECOND,10,0x04)
+BUILD_IRQ(SECOND,11,0x08)
+BUILD_IRQ(SECOND,12,0x10)
+BUILD_IRQ(SECOND,13,0x20)
+BUILD_IRQ(SECOND,14,0x40)
+BUILD_IRQ(SECOND,15,0x80)
+
+/*
+ * Pointers to the low-level handlers: first the general ones, then the
+ * fast ones, then the bad ones.
+ */
+static void (*interrupt[16])(void) = {
+ IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
+ IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
+ IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
+ IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
+};
+
+static void (*fast_interrupt[16])(void) = {
+ fast_IRQ0_interrupt, fast_IRQ1_interrupt,
+ fast_IRQ2_interrupt, fast_IRQ3_interrupt,
+ fast_IRQ4_interrupt, fast_IRQ5_interrupt,
+ fast_IRQ6_interrupt, fast_IRQ7_interrupt,
+ fast_IRQ8_interrupt, fast_IRQ9_interrupt,
+ fast_IRQ10_interrupt, fast_IRQ11_interrupt,
+ fast_IRQ12_interrupt, fast_IRQ13_interrupt,
+ fast_IRQ14_interrupt, fast_IRQ15_interrupt
+};
+
+static void (*bad_interrupt[16])(void) = {
+ bad_IRQ0_interrupt, bad_IRQ1_interrupt,
+ bad_IRQ2_interrupt, bad_IRQ3_interrupt,
+ bad_IRQ4_interrupt, bad_IRQ5_interrupt,
+ bad_IRQ6_interrupt, bad_IRQ7_interrupt,
+ bad_IRQ8_interrupt, bad_IRQ9_interrupt,
+ bad_IRQ10_interrupt, bad_IRQ11_interrupt,
+ bad_IRQ12_interrupt, bad_IRQ13_interrupt,
+ bad_IRQ14_interrupt, bad_IRQ15_interrupt
+};
+
+/*
+ * Initial irq handlers.
+ */
+static struct sigaction irq_sigaction[16] = {
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+};
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts disabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+int do_IRQ(int irq, struct pt_regs * regs)
+{
+ struct sigaction * sa = irq + irq_sigaction;
+
+ sa->sa_handler((int) regs);
+ return 0; /* re-enable the irq when returning */
+}
+
+/*
+ * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
+ * stuff - the handler is also running with interrupts disabled unless
+ * it explicitly enables them later.
+ */
+int do_fast_IRQ(int irq)
+{
+ struct sigaction * sa = irq + irq_sigaction;
+
+ sa->sa_handler(0);
+ return 0; /* re-enable the irq when returning */
+}
+
+int irqaction(unsigned int irq, struct sigaction * new)
+{
+ struct sigaction * sa;
+ unsigned long flags;
+
+ if (irq > 15)
+ return -EINVAL;
+ sa = irq + irq_sigaction;
+ if (sa->sa_mask)
+ return -EBUSY;
+ if (!new->sa_handler)
+ return -EINVAL;
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ *sa = *new;
+ sa->sa_mask = 1;
+ if (sa->sa_flags & SA_INTERRUPT)
+ set_intr_gate(0x20+irq,fast_interrupt[irq]);
+ else
+ set_intr_gate(0x20+irq,interrupt[irq]);
+ if (irq < 8)
+ outb(inb_p(0x21) & ~(1<<irq),0x21);
+ else {
+ outb(inb_p(0x21) & ~(1<<2),0x21);
+ outb(inb_p(0xA1) & ~(1<<(irq-8)),0xA1);
+ }
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return 0;
+}
+
+int request_irq(unsigned int irq, void (*handler)(int))
+{
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sa.sa_flags = 0;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ return irqaction(irq,&sa);
+}
+
+void free_irq(unsigned int irq)
+{
+ struct sigaction * sa = irq + irq_sigaction;
+ unsigned long flags;
+
+ if (irq > 15) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+ if (!sa->sa_mask) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ if (irq < 8)
+ outb(inb_p(0x21) | (1<<irq),0x21);
+ else
+ outb(inb_p(0xA1) | (1<<(irq-8)),0xA1);
+ set_intr_gate(0x20+irq,bad_interrupt[irq]);
+ sa->sa_handler = NULL;
+ sa->sa_flags = 0;
+ sa->sa_mask = 0;
+ sa->sa_restorer = NULL;
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+}
+
+extern void do_coprocessor_error(long,long);
+
+static void math_error_irq(int cpl)
+{
+ outb(0,0xF0);
+ do_coprocessor_error(0,0);
+}
+
+static void no_action(int cpl) { }
+
+static struct sigaction ignore_IRQ = {
+ no_action,
+ 0,
+ SA_INTERRUPT,
+ NULL
+};
+
+void init_IRQ(void)
+{
+ int i;
+
+ for (i = 0; i < 16 ; i++)
+ set_intr_gate(0x20+i,bad_interrupt[i]);
+ if (irqaction(2,&ignore_IRQ))
+ printk("Unable to get IRQ2 for cascade\n");
+ if (request_irq(13,math_error_irq))
+ printk("Unable to get IRQ13 for math-error handler\n");
+}
--- /dev/null
+/*
+ * linux/kernel/itimer.c
+ *
+ * Copyright (C) 1992 Darren Senn
+ */
+
+/* These are all the functions necessary to implement itimers */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+
+static unsigned long tvtojiffies(struct timeval *value)
+{
+ return((unsigned long )value->tv_sec * HZ +
+ (unsigned long )(value->tv_usec + (1000000 / HZ - 1)) /
+ (1000000 / HZ));
+}
+
+static void jiffiestotv(unsigned long jiffies, struct timeval *value)
+{
+ value->tv_usec = (jiffies % HZ) * (1000000 / HZ);
+ value->tv_sec = jiffies / HZ;
+ return;
+}
+
+int _getitimer(int which, struct itimerval *value)
+{
+ register unsigned long val, interval;
+
+ switch (which) {
+ case ITIMER_REAL:
+ val = current->it_real_value;
+ interval = current->it_real_incr;
+ break;
+ case ITIMER_VIRTUAL:
+ val = current->it_virt_value;
+ interval = current->it_virt_incr;
+ break;
+ case ITIMER_PROF:
+ val = current->it_prof_value;
+ interval = current->it_prof_incr;
+ break;
+ default:
+ return(-EINVAL);
+ }
+ jiffiestotv(val, &value->it_value);
+ jiffiestotv(interval, &value->it_interval);
+ return(0);
+}
+
+int sys_getitimer(int which, struct itimerval *value)
+{
+ struct itimerval get_buffer;
+ int k;
+
+ if (!value)
+ return -EFAULT;
+ k = _getitimer(which, &get_buffer);
+ if (k < 0)
+ return k;
+ verify_area(value, sizeof(struct itimerval));
+ memcpy_tofs(value, &get_buffer, sizeof(get_buffer));
+ return 0;
+}
+
+int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+{
+ register unsigned long i, j;
+ int k;
+
+ i = tvtojiffies(&value->it_interval);
+ j = tvtojiffies(&value->it_value);
+ if (ovalue && (k = _getitimer(which, ovalue)) < 0)
+ return k;
+ switch (which) {
+ case ITIMER_REAL:
+ current->it_real_value = j;
+ current->it_real_incr = i;
+ break;
+ case ITIMER_VIRTUAL:
+ current->it_virt_value = j;
+ current->it_virt_incr = i;
+ break;
+ case ITIMER_PROF:
+ current->it_prof_value = j;
+ current->it_prof_incr = i;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+{
+ struct itimerval set_buffer, get_buffer;
+ int k;
+
+ if (!value)
+ memset((char *) &set_buffer, 0, sizeof(set_buffer));
+ else
+ memcpy_fromfs(&set_buffer, value, sizeof(set_buffer));
+ k = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
+ if (k < 0 || !ovalue)
+ return k;
+ verify_area(ovalue, sizeof(struct itimerval));
+ memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer));
+ return 0;
+}
# unless it's something special (ie not a .c file).
#
-AR =ar
-AS =as
-LD =ld
-LDFLAGS =-s -x
-CC =gcc -nostdinc -I../../include
-CPP =cpp -nostdinc -I../../include
-
.c.s:
- $(CC) $(CFLAGS) $(MATH_EMULATION) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) $(MATH_EMULATION) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) $(MATH_EMULATION) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
-OBJS = emulate.o error.o convert.o ea.o get_put.o \
- add.o mul.o div.o compare.o
+OBJS = emulate.o convert.o ea.o get_put.o \
+ add.o mul.o div.o compare.o sqrt.o
math.a: $(OBJS)
$(AR) rcs math.a $(OBJS)
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
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
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/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/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/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/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/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
-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
+add.o : add.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+compare.o : compare.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+convert.o : convert.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+div.o : div.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+ea.o : ea.c /usr/src/linux/include/linux/stddef.h /usr/src/linux/include/linux/math_emu.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/segment.h
+emulate.o : emulate.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+get_put.o : get_put.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/math_emu.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/asm/segment.h
+mul.o : mul.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
+sqrt.o : sqrt.c /usr/src/linux/include/linux/math_emu.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h
/*
* linux/kernel/math/add.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
/*
* linux/kernel/math/compare.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
/*
* linux/kernel/math/convert.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/math_emu.h>
/*
* linux/kernel/math/div.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
/*
* linux/kernel/math/ea.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Calculate the effective address.
*/
-#include <stddef.h>
-
+#include <linux/stddef.h>
#include <linux/math_emu.h>
+
#include <asm/segment.h>
static int __regoffset[] = {
char * ea(struct info * info, unsigned short code)
{
unsigned char mod,rm;
- long * tmp = &EAX;
+ long * tmp;
int offset = 0;
mod = (code >> 6) & 3;
EIP += 4;
break;
case 3:
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
}
I387.foo = offset;
I387.fos = 0x17;
/*
* linux/kernel/math/emulate.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
#ifdef KERNEL_MATH_EMULATION
-#include <signal.h>
+#include <linux/signal.h>
#define __ALIGNED_TEMP_REAL 1
#include <linux/math_emu.h>
return;
case 0x1d1: case 0x1d2: case 0x1d3:
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0x1e0:
ST(0).exponent ^= 0x8000;
return;
ST(0).exponent &= 0x7fff;
return;
case 0x1e2: case 0x1e3:
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0x1e4:
ftst(PST(0));
return;
case 0x1e5:
printk("fxam not implemented\n\r");
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0x1e6: case 0x1e7:
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0x1e8:
fpush();
ST(0) = CONST1;
ST(0) = CONSTZ;
return;
case 0x1ef:
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
+ case 0x1fa:
+ fsqrt(PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return;
case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
- case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
- case 0x1fd: case 0x1fe: case 0x1ff:
+ case 0x1f8: case 0x1f9: case 0x1fb: case 0x1fd:
+ case 0x1fe: case 0x1ff:
printk("%04x fxxx not implemented\n\r",code + 0xd800);
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0x1fc:
frndint(PST(0),&tmp);
real_to_real(&tmp,&ST(0));
return;
case 0xb8:
printk("ffree not implemented\n\r");
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
case 0xb9:
fxchg(&ST(0),&ST(code & 7));
return;
return;
case 0xf8:
printk("ffree not implemented\n\r");
- math_abort(info,1<<(SIGILL-1));
+ math_abort(info,SIGILL);
fpop();
return;
case 0xf9:
return;
}
printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
- math_abort(info,1<<(SIGFPE-1));
+ math_abort(info,SIGFPE);
}
void math_emulate(long ___false)
void __math_abort(struct info * info, unsigned int signal)
{
EIP = ORIG_EIP;
- current->signal |= signal;
+ send_sig(signal,current,1);
__asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
}
#else /* no math emulation */
-#include <signal.h>
+#include <linux/signal.h>
#include <linux/sched.h>
void math_emulate(long ___false)
{
- current->signal |= 1<<(SIGFPE-1);
+ send_sig(SIGFPE,current,1);
schedule();
}
+++ /dev/null
-/*
- * linux/kernel/math/error.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <signal.h>
-
-#include <linux/sched.h>
-
-void math_error(void)
-{
- if (last_task_used_math)
- last_task_used_math->signal |= 1<<(SIGFPE-1);
- __asm__("fnclex");
-}
/*
* linux/kernel/math/get_put.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* ints/reals/BCD etc. This is the only part that concerns itself with
* other than temporary real format. All other cals are strictly temp_real.
*/
-#include <signal.h>
-
+#include <linux/signal.h>
#include <linux/math_emu.h>
#include <linux/kernel.h>
#include <asm/segment.h>
/*
* linux/kernel/math/mul.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
--- /dev/null
+/*
+ * linux/kernel/math/sqrt.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * simple and stupid temporary real fsqrt() routine
+ *
+ * There are probably better ways to do this, but this should work ok.
+ */
+
+#include <linux/math_emu.h>
+#include <linux/sched.h>
+
+static void shift_right(int * c)
+{
+ __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
+ ::"r" ((long) c));
+}
+
+static int sqr64(unsigned long * a, unsigned long * b)
+{
+ unsigned long tmp[4];
+
+ __asm__("movl (%0),%%eax ; mull %%eax\n\t"
+ "movl %%eax,(%1) ; movl %%edx,4(%1)\n\t"
+ "movl 4(%0),%%eax ; mull %%eax\n\t"
+ "movl %%eax,8(%1) ; movl %%edx,12(%1)\n\t"
+ "movl (%0),%%eax ; mull 4(%0)\n\t"
+ "addl %%eax,%%eax ; adcl %%edx,%%edx\n\t"
+ "adcl $0,12(%1) ; addl %%eax,4(%1)\n\t"
+ "adcl %%edx,8(%1) ; adcl $0,12(%1)"
+ ::"b" ((long) a),"c" ((long) tmp)
+ :"ax","bx","cx","dx");
+ if (tmp[3] > b[3] ||
+ (tmp[3] == b[3] && (tmp[2] > b[2] ||
+ (tmp[2] == b[2] && (tmp[1] > b[1] ||
+ (tmp[1] == b[1] && tmp[0] > b[0]))))))
+ return 0;
+ return 1;
+}
+
+void fsqrt(const temp_real * s, temp_real * d)
+{
+ unsigned long src[4];
+ unsigned long res[2];
+ int exponent;
+ unsigned long mask, *c;
+ int i;
+
+ exponent = s->exponent;
+ src[0] = src[1] = 0;
+ src[2] = s->a;
+ src[3] = s->b;
+ d->exponent = 0;
+ d->a = d->b = 0;
+ if (!exponent) /* fsqrt(0.0) = 0.0 */
+ return;
+ if (!src[2] && !src[3])
+ return;
+ if (exponent & 0x8000) {
+ send_sig(SIGFPE,current,0);
+ return;
+ }
+ if (exponent & 1) {
+ shift_right(src);
+ exponent++;
+ }
+ exponent >>= 1;
+ exponent += 0x1fff;
+ c = res + 2;
+ mask = 0;
+ for (i = 64 ; i > 0 ; i--) {
+ if (!(mask >>= 1)) {
+ c--;
+ mask = 0x80000000;
+ }
+ res[0] = d->a; res[1] = d->b;
+ *c |= mask;
+ if (sqr64(res,src)) {
+ d->a = res[0];
+ d->b = res[1];
+ }
+ }
+ if (!d->a && !d->b)
+ return;
+ while (!(d->b & 0x80000000)) {
+ __asm__("addl %%eax,%%eax ; adcl %%edx,%%edx"
+ :"=a" (d->a),"=d" (d->b)
+ :"0" (d->a),"1" (d->b));
+ exponent--;
+ }
+ d->exponent = exponent;
+}
/*
* linux/kernel/mktime.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <time.h>
/*
* linux/kernel/panic.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
/*
* linux/kernel/printk.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 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 <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/errno.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 wait_queue * 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(GFP_KERNEL);
+ 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;
}
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <errno.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+
#include <asm/segment.h>
#include <asm/system.h>
-#include <sys/ptrace.h>
/*
* does not yet catch signals sent when the child dies.
*/
#define MAGICNUMBER 68
-void do_no_page(unsigned long, unsigned long, struct task_struct *);
-void write_verify(unsigned long);
-
/* change a pid into a task struct. */
-static inline int get_task(int pid)
+static inline struct task_struct * get_task(int pid)
{
int i;
- for (i = 0; i < NR_TASKS; i++) {
+ for (i = 1; i < NR_TASKS; i++) {
if (task[i] != NULL && (task[i]->pid == pid))
- return i;
+ return task[i];
}
- return -1;
+ return NULL;
}
/*
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;
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)) {
- write_verify(addr);
+ do_wp_page(0,addr,tsk,0);
goto repeat;
}
page &= 0xfffff000;
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- int childno;
- if (request == 0) {
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->flags & PF_PTRACED)
+ return -EPERM;
/* set the ptrace bit in the proccess flags. */
current->flags |= PF_PTRACED;
return 0;
}
-
- childno = get_task(pid);
-
- if (childno < 0)
+ if (!(child = get_task(pid)))
return -ESRCH;
- else
- child = task[childno];
-
- if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
- child->state != TASK_STOPPED)
+ if (request == PTRACE_ATTACH) {
+ long tmp;
+
+ if (child == current)
+ return -EPERM;
+ if ((!child->dumpable || (current->uid != child->euid) ||
+ (current->gid != child->egid)) && !suser())
+ return -EPERM;
+ /* the same process cannot be attached many times */
+ if (child->flags & PF_PTRACED)
+ return -EPERM;
+ child->flags |= PF_PTRACED;
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ if (child->state == TASK_INTERRUPTIBLE ||
+ child->state == TASK_STOPPED)
+ child->state = TASK_RUNNING;
+ child->signal = 0;
+ return 0;
+ }
+ if (!(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
+ return -ESRCH;
+ if (child->p_pptr != current)
return -ESRCH;
switch (request) {
/* when I and D space are seperate, these will need to be fixed. */
- case 1: /* read word at location addr. */
- case 2: {
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
int tmp,res;
- res = read_long(task[childno], addr, &tmp);
+ res = read_long(child, addr, &tmp);
if (res < 0)
return res;
verify_area((void *) data, 4);
}
/* read the word at location addr in the USER area. */
- case 3: {
+ case PTRACE_PEEKUSR: {
int tmp;
addr = addr >> 2; /* temporary hack. */
if (addr < 0 || addr >= 17)
}
/* when I and D space are seperate, this will have to be fixed. */
- case 4: /* write the word at location addr. */
- case 5:
- return write_long(task[childno],addr,data);
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ return write_long(child,addr,data);
- case 6: /* write the word at location addr in the USER area */
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
addr = addr >> 2; /* temproary hack. */
if (addr < 0 || addr >= 17)
return -EIO;
return -EIO;
return 0;
- case 7: { /* restart after signal. */
+ case PTRACE_CONT: { /* restart after signal. */
long tmp;
- child->signal=0;
+ child->signal = 0;
if (data > 0 && data <= NSIG)
child->signal = 1<<(data-1);
- child->state = 0;
+ child->state = TASK_RUNNING;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
* perhaps it should be put in the status that it want's to
* exit.
*/
- case 8: {
+ case PTRACE_KILL: {
long tmp;
- child->state = 0;
+ child->state = TASK_RUNNING;
child->signal = 1 << (SIGKILL-1);
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
return 0;
}
- case 9: { /* set the trap flag. */
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp;
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
- child->state = 0;
+ child->state = TASK_RUNNING;
child->signal = 0;
- if (data > 0 && data <NSIG)
+ if (data > 0 && data <= NSIG)
child->signal= 1<<(data-1);
/* give it a chance to run. */
return 0;
}
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ long tmp;
+
+ child->flags &= ~PF_PTRACED;
+ child->signal=0;
+ child->state = 0;
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ /* make sure the single step bit is not set. */
+ tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ return 0;
+ }
+
default:
return -EIO;
}
/*
* linux/kernel/sched.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* call functions (type getpid(), which just extracts a field from
* current-task
*/
+
+#define TIMER_IRQ 0
+
+#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
-#include <signal.h>
-#include <errno.h>
+int need_resched = 0;
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-void show_task(int nr,struct task_struct * p)
+static void show_task(int nr,struct task_struct * p)
{
int i,j = 4096-sizeof(struct task_struct);
- printk("%d: pid=%d, state=%d, father=%d, child=%d, ",nr,p->pid,
+ printk("%d: pid=%d, state=%d, father=%d, child=%d, ",(p == current)?-nr:nr,p->pid,
p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
i=0;
while (i<j && !((char *)(p+1))[i])
char stack[PAGE_SIZE];
};
-static union task_union init_task = {INIT_TASK,};
+static union task_union init_task = {INIT_TASK, };
unsigned long volatile jiffies=0;
unsigned long startup_time=0;
/* 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)
if ((*p)->state == TASK_INTERRUPTIBLE) {
(*p)->timeout = 0;
- (*p)->state = TASK_RUNNING;
+ wake_one_task(*p);
}
- if ((*p)->alarm && (*p)->alarm < jiffies) {
- (*p)->signal |= (1<<(SIGALRM-1));
- (*p)->alarm = 0;
- }
if (((*p)->signal & ~(*p)->blocked) &&
- (*p)->state==TASK_INTERRUPTIBLE)
- (*p)->state=TASK_RUNNING;
+ (*p)->state==TASK_INTERRUPTIBLE)
+ wake_one_task(*p);
}
/* this is the scheduler proper: */
return -EINTR;
}
-void wake_up(struct task_struct **p)
+void wake_one_task(struct task_struct * p)
+{
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter)
+ need_resched = 1;
+}
+
+/*
+ * wake_up doesn't wake up stopped processes - they have to be awakened
+ * with signals or similar.
+ */
+void wake_up(struct wait_queue **q)
{
- struct task_struct * wakeup_ptr, * tmp;
-
- if (p && *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)
+ struct wait_queue *tmp, *next;
+ struct task_struct * p;
+ unsigned long flags;
+
+ if (!q || !(next = *q))
+ return;
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ do {
+ tmp = next;
+ next = tmp->next;
+ if (p = tmp->task) {
+ if (p->state == TASK_ZOMBIE)
printk("wake_up: TASK_ZOMBIE\n");
- else
- wakeup_ptr->state = TASK_RUNNING;
- tmp = wakeup_ptr->next_wait;
- wakeup_ptr->next_wait = task[0];
- wakeup_ptr = tmp;
+ else if (p->state != TASK_STOPPED) {
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter)
+ need_resched = 1;
+ }
}
- }
+ tmp->next = NULL;
+ } while (next && next != *q);
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
-static inline void __sleep_on(struct task_struct **p, int state)
+static inline void __sleep_on(struct wait_queue **p, int state)
{
- unsigned int flags;
+ unsigned long flags;
if (!p)
return;
if (current == task[0])
panic("task[0] trying to sleep");
- __asm__("pushfl ; popl %0":"=r" (flags));
- current->next_wait = *p;
- task[0]->next_wait = NULL;
- *p = current;
+ if (current->wait.next)
+ printk("__sleep_on: wait->next exists\n");
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
current->state = state;
+ add_wait_queue(p,¤t->wait);
sti();
schedule();
- if (current->next_wait != task[0])
- wake_up(p);
- current->next_wait = NULL;
+ remove_wait_queue(p,¤t->wait);
__asm__("pushl %0 ; popfl"::"r" (flags));
}
-void interruptible_sleep_on(struct task_struct **p)
+void interruptible_sleep_on(struct wait_queue **p)
{
__sleep_on(p,TASK_INTERRUPTIBLE);
}
-void sleep_on(struct task_struct **p)
+void sleep_on(struct wait_queue **p)
{
__sleep_on(p,TASK_UNINTERRUPTIBLE);
}
* proper. They are here because the floppy needs a timer, and this
* was the easiest way of doing it.
*/
-static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
+static struct wait_queue * wait_motor[4] = {NULL,NULL,NULL,NULL};
static int mon_timer[4]={0,0,0,0};
static int moff_timer[4]={0,0,0,0};
unsigned char current_DOR = 0x0C;
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] = { 0, }; /* 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];
-void do_timer(long cpl)
+/*
+ * The int argument is really a (struct pt_regs *), in case the
+ * interrupt wants to know from where it was called. The timer
+ * irq uses this to decide if it should update the user or system
+ * times.
+ */
+static void do_timer(int regs)
{
unsigned long mask;
struct timer_struct *tp = timer_table+0;
+ struct task_struct ** task_p;
+ static int avg_cnt = 0;
+ jiffies++;
+ if (3 & ((struct pt_regs *) regs)->cs)
+ current->utime++;
+ else {
+ current->stime++;
+ /* Update ITIMER_VIRT for current task if not in a system call */
+ if (current->it_virt_value && !(--current->it_virt_value)) {
+ current->it_virt_value = current->it_virt_incr;
+ send_sig(SIGVTALRM,current,1);
+ }
+ }
+ if (--avg_cnt < 0) {
+ avg_cnt = 500;
+ update_avg();
+ }
+ if ((--current->counter)<=0) {
+ current->counter=0;
+ need_resched = 1;
+ }
+ /* Update ITIMER_REAL for every task */
+ for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--)
+ if (*task_p && (*task_p)->it_real_value
+ && !(--(*task_p)->it_real_value)) {
+ send_sig(SIGALRM,*task_p,1);
+ (*task_p)->it_real_value = (*task_p)->it_real_incr;
+ need_resched = 1;
+ }
+ /* Update ITIMER_PROF for the current task */
+ if (current->it_prof_value && !(--current->it_prof_value)) {
+ current->it_prof_value = current->it_prof_incr;
+ send_sig(SIGPROF,current,1);
+ }
for (mask = 1 ; mask ; tp++,mask += mask) {
if (mask > timer_active)
break;
continue;
timer_active &= ~mask;
tp->fn();
+ sti();
}
-
- if (cpl)
- current->utime++;
- else
- current->stime++;
-
if (next_timer) {
next_timer->jiffies--;
while (next_timer && next_timer->jiffies <= 0) {
}
if (current_DOR & 0xf0)
do_floppy_timer();
- if ((--current->counter)>0) return;
- current->counter=0;
- if (!cpl) return;
- schedule();
}
int sys_alarm(long seconds)
{
- int old = current->alarm;
-
- if (old)
- old = (old - jiffies) / HZ;
- current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
- return (old);
+ extern int _setitimer(int, struct itimerval *, struct itimerval *);
+ struct itimerval new, old;
+
+ new.it_interval.tv_sec = new.it_interval.tv_usec = 0;
+ new.it_value.tv_sec = seconds;
+ new.it_value.tv_usec = 0;
+ _setitimer(ITIMER_REAL, &new, &old);
+ return(old.it_value.tv_sec + (old.it_value.tv_usec / 1000000));
}
int sys_getpid(void)
{
if (increment < 0 && !suser())
return -EPERM;
- if (increment > current->priority)
+ if (increment >= current->priority)
increment = current->priority-1;
current->priority -= increment;
return 0;
panic("Struct sigaction MUST be 16 bytes");
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
+ set_system_gate(0x80,&system_call);
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1 ; i<NR_TASKS ; i++) {
task[i] = NULL;
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
- set_intr_gate(0x20,&timer_interrupt);
- outb(inb_p(0x21)&~0x01,0x21);
- set_system_gate(0x80,&system_call);
+ request_irq(TIMER_IRQ,do_timer);
}
/*
* linux/kernel/signal.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+
#include <asm/segment.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <errno.h>
-
-int send_sig (int, struct task_struct *, int);
-
+extern int core_dump(long signr,struct pt_regs * regs);
+
int sys_sgetmask()
{
return current->blocked;
return -EINVAL;
tmp.sa_handler = (void (*)(int)) handler;
tmp.sa_mask = 0;
- tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
+ tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
tmp.sa_restorer = (void (*)(void)) restorer;
handler = (long) current->sigaction[signum-1].sa_handler;
current->sigaction[signum-1] = tmp;
return 0;
}
-/*
- * Routine writes a core dump image in the current directory.
- * Currently not implemented.
- */
-int core_dump(long signr)
-{
- return(0); /* We didn't do a dump */
-}
-
extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
-int do_signal(long signr,long ebx, long ecx, long edx,
- long esi, long edi, long ebp, long eax,
- long ds, long es, long fs, long gs,
- long orig_eax,
- long eip, long cs, long eflags,
- unsigned long * esp, long ss)
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(long signr,struct pt_regs * regs)
{
unsigned long sa_handler;
- long old_eip=eip;
+ long old_eip = regs->eip;
struct sigaction * sa = current->sigaction + signr - 1;
int longs;
-
unsigned long * tmp_esp;
#ifdef notdef
printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n",
- current->pid, signr, eax, orig_eax,
+ current->pid, signr, regs->eax, regs->orig_eax,
sa->sa_flags & SA_INTERRUPT);
#endif
- if ((orig_eax != -1) &&
- ((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) {
- if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
- signr < SIGCONT || signr > SIGTTOU))
- *(&eax) = -EINTR;
+ sa_handler = (unsigned long) sa->sa_handler;
+ if ((regs->orig_eax != -1) &&
+ ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
+ if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
+ (sa->sa_flags & SA_INTERRUPT))
+ regs->eax = -EINTR;
else {
- *(&eax) = orig_eax;
- *(&eip) = old_eip -= 2;
+ regs->eax = regs->orig_eax;
+ regs->eip = old_eip -= 2;
}
}
- sa_handler = (unsigned long) sa->sa_handler;
if (sa_handler==1) {
/* check for SIGCHLD: it's special */
if (signr == SIGCHLD)
return(1); /* Ignore, see if there are more signals... */
}
if (!sa_handler) {
+ if (current->pid == 1)
+ return 1;
switch (signr) {
case SIGCONT:
case SIGCHLD:
current->exit_code = signr;
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- send_sig(SIGCHLD, current->p_pptr, 1);
-/* current->p_pptr->signal |= (1<<(SIGCHLD-1));*/
-
+ send_sig(SIGCHLD, current->p_pptr, 1);
return(1); /* Reschedule another event */
case SIGQUIT:
case SIGIOT:
case SIGFPE:
case SIGSEGV:
- if (core_dump(signr))
+ if (core_dump(signr,regs))
do_exit(signr|0x80);
/* fall through */
default:
*/
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- *(&eip) = sa_handler;
- longs = (sa->sa_flags & SA_NOMASK)?7:8;
- *(&esp) -= longs;
- verify_area(esp,longs*4);
- tmp_esp=esp;
+ regs->eip = sa_handler;
+ longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
+ regs->esp -= longs;
+ tmp_esp = (unsigned long *) regs->esp;
+ verify_area(tmp_esp,longs);
put_fs_long((long) sa->sa_restorer,tmp_esp++);
put_fs_long(signr,tmp_esp++);
if (!(sa->sa_flags & SA_NOMASK))
put_fs_long(current->blocked,tmp_esp++);
- put_fs_long(eax,tmp_esp++);
- put_fs_long(ecx,tmp_esp++);
- put_fs_long(edx,tmp_esp++);
- put_fs_long(eflags,tmp_esp++);
+ put_fs_long(regs->eax,tmp_esp++);
+ put_fs_long(regs->ecx,tmp_esp++);
+ put_fs_long(regs->edx,tmp_esp++);
+ put_fs_long(regs->eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
current->blocked |= sa->sa_mask;
/* force a supervisor-mode page-in of the signal handler to reduce races */
/*
* linux/kernel/sys.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <errno.h>
-
+#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/config.h>
-#include <asm/segment.h>
-#include <sys/times.h>
-#include <sys/utsname.h>
-#include <sys/param.h>
-#include <sys/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/param.h>
+#include <linux/resource.h>
#include <linux/string.h>
+#include <asm/segment.h>
+
/*
* this indicates wether you can reboot with ctrl-alt-del: the deault is yes
*/
extern int session_of_pgrp(int pgrp);
-int sys_getpriority()
+#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)
{
- return -ENOSYS;
+ 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_setpriority()
+int sys_getpriority(int which, int who)
{
- return -ENOSYS;
+ 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()
{
if (C_A_D)
hard_reset_now();
+ else
+ send_sig(SIGINT,task[1],1);
}
*/
int sys_setregid(int rgid, int egid)
{
- if (rgid>0) {
+ if (rgid >= 0) {
if ((current->gid == rgid) ||
suser())
current->gid = rgid;
else
return(-EPERM);
}
- if (egid>0) {
+ if (egid >= 0) {
if ((current->gid == egid) ||
(current->egid == egid) ||
suser()) {
{
int old_ruid = current->uid;
- if (ruid>0) {
+ if (ruid >= 0) {
if ((current->euid==ruid) ||
- (old_ruid == ruid) ||
+ (old_ruid == ruid) ||
suser())
current->uid = ruid;
else
return(-EPERM);
}
- if (euid>0) {
+ if (euid >= 0) {
if ((old_ruid == euid) ||
- (current->euid == euid) ||
+ (current->euid == euid) ||
suser()) {
current->euid = euid;
current->suid = euid;
return 0;
}
-static struct utsname thisname = {
+static struct new_utsname thisname = {
UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
};
-int sys_uname(struct utsname * name)
+int sys_newuname(struct new_utsname * name)
{
- int i;
+ if (!name)
+ return -EFAULT;
+ verify_area(name, sizeof *name);
+ memcpy_tofs(name,&thisname,sizeof *name);
+ return 0;
+}
+int sys_uname(struct old_utsname * name)
+{
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);
+ memcpy_tofs(&name->sysname,&thisname.sysname,__OLD_UTS_LEN);
+ put_fs_byte(0,name->sysname+__OLD_UTS_LEN);
+ memcpy_tofs(&name->nodename,&thisname.nodename,__OLD_UTS_LEN);
+ put_fs_byte(0,name->nodename+__OLD_UTS_LEN);
+ memcpy_tofs(&name->release,&thisname.release,__OLD_UTS_LEN);
+ put_fs_byte(0,name->release+__OLD_UTS_LEN);
+ memcpy_tofs(&name->version,&thisname.version,__OLD_UTS_LEN);
+ put_fs_byte(0,name->version+__OLD_UTS_LEN);
+ memcpy_tofs(&name->machine,&thisname.machine,__OLD_UTS_LEN);
+ put_fs_byte(0,name->machine+__OLD_UTS_LEN);
return 0;
}
if (!suser())
return -EPERM;
- if (len > MAXHOSTNAMELEN)
+ if (len > __NEW_UTS_LEN)
return -EINVAL;
for (i=0; i < len; i++) {
if ((thisname.nodename[i] = get_fs_byte(name+i)) == 0)
- break;
- }
- if (thisname.nodename[i]) {
- thisname.nodename[i>MAXHOSTNAMELEN ? MAXHOSTNAMELEN : i] = 0;
+ return 0;
}
+ thisname.nodename[i] = 0;
return 0;
}
/*
* linux/kernel/sys_call.S
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* 40(%esp) - %oldss
*/
-SIG_CHLD = 17
-
EBX = 0x00
ECX = 0x04
EDX = 0x08
* 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 _system_call,_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 _general_protection,_reserved
.globl _alignment_check,_page_fault
-.globl _keyboard_interrupt
+.globl ret_from_sys_call
#define SAVE_ALL \
cld; \
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,$0x20
- jmp 1f; \
-1: jmp 1f; \
-1: outb %al,$0xA0
-
-#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
+ pushl %eax # save orig_eax
SAVE_ALL
+ movl $-ENOSYS,EAX(%esp)
cmpl _NR_syscalls,%eax
- jae bad_sys_call
+ jae ret_from_sys_call
call _sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # save the return value
ret_from_sys_call:
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
+1: cmpl $0,_need_resched
+ jne reschedule
+ movl _current,%eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
+ movl $1,_need_resched
+ cmpl _task,%eax # task[0] cannot have signals
+ je 2f
+ movl $0,_need_resched
movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
je 2f
btrl %ecx,%ebx
movl %ebx,signal(%eax)
+ movl %esp,%ebx
+ pushl %ebx
incl %ecx
pushl %ecx
call _do_signal
popl %ecx
+ popl %ebx
testl %eax, %eax
jne 1b # see if we need to switch tasks, or do more signals
2: popl %ebx
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(2)
- sti
- call _do_keyboard
- cli
- UNBLK_FIRST(2)
- jmp ret_from_sys_call
-
-.align 2
-_timer_interrupt:
- pushl $-1 # mark this as an int
- SAVE_ALL
- 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.
addl $8,%esp
jmp ret_from_sys_call
+.align 2
+_coprocessor_error:
+ pushl $0
+ pushl $_do_coprocessor_error
+ jmp error_code
+
+.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
+
_debug:
pushl $0
- pushl $_do_int3 # _do_debug
+ pushl $_do_debug
jmp error_code
_nmi:
/*
* linux/kernel/traps.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
*/
-#include <linux/string.h>
-
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
-#include <errno.h>
-
#define get_seg_byte(seg,addr) ({ \
register char __res; \
void page_fault(void);
void coprocessor_error(void);
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)
+static void die_if_kernel(char * str,long esp_ptr,long nr)
{
long * esp = (long *) esp_ptr;
int i;
+ if ((0xffff & esp[1]) == 0xf)
+ return;
printk("%s: %04x\n\r",str,nr&0xffff);
printk("EIP: %04x:%p\nEFLAGS: %p\n", 0xffff & esp[1],esp[0],esp[2]);
- if ((0xffff & esp[1]) == 0xf)
- printk("ESP: %04x:%p\n",0xffff & esp[4],esp[3]);
printk("fs: %04x\n",_fs());
printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
- if ((0xffff & esp[1]) == 0xf) {
- printk("Stack: ");
- for (i=0;i<4;i++)
- printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
- printk("\n");
- }
str(i);
printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i);
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 */
+ do_exit(SIGSEGV);
}
void do_double_fault(long esp, long error_code)
{
- die("double fault",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("double fault",esp,error_code);
}
void do_general_protection(long esp, long error_code)
{
- die("general protection",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("general protection",esp,error_code);
}
void do_alignment_check(long esp, long error_code)
{
- die("alignment check",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("alignment check",esp,error_code);
}
void do_divide_error(long esp, long error_code)
{
- die("divide error",esp,error_code);
+ send_sig(SIGFPE, current, 1);
+ die_if_kernel("divide error",esp,error_code);
}
void do_int3(long esp, long error_code)
{
- send_sig(SIGTRAP, current, 0);
+ send_sig(SIGTRAP, current, 1);
+ die_if_kernel("int3",esp,error_code);
}
void do_nmi(long esp, long error_code)
{
- die("nmi",esp,error_code);
+ printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
}
void do_debug(long esp, long error_code)
{
- send_sig(SIGTRAP, current, 0);
+ send_sig(SIGTRAP, current, 1);
+ die_if_kernel("debug",esp,error_code);
}
void do_overflow(long esp, long error_code)
{
- die("overflow",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("overflow",esp,error_code);
}
void do_bounds(long esp, long error_code)
{
- die("bounds",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("bounds",esp,error_code);
}
void do_invalid_op(long esp, long error_code)
{
- die("invalid operand",esp,error_code);
+ send_sig(SIGILL, current, 1);
+ die_if_kernel("invalid operand",esp,error_code);
}
void do_device_not_available(long esp, long error_code)
{
- die("device not available",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("device not available",esp,error_code);
}
void do_coprocessor_segment_overrun(long esp, long error_code)
{
- die("coprocessor segment overrun",esp,error_code);
+ send_sig(SIGFPE, last_task_used_math, 1);
+ die_if_kernel("coprocessor segment overrun",esp,error_code);
}
void do_invalid_TSS(long esp,long error_code)
{
- die("invalid TSS",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("invalid TSS",esp,error_code);
}
void do_segment_not_present(long esp,long error_code)
{
- die("segment not present",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("segment not present",esp,error_code);
}
void do_stack_segment(long esp,long error_code)
{
- die("stack segment",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("stack segment",esp,error_code);
}
void do_coprocessor_error(long esp, long error_code)
{
- if (last_task_used_math != current)
- return;
- die("coprocessor error",esp,error_code);
+ send_sig(SIGFPE, last_task_used_math, 1);
+ __asm__("fnclex");
}
void do_reserved(long esp, long error_code)
{
- die("reserved (15,17-47) error",esp,error_code);
+ send_sig(SIGSEGV, current, 1);
+ die_if_kernel("reserved (15,17-47) error",esp,error_code);
}
void trap_init(void)
set_trap_gate(17,&alignment_check);
for (i=18;i<48;i++)
set_trap_gate(i,&reserved);
- set_trap_gate(45,&irq13);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xdf,0xA1);
- set_trap_gate(39,¶llel_interrupt);
}
/*
* linux/kernel/vsprintf.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
*/
#include <stdarg.h>
+#include <linux/types.h>
#include <linux/string.h>
/* we use this so that we can do without the ctype library */
# unless it's something special (ie not a .c file).
#
-AR =ar
-AS =as
-LD =ld
-LDFLAGS =-s -x
-CC =gcc -nostdinc -I../include
-CPP =gcc -E -nostdinc -I../include
-
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \
execve.o wait.o string.o malloc.o
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
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
### Dependencies:
-_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
-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
-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
-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/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/sys/param.h ../include/sys/resource.h ../include/utime.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/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/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
-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/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
+_exit.o : _exit.c /usr/src/linux/include/linux/unistd.h
+close.o : close.c /usr/src/linux/include/linux/unistd.h
+ctype.o : ctype.c /usr/src/linux/include/linux/ctype.h
+dup.o : dup.c /usr/src/linux/include/linux/unistd.h
+errno.o : errno.c
+execve.o : execve.c /usr/src/linux/include/linux/unistd.h
+malloc.o : malloc.c /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/mm.h \
+ /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
+ /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
+ /usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
+ /usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/asm/system.h
+open.o : open.c /usr/src/linux/include/linux/unistd.h /usr/src/linux/include/stdarg.h
+setsid.o : setsid.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/unistd.h
+string.o : string.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/string.h
+wait.o : wait.c /usr/src/linux/include/linux/unistd.h /usr/src/linux/include/linux/types.h
+write.o : write.c /usr/src/linux/include/linux/unistd.h /usr/src/linux/include/linux/types.h
/*
* linux/lib/_exit.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
volatile void _exit(int exit_code)
{
+fake_volatile:
__asm__("movl %1,%%ebx\n\t"
"int $0x80"::"a" (__NR_exit),"g" (exit_code));
+ goto fake_volatile;
}
/*
* linux/lib/close.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
_syscall1(int,close,int,fd)
+
/*
* linux/lib/ctype.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/ctype.h>
/*
* linux/lib/dup.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
_syscall1(int,dup,int,fd)
+
/*
* linux/lib/errno.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
int errno;
/*
* linux/lib/execve.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
_syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+
struct bucket_desc *bdesc, *first;
int i;
- first = bdesc = (struct bucket_desc *) get_free_page();
+ first = bdesc = (struct bucket_desc *) get_free_page(GFP_KERNEL);
if (!bdesc)
panic("Out of memory in init_bucket_desc()");
for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) {
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
bdesc->bucket_size = bdir->size;
- bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
+ bdesc->page = bdesc->freeptr = (void *) cp = get_free_page(GFP_KERNEL);
if (!cp)
panic("Out of memory in kernel malloc()");
/* Set up the chain of free objects */
/*
* linux/lib/open.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
#include <stdarg.h>
int open(const char * filename, int flag, ...)
/*
* linux/lib/setsid.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
_syscall0(pid_t,setsid)
+
/*
* linux/lib/string.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#ifndef __GNUC__
#error I want gcc!
#endif
+#include <linux/types.h>
+
#define extern
#define inline
#define __LIBRARY__
/*
* linux/lib/wait.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
-#include <sys/wait.h>
+#include <linux/unistd.h>
+#include <linux/types.h>
_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
{
return waitpid(-1,wait_stat,0);
}
+
/*
* linux/lib/write.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
#define __LIBRARY__
-#include <unistd.h>
+#include <linux/unistd.h>
+#include <linux/types.h>
_syscall3(int,write,int,fd,const char *,buf,off_t,count)
+
#
# Note 2! The CFLAGS definition is now in the main makefile...
-AS =as
-AR =ar
-LD =ld
-CC =gcc -nostdinc -I../include
-CPP =cpp -nostdinc -I../include
-
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S $<
OBJS = memory.o swap.o mmap.o
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
- (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ for i in *.c;do $(CPP) -M $$i;done >> tmp_make
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 \
- ../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
+memory.o : memory.c /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/string.h
+mmap.o : mmap.c /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h \
+ /usr/src/linux/include/sys/mman.h
+swap.o : swap.c /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h
/*
* linux/mm/memory.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* 20.12.91 - Ok, making the swap-device changeable like the root.
*/
-#include <signal.h>
-
#include <asm/system.h>
+#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
+#include <linux/string.h>
#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
current->start_code + current->end_code)
-unsigned long HIGH_MEMORY = 0;
+unsigned long low_memory = 0;
+unsigned long high_memory = 0;
+unsigned long paging_pages = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
-#define CHECK_LAST_NR 16
-
-static unsigned long last_pages[CHECK_LAST_NR] = { 0, };
+unsigned char * mem_map = NULL;
-unsigned char mem_map [ PAGING_PAGES ] = {0,};
+/*
+ * oom() prints a message (so that the user knows why the process died),
+ * and gives the process an untrappable SIGSEGV.
+ */
+void oom(struct task_struct * task)
+{
+ printk("\nout of memory\n");
+ task->sigaction[SIGSEGV-1].sa_handler = NULL;
+ task->blocked &= ~(1<<(SIGSEGV-1));
+ send_sig(SIGSEGV,task,1);
+}
+int nr_free_pages = 0;
/*
* Free a page of memory at physical address 'addr'. Used by
* 'free_page_tables()'
*/
void free_page(unsigned long addr)
{
- if (addr < LOW_MEM) return;
- if (addr < HIGH_MEMORY) {
- addr -= LOW_MEM;
- addr >>= 12;
- if (mem_map[addr]--)
+ unsigned long i;
+
+ if (addr < low_memory)
+ return;
+ if (addr < high_memory) {
+ i = addr - low_memory;
+ i >>= 12;
+ if (mem_map[i] == 1)
+ ++nr_free_pages;
+ if (mem_map[i]--)
return;
- mem_map[addr]=0;
+ mem_map[i] = 0;
}
- printk("trying to free free page: memory probably corrupted");
+ printk("trying to free free page (%08x): memory probably corrupted\n",addr);
}
/*
free_page(0xfffff000 & page_dir);
}
invalidate();
- for (page = 0; page < CHECK_LAST_NR ; page++)
- last_pages[page] = 0;
return 0;
}
continue;
}
from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
- if (!(to_page_table = (unsigned long *) get_free_page()))
+ if (!(to_page_table = (unsigned long *) get_free_page(GFP_KERNEL)))
return -1; /* Out of memory, see freeing */
*to_dir = ((unsigned long) to_page_table) | 7;
nr = (from==0)?0xA0:1024;
for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
+repeat:
this_page = *from_page_table;
if (!this_page)
continue;
if (!(1 & this_page)) {
- if (!(new_page = get_free_page()))
+ if (!(new_page = get_free_page(GFP_KERNEL)))
return -1;
++current->rss;
read_swap_page(this_page>>1, (char *) new_page);
+ if (*from_page_table != this_page) {
+ free_page(new_page);
+ goto repeat;
+ }
*to_page_table = this_page;
*from_page_table = new_page | (PAGE_DIRTY | 7);
continue;
}
this_page &= ~2;
*to_page_table = this_page;
- if (this_page > LOW_MEM) {
+ if (this_page > low_memory) {
*from_page_table = this_page;
- this_page -= LOW_MEM;
+ this_page -= low_memory;
this_page >>= 12;
- mem_map[this_page]++;
+ if (!mem_map[this_page]++)
+ --nr_free_pages;
}
}
}
* a more complete version of free_page_tables which performs with page
* granularity.
*/
-int
-unmap_page_range(unsigned long from, unsigned long size)
+int unmap_page_range(unsigned long from, unsigned long size)
{
unsigned long page, page_dir;
unsigned long *page_table, *dir;
}
}
invalidate();
- for (page = 0; page < CHECK_LAST_NR ; page++)
- last_pages[page] = 0;
return 0;
}
* write/copy: yes/copy copy/copy
* exec: yes yes
*/
-int
-remap_page_range(unsigned long from, unsigned long to, unsigned long size,
+int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
int permiss)
{
unsigned long *page_table, *dir;
unsigned long poff, pcnt;
+ unsigned long page;
if ((from & 0xfff) || (to & 0xfff))
panic("remap_page_range called with wrong alignment");
while (size > 0) {
if (!(1 & *dir)) {
- if (!(page_table = (unsigned long *)get_free_page())) {
+ if (!(page_table = (unsigned long *)get_free_page(GFP_KERNEL))) {
invalidate();
return -1;
}
if (permiss & 4)
mask |= 1;
- if (*page_table) {
+ if (page = *page_table) {
+ *page_table = 0;
--current->rss;
- if (1 & *page_table)
- free_page(0xfffff000 & *page_table);
+ if (1 & page)
+ free_page(0xfffff000 & page);
else
- swap_free(*page_table >> 1);
+ swap_free(page >> 1);
}
/*
* when the page is referenced. current assumptions
* cause it to be treated as demand allocation.
*/
- if (mask == 4 || to >= HIGH_MEMORY)
+ if (mask == 4 || to >= high_memory)
*page_table++ = 0; /* not present */
else {
++current->rss;
*page_table++ = (to | mask);
- if (to > LOW_MEM) {
+ if (to > low_memory) {
unsigned long frame;
- frame = to - LOW_MEM;
+ frame = to - low_memory;
frame >>= 12;
- mem_map[frame]++;
+ if (!mem_map[frame]++)
+ --nr_free_pages;
}
}
to += PAGE_SIZE;
pcnt = (size > 1024 ? 1024 : size);
}
invalidate();
- for (to = 0; to < CHECK_LAST_NR ; to++)
- last_pages[to] = 0;
return 0;
}
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page >= HIGH_MEMORY) {
+ if (page >= high_memory) {
printk("put_page: trying to put page %p at %p\n",page,address);
return 0;
}
- if (mem_map[(page-LOW_MEM)>>12] != 1) {
- printk("mem_map disagrees with %p at %p\n",page,address);
+ if (page >= low_memory && mem_map[(page-low_memory)>>12] != 1) {
+ printk("put_page: mem_map disagrees with %p at %p\n",page,address);
return 0;
}
page_table = (unsigned long *) ((address>>20) & 0xffc);
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);
else {
- if (!(tmp=get_free_page()))
- return 0;
+ tmp = get_free_page(GFP_KERNEL);
+ if (!tmp) {
+ oom(current);
+ tmp = BAD_PAGETABLE;
+ }
*page_table = tmp | 7;
- page_table = (unsigned long *) tmp;
+ return 0;
}
page_table += (address>>12) & 0x3ff;
if (*page_table) {
/* NOTE !!! This uses the fact that _pg_dir=0 */
- if (page < LOW_MEM || page >= HIGH_MEMORY)
+ if (page < low_memory || page >= high_memory)
printk("put_dirty_page: trying to put page %p at %p\n",page,address);
- if (mem_map[(page-LOW_MEM)>>12] != 1)
+ if (mem_map[(page-low_memory)>>12] != 1)
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) ((address>>20) & 0xffc);
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);
else {
- if (!(tmp=get_free_page()))
+ if (!(tmp=get_free_page(GFP_KERNEL)))
return 0;
*page_table = tmp|7;
page_table = (unsigned long *) tmp;
return page;
}
-void un_wp_page(unsigned long * table_entry)
+static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
{
unsigned long old_page;
unsigned long new_page = 0;
repeat:
old_page = *table_entry;
- dirty = old_page & PAGE_DIRTY;
if (!(old_page & 1)) {
if (new_page)
free_page(new_page);
return;
}
+ dirty = old_page & PAGE_DIRTY;
old_page &= 0xfffff000;
- if (old_page >= HIGH_MEMORY) {
+ if (old_page >= high_memory) {
if (new_page)
free_page(new_page);
printk("bad page address\n\r");
- do_exit(SIGSEGV);
+ send_sig(SIGSEGV, task, 1);
+ *table_entry = BAD_PAGE | 7;
+ return;
}
- if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
+ if (old_page >= low_memory && mem_map[MAP_NR(old_page)]==1) {
*table_entry |= 2;
invalidate();
if (new_page)
free_page(new_page);
return;
}
- if (!new_page) {
- if (!(new_page=get_free_page()))
- oom();
+ if (!new_page && (new_page=get_free_page(GFP_KERNEL)))
goto repeat;
+ if (new_page)
+ copy_page(old_page,new_page);
+ else {
+ new_page = BAD_PAGE;
+ send_sig(SIGSEGV,task,1);
}
- copy_page(old_page,new_page);
*table_entry = new_page | dirty | 7;
free_page(old_page);
invalidate();
*
* If it's in code space we exit with a segment error.
*/
-void do_wp_page(unsigned long error_code,unsigned long address)
+void do_wp_page(unsigned long error_code, unsigned long address,
+ struct task_struct * tsk, unsigned long user_esp)
{
+ unsigned long pde, pte, page;
+
+ pde = (address>>20) & 0xffc;
+ pte = *(unsigned long *) pde;
+ if ((pte & 3) != 3) {
+ printk("do_wp_page: bogus page-table at address %08x (%08x)\n",address,pte);
+ *(unsigned long *) pde = BAD_PAGETABLE | 7;
+ send_sig(SIGSEGV, tsk, 1);
+ return;
+ }
if (address < TASK_SIZE) {
- printk("\n\rBAD! KERNEL MEMORY WP-ERR!\n\r");
- do_exit(SIGSEGV);
+ printk("do_wp_page: kernel WP error at address %08x (%08x)\n",address,pte);
+ *(unsigned long *) pde = BAD_PAGETABLE | 7;
+ send_sig(SIGSEGV, tsk, 1);
+ return;
}
- if (address - current->start_code >= TASK_SIZE) {
- printk("Bad things happen: page error in do_wp_page\n\r");
- do_exit(SIGSEGV);
+ pte &= 0xfffff000;
+ pte += (address>>10) & 0xffc;
+ page = *(unsigned long *) pte;
+ if ((page & 3) != 1) {
+ printk("do_wp_page: bogus page at address %08x (%08x)\n",address,page);
+ *(unsigned long *) pte = BAD_PAGE | 7;
+ send_sig(SIGSEGV, tsk, 1);
+ return;
}
++current->min_flt;
- un_wp_page((unsigned long *)
- (((address>>10) & 0xffc) + (0xfffff000 &
- *((unsigned long *) ((address>>20) &0xffc)))));
+ un_wp_page((unsigned long *) pte, tsk);
}
void write_verify(unsigned long address)
{
unsigned long page;
- if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
+ page = *(unsigned long *) ((address>>20) & 0xffc);
+ if (!(page & PAGE_PRESENT))
return;
page &= 0xfffff000;
page += ((address>>10) & 0xffc);
if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */
- un_wp_page((unsigned long *) page);
+ un_wp_page((unsigned long *) page, current);
return;
}
-void get_empty_page(unsigned long address)
+static void get_empty_page(unsigned long address)
{
unsigned long tmp;
- if (!(tmp=get_free_page()) || !put_page(tmp,address)) {
- free_page(tmp); /* 0 is ok - ignored */
- oom();
+ tmp = get_free_page(GFP_KERNEL);
+ if (!tmp) {
+ oom(current);
+ tmp = BAD_PAGE;
}
+ if (!put_page(tmp,address))
+ free_page(tmp);
}
/*
if ((phys_addr & 0x41) != 0x01)
return 0;
phys_addr &= 0xfffff000;
- if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)
+ if (phys_addr >= high_memory || phys_addr < low_memory)
return 0;
to = *(unsigned long *) to_page;
if (!(to & 1)) {
- if (to = get_free_page())
- *(unsigned long *) to_page = to | 7;
- else
- oom();
+ to = get_free_page(GFP_KERNEL);
+ if (!to)
+ return 0;
+ *(unsigned long *) to_page = to | 7;
}
to &= 0xfffff000;
to_page = to + ((address>>10) & 0xffc);
*(unsigned long *) from_page &= ~2;
*(unsigned long *) to_page = *(unsigned long *) from_page;
invalidate();
- phys_addr -= LOW_MEM;
+ phys_addr -= low_memory;
phys_addr >>= 12;
- mem_map[phys_addr]++;
+ if (!mem_map[phys_addr]++)
+ --nr_free_pages;
return 1;
}
struct task_struct ** p;
int i;
- if (inode->i_count < 2 || !inode)
+ if (!inode || inode->i_count < 2)
return 0;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
return 0;
}
+/*
+ * fill in an empty page-table if none exists
+ */
+static unsigned long get_empty_pgtable(unsigned long * p)
+{
+ unsigned long page = 0;
+
+repeat:
+ if (1 & *p) {
+ free_page(page);
+ return *p;
+ }
+ if (*p) {
+ printk("get_empty_pgtable: bad page-directory entry \n");
+ *p = 0;
+ }
+ if (page) {
+ *p = page | 7;
+ return *p;
+ }
+ if (page = get_free_page(GFP_KERNEL))
+ goto repeat;
+ oom(current);
+ *p = BAD_PAGETABLE | 7;
+ return 0;
+}
+
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 */
- for (i = 0; i < CHECK_LAST_NR; i++)
- if ((address & 0xfffff000) == last_pages[i]) {
- current->counter = 0;
- schedule();
- }
- last_checked++;
- if (last_checked >= CHECK_LAST_NR)
- last_checked = 0;
- last_pages[last_checked] = address & 0xfffff000;
if (address < TASK_SIZE) {
printk("\n\rBAD!! KERNEL PAGE MISSING\n\r");
do_exit(SIGSEGV);
printk("Bad things happen: nonexistent page error in do_no_page\n\r");
do_exit(SIGSEGV);
}
+ page = get_empty_pgtable((unsigned long *) ((address >> 20) & 0xffc));
+ if (!page)
+ return;
+ 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 = NULL;
- block = 1;
- i = tsk->numlibraries;
- while (i-- > 0) {
- if (tmp < (tsk->libraries[i].start +
- tsk->libraries[i].length)) {
- inode = tsk->libraries[i].library;
- block = 1 + (tmp - tsk->libraries[i].start) /
- BLOCK_SIZE;
- break;
- }
- }
- } 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 < LIBRARY_OFFSET && 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)
return;
}
++tsk->maj_flt;
- if (!(page = get_free_page()))
- oom();
-/* remember that 1 block is used for header */
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ oom(current);
+ put_page(BAD_PAGE,address);
+ return;
+ }
for (i=0 ; i<4 ; block++,i++)
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
if (i>4095)
i = 0;
tmp = page + 4096;
- while (i-- > 0) {
+ while (i--) {
tmp--;
*(char *)tmp = 0;
}
if (put_page(page,address))
return;
free_page(page);
- oom();
-}
-
-void mem_init(long start_mem, long end_mem)
-{
- int i;
-
- swap_device = 0;
- swap_file = NULL;
- HIGH_MEMORY = end_mem;
- for (i=0 ; i<PAGING_PAGES ; i++)
- mem_map[i] = USED;
- i = MAP_NR(start_mem);
- end_mem -= start_mem;
- end_mem >>= 12;
- while (end_mem-->0)
- mem_map[i++]=0;
+ oom(current);
}
void show_mem(void)
unsigned long * pg_tbl;
printk("Mem-info:\n\r");
- for(i=0 ; i<PAGING_PAGES ; i++) {
- if (mem_map[i] == USED)
- continue;
+ printk("Free pages: %6d\n",nr_free_pages);
+ printk("Buffer heads: %6d\n",nr_buffer_heads);
+ printk("Buffer blocks: %6d\n",nr_buffers);
+ for (i = 0 ; i < paging_pages ; i++) {
total++;
if (!mem_map[i])
free++;
}
printk("%d free pages of %d\n\r",free,total);
printk("%d pages shared\n\r",shared);
+ printk("%d free pages via nr_free_pages\n\r", nr_free_pages);
k = 0;
for(i=4 ; i<1024 ;) {
if (1&pg_dir[i]) {
- if (pg_dir[i]>HIGH_MEMORY) {
+ if (pg_dir[i]>high_memory) {
printk("page directory[%d]: %08X\n\r",
i,pg_dir[i]);
i++;
continue;
}
- if (pg_dir[i]>LOW_MEM)
+ if (pg_dir[i]>low_memory)
free++,k++;
pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]);
for(j=0 ; j<1024 ; j++)
- if ((pg_tbl[j]&1) && pg_tbl[j]>LOW_MEM)
- if (pg_tbl[j]>HIGH_MEMORY)
+ if ((pg_tbl[j]&1) && pg_tbl[j]>low_memory)
+ if (pg_tbl[j]>high_memory)
printk("page_dir[%d][%d]: %08X\n\r",
i,j, pg_tbl[j]);
else
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);
+ do_wp_page(error_code, address, current, user_esp);
return;
}
}
+
+unsigned long mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+ end_mem &= 0xfffff000;
+ high_memory = end_mem;
+ mem_map = (char *) start_mem;
+ paging_pages = (end_mem - start_mem) >> 12;
+ start_mem += paging_pages;
+ start_mem += 0xfff;
+ start_mem &= 0xfffff000;
+ low_memory = start_mem;
+ paging_pages = (high_memory - low_memory) >> 12;
+ swap_device = 0;
+ swap_file = NULL;
+ memset(mem_map,0,paging_pages);
+ nr_free_pages = paging_pages;
+ return start_mem;
+}
*
* Written by obz.
*/
-#include <sys/stat.h>
+#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+
#include <asm/segment.h>
#include <asm/system.h>
-#include <errno.h>
+
#include <sys/mman.h>
/*
#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);
return (caddr_t)-ENODEV;
/*
- * we only allow mappings from address 0 to HIGH_MEMORY, since thats
+ * 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].
* truly useful.
*/
- if (len > HIGH_MEMORY || off > HIGH_MEMORY - len) /* avoid overflow */
+ if (len > high_memory || off > high_memory - len) /* avoid overflow */
return (caddr_t)-ENXIO;
if (remap_page_range(addr, off, len, PERMISS(flags, prot)))
/*
* linux/mm/swap.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Started 18.12.91
*/
-#include <errno.h>
-#include <sys/stat.h>
-
#include <linux/mm.h>
-#include <linux/string.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+
+static int lowest_bit = 0;
+static int highest_bit = 0;
+
+/*
+ * The following are used to make sure we don't thrash too much...
+ */
+#define NR_LAST_FREE_PAGES 32
+static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
#define SWAP_BITS (4096<<3)
bitop(clrbit,"r")
static char * swap_bitmap = NULL;
+static char * swap_lockmap = NULL;
unsigned int swap_device = 0;
struct inode * swap_file = NULL;
void rw_swap_page(int rw, unsigned int nr, char * buf)
{
- unsigned int zones[4];
- int i;
+ static struct wait_queue * lock_queue = NULL;
- if (swap_device) {
- ll_rw_page(rw,swap_device,nr,buf);
+ if (!swap_lockmap) {
+ printk("No swap lock-map\n");
return;
}
- if (swap_file) {
- nr <<= 2;
+ while (setbit(swap_lockmap,nr))
+ sleep_on(&lock_queue);
+ if (swap_device) {
+ ll_rw_page(rw,swap_device,nr,buf);
+ } else if (swap_file) {
+ unsigned int zones[4];
+ unsigned int block = nr << 2;
+ int i;
+
for (i = 0; i < 4; i++)
- if (!(zones[i] = bmap(swap_file,nr++))) {
+ if (!(zones[i] = bmap(swap_file,block++))) {
printk("rw_swap_page: bad swap file\n");
return;
}
ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
- return;
- }
- printk("ll_swap_page: no swap file or device\n");
+ } else
+ printk("re_swap_page: no swap file or device\n");
+ if (!clrbit(swap_lockmap,nr))
+ printk("rw_swap_page: lock already cleared\n");
+ wake_up(&lock_queue);
}
-/*
- * We never page the pages in task[0] - kernel memory.
- * We page all other pages.
- */
-#define FIRST_VM_PAGE (TASK_SIZE>>12)
-#define LAST_VM_PAGE (1024*1024)
-#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
-
-static int get_swap_page(void)
+static unsigned int get_swap_page(void)
{
- int nr;
+ unsigned int nr;
if (!swap_bitmap)
return 0;
- for (nr = 1; nr < SWAP_BITS ; nr++)
- if (clrbit(swap_bitmap,nr))
- return nr;
+ for (nr = lowest_bit; nr <= highest_bit ; nr++)
+ if (clrbit(swap_bitmap,nr)) {
+ if (nr == highest_bit)
+ highest_bit--;
+ return lowest_bit = nr;
+ }
return 0;
}
-void swap_free(int swap_nr)
+void swap_free(unsigned int swap_nr)
{
if (!swap_nr)
return;
- if (swap_bitmap && swap_nr < SWAP_BITS)
+ if (swap_bitmap && swap_nr < SWAP_BITS) {
+ if (swap_nr < lowest_bit)
+ lowest_bit = swap_nr;
+ if (swap_nr > highest_bit)
+ highest_bit = swap_nr;
if (!setbit(swap_bitmap,swap_nr))
return;
- printk("swap_free: swap-space bitmap bad\n");
+ }
+ printk("swap_free: swap-space bitmap bad (bit %d)\n",swap_nr);
return;
}
void swap_in(unsigned long *table_ptr)
{
- int swap_nr;
+ unsigned long swap_nr;
unsigned long page;
- if (!swap_bitmap) {
- printk("Trying to swap in without swap bit-map");
- return;
- }
- if (1 & *table_ptr) {
+ swap_nr = *table_ptr;
+ if (1 & swap_nr) {
printk("trying to swap in present page\n\r");
return;
}
- swap_nr = *table_ptr >> 1;
if (!swap_nr) {
printk("No swap page in swap_in\n\r");
return;
}
- if (!(page = get_free_page()))
- oom();
- read_swap_page(swap_nr, (char *) page);
- if (setbit(swap_bitmap,swap_nr))
- printk("swapping in multiply from same page\n\r");
+ if (!swap_bitmap) {
+ printk("Trying to swap in without swap bit-map");
+ *table_ptr = BAD_PAGE;
+ return;
+ }
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ oom(current);
+ page = BAD_PAGE;
+ } else
+ read_swap_page(swap_nr>>1, (char *) page);
+ if (*table_ptr != swap_nr) {
+ free_page(page);
+ return;
+ }
+ swap_free(swap_nr>>1);
*table_ptr = page | (PAGE_DIRTY | 7);
}
int try_to_swap_out(unsigned long * table_ptr)
{
+ int i;
unsigned long page;
unsigned long swap_nr;
page = *table_ptr;
if (!(PAGE_PRESENT & page))
return 0;
- if (page - LOW_MEM > PAGING_MEMORY)
+ if (page < low_memory || page >= high_memory)
return 0;
+ for (i = 0; i < NR_LAST_FREE_PAGES; i++)
+ if (last_free_pages[i] == (page & 0xfffff000))
+ return 0;
if (PAGE_DIRTY & page) {
page &= 0xfffff000;
if (mem_map[MAP_NR(page)] != 1)
return 1;
}
+/*
+ * We never page the pages in task[0] - kernel memory.
+ * We page all other pages.
+ */
+#define FIRST_VM_PAGE (TASK_SIZE>>12)
+#define LAST_VM_PAGE (1024*1024)
+#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
+
/*
* 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...
+ * We now check that the process is swappable (normally only 'init'
+ * is un-swappable), allowing high-priority processes which cannot be
+ * swapped out (things like user-level device drivers (Not implemented)).
*/
int swap_out(void)
{
dir_entry++;
goto check_dir;
}
- if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
+ if (p->swappable && try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
p->rss--;
+ dir_entry++;
return 1;
}
goto check_table;
* Get physical address of first (actually last :-) free page, and mark it
* used. If no free pages left, return 0.
*/
-unsigned long get_free_page(void)
+unsigned long get_free_page(int priority)
{
unsigned long result;
+ static unsigned long index = 0;
repeat:
__asm__("std ; repne ; scasb\n\t"
"movl %%edx,%%eax\n"
"1:\tcld"
:"=a" (result)
- :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
- "D" (mem_map+PAGING_PAGES-1)
+ :"0" (0),"b" (low_memory),"c" (paging_pages),
+ "D" (mem_map+paging_pages-1)
:"di","cx","dx");
- if (result >= HIGH_MEMORY)
+ if (result >= high_memory)
goto repeat;
- if ((result && result < LOW_MEM) || (result & 0xfff)) {
+ if ((result && result < low_memory) || (result & 0xfff)) {
printk("weird result: %08x\n",result);
result = 0;
}
- if (!result && swap_out())
+ if (result) {
+ --nr_free_pages;
+ if (index >= NR_LAST_FREE_PAGES)
+ index = 0;
+ last_free_pages[index] = result;
+ index++;
+ return result;
+ }
+ if (nr_free_pages) {
+ printk("Damn. mm_free_page count is off by %d\r\n",
+ nr_free_pages);
+ nr_free_pages = 0;
+ }
+ if (priority <= GFP_BUFFER)
+ return 0;
+ if (shrink_buffers()) {
+ schedule();
+ goto repeat;
+ }
+ if (swap_out()) {
+ schedule();
goto repeat;
- return result;
+ }
+ return 0;
}
/*
*
* The swapon system call
*/
-
int sys_swapon(const char * specialfile)
{
struct inode * swap_inode;
+ char * tmp;
int i,j;
if (!suser())
return -EPERM;
if (!(swap_inode = namei(specialfile)))
return -ENOENT;
- if (swap_file || swap_device || swap_bitmap) {
+ if (swap_file || swap_device || swap_bitmap || swap_lockmap) {
iput(swap_inode);
return -EBUSY;
}
iput(swap_inode);
return -EINVAL;
}
- swap_bitmap = (char *) get_free_page();
- if (!swap_bitmap) {
+ tmp = (char *) get_free_page(GFP_USER);
+ swap_lockmap = (char *) get_free_page(GFP_USER);
+ if (!tmp || !swap_lockmap) {
+ printk("Unable to start swapping: out of memory :-)\n");
+ free_page((long) tmp);
+ free_page((long) swap_lockmap);
iput(swap_file);
swap_device = 0;
swap_file = NULL;
- printk("Unable to start swapping: out of memory :-)\n");
+ swap_bitmap = NULL;
+ swap_lockmap = NULL;
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);
+ free_page((long) swap_lockmap);
iput(swap_file);
swap_device = 0;
swap_file = NULL;
swap_bitmap = NULL;
+ swap_lockmap = NULL;
return -EINVAL;
}
- memset(swap_bitmap+4086,0,10);
+ memset(tmp+4086,0,10);
j = 0;
+ lowest_bit = 0;
+ highest_bit = 0;
for (i = 1 ; i < SWAP_BITS ; i++)
- if (bit(swap_bitmap,i))
+ if (bit(tmp,i)) {
+ if (!lowest_bit)
+ lowest_bit = i;
+ highest_bit = i;
j++;
+ }
if (!j) {
printk("Empty swap-file\n");
- free_page((long) swap_bitmap);
+ free_page((long) tmp);
+ free_page((long) swap_lockmap);
iput(swap_file);
swap_device = 0;
swap_file = NULL;
swap_bitmap = NULL;
+ swap_lockmap = NULL;
return -EINVAL;
}
+ swap_bitmap = tmp;
printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
return 0;
}
--- /dev/null
+#
+# 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...
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.s:
+ $(CC) $(CFLAGS) -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 /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/errno.h \
+ /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
+ /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
+ /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/socket.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h \
+ kern_sock.h socketcall.h
+unix.o : unix.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/sched.h \
+ /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h \
+ /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h \
+ /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_sb.h \
+ /usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
+ /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/time.h \
+ /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
+ /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/string.h /usr/src/linux/include/linux/stat.h \
+ /usr/src/linux/include/linux/socket.h /usr/src/linux/include/linux/un.h /usr/src/linux/include/linux/fcntl.h \
+ /usr/src/linux/include/linux/termios.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h \
+ kern_sock.h
--- /dev/null
+#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 wait_queue **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 sel_type, select_table * wait);
+ 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 */
--- /dev/null
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+
+#include <asm/system.h>
+#include <asm/segment.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 wait_queue *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 sel_type, select_table * wait)
+{
+ struct socket *sock;
+
+ PRINTK("sock_select: inode = 0x%x, kind = %s\n", inode,
+ (sel_type == SEL_IN) ? "in" :
+ (sel_type == SEL_OUT) ? "out" : "ex");
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_select: can't find socket for inode!\n");
+ return 0;
+ }
+
+ /*
+ * handle server sockets specially
+ */
+ if (sock->flags & SO_ACCEPTCON) {
+ if (sel_type == SEL_IN) {
+ PRINTK("sock_select: %sconnections pending\n",
+ sock->iconn ? "" : "no ");
+ if (sock->iconn)
+ return 1;
+ select_wait(&inode->i_wait, wait);
+ return sock->iconn ? 1 : 0;
+ }
+ PRINTK("sock_select: nothing else for server socket\n");
+ select_wait(&inode->i_wait, wait);
+ return 0;
+ }
+ /*
+ * we can't return errors to select, so its either yes or no.
+ */
+ if (sock->ops && sock->ops->select)
+ return sock->ops->select(sock, sel_type, wait);
+ return 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 -ERESTARTSYS;
+ }
+ }
+
+ 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;
+}
+
--- /dev/null
+#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_
--- /dev/null
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+
+#include <asm/system.h>
+#include <asm/segment.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 sel_type, select_table * wait);
+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(GFP_USER))) {
+ 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;
+
+ 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;
+ }
+
+ 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());
+ i = do_mknod(fname, S_IFSOCK | 0777, 0);
+ 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");
+ send_sig(SIGKILL,current,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) {
+ send_sig(SIGPIPE,current,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 -EAGAIN;
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ PRINTK("unix_proto_write: interrupted\n");
+ return -ERESTARTSYS;
+ }
+ if (sock->state == SS_DISCONNECTING) {
+ PRINTK("unix_proto_write: disconnected (SIGPIPE)\n");
+ send_sig(SIGPIPE,current,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");
+ send_sig(SIGKILL,current,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) {
+ send_sig(SIGPIPE,current,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 sel_type, select_table * wait)
+{
+ struct unix_proto_data *upd, *peerupd;
+
+ if (sel_type == 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;
+ }
+ select_wait(sock->wait,wait);
+ return 0;
+ }
+ if (sel_type == 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");
+ if (UN_BUF_SPACE(peerupd) > 0)
+ return 1;
+ select_wait(sock->wait,wait);
+ return 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;
+}
/*
* linux/tools/build.c
*
- * (C) 1991 Linus Torvalds
+ * Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
#include <stdlib.h> /* contains exit */
#include <sys/types.h> /* unistd.h needs this */
#include <sys/stat.h>
-#include <linux/fs.h>
+#include <sys/sysmacros.h>
#include <unistd.h> /* contains read/write */
#include <fcntl.h>
#define MINIX_HEADER 32
#define GCC_HEADER 1024
-#define SYS_SIZE 0x4000
+#define SYS_SIZE 0x5000
#define DEFAULT_MAJOR_ROOT 0
#define DEFAULT_MINOR_ROOT 0
perror(argv[4]);
die("Couldn't stat root device.");
}
- major_root = MAJOR(sb.st_rdev);
- minor_root = MINOR(sb.st_rdev);
+ major_root = major(sb.st_rdev);
+ minor_root = minor(sb.st_rdev);
} else {
major_root = 0;
minor_root = 0;
}
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
if ((major_root != 2) && (major_root != 3) &&
- (major_root != 0)) {
+ (major_root != 8) && (major_root != 0)) {
fprintf(stderr, "Illegal root device (major = %d)\n",
major_root);
die("Bad root device --- major #");