#
-# comment this line if you don't want the emulation-code
+# ROOT_DEV specifies the default root-device when making the image.
+# This can be either FLOPPY, /dev/xxxx or empty, in which case the
+# default of FLOPPY is used by 'build'.
#
-MATH_EMULATION = -DKERNEL_MATH_EMULATION
+ROOT_DEV = /dev/hdb1
#
# uncomment the correct keyboard:
#
+# The value of KBDFLAGS should be or'ed together from the following
+# bits, depending on which features you want enabled.
+# 0x80 - Off: the Alt key will set bit 7 if pressed together with
+# another key.
+# On: the Alt key will NOT set the high bit; an escape
+# character is prepended instead.
+# The least significant bits control if the following keys are "dead".
+# The key is dead by default if the bit is on.
+# 0x01 - backquote (`)
+# 0x02 - accent acute
+# 0x04 - circumflex (^)
+# 0x08 - tilde (~)
+# 0x10 - dieresis (umlaut)
+
+KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
+# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_US -DKBDFLAGS=0
+# KEYBOARD = -DKBD_GR -DKBDFLAGS=0
+# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_FR -DKBDFLAGS=0
+# KEYBOARD = -DKBD_FR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_UK -DKBDFLAGS=0
+# KEYBOARD = -DKBD_DK -DKBDFLAGS=0
+# KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0
-# KEYBOARD = -DKBD_FINNISH
-KEYBOARD = -DKBD_US
-# KEYBOARD = -DKBD_GR
-# KEYBOARD = -DKBD_FR
-# KEYBOARD = -DKBD_UK
-# KEYBOARD = -DKBD_DK
+#
+# comment this line if you don't want the emulation-code
+#
+
+MATH_EMULATION = -DKERNEL_MATH_EMULATION
#
# uncomment this line if you are using gcc-1.40
CFLAGS =-Wall -O6 -fomit-frame-pointer $(GCC_OPT)
-#
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, /dev/xxxx or empty, in which case the
-# default of FLOPPY is used by 'build'.
-#
-
-# ROOT_DEV = /dev/hdb1
-
#
# if you want the ram-disk device, define this to be the
# size in blocks.
MAKE =make CFLAGS="$(CFLAGS)"
CPP =cpp -nostdinc -Iinclude
-ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o
+ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
FILESYSTEMS =fs/minix/minix.o
-DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
+DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
+ kernel/blk_drv/scsi/scsi.a
MATH =kernel/math/math.a
LIBS =lib/lib.a
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.95c-`cat .version`\" > include/linux/config_rel.h
+ @echo \#define UTS_RELEASE \"0.96a-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
dd bs=8192 if=Image of=/dev/PS0
tools/build: tools/build.c
- $(CC) $(CFLAGS) \
+ $(CC) -static $(CFLAGS) \
-o tools/build tools/build.c
boot/head.o: boot/head.s
kernel/blk_drv/blk_drv.a: dummy
(cd kernel/blk_drv; $(MAKE))
+kernel/blk_drv/scsi/scsi.a: dummy
+ (cd kernel/blk_drv/scsi; $(MAKE))
+
kernel/chr_drv/chr_drv.a: dummy
(cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)")
fs/fs.o: dummy
(cd fs; $(MAKE))
+net/net.o: dummy
+ (cd net; $(MAKE))
+
fs/minix/minix.o: dummy
(cd fs/minix; $(MAKE))
(cd fs;make clean)
(cd kernel;make clean)
(cd lib;make clean)
+ (cd net;make clean)
backup: clean
(cd .. ; tar cf - linux | compress - > backup.Z)
(cd fs; make dep)
(cd kernel; make dep)
(cd mm; make dep)
+ (cd net;make dep)
+ (cd lib; make dep)
dummy:
### Dependencies:
-init/main.o : init/main.c include/unistd.h include/sys/stat.h \
- include/sys/types.h include/sys/time.h include/time.h include/sys/times.h \
- include/sys/utsname.h include/sys/param.h include/sys/resource.h \
- include/utime.h include/linux/tty.h include/termios.h include/linux/sched.h \
- include/linux/head.h include/linux/fs.h include/sys/dirent.h \
+init/main.o : init/main.c include/stddef.h include/stdarg.h include/fcntl.h include/sys/types.h \
+ include/time.h include/asm/system.h include/asm/io.h include/linux/config.h \
+ include/linux/config_rel.h include/linux/config_ver.h include/linux/config.dist.h \
+ include/linux/sched.h include/linux/head.h include/linux/fs.h include/sys/dirent.h \
include/limits.h include/linux/mm.h include/linux/kernel.h include/signal.h \
- include/asm/system.h include/asm/io.h include/stddef.h include/stdarg.h \
- include/fcntl.h include/string.h
+ include/sys/param.h include/sys/time.h include/sys/resource.h include/linux/tty.h \
+ include/termios.h include/linux/unistd.h
$(AS) -o $*.o $<
OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \
- block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
- fcntl.o ioctl.o select.o
+ block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
+ select.o
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
cd minix; make dep
### Dependencies:
-block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/segment.h ../include/asm/system.h
-buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/system.h ../include/asm/io.h
-char_dev.o : char_dev.c ../include/errno.h ../include/sys/types.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/segment.h ../include/asm/io.h
-exec.o : exec.c ../include/signal.h ../include/sys/types.h \
- ../include/errno.h ../include/string.h ../include/sys/stat.h \
- ../include/a.out.h ../include/linux/fs.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+block_dev.o : block_dev.c ../include/errno.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
+ ../include/asm/system.h
+buffer.o : buffer.c ../include/stdarg.h ../include/linux/config.h ../include/linux/config_rel.h \
+ ../include/linux/config_ver.h ../include/linux/config.dist.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/asm/system.h ../include/asm/io.h
+exec.o : exec.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+ ../include/linux/string.h ../include/sys/stat.h ../include/a.out.h ../include/linux/fs.h \
+ ../include/sys/dirent.h ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/asm/segment.h
+fcntl.o : fcntl.c ../include/errno.h ../include/fcntl.h ../include/sys/types.h \
+ ../include/sys/stat.h ../include/asm/segment.h ../include/linux/string.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h
+file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+ ../include/limits.h
+inode.o : inode.c ../include/linux/string.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/asm/system.h
+ioctl.o : ioctl.c ../include/linux/string.h ../include/errno.h ../include/sys/stat.h \
+ ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/signal.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+ ../include/sys/resource.h
+namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ../include/linux/string.h \
+ ../include/fcntl.h ../include/errno.h ../include/const.h ../include/sys/stat.h
+open.o : open.c ../include/errno.h ../include/fcntl.h ../include/sys/types.h \
+ ../include/utime.h ../include/sys/stat.h ../include/sys/vfs.h ../include/linux/string.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h
-fcntl.o : fcntl.c ../include/string.h ../include/errno.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/segment.h ../include/fcntl.h \
- ../include/sys/stat.h
-file_table.o : file_table.c ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h
-inode.o : inode.c ../include/string.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/system.h
-ioctl.o : ioctl.c ../include/string.h ../include/errno.h \
- ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+pipe.o : pipe.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+ ../include/termios.h ../include/fcntl.h ../include/asm/segment.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h
-namei.o : namei.c ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
- ../include/string.h ../include/fcntl.h ../include/errno.h \
- ../include/const.h ../include/sys/stat.h
-open.o : open.c ../include/string.h ../include/errno.h ../include/fcntl.h \
- ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/segment.h
-pipe.o : pipe.c ../include/signal.h ../include/sys/types.h \
- ../include/errno.h ../include/termios.h ../include/fcntl.h \
- ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/segment.h
-read_write.o : read_write.c ../include/errno.h ../include/sys/types.h \
- ../include/sys/stat.h ../include/sys/dirent.h ../include/limits.h \
- ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/linux/minix_fs.h \
+read_write.o : read_write.c ../include/errno.h ../include/sys/types.h ../include/sys/stat.h \
+ ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/linux/minix_fs.h ../include/asm/segment.h
+select.o : select.c ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/kernel.h ../include/linux/tty.h ../include/asm/system.h \
+ ../include/termios.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/mm.h \
+ ../include/signal.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+ ../include/sys/resource.h ../include/linux/string.h ../include/asm/segment.h \
+ ../include/sys/stat.h ../include/const.h ../include/errno.h
+stat.o : stat.c ../include/errno.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h
-select.o : select.c ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \
- ../include/linux/tty.h ../include/termios.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/segment.h ../include/asm/system.h \
- ../include/sys/stat.h ../include/string.h ../include/const.h \
- ../include/errno.h
-stat.o : stat.c ../include/errno.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/linux/fs.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/asm/segment.h
-super.o : super.c ../include/linux/config.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/linux/minix_fs.h ../include/asm/system.h ../include/errno.h \
- ../include/sys/stat.h
+super.o : super.c ../include/linux/config.h ../include/linux/config_rel.h ../include/linux/config_ver.h \
+ ../include/linux/config.dist.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/linux/minix_fs.h \
+ ../include/asm/system.h ../include/asm/segment.h ../include/errno.h ../include/sys/stat.h
memcpy_fromfs(p,buf,chars);
p += chars;
buf += chars;
+ bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(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);
}
}
return;
bh->b_next = hash(bh->b_dev,bh->b_blocknr);
hash(bh->b_dev,bh->b_blocknr) = bh;
- bh->b_next->b_prev = bh;
+ if (bh->b_next)
+ bh->b_next->b_prev = bh;
}
static struct buffer_head * find_buffer(int dev, int block)
if (bh = get_hash_table(dev,block))
return bh;
buffers = NR_BUFFERS;
- tmp = free_list;
- do {
- tmp = tmp->b_next_free;
+ for (tmp = free_list ; buffers-- > 0 ; tmp = tmp->b_next_free) {
if (tmp->b_count)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
if (!BADNESS(tmp))
break;
}
+#if 0
if (tmp->b_dirt)
ll_rw_block(WRITEA,tmp);
+#endif
+ }
/* and repeat until we find something good */
- } while (buffers--);
if (!bh) {
sleep_on(&buffer_wait);
goto repeat;
if (bh->b_count)
goto repeat;
while (bh->b_dirt) {
- sync_dev(bh->b_dev);
+ sync_buffers(bh->b_dev);
wait_on_buffer(bh);
if (bh->b_count)
goto repeat;
tmp=getblk(dev,first);
if (tmp) {
if (!tmp->b_uptodate)
- ll_rw_block(READA,bh);
+ ll_rw_block(READA,tmp);
tmp->b_count--;
}
}
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
+ h->b_reqnext = NULL;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
+++ /dev/null
-/*
- * linux/fs/char_dev.c
- *
- * (C) 1991 Linus Torvalds
- */
-
-#include <errno.h>
-#include <sys/types.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-
-#include <checkpoint.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-extern int tty_read(unsigned minor,char * buf,int count,unsigned short flags);
-extern int tty_write(unsigned minor,char * buf,int count);
-extern int lp_write(unsigned minor,char *buf, int count);
-
-typedef (*crw_ptr)(int,unsigned,char *,int,off_t *,unsigned short);
-
-static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
-{
- return ((rw==READ)?tty_read(minor,buf,count,flags):
- tty_write(minor,buf,count));
-}
-
-static int rw_lp(int rw,unsigned minor,char * buf,int count,off_t * pos, unsigned short flags)
-{
- return ((rw==READ)?-EINVAL:lp_write(minor,buf,count));
-}
-
-static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos, unsigned short flags)
-{
- if (current->tty<0)
- return -EPERM;
- return rw_ttyx(rw,current->tty,buf,count,pos,flags);
-}
-
-static int rw_ram(int rw,char * buf, int count, off_t *pos)
-{
- return -EIO;
-}
-
-static int rw_mem(int rw,char * buf, int count, off_t * pos)
-{
- char *p;
- unsigned long pde, pte, tmp;
- int i = count;
-
- if (count <= 0)
- return(0);
- /*
- * return EOF on nonexistant pages or pages swapped out to disk
- */
- pde = (unsigned long) pg_dir + (*pos >> 20 & 0xffc);
- if (((pte = *((unsigned long *) pde)) & 1) == 0)
- return 0; /* page table not present */
- pte &= 0xfffff000;
- pte += *pos >> 10 & 0xffc;
- if (((tmp = *((unsigned long *) pte)) & 1) == 0)
- return 0;
- if (rw == WRITE && (tmp & 2) == 0)
- un_wp_page((unsigned long *) pte);
- p = (char *) ((tmp & 0xfffff000) + (*pos & 0xfff));
- while (1) {
- if (rw == WRITE)
- *p++ = get_fs_byte(buf++);
- else
- put_fs_byte(*p++, buf++);
-
- if (--i == 0)
- break;
-
- if (count && ((unsigned long) p & 0xfff) == 0) {
- if (((pte += 4) & 0xfff) == 0) {
- if (((pde += 4) & 0xfff) == 0)
- break;
- if (((pte = *((unsigned long *) pde)) & 1) == 0)
- break;
- pte &= 0xfffff000;
- }
- if (((tmp = *((unsigned long *) pte)) & 1) == 0)
- break;
-
- if (rw == WRITE && (tmp & 2) == 0)
- un_wp_page((unsigned long *) pte);
- p = (char *) (tmp & 0xfffff000);
- }
- }
- return(count - i);
-}
-
-static int rw_kmem(int rw,char * buf, int count, off_t * pos)
-{
- char *p=(char *) *pos;
-
- if ((unsigned long) *pos > HIGH_MEMORY)
- return 0;
- if ((unsigned long) *pos + count > HIGH_MEMORY)
- count = HIGH_MEMORY - *pos;
-
- switch (rw) {
- case READ:
- while ((count -= 4) >= 0)
- put_fs_long(*((unsigned long *) p)++,
- ((unsigned long *) buf)++);
- count += 4;
- while (--count >= 0)
- put_fs_byte(*p++, buf++);
- break;
- case WRITE:
- while (--count >= 0)
- *p++ = get_fs_byte(buf++);
- break;
- default:
- return -EINVAL;
- }
- p -= *pos;
- *pos += (int) p;
- return (int) p;
-}
-
-static int rw_port(int rw,char * buf, int count, off_t * pos)
-{
- int i=*pos;
-
- while (count-->0 && i<65536) {
- if (rw==READ)
- put_fs_byte(inb(i),buf++);
- else
- outb(get_fs_byte(buf++),i);
- i++;
- }
- i -= *pos;
- *pos += i;
- return i;
-}
-
-static int rw_memory(int rw, unsigned minor, char * buf, int count,
- off_t * pos, unsigned short flags)
-{
- switch(minor) {
- case 0:
- return rw_ram(rw,buf,count,pos);
- case 1:
- return rw_mem(rw,buf,count,pos);
- case 2:
- return rw_kmem(rw,buf,count,pos);
- case 3:
- return (rw==READ)?0:count; /* rw_null */
- case 4:
- return rw_port(rw,buf,count,pos);
- default:
- return -EIO;
- }
-}
-
-#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))
-
-static crw_ptr crw_table[]={
- NULL, /* nodev */
- rw_memory, /* /dev/mem etc */
- NULL, /* /dev/fd */
- NULL, /* /dev/hd */
- rw_ttyx, /* /dev/ttyx */
- rw_tty, /* /dev/tty */
- rw_lp, /* /dev/lp */
- NULL}; /* unnamed pipes */
-
-int char_read(struct inode * inode, struct file * filp, char * buf, int count)
-{
- unsigned int major,minor;
- crw_ptr call_addr;
-
- major = MAJOR(inode->i_rdev);
- minor = MINOR(inode->i_rdev);
- if (major >= NRDEVS)
- return -ENODEV;
- if (!(call_addr = crw_table[major]))
- return -ENODEV;
- return call_addr(READ,minor,buf,count,&filp->f_pos,filp->f_flags);
-}
-
-int char_write(struct inode * inode, struct file * filp, char * buf, int count)
-{
- unsigned int major,minor;
- crw_ptr call_addr;
-
- major = MAJOR(inode->i_rdev);
- minor = MINOR(inode->i_rdev);
- if (major >= NRDEVS)
- return -ENODEV;
- if (!(call_addr=crw_table[major]))
- return -ENODEV;
- return call_addr(WRITE,minor,buf,count,&filp->f_pos,filp->f_flags);
-}
#include <signal.h>
#include <errno.h>
-#include <string.h>
+#include <linux/string.h>
#include <sys/stat.h>
#include <a.out.h>
*/
#define MAX_ARG_PAGES 32
+/*
+ * Note that a shared library must be both readable and executable due to
+ * security reasons.
+ *
+ * Also note that we take the address to load from from the file itself.
+ */
int sys_uselib(const char * library)
{
+#define libnum (current->numlibraries)
struct inode * inode;
- unsigned long base;
+ struct buffer_head * bh;
+ struct exec ex;
if (get_limit(0x17) != TASK_SIZE)
return -EINVAL;
- if (library) {
- if (!(inode=namei(library))) /* get library inode */
- return -ENOENT;
- } else
+ if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
+ return -EINVAL;
+ if (library)
+ inode = namei(library);
+ else
inode = NULL;
-/* we should check filetypes (headers etc), but we don't */
- iput(current->library);
- current->library = NULL;
- base = get_base(current->ldt[2]);
- base += LIBRARY_OFFSET;
- free_page_tables(base,LIBRARY_SIZE);
- current->library = inode;
+ if (!inode)
+ return -ENOENT;
+ if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
+ iput(inode);
+ return -EACCES;
+ }
+ ex = *(struct exec *) bh->b_data;
+ brelse(bh);
+ if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
+ ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
+ inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
+ iput(inode);
+ return -ENOEXEC;
+ }
+ current->libraries[libnum].library = inode;
+ current->libraries[libnum].start = ex.a_entry;
+ current->libraries[libnum].length = (ex.a_data+ex.a_text+0xfff) & 0xfffff000;
+#if 0
+ printk("Loaded library %d at %08x, length %08x\n",
+ libnum,
+ current->libraries[libnum].start,
+ current->libraries[libnum].length);
+#endif
+ libnum++;
return 0;
+#undef libnum
}
/*
return data_limit;
}
+static void read_omagic(struct inode *inode, int bytes)
+{
+ struct buffer_head *bh;
+ int n, blkno, blk = 0;
+ char *dest = (char *) 0;
+
+ while (bytes > 0) {
+ if (!(blkno = bmap(inode, blk)))
+ sys_exit(-1);
+ if (!(bh = bread(inode->i_dev, blkno)))
+ sys_exit(-1);
+ n = (blk ? BLOCK_SIZE : BLOCK_SIZE - sizeof(struct exec));
+ if (bytes < n)
+ n = bytes;
+
+ memcpy_tofs(dest, (blk ? bh->b_data :
+ bh->b_data + sizeof(struct exec)), n);
+ brelse(bh);
+ ++blk;
+ dest += n;
+ bytes -= n;
+ }
+ iput(inode);
+ current->executable = NULL;
+}
+
/*
* 'do_execve()' executes a new program.
*
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 */
-/* note that current->library stays unchanged by an exec */
for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
if (ch == '/')
i = 0;
current->comm[i++] = ch;
if (i < 8)
current->comm[i] = '\0';
-
if (current->executable)
iput(current->executable);
+ i = current->numlibraries;
+ while (i-- > 0) {
+ iput(current->libraries[i].library);
+ current->libraries[i].library = NULL;
+ }
+ current->numlibraries = 0;
current->executable = inode;
current->signal = 0;
for (i=0 ; i<32 ; i++) {
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)
* (C) 1991 Linus Torvalds
*/
-#include <string.h>
#include <errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-
#include <fcntl.h>
+
#include <sys/stat.h>
+#include <asm/segment.h>
+
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
extern int sys_close(int fd);
static int dupfd(unsigned int fd, unsigned int arg)
* (C) 1991 Linus Torvalds
*/
-#include <string.h>
+#include <linux/string.h>
#include <sys/stat.h>
#include <linux/sched.h>
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);
}
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);
inode->i_count--;
return;
}
- if (S_ISBLK(inode->i_mode)) {
- sync_dev(inode->i_rdev);
- wait_on_inode(inode);
- }
repeat:
if (inode->i_count>1) {
inode->i_count--;
return;
}
if (!inode->i_nlink) {
- if (inode->i_op && inode->i_op->put_inode)
- inode->i_op->put_inode(inode);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode)
+ inode->i_sb->s_op->put_inode(inode);
return;
}
if (inode->i_dirt) {
* (C) 1991 Linus Torvalds
*/
-#include <string.h>
+#include <linux/string.h>
#include <errno.h>
#include <sys/stat.h>
#include <linux/sched.h>
-extern int hd_ioctl(int dev, int cmd, int arg);
-extern int tty_ioctl(int dev, int cmd, int arg);
-extern int pipe_ioctl(struct inode *pino, int cmd, int arg);
-
-typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
-
-#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
-
-static ioctl_ptr ioctl_table[]={
- NULL, /* nodev */
- NULL, /* /dev/mem */
- NULL, /* /dev/fd */
- hd_ioctl, /* /dev/hd */
- tty_ioctl, /* /dev/ttyx */
- tty_ioctl, /* /dev/tty */
- NULL, /* /dev/lp */
- NULL}; /* named pipes */
-
-
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
- int dev,mode;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
- if (filp->f_inode->i_pipe)
- return (filp->f_mode&1)?pipe_ioctl(filp->f_inode,cmd,arg):-EBADF;
- mode=filp->f_inode->i_mode;
- if (!S_ISCHR(mode) && !S_ISBLK(mode))
- return -EINVAL;
- dev = filp->f_inode->i_rdev;
- if (MAJOR(dev) >= NRDEVS)
- return -ENODEV;
- if (!ioctl_table[MAJOR(dev)])
- return -ENOTTY;
- return ioctl_table[MAJOR(dev)](dev,cmd,arg);
+ if (filp->f_op && filp->f_op->ioctl)
+ return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
+ return -EINVAL;
}
.s.o:
$(AS) -o $*.o $<
-OBJS= minix_op.o bitmap.o truncate.o namei.o inode.o file_dev.o
+OBJS= bitmap.o truncate.o namei.o inode.o \
+ file.o dir.o symlink.o blkdev.o chrdev.o
minix.o: $(OBJS)
$(LD) -r -o minix.o $(OBJS)
cp tmp_make Makefile
### Dependencies:
-bitmap.o : bitmap.c ../../include/string.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
+bitmap.o : bitmap.c ../../include/linux/string.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h
+blkdev.o : blkdev.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
- ../../include/time.h ../../include/sys/resource.h \
- ../../include/linux/minix_fs.h
-file_dev.o : file_dev.c ../../include/errno.h ../../include/fcntl.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/termios.h ../../include/errno.h ../../include/fcntl.h ../../include/sys/stat.h
+chrdev.o : chrdev.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/sys/stat.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
- ../../include/time.h ../../include/sys/resource.h \
- ../../include/linux/minix_fs.h ../../include/asm/segment.h
-inode.o : inode.c ../../include/string.h ../../include/sys/stat.h \
- ../../include/sys/types.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/minix_fs.h \
- ../../include/asm/system.h
-minix_op.o : minix_op.c ../../include/linux/fs.h ../../include/sys/types.h \
- ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/minix_fs.h
-namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/minix_fs.h \
- ../../include/asm/segment.h ../../include/string.h ../../include/fcntl.h \
- ../../include/errno.h ../../include/const.h ../../include/sys/stat.h
-truncate.o : truncate.c ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/termios.h ../../include/errno.h ../../include/fcntl.h ../../include/sys/stat.h
+dir.o : dir.c ../../include/errno.h ../../include/sys/stat.h ../../include/sys/types.h \
+ ../../include/asm/segment.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/minix_fs.h
+file.o : file.c ../../include/errno.h ../../include/fcntl.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/sys/stat.h ../../include/asm/segment.h \
+ ../../include/asm/system.h ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h
+inode.o : inode.c ../../include/linux/string.h ../../include/sys/stat.h ../../include/sys/types.h \
+ ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h ../../include/asm/system.h
+namei.o : namei.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
- ../../include/time.h ../../include/sys/resource.h \
- ../../include/linux/minix_fs.h ../../include/linux/tty.h \
- ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/asm/segment.h ../../include/linux/string.h \
+ ../../include/fcntl.h ../../include/errno.h ../../include/const.h ../../include/sys/stat.h
+symlink.o : symlink.c ../../include/errno.h ../../include/sys/stat.h ../../include/sys/types.h \
+ ../../include/asm/segment.h ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
+ ../../include/linux/kernel.h ../../include/signal.h ../../include/sys/param.h \
+ ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h ../../include/linux/minix_fs.h
+truncate.o : truncate.c ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/minix_fs.h ../../include/linux/tty.h \
+ ../../include/asm/system.h ../../include/termios.h ../../include/errno.h ../../include/fcntl.h \
../../include/sys/stat.h
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
-#include <string.h>
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
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;
}
--- /dev/null
+/*
+ * linux/fs/chrdev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/*
+ * Called every time a minix block special file is opened
+ */
+static int blkdev_open(struct inode * inode, struct file * filp)
+{
+ int i;
+
+ check_disk_change(inode->i_rdev);
+ i = MAJOR(inode->i_rdev);
+ if (i < MAX_BLKDEV) {
+ filp->f_op = blkdev_fops[i];
+ if (filp->f_op && filp->f_op->open)
+ return filp->f_op->open(inode,filp);
+ }
+ return 0;
+}
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+static struct file_operations def_blk_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ blkdev_open, /* open */
+ NULL, /* release */
+};
+
+struct inode_operations minix_blkdev_inode_operations = {
+ &def_blk_fops, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ minix_bmap, /* bmap */
+ minix_truncate /* truncate */
+};
--- /dev/null
+/*
+ * linux/fs/chrdev.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/tty.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/*
+ * Called every time a minix character special file is opened
+ */
+static int chrdev_open(struct inode * inode, struct file * filp)
+{
+ int i;
+
+ i = MAJOR(inode->i_rdev);
+ if (i < MAX_CHRDEV) {
+ filp->f_op = chrdev_fops[i];
+ if (filp->f_op && filp->f_op->open)
+ return filp->f_op->open(inode,filp);
+ }
+ return 0;
+}
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+static struct file_operations def_chr_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ chrdev_open, /* open */
+ NULL, /* release */
+};
+
+struct inode_operations minix_chrdev_inode_operations = {
+ &def_chr_fops, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ minix_bmap, /* bmap */
+ minix_truncate /* truncate */
+};
+
--- /dev/null
+/*
+ * linux/fs/minix/dir.c
+ *
+ * minix directory hadnling functions
+ */
+
+#include <errno.h>
+
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+static int minix_readdir(struct inode *, struct file *, struct dirent *, int);
+
+static struct file_operations minix_dir_operations = {
+ NULL, /* lseek - default */
+ minix_file_read, /* read */
+ NULL, /* write - bad */
+ minix_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations minix_dir_inode_operations = {
+ &minix_dir_operations, /* default directory file-ops */
+ minix_create, /* create */
+ minix_lookup, /* lookup */
+ minix_link, /* link */
+ minix_unlink, /* unlink */
+ minix_symlink, /* symlink */
+ minix_mkdir, /* mkdir */
+ minix_rmdir, /* rmdir */
+ minix_mknod, /* mknod */
+ minix_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ minix_bmap, /* bmap */
+ minix_truncate /* truncate */
+};
+
+static int minix_readdir(struct inode * inode, struct file * filp,
+ struct dirent * dirent, int count)
+{
+ unsigned int block,offset,i;
+ char c;
+ struct buffer_head * bh;
+ struct minix_dir_entry * de;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+ if (filp->f_pos & (sizeof (struct minix_dir_entry) - 1))
+ return -EBADF;
+ while (filp->f_pos < inode->i_size) {
+ offset = filp->f_pos & 1023;
+ block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
+ if (!block || !(bh = bread(inode->i_dev,block))) {
+ filp->f_pos += 1024-offset;
+ continue;
+ }
+ de = (struct minix_dir_entry *) (offset + bh->b_data);
+ while (offset < 1024 && filp->f_pos < inode->i_size) {
+ offset += sizeof (struct minix_dir_entry);
+ filp->f_pos += sizeof (struct minix_dir_entry);
+ if (de->inode) {
+ for (i = 0; i < MINIX_NAME_LEN; i++)
+ if (c = de->name[i])
+ put_fs_byte(c,i+dirent->d_name);
+ else
+ break;
+ if (i) {
+ put_fs_long(de->inode,&dirent->d_ino);
+ put_fs_byte(0,i+dirent->d_name);
+ put_fs_word(i,&dirent->d_reclen);
+ brelse(bh);
+ return i;
+ }
+ }
+ de++;
+ }
+ brelse(bh);
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * linux/fs/minix/file.c
+ *
+ * minix regular file handling primitives
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/dirent.h>
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/kernel.h>
+
+#define NBUF 16
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+int minix_file_read(struct inode *, struct file *, char *, int);
+static int minix_file_write(struct inode *, struct file *, char *, int);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the minix filesystem.
+ */
+static struct file_operations minix_file_operations = {
+ NULL, /* lseek - default */
+ minix_file_read, /* read */
+ minix_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* no special open is needed */
+ NULL /* release */
+};
+
+struct inode_operations minix_file_inode_operations = {
+ &minix_file_operations, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ minix_bmap, /* bmap */
+ minix_truncate /* truncate */
+};
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+ cli();
+ while (bh->b_lock)
+ sleep_on(&bh->b_wait);
+ sti();
+}
+
+/*
+ * minix_file_read() is also needed by the directory read-routine,
+ * so it's not static. NOTE! reading directories directly is a bad idea,
+ * but has to be supported for now for compatability reasons with older
+ * versions.
+ */
+int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ int read,left,chars,nr;
+ int block, blocks, offset;
+ struct buffer_head ** bhb, ** bhe;
+ struct buffer_head * buflist[NBUF];
+
+ if (!inode) {
+ printk("minix_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
+ printk("minix_file_read: mode = %07o\n",inode->i_mode);
+ return -EINVAL;
+ }
+ if (filp->f_pos > inode->i_size)
+ left = 0;
+ else
+ left = inode->i_size - filp->f_pos;
+ if (left > count)
+ left = count;
+ if (left <= 0)
+ return 0;
+ read = 0;
+ block = filp->f_pos >> BLOCK_SIZE_BITS;
+ offset = filp->f_pos & (BLOCK_SIZE-1);
+ blocks = (left + offset + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ bhb = bhe = buflist;
+ do {
+ if (blocks) {
+ --blocks;
+ if (nr = minix_bmap(inode,block++)) {
+ *bhb = getblk(inode->i_dev,nr);
+ if (!(*bhb)->b_uptodate)
+ ll_rw_block(READ,*bhb);
+ } else
+ *bhb = NULL;
+
+ if (++bhb == &buflist[NBUF])
+ bhb = buflist;
+
+ if (bhb != bhe)
+ continue;
+ }
+ if (*bhe) {
+ wait_on_buffer(*bhe);
+ if (!(*bhe)->b_uptodate) {
+ do {
+ brelse(*bhe);
+ if (++bhe == &buflist[NBUF])
+ bhe = buflist;
+ } while (bhe != bhb);
+ break;
+ }
+ }
+
+ if (left < BLOCK_SIZE - offset)
+ chars = left;
+ else
+ chars = BLOCK_SIZE - offset;
+ filp->f_pos += chars;
+ left -= chars;
+ read += chars;
+ if (*bhe) {
+ memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
+ brelse(*bhe);
+ buf += chars;
+ } else {
+ while (chars-->0)
+ put_fs_byte(0,buf++);
+ }
+ offset = 0;
+ if (++bhe == &buflist[NBUF])
+ bhe = buflist;
+ } while (left > 0);
+ if (!read)
+ return -EIO;
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ return read;
+}
+
+static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ off_t pos;
+ int written,block,c;
+ struct buffer_head * bh;
+ char * p;
+
+ if (!inode) {
+ printk("minix_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("minix_file_write: mode = %07o\n",inode->i_mode);
+ return -EINVAL;
+ }
+/*
+ * ok, append may not work when many processes are writing at the same time
+ * but so what. That way leads to madness anyway.
+ */
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+ pos = filp->f_pos;
+ written = 0;
+ while (written<count) {
+ if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
+ if (!written)
+ written = -ENOSPC;
+ break;
+ }
+ c = BLOCK_SIZE - (pos % BLOCK_SIZE);
+ if (c > count-written)
+ c = count-written;
+ if (c == BLOCK_SIZE)
+ bh = getblk(inode->i_dev, block);
+ else
+ bh = bread(inode->i_dev,block);
+ if (!bh) {
+ if (!written)
+ written = -EIO;
+ break;
+ }
+ p = (pos % BLOCK_SIZE) + bh->b_data;
+ pos += c;
+ if (pos > inode->i_size) {
+ inode->i_size = pos;
+ inode->i_dirt = 1;
+ }
+ written += c;
+ memcpy_fromfs(p,buf,c);
+ buf += c;
+ bh->b_uptodate = 1;
+ bh->b_dirt = 1;
+ brelse(bh);
+ }
+ inode->i_mtime = CURRENT_TIME;
+ if (!(filp->f_flags & O_APPEND)) {
+ filp->f_pos = pos;
+ inode->i_ctime = CURRENT_TIME;
+ }
+ inode->i_dirt = 1;
+ return written;
+}
+++ /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)
-{
- unsigned int block,offset,i;
- char c;
- struct buffer_head * bh;
- struct minix_dir_entry * de;
-
- if (!S_ISDIR(inode->i_mode))
- return -EBADF;
- if (filp->f_pos & 15)
- return -EBADF;
- while (filp->f_pos < inode->i_size) {
- offset = filp->f_pos & 1023;
- block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
- if (!block || !(bh = bread(inode->i_dev,block))) {
- filp->f_pos += 1024-offset;
- continue;
- }
- de = (struct minix_dir_entry *) (offset + bh->b_data);
- while (offset < 1024 && filp->f_pos < inode->i_size) {
- offset += 16;
- filp->f_pos += 16;
- if (de->inode) {
- for (i = 0; i < 14; i++)
- if (c = de->name[i])
- put_fs_byte(c,i+dirent->d_name);
- else
- break;
- if (i) {
- put_fs_long(de->inode,&dirent->d_ino);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_word(i,&dirent->d_reclen);
- brelse(bh);
- return i;
- }
- }
- de++;
- }
- brelse(bh);
- }
- return 0;
-}
-
-int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
-{
- int read,left,chars,nr;
- struct buffer_head * bh;
-
- if (filp->f_pos > inode->i_size)
- left = 0;
- else
- left = inode->i_size - filp->f_pos;
- if (left > count)
- left = count;
- read = 0;
- while (left > 0) {
- if (nr = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) {
- if (!(bh=bread(inode->i_dev,nr)))
- return read?read:-EIO;
- } else
- bh = NULL;
- nr = filp->f_pos & (BLOCK_SIZE-1);
- chars = MIN( BLOCK_SIZE-nr , left );
- filp->f_pos += chars;
- left -= chars;
- read += chars;
- if (bh) {
- memcpy_tofs(buf,nr+bh->b_data,chars);
- buf += chars;
- brelse(bh);
- } else {
- while (chars-->0)
- put_fs_byte(0,buf++);
- }
- }
- inode->i_atime = CURRENT_TIME;
- return read;
-}
-
-int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
-{
- off_t pos;
- int written,block,c;
- struct buffer_head * bh;
- char * p;
-
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
- if (filp->f_flags & O_APPEND)
- pos = inode->i_size;
- else
- pos = filp->f_pos;
- written = 0;
- while (written<count) {
- if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
- if (!written)
- written = -ENOSPC;
- break;
- }
- if (!(bh=bread(inode->i_dev,block))) {
- if (!written)
- written = -EIO;
- break;
- }
- c = pos % BLOCK_SIZE;
- p = c + bh->b_data;
- c = BLOCK_SIZE-c;
- if (c > count-written)
- c = count-written;
- pos += c;
- if (pos > inode->i_size) {
- inode->i_size = pos;
- inode->i_dirt = 1;
- }
- written += c;
- memcpy_fromfs(p,buf,c);
- buf += c;
- bh->b_dirt = 1;
- brelse(bh);
- }
- inode->i_mtime = CURRENT_TIME;
- if (!(filp->f_flags & O_APPEND)) {
- filp->f_pos = pos;
- inode->i_ctime = CURRENT_TIME;
- }
- inode->i_dirt = 1;
- return written;
-}
* (C) 1991 Linus Torvalds
*/
-#include <string.h>
+#include <linux/string.h>
#include <sys/stat.h>
#include <linux/sched.h>
int sync_dev(int dev);
+void minix_put_inode(struct inode *inode)
+{
+ inode->i_size = 0;
+ minix_truncate(inode);
+ minix_free_inode(inode);
+}
+
void minix_put_super(struct super_block *sb)
{
int i;
static struct super_operations minix_sops = {
minix_read_inode,
+ minix_write_inode,
+ minix_put_inode,
minix_put_super
};
else for (block = 0; block < 9; block++)
inode->i_data[block] = raw_inode->i_zone[block];
brelse(bh);
- inode->i_op = &minix_inode_operations;
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &minix_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &minix_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &minix_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &minix_chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &minix_blkdev_inode_operations;
}
void minix_write_inode(struct inode * inode)
+++ /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)
-{
- minix_truncate(inode);
- minix_free_inode(inode);
-}
-
-/*
- * These are the low-level inode operations for minix filesystem inodes.
- */
-struct inode_operations minix_inode_operations = {
- minix_create,
- minix_lookup,
- minix_link,
- minix_unlink,
- minix_symlink,
- minix_mkdir,
- minix_rmdir,
- minix_mknod,
- minix_rename,
- minix_readlink,
- minix_open,
- minix_release,
- minix_follow_link,
- minix_bmap,
- minix_truncate,
- minix_write_inode,
- minix_put_inode
-};
-
-/*
- * We have mostly NULL's here: the current defaults are ok for
- * the minix filesystem.
- */
-struct file_operations minix_file_operations = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- minix_readdir
-};
-
#include <linux/kernel.h>
#include <asm/segment.h>
-#include <string.h>
+#include <linux/string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
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)
{
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;
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_size = 32;
- inode->i_dirt = 1;
+ inode->i_op = &minix_dir_inode_operations;
+ inode->i_size = 2 * sizeof (struct minix_dir_entry);
inode->i_mtime = inode->i_atime = CURRENT_TIME;
if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
iput(dir);
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
iput(dir);
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
- return -ERROR;
+ return -EIO;
}
de = (struct minix_dir_entry *) dir_block->b_data;
de->inode=inode->i_ino;
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;
}
if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
iput(dir);
inode->i_nlink--;
+ inode->i_dirt = 1;
iput(inode);
- return -ERROR;
+ return -EIO;
}
i = 0;
while (i < 1023 && (c=get_fs_byte(symname++)))
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);
/* 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) {
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
+ *
+ * minix symlink handling code
+ */
+
+#include <errno.h>
+
+#include <sys/stat.h>
+
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+
+static int minix_readlink(struct inode *, char *, int);
+static struct inode * minix_follow_link(struct inode *, struct inode *);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations minix_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ minix_readlink, /* readlink */
+ minix_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
+{
+ unsigned short fs;
+ struct buffer_head * bh;
+
+ if (!dir) {
+ dir = current->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput(dir);
+ return NULL;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(dir);
+ return inode;
+ }
+ __asm__("mov %%fs,%0":"=r" (fs));
+ if ((current->link_count > 5) || !inode->i_data[0] ||
+ !(bh = bread(inode->i_dev, inode->i_data[0]))) {
+ iput(dir);
+ iput(inode);
+ return NULL;
+ }
+ iput(inode);
+ __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
+ current->link_count++;
+ inode = _namei(bh->b_data,dir,1);
+ current->link_count--;
+ __asm__("mov %0,%%fs"::"r" (fs));
+ brelse(bh);
+ return inode;
+}
+
+static int minix_readlink(struct inode * inode, char * buffer, int buflen)
+{
+ struct buffer_head * bh;
+ int i;
+ char c;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(inode);
+ return -EINVAL;
+ }
+ if (buflen > 1023)
+ buflen = 1023;
+ if (inode->i_data[0])
+ bh = bread(inode->i_dev, inode->i_data[0]);
+ else
+ bh = NULL;
+ iput(inode);
+ if (!bh)
+ return 0;
+ i = 0;
+ while (i<buflen && (c = bh->b_data[i])) {
+ i++;
+ put_fs_byte(c,buffer++);
+ }
+ brelse(bh);
+ return i;
+}
#include <fcntl.h>
#include <sys/stat.h>
-static int minix_free_ind(int dev,int block)
+/*
+ * Truncate has the most races in the whole filesystem: coding it is
+ * a pain in the a**. Especially as I don't do any locking...
+ *
+ * The code may look a bit weird, but that's just because I've tried to
+ * handle things like file-size changes in a somewhat graceful manner.
+ * Anyway, truncating a file at the same time somebody else writes to it
+ * is likely to result in pretty weird behaviour...
+ *
+ * The new code handles normal truncates (size = 0) as well as the more
+ * general case (size = XXX). I hope.
+ */
+
+static int trunc_direct(struct inode * inode)
{
- struct buffer_head * bh;
- unsigned short * p;
int i;
- int block_busy;
+ int result = 0;
+#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
- if (!block)
- return 1;
- block_busy = 0;
- if (bh=bread(dev,block)) {
- p = (unsigned short *) bh->b_data;
- for (i=0;i<512;i++,p++)
- if (*p)
- if (minix_free_block(dev,*p)) {
- *p = 0;
- bh->b_dirt = 1;
- } else
- block_busy = 1;
- brelse(bh);
+repeat:
+ for (i = DIRECT_BLOCK ; i < 7 ; i++) {
+ if (i < DIRECT_BLOCK)
+ goto repeat;
+ if (!inode->i_data[i])
+ continue;
+ result = 1;
+ if (minix_free_block(inode->i_dev,inode->i_data[i]))
+ inode->i_data[i] = 0;
}
- if (block_busy)
- return 0;
- else
- return minix_free_block(dev,block);
+ return result;
}
-static int minix_free_dind(int dev,int block)
+static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
{
- struct buffer_head * bh;
- unsigned short * p;
int i;
- int block_busy;
+ struct buffer_head * bh = NULL;
+ unsigned short * ind;
+ int result = 0;
+#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
- if (!block)
- return 1;
- block_busy = 0;
- if (bh=bread(dev,block)) {
- p = (unsigned short *) bh->b_data;
- for (i=0;i<512;i++,p++)
- if (*p)
- if (minix_free_ind(dev,*p)) {
- *p = 0;
- bh->b_dirt = 1;
- } else
- block_busy = 1;
- brelse(bh);
- }
- if (block_busy)
+ if (*p)
+ bh = bread(inode->i_dev,*p);
+ if (!bh)
return 0;
- else
- return minix_free_block(dev,block);
+repeat:
+ for (i = INDIRECT_BLOCK ; i < 512 ; i++) {
+ if (i < 0)
+ i = 0;
+ if (i < INDIRECT_BLOCK)
+ goto repeat;
+ ind = i+(unsigned short *) bh->b_data;
+ if (!*ind)
+ continue;
+ result = 1;
+ if (minix_free_block(inode->i_dev,*ind))
+ *ind = 0;
+ }
+ ind = (unsigned short *) bh->b_data;
+ for (i = 0; i < 512; i++)
+ if (*(ind++))
+ break;
+ brelse(bh);
+ if (i >= 512) {
+ result = 1;
+ if (minix_free_block(inode->i_dev,*p))
+ *p = 0;
+ }
+ return result;
}
+
+static int trunc_dindirect(struct inode * inode)
+{
+ int i;
+ struct buffer_head * bh = NULL;
+ unsigned short * dind;
+ int result = 0;
+#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9)
+ if (inode->i_data[8])
+ bh = bread(inode->i_dev,inode->i_data[8]);
+ if (!bh)
+ return 0;
+repeat:
+ for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) {
+ if (i < 0)
+ i = 0;
+ if (i < DINDIRECT_BLOCK)
+ goto repeat;
+ dind = i+(unsigned short *) bh->b_data;
+ if (!*dind)
+ continue;
+ result |= trunc_indirect(inode,7+512+(i<<9),dind);
+ }
+ dind = (unsigned short *) bh->b_data;
+ for (i = 0; i < 512; i++)
+ if (*(dind++))
+ break;
+ brelse(bh);
+ if (i >= 512) {
+ result = 1;
+ if (minix_free_block(inode->i_dev,inode->i_data[8]))
+ inode->i_data[8] = 0;
+ }
+ return result;
+}
+
void minix_truncate(struct inode * inode)
{
- int i;
- int block_busy;
+ int flag;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
-repeat:
- block_busy = 0;
- for (i=0;i<7;i++)
- if (inode->i_data[i]) {
- if (minix_free_block(inode->i_dev,inode->i_data[i]))
- inode->i_data[i]=0;
- else
- block_busy = 1;
- }
- if (minix_free_ind(inode->i_dev,inode->i_data[7]))
- inode->i_data[7] = 0;
- else
- block_busy = 1;
- if (minix_free_dind(inode->i_dev,inode->i_data[8]))
- inode->i_data[8] = 0;
- else
- block_busy = 1;
- inode->i_dirt = 1;
- if (block_busy) {
+ if (inode->i_data[7] & 0xffff0000)
+ printk("BAD! minix inode has 16 high bits set\n");
+ while (1) {
+ flag = trunc_direct(inode);
+ flag |= trunc_indirect(inode,7,(unsigned short *)&inode->i_data[7]);
+ flag |= trunc_dindirect(inode);
+ if (!flag)
+ break;
current->counter = 0;
schedule();
- goto repeat;
}
- inode->i_size = 0;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
}
/*
{
printk("minix_release not implemented\n");
}
-
-static int check_char_dev(struct inode * inode, struct file * filp)
-{
- struct tty_struct *tty;
- int min, dev;
-
- dev = inode->i_rdev;
- if (MAJOR(dev) == 4 || MAJOR(dev) == 5) {
- if (MAJOR(dev) == 5)
- min = current->tty;
- else
- min = MINOR(dev);
- if (min < 0)
- return -1;
- if ((IS_A_PTY_MASTER(min)) && (inode->i_count>1))
- return -1;
- tty = TTY_TABLE(min);
- if (!(filp->f_flags & O_NOCTTY) &&
- current->leader &&
- current->tty<0 &&
- tty->session==0) {
- current->tty = min;
- tty->session= current->session;
- tty->pgrp = current->pgrp;
- }
- if (IS_A_SERIAL(min))
- serial_open(min-64);
- }
- return 0;
-}
-
-/*
- * Called every time a minix-file is opened
- */
-int minix_open(struct inode * inode, struct file * filp)
-{
- if (S_ISCHR(inode->i_mode)) {
- if (check_char_dev(inode,filp))
- return -EAGAIN;
- } else if (S_ISBLK(inode->i_mode))
- check_disk_change(inode->i_rdev);
- filp->f_op = &minix_file_operations;
- return 0;
-}
#include <linux/kernel.h>
#include <asm/segment.h>
-#include <string.h>
+#include <linux/string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
inode = follow_link(base,inode);
else
iput(base);
- if (inode) {
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
- }
return inode;
}
}
inode->i_atime = CURRENT_TIME;
if (flag & O_TRUNC)
- if (inode->i_op && inode->i_op->truncate)
+ if (inode->i_op && inode->i_op->truncate) {
+ inode->i_size = 0;
inode->i_op->truncate(inode);
+ }
*res_inode = inode;
return 0;
}
* (C) 1991 Linus Torvalds
*/
-#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utime.h>
+
#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
+struct file_operations * chrdev_fops[MAX_CHRDEV] = {
+ NULL,
+};
+
+struct file_operations * blkdev_fops[MAX_BLKDEV] = {
+ NULL,
+};
+
int sys_ustat(int dev, struct ustat * ubuf)
{
return -ENOSYS;
}
+int sys_statfs(const char * path, struct statfs * buf)
+{
+ printk("statfs not implemented\n");
+ return -ENOSYS;
+}
+
+int sys_fstatfs(unsigned int fd, struct statfs * buf)
+{
+ printk("fstatfs not implemented\n");
+ return -ENOSYS;
+}
+
+int sys_truncate(const char * path, unsigned int length)
+{
+ struct inode * inode;
+
+ if (!(inode = namei(path)))
+ return -ENOENT;
+ if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
+ iput(inode);
+ return -EACCES;
+ }
+ inode->i_size = length;
+ if (inode->i_op && inode->i_op->truncate)
+ inode->i_op->truncate(inode);
+ inode->i_atime = inode->i_mtime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ iput(inode);
+ return 0;
+}
+
+int sys_ftruncate(unsigned int fd, unsigned int length)
+{
+ struct inode * inode;
+ struct file * file;
+
+ if (fd >= NR_OPEN || !(file = current->filp[fd]))
+ return -EBADF;
+ if (!(inode = file->f_inode))
+ return -ENOENT;
+ if (S_ISDIR(inode->i_mode) || !(file->f_flags & 2))
+ return -EACCES;
+ inode->i_size = length;
+ if (inode->i_op && inode->i_op->truncate)
+ inode->i_op->truncate(inode);
+ inode->i_atime = inode->i_mtime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ return 0;
+}
+
int sys_utime(char * filename, struct utimbuf * times)
{
struct inode * inode;
if (current->euid != inode->i_uid &&
!permission(inode,MAY_WRITE)) {
iput(inode);
- return -EPERM;
+ return -EACCES;
}
actime = get_fs_long((unsigned long *) ×->actime);
modtime = get_fs_long((unsigned long *) ×->modtime);
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);
}
-int sys_chmod(const char * filename,int mode)
+int sys_fchmod(unsigned int fd, mode_t mode)
{
struct inode * inode;
+ struct file * file;
- if (!(inode=namei(filename)))
+ if (fd >= NR_OPEN || !(file = current->filp[fd]))
+ return -EBADF;
+ if (!(inode = file->f_inode))
+ return -ENOENT;
+ if ((current->euid != inode->i_uid) && !suser())
+ return -EPERM;
+ inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
+ inode->i_dirt = 1;
+ return 0;
+}
+
+int sys_chmod(const char * filename, mode_t mode)
+{
+ struct inode * inode;
+
+ if (!(inode = namei(filename)))
return -ENOENT;
if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
- return -EACCES;
+ return -EPERM;
}
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
return 0;
}
-int sys_chown(const char * filename,int uid,int gid)
+int sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
struct inode * inode;
+ struct file * file;
- if (!(inode=namei(filename)))
+ if (fd >= NR_OPEN || !(file = current->filp[fd]))
+ return -EBADF;
+ if (!(inode = file->f_inode))
return -ENOENT;
- if (!suser()) {
+ if ((current->euid == inode->i_uid && user == inode->i_uid &&
+ (in_group_p(group) || group == inode->i_gid)) ||
+ suser()) {
+ inode->i_uid = user;
+ inode->i_gid = group;
+ inode->i_dirt=1;
+ return 0;
+ }
+ return -EPERM;
+}
+
+int sys_chown(const char * filename, uid_t user, gid_t group)
+{
+ struct inode * inode;
+
+ if (!(inode = lnamei(filename)))
+ return -ENOENT;
+ if ((current->euid == inode->i_uid && user == inode->i_uid &&
+ (in_group_p(group) || group == inode->i_gid)) ||
+ suser()) {
+ inode->i_uid = user;
+ inode->i_gid = group;
+ inode->i_dirt=1;
iput(inode);
- return -EACCES;
+ return 0;
}
- inode->i_uid=uid;
- inode->i_gid=gid;
- inode->i_dirt=1;
iput(inode);
- return 0;
+ return -EPERM;
}
int sys_open(const char * filename,int flag,int mode)
if (!f->f_count) break;
if (i>=NR_FILE)
return -EINVAL;
- (current->filp[fd]=f)->f_count++;
- if ((i=open_namei(filename,flag,mode,&inode))<0) {
+ (current->filp[fd] = f)->f_count++;
+ if ((i = open_namei(filename,flag,mode,&inode))<0) {
current->filp[fd]=NULL;
f->f_count=0;
return i;
}
- f->f_op = NULL;
f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
f->f_flags = flag;
f->f_count = 1;
f->f_inode = inode;
f->f_pos = 0;
- if (inode->i_op && inode->i_op->open)
- if (i = inode->i_op->open(inode,f)) {
+ f->f_reada = 0;
+ f->f_op = NULL;
+ if (inode->i_op)
+ f->f_op = inode->i_op->default_file_ops;
+ if (f->f_op && f->f_op->open)
+ if (i = f->f_op->open(inode,f)) {
iput(inode);
f->f_count=0;
current->filp[fd]=NULL;
if (!(filp = current->filp[fd]))
return -EINVAL;
current->filp[fd] = NULL;
- if (filp->f_count == 0)
- panic("Close: file count is 0");
- if (--filp->f_count)
- return (0);
+ if (filp->f_count == 0) {
+ printk("Close: file count is 0\n");
+ return 0;
+ }
+ if (filp->f_count > 1) {
+ filp->f_count--;
+ return 0;
+ }
+ if (filp->f_op && filp->f_op->release)
+ filp->f_op->release(filp->f_inode,filp);
iput(filp->f_inode);
- return (0);
+ filp->f_count--;
+ return 0;
}
#include <termios.h>
#include <fcntl.h>
-#include <linux/sched.h>
#include <asm/segment.h>
+
+#include <linux/sched.h>
#include <linux/kernel.h>
-int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
+static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, read = 0;
return read?read:-EAGAIN;
}
-int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
+static int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
{
int chars, size, written = 0;
return written;
}
+static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+ return -ESPIPE;
+}
+
+static int pipe_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
+{
+ return -ENOTDIR;
+}
+
+static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ return -EBADF;
+}
+
+static int pipe_ioctl(struct inode *pino, struct file * filp,
+ unsigned int cmd, unsigned int arg)
+{
+ switch (cmd) {
+ case FIONREAD:
+ verify_area((void *) arg,4);
+ put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Ok, these two routines should keep track of readers/writers,
+ * but it's currently done with the inode->i_count checking.
+ */
+static void pipe_read_release(struct inode * inode, struct file * filp)
+{
+}
+
+static void pipe_write_release(struct inode * inode, struct file * filp)
+{
+}
+
+static struct file_operations read_pipe_fops = {
+ pipe_lseek,
+ pipe_read,
+ bad_pipe_rw,
+ pipe_readdir,
+ NULL, /* pipe_select */
+ pipe_ioctl,
+ NULL, /* no special open code */
+ pipe_read_release
+};
+
+static struct file_operations write_pipe_fops = {
+ pipe_lseek,
+ bad_pipe_rw,
+ pipe_write,
+ pipe_readdir,
+ NULL, /* pipe_select */
+ pipe_ioctl,
+ NULL, /* no special open code */
+ pipe_write_release
+};
+
int sys_pipe(unsigned long * fildes)
{
struct inode * inode;
}
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
+ f[0]->f_op = &read_pipe_fops;
f[0]->f_mode = 1; /* read */
+ f[1]->f_op = &write_pipe_fops;
f[1]->f_mode = 2; /* write */
put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
return 0;
}
-
-int pipe_ioctl(struct inode *pino, int cmd, int arg)
-{
- switch (cmd) {
- case FIONREAD:
- verify_area((void *) arg,4);
- put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
- return 0;
- default:
- return -EINVAL;
- }
-}
return -EBADF;
if (file->f_op && file->f_op->readdir) {
verify_area(dirent, sizeof (*dirent));
- return file->f_op->readdir(inode,file,dirent);
+ return file->f_op->readdir(inode,file,dirent,count);
}
- return -EBADF;
+ return -ENOTDIR;
}
int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
struct file * file;
- int tmp, mem_dev;
+ int tmp;
if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode))
return -EBADF;
if (origin > 2)
return -EINVAL;
- if (file->f_inode->i_pipe)
- return -ESPIPE;
if (file->f_op && file->f_op->lseek)
return file->f_op->lseek(file->f_inode,file,offset,origin);
- mem_dev = S_ISCHR(file->f_inode->i_mode);
/* this is the default handler if no lseek handler is present */
switch (origin) {
case 0:
- if (offset<0 && !mem_dev) return -EINVAL;
- file->f_pos=offset;
+ tmp = offset;
break;
case 1:
- if (file->f_pos+offset<0 && !mem_dev) return -EINVAL;
- file->f_pos += offset;
+ tmp = file->f_pos + offset;
break;
case 2:
- if ((tmp=file->f_inode->i_size+offset)<0 && !mem_dev)
+ if (!file->f_inode)
return -EINVAL;
- file->f_pos = tmp;
+ tmp = file->f_inode->i_size + offset;
+ break;
}
- if (mem_dev && file->f_pos < 0)
- return 0;
+ if (tmp < 0)
+ return -EINVAL;
+ file->f_pos = tmp;
+ file->f_reada = 0;
return file->f_pos;
}
verify_area(buf,count);
if (file->f_op && file->f_op->read)
return file->f_op->read(inode,file,buf,count);
-/* these are the default read-functions */
- if (inode->i_pipe)
- return pipe_read(inode,file,buf,count);
- if (S_ISCHR(inode->i_mode))
- return char_read(inode,file,buf,count);
- if (S_ISBLK(inode->i_mode))
- return block_read(inode,file,buf,count);
- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode))
- return minix_file_read(inode,file,buf,count);
printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
return 0;
if (file->f_op && file->f_op->write)
return file->f_op->write(inode,file,buf,count);
-/* these are the default read-functions */
- if (inode->i_pipe)
- return pipe_write(inode,file,buf,count);
- if (S_ISCHR(inode->i_mode))
- return char_write(inode,file,buf,count);
- if (S_ISBLK(inode->i_mode))
- return block_write(inode,file,buf,count);
- if (S_ISREG(inode->i_mode))
- return minix_file_write(inode,file,buf,count);
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/sched.h>
+#include <linux/string.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <string.h>
+#include <sys/time.h>
+
#include <const.h>
#include <errno.h>
-#include <sys/time.h>
#include <signal.h>
/*
* task.
*/
-typedef struct {
- struct task_struct * old_task;
- struct task_struct ** wait_address;
-} wait_entry;
-
-typedef struct select_table_struct {
- int nr, woken;
- struct task_struct * current;
- struct select_table_struct * next_table;
- wait_entry entry[NR_OPEN*3];
-} select_table;
-
static select_table * sel_tables = NULL;
static void add_wait(struct task_struct ** wait_address, select_table * p)
return 1;
else
add_wait(&inode->i_wait, wait);
+ else if (S_ISSOCK(inode->i_mode))
+ if (sock_select(inode, NULL, SEL_IN, wait))
+ return 1;
+ else
+ add_wait(&inode->i_wait, wait);
return 0;
}
return 1;
else
add_wait(&inode->i_wait, wait);
+ else if (S_ISSOCK(inode->i_mode))
+ if (sock_select(inode, NULL, SEL_OUT, wait))
+ return 1;
+ else
+ add_wait(&inode->i_wait, wait);
return 0;
}
return 1;
else
add_wait(&inode->i_wait,wait);
+ else if (S_ISSOCK(inode->i_mode))
+ if (sock_select(inode, NULL, SEL_EX, wait))
+ return 1;
+ else
+ add_wait(&inode->i_wait, wait);
return 0;
}
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:
sel_tables = &wait_table;
*inp = *outp = *exp = 0;
count = 0;
+ current->state = TASK_INTERRUPTIBLE;
mask = 1;
for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
if (mask & in)
}
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;
}
timeout += jiffies;
}
current->timeout = timeout;
- cli();
i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
if (current->timeout > jiffies)
timeout = current->timeout - jiffies;
else
timeout = 0;
- sti();
current->timeout = 0;
if (i < 0)
return i;
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <asm/system.h>
+#include <asm/segment.h>
#include <errno.h>
#include <sys/stat.h>
struct super_block * sb;
int dev;
- if (!(inode=namei(dev_name)))
+ if (!suser())
+ return -EPERM;
+ if (!(inode = namei(dev_name)))
return -ENOENT;
dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode)) {
return 0;
}
-int sys_mount(char * dev_name, char * dir_name, int rw_flag)
+int sys_mount(char * dev_name, char * dir_name, char * type, int rw_flag)
{
struct inode * dev_i, * dir_i;
struct super_block * sb;
int dev;
+ char tmp[100],*t;
+ int i;
- if (!(dev_i=namei(dev_name)))
+ if (!suser())
+ return -EPERM;
+ if (!(dev_i = namei(dev_name)))
return -ENOENT;
dev = dev_i->i_rdev;
if (!S_ISBLK(dev_i->i_mode)) {
iput(dir_i);
return -EPERM;
}
- if (!(sb=read_super(dev,"minix",NULL))) {
+ if (type) {
+ i = 0;
+ while (i < 100 && (tmp[i] = get_fs_byte(type++)))
+ i++;
+ t = tmp;
+ } else
+ t = "minix";
+ if (!(sb = read_super(dev,t,NULL))) {
iput(dir_i);
return -EBUSY;
}
#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"
extern void inline outb_p(char value, unsigned short port)
{
-__asm__ volatile ("outb %0,%1\n"
- "\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:"
+__asm__ volatile ("outb %0,%1\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80"
::"a" ((char) value),"d" ((unsigned short) port));
}
extern unsigned char inline inb_p(unsigned short port)
{
unsigned char _v;
-__asm__ volatile ("inb %1,%0\n"
- "\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:\tjmp 1f\n"
- "1:"
+__asm__ volatile ("inb %1,%0\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80\n\t"
+ "outb %0,$0x80"
:"=a" (_v):"d" ((unsigned short) port));
return _v;
}
((limit) & 0x0ffff); }
#define _set_tssldt_desc(n,addr,type) \
-__asm__ ("movw $104,%1\n\t" \
+__asm__ ("movw $232,%1\n\t" \
"movw %%ax,%2\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,%3\n\t" \
+++ /dev/null
-#ifndef _CTYPE_H
-#define _CTYPE_H
-
-#define _U 0x01 /* upper */
-#define _L 0x02 /* lower */
-#define _D 0x04 /* digit */
-#define _C 0x08 /* cntrl */
-#define _P 0x10 /* punct */
-#define _S 0x20 /* white space (space/lf/tab) */
-#define _X 0x40 /* hex digit */
-#define _SP 0x80 /* hard space (0x20) */
-
-extern unsigned char _ctype[];
-extern char _ctmp;
-
-#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
-#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
-#define iscntrl(c) ((_ctype+1)[c]&(_C))
-#define isdigit(c) ((_ctype+1)[c]&(_D))
-#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
-#define islower(c) ((_ctype+1)[c]&(_L))
-#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
-#define ispunct(c) ((_ctype+1)[c]&(_P))
-#define isspace(c) ((_ctype+1)[c]&(_S))
-#define isupper(c) ((_ctype+1)[c]&(_U))
-#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
-
-#define isascii(c) (((unsigned) c)<=0x7f)
-#define toascii(c) (((unsigned) c)&0x7f)
-
-#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
-#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
-
-#endif
extern int errno;
-#define ERROR 99
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
--- /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_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
*/
leave HD_TYPE undefined. This is the normal thing to do.
*/
+#undef HD_TYPE
+
+#undef CONFIG_BLK_DEV_SD
+#undef CONFIG_BLK_DEV_ST
+
+/*
+ Choose supported SCSI adapters here.
+*/
+
+#undef CONFIG_SCSI_AHA1542
+#undef CONFIG_SCSI_ALWAYS
+#undef CONFIG_SCSI_CSC
+#undef CONFIG_SCSI_DTC
+#undef CONFIG_SCSI_FUTURE_DOMAIN
+#undef CONFIG_SCSI_SEAGATE
+#undef CONFIG_SCSI_ULTRASTOR
+
+#if defined(CONFIG_BLK_DEV_SD) || defined(CONFIG_BLK_DEV_ST)
+ #ifndef CONFIG_SCSI
+ #define CONFIG_SCSI
+ #endif
+
+ #if !defined(CONFIG_SCSI_AHA1542) && !defined(CONFIG_SCSI_CSC) && !defined(CONFIG_SCSI_DTC) && \
+ !defined(CONFIG_SCSI_FUTURE_DOMAIN) && !defined(CONFIG_SCSI_SEAGATE) && !defined(CONFIG_SCSI_ULTRASTOR)
+
+ #error Error : SCSI devices enabled, but no low level drivers have been enabled.
+ #endif
+#endif
+
+#ifdef CONFIG_DISTRIBUTION
+ #include <linux/config.dist.h>
+#else
+ #include <linux/config.site.h>
+#endif
+
+/*
+ File type specific stuff goes into this.
+*/
+
+#ifdef ASM_SRC
+#endif
+
+#ifdef C_SRC
+#endif
+
+#ifdef MAKE
+#endif
+
#endif
--- /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-18"
+#define UTS_RELEASE "0.96a-10"
-#define UTS_VERSION "04/09/92"
+#define UTS_VERSION "05/22/92"
--- /dev/null
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+extern char _ctmp;
+
+#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))
+#define isalpha(c) ((_ctype+1)[c]&(_U|_L))
+#define iscntrl(c) ((_ctype+1)[c]&(_C))
+#define isdigit(c) ((_ctype+1)[c]&(_D))
+#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
+#define islower(c) ((_ctype+1)[c]&(_L))
+#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
+#define ispunct(c) ((_ctype+1)[c]&(_P))
+#define isspace(c) ((_ctype+1)[c]&(_S))
+#define isupper(c) ((_ctype+1)[c]&(_U))
+#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))
+
+#define isascii(c) (((unsigned) c)<=0x7f)
+#define toascii(c) (((unsigned) c)&0x7f)
+
+#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
+#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)
+
+#endif
--- /dev/null
+#ifndef _FD_H_
+#define _FD_H
+
+#define FDCLRPRM 0 /* clear user-defined parameters */
+#define FDSETPRM 1 /* set user-defined parameters for current media */
+#define FDDEFPRM 2 /* set user-defined parameters until explicitly cleared */
+#define FDGETPRM 3 /* get disk parameters */
+#define FDMSGON 4 /* issue kernel messages on media type change */
+#define FDMSGOFF 5 /* don't issue kernel messages on media type change */
+#define FDFMTBEG 6 /* begin formatting a disk */
+#define FDFMTTRK 7 /* format the specified track */
+#define FDFMTEND 8 /* end formatting a disk */
+
+#define FD_FILL_BYTE 0xF6 /* format fill byte */
+
+#define FORMAT_NONE 0 /* no format request */
+#define FORMAT_WAIT 1 /* format request is waiting */
+#define FORMAT_BUSY 2 /* formatting in progress */
+#define FORMAT_OKAY 3 /* successful completion */
+#define FORMAT_ERROR 4 /* formatting error */
+
+struct floppy_struct {
+ unsigned int size, sect, head, track, stretch;
+ unsigned char gap,rate,spec1,fmt_gap;
+ char *name; /* used only for predefined formats */
+};
+
+struct format_descr {
+ unsigned int device,head,track;
+};
+
+#endif
#define FD_WRITE 0xC5 /* write with MT, MFM */
#define FD_SENSEI 0x08 /* Sense Interrupt Status */
#define FD_SPECIFY 0x03 /* specify HUT etc */
+#define FD_FORMAT 0x4D /* format one track */
/* DMA commands */
#define DMA_READ 0x46
* 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 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
struct buffer_head * b_next;
struct buffer_head * b_prev_free;
struct buffer_head * b_next_free;
+ struct buffer_head * b_reqnext;
};
struct inode {
unsigned short f_mode;
unsigned short f_flags;
unsigned short f_count;
+ unsigned short f_reada;
struct inode * f_inode;
struct file_operations * f_op;
off_t f_pos;
};
+typedef struct {
+ struct task_struct * old_task;
+ struct task_struct ** wait_address;
+} wait_entry;
+
+typedef struct select_table_struct {
+ int nr, woken;
+ struct task_struct * current;
+ struct select_table_struct * next_table;
+ wait_entry entry[NR_OPEN*3];
+} select_table;
+
struct super_block {
unsigned short s_ninodes;
unsigned short s_nzones;
int (*lseek) (struct inode *, struct file *, off_t, int);
int (*read) (struct inode *, struct file *, char *, int);
int (*write) (struct inode *, struct file *, char *, int);
- int (*readdir) (struct inode *, struct file *, struct dirent *);
+ int (*readdir) (struct inode *, struct file *, struct dirent *, int count);
+ int (*select) (struct inode *, struct file *, int, select_table *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned int);
+ int (*open) (struct inode *, struct file *);
+ void (*release) (struct inode *, struct file *);
};
struct inode_operations {
+ struct file_operations * default_file_ops;
int (*create) (struct inode *,const char *,int,int,struct inode **);
int (*lookup) (struct inode *,const char *,int,struct inode **);
int (*link) (struct inode *,struct inode *,const char *,int);
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);
};
char *name;
};
+extern struct file_operations * chrdev_fops[MAX_CHRDEV];
+extern struct file_operations * blkdev_fops[MAX_BLKDEV];
+
extern struct file_system_type *get_fs_type(char *name);
extern struct inode inode_table[NR_INODE];
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);
extern void lock_super(struct super_block * sb);
extern void free_super(struct super_block * sb);
-extern int pipe_read(struct inode *, struct file *, char *, int);
extern int char_read(struct inode *, struct file *, char *, int);
extern int block_read(struct inode *, struct file *, char *, int);
-extern int pipe_write(struct inode *, struct file *, char *, int);
extern int char_write(struct inode *, struct file *, char *, int);
extern int block_write(struct inode *, struct file *, char *, int);
void verify_area(void * addr,int count);
volatile void panic(const char * str);
volatile void do_exit(long error_code);
-int printf(const char * fmt, ...);
int printk(const char * fmt, ...);
-void console_print(const char * str);
-int tty_write(unsigned ch,char * buf,int count);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
#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
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;
};
/*
*/
extern void lp_init(void);
-
-extern int lp_reset(int minor);
-extern int lp_char(char lpchar, int minor);
-extern int lp_write(unsigned minor, char *buf, int count);
-
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 int minix_new_block(int dev);
extern int minix_free_block(int dev, int block);
-extern int minix_create_block(struct inode * inode, int block);
-extern int minix_bmap(struct inode * inode,int block);
+extern int minix_create_block(struct inode *, int);
+extern int minix_bmap(struct inode *,int);
-extern void minix_truncate(struct inode * inode);
-extern void minix_put_super(struct super_block *sb);
-extern struct super_block *minix_read_super(struct super_block *s,void *data);
-extern void minix_read_inode(struct inode * inode);
-extern void minix_write_inode(struct inode * inode);
+extern void minix_truncate(struct inode *);
+extern void minix_put_super(struct super_block *);
+extern struct super_block *minix_read_super(struct super_block *,void *);
+extern void minix_read_inode(struct inode *);
+extern void minix_write_inode(struct inode *);
+extern void minix_put_inode(struct inode *);
-extern int minix_lseek(struct inode * inode, struct file * filp, off_t offset, int origin);
-extern int minix_read(struct inode * inode, struct file * filp, char * buf, int count);
-extern int minix_write(struct inode * inode, struct file * filp, char * buf, int count);
-extern int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent);
+extern int minix_lseek(struct inode *, struct file *, off_t, int);
+extern int minix_read(struct inode *, struct file *, char *, int);
+extern int minix_write(struct inode *, struct file *, char *, int);
extern int minix_file_read(struct inode *, struct file *, char *, int);
-extern int minix_file_write(struct inode *, struct file *, char *, int);
-extern struct inode_operations minix_inode_operations;
+extern struct inode_operations minix_file_inode_operations;
+extern struct inode_operations minix_dir_inode_operations;
+extern struct inode_operations minix_symlink_inode_operations;
+extern struct inode_operations minix_chrdev_inode_operations;
+extern struct inode_operations minix_blkdev_inode_operations;
+
extern struct file_operations minix_file_operations;
+extern struct file_operations minix_dir_operations;
#endif
#define TASK_SIZE 0x04000000
#define LIBRARY_SIZE 0x00400000
+/*
+ * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
+ */
+#define IO_BITMAP_SIZE 32
+
#if (TASK_SIZE & 0x3fffff)
#error "TASK_SIZE must be multiple of 4M"
#endif
#define NULL ((void *) 0)
#endif
+#define MAX_SHARED_LIBS 6
+
extern int copy_page_tables(unsigned long from, unsigned long to, long size);
extern int free_page_tables(unsigned long from, unsigned long size);
extern void schedule(void);
extern void trap_init(void);
extern void panic(const char * str);
-extern int tty_write(unsigned minor,char * buf,int count);
typedef int (*fn_ptr)();
};
struct tss_struct {
- long back_link; /* 16 high bits zero */
- long esp0;
- long ss0; /* 16 high bits zero */
- long esp1;
- long ss1; /* 16 high bits zero */
- long esp2;
- long ss2; /* 16 high bits zero */
- long cr3;
- long eip;
- long eflags;
- long eax,ecx,edx,ebx;
- long esp;
- long ebp;
- long esi;
- long edi;
- long es; /* 16 high bits zero */
- long cs; /* 16 high bits zero */
- long ss; /* 16 high bits zero */
- long ds; /* 16 high bits zero */
- long fs; /* 16 high bits zero */
- long gs; /* 16 high bits zero */
- long ldt; /* 16 high bits zero */
- long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
+ unsigned long back_link; /* 16 high bits zero */
+ unsigned long esp0;
+ unsigned long ss0; /* 16 high bits zero */
+ unsigned long esp1;
+ unsigned long ss1; /* 16 high bits zero */
+ unsigned long esp2;
+ unsigned long ss2; /* 16 high bits zero */
+ unsigned long cr3;
+ unsigned long eip;
+ unsigned long eflags;
+ unsigned long eax,ecx,edx,ebx;
+ unsigned long esp;
+ unsigned long ebp;
+ unsigned long esi;
+ unsigned long edi;
+ unsigned long es; /* 16 high bits zero */
+ unsigned long cs; /* 16 high bits zero */
+ unsigned long ss; /* 16 high bits zero */
+ unsigned long ds; /* 16 high bits zero */
+ unsigned long fs; /* 16 high bits zero */
+ unsigned long gs; /* 16 high bits zero */
+ unsigned long ldt; /* 16 high bits zero */
+ unsigned long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
+ unsigned long io_bitmap[IO_BITMAP_SIZE];
struct i387_struct i387;
};
struct inode * pwd;
struct inode * root;
struct inode * executable;
- struct inode * library;
- unsigned long close_on_exec;
+ struct {
+ struct inode * library;
+ unsigned long start;
+ unsigned long length;
+ } libraries[MAX_SHARED_LIBS];
+ int numlibraries;
struct file * filp[NR_OPEN];
+ unsigned long close_on_exec;
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
struct desc_struct ldt[3];
/* tss for this task */
/* math */ 0, \
/* rss */ 2, \
/* comm */ "swapper", \
-/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL,0, \
-/* filp */ {NULL,}, \
- { \
- {0,0}, \
-/* ldt */ {0x9f,0xc0fa00}, \
- {0x9f,0xc0f200}, \
- }, \
+/* fs info */ 0,-1,0022,NULL,NULL,NULL, \
+/* libraries */ { { NULL, 0, 0}, }, 0, \
+/* filp */ {NULL,}, 0, \
+ { \
+ {0,0}, \
+/* ldt */ {0x9f,0xc0fa00}, \
+ {0x9f,0xc0f200} \
+ }, \
/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
0,0,0,0,0,0,0,0, \
0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
- _LDT(0),0x80000000, \
+ _LDT(0),0x80000000,{0xffffffff}, \
{} \
}, \
}
extern void add_timer(long jiffies, void (*fn)(void));
extern void sleep_on(struct task_struct ** p);
+extern int send_sig(long sig,struct task_struct * p,int priv);
extern void interruptible_sleep_on(struct task_struct ** p);
extern void wake_up(struct task_struct ** p);
extern int in_group_p(gid_t grp);
--- /dev/null
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+extern char * strerror(int errno);
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+extern inline char * strcpy(char * dest,const char *src)
+{
+__asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ ::"S" (src),"D" (dest):"si","di","ax");
+return dest;
+}
+
+extern inline char * strncpy(char * dest,const char *src,size_t count)
+{
+__asm__("cld\n"
+ "1:\tdecl %2\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "rep\n\t"
+ "stosb\n"
+ "2:"
+ ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strcat(char * dest,const char * src)
+{
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n"
+ "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * strncat(char * dest,const char * src,size_t count)
+{
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n\t"
+ "movl %4,%3\n"
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %2,%2\n\t"
+ "stosb"
+ ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
+ :"si","di","ax","cx");
+return dest;
+}
+
+extern inline int strcmp(const char * cs,const char * ct)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "scasb\n\t"
+ "jne 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "jmp 3f\n"
+ "2:\tmovl $1,%%eax\n\t"
+ "jl 3f\n\t"
+ "negl %%eax\n"
+ "3:"
+ :"=a" (__res):"D" (cs),"S" (ct):"si","di");
+return __res;
+}
+
+extern inline int strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n"
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "scasb\n\t"
+ "jne 3f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %%eax,%%eax\n\t"
+ "jmp 4f\n"
+ "3:\tmovl $1,%%eax\n\t"
+ "jl 4f\n\t"
+ "negl %%eax\n"
+ "4:"
+ :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
+return __res;
+}
+
+extern inline char * strchr(const char * s,char c)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t"
+ "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "je 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "movl $1,%1\n"
+ "2:\tmovl %1,%0\n\t"
+ "decl %0"
+ :"=a" (__res):"S" (s),"0" (c):"si");
+return __res;
+}
+
+extern inline char * strrchr(const char * s,char c)
+{
+register char * __res __asm__("dx");
+__asm__("cld\n\t"
+ "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "jne 2f\n\t"
+ "movl %%esi,%0\n\t"
+ "decl %0\n"
+ "2:\ttestb %%al,%%al\n\t"
+ "jne 1b"
+ :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
+return __res;
+}
+
+extern inline size_t strspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 1b\n"
+ "2:\tdecl %0"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline size_t strcspn(const char * cs, const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 1b\n"
+ "2:\tdecl %0"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline char * strpbrk(const char * cs,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "movl %%ecx,%%edx\n"
+ "1:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 2f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 1b\n\t"
+ "decl %0\n\t"
+ "jmp 3f\n"
+ "2:\txorl %0,%0\n"
+ "3:"
+ :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+ :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline char * strstr(const char * cs,const char * ct)
+{
+register char * __res __asm__("ax");
+__asm__("cld\n\t" \
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
+ "movl %%ecx,%%edx\n"
+ "1:\tmovl %4,%%edi\n\t"
+ "movl %%esi,%%eax\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repe\n\t"
+ "cmpsb\n\t"
+ "je 2f\n\t" /* also works for empty string, see above */
+ "xchgl %%eax,%%esi\n\t"
+ "incl %%esi\n\t"
+ "cmpb $0,-1(%%eax)\n\t"
+ "jne 1b\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "2:"
+ :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
+ :"cx","dx","di","si");
+return __res;
+}
+
+extern inline size_t strlen(const char * s)
+{
+register int __res __asm__("cx");
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %0\n\t"
+ "decl %0"
+ :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
+return __res;
+}
+
+extern char * ___strtok;
+
+extern inline char * strtok(char * s,const char * ct)
+{
+register char * __res __asm__("si");
+__asm__("testl %1,%1\n\t"
+ "jne 1f\n\t"
+ "testl %0,%0\n\t"
+ "je 8f\n\t"
+ "movl %0,%1\n"
+ "1:\txorl %0,%0\n\t"
+ "movl $-1,%%ecx\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "cld\n\t"
+ "movl %4,%%edi\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %%ecx\n\t"
+ "decl %%ecx\n\t"
+ "je 7f\n\t" /* empty delimeter-string */
+ "movl %%ecx,%%edx\n"
+ "2:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 7f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 2b\n\t"
+ "decl %1\n\t"
+ "cmpb $0,(%1)\n\t"
+ "je 7f\n\t"
+ "movl %1,%0\n"
+ "3:\tlodsb\n\t"
+ "testb %%al,%%al\n\t"
+ "je 5f\n\t"
+ "movl %4,%%edi\n\t"
+ "movl %%edx,%%ecx\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "jne 3b\n\t"
+ "decl %1\n\t"
+ "cmpb $0,(%1)\n\t"
+ "je 5f\n\t"
+ "movb $0,(%1)\n\t"
+ "incl %1\n\t"
+ "jmp 6f\n"
+ "5:\txorl %1,%1\n"
+ "6:\tcmpb $0,(%0)\n\t"
+ "jne 7f\n\t"
+ "xorl %0,%0\n"
+ "7:\ttestl %0,%0\n\t"
+ "jne 8f\n\t"
+ "movl %0,%1\n"
+ "8:"
+#if __GNUC__ == 2
+ :"=r" (__res)
+#else
+ :"=b" (__res)
+#endif
+ ,"=S" (___strtok)
+ :"0" (___strtok),"1" (s),"g" (ct)
+ :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline void * memcpy(void * dest,const void * src, size_t n)
+{
+__asm__("cld\n\t"
+ "rep\n\t"
+ "movsb"
+ ::"c" (n),"S" (src),"D" (dest)
+ :"cx","si","di");
+return dest;
+}
+
+extern inline void * memmove(void * dest,const void * src, size_t n)
+{
+if (dest<src)
+__asm__("cld\n\t"
+ "rep\n\t"
+ "movsb"
+ ::"c" (n),"S" (src),"D" (dest)
+ :"cx","si","di");
+else
+__asm__("std\n\t"
+ "rep\n\t"
+ "movsb\n\t"
+ "cld"
+ ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
+ :"cx","si","di");
+return dest;
+}
+
+extern inline int memcmp(const void * cs,const void * ct,size_t count)
+{
+register int __res __asm__("ax");
+__asm__("cld\n\t"
+ "repe\n\t"
+ "cmpsb\n\t"
+ "je 1f\n\t"
+ "movl $1,%%eax\n\t"
+ "jl 1f\n\t"
+ "negl %%eax\n"
+ "1:"
+ :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
+ :"si","di","cx");
+return __res;
+}
+
+extern inline void * memchr(const void * cs,char c,size_t count)
+{
+register void * __res __asm__("di");
+if (!count)
+ return NULL;
+__asm__("cld\n\t"
+ "repne\n\t"
+ "scasb\n\t"
+ "je 1f\n\t"
+ "movl $1,%0\n"
+ "1:\tdecl %0"
+ :"=D" (__res):"a" (c),"D" (cs),"c" (count)
+ :"cx");
+return __res;
+}
+
+extern inline void * memset(void * s,char c,size_t count)
+{
+__asm__("cld\n\t"
+ "rep\n\t"
+ "stosb"
+ ::"a" (c),"D" (s),"c" (count)
+ :"cx","di");
+return s;
+}
+
+#endif
extern int sys_swapon();
extern int sys_reboot();
extern int sys_readdir();
+extern int sys_mmap();
+extern int sys_munmap();
+extern int sys_truncate();
+extern int sys_ftruncate();
+extern int sys_fchmod();
+extern int sys_fchown();
+extern int sys_getpriority();
+extern int sys_setpriority();
+extern int sys_profil();
+extern int sys_statfs();
+extern int sys_fstatfs();
+extern int sys_ioperm();
+extern int sys_socketcall();
+extern int sys_syslog();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
-sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname,
-sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday,
-sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,
-sys_lstat, sys_readlink, sys_uselib, sys_swapon, sys_reboot, sys_readdir };
+sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending,
+sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage,
+sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups,
+sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
+sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap,
+sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority,
+sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
+sys_socketcall, sys_syslog };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
* 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;
#ifndef _TTY_H
#define _TTY_H
+#include <asm/system.h>
+
#define MAX_CONSOLES 8
#define NR_SERIALS 4
#define NR_PTYS 4
unsigned long head;
unsigned long tail;
struct task_struct * proc_list;
- char buf[TTY_BUF_SIZE];
+ unsigned char buf[TTY_BUF_SIZE];
};
#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00)
#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)])
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
-#define GETCH(queue,c) \
-(void)({c=(queue)->buf[(queue)->tail];INC((queue)->tail);})
-#define PUTCH(c,queue) \
-(void)({(queue)->buf[(queue)->head]=(c);INC((queue)->head);})
+static inline void PUTCH(char c, struct tty_queue * queue)
+{
+ int head;
+
+ cli();
+ head = (queue->head + 1) & (TTY_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->buf[queue->head] = c;
+ queue->head = head;
+ }
+ sti();
+}
+
+static inline int GETCH(struct tty_queue * queue)
+{
+ int result = -1;
+
+ if (queue->tail != queue->head) {
+ result = 0xff & queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
+ }
+ return result;
+}
+
#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
#define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
+#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
+#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
+#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
+
+#define L_CANON(tty) _L_FLAG((tty),ICANON)
+#define L_ISIG(tty) _L_FLAG((tty),ISIG)
+#define L_ECHO(tty) _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
+
+#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
+#define I_NLCR(tty) _I_FLAG((tty),INLCR)
+#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
+#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
+#define I_IXON(tty) _I_FLAG((tty),IXON)
+#define I_STRP(tty) _I_FLAG((tty),ISTRIP)
+
+#define O_POST(tty) _O_FLAG((tty),OPOST)
+#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
+#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
+#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
+#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
+
+#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD)
+#define C_HUP(tty) (C_SPEED((tty)) == B0)
+
struct tty_struct {
struct termios termios;
int pgrp;
int session;
int stopped;
int busy;
+ int count;
struct winsize winsize;
void (*write)(struct tty_struct * tty);
struct tty_queue *read_q;
} while (0)
extern struct tty_struct tty_table[];
+extern struct tty_struct * redirect;
extern int fg_console;
extern unsigned long video_num_columns;
extern unsigned long video_num_lines;
*/
#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-void rs_init(void);
-void con_init(void);
-void tty_init(void);
+extern void rs_init(void);
+extern void lp_init(void);
+extern void con_init(void);
+extern void tty_init(void);
+
+extern void flush(struct tty_queue * queue);
-int tty_read(unsigned c, char * buf, int n, unsigned short flags);
-int tty_write(unsigned c, char * buf, int n);
+extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
+extern int is_orphaned_pgrp(int pgrp);
+extern int is_ignored(int sig);
+extern int tty_signal(int sig, struct tty_struct *tty);
-void con_write(struct tty_struct * tty);
-void rs_write(struct tty_struct * tty);
-void mpty_write(struct tty_struct * tty);
-void spty_write(struct tty_struct * tty);
+extern void rs_write(struct tty_struct * tty);
+extern void con_write(struct tty_struct * tty);
+extern void mpty_write(struct tty_struct * tty);
+extern void spty_write(struct tty_struct * tty);
extern void serial_open(unsigned int line);
void update_screen(int new_console);
+int kill_pg(int pgrp, int sig, int priv);
+
#endif
--- /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_stat 18
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_umount 22
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_stime 25
+#define __NR_ptrace 26
+#define __NR_alarm 27
+#define __NR_fstat 28
+#define __NR_pause 29
+#define __NR_utime 30
+#define __NR_stty 31
+#define __NR_gtty 32
+#define __NR_access 33
+#define __NR_nice 34
+#define __NR_ftime 35
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_prof 44
+#define __NR_brk 45
+#define __NR_setgid 46
+#define __NR_getgid 47
+#define __NR_signal 48
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_acct 51
+#define __NR_phys 52
+#define __NR_lock 53
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_mpx 56
+#define __NR_setpgid 57
+#define __NR_ulimit 58
+#define __NR_uname 59
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+#define __NR_sigaction 67
+#define __NR_sgetmask 68
+#define __NR_ssetmask 69
+#define __NR_setreuid 70
+#define __NR_setregid 71
+#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrlimit 76
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_getgroups 80
+#define __NR_setgroups 81
+#define __NR_select 82
+#define __NR_symlink 83
+#define __NR_lstat 84
+#define __NR_readlink 85
+#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
+#define __NR_readdir 89
+#define __NR_mmap 90
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_fchown 95
+/*
+ * Not all of these are implemented yet, but these are the
+ * numbers they will use.
+ */
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+#define __NR_profil 98
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+#define __NR_ioperm 101
+#define __NR_socketcall 102
+#define __NR_syslog 103
+
+extern int errno;
+
+/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name)); \
+if (__res >= 0) \
+ return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall1(type,name,atype,a) \
+type name(atype a) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"g" ((long)(a)):"bx"); \
+if (__res >= 0) \
+ return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall2(type,name,atype,a,btype,b) \
+type name(atype a,btype b) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \
+if (__res >= 0) \
+ return (type) __res; \
+errno = -__res; \
+return -1; \
+}
+
+#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+type name(atype a,btype b,ctype c) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \
+if (__res>=0) \
+ return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
+type name (atype a, btype b, ctype c, dtype d) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \
+ "d" ((long)(c)),"S" ((long)(d))); \
+if (__res>=0) \
+ return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \
+type name (atype a,btype b,ctype c,dtype d,etype e) \
+{ \
+long __res; \
+__asm__ volatile ("movl %2,%%ebx\n\t" \
+ "int $0x80" \
+ : "=a" (__res) \
+ : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \
+ "d" ((long)(c)),"S" ((long)(d)),"D" ((long)(e))); \
+if (__res>=0) \
+ return (type) __res; \
+errno=-__res; \
+return -1; \
+}
+
+#endif /* _LINUX_UNISTD_H */
+++ /dev/null
-#ifndef _STRING_H_
-#define _STRING_H_
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-#ifndef _SIZE_T
-#define _SIZE_T
-typedef unsigned int size_t;
-#endif
-
-extern char * strerror(int errno);
-
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- * (C) 1991 Linus Torvalds
- */
-
-extern inline char * strcpy(char * dest,const char *src)
-{
-__asm__("cld\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- ::"S" (src),"D" (dest):"si","di","ax");
-return dest;
-}
-
-extern inline char * strncpy(char * dest,const char *src,size_t count)
-{
-__asm__("cld\n"
- "1:\tdecl %2\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "rep\n\t"
- "stosb\n"
- "2:"
- ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");
-return dest;
-}
-
-extern inline char * strcat(char * dest,const char * src)
-{
-__asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
-return dest;
-}
-
-extern inline char * strncat(char * dest,const char * src,size_t count)
-{
-__asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n\t"
- "movl %4,%3\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %2,%2\n\t"
- "stosb"
- ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
- :"si","di","ax","cx");
-return dest;
-}
-
-extern inline int strcmp(const char * cs,const char * ct)
-{
-register int __res __asm__("ax");
-__asm__("cld\n"
- "1:\tlodsb\n\t"
- "scasb\n\t"
- "jne 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "jmp 3f\n"
- "2:\tmovl $1,%%eax\n\t"
- "jl 3f\n\t"
- "negl %%eax\n"
- "3:"
- :"=a" (__res):"D" (cs),"S" (ct):"si","di");
-return __res;
-}
-
-extern inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res __asm__("ax");
-__asm__("cld\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "scasb\n\t"
- "jne 3f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %%eax,%%eax\n\t"
- "jmp 4f\n"
- "3:\tmovl $1,%%eax\n\t"
- "jl 4f\n\t"
- "negl %%eax\n"
- "4:"
- :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
-return __res;
-}
-
-extern inline char * strchr(const char * s,char c)
-{
-register char * __res __asm__("ax");
-__asm__("cld\n\t"
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "je 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "movl $1,%1\n"
- "2:\tmovl %1,%0\n\t"
- "decl %0"
- :"=a" (__res):"S" (s),"0" (c):"si");
-return __res;
-}
-
-extern inline char * strrchr(const char * s,char c)
-{
-register char * __res __asm__("dx");
-__asm__("cld\n\t"
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "jne 2f\n\t"
- "movl %%esi,%0\n\t"
- "decl %0\n"
- "2:\ttestb %%al,%%al\n\t"
- "jne 1b"
- :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
-return __res;
-}
-
-extern inline size_t strspn(const char * cs, const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 1b\n"
- "2:\tdecl %0"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
-return __res-cs;
-}
-
-extern inline size_t strcspn(const char * cs, const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 1b\n"
- "2:\tdecl %0"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
-return __res-cs;
-}
-
-extern inline char * strpbrk(const char * cs,const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "movl %%ecx,%%edx\n"
- "1:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 2f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 1b\n\t"
- "decl %0\n\t"
- "jmp 3f\n"
- "2:\txorl %0,%0\n"
- "3:"
- :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
- :"ax","cx","dx","di");
-return __res;
-}
-
-extern inline char * strstr(const char * cs,const char * ct)
-{
-register char * __res __asm__("ax");
-__asm__("cld\n\t" \
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
- "movl %%ecx,%%edx\n"
- "1:\tmovl %4,%%edi\n\t"
- "movl %%esi,%%eax\n\t"
- "movl %%edx,%%ecx\n\t"
- "repe\n\t"
- "cmpsb\n\t"
- "je 2f\n\t" /* also works for empty string, see above */
- "xchgl %%eax,%%esi\n\t"
- "incl %%esi\n\t"
- "cmpb $0,-1(%%eax)\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "2:"
- :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
- :"cx","dx","di","si");
-return __res;
-}
-
-extern inline size_t strlen(const char * s)
-{
-register int __res __asm__("cx");
-__asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %0\n\t"
- "decl %0"
- :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
-return __res;
-}
-
-extern char * ___strtok;
-
-extern inline char * strtok(char * s,const char * ct)
-{
-register char * __res __asm__("si");
-__asm__("testl %1,%1\n\t"
- "jne 1f\n\t"
- "testl %0,%0\n\t"
- "je 8f\n\t"
- "movl %0,%1\n"
- "1:\txorl %0,%0\n\t"
- "movl $-1,%%ecx\n\t"
- "xorl %%eax,%%eax\n\t"
- "cld\n\t"
- "movl %4,%%edi\n\t"
- "repne\n\t"
- "scasb\n\t"
- "notl %%ecx\n\t"
- "decl %%ecx\n\t"
- "je 7f\n\t" /* empty delimeter-string */
- "movl %%ecx,%%edx\n"
- "2:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 7f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 2b\n\t"
- "decl %1\n\t"
- "cmpb $0,(%1)\n\t"
- "je 7f\n\t"
- "movl %1,%0\n"
- "3:\tlodsb\n\t"
- "testb %%al,%%al\n\t"
- "je 5f\n\t"
- "movl %4,%%edi\n\t"
- "movl %%edx,%%ecx\n\t"
- "repne\n\t"
- "scasb\n\t"
- "jne 3b\n\t"
- "decl %1\n\t"
- "cmpb $0,(%1)\n\t"
- "je 5f\n\t"
- "movb $0,(%1)\n\t"
- "incl %1\n\t"
- "jmp 6f\n"
- "5:\txorl %1,%1\n"
- "6:\tcmpb $0,(%0)\n\t"
- "jne 7f\n\t"
- "xorl %0,%0\n"
- "7:\ttestl %0,%0\n\t"
- "jne 8f\n\t"
- "movl %0,%1\n"
- "8:"
-#if __GNUC__ == 2
- :"=r" (__res)
-#else
- :"=b" (__res)
-#endif
- ,"=S" (___strtok)
- :"0" (___strtok),"1" (s),"g" (ct)
- :"ax","cx","dx","di");
-return __res;
-}
-
-extern inline void * memcpy(void * dest,const void * src, size_t n)
-{
-__asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
-return dest;
-}
-
-extern inline void * memmove(void * dest,const void * src, size_t n)
-{
-if (dest<src)
-__asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
-else
-__asm__("std\n\t"
- "rep\n\t"
- "movsb\n\t"
- "cld"
- ::"c" (n),"S" (src+n-1),"D" (dest+n-1)
- :"cx","si","di");
-return dest;
-}
-
-extern inline int memcmp(const void * cs,const void * ct,size_t count)
-{
-register int __res __asm__("ax");
-__asm__("cld\n\t"
- "repe\n\t"
- "cmpsb\n\t"
- "je 1f\n\t"
- "movl $1,%%eax\n\t"
- "jl 1f\n\t"
- "negl %%eax\n"
- "1:"
- :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
- :"si","di","cx");
-return __res;
-}
-
-extern inline void * memchr(const void * cs,char c,size_t count)
-{
-register void * __res __asm__("di");
-if (!count)
- return NULL;
-__asm__("cld\n\t"
- "repne\n\t"
- "scasb\n\t"
- "je 1f\n\t"
- "movl $1,%0\n"
- "1:\tdecl %0"
- :"=D" (__res):"a" (c),"D" (cs),"c" (count)
- :"cx");
-return __res;
-}
-
-extern inline void * memset(void * s,char c,size_t count)
-{
-__asm__("cld\n\t"
- "rep\n\t"
- "stosb"
- ::"a" (c),"D" (s),"c" (count)
- :"cx","di");
-return s;
-}
-
-#endif
--- /dev/null
+#ifndef _KD_H
+#define _KD_H
+
+/* 0x4B is 'K', to avoid collision with termios and vt */
+
+#define SWAPMONO 0x4B00 /* use mca as output device */
+#define SWAPCGA 0x4B01 /* use cga as output device */
+#define SWAPEGA 0x4B02 /* use ega as output device */
+#define SWAPVGA 0x4B03 /* use vga as output device */
+#define CONS_CURRENT 0x4B04 /* return current output device */
+#define MONO 0x01
+#define CGA 0x02
+#define EGA 0x03
+
+#define SW_B40x25 0x4B05 /* 40x25 mono text (cga/ega) */
+#define SW_C40x25 0x4B06 /* 40x24 color text (cga/ega) */
+#define SW_B80x25 0x4B07 /* 80x25 mono text (cga/ega) */
+#define SW_C80x25 0x4B08 /* 80x25 color text (cga/ega) */
+#define SW_BG320 0x4B09 /* 320x200 mono graphics (cga/ega) */
+#define SW_CG320 0x4B0A /* 320x200 color graphics (cga/ega) */
+#define SW_BG640 0x4B0B /* 640x200 mono graphics (cga/ega) */
+#define SW_CG320_D 0x4B0C /* 320x200 graphics (ega mode d) */
+#define SW_CG640_E 0x4B0D /* 640x200 graphics (ega mode e) */
+#define SW_EGAMONOAPA 0x4B0E /* 640x350 graphics (ega mode f) */
+#define SW_ENH_MONOAPA2 0x4B0F /* 640x350 graphics extd mem (ega mode f*) */
+#define SW_CG640x350 0x4B10 /* 640x350 graphics (ega mode 10) */
+#define SW_ENH_CG640 0x4B11 /* 640x350 graphics extd mem (ega mode 10*) */
+#define SW_EGAMONO80x25 0x4B12 /* 80x25 mono text (ega mode 7) */
+#define SW_ENHB40x25 0x4B13 /* enhanced 40x25 mono text (ega) */
+#define SW_ENHC40x25 0x4B14 /* enhanced 40x25 color text (ega) */
+#define SW_ENHB80x25 0x4B15 /* enhanced 80x25 mono text (ega) */
+#define SW_ENHC80x25 0x4B16 /* enhanced 80x25 color text (ega) */
+#define SW_ENHB80x43 0x4B17 /* enhanced 80x43 mono text (ega) */
+#define SW_ENHC80x43 0x4B18 /* enhanced 80x43 color text (ega) */
+#define SW_MCAMODE 0x4B19 /* reinit mca */
+#define SW_ATT640 0x4B1A /* 640x400 16color */
+/* should add more vga modes, etc */
+
+#define CONS_GET 0x4B1B /* get current display mode */
+#define M_B40x25 0 /* 40x25 mono (cga/ega) */
+#define M_C40x25 1 /* 40x25 color (cga/ega) */
+#define M_B80x25 2 /* 80x25 mono (cga/ega) */
+#define M_C80x25 3 /* 80x25 color (cga/ega) */
+#define M_BG320 4 /* 320x200 mono (cga/ega) */
+#define M_CG320 5 /* 320x200 color (cga/ega) */
+#define M_BG640 6 /* 640x200 mono (cga/ega) */
+#define M_EGAMONO80x25 7 /* 80x25 mono (ega) */
+#define M_CG320_D 13 /* ega mode d */
+#define M_CG640_E 14 /* ega mode e */
+#define M_EFAMONOAPA 15 /* ega mode f */
+#define M_CG640x350 16 /* ega mode 10 */
+#define M_ENHMONOAPA2 17 /* ega mode f with ext mem */
+#define M_ENH_CG640 18 /* ega mode 10* */
+#define M_ENH_B40x25 19 /* ega enh 40x25 mono */
+#define M_ENH_C40x25 20 /* ega enh 40x25 color */
+#define M_ENH_B80x25 21 /* ega enh 80x25 mono */
+#define M_ENH_C80x25 22 /* ega enh 80x25 color */
+#define M_ENH_B80x43 0x70 /* ega enh 80x43 mono */
+#define M_ENH_C80x43 0x71 /* ega enh 80x43 color */
+#define M_MCA_MODE 0xff /* monochrome adapter mode */
+#define MCA_GET 0x4B1C /* get mca display mode */
+#define CGA_GET 0x4B1D /* get cga display mode */
+#define EGA_GET 0x4B1E /* get ega display mode */
+
+#define MAPCONS 0x4B1F /* map current video mem into address space */
+#define MAPMONO 0x4B20 /* map mca video mem into address space */
+#define MAPCGA 0x4B21 /* map cga video mem into address space */
+#define MAPEGA 0x4B22 /* map ega video mem into address space */
+#define MAPVGA 0x4B23 /* map vga video mem into address space */
+
+struct port_io_struc {
+ char dir; /* direction in vs out */
+ unsigned short port;
+ char data;
+};
+#define IN_ON_PORT 0x00
+#define OUT_ON_PORT 0x01
+struct port_io_arg {
+ struct port_io_struc args[4];
+};
+#define MCAIO 0x4B24 /* i/o to mca video board */
+#define CGAIO 0x4B25 /* i/o to cga video board */
+#define EGAIO 0x4B26 /* i/o to ega video board */
+#define VGAIO 0x4B27 /* i/o to vga video board */
+
+#define GIO_FONT8x8 0x4B28 /* gets current 8x8 font used */
+#define PIO_FONT8x8 0x4B29 /* use supplied 8x8 font */
+#define GIO_FONT8x14 0x4B2A /* gets current 8x14 font used */
+#define PIO_FONT8x14 0x4B2B /* use supplied 8x14 font */
+#define GIO_FONT8x16 0x4B2C /* gets current 8x16 font used */
+#define PIO_FONT8x16 0x4B2D /* use supplied 8x16 font */
+
+#define MKDIOADDR 32 /* io bitmap size from <linux/sched.h> */
+struct kd_disparam {
+ long type; /* type of display */
+ char *addr; /* display mem address */
+ ushort ioaddr[MKDIOADDR]; /* valid i/o addresses */
+};
+#define KDDISPTYPE 0x4B2E /* gets display info */
+#define KD_MONO 0x01
+#define KD_HERCULES 0x02
+#define KD_CGA 0x03
+#define KD_EGA 0x04
+
+#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
+#define KDMKTONE 0x4B30 /* generate tone */
+
+#define KDGETLED 0x4B31 /* return current led flags */
+#define KDSETLED 0x4B32 /* set current led flags */
+#define LED_SCR 0x01 /* scroll lock */
+#define LED_CAP 0x04 /* caps lock */
+#define LED_NUM 0x02 /* num lock */
+
+#define KDGKBTYPE 0x4B33 /* get keyboard type */
+#define KB_84 0x01
+#define KB_101 0x02
+#define KB_OTHER 0x03
+
+#define KDADDIO 0x4B34 /* add i/o port as valid */
+#define KDDELIO 0x4B35 /* del i/o port as valid */
+#define KDENABIO 0x4B36 /* enable i/o to video board */
+#define KDDISABIO 0x4B37 /* disable i/o to video board */
+
+struct kd_quemode {
+ int qsize; /* desired # elem in queue */
+ int signo; /* signal to send when queue not empty */
+ char *qaddr; /* user virt addr of queue */
+};
+#define KDQUEMODE 0x4B38 /* enable/disable special queue mode */
+
+#define KDSBORDER 0x4B39 /* set screen boarder in ega text mode */
+
+#define KDSETMODE 0x4B3A /* set text/grahics mode */
+#define KD_TEXT 0x00
+#define KD_GRAPHICS 0x01
+#define KD_TEXT0 0x02 /* ? */
+#define KD_TEXT1 0x03 /* ? */
+#define KDGETMODE 0x4B3B /* get current mode */
+
+struct kd_memloc {
+ char *vaddr; /* virt addr to map to */
+ char *physaddr; /* phys addr to map from */
+ long length; /* number of bytes */
+ long ioflg; /* enable i/o if set */
+};
+#define KDMAPDISP 0x4B3C /* map display into address space */
+#define KDUNMAPDISP 0x4B3D /* unmap display from address space */
+
+#define KDVDCTYPE 0x4B3E /* return vdc controller/display info */
+
+#define KIOCINFO 0x4B3F /* tell what the device is */
+
+typedef char scrnmap_t;
+#define E_TABSZ 256
+#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */
+#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */
+
+#define GIO_ATTR 0x4B42 /* get screen attributes */
+#define GIO_COLOR 0x4B43 /* return nonzero if display is color */
+
+#define K_RAW 0x00
+#define K_XLATE 0x01
+#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
+#define KDSKBMODE 0x4B45 /* sets current keyboard mode */
+
+struct kbentry {
+ u_char kb_table;
+ u_char kb_index;
+ u_char kb_value;
+};
+#define K_NORMTAB 0x00
+#define K_SHIFTTAB 0x01
+#define K_ALTTAB 0x02
+#define K_ALTSHIFTTAB 0x03
+#define K_SRQTAB 0x04
+#define KDGKBENT 0x4B46 /* gets one entry in translation table */
+#define KDSKBENT 0x4B47 /* sets one entry in translation table */
+
+#endif /* _KD_H */
--- /dev/null
+#ifndef _MMAN_H
+#define _MMAN_H
+
+#define PROT_READ 0x1 /* page can be read */
+#define PROT_WRITE 0x2 /* page can be written */
+#define PROT_EXEC 0x4 /* page can be executed */
+#define PROT_NONE 0x0 /* page can not be accessed */
+
+#define MAP_SHARED 1 /* Share changes */
+#define MAP_PRIVATE 2 /* Changes are private */
+#define MAP_TYPE 0xf /* Mask for type of mapping */
+#define MAP_FIXED 0x10 /* Interpret addr exactly */
+
+extern caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd,
+ off_t off);
+extern int munmap(caddr_t addr, size_t len);
+
+#endif /* _MMAN_H */
int rlim_max;
};
+#define PRIO_MIN -99
+#define PRIO_MAX 14
+
+#define PRIO_PROCESS 0
+#define PRIO_PGRP 1
+#define PRIO_USER 2
+
#endif /* _SYS_RESOURCE_H */
--- /dev/null
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+struct sockaddr {
+ u_short sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+/*
+ * socket types
+ */
+#define SOCK_STREAM 1 /* stream (connection) socket */
+#define SOCK_DGRAM 2 /* datagram (connectionless) socket */
+#define SOCK_SEQPACKET 3 /* sequential packet socket */
+#define SOCK_RAW 4 /* raw socket */
+
+/*
+ * supported address families
+ */
+#define AF_UNSPEC 0
+#define AF_UNIX 1
+#define AF_INET 2
+
+/*
+ * protocol families, same as address families
+ */
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+
+int socket(int family, int type, int protocol);
+int socketpair(int family, int type, int protocol, int sockvec[2]);
+int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
+int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
+int listen(int sockfd, int backlog);
+int accept(int sockfd, struct sockaddr *peer, int *paddrlen);
+int getsockname(int sockfd, struct sockaddr *addr, int *paddrlen);
+int getpeername(int sockfd, struct sockaddr *peer, int *paddrlen);
+
+#endif /* _SOCKET_H */
};
#define S_IFMT 00170000
+#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#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
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;
--- /dev/null
+#ifndef _UN_H
+#define _UN_H
+
+struct sockaddr_un {
+ u_short sun_family; /* AF_UNIX */
+ char sun_path[108]; /* pathname */
+};
+
+#endif /* _UN_H */
--- /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 _VT_H
+#define _VT_H
+
+/* 0x56 is 'V', to avoid collision with termios and kd */
+
+#define VT_OPENQRY 0x5600 /* find available vt */
+
+struct vt_mode {
+ char mode; /* vt mode */
+ char waitv; /* if set, hang on writes if not active */
+ short relsig; /* signal to raise on release req */
+ short acqsig; /* signal to raise on acquisition */
+ short frsig; /* unused (set to 0) */
+};
+#define VT_GETMODE 0x5601 /* get mode of active vt */
+#define VT_SETMODE 0x5602 /* set mode of active vt */
+#define VT_AUTO 0x00 /* auto vt switching */
+#define VT_PROCESS 0x01 /* process controls switching */
+
+struct vt_stat {
+ ushort v_active; /* active vt */
+ ushort v_signal; /* signal to send */
+ ushort v_state; /* vt bitmask */
+};
+#define VT_GETSTATE 0x5603 /* get global vt state info */
+#define VT_SENDSIG 0x5604 /* signal to send to bitmask of vts */
+
+#define VT_RELDISP 0x5605 /* release display */
+
+#define VT_ACTIVATE 0x5606 /* make vt active */
+
+#endif /* _VT_H */
#define FIONREAD 0x541B
#define TIOCINQ FIONREAD
#define TIOCLINUX 0x541C
+#define TIOCCONS 0x541D
struct winsize {
unsigned short ws_row;
#include <utime.h>
#ifdef __LIBRARY__
-
-#define __NR_setup 0 /* used only by init, to get system going */
-#define __NR_exit 1
-#define __NR_fork 2
-#define __NR_read 3
-#define __NR_write 4
-#define __NR_open 5
-#define __NR_close 6
-#define __NR_waitpid 7
-#define __NR_creat 8
-#define __NR_link 9
-#define __NR_unlink 10
-#define __NR_execve 11
-#define __NR_chdir 12
-#define __NR_time 13
-#define __NR_mknod 14
-#define __NR_chmod 15
-#define __NR_chown 16
-#define __NR_break 17
-#define __NR_stat 18
-#define __NR_lseek 19
-#define __NR_getpid 20
-#define __NR_mount 21
-#define __NR_umount 22
-#define __NR_setuid 23
-#define __NR_getuid 24
-#define __NR_stime 25
-#define __NR_ptrace 26
-#define __NR_alarm 27
-#define __NR_fstat 28
-#define __NR_pause 29
-#define __NR_utime 30
-#define __NR_stty 31
-#define __NR_gtty 32
-#define __NR_access 33
-#define __NR_nice 34
-#define __NR_ftime 35
-#define __NR_sync 36
-#define __NR_kill 37
-#define __NR_rename 38
-#define __NR_mkdir 39
-#define __NR_rmdir 40
-#define __NR_dup 41
-#define __NR_pipe 42
-#define __NR_times 43
-#define __NR_prof 44
-#define __NR_brk 45
-#define __NR_setgid 46
-#define __NR_getgid 47
-#define __NR_signal 48
-#define __NR_geteuid 49
-#define __NR_getegid 50
-#define __NR_acct 51
-#define __NR_phys 52
-#define __NR_lock 53
-#define __NR_ioctl 54
-#define __NR_fcntl 55
-#define __NR_mpx 56
-#define __NR_setpgid 57
-#define __NR_ulimit 58
-#define __NR_uname 59
-#define __NR_umask 60
-#define __NR_chroot 61
-#define __NR_ustat 62
-#define __NR_dup2 63
-#define __NR_getppid 64
-#define __NR_getpgrp 65
-#define __NR_setsid 66
-#define __NR_sigaction 67
-#define __NR_sgetmask 68
-#define __NR_ssetmask 69
-#define __NR_setreuid 70
-#define __NR_setregid 71
-#define __NR_sigsuspend 72
-#define __NR_sigpending 73
-#define __NR_sethostname 74
-#define __NR_setrlimit 75
-#define __NR_getrlimit 76
-#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
-#define __NR_getgroups 80
-#define __NR_setgroups 81
-#define __NR_select 82
-#define __NR_symlink 83
-#define __NR_lstat 84
-#define __NR_readlink 85
-#define __NR_uselib 86
-#define __NR_swapon 87
-#define __NR_reboot 88
-#define __NR_readdir 89
-
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
-#define _syscall0(type,name) \
-type name(void) \
-{ \
-long __res; \
-__asm__ volatile ("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name)); \
-if (__res >= 0) \
- return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall1(type,name,atype,a) \
-type name(atype a) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
- "int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"g" ((long)(a)):"bx"); \
-if (__res >= 0) \
- return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall2(type,name,atype,a,btype,b) \
-type name(atype a,btype b) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
- "int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)):"bx"); \
-if (__res >= 0) \
- return (type) __res; \
-errno = -__res; \
-return -1; \
-}
-
-#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
-type name(atype a,btype b,ctype c) \
-{ \
-long __res; \
-__asm__ volatile ("movl %2,%%ebx\n\t" \
- "int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name),"g" ((long)(a)),"c" ((long)(b)),"d" ((long)(c)):"bx"); \
-if (__res>=0) \
- return (type) __res; \
-errno=-__res; \
-return -1; \
-}
-
+#include <linux/unistd.h>
#endif /* __LIBRARY__ */
/* XXX - illegal. */
int link(const char * filename1, const char * filename2);
off_t lseek(int fildes, off_t offset, int origin);
int mknod(const char * filename, mode_t mode, dev_t dev); /* XXX - shorts */
-int mount(const char * specialfile, const char * dir, int rwflag);
+int mount(const char * specialfile, const char * dir, const char * type, int rwflag);
int nice(int val);
int open(const char * filename, int flag, ...);
int pause(void);
* (C) 1991 Linus Torvalds
*/
-#define __LIBRARY__
-#include <unistd.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <fcntl.h>
#include <time.h>
+#include <sys/types.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/head.h>
+#include <linux/unistd.h>
+
/*
* we need this inline - forking from kernel space will result
* in NO COPY ON WRITE (!!!), until an execve is executed. This
static inline _syscall0(int,pause)
static inline _syscall1(int,setup,void *,BIOS)
static inline _syscall0(int,sync)
-
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/head.h>
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-
-#include <linux/fs.h>
-
-#include <string.h>
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall1(int,dup,int,fd)
+static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+
+static inline pid_t wait(int * wait_stat)
+{
+ return waitpid(-1,wait_stat,0);
+}
static char printbuf[1024];
-extern char *strcpy();
extern int vsprintf();
extern void init(void);
extern void blk_dev_init(void);
extern void chr_dev_init(void);
extern void hd_init(void);
extern void floppy_init(void);
+extern void sock_init(void);
extern void mem_init(long start, long end);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
+#ifdef CONFIG_SCSI
+extern void scsi_dev_init(void);
+#endif
+
static int sprintf(char * str, const char *fmt, ...)
{
va_list args;
#endif
mem_init(main_memory_start,memory_end);
trap_init();
- blk_dev_init();
+ sched_init();
chr_dev_init();
- tty_init();
+ blk_dev_init();
time_init();
- sched_init();
+ printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
+ sock_init();
sti();
+#ifdef CONFIG_SCSI
+ scsi_dev_init();
+#endif
move_to_user_mode();
if (!fork()) { /* we count on this going ok */
init();
CPP =cpp -nostdinc -I../include
+.S.s:
+ $(CPP) -traditional $< -o $*.s
.c.s:
$(CC) $(CFLAGS) \
-S -o $*.s $<
OBJS = sched.o sys_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
- signal.o mktime.o ptrace.o
+ signal.o mktime.o ptrace.o ioport.o
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
sync
+sys_call.s: sys_call.S
+
+sys_call.o: sys_call.s
+
sched.o: sched.c
$(CC) $(CFLAGS) -fno-omit-frame-pointer -c $<
clean:
- rm -f core *.o *.a tmp_make keyboard.s
+ rm -f core *.o *.a tmp_make sys_call.s
for i in *.c;do rm -f `basename $$i .c`.s;done
(cd chr_drv; make clean)
(cd blk_drv; make clean)
cp tmp_make Makefile
(cd chr_drv; make dep)
(cd blk_drv; make dep)
+ (cd math; make dep)
### Dependencies:
-exit.s exit.o : exit.c ../include/errno.h ../include/signal.h \
- ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/sys/param.h ../include/sys/time.h ../include/time.h \
- ../include/sys/resource.h ../include/linux/tty.h ../include/termios.h \
- ../include/asm/segment.h
-fork.s fork.o : fork.c ../include/errno.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+exit.s exit.o : exit.c ../include/errno.h ../include/signal.h ../include/sys/types.h \
+ ../include/sys/wait.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/linux/tty.h ../include/asm/system.h ../include/termios.h ../include/asm/segment.h
+fork.s fork.o : fork.c ../include/errno.h ../include/stddef.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
../include/asm/segment.h ../include/asm/system.h
+ioport.s ioport.o : ioport.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/errno.h
mktime.s mktime.o : mktime.c ../include/time.h
-panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+panic.s panic.o : panic.c ../include/linux/kernel.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
../include/time.h ../include/sys/resource.h
-printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h \
- ../include/linux/kernel.h
-ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h \
- ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/errno.h \
- ../include/asm/segment.h ../include/asm/system.h ../include/sys/ptrace.h
-sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/linux/timer.h \
- ../include/linux/sys.h ../include/linux/fdreg.h ../include/asm/system.h \
- ../include/asm/io.h ../include/asm/segment.h ../include/errno.h
-signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h \
- ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
- ../include/sys/wait.h ../include/errno.h
-sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/linux/tty.h ../include/termios.h ../include/linux/config.h \
- ../include/asm/segment.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/string.h
-traps.s traps.o : traps.c ../include/string.h ../include/linux/head.h \
- ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
- ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
- ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
- ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h \
+printk.s printk.o : printk.c ../include/stdarg.h ../include/stddef.h ../include/errno.h \
+ ../include/asm/segment.h ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h
+ptrace.s ptrace.o : ptrace.c ../include/linux/head.h ../include/linux/kernel.h ../include/linux/sched.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/errno.h ../include/asm/segment.h \
+ ../include/asm/system.h ../include/sys/ptrace.h
+sched.s sched.o : sched.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/linux/timer.h ../include/linux/sys.h \
+ ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h ../include/asm/segment.h \
+ ../include/errno.h
+signal.s signal.o : signal.c ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h ../include/sys/time.h \
+ ../include/time.h ../include/sys/resource.h ../include/asm/segment.h ../include/sys/wait.h \
../include/errno.h
-vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/string.h
+sys.s sys.o : sys.c ../include/errno.h ../include/linux/sched.h ../include/linux/head.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/linux/tty.h \
+ ../include/asm/system.h ../include/termios.h ../include/linux/config.h ../include/linux/config_rel.h \
+ ../include/linux/config_ver.h ../include/linux/config.dist.h ../include/asm/segment.h \
+ ../include/sys/times.h ../include/sys/utsname.h ../include/linux/string.h
+traps.s traps.o : traps.c ../include/linux/string.h ../include/linux/head.h ../include/linux/sched.h \
+ ../include/linux/fs.h ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/system.h \
+ ../include/asm/segment.h ../include/asm/io.h ../include/errno.h
+vsprintf.s vsprintf.o : vsprintf.c ../include/stdarg.h ../include/linux/string.h
*/
/*
- * asm.s contains the low-level code for most hardware faults.
- * page_exception is handled by the mm, so that isn't here. This
- * file also handles (hopefully) fpu-exceptions due to TS-bit, as
- * the fpu must be properly saved/resored. This hasn't been tested.
+ * asm.s contains the low-level code for interrupts that cannot
+ * result in an task-switch. These are things like the hd- and
+ * floppy-interrupt etc. With these interrupts, we don't have to
+ * care about the stack layout etc.
*/
-.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
-.globl _double_fault,_coprocessor_segment_overrun
-.globl _invalid_TSS,_segment_not_present,_stack_segment
-.globl _general_protection,_coprocessor_error,_irq13,_reserved
-.globl _alignment_check
-.globl _page_fault
+.globl _floppy_interrupt,_parallel_interrupt
-_divide_error:
- pushl $0 # no error code
- pushl $_do_divide_error
-error_code:
- push %fs
- push %es
- push %ds
+_floppy_interrupt:
+ cld
pushl %eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
pushl %ecx
- pushl %ebx
- cld
- movl $-1, %eax
- xchgl %eax, 0x2c(%esp) # orig_eax (get the error code. )
- xorl %ebx,%ebx # zero ebx
- mov %gs,%bx # get the lower order bits of gs
- xchgl %ebx, 0x28(%esp) # get the address and save gs.
- pushl %eax # push the error code
- lea 52(%esp),%edx
pushl %edx
- movl $0x10,%edx
- mov %dx,%ds
- mov %dx,%es
- mov %dx,%fs
- call *%ebx
- addl $8,%esp
- popl %ebx
- popl %ecx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0x20 # EOI to interrupt controller #1
+ xorl %eax,%eax
+ xchgl _do_floppy,%eax
+ testl %eax,%eax
+ jne 1f
+ movl $_unexpected_floppy_interrupt,%eax
+1: call *%eax # "interesting" way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
popl %edx
- popl %esi
- popl %edi
- popl %ebp
+ popl %ecx
popl %eax
- pop %ds
- pop %es
- pop %fs
- pop %gs
- addl $4,%esp
iret
-_debug:
- pushl $0
- pushl $_do_int3 # _do_debug
- jmp error_code
-
-_nmi:
- pushl $0
- pushl $_do_nmi
- jmp error_code
-
-_int3:
- pushl $0
- pushl $_do_int3
- jmp error_code
-
-_overflow:
- pushl $0
- pushl $_do_overflow
- jmp error_code
-
-_bounds:
- pushl $0
- pushl $_do_bounds
- jmp error_code
-
-_invalid_op:
- pushl $0
- pushl $_do_invalid_op
- jmp error_code
-
-_coprocessor_segment_overrun:
- pushl $0
- pushl $_do_coprocessor_segment_overrun
- jmp error_code
-
-_reserved:
- pushl $0
- pushl $_do_reserved
- jmp error_code
-
-_irq13:
+_parallel_interrupt:
+ cld
pushl %eax
- xorb %al,%al
- outb %al,$0xF0
movb $0x20,%al
outb %al,$0x20
- jmp 1f
-1: jmp 1f
-1: outb %al,$0xA0
popl %eax
- jmp _coprocessor_error
-
-_double_fault:
- pushl $_do_double_fault
- jmp error_code
-
-_invalid_TSS:
- pushl $_do_invalid_TSS
- jmp error_code
-
-_segment_not_present:
- pushl $_do_segment_not_present
- jmp error_code
-
-_stack_segment:
- pushl $_do_stack_segment
- jmp error_code
-
-_general_protection:
- pushl $_do_general_protection
- jmp error_code
-
-_alignment_check:
- pushl $_do_alignment_check
- jmp error_code
-
-_page_fault:
- pushl $_do_page_fault
- jmp error_code
+ iret
$(CC) $(CFLAGS) \
-c -o $*.o $<
-OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o
+OBJS = hd.o ll_rw_blk.o floppy.o ramdisk.o
+
+all: blk_drv.a
blk_drv.a: $(OBJS)
+ rm -f blk_drv.a
$(AR) rcs blk_drv.a $(OBJS)
sync
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
+ (cd scsi; make clean)
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
cp tmp_make Makefile
### Dependencies:
-floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/fdreg.h \
- ../../include/asm/system.h ../../include/asm/io.h \
- ../../include/asm/segment.h blk.h
-hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/timer.h \
- ../../include/linux/hdreg.h ../../include/asm/system.h \
- ../../include/asm/io.h ../../include/asm/segment.h blk.h
+floppy.s floppy.o : floppy.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/timer.h ../../include/linux/fdreg.h ../../include/linux/fd.h \
+ ../../include/asm/system.h ../../include/asm/io.h ../../include/asm/segment.h \
+ ../../include/errno.h blk.h
+hd.s hd.o : hd.c ../../include/errno.h ../../include/linux/config.h ../../include/linux/config_rel.h \
+ ../../include/linux/config_ver.h ../../include/linux/config.dist.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/timer.h ../../include/linux/hdreg.h \
+ ../../include/asm/system.h ../../include/asm/io.h ../../include/asm/segment.h \
+ blk.h
ll_rw_blk.s ll_rw_blk.o : ll_rw_blk.c ../../include/errno.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/asm/system.h blk.h
+ramdisk.s ramdisk.o : ramdisk.c ../../include/linux/string.h ../../include/linux/config.h \
+ ../../include/linux/config_rel.h ../../include/linux/config_ver.h ../../include/linux/config.dist.h \
+ ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
- ../../include/time.h ../../include/sys/resource.h \
- ../../include/asm/system.h blk.h
-ramdisk.s ramdisk.o : ramdisk.c ../../include/string.h ../../include/linux/config.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/minix_fs.h \
- ../../include/asm/system.h ../../include/asm/segment.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/minix_fs.h ../../include/asm/system.h ../../include/asm/segment.h \
../../include/asm/memory.h blk.h
#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
char * buffer;
struct task_struct * waiting;
struct buffer_head * bh;
+ struct buffer_head * bhtail;
struct request * next;
};
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == 8)
+/* scsi disk */
+#define DEVICE_NAME "scsidisk"
+#define DEVICE_INTR do_sd
+#define DEVICE_REQUEST do_sd_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == 9)
+/* scsi tape */
+#define DEVICE_NAME "scsitape"
+#define DEVICE_INTR do_st
+#define DEVICE_REQUEST do_st_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#elif
/* unknown blk device */
#error "unknown blk device"
wake_up(&bh->b_wait);
}
-extern inline void end_request(int uptodate)
+extern inline void next_buffer(int uptodate)
{
- DEVICE_OFF(CURRENT->dev);
- if (CURRENT->bh) {
- CURRENT->bh->b_uptodate = uptodate;
- unlock_buffer(CURRENT->bh);
- }
+ struct buffer_head *tmp;
+
+ CURRENT->bh->b_uptodate = uptodate;
+ unlock_buffer(CURRENT->bh);
if (!uptodate) {
printk(DEVICE_NAME " I/O error\n\r");
printk("dev %04x, block %d\n\r",CURRENT->dev,
CURRENT->bh->b_blocknr);
}
- wake_up(&CURRENT->waiting);
+ tmp = CURRENT->bh;
+ CURRENT->bh = CURRENT->bh->b_reqnext;
+ tmp->b_reqnext = NULL;
+ if (!CURRENT->bh)
+ panic("next_buffer: request buffer list destroyed\r\n");
+ CURRENT->buffer = CURRENT->bh->b_data;
+ CURRENT->errors = 0;
+}
+
+extern inline void end_request(int uptodate)
+{
+ struct request * tmp;
+
+ tmp = CURRENT;
+ DEVICE_OFF(tmp->dev);
+ CURRENT = tmp->next;
+ if (tmp->bh) {
+ tmp->bh->b_uptodate = uptodate;
+ unlock_buffer(tmp->bh);
+ }
+ if (!uptodate) {
+ printk(DEVICE_NAME " I/O error\n\r");
+ printk("dev %04x, block %d\n\r",tmp->dev,
+ tmp->bh->b_blocknr);
+ }
+ wake_up(&tmp->waiting);
+ tmp->dev = -1;
wake_up(&wait_for_request);
- CURRENT->dev = -1;
- CURRENT = CURRENT->next;
}
#ifdef DEVICE_INTR
* by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
*/
+/*
+ * Automatic floppy-detection and formatting written by Werner Almesberger
+ * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
+ * the floppy-change signa| detection.
+ */
+
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
+#include <linux/timer.h>
#include <linux/fdreg.h>
+#include <linux/fd.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
+#include <errno.h>
#define MAJOR_NR 2
#include "blk.h"
-unsigned int changed_floppies = 0;
+static unsigned int changed_floppies = 0, fake_change = 0;
static int recalibrate = 0;
static int reset = 0;
+static int recover = 0; /* recalibrate immediately after resetting */
static int seek = 0;
extern unsigned char current_DOR;
*/
#define MAX_ERRORS 12
+/*
+ * Maximum disk size (in kilobytes). This default is used whenever the
+ * current disk size is unknown.
+ */
+
+#define MAX_DISK_SIZE 1440
+
+/*
+ * Maximum number of sectors in a track buffer. Track buffering is disabled
+ * if tracks are bigger.
+ */
+
+#define MAX_BUFFER_SECTORS 18
+
/*
* globals used by 'result()'
*/
* types (ie 360kB diskette in 1.2MB drive etc). Others should
* be self-explanatory.
*/
-struct floppy_struct {
- unsigned int size, sect, head, track, stretch;
- unsigned char gap,rate,spec1;
-};
static struct floppy_struct floppy_type[] = {
- { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */
- { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */
- { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */
- { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */
- { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */
- { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */
- { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */
- { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */
+ { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* no testing */
+ { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB PC diskettes */
+ { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL }, /* 1.2 MB AT-diskettes */
+ { 720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB in 720kB drive */
+ { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL }, /* 3.5" 720kB diskette */
+ { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL }, /* 360kB in 1.2MB drive */
+ { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL }, /* 720kB in 1.2MB drive */
+ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }, /* 1.44MB diskette */
};
+/* For auto-detection. Each drive type has a pair of formats to try. */
+
+static struct floppy_struct floppy_types[] = {
+ { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
+ { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */
+ { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" }, /* 1.2 MB AT-diskettes */
+ { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */
+ { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */
+ { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */
+ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" }, /* 1.44MB diskette */
+ { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */
+};
+
+/* Auto-detection: Disk type used until the next media change occurs. */
+
+struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
+
+/* This type is tried first. */
+
+struct floppy_struct *base_type[4];
+
+/* User-provided type information. current_type points to the respective entry
+ of this array. */
+
+struct floppy_struct user_params[4];
+
+static int floppy_sizes[] ={
+ MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
+ 360, 360 ,360, 360,
+ 1200,1200,1200,1200,
+ 360, 360, 360, 360,
+ 720, 720, 720, 720,
+ 360, 360, 360, 360,
+ 720, 720, 720, 720,
+ 1440,1440,1440,1440
+};
+
+/* The driver is trying to determine the correct media format while probing
+ is set. rw_interrupts clears it after a successful access. */
+
+static int probing = 0;
+
+/* (User-provided) media information is _not_ discarded after a media change
+ if the corresponding keep_data flag is non-zero. Positive values are
+ decremented after each probe. */
+
+static int keep_data[4] = { 0,0,0,0 };
+
+/* Announce successful media type detection and media information loss after
+ disk changes. */
+
+static ftd_msg[4] = { 1,1,1,1 };
+
+/* Synchronization of FDC access. */
+
+static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
+static struct task_struct *fdc_wait = NULL, *format_done = NULL;
+
+/* Errors during formatting are counted here. */
+
+static int format_errors;
+
+/* Format request descriptor. */
+
+static struct format_descr format_req;
+
+/* Current device number. Taken either from the block header or from the
+ format request descriptor. */
+
+#define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \
+ (CURRENT->dev))
+
+/* Current error count. */
+
+#define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \
+ (CURRENT->errors))
+
/*
* Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps
* Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
extern void floppy_interrupt(void);
extern char tmp_floppy_area[1024];
-extern char floppy_track_buffer[512*2*18];
+extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
+
+static void redo_fd_request(void);
/*
* These are global variables, as that's the easiest way to give
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;
copy_buffer(CURRENT->buffer,tmp_floppy_area);
}
/* mask DMA 2 */
+ cli();
immoutb_p(4|2,10);
/* output command byte. I don't know why, but everyone (minix, */
/* sanches & canton) output this twice, first to 12 then to 11 */
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;
if (ST1 & 0x02) {
printk("Drive %d is write protected\n\r",current_drive);
floppy_deselect(current_drive);
- end_request(0);
+ request_done(0);
} else
bad_flp_intr();
- do_fd_request();
+ redo_fd_request();
return;
}
+ if (probing) {
+ int drive = MINOR(CURRENT->dev);
+
+ if (ftd_msg[drive])
+ printk("Auto-detected floppy type %s in fd%d\r\n",
+ floppy->name,drive);
+ current_type[drive] = floppy;
+ floppy_sizes[drive] = floppy->size >> 1;
+ probing = 0;
+ }
if (read_track) {
buffer_track = seek_track;
buffer_drive = current_drive;
(unsigned long)(CURRENT->buffer) >= 0x100000)
copy_buffer(tmp_floppy_area,CURRENT->buffer);
floppy_deselect(current_drive);
- end_request(1);
- do_fd_request();
+ request_done(1);
+ redo_fd_request();
}
/*
setup_DMA();
do_floppy = rw_interrupt;
output_byte(command);
- if (read_track) {
- output_byte(current_drive);
- output_byte(track);
- output_byte(0);
- output_byte(1);
+ if (command != FD_FORMAT) {
+ if (read_track) {
+ output_byte(current_drive);
+ output_byte(track);
+ output_byte(0);
+ output_byte(1);
+ } else {
+ output_byte(head<<2 | current_drive);
+ output_byte(track);
+ output_byte(head);
+ output_byte(sector);
+ }
+ output_byte(2); /* sector size = 512 */
+ output_byte(floppy->sect);
+ output_byte(floppy->gap);
+ output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
} else {
output_byte(head<<2 | current_drive);
- output_byte(track);
- output_byte(head);
- output_byte(sector);
+ output_byte(2);
+ output_byte(floppy->sect);
+ output_byte(floppy->fmt_gap);
+ output_byte(FD_FILL_BYTE);
}
- output_byte(2); /* sector size = 512 */
- output_byte(floppy->sect);
- output_byte(floppy->gap);
- output_byte(0xFF); /* sector size (0xff when n!=0 ?) */
if (reset)
- do_fd_request();
+ redo_fd_request();
}
/*
if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
recalibrate = 1;
bad_flp_intr();
- do_fd_request();
+ redo_fd_request();
return;
}
current_track = ST1;
*/
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);
if (cur_rate != floppy->rate)
outb_p(cur_rate = floppy->rate,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();
+
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)
output_byte(FD_RECALIBRATE);
output_byte(head<<2 | current_drive);
if (reset)
- do_fd_request();
+ redo_fd_request();
}
static void reset_interrupt(void)
output_byte(FD_SPECIFY);
output_byte(cur_spec1); /* hut etc */
output_byte(6); /* Head load time =6ms, DMA */
- do_fd_request();
+ if (!recover) redo_fd_request();
+ else {
+ recalibrate_floppy();
+ recover = 0;
+ }
}
/*
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;
+
+ for (count = 1; count <= floppy->sect; count++) {
+ *here++ = track;
+ *here++ = head;
+ *here++ = count;
+ *here++ = 2; /* 512 bytes */
+ }
+}
+
+static void redo_fd_request(void)
{
unsigned int block;
char * buffer_area;
-
- INIT_REQUEST;
+ int device;
+
+repeat:
+ if (format_status == FORMAT_WAIT) format_status = FORMAT_BUSY;
+ if (format_status != FORMAT_BUSY) {
+ if (!CURRENT) {
+ if (!fdc_busy) panic("FDC access conflict");
+ fdc_busy = 0;
+ wake_up(&fdc_wait);
+ CLEAR_INTR;
+ return;
+ }
+ if (MAJOR(CURRENT->dev) != MAJOR_NR)
+ panic(DEVICE_NAME ": request list destroyed"); \
+ if (CURRENT->bh) {
+ if (!CURRENT->bh->b_lock)
+ panic(DEVICE_NAME ": block not locked");
+ }
+ }
seek = 0;
- floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
- if (current_drive != CURRENT_DEV)
- current_track = NO_TRACK;
- current_drive = CURRENT_DEV;
- block = CURRENT->sector;
- if (block+2 > floppy->size) {
- end_request(0);
- goto repeat;
+ probing = 0;
+ device = MINOR(CURRENT_DEVICE);
+ if (device > 3)
+ floppy = (device >> 2) + floppy_type;
+ else { /* Auto-detection */
+ if ((floppy = current_type[device & 3]) == NULL) {
+ probing = 1;
+ if ((floppy = base_type[device & 3]) ==
+ NULL) {
+ request_done(0);
+ goto repeat;
+ }
+ floppy += CURRENT_ERRORS & 1;
+ }
+ }
+ if (format_status != FORMAT_BUSY) {
+ if (current_drive != CURRENT_DEV)
+ current_track = NO_TRACK;
+ current_drive = CURRENT_DEV;
+ block = CURRENT->sector;
+ if (block+2 > floppy->size) {
+ request_done(0);
+ goto repeat;
+ }
+ sector = block % floppy->sect;
+ block /= floppy->sect;
+ head = block % floppy->head;
+ track = block / floppy->head;
+ seek_track = track << floppy->stretch;
+ if (CURRENT->cmd == READ)
+ command = FD_READ;
+ else if (CURRENT->cmd == WRITE)
+ command = FD_WRITE;
+ else {
+ printk("do_fd_request: unknown command\n");
+ request_done(0);
+ goto repeat;
+ }
}
- sector = block % floppy->sect;
- block /= floppy->sect;
- head = block % floppy->head;
- track = block / floppy->head;
- seek_track = track << floppy->stretch;
- if (CURRENT->cmd == READ)
- command = FD_READ;
- else if (CURRENT->cmd == WRITE)
- command = FD_WRITE;
else {
- printk("do_fd_request: unknown command\n");
- end_request(0);
- goto repeat;
+ if (current_drive != (format_req.device & 3))
+ current_track = NO_TRACK;
+ current_drive = format_req.device & 3;
+ if (format_req.track < 0 || format_req.track >= floppy->track ||
+ (format_req.head & 0xfffe) || probing) {
+ request_done(0);
+ goto repeat;
+ }
+ head = format_req.head;
+ track = format_req.track;
+ seek_track = track << floppy->stretch;
+ if (seek_track == buffer_track) buffer_track = -1;
+ command = FD_FORMAT;
+ setup_format_params();
}
+ timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
+ timer_active |= 1 << FLOPPY_TIMER;
if ((seek_track == buffer_track) &&
(current_drive == buffer_drive)) {
buffer_area = floppy_track_buffer +
((sector + head*floppy->sect)<<9);
if (command == FD_READ) {
copy_buffer(buffer_area,CURRENT->buffer);
- end_request(1);
+ request_done(1);
goto repeat;
- } else
+ } else if (command == FD_WRITE)
copy_buffer(CURRENT->buffer,buffer_area);
}
if (seek_track != current_track)
add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
}
-static int floppy_sizes[] ={
- 0, 0, 0, 0,
- 360, 360 ,360, 360,
- 1200,1200,1200,1200,
- 360, 360, 360, 360,
- 720, 720, 720, 720,
- 360, 360, 360, 360,
- 720, 720, 720, 720,
- 1440,1440,1440,1440
+void do_fd_request(void)
+{
+ cli();
+ while (fdc_busy) sleep_on(&fdc_wait);
+ fdc_busy = 1;
+ sti();
+ redo_fd_request();
+}
+
+static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned int param)
+{
+ int drive,cnt,okay;
+ struct floppy_struct *this;
+
+ if (!suser()) return -EPERM;
+ drive = MINOR(inode->i_rdev);
+ switch (cmd) {
+ case FDFMTBEG:
+ return 0;
+ case FDFMTEND:
+ cli();
+ fake_change |= 1 << (drive & 3);
+ sti();
+ drive &= 3;
+ cmd = FDCLRPRM;
+ break;
+ case FDGETPRM:
+ if (drive > 3) this = &floppy_type[drive >> 2];
+ else if ((this = current_type[drive & 3]) == NULL)
+ return -ENODEV;
+ verify_area((void *) param,sizeof(struct floppy_struct));
+ for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
+ put_fs_byte(((char *) this)[cnt],
+ (char *) param+cnt);
+ return 0;
+ case FDFMTTRK:
+ cli();
+ while (format_status != FORMAT_NONE)
+ sleep_on(&format_done);
+ for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
+ ((char *) &format_req)[cnt] = get_fs_byte(
+ (char *) param+cnt);
+ format_req.device = drive;
+ format_status = FORMAT_WAIT;
+ format_errors = 0;
+ while (format_status != FORMAT_OKAY && format_status !=
+ FORMAT_ERROR) {
+ if (fdc_busy) sleep_on(&fdc_wait);
+ else {
+ fdc_busy = 1;
+ redo_fd_request();
+ }
+ }
+ while (format_status != FORMAT_OKAY && format_status !=
+ FORMAT_ERROR)
+ sleep_on(&format_done);
+ sti();
+ okay = format_status == FORMAT_OKAY;
+ format_status = FORMAT_NONE;
+ wake_up(&format_done);
+ return okay ? 0 : -EIO;
+ }
+ if (drive < 0 || drive > 3) return -EINVAL;
+ switch (cmd) {
+ case FDCLRPRM:
+ current_type[drive] = NULL;
+ floppy_sizes[drive] = MAX_DISK_SIZE;
+ keep_data[drive] = 0;
+ break;
+ case FDSETPRM:
+ case FDDEFPRM:
+ for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
+ ((char *) &user_params[drive])[cnt] =
+ get_fs_byte((char *) param+cnt);
+ current_type[drive] = &user_params[drive];
+ floppy_sizes[drive] = user_params[drive].size >> 1;
+ if (cmd == FDDEFPRM) keep_data[drive] = -1;
+ else {
+ cli();
+ while (fdc_busy) sleep_on(&fdc_wait);
+ fdc_busy = 1;
+ sti();
+ outb_p((current_DOR & 0xfc) | drive |
+ (0x10 << drive),FD_DOR);
+ for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
+ keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
+ outb_p(current_DOR,FD_DOR);
+ fdc_busy = 0;
+ wake_up(&fdc_wait);
+ }
+ break;
+ case FDMSGON:
+ ftd_msg[drive] = 1;
+ break;
+ case FDMSGOFF:
+ ftd_msg[drive] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#define CMOS_READ(addr) ({ \
+outb_p(0x80|addr,0x70); \
+inb_p(0x71); \
+})
+
+static struct floppy_struct *find_base(int drive,int code)
+{
+ struct floppy_struct *base;
+
+ if (code > 0 && code < 5) {
+ base = &floppy_types[(code-1)*2];
+ printk("fd%d is %s",drive,base->name);
+ return base;
+ }
+ printk("fd%d is unknown type %d",drive,code);
+ return NULL;
+}
+
+static void config_types(void)
+{
+ printk("Floppy drive(s): ");
+ base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
+ if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[0] = NULL;
+ else {
+ printk(", ");
+ base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
+ }
+ base_type[2] = base_type[3] = NULL;
+ printk("\r\n");
+}
+
+static int floppy_open(struct inode * inode, struct file * filp)
+{
+ if (filp->f_mode)
+ check_disk_change(inode->i_rdev);
+ return 0;
+}
+
+static void floppy_release(struct inode * inode, struct file * filp)
+{
+ sync_dev(inode->i_rdev);
+}
+
+static struct file_operations floppy_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ fd_ioctl, /* ioctl */
+ floppy_open, /* open */
+ floppy_release /* release */
};
void floppy_init(void)
outb(current_DOR,FD_DOR);
blk_size[MAJOR_NR] = floppy_sizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blkdev_fops[MAJOR_NR] = &floppy_fops;
+ timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
+ timer_active &= ~(1 << FLOPPY_TIMER);
+ config_types();
set_intr_gate(0x26,&floppy_interrupt);
outb(inb_p(0x21)&~0x40,0x21);
}
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.
*/
current_minor, hd[current_minor].start_sect,
hd[current_minor].nr_sects,
hd[current_minor].start_sect +
- hd[current_minor].nr_sects);
+ hd[current_minor].nr_sects - 1);
current_minor++;
p++;
/*
hd[minor].start_sect = first_sector + p->start_sect;
printk(" part %d start %d size %d end %d \n\r", i,
hd[minor].start_sect, hd[minor].nr_sects,
- hd[minor].start_sect + hd[minor].nr_sects);
+ hd[minor].start_sect + hd[minor].nr_sects - 1);
if ((current_minor & 0x3f) >= 60)
continue;
if (p->sys_ind == EXTENDED_PARTITION) {
hd[current_minor].start_sect,
hd[current_minor].nr_sects,
hd[current_minor].start_sect +
- hd[current_minor].nr_sects);
+ hd[current_minor].nr_sects - 1);
}
}
} else
return (0);
}
+#if (HD_DELAY > 0)
+unsigned long read_timer(void)
+{
+ unsigned long t;
+ int i;
+
+ cli();
+ outb_p(0xc2, 0x43);
+ t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
+ i = inb_p(0x40);
+ i |= inb(0x40) << 8;
+ sti();
+ return(t - i / 2);
+}
+#endif
+
static int controller_ready(void)
{
int retries = 100000;
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)
{
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);
if (!CURRENT)
return;
if (++CURRENT->errors >= MAX_ERRORS)
- end_request(0);
+ if (CURRENT->bh && CURRENT->nr_sectors > 2) {
+ CURRENT->nr_sectors &= ~1;
+ next_buffer(0);
+ } else
+ end_request(0);
if (CURRENT->errors > MAX_ERRORS/2)
reset = 1;
else
recalibrate = 1;
}
+#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
+#define STAT_OK (READY_STAT | SEEK_STAT)
+
static void read_intr(void)
{
- SET_INTR(&read_intr);
- if (win_result()) {
- SET_INTR(NULL);
- bad_rw_intr();
- do_hd_request();
- return;
- }
+ int i;
+
+ i = (unsigned) inb_p(HD_STATUS);
+ if (!(i & DRQ_STAT))
+ goto bad_read;
+ if ((i & STAT_MASK) != STAT_OK)
+ goto bad_read;
port_read(HD_DATA,CURRENT->buffer,256);
+ i = (unsigned) inb_p(HD_STATUS);
+ if (!(i & BUSY_STAT))
+ if ((i & STAT_MASK) != STAT_OK)
+ goto bad_read;
CURRENT->errors = 0;
- CURRENT->buffer += 512;
+ if (CURRENT->bh && (CURRENT->nr_sectors&1) && CURRENT->nr_sectors > 2)
+ next_buffer(1);
+ else
+ CURRENT->buffer += 512;
CURRENT->sector++;
- if (--CURRENT->nr_sectors)
+ if (--CURRENT->nr_sectors) {
+ SET_INTR(&read_intr);
return;
- SET_INTR(NULL);
+ }
end_request(1);
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
do_hd_request();
+ return;
+bad_read:
+ if (i & ERR_STAT)
+ i = (unsigned) inb(HD_ERROR);
+ bad_rw_intr();
+ do_hd_request();
+ return;
}
static void write_intr(void)
{
- if (win_result()) {
- bad_rw_intr();
+ int i;
+
+ i = (unsigned) inb_p(HD_STATUS);
+ if ((i & STAT_MASK) != STAT_OK)
+ goto bad_write;
+ if (CURRENT->nr_sectors < 2) {
+ end_request(1);
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
do_hd_request();
return;
}
- if (--CURRENT->nr_sectors) {
- CURRENT->sector++;
+ if (!(i & DRQ_STAT))
+ goto bad_write;
+ CURRENT->sector++;
+ CURRENT->nr_sectors--;
+ if (CURRENT->bh && !(CURRENT->nr_sectors & 1))
+ next_buffer(1);
+ else
CURRENT->buffer += 512;
- SET_INTR(&write_intr);
- port_write(HD_DATA,CURRENT->buffer,256);
- return;
- }
- end_request(1);
+ SET_INTR(&write_intr);
+ port_write(HD_DATA,CURRENT->buffer,256);
+ return;
+bad_write:
+ if (i & ERR_STAT)
+ i = (unsigned) inb(HD_ERROR);
+ bad_rw_intr();
do_hd_request();
+ return;
}
static void recal_intr(void)
printk("HD timeout\n\r");
cli();
if (++CURRENT->errors >= MAX_ERRORS)
- end_request(0);
+ if (CURRENT->bh && CURRENT->nr_sectors > 2) {
+ CURRENT->nr_sectors &= ~1;
+ next_buffer(0);
+ } else
+ end_request(0);
do_hd_request();
}
}
if (recalibrate) {
recalibrate = 0;
- hd_out(dev,hd_info[dev].sect,0,0,0,
- WIN_RESTORE,&recal_intr);
+ hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
if (reset)
goto repeat;
return;
panic("unknown hd-command");
}
-void hd_init(void)
-{
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- set_intr_gate(0x2E,&hd_interrupt);
- outb_p(inb_p(0x21)&0xfb,0x21);
- outb(inb_p(0xA1)&0xbf,0xA1);
- timer_table[HD_TIMER].fn = hd_times_out;
-}
-
-int hd_ioctl(int dev, int cmd, int arg)
+static int hd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned int arg)
{
struct hd_geometry *loc = (void *) arg;
+ int dev;
- if (!loc)
+ if (!loc || !inode)
return -EINVAL;
- dev = MINOR(dev) >> 6;
+ dev = MINOR(inode->i_rdev) >> 6;
if (dev >= NR_HD)
return -EINVAL;
-
switch (cmd) {
case HDIO_REQ:
+ verify_area(loc, sizeof(*loc));
put_fs_byte(hd_info[dev].head,
(char *) &loc->heads);
put_fs_byte(hd_info[dev].sect,
return -EINVAL;
}
}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static void hd_release(struct inode * inode, struct file * file)
+{
+ sync_dev(inode->i_rdev);
+}
+
+static struct file_operations hd_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ hd_ioctl, /* ioctl */
+ NULL, /* no special open code */
+ hd_release /* release */
+};
+
+void hd_init(void)
+{
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blkdev_fops[MAJOR_NR] = &hd_fops;
+ set_intr_gate(0x2E,&hd_interrupt);
+ outb_p(inb_p(0x21)&0xfb,0x21);
+ outb(inb_p(0xA1)&0xbf,0xA1);
+ timer_table[HD_TIMER].fn = hd_times_out;
+}
{ 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 */
};
/*
return;
}
repeat:
+ cli();
+ if (major == 3 && (req = blk_dev[major].current_request)) {
+ while (req = req->next) {
+ if (req->dev == bh->b_dev &&
+ !req->waiting &&
+ req->cmd == rw &&
+ req->sector + req->nr_sectors == bh->b_blocknr << 1 &&
+ req->nr_sectors < 254) {
+ req->bhtail->b_reqnext = bh;
+ req->bhtail = bh;
+ req->nr_sectors += 2;
+ bh->b_dirt = 0;
+ sti();
+ return;
+ }
+ }
+ }
/* we don't allow the write-requests to fill up the queue completely:
* we want some room for reads: they take precedence. The last third
* of the requests are only for reads.
if (rw == READ)
req = request+NR_REQUEST;
else
- req = request+((NR_REQUEST*2)/3);
+ req = request+(NR_REQUEST/2);
/* find an empty request */
- cli();
while (--req >= request)
if (req->dev < 0)
goto found;
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;
+ if (!bh)
+ return;
if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
!(blk_dev[major].request_fn)) {
printk("ll_rw_block: Trying to read nonexistent block-device\n\r");
* Written by Theodore Ts'o, 12/2/91
*/
-#include <string.h>
+#include <linux/string.h>
#include <linux/config.h>
#include <linux/sched.h>
goto repeat;
}
+static struct file_operations rd_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ NULL, /* ioctl */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
/*
* Returns amount of memory which needs to be reserved.
*/
char *cp;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blkdev_fops[MAJOR_NR] = &rd_fops;
rd_start = (char *) mem_start;
rd_length = length;
cp = rd_start;
--- /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
+
+AR =ar
+AS =as
+LD =ld
+LDFLAGS =-s -x
+CC =cc
+
+CPP =cc -E -nostdinc -I../../../include
+
+.c.s:
+ $(CC) -nostdinc $(CFLAGS) $(DEBUG) \
+ -S -o $*.s $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) -nostdinc -I../../../include $(CFLAGS) $(DEBUG) \
+ -c -o $*.o $<
+
+LOWLEVELCSRC = aha1542.c seagate.c ultrastor.c
+LOWLEVELHSRC = aha1542.c seagate.h ultrastor.h
+
+CSRC = hosts.c sd.c st.c scsi.c $(LOWLEVELCSRC)
+HSRC = hosts.h sd.h st.h scsi.h $(LOWLEVELHSRC)
+
+OBJS = scsi.o hosts.o scsi_ioctl.o sd.o sd_ioctl.o st.o st_ioctl.o \
+ aha1542.o seagate.o ultrastor.o
+
+all: scsi.a
+
+config.out : config.in ../../../include/linux/config.h
+ rm -f foo.c
+ ln -s config.in foo.c
+ $(CPP) foo.c | grep '\.o' > config.out
+ rm foo.c
+
+figure : hosts.h ../../../include/linux/config.h hosts.c config.out
+ $(CC) -I../../../include -DFIGURE_MAX_SCSI_HOSTS hosts.c -o figure
+
+max_hosts.h : figure
+ (echo "#ifndef _MAX_HOSTS_H"; \
+ echo "#define _MAX_HOSTS_H"; \
+ echo "#define MAX_SCSI_HOSTS `./figure`";\
+ echo "#endif") > tmp_max
+ cp tmp_max max_hosts.h
+
+scsi.a: $(OBJS)
+ $(AR) rcs scsi.a $(OBJS)
+ sync
+
+scsi.shar: Makefile scsi.doc $(CSRC) $(HSRC) ../ll_rw_blk.c ../blk.h all.diff
+ (cd ..; shar scsi/scsi.doc scsi/Makefile scsi/*.{c,h} scsi/all.diff blk.h ll_rw_blk.c) > scsi.shar;
+
+clean:
+ rm -f core *.o *.a tmp_make tmp_max figure config.out Makefile.tag max_hosts.h
+
+seagate.s seagate.o : seagate.c ../../../include/linux/config.h \
+ ../../../include/linux/config.dist.h ../../../include/linux/sched.h \
+ ../../../include/linux/head.h ../../../include/linux/fs.h \
+ ../../../include/sys/types.h ../../../include/linux/mm.h \
+ ../../../include/linux/kernel.h ../../../include/signal.h \
+ ../../../include/sys/param.h ../../../include/sys/time.h \
+ ../../../include/time.h ../../../include/sys/resource.h \
+ ../../../include/linux/string.h seagate.h scsi.h hosts.h max_hosts.h
+ cc -nostdinc -I../../../include -Wall -c seagate.c $(DEBUG)
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c ;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
+ $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+aha1542.s aha1542.o : aha1542.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+ ../../../include/linux/head.h ../../../include/linux/string.h ../../../include/asm/system.h \
+ ../../../include/asm/io.h scsi.h hosts.h max_hosts.h aha1542.h
+hosts.s hosts.o : hosts.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+ scsi.h hosts.h max_hosts.h aha1542.h seagate.h ultrastor.h
+scsi.s scsi.o : scsi.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/asm/system.h \
+ ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+ ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+ ../../../include/linux/mm.h ../../../include/linux/kernel.h ../../../include/signal.h \
+ ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+ ../../../include/sys/resource.h ../../../include/linux/timer.h ../../../include/linux/string.h \
+ scsi.h hosts.h max_hosts.h sd.h st.h
+scsi_ioctl.s scsi_ioctl.o : scsi_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/errno.h \
+ ../../../include/asm/io.h ../../../include/asm/segment.h ../../../include/asm/system.h \
+ ../../../include/linux/kernel.h ../../../include/linux/sched.h ../../../include/linux/head.h \
+ ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+ ../../../include/limits.h ../../../include/linux/mm.h ../../../include/signal.h \
+ ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+ ../../../include/sys/resource.h ../../../include/linux/string.h scsi.h hosts.h \
+ max_hosts.h scsi_ioctl.h
+sd.s sd.o : sd.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/string.h \
+ ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+ ../../../include/limits.h ../../../include/linux/kernel.h ../../../include/linux/sched.h \
+ ../../../include/linux/head.h ../../../include/linux/mm.h ../../../include/signal.h \
+ ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+ ../../../include/sys/resource.h scsi.h sd.h ../blk.h
+sd_ioctl.s sd_ioctl.o : sd_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+ ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+ ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+ ../../../include/linux/mm.h ../../../include/signal.h ../../../include/sys/param.h \
+ ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+ scsi.h sd.h
+seagate.s seagate.o : seagate.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/sched.h \
+ ../../../include/linux/head.h ../../../include/linux/fs.h ../../../include/sys/types.h \
+ ../../../include/sys/dirent.h ../../../include/limits.h ../../../include/linux/mm.h \
+ ../../../include/linux/kernel.h ../../../include/signal.h ../../../include/sys/param.h \
+ ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+ seagate.h scsi.h hosts.h max_hosts.h
+st.s st.o : st.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h scsi.h \
+ st.h ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+ ../../../include/limits.h ../../../include/linux/kernel.h ../../../include/linux/sched.h \
+ ../../../include/linux/head.h ../../../include/linux/mm.h ../../../include/signal.h \
+ ../../../include/sys/param.h ../../../include/sys/time.h ../../../include/time.h \
+ ../../../include/sys/resource.h ../blk.h
+st_ioctl.s st_ioctl.o : st_ioctl.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/linux/kernel.h \
+ ../../../include/linux/sched.h ../../../include/linux/head.h ../../../include/linux/fs.h \
+ ../../../include/sys/types.h ../../../include/sys/dirent.h ../../../include/limits.h \
+ ../../../include/linux/mm.h ../../../include/signal.h ../../../include/sys/param.h \
+ ../../../include/sys/time.h ../../../include/time.h ../../../include/sys/resource.h \
+ st.h scsi.h
+ultrastor.s ultrastor.o : ultrastor.c ../../../include/linux/config.h ../../../include/linux/config_rel.h \
+ ../../../include/linux/config_ver.h ../../../include/linux/config.dist.h ../../../include/stddef.h \
+ ../../../include/linux/string.h ../../../include/linux/sched.h ../../../include/linux/head.h \
+ ../../../include/linux/fs.h ../../../include/sys/types.h ../../../include/sys/dirent.h \
+ ../../../include/limits.h ../../../include/linux/mm.h ../../../include/linux/kernel.h \
+ ../../../include/signal.h ../../../include/sys/param.h ../../../include/sys/time.h \
+ ../../../include/time.h ../../../include/sys/resource.h ../../../include/linux/hdreg.h \
+ ../../../include/asm/system.h ../../../include/asm/io.h ../../../include/asm/segment.h \
+ ultrastor.h scsi.h hosts.h max_hosts.h
--- /dev/null
+/* $Id: aha1542.c,v 1.1 1992/04/24 18:01:50 root Exp root $
+ * linux/kernel/aha1542.c
+ *
+ * (C) 1992 Tommy Thorn
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include "hosts.h"
+
+#include "aha1542.h"
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+#define base 0x330
+#define intr_chan 11
+
+static struct mailbox mb[2];
+static struct ccb ccb;
+
+long WAITtimeout, WAITnexttimeout = 3000000;
+
+void (*do_done)() = NULL;
+extern void aha1542_interrupt();
+
+#define aha1542_intr_reset() outb(IRST, CONTROL)
+#define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
+#define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
+
+#define WAIT(port, mask, allof, noneof) \
+ { register WAITbits; \
+ register WAITtimeout = WAITnexttimeout; \
+ while (1) { \
+ WAITbits = inb(port) & (mask); \
+ if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+ break; \
+ if (--WAITtimeout == 0) goto fail; \
+ } \
+ }
+
+static void aha1542_stat(void)
+{
+ int s = inb(STATUS), i = inb(INTRFLAGS);
+/* printk("status = %x, intrflags = %x served %d last %x timeout %d\n", s, i, intr_flag, intr_last, WAITtimeout); */
+ printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout);
+}
+
+static int aha1542_out(unchar *cmdp, int len)
+{
+ while (len--)
+ {
+ WAIT(STATUS, CDF, 0, CDF);
+ outb(*cmdp++, DATA);
+ }
+ return 0;
+ fail:
+ printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
+ return 1;
+}
+
+int makecode(unsigned hosterr, unsigned scsierr)
+{
+ switch (hosterr) {
+ case 0x0:
+ case 0xa: /* Linked command complete without error and linked normally */
+ case 0xb: /* Linked command complete without error, interrupt generated */
+ hosterr = 0;
+ break;
+
+ case 0x11: /* Selection time out-The initiator selection or target
+ reselection was not complete within the SCSI Time out period */
+ hosterr = DID_TIME_OUT;
+ break;
+
+ case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
+ thean was allocated by the Data Length field or the sum of the
+ Scatter / Gather Data Length fields. */
+
+ case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+ case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
+ invalid. This usually indicates a software failure. */
+
+ case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+ This usually indicates a software failure. */
+
+ case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
+ of linked CCB's does not specify the same logical unit number as
+ the first. */
+ case 0x18: /* Invalid Target Direction received from Host-The direction of a
+ Target Mode CCB was invalid. */
+
+ case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
+ received to service data transfer between the same target LUN
+ and initiator SCSI ID in the same direction. */
+
+ case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
+ length segment or invalid segment list boundaries was received.
+ A CCB parameter was invalid. */
+ hosterr = DID_ERROR; /* Couldn't find any better */
+ break;
+
+ case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
+ phase sequence was requested by the target. The host adapter
+ will generate a SCSI Reset Condition, notifying the host with
+ a SCRD interrupt */
+ hosterr = DID_RESET;
+ break;
+ default:
+ printk("makecode: unknown hoststatus %x\n", hosterr);
+ break;
+ }
+ return scsierr|(hosterr << 16);
+}
+
+int aha1542_test_port(void)
+{
+ volatile int debug = 0;
+
+ /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
+
+ /* DEB(printk("aha1542_test_port called \n")); */
+
+ outb(SRST|IRST/*|SCRST*/, CONTROL);
+
+ debug = 1;
+ /* Expect INIT and IDLE, any of the others are bad */
+ WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+
+ debug = 2;
+ /* Shouldn't have generated any interrupts during reset */
+ if (inb(INTRFLAGS)&INTRMASK) goto fail;
+
+ debug = 3;
+ /* Test the basic ECHO command */
+ outb(CMD_ECHO, DATA);
+
+ debug = 4;
+ /* Wait for CDF=0. If any of the others are set, it's bad */
+ WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
+
+ debug = 5;
+ /* The meaning of life */
+ outb(42, DATA);
+
+ debug = 6;
+ /* Expect only DF, that is, data ready */
+ WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
+
+ debug = 7;
+ /* Is the answer correct? */
+ if (inb(DATA) != 42) goto fail;
+
+ debug = 8;
+ /* Reading port should reset DF */
+ if (inb(STATUS) & DF) goto fail;
+
+ debug = 9;
+ /* When HACC, command is completed, and we're though testing */
+ WAIT(INTRFLAGS, HACC, HACC, 0);
+ /* now initialize adapter */
+
+ debug = 10;
+ /* Clear interrupts */
+ outb(IRST, CONTROL);
+
+ debug = 11;
+
+ return debug; /* 1 = ok */
+ fail:
+ return 0; /* 0 = not ok */
+}
+
+/* What's this little function for? */
+char *aha1542_info(void)
+{
+ static char buffer[] = "Adaptec 1542";
+ return buffer;
+}
+
+/* A "high" level interrupt handler */
+void aha1542_intr_handle(void)
+{
+ int flag = inb(INTRFLAGS);
+ void (*my_done)() = do_done;
+ int errstatus;
+
+ do_done = NULL;
+#ifdef DEBUG
+ printk("aha1542_intr_handle: ");
+ if (!(flag&ANYINTR)) printk("no interrupt?");
+ if (flag&MBIF) printk("MBIF ");
+ if (flag&MBOA) printk("MBOF ");
+ if (flag&HACC) printk("HACC ");
+ if (flag&SCRD) printk("SCRD ");
+ printk("status %02x\n", inb(STATUS));
+ if (ccb.tarstat|ccb.hastat)
+ printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
+#endif
+ aha1542_intr_reset();
+ if (!my_done) {
+ printk("aha1542_intr_handle: Unexpected interrupt\n");
+ return;
+ }
+
+ /* is there mail :-) */
+
+ if (!mb[1].status) {
+ DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
+ my_done(DID_TIME_OUT << 16);
+ return;
+ }
+
+ /* more error checking left out here */
+ if (mb[1].status != 1)
+ /* This is surely wrong, but I don't know what's right */
+ errstatus = makecode(ccb.hastat, ccb.tarstat);
+ else
+ errstatus = 0;
+
+ mb[1].status = 0;
+
+ if (ccb.tarstat == 2) {
+ int i;
+ DEB(printk("aha1542_intr_handle: sense:"));
+ for (i = 0; i < 12; i++)
+ printk("%02x ", ccb.cdb[ccb.cdblen+i]);
+ printk("\n");
+/*
+ DEB(printk("aha1542_intr_handle: buf:"));
+ for (i = 0; i < bufflen; i++)
+ printk("%02x ", ((unchar *)buff)[i]);
+ printk("\n");
+*/
+ }
+ DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+ my_done(errstatus);
+ return;
+}
+
+int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int))
+{
+ unchar ahacmd = CMD_START_SCSI;
+ int i;
+ unchar *cmd = (unchar *) cmnd;
+
+ DEB(if (target > 1) {done(DID_TIME_OUT << 16); return 0;});
+
+#ifdef DEBUG
+ if (*cmd == READ_10 || *cmd == WRITE_10)
+ i = xscsi2int(cmd+2);
+ else if (*cmd == READ_6 || *cmd == WRITE_6)
+ i = scsi2int(cmd+2);
+ else
+ i = -1;
+ if (done)
+ printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ else
+ printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ aha1542_stat();
+ printk("aha1542_queuecommand: dumping scsi cmd:");
+ for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
+ printk("\n");
+ if (*cmd == WRITE_10 || *cmd == WRITE_6)
+ return 0; /* we are still testing, so *don't* write */
+#endif
+ memset(&ccb, 0, sizeof ccb);
+
+ ccb.cdblen = (*cmd<=0x1f)?6:10; /* SCSI Command Descriptor Block Length */
+
+ memcpy(ccb.cdb, cmd, ccb.cdblen);
+ ccb.op = 0; /* SCSI Initiator Command */
+ ccb.idlun = (target&7)<<5; /* SCSI Target Id */
+ ccb.rsalen = 12;
+ any2scsi(ccb.datalen, bufflen);
+ any2scsi(ccb.dataptr, buff);
+ ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
+ ccb.commlinkid = 0;
+
+ mb[0].status = 1;
+ mb[1].status = 0;
+
+#ifdef DEBUGd
+ printk("aha1542_command: sending.. ");
+ for (i = 0; i < sizeof(ccb)-10; i++)
+ printk("%02x ", ((unchar *)&ccb)[i]);
+#endif
+
+ if (done) {
+ DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
+ if (do_done)
+ printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
+ else
+ do_done = done;
+ aha1542_out(&ahacmd, 1); /* start scsi command */
+ DEB(aha1542_stat());
+ aha1542_enable_intr();
+ }
+ else
+ printk("aha1542_queuecommand: done can't be NULL\n");
+
+ return 0;
+}
+
+volatile static int internal_done_flag = 0;
+volatile static int internal_done_errcode = 0;
+static void internal_done(int errcode)
+{
+ internal_done_errcode = errcode;
+ ++internal_done_flag;
+}
+
+int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
+{
+ DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
+ aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
+
+ while (!internal_done_flag);
+ internal_done_flag = 0;
+ return internal_done_errcode;
+}
+
+/* Initialize mailboxes */
+static void setup_mailboxes()
+{
+ static unchar cmd[5] = {CMD_MBINIT, 1};
+
+ mb[0].status = mb[1].status = 0;
+ aha1542_intr_reset(); /* reset interrupts, so they don't block */
+ any2scsi((cmd+2), mb);
+ any2scsi(mb[0].ccbptr, &ccb);
+ aha1542_out(cmd, 5);
+ WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ while (0) {
+ fail:
+ printk("aha1542_detect: failed setting up mailboxes\n");
+ }
+ aha1542_intr_reset();
+}
+
+/* a hack to avoid a strange compilation error */
+
+void call_buh()
+{
+ set_intr_gate(0x2b,&aha1542_interrupt);
+}
+
+/* return non-zero on detection */
+int aha1542_detect(int hostnum) /* hostnum ignored for now */
+{
+ int i;
+
+ DEB(printk("aha1542_detect: \n"));
+
+ if (!(i = aha1542_test_port())) {
+ return 0;
+ }
+
+ /* Set the Bus on/off-times as not to ruin floppy performens */
+ {
+ static unchar oncmd[] = {CMD_BUSON_TIME, 5};
+ static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
+
+ aha1542_intr_reset();
+ aha1542_out(oncmd, 2);
+ WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ aha1542_intr_reset();
+ aha1542_out(offcmd, 2);
+ WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ while (0) {
+ fail:
+ printk("aha1542_detect: setting bus on/off-time failed\n");
+ }
+ aha1542_intr_reset();
+ }
+
+ aha1542_stat();
+ setup_mailboxes();
+
+ aha1542_stat();
+
+ DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
+ call_buh();
+
+ if (intr_chan >= 8)
+ outb(inb_p(0x21)&0xfb,0x21); /* open for slave ?? */
+
+ DEB(printk("aha1542_detect: enabling interrupts\n"));
+ aha1542_enable_intr();
+
+#ifdef DEBUG
+ DEB(printk(" *** READ CAPACITY ***\n"));
+
+ {
+ unchar buf[8];
+ static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ int i;
+
+ for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
+ for (i = 0; i < 2; ++i)
+ if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+ printk("aha_detect: LU %d sector_size %d device_size %d\n",
+ i, xscsi2int(buf+4), xscsi2int(buf));
+ }
+ }
+
+ DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+ for (i = 0; i < 4; ++i)
+ {
+ unsigned char cmd[10];
+ static buffer[512];
+
+ cmd[0] = READ_10;
+ cmd[1] = 0;
+ xany2scsi(cmd+2, i);
+ cmd[6] = 0;
+ cmd[7] = 0;
+ cmd[8] = 1;
+ cmd[9] = 0;
+ aha1542_command(0, cmd, buffer, 512);
+ }
+#endif
+ return 1;
+}
+
+int aha1542_abort(int i)
+{
+ DEB(printk("aha1542_abort\n"));
+ return 0;
+}
+
+int aha1542_reset(void)
+{
+ DEB(printk("aha1542_reset called\n"));
+ return 0;
+}
+
+__asm__("
+_aha1542_interrupt:
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%es
+ movl $0x17,%eax
+ mov %ax,%fs
+ movb $0x20,%al
+ outb %al,$0xA0 # EOI to interrupt controller #1
+ jmp 1f # give port chance to breathe
+1: jmp 1f
+1: outb %al,$0x20
+# Please, someone, change this to use the timer
+# andl $0xfffeffff,_timer_active
+ movl $_aha1542_intr_handle,%edx
+ call *%edx # ``interesting'' way of handling intr.
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+");
--- /dev/null
+#ifndef _AHA1542_H
+
+/* $Id: aha1542.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+ *
+ * Header file for the adaptec 1542 driver for Linux
+ *
+ * $Log: aha1542.h,v $
+ * Revision 1.1 1992/04/24 18:01:50 root
+ * Initial revision
+ *
+ * Revision 1.1 1992/04/02 03:23:13 drew
+ * Initial revision
+ *
+ * Revision 1.3 1992/01/27 14:46:29 tthorn
+ * *** empty log message ***
+ *
+ */
+
+typedef unsigned char unchar;
+
+/* I/O Port interface 4.2 */
+/* READ */
+#define STATUS base
+#define STST 0x80 /* Self Test in Progress */
+#define DIAGF 0x40 /* Internal Diagonostic Failure */
+#define INIT 0x20 /* Mailbox Initialization Required */
+#define IDLE 0x10 /* SCSI Host Adapter Idle */
+#define CDF 0x08 /* Command/Data Out Port Full */
+#define DF 0x04 /* Data In Port Full */
+#define INVDCMD 0x01 /* Invalid H A Command */
+#define STATMASK 0xfd /* 0x02 is reserved */
+
+#define INTRFLAGS STATUS+2
+#define ANYINTR 0x80 /* Any Interrupt */
+#define SCRD 0x08 /* SCSI Reset Detected */
+#define HACC 0x04 /* HA Command Complete */
+#define MBOA 0x02 /* MBO Empty */
+#define MBIF 0x01 /* MBI Full */
+#define INTRMASK 0x8f
+
+/* WRITE */
+#define CONTROL STATUS
+#define HRST 0x80 /* Hard Reset */
+#define SRST 0x40 /* Soft Reset */
+#define IRST 0x20 /* Interrupt Reset */
+#define SCRST 0x10 /* SCSI Bus Reset */
+
+/* READ/WRITE */
+#define DATA STATUS+1
+#define CMD_NOP 0x00 /* No Operation */
+#define CMD_MBINIT 0x01 /* Mailbox Initialization */
+#define CMD_START_SCSI 0x02 /* Start SCSI Command */
+#define CMD_INQUIRY 0x04 /* Adapter Inquiry */
+#define CMD_EMBOI 0x05 /* Enable MailBox Out Interrupt */
+#define CMD_BUSON_TIME 0x07 /* Set Bus-On Time */
+#define CMD_BUSOFF_TIME 0x08 /* Set Bus-Off Time */
+#define CMD_RETDEVS 0x0a /* Return Installed Devices */
+#define CMD_RETCONF 0x0b /* Return Configuration Data */
+#define CMD_RETSETUP 0x0d /* Return Setup Data */
+#define CMD_ECHO 0x1f /* ECHO Command Data */
+
+/* Mailbox Definition 5.2.1 and 5.2.2 */
+struct mailbox {
+ unchar status; /* Command/Status */
+ unchar ccbptr[3]; /* msb, .., lsb */
+};
+
+/* These belong in scsi.h also */
+#define any2scsi(up, p) \
+(up)[0] = (((long)(p)) >> 16) & 0xff; \
+(up)[1] = ((long)(p)) >> 8; \
+(up)[2] = ((long)(p));
+
+#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
+
+#define xany2scsi(up, p) \
+(up)[0] = ((long)(p)) >> 24; \
+(up)[1] = ((long)(p)) >> 16; \
+(up)[2] = ((long)(p)) >> 8; \
+(up)[3] = ((long)(p));
+
+#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+ + (((long)(up)[2]) << 8) + ((long)(up)[3]) )
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+
+struct ccb { /* Command Control Block 5.3 */
+ unchar op; /* Command Control Block Operation Code */
+ unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */
+ /* Outbound data transfer, length is checked*/
+ /* Inbound data transfer, length is checked */
+ /* Logical Unit Number */
+ unchar cdblen; /* SCSI Command Length */
+ unchar rsalen; /* Request Sense Allocation Length/Disable */
+ unchar datalen[3]; /* Data Length (msb, .., lsb) */
+ unchar dataptr[3]; /* Data Pointer */
+ unchar linkptr[3]; /* Link Pointer */
+ unchar commlinkid; /* Command Linking Identifier */
+ unchar hastat; /* Host Adapter Status (HASTAT) */
+ unchar tarstat; /* Target Device Status */
+ unchar reserved[2];
+ unchar cdb[MAX_CDB+MAX_SENSE];/* SCSI Command Descriptor Block */
+ /* REQUEST SENSE */
+};
+
+int aha1542_detect(int);
+int aha1542_command(unsigned char target, const void *cmnd, void *buff, int bufflen);
+/*int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int));*/
+int aha1542_abort(int);
+char *aha1542_info(void);
+int aha1542_reset(void);
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+#define AHA1542 {"Adaptec 1542", aha1542_detect, \
+ aha1542_info, aha1542_command, \
+ /*aha1542_queuecommand*/ NULL, \
+ aha1542_abort, \
+ aha1542_reset, \
+ 0, 7, 0}
+#endif
--- /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
+/*
+ * hosts.c Copyright (C) 1992 Drew Eckhardt
+ * mid to lowlevel SCSI driver interface by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+
+
+/*
+ This file contains the medium level SCSI
+ host interface initialization, as well as the scsi_hosts array of SCSI
+ hosts currently present in the system.
+*/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI
+#include <linux/kernel.h>
+#include "scsi.h"
+
+#ifndef NULL
+ #define NULL 0L
+#endif
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+ #define MAX_SCSI_HOSTS
+#endif
+
+#include "hosts.h"
+
+#ifdef CONFIG_SCSI_AHA1542
+#include "aha1542.h"
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include "seagate.h"
+#endif
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+#include "ultrastor.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+/*
+ The scsi host entries should be in the order you wish the
+ cards to be detected. A driver may appear more than once IFF
+ it can deal with being detected (and therefore initialized)
+ with more than one simulatenous host number, can handle being
+ rentrant, etc.
+
+ They may appear in any order, as each SCSI host is told which host number it is
+ during detection.
+*/
+
+/*
+ When figure is run, we don't want to link to any object code. Since
+ the macro for each host will contain function pointers, we cannot
+ use it and instead must use a "blank" that does no such
+ idiocy.
+*/
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+ #define BLANKIFY(what) BLANK_HOST
+#else
+ #define BLANKIFY(what) what
+#endif
+
+Scsi_Host scsi_hosts[] =
+ {
+#ifdef CONFIG_SCSI_AHA1542
+ BLANKIFY(AHA1542),
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+ BLANKIFY(SEAGATE_ST0X),
+#endif
+#ifdef CONFIG_SCSI_ULTRASTOR
+ BLANKIFY(ULTRASTOR_14F),
+#endif
+ };
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+ #undef MAX_SCSI_HOSTS
+ #define MAX_SCSI_HOSTS (sizeof(scsi_hosts) / sizeof(Scsi_Host))
+#endif
+
+#ifdef FIGURE_MAX_SCSI_HOSTS
+#include <stdio.h>
+void main (void)
+{
+ printf("%d", MAX_SCSI_HOSTS);
+}
+#else
+/*
+ Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here.
+*/
+
+volatile unsigned char host_busy[MAX_SCSI_HOSTS];
+volatile int host_timeout[MAX_SCSI_HOSTS];
+volatile Scsi_Cmnd *host_queue[MAX_SCSI_HOSTS];
+/*
+ scsi_init initializes the scsi hosts.
+*/
+
+void scsi_init(void)
+ {
+ static int called = 0;
+ int i, count;
+ if (!called)
+ {
+ called = 1;
+ for (count = i = 0; i < MAX_SCSI_HOSTS; ++i)
+ {
+ /*
+ Initialize our semaphores. -1 is interpreted to mean
+ "inactive" - where as 0 will indicate a time out condition.
+ */
+
+ host_busy[i] = 0;
+ host_timeout[i] = 0;
+ host_queue[i] = NULL;
+
+ if ((scsi_hosts[i].detect) && (scsi_hosts[i].present = scsi_hosts[i].detect(i)))
+ {
+ printk ("Host %d is detected as a(n) %s.\n\r",
+ count, scsi_hosts[i].name);
+ printk ("%s", scsi_hosts[i].info());
+ ++count;
+ }
+ }
+ printk ("%d host adapters detected. \n\r", count);
+ }
+
+ }
+
+#endif
+
+#endif
--- /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/04/24 18:01:50 root Exp root $
+*/
+
+/*
+ The Scsi_Cmnd structure is used by scsi.c internally, and for communication with
+ low level drivers that support multiple outstanding commands.
+*/
+
+typedef struct scsi_cmnd {
+ int host;
+ unsigned char target, lun;
+ unsigned char cmnd[10];
+ unsigned bufflen;
+ void *buffer;
+
+ unsigned char sense_cmnd[6];
+ unsigned char *sense_buffer;
+
+ unsigned flags;
+
+ int retries;
+ int allowed;
+ int timeout_per_command, timeout_total, timeout;
+
+ void (*done)(int,int);
+ struct scsi_cmnd *next, *prev;
+ } Scsi_Cmnd;
+
+/*
+ The Scsi_Host type has all that is needed to interface with a SCSI
+ host in a device independant matter.
+*/
+
+typedef struct
+ {
+ /*
+ The name pointer is a pointer to the name of the SCSI
+ device detected.
+ */
+
+ char *name;
+
+ /*
+ The detect function shall return non zero on detection,
+ and initialize all data necessary for this particular
+ SCSI driver. It is passed the host number, so this host
+ knows where it is in the hosts array
+ */
+
+ int (* detect)(int);
+
+ /*
+ The info function will return whatever useful
+ information the developer sees fit.
+ */
+
+ char *(* info)(void);
+
+ /*
+ The command function takes a target, a command (this is a SCSI
+ command formatted as per the SCSI spec, nothing strange), a
+ data buffer pointer, and data buffer length pointer. The return
+ is a status int, bit fielded as follows :
+ Byte What
+ 0 SCSI status code
+ 1 SCSI 1 byte message
+ 2 host error return.
+ 3 mid level error return
+ */
+
+ int (* command)(unsigned char target, const void *cmnd,
+ void *buff, int bufflen);
+
+ /*
+ The QueueCommand function works in a similar manner
+ to the command function. It takes an additional parameter,
+ void (* done)(int host, int code) which is passed the host
+ # and exit result when the command is complete.
+ Host number is the POSITION IN THE hosts array of THIS
+ host adapter.
+ */
+
+ int (* queuecommand)(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int,int));
+
+
+ /*
+ Since the mid level driver handles time outs, etc, we want to
+ be able to abort the current command. Abort returns 0 if the
+ abortion was successful. If non-zero, the code passed to it
+ will be used as the return code, otherwise
+ DID_ABORT should be returned.
+
+ Note that the scsi driver should "clean up" after itself,
+ resetting the bus, etc. if necessary.
+ */
+
+ int (* abort)(int);
+
+ /*
+ The reset function will reset the SCSI bus. Any executing
+ commands should fail with a DID_RESET in the host byte.
+ */
+
+ int (* reset)(void);
+
+ /*
+ This determines if we will use a non-interrupt driven
+ or an interrupt driven scheme, It is set to the maximum number
+ of simulataneous commands a given host adapter will accept.
+ */
+
+ int can_queue;
+
+ /*
+ In many instances, especially where disconnect / reconnect are
+ supported, our host also has an ID on the SCSI bus. If this is
+ the case, then it must be reserved. Please set this_id to -1 if your settup is in single initiator mode, and the host lacks an
+ ID.
+ */
+
+ int this_id;
+
+ /*
+ present contains a flag as to weather we are present -
+ so we don't have to call detect multiple times.
+ */
+
+ unsigned present:1;
+ } Scsi_Host;
+
+/*
+ The scsi_hosts array is the array containing the data for all
+ possible <supported> scsi hosts.
+*/
+
+extern Scsi_Host scsi_hosts[];
+
+/*
+ This is our semaphore array, used by scsi.c, sd.c, st.c.
+ Other routines SHOULD NOT mess with it. Your driver should NOT mess with it.
+ This is used to protect against contention by disk and tape drivers.
+*/
+
+extern volatile unsigned char host_busy[];
+extern volatile int host_timeout[];
+
+/*
+ This is the queue of currently pending commands for a given
+ SCSI host.
+*/
+
+extern volatile Scsi_Cmnd *host_queue[];
+
+/*
+ scsi_init initializes the scsi hosts.
+*/
+
+
+void scsi_init(void);
+
+#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#endif
--- /dev/null
+/*
+ * scsi.c Copyright (C) 1992 Drew Eckhardt
+ * generic mid-level SCSI driver by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+#ifdef CONFIG_BLK_DEV_SD
+#include "sd.h"
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+#include "st.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+#define INTERNAL_ERROR (printk ("Internal error in file %s, line %s.\n", __FILE__, __LINE__), panic(""))
+
+static void scsi_done (int host, int result);
+static void update_timeout (void);
+
+static int time_start;
+static int time_elapsed;
+
+/*
+ global variables :
+ NR_SCSI_DEVICES is the number of SCSI devices we have detected,
+ scsi_devices an array of these specifing the address for each
+ (host, id, LUN)
+*/
+
+int NR_SCSI_DEVICES=0;
+Scsi_Device scsi_devices[MAX_SCSI_DEVICE];
+
+#define SENSE_LENGTH 255
+/*
+ As the scsi do command functions are inteligent, and may need to
+ redo a command, we need to keep track of the last command
+ executed on each one.
+*/
+
+#define WAS_RESET 0x01
+#define WAS_TIMEDOUT 0x02
+#define WAS_SENSE 0x04
+#define IS_RESETTING 0x08
+
+static Scsi_Cmnd last_cmnd[MAX_SCSI_HOSTS];
+static int last_reset[MAX_SCSI_HOSTS];
+
+/*
+ This is the number of clock ticks we should wait before we time out
+ and abort the command. This is for where the scsi.c module generates
+ the command, not where it originates from a higher level, in which
+ case the timeout is specified there.
+
+
+ ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+ respectively.
+*/
+#ifdef DEBUG
+ #define SCSI_TIMEOUT 500
+#else
+ #define SCSI_TIMEOUT 100
+#endif
+#ifdef DEBUG
+ #define SENSE_TIMEOUT SCSI_TIMEOUT
+ #define ABORT_TIMEOUT SCSI_TIMEOUT
+ #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+
+ #define SENSE_TIMEOUT 50
+ #define RESET_TIMEOUT 50
+ #define ABORT_TIMEOUT 50
+ #define MIN_RESET_DELAY 25
+
+#endif
+/*
+ As the actual SCSI command runs in the background, we must set up a
+ flag that tells scan_scsis() when the result it has is valid.
+ scan_scsis can set the_result to -1, and watch for it to become the
+ actual return code for that call. the scan_scsis_done function() is
+ our user specified completion function that is passed on to the
+ scsi_do_cmd() function.
+*/
+
+static int the_result;
+static unsigned char sense_buffer[SENSE_LENGTH];
+static void scan_scsis_done (int host, int result)
+ {
+
+#ifdef DEBUG
+ printk ("scan_scsis_done(%d, %06x\n\r", host, result);
+#endif
+ the_result = result;
+ }
+/*
+ Detecting SCSI devices :
+ We scan all present host adapter's busses, from ID 0 to ID 6.
+ We use the INQUIRY command, determine device type, and pass the ID /
+ lun address of all sequential devices to the tape driver, all random
+ devices to the disk driver.
+*/
+
+static void scan_scsis (void)
+ {
+ int host_nr , dev, lun, type, maxed;
+ static unsigned char scsi_cmd [12];
+ static unsigned char scsi_result [256];
+
+ for (host_nr = 0; host_nr < MAX_SCSI_HOSTS; ++host_nr)
+ if (scsi_hosts[host_nr].present)
+ {
+ for (dev = 0; dev < 7; ++dev)
+ if (scsi_hosts[host_nr].this_id != dev)
+ #ifdef MULTI_LUN
+ for (lun = 0; lun < 8; ++lun)
+ {
+ #else
+ {
+ lun = 0;
+ #endif
+ /* Build an INQUIRY command block. */
+
+ scsi_cmd[0] = INQUIRY;
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ scsi_cmd[2] = 0;
+ scsi_cmd[3] = 0;
+ scsi_cmd[4] = 255;
+ scsi_cmd[5] = 0;
+ the_result = -1;
+#ifdef DEBUG
+ memset ((void *) scsi_result , 0, 255);
+#endif
+ scsi_do_cmd (host_nr, dev, (void *) scsi_cmd, (void *)
+ scsi_result, 256, scan_scsis_done,
+ SCSI_TIMEOUT, sense_buffer, 3);
+
+ /* Wait for valid result */
+
+ while (the_result < 0);
+
+
+ if (!the_result)
+ {
+ scsi_devices[NR_SCSI_DEVICES].
+ host_no = host_nr;
+ scsi_devices[NR_SCSI_DEVICES].
+ id = dev;
+ scsi_devices[NR_SCSI_DEVICES].
+ lun = lun;
+ scsi_devices[NR_SCSI_DEVICES].
+ removable = (0x80 &
+ scsi_result[1]) >> 7;
+
+
+
+/*
+ Currently, all sequential devices are assumed to be tapes,
+ all random devices disk, with the appropriate read only
+ flags set for ROM / WORM treated as RO.
+*/
+
+ switch (type = scsi_result[0])
+ {
+ case TYPE_TAPE:
+ case TYPE_DISK:
+ scsi_devices[NR_SCSI_DEVICES].writeable = 1;
+ break;
+ case TYPE_WORM:
+ case TYPE_ROM:
+ scsi_devices[NR_SCSI_DEVICES].writeable = 0;
+ break;
+ default:
+ type = -1;
+ }
+
+ scsi_devices[NR_SCSI_DEVICES].random = (type == TYPE_TAPE) ? 0 : 1;
+
+ maxed = 0;
+ switch (type)
+ {
+ case -1:
+ break;
+ case TYPE_TAPE:
+ printk("Detected scsi tape at host %d, ID %d, lun %d \n", host_nr, dev, lun);
+#ifdef CONFIG_BLK_DEV_ST
+ if (!(maxed = (NR_ST == MAX_ST)))
+ scsi_tapes[NR_ST].device = &scsi_devices[NR_SCSI_DEVICES];
+#endif
+ default:
+ printk("Detected scsi disk at host %d, ID %d, lun %d \n", host_nr, dev, lun);
+#ifdef CONFIG_BLK_DEV_SD
+ if (!(maxed = (NR_SD >= MAX_SD)))
+ rscsi_disks[NR_SD].device = &scsi_devices[NR_SCSI_DEVICES];
+#endif
+ }
+
+ if (maxed)
+ {
+ printk ("Already have detected maximum number of SCSI %ss Unable to \n"
+ "add drive at SCSI host %s, ID %d, LUN %d\n\r", (type == TYPE_TAPE) ?
+ "tape" : "disk", scsi_hosts[host_nr].name,
+ dev, lun);
+ type = -1;
+ break;
+ }
+
+ else if (type != -1)
+ {
+ if (type == TYPE_TAPE)
+#ifdef CONFIG_BLK_DEV_ST
+ ++NR_ST;
+#else
+;
+#endif
+
+ else
+#ifdef CONFIG_BLK_DEV_SD
+ ++NR_SD;
+#else
+;
+#endif
+ }
+ ++NR_SCSI_DEVICES;
+ } /* if result == DID_OK ends */
+ } /* for lun ends */
+ } /* if present */
+
+ printk("Detected "
+#ifdef CONFIG_BLK_DEV_SD
+"%d disk%s "
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+"%d tape%s "
+#endif
+
+"total.\n",
+
+#ifdef CONFIG_BLK_DEV_SD
+NR_SD, (NR_SD != 1) ? "s" : ""
+#ifdef CONFIG_BLK_DEV_ST
+,
+#endif
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+NR_ST, (NR_ST != 1) ? "s" : ""
+#endif
+);
+ } /* scan_scsis ends */
+
+/*
+ We handle the timeout differently if it happens when a reset,
+ abort, etc are in process.
+*/
+
+static unsigned char internal_timeout[MAX_SCSI_HOSTS];
+
+/* Flag bits for the internal_timeout array */
+
+#define NORMAL_TIMEOUT 0
+#define IN_ABORT 1
+#define IN_RESET 2
+/*
+ This is our time out function, called when the timer expires for a
+ given host adapter. It will attempt to abort the currently executing
+ command, that failing perform a kernel panic.
+*/
+
+static void scsi_times_out (int host)
+ {
+
+ switch (internal_timeout[host] & (IN_ABORT | IN_RESET))
+ {
+ case NORMAL_TIMEOUT:
+ printk("SCSI host %d timed out - aborting command \r\n",
+ host);
+
+ if (!scsi_abort (host, DID_TIME_OUT))
+ return;
+ case IN_ABORT:
+ printk("SCSI host %d abort() timed out - reseting \r\n",
+ host);
+ if (!scsi_reset (host))
+ return;
+ case IN_RESET:
+ case (IN_ABORT | IN_RESET):
+ printk("Unable to reset scsi host %d\r\n",host);
+ panic("");
+ default:
+ INTERNAL_ERROR;
+ }
+
+ }
+
+/*
+ This is inline because we have stack problemes if we recurse to deeply.
+*/
+
+static void internal_cmnd (int host, unsigned char target, const void *cmnd ,
+ void *buffer, unsigned bufflen, void (*done)(int,int))
+ {
+ int temp;
+
+#ifdef DEBUG_DELAY
+ int clock;
+#endif
+
+ if ((host < 0) || (host > MAX_SCSI_HOSTS))
+ panic ("Host number in internal_cmnd() is out of range.\n");
+
+
+/*
+ We will wait MIN_RESET_DELAY clock ticks after the last reset so
+ we can avoid the drive not being ready.
+*/
+temp = last_reset[host];
+while (jiffies < temp);
+
+host_timeout[host] = last_cmnd[host].timeout_per_command;
+update_timeout();
+
+/*
+ We will use a queued command if possible, otherwise we will emulate the
+ queing and calling of completion function ourselves.
+*/
+#ifdef DEBUG
+ printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer = %08x, \n"
+ "bufflen = %d, done = %08x)\n", host, target, cmnd, buffer, bufflen, done);
+#endif
+
+
+ if (scsi_hosts[host].can_queue)
+ {
+#ifdef DEBUG
+ printk("queuecommand : routine at %08x\n",
+ scsi_hosts[host].queuecommand);
+#endif
+ scsi_hosts[host].queuecommand (target, cmnd, buffer, bufflen,
+ done);
+ }
+ else
+ {
+
+#ifdef DEBUG
+ printk("command() : routine at %08x\n", scsi_hosts[host].command);
+#endif
+ temp=scsi_hosts[host].command (target, cmnd, buffer, bufflen);
+
+#ifdef DEBUG_DELAY
+ clock = jiffies + 400;
+ while (jiffies < clock);
+ printk("done(host = %d, result = %04x) : routine at %08x\n", host, temp, done);
+#endif
+ done(host, temp);
+ }
+#ifdef DEBUG
+ printk("leaving internal_cmnd()\n");
+#endif
+ }
+
+static void scsi_request_sense (int host, unsigned char target,
+ unsigned char lun)
+ {
+ cli();
+ host_timeout[host] = SENSE_TIMEOUT;
+ update_timeout();
+ last_cmnd[host].flags |= WAS_SENSE;
+ sti();
+
+ last_cmnd[host].sense_cmnd[1] = lun << 5;
+
+ internal_cmnd (host, target, (void *) last_cmnd[host].sense_cmnd,
+ (void *) last_cmnd[host].sense_buffer, SENSE_LENGTH,
+ scsi_done);
+ }
+
+
+
+
+
+/*
+ scsi_do_cmd sends all the commands out to the low-level driver. It
+ handles the specifics required for each low level driver - ie queued
+ or non queud. It also prevents conflicts when different high level
+ drivers go for the same host at the same time.
+*/
+
+void scsi_do_cmd (int host, unsigned char target, const void *cmnd ,
+ void *buffer, unsigned bufflen, void (*done)(int,int),
+ int timeout, unsigned char *sense_buffer, int retries
+ )
+ {
+ int ok = 0;
+
+#ifdef DEBUG
+ int i;
+ printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, "
+ "bufflen = %d, done = %08x, timeout = %d, retries = %d)\n"
+ "command : " , host, target, buffer, bufflen, done, timeout, retries);
+ for (i = 0; i < 10; ++i)
+ printk ("%02x ", ((unsigned char *) cmnd)[i]);
+ printk("\n");
+#endif
+
+ if ((host >= MAX_SCSI_HOSTS) || !scsi_hosts[host].present)
+ {
+ printk ("Invalid or not present host number. %d\n", host);
+ panic("");
+ }
+
+
+/*
+ We must prevent reentrancy to the lowlevel host driver. This prevents
+ it - we enter a loop until the host we want to talk to is not busy.
+ Race conditions are prevented, as interrupts are disabled inbetween the
+ time we check for the host being not busy, and the time we mark it busy
+ ourselves.
+*/
+
+ do {
+ cli();
+ if (host_busy[host])
+ {
+ sti();
+#ifdef DEBUG
+ printk("Host %d is busy.\n" );
+#endif
+ while (host_busy[host]);
+#ifdef DEBUG
+ printk("Host %d is no longer busy.");
+#endif
+ }
+ else
+ {
+ host_busy[host] = 1;
+ ok = 1;
+ sti();
+ }
+ } while (!ok);
+
+
+/*
+ Our own function scsi_done (which marks the host as not busy, disables
+ the timeout counter, etc) will be called by us or by the
+ scsi_hosts[host].queuecommand() function needs to also call
+ the completion function for the high level driver.
+
+*/
+
+ memcpy ((void *) last_cmnd[host].cmnd , (void *) cmnd, 10);
+ last_cmnd[host].host = host;
+ last_cmnd[host].target = target;
+ last_cmnd[host].lun = (last_cmnd[host].cmnd[1] >> 5);
+ last_cmnd[host].bufflen = bufflen;
+ last_cmnd[host].buffer = buffer;
+ last_cmnd[host].sense_buffer = sense_buffer;
+ last_cmnd[host].flags=0;
+ last_cmnd[host].retries=0;
+ last_cmnd[host].allowed=retries;
+ last_cmnd[host].done = done;
+ last_cmnd[host].timeout_per_command = timeout;
+
+ /* Start the timer ticking. */
+
+ internal_timeout[host] = 0;
+ internal_cmnd (host, target, cmnd , buffer, bufflen, scsi_done);
+
+#ifdef DEBUG
+ printk ("Leaving scsi_do_cmd()\n");
+#endif
+ }
+
+
+/*
+ The scsi_done() function disables the timeout timer for the scsi host,
+ marks the host as not busy, and calls the user specified completion
+ function for that host's current command.
+*/
+
+static void reset (int host)
+ {
+ #ifdef DEBUG
+ printk("reset(%d)\n", host);
+ #endif
+
+ last_cmnd[host].flags |= (WAS_RESET | IS_RESETTING);
+ scsi_reset(host);
+
+ #ifdef DEBUG
+ printk("performing request sense\n");
+ #endif
+
+ scsi_request_sense (host, last_cmnd[host].target, last_cmnd[host].lun);
+ }
+
+
+
+static int check_sense (int host)
+ {
+ if (((sense_buffer[0] & 0x70) >> 4) == 7)
+ switch (sense_buffer[2] & 0xf)
+ {
+ case NO_SENSE:
+ case RECOVERED_ERROR:
+ return 0;
+
+ case ABORTED_COMMAND:
+ case NOT_READY:
+ case UNIT_ATTENTION:
+ return SUGGEST_RETRY;
+
+ /* these three are not supported */
+ case COPY_ABORTED:
+ case VOLUME_OVERFLOW:
+ case MISCOMPARE:
+
+ case MEDIUM_ERROR:
+ return SUGGEST_REMAP;
+ case BLANK_CHECK:
+ case DATA_PROTECT:
+ case HARDWARE_ERROR:
+ case ILLEGAL_REQUEST:
+ default:
+ return SUGGEST_ABORT;
+ }
+ else
+ return SUGGEST_RETRY;
+ }
+
+static void scsi_done (int host, int result)
+ {
+ int status=0;
+ int exit=0;
+ int checked;
+ int oldto;
+ oldto = host_timeout[host];
+ host_timeout[host] = 0;
+ update_timeout();
+
+#define FINISHED 0
+#define MAYREDO 1
+#define REDO 3
+
+#ifdef DEBUG
+ printk("In scsi_done(host = %d, result = %06x)\n", host, result);
+#endif
+ if (host > MAX_SCSI_HOSTS || host < 0)
+ {
+ host_timeout[host] = 0;
+ update_timeout();
+ panic("scsi_done() called with invalid host number.\n");
+ }
+
+ switch (host_byte(result))
+ {
+ case DID_OK:
+ if (last_cmnd[host].flags & IS_RESETTING)
+ {
+ last_cmnd[host].flags &= ~IS_RESETTING;
+ status = REDO;
+ break;
+ }
+
+ if (status_byte(result) && (last_cmnd[host].flags &
+ WAS_SENSE))
+ {
+ last_cmnd[host].flags &= ~WAS_SENSE;
+ cli();
+ internal_timeout[host] &= ~SENSE_TIMEOUT;
+ sti();
+
+ if (!(last_cmnd[host].flags & WAS_RESET))
+ reset(host);
+ else
+ {
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ status = FINISHED;
+ }
+ }
+ else switch(msg_byte(result))
+ {
+ case COMMAND_COMPLETE:
+ switch (status_byte(result))
+ {
+ case GOOD:
+ if (last_cmnd[host].flags & WAS_SENSE)
+ {
+#ifdef DEBUG
+ printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
+#endif
+
+ last_cmnd[host].flags &= ~WAS_SENSE;
+ cli();
+ internal_timeout[host] &= ~SENSE_TIMEOUT;
+ sti();
+
+ switch (checked = check_sense(host))
+ {
+ case 0:
+#ifdef DEBUG
+ printk("NO SENSE. status = REDO\n");
+#endif
+
+ host_timeout[host] = oldto;
+ update_timeout();
+ status = REDO;
+ break;
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
+#ifdef DEBUG
+ printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
+#endif
+
+ status = MAYREDO;
+ exit = SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
+#ifdef DEBUG
+ printk("SENSE SUGGEST ABORT - status = FINISHED");
+#endif
+
+ status = FINISHED;
+ exit = DRIVER_SENSE;
+ break;
+ default:
+ printk ("Internal error %s %s \n", __FILE__,
+ __LINE__);
+ }
+ }
+ else
+ {
+#ifdef DEBUG
+ printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
+#endif
+
+ exit = DRIVER_OK;
+ status = FINISHED;
+ }
+ break;
+
+ case CHECK_CONDITION:
+
+#ifdef DEBUG
+ printk("CHECK CONDITION message returned, performing request sense.\n");
+#endif
+
+ scsi_request_sense (host, last_cmnd[host].target, last_cmnd[host].lun);
+ break;
+
+ case CONDITION_GOOD:
+ case INTERMEDIATE_GOOD:
+ case INTERMEDIATE_C_GOOD:
+#ifdef DEBUG
+ printk("CONDITION GOOD, INTERMEDIATE GOOD, or INTERMEDIATE CONDITION GOOD recieved and ignored. \n");
+#endif
+ break;
+
+ case BUSY:
+#ifdef DEBUG
+ printk("BUSY message returned, performing REDO");
+#endif
+ host_timeout[host] = oldto;
+ update_timeout();
+ status = REDO;
+ break;
+
+ case RESERVATION_CONFLICT:
+ reset(host);
+ exit = DRIVER_SOFT | SUGGEST_ABORT;
+ status = MAYREDO;
+ break;
+ default:
+ printk ("Internal error %s %s \n"
+ "status byte = %d \n", __FILE__,
+ __LINE__, status_byte(result));
+
+ }
+ break;
+ default:
+ panic ("unsupported message byte recieved.");
+ }
+ break;
+ case DID_TIME_OUT:
+#ifdef DEBUG
+ printk("Host returned DID_TIME_OUT - ");
+#endif
+
+ if (last_cmnd[host].flags & WAS_TIMEDOUT)
+ {
+#ifdef DEBUG
+ printk("Aborting\n");
+#endif
+ exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+ }
+ else
+ {
+#ifdef DEBUG
+ printk ("Retrying.\n");
+#endif
+ last_cmnd[host].flags |= WAS_TIMEDOUT;
+ status = REDO;
+ }
+ break;
+ case DID_BUS_BUSY:
+ case DID_PARITY:
+ status = REDO;
+ break;
+ case DID_NO_CONNECT:
+#ifdef DEBUG
+ printk("Couldn't connect.\n");
+#endif
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_ERROR:
+ status = MAYREDO;
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_BAD_TARGET:
+ case DID_ABORT:
+ exit = (DRIVER_INVALID | SUGGEST_ABORT);
+ break;
+ default :
+ exit = (DRIVER_ERROR | SUGGEST_DIE);
+ }
+
+ switch (status)
+ {
+ case FINISHED:
+ break;
+ case MAYREDO:
+
+#ifdef DEBUG
+ printk("In MAYREDO, allowing %d retries, have %d\n\r",
+ last_cmnd[host].allowed, last_cmnd[host].retries);
+#endif
+
+ if ((++last_cmnd[host].retries) < last_cmnd[host].allowed)
+ {
+ if ((last_cmnd[host].retries >= (last_cmnd[host].allowed >> 1))
+ && !(last_cmnd[host].flags & WAS_RESET))
+ reset(host);
+ break;
+
+ }
+ else
+ {
+ status = FINISHED;
+ break;
+ }
+ /* fall through to REDO */
+
+ case REDO:
+ if (last_cmnd[host].flags & WAS_SENSE)
+ scsi_request_sense (host, last_cmnd[host].target,
+ last_cmnd[host].lun);
+ else
+ internal_cmnd (host, last_cmnd[host].target,
+ last_cmnd[host].cmnd,
+ last_cmnd[host].buffer,
+ last_cmnd[host].bufflen, scsi_done);
+ break;
+ default:
+ INTERNAL_ERROR;
+ }
+
+ if (status == FINISHED)
+ {
+ #ifdef DEBUG
+ printk("Calling done function - at address %08x\n", last_cmnd[host].done);
+ #endif
+ last_cmnd[host].done (host, (result | ((exit & 0xff) << 24)));
+ host_busy[host] = 0;
+ }
+
+
+#undef FINISHED
+#undef REDO
+#undef MAYREDO
+
+ }
+
+/*
+ The scsi_abort function interfaces with the abort() function of the host
+ we are aborting, and causes the current command to not complete. The
+ caller should deal with any error messages or status returned on the
+ next call.
+
+ This will not be called rentrantly for a given host.
+*/
+
+/*
+ Since we're nice guys and specified that abort() and reset()
+ can be non-reentrant. The internal_timeout flags are used for
+ this.
+*/
+
+
+int scsi_abort (int host, int why)
+ {
+ int temp, oldto;
+
+ while(1)
+ {
+ cli();
+ if (internal_timeout[host] & IN_ABORT)
+ {
+ sti();
+ while (internal_timeout[host] & IN_ABORT);
+ }
+ else
+ {
+ internal_timeout[host] |= IN_ABORT;
+ host_timeout[host] = ABORT_TIMEOUT;
+ update_timeout();
+
+ oldto = host_timeout[host];
+
+ sti();
+ if (!host_busy[host] || !scsi_hosts[host].abort(why))
+ temp = 0;
+ else
+ temp = 1;
+
+ cli();
+ internal_timeout[host] &= ~IN_ABORT;
+ host_timeout[host]=oldto;
+ update_timeout();
+ sti();
+ return temp;
+ }
+ }
+ }
+
+int scsi_reset (int host)
+ {
+ int temp, oldto;
+
+ while (1) {
+ cli();
+ if (internal_timeout[host] & IN_RESET)
+ {
+ sti();
+ while (internal_timeout[host] & IN_RESET);
+ }
+ else
+ {
+ oldto = host_timeout[host];
+ host_timeout[host] = RESET_TIMEOUT;
+ update_timeout();
+ internal_timeout[host] |= IN_RESET;
+
+ if (host_busy[host])
+ {
+ sti();
+ if (!(last_cmnd[host].flags & IS_RESETTING) && !(internal_timeout[host] & IN_ABORT))
+ scsi_abort(host, DID_RESET);
+
+ temp = scsi_hosts[host].reset();
+ }
+ else
+ {
+ host_busy[host]=1;
+
+ sti();
+ temp = scsi_hosts[host].reset();
+ last_reset[host] = jiffies;
+ host_busy[host]=0;
+ }
+
+ cli();
+ host_timeout[host] = oldto;
+ update_timeout();
+ internal_timeout[host] &= ~IN_RESET;
+ sti();
+ return temp;
+ }
+ }
+ }
+
+
+static void scsi_main_timeout(void)
+ {
+ /*
+ We must not enter update_timeout with a timeout condition still pending.
+ */
+
+ int i, timed_out;
+
+ do {
+ cli();
+
+ /*
+ Find all timers such that they have 0 or negative (shouldn't happen)
+ time remaining on them.
+ */
+
+ for (i = timed_out = 0; i < MAX_SCSI_HOSTS; ++i)
+ if (host_timeout[i] != 0 && host_timeout[i] <= time_elapsed)
+ {
+ sti();
+ host_timeout[i] = 0;
+ scsi_times_out(i);
+ ++timed_out;
+ }
+
+ update_timeout();
+ } while (timed_out);
+ sti();
+ }
+
+/*
+ These are used to keep track of things.
+*/
+
+static int time_start, time_elapsed;
+
+/*
+ The strategy is to cause the timer code to call scsi_times_out()
+ when the soonest timeout is pending.
+*/
+
+static void update_timeout(void)
+ {
+ int i, least, used;
+
+ cli();
+
+/*
+ Figure out how much time has passed since the last time the timeouts
+ were updated
+*/
+ used = (time_start) ? (jiffies - time_start) : 0;
+
+/*
+ Find out what is due to timeout soonest, and adjust all timeouts for
+ the amount of time that has passed since the last time we called
+ update_timeout.
+*/
+
+ for (i = 0, least = 0xffffffff; i < MAX_SCSI_HOSTS; ++i)
+ if (host_timeout[i] > 0 && (host_timeout[i] -= used) < least)
+ least = host_timeout[i];
+
+/*
+ If something is due to timeout again, then we will set the next timeout
+ interrupt to occur. Otherwise, timeouts are disabled.
+*/
+
+ if (least != 0xffffffff)
+ {
+ time_start = jiffies;
+ timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
+ timer_active |= 1 << SCSI_TIMER;
+ }
+ else
+ {
+ timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
+ timer_active &= ~(1 << SCSI_TIMER);
+ }
+ sti();
+ }
+/*
+ scsi_dev_init() is our initialization routine, which inturn calls host
+ initialization, bus scanning, and sd/st initialization routines. It
+ should be called from main().
+*/
+
+static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+void scsi_dev_init (void)
+ {
+ int i;
+#ifdef FOO_ON_YOU
+ return;
+#endif
+ timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+ timer_table[SCSI_TIMER].expires = 0;
+
+ scsi_init(); /* initialize all hosts */
+ /*
+ Set up sense command in each host structure.
+ */
+
+ for (i = 0; i < MAX_SCSI_HOSTS; ++i)
+ {
+ memcpy ((void *) last_cmnd[i].sense_cmnd, (void *) generic_sense,
+ 6);
+ last_reset[i] = 0;
+ }
+
+ scan_scsis(); /* scan for scsi devices */
+
+#ifdef CONFIG_BLK_DEV_SD
+ sd_init(); /* init scsi disks */
+#endif
+
+#ifdef CONFIG_BLK_DEV_ST
+ st_init(); /* init scsi tapes */
+#endif
+ }
+#endif
--- /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/04/24 18:01:50 root Exp root $
+
+ For documentation on the OPCODES, MESSAGES, and SENSE values,
+ please consult the SCSI standard.
+
+*/
+
+/*
+ SCSI opcodes
+*/
+
+#define TEST_UNIT_READY 0x00
+#define REZERO_UNIT 0x01
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define REASSIGN_BLOCKS 0x07
+#define READ_6 0x08
+#define WRITE_6 0x0a
+#define SEEK_6 0x0b
+#define INQUIRY 0x12
+#define MODE_SELECT 0x15
+#define RESERVE 0x16
+#define RELEASE 0x17
+#define COPY 0x18
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define RECIEVE_DAIGNOSTIC 0x1c
+#define SEND_DIAGNOSTIC 0x1d
+#define ALLOW_MEDIUM_REMOVAL 0x1e
+
+#define READ_CAPACITY 0x25
+#define READ_10 0x28
+#define WRITE_10 0x2a
+#define SEEK_10 0x2b
+#define WRITE_VERIFY 0x2e
+#define VERIFY 0x2f
+#define SEARCH_HIGH 0x30
+#define SEARCH_EQUAL 0x31
+#define SEARCH_LOW 0x32
+#define SET_LIMITS 0x33
+#define COMPARE 0x39
+#define COPY_VERIFY 0x3a
+
+#define COMMAND_SIZE(opcode) ((opcode) ? ((opcode) > 0x20 ? 10 : 6) : 0)
+
+/*
+ MESSAGE CODES
+*/
+
+#define COMMAND_COMPLETE 0x00
+#define EXTENDED_MESSAGE 0x01
+#define SAVE_POINTERS 0x02
+#define RESTORE_POINTERS 0x03
+#define DISCONNECT 0x04
+#define INITIATOR_ERROR 0x05
+#define ABORT 0x06
+#define MESSAGE_REJECT 0x07
+#define NOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET 0x0c
+#define IDENTIFY 0x80
+/*
+ Status codes
+*/
+
+#define GOOD 0x00
+#define CHECK_CONDITION 0x01
+#define CONDITION_GOOD 0x02
+#define BUSY 0x04
+#define INTERMEDIATE_GOOD 0x08
+#define INTERMEDIATE_C_GOOD 0x0a
+#define RESERVATION_CONFLICT 0x0c
+
+#define STATUS_MASK 0x1e
+
+/*
+ the return of the status word will be in the following format :
+ The low byte is the status returned by the SCSI command,
+ with vendor specific bits masked.
+
+ The next byte is the message which followed the SCSI status.
+ This allows a stos to be used, since the Intel is a little
+ endian machine.
+
+ The final byte is a host return code, which is one of the following.
+
+ IE
+ lsb msb
+ status msg host code
+
+ Our errors returned by OUR driver, NOT SCSI message. Orr'd with
+ SCSI message passed back to driver <IF any>.
+*/
+
+/* NO error */
+#define DID_OK 0x00
+/* Couldn't connect before timeout period */
+#define DID_NO_CONNECT 0x01
+/* BUS stayed busy through time out period */
+#define DID_BUS_BUSY 0x02
+/* TIMED OUT for other reason */
+#define DID_TIME_OUT 0x03
+/* BAD target. */
+#define DID_BAD_TARGET 0x04
+/* Told to abort for some other reason */
+#define DID_ABORT 0x05
+/*
+ Parity error
+*/
+#define DID_PARITY 0x06
+/*
+ Internal error
+*/
+#define DID_ERROR 0x07
+/*
+ Reset by somebody.
+*/
+#define DID_RESET 0x08
+
+/*
+ Driver status
+*/
+#define DRIVER_OK 0x00
+
+/*
+ These indicate the error that occured, and what is available.
+*/
+
+#define DRIVER_BUSY 0x01
+#define DRIVER_SOFT 0x02
+#define DRIVER_MEDIA 0x03
+#define DRIVER_ERROR 0x04
+
+#define DRIVER_INVALID 0x05
+#define DRIVER_TIMEOUT 0x06
+#define DRIVER_HARD 0x07
+
+#define SUGGEST_RETRY 0x08
+#define SUGGEST_ABORT 0x09
+#define SUGGEST_REMAP 0x0a
+#define SUGGEST_DIE 0x0b
+
+#define DRIVER_SENSE 0x10
+
+#define DRIVER_MASK 0x0f
+#define SUGGEST_MASK 0xf0
+
+/*
+
+ SENSE KEYS
+*/
+
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define COPY_ABORTED 0x0a
+#define ABORTED_COMMAND 0x0b
+#define VOLUME_OVERFLOW 0x0d
+#define MISCOMPARE 0x0e
+
+
+/*
+ DEVICE TYPES
+
+*/
+
+#define TYPE_DISK 0x00
+#define TYPE_TAPE 0x01
+#define TYPE_WORM 0x04 /* Treated as ROM by our system */
+#define TYPE_ROM 0x05
+#define TYPE_NO_LUN 0x7f
+/*
+ Every SCSI command starts with a one byte OP-code.
+ The next byte's high three bits are the LUN of the
+ device. Any multi-byte quantities are stored high byte
+ first, and may have a 5 bit MSB in the same byte
+ as the LUN.
+*/
+
+
+/*
+ The scsi_device struct contains what we know about each given scsi
+ device.
+*/
+
+typedef struct scsi_device {
+ unsigned char host_no, id, lun;
+ unsigned writeable:1;
+ unsigned removable:1;
+ unsigned random:1;
+ } Scsi_Device;
+/*
+ Use these to separate status msg and our bytes
+*/
+
+#define status_byte(result) (((result) >> 1) & 0xf)
+#define msg_byte(result) (((result) >> 8) & 0xff)
+#define host_byte(result) (((result) >> 16) & 0xff)
+#define driver_byte(result) (((result) >> 24) & 0xff)
+#define sugestion(result) (driver_byte(result) & SUGGEST_MASK)
+
+#define sense_class(sense) (((sense) >> 4) & 0x7)
+#define sense_error(sense) ((sense) & 0xf)
+#define sense_valid(sense) ((sense) & 0x80);
+
+/*
+ These are the SCSI devices available on the system.
+*/
+
+#define MAX_SCSI_DEVICE 2
+extern int NR_SCSI_DEVICES;
+extern Scsi_Device scsi_devices[MAX_SCSI_DEVICE];
+/*
+ scsi_abort aborts the current command that is executing on host host.
+ The error code, if non zero is returned in the host byte, otherwise
+ DID_ABORT is returned in the hostbyte.
+*/
+
+extern int scsi_abort (int host, int code);
+
+/*
+ Initializes all SCSI devices. This scans all scsi busses.
+*/
+
+extern void scsi_dev_init (void);
+
+/*
+ You guesed it. This sends a command to the selected SCSI host
+*/
+
+
+
+extern void scsi_do_cmd (int host, unsigned char target, const void *cmnd ,
+ void *buffer, unsigned bufflen, void (*done)(int,int),
+ int timeout, unsigned char *sense_buffer, int retries);
+
+int scsi_reset (int host);
+#endif
--- /dev/null
+#include <linux/config.h>
+#ifdef CONFIG_SCSI
+
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "scsi_ioctl.h"
+
+#define MAX_RETRIES 5
+#define MAX_TIMEOUT 200
+#define MAX_BUF 1024
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+/*
+ * If we are told to probe a host, we will return 0 if the host is not
+ * present, 1 if the host is present, and will return an identifying
+ * string at *arg, if arg is non null, filling to the length stored at
+ * (int *) arg
+ */
+
+static int ioctl_probe(int dev, void *buffer)
+{
+ int temp;
+ int len;
+
+ if ((temp = scsi_hosts[dev].present) && buffer) {
+ len = get_fs_long ((int *) buffer);
+ memcpy_tofs (buffer, scsi_hosts[dev].info(), len);
+ }
+ return temp;
+}
+
+/*
+ *
+ * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
+ * The MAX_TIMEOUT and MAX_RETRIES variables are used.
+ *
+ * dev is the SCSI device number, *(int *) arg the length of the input
+ * data, *((int *)arg + 1) the output buffer.
+ *
+ * *(char *) ((int *) arg)[1] the actual command.
+ *
+ * Note that no more than MAX_BUF bytes will be transfered. Since
+ * SCSI block device size is 512 bytes, I figured 1K was good.
+ *
+ * This size * does * include the initial lengths that were passed.
+ *
+ * The SCSI command is read from the memory location immediately after the
+ * length words, and the out data after the command. The SCSI routines know the
+ * command size based on the length byte.
+ *
+ * The area is then filled in from the byte at offset 0.
+ */
+
+static int the_result[MAX_SCSI_HOSTS];
+
+static void scsi_ioctl_done (int host, int result)
+{
+ the_result[host] = result;
+}
+
+static int ioctl_command(Scsi_Device *dev, void *buffer)
+{
+ char buf[MAX_BUF];
+ char cmd[10];
+ char * cmd_in;
+ unsigned char opcode;
+ int inlen, outlen, cmdlen, temp, host;
+
+ if (!buffer)
+ return -EINVAL;
+
+ inlen = get_fs_long((int *) buffer);
+ outlen = get_fs_long(((int *) buffer) + 1);
+
+ cmd_in = (char *) ( ((int *)buffer) + 2);
+ opcode = get_fs_byte(cmd_in);
+
+ memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
+ memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen);
+ host = dev->host_no;
+
+#ifndef DEBUG_NO_CMD
+ do {
+ cli();
+ if (the_result[host]) {
+ sti();
+ while(the_result[host])
+ /* nothing */;
+ } else {
+ the_result[host]=-1;
+ sti();
+ break;
+ }
+ } while (1);
+
+ scsi_do_cmd(host, dev->id, cmd, buf, ((outlen > MAX_BUF) ?
+ MAX_BUF : outlen), scsi_ioctl_done, MAX_TIMEOUT,
+ buf, MAX_RETRIES);
+
+ while (the_result[host] == -1)
+ /* nothing */;
+ temp = the_result[host];
+ the_result[host]=0;
+ memcpy_tofs (buffer, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
+ return temp;
+#else
+ {
+ int i;
+ printk("scsi_ioctl : device %d. command = ", dev);
+ for (i = 0; i < 10; ++i)
+ printk("%02x ", cmd[i]);
+ printk("\r\nbuffer =");
+ for (i = 0; i < 20; ++i)
+ printk("%02x ", buf[i]);
+ printk("\r\n");
+ }
+ return 0;
+#endif
+}
+
+
+/*
+ the scsi_ioctl() function differs from most ioctls in that it does
+ not take a major/minor number as the dev filed. Rather, it takes
+ an index in scsi_devices[]
+*/
+int scsi_ioctl (int dev, int cmd, void *arg)
+{
+ if ((cmd != 0 && dev > NR_SCSI_DEVICES) || dev < 0)
+ return -ENODEV;
+ if ((cmd == 0 && dev > MAX_SCSI_HOSTS))
+ return -ENODEV;
+
+ switch (cmd) {
+ case SCSI_IOCTL_PROBE_HOST:
+ return ioctl_probe(dev, arg);
+ case SCSI_IOCTL_SEND_COMMAND:
+ return ioctl_command((Scsi_Device *) dev, arg);
+ default :
+ return -EINVAL;
+ }
+}
+#endif
--- /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/string.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include "sd.h"
+
+#define MAJOR_NR 8
+
+#include "../blk.h"
+
+/*
+static const char RCSid[] = "$Header:";
+*/
+
+#define MAX_RETRIES 5
+
+/*
+ * Time out in seconds
+ */
+
+#define SD_TIMEOUT 100
+
+Partition scsi_disks[MAX_SD << 4];
+int NR_SD=0;
+Scsi_Disk rscsi_disks[MAX_SD];
+static int sd_sizes[MAX_SD << 4];
+static int this_count;
+static int the_result;
+
+extern int sd_ioctl(struct inode *, struct file *, unsigned long, unsigned long);
+
+static void sd_release(struct inode * inode, struct file * file)
+{
+ sync_dev(inode->i_rdev);
+}
+
+static struct file_operations sd_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ sd_ioctl, /* ioctl */
+ NULL, /* no special open code */
+ sd_release /* release */
+};
+
+/*
+ The sense_buffer is where we put data for all mode sense commands
+ performed.
+*/
+
+static unsigned char sense_buffer[255];
+
+/*
+ rw_intr is the interrupt routine for the device driver. It will
+ be notified on the end of a SCSI read / write, and
+ will take on of several actions based on success or failure.
+*/
+
+static void rw_intr (int host, int result)
+{
+ if (HOST != host)
+ panic ("sd.o : rw_intr() recieving interrupt for different host.");
+
+/*
+ First case : we assume that the command succeeded. One of two things will
+ happen here. Either we will be finished, or there will be more
+ sectors that we were unable to read last time.
+*/
+
+ if (!result)
+ if (!(CURRENT->nr_sectors -= this_count)) {
+ end_request(1);
+ do_sd_request();
+ } else {
+ CURRENT->nr_sectors -= this_count;
+/*
+ The CURRENT->nr_sectors field is always done in 512 byte sectors,
+ even if this really isn't the case.
+*/
+
+ (char *) CURRENT->buffer += this_count << 9;
+ CURRENT->sector += this_count;
+ CURRENT->errors = 0;
+ do_sd_request();
+ }
+
+/*
+ Now, if we were good little boys and girls, Santa left us a request
+ sense buffer. We can extract information from this, so we
+ can choose a block to remap, etc.
+*/
+
+ else if (driver_byte(result) & DRIVER_SENSE) {
+ if (sugestion(result) == SUGGEST_REMAP) {
+#ifdef REMAP
+/*
+ Not yet implemented. A read will fail after being remapped,
+ a write will call the strategy routine again.
+*/
+
+ if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
+ {
+ result = 0;
+ }
+ else
+
+#endif
+ }
+/*
+ If we had an ILLEGAL REQUEST returned, then we may have performed
+ an unsupported command. The only thing this should be would be a ten
+ byte read where only a six byte read was supportted. Also, on a
+ system where READ CAPACITY failed, we mave have read past the end of the
+ disk.
+*/
+
+ else if (sense_buffer[7] == ILLEGAL_REQUEST) {
+ if (rscsi_disks[DEVICE_NR(CURRENT->dev)].ten) {
+ rscsi_disks[DEVICE_NR(CURRENT->dev)].ten = 0;
+ do_sd_request();
+ result = 0;
+ } else {
+ }
+ }
+ }
+ if (result) {
+ printk("SCSI disk error : host %d id %d lun %d return code = %03x\n",
+ rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no,
+ rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id,
+ rscsi_disks[DEVICE_NR(CURRENT->dev)].device->lun);
+
+ if (driver_byte(result) & DRIVER_SENSE)
+ printk("\tSense class %x, sense error %x, extended sense %x\n",
+ sense_class(sense_buffer[0]),
+ sense_error(sense_buffer[0]),
+ sense_buffer[2] & 0xf);
+
+ end_request(0);
+ }
+}
+
+/*
+ do_sd_request() is the request handler function for the sd driver.
+ Its function in life is to take block device requests, and translate
+ them to SCSI commands.
+*/
+
+void do_sd_request (void)
+{
+ int dev, block;
+ unsigned char cmd[10];
+
+ INIT_REQUEST;
+ dev = MINOR(CURRENT->dev);
+ block = CURRENT->sector;
+
+#ifdef DEBUG
+ printk("Doing sd request, dev = %d, block = %d\n", dev, block);
+#endif
+
+ if (dev >= (NR_SD << 4) || block + 2 > scsi_disks[dev].nr_sects ||
+ (dev % 16) > 5)
+ {
+ end_request(0);
+ goto repeat;
+ }
+
+ block += scsi_disks[dev].start_sect;
+ dev = DEVICE_NR(dev);
+
+#ifdef DEBUG
+ printk("Real dev = %d, block = %d\n", dev, block);
+#endif
+
+ if (!rscsi_disks[dev].use)
+ {
+ end_request(0);
+ goto repeat;
+ }
+
+ this_count = CURRENT->nr_sectors;
+ switch (CURRENT->cmd)
+ {
+ case WRITE :
+ if (!rscsi_disks[dev].device->writeable)
+ {
+ end_request(0);
+ goto repeat;
+ }
+ cmd[0] = WRITE_6;
+ break;
+ case READ :
+ cmd[0] = READ_6;
+ break;
+ default :
+ printk ("Unknown sd command %d\r\n", CURRENT->cmd);
+ panic("");
+ }
+
+ cmd[1] = (LUN << 5) & 0xe0;
+
+ if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
+ {
+ if (this_count > 0xffff)
+ this_count = 0xffff;
+
+ cmd[0] += READ_10 - READ_6 ;
+ cmd[2] = (unsigned char) (block >> 24) & 0xff;
+ cmd[3] = (unsigned char) (block >> 16) & 0xff;
+ cmd[4] = (unsigned char) (block >> 8) & 0xff;
+ cmd[5] = (unsigned char) block & 0xff;
+ cmd[6] = cmd[9] = 0;
+ cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
+ cmd[8] = (unsigned char) this_count & 0xff;
+ }
+ else
+ {
+ if (this_count > 0xff)
+ this_count = 0xff;
+
+ cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+ cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+ cmd[3] = (unsigned char) block & 0xff;
+ cmd[4] = (unsigned char) this_count;
+ cmd[5] = 0;
+ }
+
+ scsi_do_cmd (HOST, ID, (void *) cmd, CURRENT->buffer, this_count << 9,
+ rw_intr, SD_TIMEOUT, sense_buffer, MAX_RETRIES);
+}
+
+static void sd_init_done (int host, int result)
+{
+ the_result = result;
+}
+
+/*
+ The sd_init() function looks at all SCSI drives present, determines
+ their size, and reads partition table entries for them.
+*/
+
+void sd_init(void)
+{
+ int i,j,k;
+ unsigned char cmd[10];
+ unsigned char buffer[513];
+
+ Partition *p;
+
+
+ for (i = 0; i < NR_SD; ++i)
+ {
+ cmd[0] = READ_CAPACITY;
+ rscsi_disks[i].use = 1;
+ cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ memset ((void *) &cmd[2], 0, 8);
+ the_result = -1;
+#ifdef DEBUG
+ printk("Read capacity, disk %d at host = %d, id = %d\n", i,
+ rscsi_disks[i].device->host_no, rscsi_disks[i].device->id);
+#endif
+ scsi_do_cmd (rscsi_disks[i].device->host_no ,
+ rscsi_disks[i].device->id,
+ (void *) cmd, (void *) buffer,
+ 512, sd_init_done, SD_TIMEOUT, sense_buffer,
+ MAX_RETRIES);
+
+ while(the_result < 0);
+/*
+ The SCSI standard says "READ CAPACITY is necessary for self confuring software"
+ While not mandatory, support of READ CAPACITY is strongly encouraged.
+
+ We used to die if we couldn't successfully do a READ CAPACITY.
+ But, now we go on about our way. The side effects of this are
+
+ 1. We can't know block size with certainty. I have said "512 bytes is it"
+ as this is most common.
+
+ 2. Recovery from when some one attempts to read past the end of the raw device will
+ be slower.
+*/
+
+ if (the_result)
+ {
+ printk ("Warning : SCSI device at host %d, id %d, lun %d failed READ CAPACITY.\n"
+ "status = %x, message = %02x, host = %02x, driver = %02x \n",
+ rscsi_disks[i].device->host_no, rscsi_disks[i].device->id,
+ rscsi_disks[i].device->lun,
+ status_byte(the_result),
+ msg_byte(the_result),
+ host_byte(the_result),
+ driver_byte(the_result)
+ );
+ if (driver_byte(the_result) & DRIVER_SENSE)
+ printk("Extended sense code = %1x \n", sense_buffer[2] & 0xf);
+ else
+ printk("Sense not available. \n");
+
+ printk("Block size assumed to be 512 bytes, disk size 1GB. \n");
+ rscsi_disks[i].capacity = 0x1fffff;
+ rscsi_disks[i].sector_size = 512;
+ }
+ else
+ {
+ rscsi_disks[i].capacity = (buffer[0] << 24) |
+ (buffer[1] << 16) |
+ (buffer[2] << 8) |
+ buffer[3];
+
+ if ((rscsi_disks[i].sector_size = (buffer[4] << 24) |
+ (buffer[5] << 16) |
+ (buffer[6] << 8) |
+ buffer[7]) != 512)
+ {
+ printk ("Unsupported sector size %d for sd %d",
+ rscsi_disks[i].sector_size, i);
+ rscsi_disks[i].use = 0;
+ }
+ }
+
+ if (rscsi_disks[i].use)
+ {
+ scsi_disks[j = (i << 4)].start_sect = 0;
+
+ sd_sizes[j]=(scsi_disks[j].nr_sects = rscsi_disks[i].capacity)>>1;
+#ifdef DEBUG
+ printk("/dev/sd%1d size = %d\n", j, sd_sizes[j]);
+#endif
+ cmd[0] = READ_6;
+ cmd[2] = cmd[3] = cmd[5] = 0;
+ cmd[4] = 1;
+ the_result = -1;
+
+ scsi_do_cmd (rscsi_disks[i].device->host_no , rscsi_disks[i].device->id,
+ (void *) cmd, (void *) buffer, 512, sd_init_done, SD_TIMEOUT,
+ sense_buffer, MAX_RETRIES);
+
+ while (the_result < 0);
+
+
+ if (the_result || (0xaa55 != *(unsigned short *)(buffer + 510)))
+ {
+ printk ("Cannot read partition table for sd %d"
+ "\n\r",i);
+ rscsi_disks[i].use = 0;
+ }
+ else
+ for (++j, k=j+4, p=(Partition *) (buffer + 0x1be); j < k; ++j, ++p)
+ {
+ memcpy ((void *) &scsi_disks[j], (void *) p, sizeof(Partition));
+ sd_sizes[j]=(scsi_disks[j].nr_sects)>>1;
+#ifdef DEBUG
+ printk("/dev/sd%1d size = %d (%d blocks), offset = %d\n", j, scsi_disks[j].nr_sects, sd_sizes[j], scsi_disks[j].start_sect);
+#endif
+ }
+
+ rscsi_disks[i].ten = 1;
+ rscsi_disks[i].remap = 1;
+ }
+ }
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blk_size[MAJOR_NR] = sd_sizes;
+ blkdev_fops[MAJOR_NR] = &sd_fops;
+}
+#endif
+
--- /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/04/24 18:01:50 root Exp root $
+*/
+
+#ifndef _SCSI_H
+#include "scsi.h"
+#endif
+
+#define MAX_SD 2
+
+typedef struct partition {
+ unsigned char boot_ind; /* 0x80 - active (unused) */
+ unsigned char head; /* ? */
+ unsigned char sector; /* ? */
+ unsigned char cyl; /* ? */
+ unsigned char sys_ind; /* ? */
+ unsigned char end_head; /* ? */
+ unsigned char end_sector; /* ? */
+ unsigned char end_cyl; /* ? */
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+} Partition;
+
+extern int NR_SD;
+
+extern Partition scsi_disks[MAX_SD << 4] ;
+
+
+typedef struct {
+ unsigned capacity; /* size in blocks */
+ unsigned sector_size; /* size in bytes */
+ Scsi_Device *device;
+ unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */
+ unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
+ unsigned ten:1; /* support ten byte read / write */
+ unsigned remap:1; /* support remapping */
+ unsigned use:1; /* after the initial inquiry, is
+ the device still supported ? */
+ } Scsi_Disk;
+
+extern Scsi_Disk rscsi_disks[MAX_SD];
+
+void sd_init(void);
+
+#define HOST (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no)
+#define ID (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id)
+#define LUN (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->lun)
+#endif
--- /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 (int dev, int cmd, void *arg);
+
+int sd_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsigned long arg)
+{
+ int dev = inode->i_rdev;
+
+ switch (cmd) {
+ default:
+ return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device,cmd,(void *) arg);
+ }
+}
+#endif
--- /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>
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include <linux/sched.h>
+
+#include "seagate.h"
+#include "scsi.h"
+#include "hosts.h"
+
+static int incommand; /*
+ set if arbitration has finished and we are
+ in some command phase.
+ */
+
+static void *base_address = NULL; /*
+ Where the card ROM starts,
+ used to calculate memory mapped
+ register location.
+ */
+static volatile int abort_confirm = 0;
+
+volatile void *st0x_cr_sr; /*
+ control register write,
+ status register read.
+ 256 bytes in length.
+
+ Read is status of SCSI BUS,
+ as per STAT masks.
+
+ */
+
+
+static volatile void *st0x_dr; /*
+ data register, read write
+ 256 bytes in length.
+ */
+
+
+static volatile int st0x_aborted=0; /*
+ set when we are aborted, ie by a time out, etc.
+ */
+
+ /*
+ In theory, we have a nice auto
+ detect routine - but this
+ overides it.
+ */
+
+
+#define retcode(result) (((result) << 16) | (message << 8) | status)
+#define STATUS (*(unsigned char *) st0x_cr_sr)
+#define CONTROL STATUS
+#define DATA (*(unsigned char *) st0x_dr)
+
+#ifndef OVERRIDE
+static const char * seagate_bases[] = {(char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xce000,
+ (char *) 0xdc000, (char *) 0xde000};
+typedef struct
+ {
+ char *signature ;
+ unsigned offset;
+ unsigned length;
+ } Signature;
+
+static const Signature signatures[] = {
+{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40},
+{"SEAGATE SCSI BIOS ",16, 17},
+{"SEAGATE SCSI BIOS ",17, 17}};
+/*
+ Note that the last signature handles BIOS revisions 3.0.0 and
+ 3.2 - the real ID's are
+
+SEAGATE SCSI BIOS REVISION 3.0.0
+SEAGATE SCSI BIOS REVISION 3.2
+
+*/
+
+#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature))
+#endif
+
+int seagate_st0x_detect (int hostnum)
+ {
+ #ifndef OVERRIDE
+ int i,j;
+ #endif
+
+ /*
+ First, we try for the manual override.
+ */
+ #ifdef DEBUG
+ printk("Autodetecting seagate ST0x\n");
+ #endif
+
+ base_address = NULL;
+ #ifdef OVERRIDE
+ base_address = (void *) OVERRIDE;
+ #ifdef DEBUG
+ printk("Base address overridden to %x\n", base_address);
+ #endif
+ #else
+ /*
+ To detect this card, we simply look for the SEAGATE SCSI
+ from the BIOS version notice in all the possible locations
+ of the ROM's.
+ */
+
+ for (i = 0; i < (sizeof (seagate_bases) / sizeof (char * )); ++i)
+ for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)
+ if (!memcmp ((void *) (seagate_bases[i] +
+ signatures[j].offset), (void *) signatures[j].signature,
+ signatures[j].length))
+ base_address = (void *) seagate_bases[i];
+ #endif
+
+ if (base_address)
+ {
+ st0x_cr_sr =(void *) (((unsigned char *) base_address) + 0x1a00);
+ st0x_dr = (void *) (((unsigned char *) base_address )+ 0x1c00);
+ #ifdef DEBUG
+ printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);
+ #endif
+ return -1;
+ }
+ else
+ {
+ #ifdef DEBUG
+ printk("ST0x not detected.\n");
+ #endif
+ return 0;
+ }
+ }
+
+
+
+char *seagate_st0x_info(void)
+{
+ static char buffer[] = "Seagate ST-0X SCSI driver by Drew Eckhardt \n"
+"$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/seagate.c,v 1.1 1992/04/24 18:01:50 root Exp root $\n";
+ return buffer;
+}
+
+
+
+int seagate_st0x_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen)
+ {
+ int len;
+ unsigned char *data;
+
+ int clock; /*
+ We use clock for timeouts, etc. This replaces the
+ seagate_st0x_timeout that we had been using.
+ */
+ #if (DEBUG & PHASE_SELECTION)
+ int temp;
+ #endif
+
+ #if (DEBUG & PHASE_EXIT)
+ void *retaddr, *realretaddr;
+ #endif
+
+ #if ((DEBUG & PHASE_ETC) || (DEBUG & PRINT_COMMAND) || (DEBUG & PHASE_EXIT))
+ int i;
+ #endif
+
+ #if (DEBUG & PHASE_ETC)
+ int phase=0, newphase;
+ #endif
+
+ int done = 0;
+ unsigned char status = 0;
+ unsigned char message = 0;
+ register unsigned char status_read;
+
+ #if (DEBUG & PHASE_EXIT)
+ __asm__("
+movl 4(%%ebp), %%eax
+":"=a" (realretaddr):);
+ printk("return address = %08x\n", realretaddr);
+ #endif
+
+
+ len=bufflen;
+ data=(unsigned char *) buff;
+
+ incommand = 0;
+ st0x_aborted = 0;
+
+ #if (DEBUG & PRINT_COMMAND)
+ printk ("seagate_st0x_command, target = %d, command = ", target);
+ for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i)
+ printk("%02x ", ((unsigned char *) cmnd)[i]);
+ printk("\n");
+ #endif
+
+ if (target > 6)
+ return DID_BAD_TARGET;
+
+
+ #if (DEBUG & PHASE_BUS_FREE)
+ printk ("SCSI PHASE = BUS FREE \n");
+ #endif
+
+ /*
+
+ BUS FREE PHASE
+
+ On entry, we make sure that the BUS is in a BUS FREE
+ phase, by insuring that both BSY and SEL are low for
+ at least one bus settle delay. The standard requires a
+ minimum of 400 ns, which is 16 clock cycles on a
+ 386-40 .
+
+ This doesn't give us much time - so we'll do two several
+ reads to be sure be sure.
+ */
+
+ clock = jiffies + ST0X_BUS_FREE_DELAY;
+
+ while (((STATUS | STATUS | STATUS) &
+ (STAT_BSY | STAT_SEL)) &&
+ (!st0x_aborted) && (jiffies < clock));
+
+ if (jiffies > clock)
+ return retcode(DID_BUS_BUSY);
+ else if (st0x_aborted)
+ return retcode(st0x_aborted);
+
+ /*
+ Bus free has been detected, within BUS settle. I used to support an arbitration
+ phase - however, on the seagate, this degraded performance by a factor > 10 - so
+ it is no more.
+ */
+
+ /*
+ SELECTION PHASE
+
+ Now, we select the disk, giving it the SCSI ID at data
+ and a command of PARITY if necessary, plus driver enable,
+ plus raise select signal.
+ */
+
+ #if (DEBUG & PHASE_SELECTION)
+ printk("SCSI PHASE = SELECTION\n");
+ #endif
+
+ clock = jiffies + ST0X_SELECTION_DELAY;
+ DATA = (unsigned char) (1 << target);
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL;
+
+ /*
+ When the SCSI device decides that we're gawking at it, it will respond by asserting BUSY on the bus.
+ */
+ while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock) && !st0x_aborted)
+
+#if (DEBUG & PHASE_SELECTION)
+ {
+ temp = clock - jiffies;
+
+ if (!(jiffies % 5))
+ printk("seagate_st0x_timeout : %d \r",temp);
+
+ }
+ printk("Done. \n\r");
+ printk("Status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", status_read, temp,
+ st0x_aborted);
+#else
+ ;
+#endif
+
+
+ if ((jiffies > clock) || (!st0x_aborted & !(status_read & STAT_BSY)))
+ {
+ #if (DEBUG & PHASE_SELECT)
+ printk ("NO CONNECT with target %d, status = %x \n", target, STATUS);
+ #endif
+ return retcode(DID_NO_CONNECT);
+ }
+
+ /*
+ If we have been aborted, and we have a command in progress, IE the target still has
+ BSY asserted, then we will reset the bus, and notify the midlevel driver to
+ expect sense.
+ */
+
+ if (st0x_aborted)
+ {
+ CONTROL = BASE_CMD;
+ if (STATUS & STAT_BSY)
+ {
+ seagate_st0x_reset();
+ return retcode(DID_RESET);
+ }
+
+ return retcode(st0x_aborted);
+ }
+
+ /*
+ COMMAND PHASE
+ The device has responded with a BSY, so we may now enter
+ the information transfer phase, where we will send / recieve
+ data and command as directed by the target.
+
+
+ The nasty looking read / write inline assembler loops we use for
+ DATAIN and DATAOUT phases are approximately 4-5 times as fast as
+ the 'C' versions - since we're moving 1024 bytes of data, this
+ really adds up.
+ */
+
+ #if (DEBUG & PHASE_ETC)
+ printk("PHASE = information transfer\n");
+ #endif
+
+ incommand = 1;
+
+ /*
+ Enable command
+ */
+
+ CONTROL = BASE_CMD | CMD_DRVR_ENABLE;
+
+ /*
+ Now, we poll the device for status information,
+ and handle any requests it makes. Note that since we are unsure of
+ how much data will be flowing across the system, etc and cannot
+ make reasonable timeouts, that we will instead have the midlevel
+ driver handle any timeouts that occur in this phase.
+ */
+
+ while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done)
+ {
+ #ifdef PARITY
+ if (status_read & STAT_PARITY)
+ {
+ done = 1;
+ st0x_aborted = DID_PARITY;
+ }
+ #endif
+
+ if (status_read & STAT_REQ)
+ {
+ #if (DEBUG & PHASE_ETC)
+ if ((newphase = (status_read & REQ_MASK)) != phase)
+ {
+ phase = newphase;
+ switch (phase)
+ {
+ case REQ_DATAOUT : printk("SCSI PHASE = DATA OUT\n"); break;
+ case REQ_DATAIN : printk("SCSI PHASE = DATA IN\n"); break;
+ case REQ_CMDOUT : printk("SCSI PHASE = COMMAND OUT\n"); break;
+ case REQ_STATIN : printk("SCSI PHASE = STATUS IN\n"); break;
+ case REQ_MSGOUT : printk("SCSI PHASE = MESSAGE OUT\n"); break;
+ case REQ_MSGIN : printk("SCSI PHASE = MESSAGE IN\n"); break;
+ default : printk("UNKNOWN PHASE"); st0x_aborted = 1; done = 1;
+ }
+ }
+ #endif
+
+ switch (status_read & REQ_MASK)
+ {
+ case REQ_DATAOUT :
+
+ /*
+ We loop as long as we are in a data out phase, there is data to send, and BSY is still
+ active
+ */
+ __asm__ ("
+
+/*
+ Local variables :
+ len = ecx
+ data = esi
+ st0x_cr_sr = ebx
+ st0x_dr = edi
+
+ Test for any data here at all.
+*/
+ movl %0, %%esi /* local value of data */
+ movl %1, %%ecx /* local value of len */
+ orl %%ecx, %%ecx
+ jz 2f
+
+ cld
+
+ movl _st0x_cr_sr, %%ebx
+ movl _st0x_dr, %%edi
+
+1: movb (%%ebx), %%al
+/*
+ Test for BSY
+*/
+
+ test $1, %%al
+ jz 2f
+
+/*
+ Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0.
+*/
+ test $0xe, %%al
+ jnz 2f
+/*
+ Test for REQ
+*/
+ test $0x10, %%al
+ jz 1b
+ lodsb
+ movb %%al, (%%edi)
+ loop 1b
+
+2:
+ movl %%esi, %2
+ movl %%ecx, %3
+ ":
+/* output */
+"=r" (data), "=r" (len) :
+/* input */
+"0" (data), "1" (len) :
+/* clobbered */
+"ebx", "ecx", "edi", "esi");
+
+ break;
+
+ case REQ_DATAIN :
+ /*
+ We loop as long as we are in a data out phase, there is room to read, and BSY is still
+ active
+ */
+
+ __asm__ ("
+/*
+ Local variables :
+ ecx = len
+ edi = data
+ esi = st0x_cr_sr
+ ebx = st0x_dr
+
+ Test for room to read
+*/
+
+ movl %0, %%edi /* data */
+ movl %1, %%ecx /* len */
+ orl %%ecx, %%ecx
+ jz 2f
+
+ cld
+ movl _st0x_cr_sr, %%esi
+ movl _st0x_dr, %%ebx
+
+1: movb (%%esi), %%al
+/*
+ Test for BSY
+*/
+
+ test $1, %%al
+ jz 2f
+
+/*
+ Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4.
+*/
+ movb $0xe, %%ah
+ andb %%al, %%ah
+ cmpb $0x04, %%ah
+ jne 2f
+
+/*
+ Test for REQ
+*/
+ test $0x10, %%al
+ jz 1b
+
+ movb (%%ebx), %%al
+ stosb
+ loop 1b
+
+2: movl %%edi, %2 /* data */
+ movl %%ecx, %3 /* len */
+ ":
+/* output */
+"=r" (data), "=r" (len) :
+/* input */
+"0" (data), "1" (len) :
+/* clobbered */
+"ebx", "ecx", "edi", "esi");
+ break;
+
+ case REQ_CMDOUT :
+ while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) ==
+ REQ_CMDOUT))
+ DATA = *(unsigned char *) cmnd ++;
+ break;
+
+ case REQ_STATIN :
+ status = DATA;
+ break;
+
+ case REQ_MSGOUT :
+ DATA = MESSAGE_REJECT;
+ break;
+
+ case REQ_MSGIN :
+ if ((message = DATA) == COMMAND_COMPLETE)
+ done=1;
+
+ break;
+
+ default : printk("UNKNOWN PHASE"); st0x_aborted = DID_ERROR;
+ }
+ }
+
+ }
+
+#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT))
+ printk("Transfered %d bytes, allowed %d additional bytes\n", (bufflen - len), len);
+#endif
+
+#if (DEBUG & PHASE_EXIT)
+ printk("Buffer : \n");
+ for (i = 0; i < 20; ++i)
+ printk ("%02x ", ((unsigned char *) buff)[i]);
+ printk("\n");
+ printk("Status = %02x, message = %02x\n", status, message);
+#endif
+
+
+ if (st0x_aborted)
+ {
+ if (STATUS & STAT_BSY)
+ {
+ seagate_st0x_reset();
+ st0x_aborted = DID_RESET;
+ }
+ abort_confirm = 1;
+ }
+
+ CONTROL = BASE_CMD;
+
+#if (DEBUG & PHASE_EXIT)
+ __asm__("
+mov 4(%%ebp), %%eax
+":"=a" (retaddr):);
+
+ printk("Exiting seagate_st0x_command() - return address is %08x \n", retaddr);
+ if (retaddr != realretaddr)
+ panic ("Corrupted stack : return address on entry != return address on exit.\n");
+
+#endif
+
+ return retcode (st0x_aborted);
+ }
+
+int seagate_st0x_abort (int code)
+ {
+ if (code)
+ st0x_aborted = code;
+ else
+ st0x_aborted = DID_ABORT;
+
+ return 0;
+ }
+
+/*
+ the seagate_st0x_reset function resets the SCSI bus
+*/
+
+int seagate_st0x_reset (void)
+ {
+ unsigned clock;
+ /*
+ No timeouts - this command is going to fail because
+ it was reset.
+ */
+
+#ifdef DEBUG
+ printk("In seagate_st0x_reset()\n");
+#endif
+
+
+ /* assert RESET signal on SCSI bus. */
+
+ CONTROL = BASE_CMD | CMD_RST;
+ clock=jiffies+2;
+
+
+ /* Wait. */
+
+ while (jiffies < clock);
+
+ CONTROL = BASE_CMD;
+
+ st0x_aborted = DID_RESET;
+
+#ifdef DEBUG
+ printk("SCSI bus reset.\n");
+#endif
+ return 0;
+ }
+#endif
--- /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_abort(int);
+char *seagate_st0x_info(void);
+int seagate_st0x_reset(void);
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \
+ seagate_st0x_info, seagate_st0x_command, \
+ NULL, seagate_st0x_abort, seagate_st0x_reset, \
+ 0, 7, 0}
+#endif
+
+
+/*
+ defining PARITY causes parity data to be checked
+*/
+
+#define PARITY
+
+/*
+ defining ARBITRATE causes the arbitration sequence to be used. And speed to drop by a
+ factor of ten.
+*/
+
+#undef ARBITRATE
+
+
+/*
+ Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
+ driver, and Mitsugu Suzuki for information on the ST-01
+ SCSI host.
+*/
+
+/*
+ CONTROL defines
+*/
+
+#define CMD_RST 0x01
+#define CMD_SEL 0x02
+#define CMD_BSY 0x04
+#define CMD_ATTN 0x08
+#define CMD_START_ARB 0x10
+#define CMD_EN_PARITY 0x20
+#define CMD_INTR 0x40
+#define CMD_DRVR_ENABLE 0x80
+
+/*
+ STATUS
+*/
+
+#define STAT_BSY 0x01
+#define STAT_MSG 0x02
+#define STAT_IO 0x04
+#define STAT_CD 0x08
+#define STAT_REQ 0x10
+#define STAT_SEL 0x20
+#define STAT_PARITY 0x40
+#define STAT_ARB_CMPL 0x80
+
+/*
+ REQUESTS
+*/
+
+#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG)
+#define REQ_DATAOUT 0
+#define REQ_DATAIN STAT_IO
+#define REQ_CMDOUT STAT_CD
+#define REQ_STATIN (STAT_CD | STAT_IO)
+#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
+
+extern volatile int seagate_st0x_timeout;
+
+#ifdef PARITY
+ #define BASE_CMD CMD_EN_PARITY
+#else
+ #define BASE_CMD 0
+#endif
+
+/*
+ Debugging code
+*/
+
+#define PHASE_BUS_FREE 1
+#define PHASE_ARBITRATION 2
+#define PHASE_SELECTION 4
+#define PHASE_DATAIN 8
+#define PHASE_DATAOUT 0x10
+#define PHASE_CMDOUT 0x20
+#define PHASE_MSGIN 0x40
+#define PHASE_MSGOUT 0x80
+#define PHASE_STATUSIN 0x100
+#define PHASE_ETC (PHASE_DATAIN | PHASE_DATA_OUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
+#define PRINT_COMMAND 0x200
+#define PHASE_EXIT 0x400
+
+/*
+ Control options - these are timeouts specified in .01 seconds.
+*/
+
+#define ST0X_BUS_FREE_DELAY 25
+#define ST0X_SELECTION_DELAY 25
+
+#endif
+
--- /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"
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.c,v 1.1 1992/04/24 18:01:50 root Exp root $";
+*/
+
+Scsi_Tape scsi_tapes[MAX_ST];
+static int st_sizes[MAX_ST];
+int NR_ST=0;
+
+void do_st_request(void)
+{
+ panic("There is no st driver.\n\r");
+}
+
+void st_init(void)
+{
+ blk_dev[MAJOR_NR].request_fn = do_st_request;
+ blk_size[MAJOR_NR] = st_sizes;
+}
+#endif
--- /dev/null
+
+#ifndef _ST_H
+ #define _ST_H
+/*
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+*/
+
+#ifndef _SCSI_H
+#include "scsi.h"
+#endif
+
+#define MAX_ST 1
+
+typedef struct
+ {
+ /*
+ Undecided goodies go here!!!
+ */
+ Scsi_Device* device;
+ } Scsi_Tape;
+
+
+extern int NR_ST;
+extern Scsi_Tape scsi_tapes[MAX_ST];
+void st_init(void);
+#endif
--- /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(int dev, int cmd, void *arg);
+
+int st_ioctl(struct inode * inode,struct file * file, unsigned long cmd, unsigned long arg)
+{
+ int dev = inode->i_rdev;
+
+ switch (cmd) {
+ default:
+ return scsi_ioctl(scsi_tapes[MINOR(dev)].device,cmd,(void *) arg);
+ }
+}
+#endif
--- /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
+ */
+
+/* ??? Caveats:
+ This driver is VERY stupid. It takes no advantage of much of the power of
+ the UltraStor controller. We just sit-and-spin while waiting for commands
+ to complete. I hope to go back and beat it into shape, but PLEASE, anyone
+ else who would like to, please make improvements! */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+
+#include <stddef.h>
+
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#include "ultrastor.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#define VERSION "1.0 alpha"
+
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+#define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
+
+/* Simply using "unsigned long" in these structures won't work as it causes
+ alignment. Perhaps the "aligned" attribute may be used in GCC 2.0 to get
+ around this, but for now I use this hack. */
+typedef struct {
+ unsigned char bytes[4];
+} Longword;
+
+/* Used to store configuration info read from config i/o registers. Most of
+ this is not used yet, but might as well save it. */
+struct config {
+ struct {
+ unsigned char bios_segment: 3;
+ unsigned char reserved: 1;
+ unsigned char interrupt: 2;
+ unsigned char dma_channel: 2;
+ } config_1;
+ struct {
+ unsigned char ha_scsi_id: 3;
+ unsigned char mapping_mode: 2;
+ unsigned char bios_drive_number: 1;
+ unsigned char tfr_port: 2;
+ } config_2;
+};
+
+/* MailBox SCSI Command Packet. Basic command structure for communicating
+ with controller. */
+struct mscp {
+ unsigned char opcode: 3; /* type of command */
+ unsigned char xdir: 2; /* data transfer direction */
+ unsigned char dcn: 1; /* disable disconnect */
+ unsigned char ca: 1; /* use cache (if available) */
+ unsigned char sg: 1; /* scatter/gather operation */
+ unsigned char target_id: 3; /* target SCSI id */
+ unsigned char ch_no: 2; /* SCSI channel (always 0 for 14f) */
+ unsigned char lun: 3; /* logical unit number */
+ Longword transfer_data; /* transfer data pointer */
+ Longword transfer_data_length; /* length in bytes */
+ Longword command_link; /* for linking command chains */
+ unsigned char scsi_command_link_id; /* identifies command in chain */
+ unsigned char number_of_sg_list; /* (if sg is set) 8 bytes per list */
+ unsigned char length_of_sense_byte;
+ unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */
+ unsigned char scsi_cdbs[12]; /* SCSI commands */
+ unsigned char adapter_status; /* non-zero indicates HA error */
+ unsigned char target_status; /* non-zero indicates target error */
+ Longword sense_data;
+};
+
+/* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
+static const void *const bios_segment_table[8] = {
+ NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
+ (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
+};
+
+/* Allowed IRQs for 14f */
+static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
+
+/* Allowed DMA channels for 14f (0 indicates reserved) */
+static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
+
+#if 0 /* Not currently used, head/sector mappings allowed by 14f */
+static const struct {
+ unsigned char heads;
+ unsigned char sectors;
+} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
+#endif
+
+/* Config info */
+static struct config config;
+
+/* Our index in the host adapter array maintained by higher-level driver */
+static int host_number;
+
+/* PORT_ADDRESS is first port address used for i/o of messages. */
+#ifdef PORT_OVERRIDE
+# define PORT_ADDRESS PORT_OVERRIDE
+#else
+static unsigned short port_address = 0;
+# define PORT_ADDRESS port_address
+#endif
+
+static volatile int aborted = 0;
+
+#ifndef PORT_OVERRIDE
+static const unsigned short ultrastor_ports[] = {
+ 0x330, 0x340, 0x310, 0x230, 0x240, 0x210, 0x130, 0x140,
+};
+#endif
+
+static const struct {
+ const char *signature;
+ size_t offset;
+ size_t length;
+} signatures[] = {
+ { "SBIOS 1.01 COPYRIGHT (C) UltraStor Corporation,1990-1992.", 0x10, 57 },
+};
+
+int ultrastor_14f_detect(int hostnum)
+{
+ size_t i;
+ unsigned char in_byte;
+ const void *base_address;
+
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: called\n");
+#endif
+
+#ifndef PORT_OVERRIDE
+/* ??? This is easy to implement, but I'm not sure how "friendly" it is to
+ go off and read random i/o ports. */
+# error Not implemented!
+#endif
+
+ if (!PORT_ADDRESS) {
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: no port address found!\n");
+#endif
+ return FALSE;
+ }
+
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: port address = %X\n", PORT_ADDRESS);
+#endif
+
+ in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
+ if (in_byte != US14F_PRODUCT_ID_0) {
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: unknown product ID 0 - %02X\n", in_byte);
+#endif
+ return FALSE;
+ }
+ in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
+ /* Only upper nibble is defined for Product ID 1 */
+ if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: unknown product ID 1 - %02X\n", in_byte);
+#endif
+ return FALSE;
+ }
+
+ /* All above tests passed, must be the right thing. Get some useful
+ info. */
+ *(char *)&config.config_1 = inb(CONFIG(PORT_ADDRESS + 0));
+ *(char *)&config.config_2 = inb(CONFIG(PORT_ADDRESS + 1));
+
+ /* To verify this card, we simply look for the UltraStor SCSI from the
+ BIOS version notice. */
+ base_address = bios_segment_table[config.config_1.bios_segment];
+ if (base_address != NULL) {
+ int found = 0;
+
+ for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
+ if (memcmp((char *)base_address + signatures[i].offset,
+ signatures[i].signature, signatures[i].length))
+ found = 1;
+ if (!found)
+ base_address = NULL;
+ }
+ if (!base_address) {
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: not detected.\n");
+#endif
+ return FALSE;
+ }
+
+ /* Final consistancy check, verify previous info. */
+ if (!dma_channel_table[config.config_1.dma_channel]
+ || !(config.config_2.tfr_port & 0x2)) {
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: consistancy check failed\n");
+#endif
+ return FALSE;
+ }
+
+ /* If we were TRULY paranoid, we could issue a host adapter inquiry
+ command here and verify the data returned. But frankly, I'm
+ exhausted! */
+
+ /* Finally! Now I'm satisfied... */
+#ifdef DEBUG
+ printk("ultrastor_14f_detect: detect succeeded\n"
+ " BIOS segment: %05X\n"
+ " Interrupt: %d\n"
+ " DMA channel: %d\n"
+ " H/A SCSI ID: %d\n",
+ base_address, interrupt_table[config.config_1.interrupt],
+ dma_channel_table[config.config_1.dma_channel],
+ config.config_2.ha_scsi_id);
+#endif
+ host_number = hostnum;
+ scsi_hosts[hostnum].this_id = config.config_2.ha_scsi_id;
+ return TRUE;
+}
+
+const char *ultrastor_14f_info(void)
+{
+ return "UltraStor 14F SCSI driver version "
+ VERSION
+ " by David B. Gentzel\n";
+}
+
+#if 0
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+ void *buff, int bufflen, void (*done)(int, int))
+#else
+int ultrastor_14f_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen)
+#endif
+{
+ struct mscp mscp = {
+ OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE,
+ target, 0, 0 /* LUN??? */,
+ *(Longword *)&buff,
+ *(Longword *)&bufflen,
+ { 0, 0, 0, 0 },
+ 0,
+ 0,
+ 0,
+ ((*(char *)cmnd <= 0x1F) ? 6 : 10),
+ { 0 }, /* Filled in via memcpy below */
+ 0,
+ 0,
+ { 0, 0, 0, 0 }
+ };
+ unsigned char in_byte;
+
+ memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
+
+ /* Find free OGM slot (OGMINT bit is 0) */
+ do
+ in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS));
+ while (!aborted && (in_byte & 1));
+ if (aborted)
+ /* ??? is this right? */
+ return (aborted << 16);
+
+ /* Store pointer in OGM address bytes */
+ outb(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
+ outb(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
+ outb(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
+ outb(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
+
+ /* Issue OGM interrupt */
+ outb(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
+
+ /* Wait for ICM interrupt */
+ do
+ in_byte = inb(SYS_DOORBELL_INTR(PORT_ADDRESS));
+ while (!aborted && !(in_byte & 1));
+ if (aborted)
+ /* ??? is this right? */
+ return (aborted << 16);
+
+ /* Clean ICM slot (set ICMINT bit to 0) */
+ outb(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
+
+ /* ??? not right, but okay for now? */
+ return (mscp.adapter_status << 16) | mscp.target_status;
+}
+
+int ultrastor_14f_abort(int code)
+{
+ aborted = (code ? code : DID_ABORT);
+ return 0;
+}
+
+int ultrastor_14f_reset(void)
+{
+ unsigned char in_byte;
+
+#ifdef DEBUG
+ printk("ultrastor_14f_reset: called\n");
+#endif
+
+ /* Issue SCSI BUS reset */
+ outb(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
+ /* Wait for completion... */
+ do
+ in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS));
+ while (in_byte & 0x20);
+
+ aborted = DID_RESET;
+
+#ifdef DEBUG
+ printk("ultrastor_14f_reset: returning\n");
+#endif
+ return 0;
+}
+
+#endif
--- /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
+
+/* ??? Some of the stuff in this file is really private to ultrastor.c and
+ should be moved elsewhere (as this file is included by higher-level driver
+ files). */
+
+/* ??? These don't really belong here */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+int ultrastor_14f_detect(int);
+const char *ultrastor_14f_info(void);
+#if 0 /* ??? Future direction... */
+int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
+ void *buff, int bufflen,
+ void (*done)(int, int));
+#else
+int ultrastor_14f_command(unsigned char target, const void *cmnd,
+ void *buff, int bufflen);
+#endif
+int ultrastor_14f_abort(int);
+int ultrastor_14f_reset(void);
+
+#if 0 /* ??? Future direction... */
+# define ULTRASTOR_14F \
+ { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, 0, \
+ ultrastor_14f_queuecommand, ultrastor_14f_abort, ultrastor_14f_reset, \
+ TRUE, 0, 0 }
+#else
+# define ULTRASTOR_14F \
+ { "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \
+ ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \
+ FALSE, 0, 0 }
+#endif
+
+#define PORT_OVERRIDE 0x330
+
+/* Port addresses (relative to the base address) */
+#define LCL_DOORBELL_MASK(port) ((port) + 0x0)
+#define LCL_DOORBELL_INTR(port) ((port) + 0x1)
+#define SYS_DOORBELL_MASK(port) ((port) + 0x2)
+#define SYS_DOORBELL_INTR(port) ((port) + 0x3)
+#define PRODUCT_ID(port) ((port) + 0x4)
+#define CONFIG(port) ((port) + 0x6)
+#define OGM_DATA_PTR(port) ((port) + 0x8)
+#define ICM_DATA_PTR(port) ((port) + 0xC)
+
+/* Values for the PRODUCT_ID ports for the 14F */
+#define US14F_PRODUCT_ID_0 0x56
+#define US14F_PRODUCT_ID_1 0x40 /* NOTE: Only upper nibble is used */
+
+/* MSCP field values */
+
+/* Opcode */
+#define OP_HOST_ADAPTER 0x1
+#define OP_SCSI 0x2
+#define OP_RESET 0x4
+
+/* Date Transfer Direction */
+#define DTD_SCSI 0x0
+#define DTD_IN 0x1
+#define DTD_OUT 0x2
+#define DTD_NONE 0x3
+
+/* Host Adapter command subcodes */
+#define HA_CMD_INQUIRY 0x1
+#define HA_CMD_SELF_DIAG 0x2
+#define HA_CMD_READ_BUFF 0x3
+#define HA_CMD_WRITE_BUFF 0x4
+
+#endif
$(CC) $(CFLAGS) \
-c -o $*.o $<
-OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \
- tty_ioctl.o pty.o lp.o
+OBJS = tty_io.o console.o keyboard.o serial.o \
+ tty_ioctl.o pty.o lp.o vt.o mem.o
chr_drv.a: $(OBJS)
$(AR) rcs chr_drv.a $(OBJS)
sync
-keyboard.s: keyboard.S
- $(CPP) $(KEYBOARD) -traditional keyboard.S -o keyboard.s
+keyboard.o: keyboard.c
+ $(CC) $(CFLAGS) $(KEYBOARD) -c -o keyboard.o keyboard.c
clean:
rm -f core *.o *.a tmp_make keyboard.s
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \
- $(CPP) -M $$i;done) >> tmp_make
+ $(CPP) -M -DKBD_FINNISH $$i;done) >> tmp_make
cp tmp_make Makefile
### Dependencies:
-console.s console.o : console.c ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
+console.s console.o : console.c ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/timer.h ../../include/linux/tty.h \
+ ../../include/asm/system.h ../../include/termios.h ../../include/linux/config.h \
+ ../../include/linux/config_rel.h ../../include/linux/config_ver.h ../../include/linux/config.dist.h \
+ ../../include/asm/io.h ../../include/asm/segment.h ../../include/linux/string.h \
+ ../../include/errno.h ../../include/sys/kd.h vt_kern.h
+keyboard.s keyboard.o : keyboard.c ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/ctype.h ../../include/linux/tty.h \
+ ../../include/asm/system.h ../../include/termios.h ../../include/asm/io.h
+lp.s lp.o : lp.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h \
- ../../include/time.h ../../include/sys/resource.h \
- ../../include/linux/timer.h ../../include/linux/tty.h \
- ../../include/termios.h ../../include/linux/config.h \
- ../../include/linux/config_rel.h ../../include/linux/config_ver.h \
- ../../include/asm/io.h ../../include/asm/system.h \
- ../../include/asm/segment.h ../../include/string.h ../../include/errno.h
-lp.s lp.o : lp.c ../../include/linux/lp.h ../../include/errno.h \
- ../../include/linux/kernel.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/lp.h ../../include/errno.h ../../include/asm/io.h ../../include/asm/segment.h
+mem.s mem.o : mem.c ../../include/errno.h ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/termios.h ../../include/asm/segment.h ../../include/asm/io.h
+pty.s pty.o : pty.c ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
../../include/sys/types.h ../../include/sys/dirent.h ../../include/limits.h \
- ../../include/linux/mm.h ../../include/signal.h ../../include/sys/param.h \
- ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
- ../../include/asm/io.h ../../include/asm/segment.h \
- ../../include/checkpoint.h
-pty.s pty.o : pty.c ../../include/linux/tty.h ../../include/termios.h \
- ../../include/sys/types.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/asm/system.h \
+ ../../include/linux/mm.h ../../include/linux/kernel.h ../../include/signal.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/tty.h ../../include/asm/system.h ../../include/termios.h \
../../include/asm/io.h
-serial.s serial.o : serial.c ../../include/linux/tty.h ../../include/termios.h \
- ../../include/sys/types.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/timer.h \
- ../../include/asm/system.h ../../include/asm/io.h
-tty_io.s tty_io.o : tty_io.c ../../include/ctype.h ../../include/errno.h \
- ../../include/signal.h ../../include/sys/types.h ../../include/unistd.h \
- ../../include/sys/stat.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/times.h ../../include/sys/utsname.h \
- ../../include/sys/param.h ../../include/sys/resource.h \
- ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/linux/tty.h \
- ../../include/termios.h ../../include/asm/segment.h \
- ../../include/asm/system.h
-tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h \
- ../../include/sys/types.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/linux/tty.h \
- ../../include/asm/io.h ../../include/asm/segment.h \
- ../../include/asm/system.h
+serial.s serial.o : serial.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/linux/timer.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/termios.h ../../include/asm/io.h
+tty_io.s tty_io.o : tty_io.c ../../include/linux/ctype.h ../../include/errno.h ../../include/signal.h \
+ ../../include/sys/types.h ../../include/unistd.h ../../include/sys/stat.h ../../include/sys/time.h \
+ ../../include/time.h ../../include/sys/times.h ../../include/sys/utsname.h ../../include/sys/param.h \
+ ../../include/sys/resource.h ../../include/utime.h ../../include/fcntl.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/linux/tty.h ../../include/asm/system.h ../../include/termios.h \
+ ../../include/asm/io.h ../../include/asm/segment.h
+tty_ioctl.s tty_ioctl.o : tty_ioctl.c ../../include/errno.h ../../include/termios.h ../../include/sys/types.h \
+ ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/asm/io.h ../../include/asm/segment.h
+vt.s vt.o : vt.c ../../include/errno.h ../../include/sys/types.h ../../include/sys/kd.h \
+ ../../include/sys/vt.h ../../include/asm/io.h ../../include/asm/segment.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ ../../include/sys/resource.h ../../include/linux/tty.h ../../include/asm/system.h \
+ ../../include/termios.h vt_kern.h
#include <asm/system.h>
#include <asm/segment.h>
-#include <string.h>
+#include <linux/string.h>
#include <errno.h>
+#include <sys/kd.h>
+#include "vt_kern.h"
+
#define DEF_TERMIOS \
(struct termios) { \
ICRNL, \
int NR_CONSOLES = 0;
+extern void vt_init(void);
extern void keyboard_interrupt(void);
extern void set_leds(void);
extern unsigned char kapplic;
extern unsigned char kleds;
extern unsigned char kmode;
+extern unsigned char kraw;
+extern unsigned char ke0;
unsigned long video_num_columns; /* Number of text columns */
unsigned long video_num_lines; /* Number of test lines */
unsigned int vc_saved_y;
unsigned int vc_iscolor;
unsigned char vc_kbdapplic;
- unsigned char vc_kbdleds;
unsigned char vc_kbdmode;
char * vc_translate;
+ /* additional information is in vt_kern.h */
} vc_cons [MAX_CONSOLES];
#define MEM_BUFFER_SIZE (2*80*50*8)
#define iscolor (vc_cons[currcons].vc_iscolor)
#define kbdapplic (vc_cons[currcons].vc_kbdapplic)
#define kbdmode (vc_cons[currcons].vc_kbdmode)
-#define kbdleds (vc_cons[currcons].vc_kbdleds)
+#define kbdraw (vt_cons[currcons].vc_kbdraw)
+#define kbde0 (vt_cons[currcons].vc_kbde0)
+#define kbdleds (vt_cons[currcons].vc_kbdleds)
int blankinterval = 5*60*HZ;
static int screen_size = 0;
{
char * p = RESPONSE;
- cli();
while (*p) {
PUTCH(*p,tty->read_q);
p++;
}
- sti();
TTY_READ_FLUSH(tty);
}
void con_write(struct tty_struct * tty)
{
- unsigned char c;
+ int c;
unsigned int currcons;
wake_up(&tty->write_q->proc_list);
printk("con_write: illegal tty\n\r");
return;
}
- while (!EMPTY(tty->write_q)) {
- if (tty->stopped)
- break;
- GETCH(tty->write_q,c);
+ if (vt_cons[currcons].vt_mode == KD_GRAPHICS) {
+ flush(tty->write_q);
+ return; /* no output in graphics mode */
+ }
+ while (!tty->stopped && (c = GETCH(tty->write_q)) >= 0) {
if (c == 24 || c == 26)
state = ESnormal;
switch(state) {
par[1] <= video_num_lines) {
top=par[0];
bottom=par[1];
+ gotoxy(currcons,0,0);
}
break;
case 's':
}
set_cursor(currcons);
timer_active &= ~(1<<BLANK_TIMER);
- if (console_blanked) {
- timer_table[BLANK_TIMER].expires = 0;
- timer_active |= 1<<BLANK_TIMER;
- } else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
- }
+ if (currcons == fg_console)
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
+ }
}
void do_keyboard_interrupt(void)
{
TTY_READ_FLUSH(TTY_TABLE(0));
timer_active &= ~(1<<BLANK_TIMER);
+ if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ return;
if (console_blanked) {
timer_table[BLANK_TIMER].expires = 0;
timer_active |= 1<<BLANK_TIMER;
char *display_desc = "????";
char *display_ptr;
int currcons = 0;
- long base, term;
- long video_memory;
- long saveterm, savebase;
+ long base;
video_num_columns = ORIG_VIDEO_COLS;
video_size_row = video_num_columns * 2;
display_ptr++;
}
- savebase = video_mem_base;
- saveterm = video_mem_term;
memsetw(vc_scrmembuf,video_erase_char,MEM_BUFFER_SIZE/2);
- video_mem_base = (long)vc_scrmembuf;
- video_mem_term = (long)&(vc_scrmembuf[MEM_BUFFER_SIZE/2]);
- video_memory = video_mem_term - video_mem_base;
+ base = (long)vc_scrmembuf;
screen_size = (video_num_lines * video_size_row);
- NR_CONSOLES = video_memory / screen_size;
+ NR_CONSOLES = MEM_BUFFER_SIZE / screen_size;
if (NR_CONSOLES > MAX_CONSOLES)
NR_CONSOLES = MAX_CONSOLES;
if (!NR_CONSOLES)
NR_CONSOLES = 1;
- video_memory = screen_size;
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
- base = origin = video_mem_start = video_mem_base;
- term = video_mem_end = base + video_memory;
- scr_end = video_mem_start + screen_size;
+ base = origin = video_mem_start = (long)vc_scrmembuf;
+ scr_end = video_mem_end = base + screen_size;
+ vc_scrbuf[0] = (unsigned short *) origin;
top = 0;
bottom = video_num_lines;
attr = 0x07;
translate = NORM_TRANS;
kbdleds = 2;
kbdmode = 0;
+ kbdraw = 0;
+ kbde0 = 0;
kbdapplic = 0;
+ vt_cons[0].vt_mode = KD_TEXT;
vc_cons[0].vc_bold_attr = -1;
gotoxy(currcons,ORIG_X,ORIG_Y);
for (currcons = 1; currcons<NR_CONSOLES; currcons++) {
vc_cons[currcons] = vc_cons[0];
- origin = video_mem_start = (base += video_memory);
- scr_end = origin + video_num_lines * video_size_row;
- video_mem_end = (term += video_memory);
+ vt_cons[currcons] = vt_cons[0];
+ base += screen_size;
+ origin = video_mem_start = base;
+ scr_end = video_mem_end = base + screen_size;
+ vc_scrbuf[currcons] = (unsigned short *) origin;
gotoxy(currcons,0,0);
}
- for (currcons = 0; currcons<NR_CONSOLES; currcons++)
- vc_scrbuf[currcons] = (unsigned short *)origin;
currcons = 0;
- video_mem_base = savebase;
- video_mem_term = saveterm;
video_mem_start = video_mem_base;
video_mem_end = video_mem_term;
{
int currcons = fg_console;
kbdmode = kmode;
+ kbdraw = kraw;
+ kbde0 = ke0;
kbdleds = kleds;
kbdapplic = kapplic;
currcons = new_console;
kmode = (kmode & 0x3F) | (kbdmode & 0xC0);
+ kraw = kbdraw;
+ ke0 = kbde0;
kleds = kbdleds;
kapplic = kbdapplic;
set_leds();
if (currcons<0 || currcons>=NR_CONSOLES)
currcons = 0;
+ if (vt_cons[currcons].vt_mode == KD_GRAPHICS)
+ return; /* no output in graphics mode */
while (c = *(b++)) {
if (c == 10) {
cr(currcons);
+++ /dev/null
-/*
- * linux/kernel/keyboard.S
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * Thanks to Alfred Leung for US keyboard patches
- * Wolfgang Thiel for German keyboard patches
- * Marc Corsini for the French keyboard
- * LeBlanc@mcc.ac.uk for the UK keyboard
- * Tommy Thorn (tthorn@daimi.aau.dk) for Danish keyboard
- */
-
-/* KBD_FINNISH for Finnish keyboards
- * KBD_US for US-type
- * KBD_GR for German keyboards
- * KBD_FR for Frech keyboard
- * KBD_UK for British extended keyboard
- * KBD_DK for Danish keyboard
- */
-
-.text
-.globl _hard_reset_now
-.globl _keyboard_interrupt
-.globl _kapplic
-.globl _kmode
-.globl _kleds
-.globl _set_leds
-
-/*
- * these are for the keyboard read functions
- */
-size = 2048 /* must be a power of two ! And MUST be the same
- as in tty_io.c !!!! */
-head = 4
-tail = 8
-proc_list = 12
-buf = 16
-
-_kapplic: .byte 0
-_kmode: .byte 0 /* caps, alt, ctrl and shift mode */
-_kleds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
-e0: .byte 0
-
-/*
- * con_int is the real interrupt routine that reads the
- * keyboard scan-code and converts it into the appropriate
- * ascii character(s).
- */
-_keyboard_interrupt:
- cld
- pushl %eax
- pushl %ebx
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- xorl %eax,%eax /* %eax is scan code */
- inb $0x60,%al
- pushl %eax
- inb $0x61,%al
- jmp 1f
-1: jmp 1f
-1: orb $0x80,%al
- jmp 1f
-1: jmp 1f
-1: outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: andb $0x7F,%al
- outb %al,$0x61
- jmp 1f
-1: jmp 1f
-1: movb $0x20,%al
- outb %al,$0x20
- popl %eax
- movl $1,%ebx
- cmpb $0xE0,%al
- je end_intr
- movl $2,%ebx
- cmpb $0xE1,%al
- je end_intr
- sti
- call key_table(,%eax,4)
- call _do_keyboard_interrupt
- movl $0,%ebx
-end_intr:
- movb %bl,e0
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %ebx
- popl %eax
- iret
-
-/*
- * This routine fills the buffer with max 8 bytes, taken from
- * %ebx:%eax. (%edx is high). The bytes are written in the
- * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero.
- */
-put_queue:
- pushl %ecx
- pushl %edx
- movl _table_list,%edx # read-queue for console
- movl head(%edx),%ecx
-1: movb %al,buf(%edx,%ecx)
- incl %ecx
- andl $size-1,%ecx
- cmpl tail(%edx),%ecx # buffer full - discard everything
- je 3f
- shrdl $8,%ebx,%eax
- je 2f
- shrl $8,%ebx
- jmp 1b
-2: movl %ecx,head(%edx)
- movl proc_list(%edx),%ecx
- testl %ecx,%ecx
- je 3f
- movl $0,(%ecx)
-3: popl %edx
- popl %ecx
- ret
-
-ctrl: movb $0x04,%al
- jmp 1f
-alt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: orb %al,_kmode
- ret
-unctrl: movb $0x04,%al
- jmp 1f
-unalt: movb $0x10,%al
-1: cmpb $0,e0
- je 2f
- addb %al,%al
-2: notb %al
- andb %al,_kmode
- ret
-
-lshift:
- orb $0x01,_kmode
- ret
-unlshift:
- andb $0xfe,_kmode
- ret
-rshift:
- orb $0x02,_kmode
- ret
-unrshift:
- andb $0xfd,_kmode
- ret
-
-old_leds:
- .byte 2
-
-caps: testb $0x80,_kmode
- jne 1f
- xorb $4,_kleds
- xorb $0x40,_kmode
- orb $0x80,_kmode
-_set_leds:
- movb _kleds,%al
- cmpb old_leds,%al
- je 1f
- movb %al,old_leds
- call kb_wait
- movb $0xed,%al /* set leds command */
- outb %al,$0x60
- call kb_wait
- movb _kleds,%al
- outb %al,$0x60
-1: ret
-uncaps: andb $0x7f,_kmode
- ret
-scroll:
- testb $0x03,_kmode
- je 1f
- call _show_mem
- jmp 2f
-1: call _show_state
-2: xorb $1,_kleds
- jmp _set_leds
-
-num: cmpb $0x01,_kapplic
- jne notappl
- movw $0x0050,%ax
-applkey:
- shll $16,%eax
- movw $0x4f1b,%ax
- xorl %ebx,%ebx
- jmp put_queue
-
-notappl:
- xorb $2,_kleds
- jmp _set_leds
-
-/*
- * cursor-key/numeric keypad cursor keys are handled here.
- * checking for numeric keypad etc.
- */
-cursor:
- subb $0x47,%al
- jb 1f
- cmpb $12,%al
- ja 1f
- jne cur2 /* check for ctrl-alt-del */
- testb $0x0c,_kmode
- je cur2
- testb $0x30,_kmode
- jne _ctrl_alt_del
-cur2: cmpb $0x01,e0 /* e0 forces cursor movement */
- je cur
- testb $0x03,_kmode /* shift forces cursor */
- jne cur
- cmpb $0x01,_kapplic
- jne notcappl
- movb appl_table(%eax),%al
- jmp applkey
-notcappl:
- testb $0x02,_kleds /* not num-lock forces cursor */
- je cur
- xorl %ebx,%ebx
- movb num_table(%eax),%al
- jmp put_queue
-1: ret
-
-/*
- * cursor keys send ^[ [ x if normal, ^[ O x if application mode
- */
-cur: movb cur_table(%eax),%al
- cmpb $'9,%al
- ja ok_cur
- movb $'~,%ah
-ok_cur: shll $16,%eax
- movw $0x5b1b,%ax
- xorl %ebx,%ebx
- cmpb $0x01,_kapplic
- jne put_queue
- movb $0x4f,%ah
- jmp put_queue
-
-#if defined(KBD_FR) /* || defined(KBD_DK) correct, but .. */
-num_table:
- .ascii "789-456+1230."
-#else
-num_table:
- .ascii "789-456+1230,"
-#endif
-cur_table:
- .ascii "HA5-DGC+YB623"
-
-/*
- Keypad / 35 B7 Q
- Keypad * (PrtSc) 37 B7 R
- Keypad NumLock 45 ?? P
- Keypad 7 (Home) 47 C7 w
- Keypad 8 (Up arrow) 48 C8 x
- Keypad 9 (PgUp) 49 C9 y
- Keypad - 4A CA S
- Keypad 4 (Left arrow) 4B CB t
- Keypad 5 4C CC u
- Keypad 6 (Right arrow) 4D CD v
- Keypad + 4E CE l
- Keypad 1 (End) 4F CF q
- Keypad 2 (Down arrow) 50 D0 r
- Keypad 3 (PgDn) 51 D1 s
- Keypad 0 (Ins) 52 D2 p
- Keypad . (Del) 53 D3 n
-*/
-
-appl_table:
- .ascii "wxyStuvlqrspn"
-
-/*
- * this routine handles function keys
- */
-func:
- subb $0x3B,%al
- jb end_func
- cmpb $9,%al
- jbe ok_func
- subb $18,%al
- cmpb $10,%al
- jb end_func
- cmpb $11,%al
- ja end_func
-ok_func:
- testb $0x10,_kmode
- jne alt_func
- cmpl $4,%ecx /* check that there is enough room */
- jl end_func
- movl func_table(,%eax,4),%eax
- xorl %ebx,%ebx
- jmp put_queue
-alt_func:
- pushl %eax
- call _change_console
- popl %eax
-end_func:
- ret
-
-/*
- * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc.
- */
-func_table:
- .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b
- .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b
- .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b
-
-#if defined(KBD_FINNISH)
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop}"
- .byte 0,13,0
- .ascii "asdfghjkl|{"
- .byte 0,0
- .ascii "'zxcvbnm,.-"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "!\"#$%&/()=?`"
- .byte 127,9
- .ascii "QWERTYUIOP]^"
- .byte 13,0
- .ascii "ASDFGHJKL\\["
- .byte 0,0
- .ascii "*ZXCVBNM;:_"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\\\0"
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_US)
-
-key_map:
- .byte 0,27
- .ascii "1234567890-="
- .byte 127,9
- .ascii "qwertyuiop[]"
- .byte 13,0
- .ascii "asdfghjkl;'"
- .byte '`,0
- .ascii "\\zxcvbnm,./"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "!@#$%^&*()_+"
- .byte 127,9
- .ascii "QWERTYUIOP{}"
- .byte 13,0
- .ascii "ASDFGHJKL:\""
- .byte '~,0
- .ascii "|ZXCVBNM<>?"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\\\0"
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_UK)
-
-key_map:
- .byte 0,27
- .ascii "1234567890-="
- .byte 127,9
- .ascii "qwertyuiop[]"
- .byte 13,0
- .ascii "asdfghjkl;'"
- .byte '`,0
- .ascii "#zxcvbnm,./"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .ascii "\\"
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "!\"#$%^&*()_+"
- .byte 127,9
- .ascii "QWERTYUIOP{}"
- .byte 13,0
- .ascii "ASDFGHJKL:@"
- .byte '~,0
- .ascii "~ZXCVBNM<>?"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\\\0"
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_GR)
-
-key_map:
- .byte 0,27
- .ascii "1234567890\\'"
- .byte 127,9
- .ascii "qwertzuiop@+"
- .byte 13,0
- .ascii "asdfghjkl[]^"
- .byte 0,'#
- .ascii "yxcvbnm,.-"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "!\"#$%&/()=?`"
- .byte 127,9
- .ascii "QWERTZUIOP\\*"
- .byte 13,0
- .ascii "ASDFGHJKL{}~"
- .byte 0,''
- .ascii "YXCVBNM;:_"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\\\0"
- .byte 0,0
- .byte '@,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_FR)
-
-key_map:
- .byte 0,27
- .ascii "&{\"'(-}_/@)="
- .byte 127,9
- .ascii "azertyuiop^$"
- .byte 13,0
- .ascii "qsdfghjklm|"
- .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */
- .ascii "wxcvbn,;:!"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "1234567890]+"
- .byte 127,9
- .ascii "AZERTYUIOP<>"
- .byte 13,0
- .ascii "QSDFGHJKLM%"
- .byte '~,0,'#
- .ascii "WXCVBN?./\\"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0~#{[|`\\^@]}"
- .byte 0,0
- .byte '@,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '|
- .fill 10,1,0
-
-#elif defined(KBD_DK)
-
-key_map:
- .byte 0,27
- .ascii "1234567890+'"
- .byte 127,9
- .ascii "qwertyuiop"
- .byte 134,0,13,0 /* This is IBM-PC, change it to latin-1 */
- .ascii "asdfghjkl"
- .byte 145,155,0,0
- .ascii "'zxcvbnm,.-"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '<
- .fill 10,1,0
-
-shift_map:
- .byte 0,27
- .ascii "!\"#$%&/()=?`"
- .byte 127,9
- .ascii "QWERTYUIOP"
- .byte 143,94,13,0
- .ascii "ASDFGHJKL"
- .byte 146,157,0,0
- .ascii "*ZXCVBNM;:_"
- .byte 0,'*,0,32 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte '-,0,0,0,'+ /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .byte '>
- .fill 10,1,0
-
-alt_map:
- .byte 0,0
- .ascii "\0@\0$\0\0{[]}\0"
- .byte '|,0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte '~,13,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0
- .byte 0,0,0,0,0,0,0,0,0,0,0
- .byte 0,0,0,0 /* 36-39 */
- .fill 16,1,0 /* 3A-49 */
- .byte 0,0,0,0,0 /* 4A-4E */
- .byte 0,0,0,0,0,0,0 /* 4F-55 */
- .ascii "\\"
- .fill 10,1,0
-
-#else
-#error "KBD-type not defined"
-#endif
-/*
- * do_self handles "normal" keys, ie keys that don't change meaning
- * and which have just one character returns.
- */
-do_self:
- lea alt_map,%ebx
- testb $0x20,_kmode /* alt-gr */
- jne 1f
- lea shift_map,%ebx
- testb $0x0f,_kmode
- jne 1f
- lea key_map,%ebx
-1: movb (%ebx,%eax),%al
- orb %al,%al
- je none
- testb $0x4c,_kmode /* ctrl or caps */
- je 2f
- cmpb $'a,%al
- jb 2f
- cmpb $'},%al
- ja 2f
- subb $32,%al
-2: testb $0x0c,_kmode /* ctrl */
- je 3f
- andb $0x1f,%al
-3: testb $0x10,_kmode /* left alt */
- je 4f
- orb $0x80,%al
-4: andl $0xff,%eax
- xorl %ebx,%ebx
- call put_queue
-none: ret
-
-/*
- * slash and star have routines of their own, as a 'E0h' before
- * the scan code for slash means that the numeric keypad
- * slash was pushed.
- */
-slash: cmpb $1,e0
- jne do_self
- cmpb $1,_kapplic
- jne notmapplic
- movw $'Q,%ax
- jmp applkey
-
-notmapplic:
- movl $'/,%eax
- xorl %ebx,%ebx
- jmp put_queue
-
-star: cmpb $1,_kapplic
- jne do_self
- movw $'R,%ax
- jmp applkey
-
-notsapplic:
- movl $'*,%eax
- xorl %ebx,%ebx
- jmp put_queue
-
-enter: cmpb $1,e0
- jne do_self
- cmpb $1,_kapplic
- jne do_self
- movw $'M,%ax
- jmp applkey
-
-minus: cmpb $1,_kapplic
- jne do_self
- movw $'S,%ax
- jmp applkey
-
-plus: cmpb $1,_kapplic
- jne do_self
- movw $'l,%ax
- jmp applkey
-
-/*
- * This table decides which routine to call when a scan-code has been
- * gotten. Most routines just call do_self, or none, depending if
- * they are make or break.
- */
-key_table:
- .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */
- .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */
- .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */
- .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */
- .long do_self,do_self,do_self,do_self /* 10-13 q w e r */
- .long do_self,do_self,do_self,do_self /* 14-17 t y u i */
- .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */
- .long enter,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */
- .long do_self,do_self,do_self,do_self /* 20-23 d f g h */
- .long do_self,do_self,do_self,do_self /* 24-27 j k l | */
- .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */
- .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */
- .long do_self,do_self,do_self,do_self /* 30-33 b n m , */
- .long do_self,slash,rshift,star /* 34-37 . - rshift * */
- .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */
- .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */
- .long func,func,func,func /* 40-43 f6 f7 f8 f9 */
- .long func,num,scroll,cursor /* 44-47 f10 num scr home */
- .long cursor,cursor,minus,cursor /* 48-4B up pgup - left */
- .long cursor,cursor,plus,cursor /* 4C-4F n5 right + end */
- .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */
- .long none,none,do_self,func /* 54-57 sysreq ? < f11 */
- .long func,none,none,none /* 58-5B f12 ? ? ? */
- .long none,none,none,none /* 5C-5F ? ? ? ? */
- .long none,none,none,none /* 60-63 ? ? ? ? */
- .long none,none,none,none /* 64-67 ? ? ? ? */
- .long none,none,none,none /* 68-6B ? ? ? ? */
- .long none,none,none,none /* 6C-6F ? ? ? ? */
- .long none,none,none,none /* 70-73 ? ? ? ? */
- .long none,none,none,none /* 74-77 ? ? ? ? */
- .long none,none,none,none /* 78-7B ? ? ? ? */
- .long none,none,none,none /* 7C-7F ? ? ? ? */
- .long none,none,none,none /* 80-83 ? br br br */
- .long none,none,none,none /* 84-87 br br br br */
- .long none,none,none,none /* 88-8B br br br br */
- .long none,none,none,none /* 8C-8F br br br br */
- .long none,none,none,none /* 90-93 br br br br */
- .long none,none,none,none /* 94-97 br br br br */
- .long none,none,none,none /* 98-9B br br br br */
- .long none,unctrl,none,none /* 9C-9F br unctrl br br */
- .long none,none,none,none /* A0-A3 br br br br */
- .long none,none,none,none /* A4-A7 br br br br */
- .long none,none,unlshift,none /* A8-AB br br unlshift br */
- .long none,none,none,none /* AC-AF br br br br */
- .long none,none,none,none /* B0-B3 br br br br */
- .long none,none,unrshift,none /* B4-B7 br br unrshift br */
- .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */
- .long none,none,none,none /* BC-BF br br br br */
- .long none,none,none,none /* C0-C3 br br br br */
- .long none,none,none,none /* C4-C7 br br br br */
- .long none,none,none,none /* C8-CB br br br br */
- .long none,none,none,none /* CC-CF br br br br */
- .long none,none,none,none /* D0-D3 br br br br */
- .long none,none,none,none /* D4-D7 br br br br */
- .long none,none,none,none /* D8-DB br ? ? ? */
- .long none,none,none,none /* DC-DF ? ? ? ? */
- .long none,none,none,none /* E0-E3 e0 e1 ? ? */
- .long none,none,none,none /* E4-E7 ? ? ? ? */
- .long none,none,none,none /* E8-EB ? ? ? ? */
- .long none,none,none,none /* EC-EF ? ? ? ? */
- .long none,none,none,none /* F0-F3 ? ? ? ? */
- .long none,none,none,none /* F4-F7 ? ? ? ? */
- .long none,none,none,none /* F8-FB ? ? ? ? */
- .long none,none,none,none /* FC-FF ? ? ? ? */
-
-/*
- * kb_wait waits for the keyboard controller buffer to empty.
- */
-kb_wait:
- pushl %eax
- pushl %ebx
- movl $10000,%ebx
-1: inb $0x64,%al
- testb $0x02,%al
- je 2f
- decl %ebx
- jne 1b
-2: popl %ebx
- popl %eax
- ret
-
-no_idt:
- .long 0,0
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low. We try that for a while,
- * and if it doesn't work, we do some other stupid things.
- */
-_hard_reset_now:
- sti
- movl $100,%ebx
-1: call kb_wait
- movw $0x1234,0x472 /* don't do memory check */
- movb $0xfe,%al /* pulse reset low */
- outb %al,$0x64
- decl %ebx
- jne 1b
- lidt no_idt /* zero-length idt: should triple-fault */
- jmp _hard_reset_now
--- /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 <asm/io.h>
+#include <asm/system.h>
+
+#define LSHIFT 0x01
+#define RSHIFT 0x02
+#define LCTRL 0x04
+#define RCTRL 0x08
+#define ALT 0x10
+#define ALTGR 0x20
+#define CAPS 0x40
+#define CAPSDOWN 0x80
+
+#define SCRLED 0x01
+#define NUMLED 0x02
+#define CAPSLED 0x04
+
+#define NO_META_BIT 0x80
+
+unsigned char kapplic = 0;
+unsigned char kmode = 0;
+unsigned char kleds = NUMLED;
+unsigned char ke0 = 0;
+unsigned char kraw = 0;
+unsigned char kbd_flags = KBDFLAGS;
+
+extern void do_keyboard_interrupt(void);
+extern void ctrl_alt_del(void);
+extern void show_mem(void), show_state(void);
+extern void change_console(unsigned int new_console);
+extern struct tty_queue *table_list[];
+
+typedef void (*fptr)(int);
+
+static unsigned char old_leds = 2;
+static int diacr = -1;
+static int npadch = 0;
+fptr key_table[];
+
+static void put_queue(int);
+void set_leds(void);
+static void applkey(int);
+static void cur(int);
+static void kb_wait(void), kb_ack(void);
+static unsigned int handle_diacr(unsigned int);
+
+void do_keyboard(void)
+{
+ unsigned char scancode, x;
+
+ scancode=inb_p(0x60);
+ x=inb_p(0x61);
+ outb_p(x|0x80, 0x61);
+ outb_p(x&0x7f, 0x61);
+ outb(0x20, 0x20);
+ sti();
+
+ if (kraw) {
+ put_queue(scancode);
+ do_keyboard_interrupt();
+ } else if (scancode == 0xe0)
+ ke0 = 1;
+ else if (scancode == 0xe1)
+ ke0 = 2;
+ else {
+ key_table[scancode](scancode);
+ do_keyboard_interrupt();
+ ke0 = 0;
+ }
+}
+
+static void put_queue(int ch)
+{
+ register struct tty_queue *qp = table_list[0];
+ unsigned long new_head;
+
+ qp->buf[qp->head]=ch;
+ if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1)) != qp->tail)
+ qp->head=new_head;
+ if (qp->proc_list != NULL)
+ qp->proc_list->state=0;
+}
+
+static void puts_queue(char *cp)
+{
+ register struct tty_queue *qp = table_list[0];
+ unsigned long new_head;
+ char ch;
+
+ while (ch=*cp++) {
+ qp->buf[qp->head]=ch;
+ if ((new_head=(qp->head+1)&(TTY_BUF_SIZE-1))
+ != qp->tail)
+ qp->head=new_head;
+ }
+ if (qp->proc_list != NULL)
+ qp->proc_list->state=0;
+}
+
+static void ctrl(int sc)
+{
+ if (ke0)
+ kmode|=RCTRL;
+ else
+ kmode|=LCTRL;
+}
+
+static void alt(int sc)
+{
+ if (ke0)
+ kmode|=ALTGR;
+ else
+ kmode|=ALT;
+}
+
+static void unctrl(int sc)
+{
+ if (ke0)
+ kmode&=(~RCTRL);
+ else
+ kmode&=(~LCTRL);
+}
+
+static void unalt(int sc)
+{
+ if (ke0)
+ kmode&=(~ALTGR);
+ else {
+ kmode&=(~ALT);
+ if (npadch != 0) {
+ put_queue(npadch);
+ npadch=0;
+ }
+ }
+}
+
+static void lshift(int sc)
+{
+ kmode|=LSHIFT;
+}
+
+static void unlshift(int sc)
+{
+ kmode&=(~LSHIFT);
+}
+
+static void rshift(int sc)
+{
+ kmode|=RSHIFT;
+}
+
+static void unrshift(int sc)
+{
+ kmode&=(~RSHIFT);
+}
+
+static void caps(int sc)
+{
+ if (!(kmode&CAPSDOWN)) {
+ kleds^=CAPSLED;
+ kmode^=CAPS;
+ kmode|=CAPSDOWN;
+ set_leds();
+ }
+}
+
+void set_leds(void)
+{
+ if (kleds != old_leds) {
+ old_leds=kleds;
+ kb_wait();
+ outb(0xed, 0x60); /* set leds command */
+ kb_ack();
+ kb_wait();
+ outb(kleds, 0x60);
+ kb_ack();
+ }
+}
+
+static void uncaps(int sc)
+{
+ kmode&=(~CAPSDOWN);
+}
+
+static void scroll(int sc)
+{
+ if (kmode&(LSHIFT|RSHIFT))
+ show_mem();
+ else
+ show_state();
+ kleds^=SCRLED;
+ set_leds();
+}
+
+static void num(int sc)
+{
+ if (kapplic)
+ applkey(0x50);
+ else {
+ kleds^=NUMLED;
+ set_leds();
+ }
+}
+
+static void applkey(int key)
+{
+ char buf[] = { 0x1b, 0x4f, 0x00, 0x00 };
+
+ buf[2]=key;
+ puts_queue(buf);
+}
+
+
+#if defined KBD_FINNISH
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '+', '\'', 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '}', 0, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', '|',
+ '{', 0, 0, '\'', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '\"', '#', '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', ']', '^', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', '\\',
+ '[', 0, 0, '*', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 163, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_FINNISH_LATIN1
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '+', 180, 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', 229, 168, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246,
+ 228, 167, 0, '\'', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '"', '#', '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', 197, '^', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 214,
+ 196, 189, 0, '*', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 163, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_US
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '"', '~', '0', '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 0, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_UK
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', 0, '#', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '\\', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '"', 163, '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '@', '~', '0', '~', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 0, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_GR
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '\\', '\'', 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
+ 'o', 'p', '@', '+', 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', '[',
+ ']', '^', 0, '#', 'y', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '"', '#', '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I',
+ 'O', 'P', '\\', '*', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', '{',
+ '}', '~', 0, '\'', 'Y', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 0, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ '@', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_GR_LATIN1
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', 223, 180, 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i',
+ 'o', 'p', 252, '+', 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 246,
+ 228, 94, 0, '#', 'y', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '"', 167, '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I',
+ 'O', 'P', 220, '*', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 214,
+ 196, 176, 0, '\'', 'Y', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, 178, 179, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ '@', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 181, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_FR
+
+static unsigned char key_map[] = {
+ 0, 27, '&', '{', '"', '\'', '(', '-',
+ '}', '_', '/', '@', ')', '=', 127, 9,
+ 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '^', '$', 13, 0, 'q', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
+ '|', '`', 0, 42, 'w', 'x', 'c', 'v',
+ 'b', 'n', ',', ';', ':', '!', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', ']', '+', 127, 9,
+ 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '<', '>', 13, 0, 'Q', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
+ '%', '~', 0, '#', 'W', 'X', 'C', 'V',
+ 'B', 'N', '?', '.', '/', '\\', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '~', '#', '{', '[', '|',
+ '`', '\\', '^', '@', ']', '}', 0, 0,
+ '@', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_FR_LATIN1
+
+static unsigned char key_map[] = {
+ 0, 27, '&', 233, '"', '\'', '(', '-',
+ 232, '_', 231, 224, ')', '=', 127, 9,
+ 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '^', '$', 13, 0, 'q', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
+ 249, 178, 0, 42, 'w', 'x', 'c', 'v',
+ 'b', 'n', ',', ';', ':', '!', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', 176, '+', 127, 9,
+ 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', 168, 163, 13, 0, 'Q', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
+ '%', 0, 0, 181, 'W', 'X', 'C', 'V',
+ 'B', 'N', '?', '.', '/', 167, 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '~', '#', '{', '[', '|',
+ '`', '\\', '^', '@', ']', '}', 0, 0,
+ '@', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 164, 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_DK
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '+', '\'', 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', 229, 0, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 230,
+ 162, 0, 0, '\'', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '\"', '#', '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', 197, '^', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 198,
+ 165, 0, 0, '*', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 163, '$', 0, 0,
+ '{', '[', ']', '}', 0, '|', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_DK_LATIN1
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '+', 180, 127, 9,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', 229, 168, 13, 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 230,
+ 162, 189, 0, '\'', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '-', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '\"', '#', '$', '%', '&',
+ '/', '(', ')', '=', '?', '`', 127, 9,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', 197, '^', 13, 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 198,
+ 165, 167, 0, '*', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', ';', ':', '_', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '>', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 163, '$', 0, 0,
+ '{', '[', ']', '}', 0, '|', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '\\', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#elif defined KBD_DVORAK
+
+static unsigned char key_map[] = {
+ 0, 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '\\', '=', 127, 9,
+ '\'', ',', '.', 'p', 'y', 'f', 'g', 'c',
+ 'r', 'l', '/', ']', 13, 0, 'a', 'o',
+ 'e', 'u', 'i', 'd', 'h', 't', 'n', 's',
+ '-', '`', 0, '[', ';', 'q', 'j', 'k',
+ 'x', 'b', 'm', 'w', 'v', 'z', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char shift_map[] = {
+ 0, 27, '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '|', '+', 127, 9,
+ '"', '<', '>', 'P', 'Y', 'F', 'G', 'C',
+ 'R', 'L', '?', '}', 13, 0, 'A', 'O',
+ 'E', 'U', 'I', 'D', 'H', 'T', 'N', 'S',
+ '_', '~', 0, '{', ':', 'Q', 'J', 'K',
+ 'X', 'B', 'M', 'W', 'V', 'Z', 0, '*',
+ 0, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '-', 0, 0, 0, '+', 0,
+ 0, 0, 0, 0, 0, 0, '<', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+static unsigned char alt_map[] = {
+ 0, 0, 0, '@', 0, '$', 0, 0,
+ '{', '[', ']', '}', '\\', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, '~', 13, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '|', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0 };
+
+#else
+#error "KBD-type not defined"
+#endif
+
+static void do_self(int sc)
+{
+ unsigned char ch;
+
+ if (kmode&ALTGR)
+ ch=alt_map[sc];
+ else if (kmode&(LSHIFT|RSHIFT|LCTRL|RCTRL))
+ ch=shift_map[sc];
+ else
+ ch=key_map[sc];
+
+ if (ch == 0)
+ return;
+
+ if ((ch=handle_diacr(ch)) == 0)
+ return;
+
+ if (kmode&(LCTRL|RCTRL|CAPS)) /* ctrl or caps */
+ if ((ch>='a' && ch <='z') || (ch>=224 && ch<=254))
+ ch -= 32;
+ if (kmode&(LCTRL|RCTRL)) /* ctrl */
+ ch &= 0x1f;
+
+ if (kmode&ALT)
+ if (kbd_flags&NO_META_BIT) {
+ put_queue('\033');
+ put_queue(ch);
+ } else
+ put_queue(ch|0x80);
+ else
+ put_queue(ch);
+}
+
+unsigned char accent_table[5][64] = {
+ " \300BCD\310FGH\314JKLMN\322PQRST\331VWXYZ[\\]^_"
+ "`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~", /* accent grave */
+
+ " \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_"
+ "`\341bcd\351fgh\355jklmn\363pqrst\372vwxyz{|}~", /* accent acute */
+
+ " \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
+ "`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~", /* circumflex */
+
+ " \303BCDEFGHIJKLMN\325PQRSTUVWXYZ[\\]^_"
+ "`\343bcdefghijklm\361\365pqrstuvwxyz{|}~", /* tilde */
+
+ " \304BCD\313FGH\316JKLMN\326PQRST\334VWXYZ[\\]^_"
+ "`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
+};
+
+
+/*
+ * Check if dead key pressed. If so, check if same key pressed twice;
+ * in that case return the char, otherwise store char and return 0.
+ * If dead key not pressed, check if accented character pending. If
+ * not: return the char, otherwise check if char is a space. If it is
+ * a space return the diacritical. Else combine char with diacritical
+ * mark and return.
+ */
+
+unsigned int handle_diacr(unsigned int ch)
+{
+ static unsigned char diacr_table[] =
+ {'`', 180, '^', '~', 168, 0}; /* Must end with 0 */
+ int i;
+
+ for(i=0; diacr_table[i]; i++)
+ if (ch==diacr_table[i] && ((1<<i)&kbd_flags)) {
+ if (diacr == i) {
+ diacr=-1;
+ return ch; /* pressed twice */
+ } else {
+ diacr=i; /* key is dead */
+ return 0;
+ }
+ }
+ if (diacr == -1)
+ return ch;
+ else if (ch == ' ') {
+ ch=diacr_table[diacr];
+ diacr=-1;
+ return ch;
+ } else if (ch<64 || ch>122) {
+ diacr=-1;
+ return ch;
+ } else {
+ ch=accent_table[diacr][ch-64];
+ diacr=-1;
+ return ch;
+ }
+}
+
+
+#if defined KBD_FR
+static unsigned char num_table[] = "789-456+1230.";
+#else
+static unsigned char num_table[] = "789-456+1230,";
+#endif
+
+static unsigned char cur_table[] = "HA5-DGC+YB623";
+static unsigned int pad_table[] = { 7,8,9,0,4,5,6,0,1,2,3,0,0 };
+
+/*
+ Keypad / 35 B7 Q
+ Keypad * (PrtSc) 37 B7 R
+ Keypad NumLock 45 ?? P
+ Keypad 7 (Home) 47 C7 w
+ Keypad 8 (Up arrow) 48 C8 x
+ Keypad 9 (PgUp) 49 C9 y
+ Keypad - 4A CA S
+ Keypad 4 (Left arrow) 4B CB t
+ Keypad 5 4C CC u
+ Keypad 6 (Right arrow) 4D CD v
+ Keypad + 4E CE l
+ Keypad 1 (End) 4F CF q
+ Keypad 2 (Down arrow) 50 D0 r
+ Keypad 3 (PgDn) 51 D1 s
+ Keypad 0 (Ins) 52 D2 p
+ Keypad . (Del) 53 D3 n
+*/
+
+static unsigned char appl_table[] = "wxyStuvlqrspn";
+
+static char *func_table[] = {
+ "\033[[A", "\033[[B", "\033[[C", "\033[[D",
+ "\033[[E", "\033[[F", "\033[[G", "\033[[H",
+ "\033[[I", "\033[[J", "\033[[K", "\033[[L"
+};
+
+
+static void cursor(int sc)
+{
+ if (sc < 0x47 || sc > 0x53)
+ return;
+ sc-=0x47;
+ if (sc == 12 && (kmode&(LCTRL|RCTRL)) && (kmode&(ALT|ALTGR))) {
+ ctrl_alt_del();
+ return;
+ }
+ if (ke0 == 1) {
+ cur(sc);
+ return;
+ }
+
+ if ((kmode&ALT) && sc!=12) { /* Alt-numpad */
+ npadch=npadch*10+pad_table[sc];
+ return;
+ }
+
+ if (kapplic && !(kmode&(LSHIFT|RSHIFT))) { /* shift forces cursor */
+ applkey(appl_table[sc]);
+ return;
+ }
+
+ if (kleds&NUMLED) {
+ put_queue(num_table[sc]);
+ } else
+ cur(sc);
+}
+
+static void cur(int sc)
+{
+ char buf[] = { 0x1b, '[', 0, 0, 0 }; /* must not be static */
+
+ buf[2]=cur_table[sc];
+ if (buf[2] < '9')
+ buf[3]='~';
+ if (kapplic)
+ buf[1]='O';
+ puts_queue(buf);
+}
+
+static void func(int sc)
+{
+ if (sc < 0x3b)
+ return;
+ sc-=0x3b;
+ if (sc > 9) {
+ sc-=18;
+ if (sc < 10 || sc > 11)
+ return;
+ }
+ if (kmode&ALT)
+ change_console(sc);
+ else
+ puts_queue(func_table[sc]);
+}
+
+
+static void slash(int sc)
+{
+ if (ke0 != 1)
+ do_self(sc);
+ else if (kapplic)
+ applkey('Q');
+ else
+ put_queue('/');
+}
+
+static void star(int sc)
+{
+ if (kapplic)
+ applkey('R');
+ else
+ do_self(sc);
+}
+
+static void enter(int sc)
+{
+ if (ke0 != 1)
+ do_self(sc);
+ else if (kapplic)
+ applkey('M');
+ else
+ do_self(sc);
+}
+
+static void minus(int sc)
+{
+ if (kapplic)
+ applkey('S');
+ else
+ do_self(sc);
+}
+
+static void plus(int sc)
+{
+ if (kapplic)
+ applkey('l');
+ else
+ do_self(sc);
+}
+
+
+static void none(int sc)
+{
+}
+
+
+/*
+ * kb_wait waits for the keyboard controller buffer to empty.
+ */
+
+static void kb_wait(void)
+{
+ int i;
+
+ for (i=0; i<0x10000; i++)
+ if ((inb(0x64)&0x02) == 0)
+ break;
+}
+
+/*
+ * kb_ack waits for 0xfa to appear in port 0x60
+ *
+ * Suggested by Bruce Evans
+ * Added by Niels Skou Olsen [NSO]
+ * April 21, 1992
+ *
+ * Heavily inspired by kb_wait :-)
+ * I don't know how much waiting actually is required,
+ * but this seems to work
+ */
+
+void kb_ack(void)
+{
+ int i;
+
+ for(i=0; i<0x10000; i++)
+ if (inb(0x64) == 0xfa)
+ break;
+}
+
+long no_idt[2] = {0, 0};
+
+/*
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ */
+void hard_reset_now(void)
+{
+ int i;
+
+ sti();
+ for (;;) {
+ for (i=0; i<100; i++) {
+ kb_wait();
+ *((unsigned short *)0x472)=0x1234;
+ outb(0xfe,0x64); /* pulse reset low */
+ }
+ __asm__("\tlidt _no_idt"::);
+ }
+}
+
+
+static fptr key_table[] = {
+ none,do_self,do_self,do_self, /* 00-03 s0 esc 1 2 */
+ do_self,do_self,do_self,do_self, /* 04-07 3 4 5 6 */
+ do_self,do_self,do_self,do_self, /* 08-0B 7 8 9 0 */
+ do_self,do_self,do_self,do_self, /* 0C-0F + ' bs tab */
+ do_self,do_self,do_self,do_self, /* 10-13 q w e r */
+ do_self,do_self,do_self,do_self, /* 14-17 t y u i */
+ do_self,do_self,do_self,do_self, /* 18-1B o p } ^ */
+ enter,ctrl,do_self,do_self, /* 1C-1F enter ctrl a s */
+ do_self,do_self,do_self,do_self, /* 20-23 d f g h */
+ do_self,do_self,do_self,do_self, /* 24-27 j k l | */
+ do_self,do_self,lshift,do_self, /* 28-2B { para lshift , */
+ do_self,do_self,do_self,do_self, /* 2C-2F z x c v */
+ do_self,do_self,do_self,do_self, /* 30-33 b n m , */
+ do_self,slash,rshift,star, /* 34-37 . - rshift * */
+ alt,do_self,caps,func, /* 38-3B alt sp caps f1 */
+ func,func,func,func, /* 3C-3F f2 f3 f4 f5 */
+ func,func,func,func, /* 40-43 f6 f7 f8 f9 */
+ func,num,scroll,cursor, /* 44-47 f10 num scr home */
+ cursor,cursor,minus,cursor, /* 48-4B up pgup - left */
+ cursor,cursor,plus,cursor, /* 4C-4F n5 right + end */
+ cursor,cursor,cursor,cursor, /* 50-53 dn pgdn ins del */
+ none,none,do_self,func, /* 54-57 sysreq ? < f11 */
+ func,none,none,none, /* 58-5B f12 ? ? ? */
+ none,none,none,none, /* 5C-5F ? ? ? ? */
+ none,none,none,none, /* 60-63 ? ? ? ? */
+ none,none,none,none, /* 64-67 ? ? ? ? */
+ none,none,none,none, /* 68-6B ? ? ? ? */
+ none,none,none,none, /* 6C-6F ? ? ? ? */
+ none,none,none,none, /* 70-73 ? ? ? ? */
+ none,none,none,none, /* 74-77 ? ? ? ? */
+ none,none,none,none, /* 78-7B ? ? ? ? */
+ none,none,none,none, /* 7C-7F ? ? ? ? */
+ none,none,none,none, /* 80-83 ? br br br */
+ none,none,none,none, /* 84-87 br br br br */
+ none,none,none,none, /* 88-8B br br br br */
+ none,none,none,none, /* 8C-8F br br br br */
+ none,none,none,none, /* 90-93 br br br br */
+ none,none,none,none, /* 94-97 br br br br */
+ none,none,none,none, /* 98-9B br br br br */
+ none,unctrl,none,none, /* 9C-9F br unctrl br br */
+ none,none,none,none, /* A0-A3 br br br br */
+ none,none,none,none, /* A4-A7 br br br br */
+ none,none,unlshift,none, /* A8-AB br br unlshift br */
+ none,none,none,none, /* AC-AF br br br br */
+ none,none,none,none, /* B0-B3 br br br br */
+ none,none,unrshift,none, /* B4-B7 br br unrshift br */
+ unalt,none,uncaps,none, /* B8-BB unalt br uncaps br */
+ none,none,none,none, /* BC-BF br br br br */
+ none,none,none,none, /* C0-C3 br br br br */
+ none,none,none,none, /* C4-C7 br br br br */
+ none,none,none,none, /* C8-CB br br br br */
+ none,none,none,none, /* CC-CF br br br br */
+ none,none,none,none, /* D0-D3 br br br br */
+ none,none,none,none, /* D4-D7 br br br br */
+ none,none,none,none, /* D8-DB br ? ? ? */
+ none,none,none,none, /* DC-DF ? ? ? ? */
+ none,none,none,none, /* E0-E3 e0 e1 ? ? */
+ none,none,none,none, /* E4-E7 ? ? ? ? */
+ none,none,none,none, /* E8-EB ? ? ? ? */
+ none,none,none,none, /* EC-EF ? ? ? ? */
+ none,none,none,none, /* F0-F3 ? ? ? ? */
+ none,none,none,none, /* F4-F7 ? ? ? ? */
+ none,none,none,none, /* F8-FB ? ? ? ? */
+ none,none,none,none /* FC-FF ? ? ? ? */
+};
james_r_wiegand Exp james_r_wiegand $
*/
+/*
+ * Edited by Linus - cleaner interface etc. Still not using interrupts, so
+ * it eats more resources than necessary, but it was easy to code this way...
+ */
+
+#include <linux/sched.h>
#define __LP_C__
#include <linux/lp.h>
-#include <checkpoint.h>
-
-int lp_reset(int minor)
+static int lp_reset(int minor)
{
int testvalue;
return LP_S(minor);
}
-void lp_init(void)
-{
- int offset = 0;
- unsigned int testvalue = 0;
- int count = 0;
-
- /* take on all known port values */
- for (offset = 0; offset < LP_NO; offset++) {
- /* write to port & read back to check */
- outb( LP_DUMMY, LP_B(offset));
- for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
- ;
- testvalue = inb(LP_B(offset));
- if (testvalue != 255) {
- LP_F(offset) |= LP_EXIST;
- lp_reset(offset);
- printk("lp_init: lp%d exists (%d)\n", offset, testvalue);
- count++;
- }
- }
- if (count == 0)
- printk("lp_init: no lp devices found\n");
-}
-
-int lp_char(char lpchar, int minor)
+static int lp_char(char lpchar, int minor)
{
int retval = 0;
unsigned long count = 0;
return LP_S(minor);
}
-int lp_write(unsigned minor, char *buf, int count)
+static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
{
int retval;
- int loop;
- int tcount;
+ unsigned int minor = MINOR(inode->i_rdev);
char c, *temp = buf;
- if (minor > LP_NO - 1)
- return -ENODEV;
- if ((LP_F(minor) & LP_EXIST) == 0)
- return -ENODEV;
-
-/* if we aren't the "owner task", check if the old owner has died... */
- if (LP_T(minor) != current->pid && (LP_F(minor) & LP_BUSY)) {
- for(tcount = 0; tcount < NR_TASKS; tcount++) {
- if (!task[tcount])
- continue;
- if (task[tcount]->state == TASK_ZOMBIE)
- continue;
- if (task[tcount]->pid == LP_T(minor)) {
- tcount = -1;
- break;
- }
- }
- if (tcount == -1)
- return -EBUSY;
- }
-
- LP_T(minor) = current->pid;
- LP_F(minor) |= LP_BUSY;
- LP_R(minor) = count;
temp = buf;
-
- for (loop = 0 ; loop < count ; loop++, temp++) {
- c = get_fs_byte(temp);
+ while (count > 0) {
+ c = get_fs_byte(temp++);
retval = lp_char(c, minor);
- LP_R(minor)--;
+ count--;
if (retval & LP_POUTPA) {
LP_F(minor) |= LP_NOPA;
- return loop?loop:-ENOSPC;
+ return temp-buf?temp-buf:-ENOSPC;
} else
LP_F(minor) &= ~LP_NOPA;
if (!(retval & LP_PSELECD)) {
LP_F(minor) &= ~LP_SELEC;
- return loop?loop:-EFAULT;
+ return temp-buf?temp-buf:-EFAULT;
} else
LP_F(minor) &= ~LP_SELEC;
/* not offline or out of paper. on fire? */
if (!(retval & LP_PERRORP)) {
LP_F(minor) |= LP_ERR;
- return loop?loop:-EIO;
+ return temp-buf?temp-buf:-EIO;
} else
LP_F(minor) &= ~LP_SELEC;
}
- return count;
+ return temp-buf;
+}
+
+static int lp_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+ return -EINVAL;
+}
+
+static int lp_lseek(struct inode * inode, struct file * file, off_t offset, int origin)
+{
+ return -EINVAL;
+}
+
+static int lp_open(struct inode * inode, struct file * file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ if (minor >= LP_NO)
+ return -ENODEV;
+ if ((LP_F(minor) & LP_EXIST) == 0)
+ return -ENODEV;
+ if (LP_F(minor) & LP_BUSY)
+ return -EBUSY;
+ LP_F(minor) |= LP_BUSY;
+ return 0;
+}
+
+static void lp_release(struct inode * inode, struct file * file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ LP_F(minor) &= ~LP_BUSY;
+}
+
+static struct file_operations lp_fops = {
+ lp_lseek,
+ lp_read,
+ lp_write,
+ NULL, /* lp_readdir */
+ NULL, /* lp_select */
+ NULL, /* lp_ioctl */
+ lp_open,
+ lp_release
+};
+
+void lp_init(void)
+{
+ int offset = 0;
+ unsigned int testvalue = 0;
+ int count = 0;
+
+ chrdev_fops[6] = &lp_fops;
+ /* take on all known port values */
+ for (offset = 0; offset < LP_NO; offset++) {
+ /* write to port & read back to check */
+ outb( LP_DUMMY, LP_B(offset));
+ for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
+ ;
+ testvalue = inb(LP_B(offset));
+ if (testvalue != 255) {
+ LP_F(offset) |= LP_EXIST;
+ lp_reset(offset);
+ printk("lp_init: lp%d exists (%d)\n", offset, testvalue);
+ count++;
+ }
+ }
+ if (count == 0)
+ printk("lp_init: no lp devices found\n");
}
--- /dev/null
+/*
+ * linux/kernel/chr_drv/mem.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
+{
+ return -EIO;
+}
+
+static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
+{
+ return -EIO;
+}
+
+static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long addr;
+ char *tmp;
+ unsigned long pde, pte, page;
+ int i;
+
+ if (count < 0)
+ return -EINVAL;
+ addr = file->f_pos;
+ tmp = buf;
+ while (count > 0) {
+ pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
+ if (!((pte = *((unsigned long *) pde)) & 1))
+ break;
+ pte &= 0xfffff000;
+ pte += (addr >> 10) & 0xffc;
+ if (((page = *((unsigned long *) pte)) & 1) == 0)
+ break;
+/*
+ if ((page & 2) == 0)
+ un_wp_page((unsigned long *) pte);
+*/
+ page &= 0xfffff000;
+ page += addr & 0xfff;
+ i = 4096-(addr & 0xfff);
+ if (i > count)
+ i = count;
+ memcpy_tofs(tmp,(void *) page,i);
+ addr += i;
+ tmp += i;
+ count -= i;
+ }
+ file->f_pos = addr;
+ return tmp-buf;
+}
+
+static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long addr;
+ char *tmp;
+ unsigned long pde, pte, page;
+ int i;
+
+ if (count < 0)
+ return -EINVAL;
+ addr = file->f_pos;
+ tmp = buf;
+ while (count > 0) {
+ pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
+ if (!((pte = *((unsigned long *) pde)) & 1))
+ break;
+ pte &= 0xfffff000;
+ pte += (addr >> 10) & 0xffc;
+ if (((page = *((unsigned long *) pte)) & 1) == 0)
+ break;
+ if ((page & 2) == 0)
+ un_wp_page((unsigned long *) pte);
+ page &= 0xfffff000;
+ page += addr & 0xfff;
+ i = 4096-(addr & 0xfff);
+ if (i > count)
+ i = count;
+ memcpy_fromfs((void *) page,tmp,i);
+ addr += i;
+ tmp += i;
+ count -= i;
+ }
+ file->f_pos = addr;
+ return tmp-buf;
+}
+
+static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long p = file->f_pos;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= HIGH_MEMORY)
+ return 0;
+ if (count > HIGH_MEMORY - p)
+ count = HIGH_MEMORY - p;
+ memcpy_tofs(buf,(void *) p,count);
+ file->f_pos += count;
+ return count;
+}
+
+static int write_kmem(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long p = file->f_pos;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= HIGH_MEMORY)
+ return 0;
+ if (count > HIGH_MEMORY - p)
+ count = HIGH_MEMORY - p;
+ memcpy_fromfs((void *) p,buf,count);
+ file->f_pos += count;
+ return count;
+}
+
+static int read_port(struct inode * inode,struct file * file,char * buf, int count)
+{
+ unsigned int i = file->f_pos;
+ char * tmp = buf;
+
+ while (count-- > 0 && i < 65536) {
+ put_fs_byte(inb(i),tmp);
+ i++;
+ tmp++;
+ }
+ file->f_pos = i;
+ return tmp-buf;
+}
+
+static int write_port(struct inode * inode,struct file * file,char * buf, int count)
+{
+ unsigned int i = file->f_pos;
+ char * tmp = buf;
+
+ while (count-- > 0 && i < 65536) {
+ outb(get_fs_byte(tmp),i);
+ i++;
+ tmp++;
+ }
+ file->f_pos = i;
+ return tmp-buf;
+}
+
+/*
+ * The memory devices use the full 32 bits of the offset, and so we cannot
+ * check against negative addresses: they are ok. The return value is weird,
+ * though, in that case (0).
+ *
+ * also note that seeking relative to the "end of file" isn't supported:
+ * it has no meaning, so it returns -EINVAL.
+ */
+static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+ default:
+ return -EINVAL;
+ }
+ if (file->f_pos < 0)
+ return 0;
+ return file->f_pos;
+}
+
+static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+ switch (MINOR(inode->i_rdev)) {
+ case 0:
+ return read_ram(inode,file,buf,count);
+ case 1:
+ return read_mem(inode,file,buf,count);
+ case 2:
+ return read_kmem(inode,file,buf,count);
+ case 3:
+ return 0; /* /dev/null */
+ case 4:
+ return read_port(inode,file,buf,count);
+ default:
+ return -ENODEV;
+ }
+}
+
+static int mem_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+ switch (MINOR(inode->i_rdev)) {
+ case 0:
+ return write_ram(inode,file,buf,count);
+ case 1:
+ return write_mem(inode,file,buf,count);
+ case 2:
+ return write_kmem(inode,file,buf,count);
+ case 3:
+ return count; /* /dev/null */
+ case 4:
+ return write_port(inode,file,buf,count);
+ default:
+ return -ENODEV;
+ }
+}
+
+static struct file_operations mem_fops = {
+ mem_lseek,
+ mem_read,
+ mem_write,
+ NULL, /* mem_readdir */
+ NULL, /* mem_select */
+ NULL, /* mem_ioctl */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
+void chr_dev_init(void)
+{
+ chrdev_fops[1] = &mem_fops;
+ tty_init();
+ lp_init();
+}
* void spty_write(struct tty_struct * queue);
*/
-#include <linux/tty.h>
#include <linux/sched.h>
+#include <linux/tty.h>
+
#include <asm/system.h>
#include <asm/io.h>
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
- char c;
+ int c;
while (!from->stopped && !EMPTY(from->write_q)) {
if (FULL(to->read_q)) {
TTY_READ_FLUSH(to);
continue;
}
- GETCH(from->write_q,c);
+ c = GETCH(from->write_q);
PUTCH(c,to->read_q);
if (current->signal & ~current->blocked)
break;
+++ /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
* and all interrupts pertaining to serial IO.
*/
-#include <linux/tty.h>
+#include <signal.h>
+
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/tty.h>
+
#include <asm/system.h>
#include <asm/io.h>
-#define WAKEUP_CHARS (TTY_BUF_SIZE/4)
+#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
+
+extern void IRQ3_interrupt(void);
+extern void IRQ4_interrupt(void);
+
+static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+ unsigned char status = inb(port+6);
+
+ if ((status & 0x88) == 0x08 && tty->pgrp > 0)
+ kill_pg(tty->pgrp,SIGHUP,1);
+}
+
+/*
+ * There are several races here: we avoid most of them by disabling timer_active
+ * for the crucial part of the process.. That's a good idea anyway.
+ *
+ * The problem is that we have to output characters /both/ from interrupts
+ * and from the normal write: the latter to be sure the interrupts start up
+ * again. With serial lines, the interrupts can happen so often that the
+ * races actually are noticeable.
+ */
+static void send_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+ int c;
+
+#define TIMER ((SER1_TIMEOUT-1)+line)
+ timer_active &= ~(1 << TIMER);
+ if ((c = GETCH(tty->write_q)) < 0)
+ return;
+ outb(c,port);
+ timer_table[TIMER].expires = jiffies + 10;
+ timer_active |= 1 << TIMER;
+ if (LEFT(tty->write_q) > WAKEUP_CHARS)
+ wake_up(&tty->write_q->proc_list);
+#undef TIMER
+}
+
+static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+ if (FULL(tty->read_q))
+ return;
+ PUTCH(inb(port),tty->read_q);
+ timer_active |= (1<<(SER1_TIMER-1))<<line;
+}
+
+static void line_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
+{
+ unsigned char status = inb(port+5);
+
+/* printk("line status: %02x\n",status); */
+}
+
+static void (*jmp_table[4])(unsigned,unsigned,struct tty_struct *) = {
+ modem_status_intr,
+ send_intr,
+ receive_intr,
+ line_status_intr
+};
+
+static void check_tty(unsigned line,struct tty_struct * tty)
+{
+ unsigned short port;
+ unsigned char ident;
+
+ if (!(port = tty->read_q->data))
+ return;
+ while (1) {
+ ident = inb(port+2);
+ if (ident & 1)
+ return;
+ ident >>= 1;
+ if (ident > 3)
+ return;
+ jmp_table[ident](line,port,tty);
+ }
+}
+
+/*
+ * IRQ3 normally handles com2 and com4
+ */
+void do_IRQ3(void)
+{
+ check_tty(2,tty_table+65);
+ check_tty(4,tty_table+67);
+}
-extern void rs1_interrupt(void);
-extern void rs2_interrupt(void);
+/*
+ * IRQ4 normally handles com1 and com2
+ */
+void do_IRQ4(void)
+{
+ check_tty(1,tty_table+64);
+ check_tty(3,tty_table+66);
+}
static void com1_timer(void)
{
TTY_READ_FLUSH(tty_table+67);
}
-static inline void do_rs_write(unsigned int port)
+/*
+ * Again, we disable interrupts to be sure there aren't any races:
+ * see send_intr for details.
+ */
+static inline void do_rs_write(unsigned line, struct tty_struct * tty)
{
- char c;
+ int port;
-#define TTY (tty_table[64+port].write_q)
-#define TIMER (SER1_TIMEOUT+port)
+#define TIMER ((SER1_TIMEOUT-1)+line)
+ if (!tty || !tty->write_q || EMPTY(tty->write_q))
+ return;
+ if (!(port = tty->write_q->data))
+ return;
cli();
- if (!EMPTY(TTY)) {
- outb_p(inb_p(TTY->data+1)|0x02,TTY->data+1);
- if (inb(TTY->data+5) & 0x20) {
- GETCH(TTY,c);
- outb(c,TTY->data);
- }
- timer_table[TIMER].expires = jiffies + 50;
+ if (inb_p(port+5) & 0x20)
+ send_intr(line,port,tty);
+ else {
+ timer_table[TIMER].expires = jiffies + 10;
timer_active |= 1 << TIMER;
- } else
- timer_active &= ~(1 << TIMER);
+ }
sti();
#undef TIMER
-#undef TTY
}
static void com1_timeout(void)
{
- do_rs_write(0);
+ do_rs_write(1,tty_table+64);
}
static void com2_timeout(void)
{
- do_rs_write(1);
+ do_rs_write(2,tty_table+65);
}
static void com3_timeout(void)
{
- do_rs_write(2);
+ do_rs_write(3,tty_table+66);
}
static void com4_timeout(void)
{
- do_rs_write(3);
+ do_rs_write(4,tty_table+67);
}
static void init(int port)
outb_p(0x00,port+1); /* MS of divisor */
outb_p(0x03,port+3); /* reset DLAB */
outb_p(0x00,port+4); /* reset DTR,RTS, OUT_2 */
- outb_p(0x0d,port+1); /* enable all intrs but writes */
+ outb_p(0x0f,port+1); /* enable all intrs */
(void)inb(port); /* read data port to reset things (?) */
}
* this routine enables interrupts on 'line', and disables them on
* 'line ^ 2', as they share the same IRQ. Braindamaged AT hardware.
*/
-void serial_open(unsigned int line)
+void serial_open(unsigned line)
{
unsigned short port;
unsigned short port2;
outb_p(0x00,port2+4);
outb_p(0x03,port+3); /* reset DLAB */
outb_p(0x0f,port+4); /* set DTR,RTS, OUT_2 */
- outb_p(0x0d,port+1); /* enable all intrs but writes */
+ outb_p(0x0f,port+1); /* enable all intrs */
inb_p(port+5);
inb_p(port+0);
- inb(port+6);
+ inb_p(port+6);
inb(port+2);
sti();
}
timer_table[SER3_TIMEOUT].expires = 0;
timer_table[SER4_TIMEOUT].fn = com4_timeout;
timer_table[SER4_TIMEOUT].expires = 0;
- set_intr_gate(0x24,rs1_interrupt);
- set_intr_gate(0x23,rs2_interrupt);
+ set_intr_gate(0x23,IRQ3_interrupt);
+ set_intr_gate(0x24,IRQ4_interrupt);
init(tty_table[64].read_q->data);
init(tty_table[65].read_q->data);
init(tty_table[66].read_q->data);
*/
void rs_write(struct tty_struct * tty)
{
- cli();
- if (!EMPTY(tty->write_q))
- outb_p(inb_p(tty->write_q->data+1)|0x02,tty->write_q->data+1);
- timer_active |= 15 << SER1_TIMEOUT;
- sti();
+ int line = tty - tty_table - 63;
+
+ do_rs_write(line,tty);
}
* Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
*/
-#include <ctype.h>
+#include <linux/ctype.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
-int kill_pg(int pgrp, int sig, int priv);
-int is_orphaned_pgrp(int pgrp);
-
-extern void lp_init(void);
-
-#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
-#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
-#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
-
-#define L_CANON(tty) _L_FLAG((tty),ICANON)
-#define L_ISIG(tty) _L_FLAG((tty),ISIG)
-#define L_ECHO(tty) _L_FLAG((tty),ECHO)
-#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
-#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
-#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
-#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
-#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
-#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
-
-#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
-#define I_NLCR(tty) _I_FLAG((tty),INLCR)
-#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
-#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
-#define I_IXON(tty) _I_FLAG((tty),IXON)
-#define I_STRP(tty) _I_FLAG((tty),ISTRIP)
-
-#define O_POST(tty) _O_FLAG((tty),OPOST)
-#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
-#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
-#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
-#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
-
-#define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD)
-#define C_HUP(tty) (C_SPEED((tty)) == B0)
-
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#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.
rs_queues + 3, rs_queues + 4,
rs_queues + 6, rs_queues + 7,
rs_queues + 9, rs_queues + 10
- };
+};
void change_console(unsigned int new_console)
{
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);
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)) {
current->counter = 0;
break;
}
- GETCH(tty->read_q,c);
+ c = GETCH(tty->read_q);
if (I_STRP(tty))
c &= 0x7f;
if (c==13) {
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)
+ if (current->sigaction[sig-1].sa_handler)
return -EINTR; /* We _will_ be interrupted :-) */
else
return -ERESTARTSYS; /* We _will_ be interrupted :-) */
/* (but restart after we continue) */
}
-int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
+static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
{
struct tty_struct * tty;
struct tty_struct * other_tty = NULL;
- unsigned char c;
+ int c;
char * b=buf;
int minimum,time;
tty = TTY_TABLE(channel);
if (!(tty->read_q && tty->secondary))
return -EIO;
- if ((tty->pgrp > 0) && (current->tty == channel) &&
+ if ((tty->pgrp > 0) &&
+ (current->tty == channel) &&
(tty->pgrp != current->pgrp))
- return(tty_signal(SIGTTIN, tty));
+ if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ else
+ return(tty_signal(SIGTTIN, tty));
if (channel & 0x80)
other_tty = tty_table + (channel ^ 0x40);
time = 10L*tty->termios.c_cc[VTIME];
current->timeout = time + jiffies;
time = 0;
}
- if (flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK)
time = current->timeout = 0;
if (minimum>nr)
minimum = nr;
}
sti();
do {
- GETCH(tty->secondary,c);
+ c = GETCH(tty->secondary);
if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
c==EOF_CHAR(tty)) || c==10)
tty->secondary->data--;
current->timeout = time+jiffies;
}
sti();
+ TTY_READ_FLUSH(tty);
+ if (other_tty && other_tty->write)
+ TTY_WRITE_FLUSH(other_tty);
current->timeout = 0;
if (b-buf)
return b-buf;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
- if (flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
return 0;
}
-int tty_write(unsigned channel, char * buf, int nr)
+static int write_chan(unsigned int channel, struct file * file, char * buf, int nr)
{
static cr_flag=0;
struct tty_struct * tty;
if (channel > 255)
return -EIO;
tty = TTY_TABLE(channel);
- if (!(tty->write_q && tty->write))
- return -EIO;
- if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
- (current->tty == channel) && (tty->pgrp != current->pgrp))
- return(tty_signal(SIGTTOU, tty));
+ if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
+ (current->tty == channel) && (tty->pgrp != current->pgrp)) {
+ if (is_orphaned_pgrp(tty->pgrp))
+ return -EIO;
+ if (!is_ignored(SIGTTOU))
+ return tty_signal(SIGTTOU, tty);
+ }
if (nr < 0)
return -EINVAL;
if (!nr)
return 0;
+ if (redirect && tty == TTY_TABLE(0))
+ tty = redirect;
+ if (!(tty->write_q && tty->write))
+ return -EIO;
while (nr>0) {
- sleep_if_full(tty->write_q);
if (current->signal & ~current->blocked)
break;
+ if (FULL(tty->write_q)) {
+ TTY_WRITE_FLUSH(tty);
+ cli();
+ if (FULL(tty->write_q))
+ interruptible_sleep_on(&tty->write_q->proc_list);
+ sti();
+ continue;
+ }
while (nr>0 && !FULL(tty->write_q)) {
c=get_fs_byte(b);
if (O_POST(tty)) {
cr_flag = 0;
PUTCH(c,tty->write_q);
}
- TTY_WRITE_FLUSH(tty);
if (nr>0)
schedule();
}
+ TTY_WRITE_FLUSH(tty);
if (b-buf)
return b-buf;
if (current->signal & ~current->blocked)
return 0;
}
-void chr_dev_init(void)
+static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+ int i;
+
+ i = read_chan(current->tty,file,buf,count);
+ if (i > 0)
+ inode->i_atime = CURRENT_TIME;
+ return i;
+}
+
+static int ttyx_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+ int i;
+
+ i = read_chan(MINOR(inode->i_rdev),file,buf,count);
+ if (i > 0)
+ inode->i_atime = CURRENT_TIME;
+ return i;
+}
+
+static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+ int i;
+
+ i = write_chan(current->tty,file,buf,count);
+ if (i > 0)
+ inode->i_mtime = CURRENT_TIME;
+ return i;
+}
+
+static int ttyx_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+ int i;
+
+ i = write_chan(MINOR(inode->i_rdev),file,buf,count);
+ if (i > 0)
+ inode->i_mtime = CURRENT_TIME;
+ return i;
+}
+
+static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+ return -EBADF;
+}
+
+/*
+ * tty_open and tty_release keep up the tty count that contains the
+ * number of opens done on a tty. We cannot use the inode-count, as
+ * different inodes might point to the same tty.
+ *
+ * Open-counting is needed for pty masters, as well as for keeping
+ * track of serial lines: DTR is dropped when the last close happens.
+ */
+static int tty_open(struct inode * inode, struct file * filp)
+{
+ struct tty_struct *tty;
+ int dev;
+
+ dev = inode->i_rdev;
+ if (MAJOR(dev) == 5)
+ dev = current->tty;
+ else
+ dev = MINOR(dev);
+ if (dev < 0)
+ return -ENODEV;
+ tty = TTY_TABLE(dev);
+ if (IS_A_PTY_MASTER(dev)) {
+ if (tty->count)
+ return -EAGAIN;
+ }
+ tty->count++;
+ if (!(filp->f_flags & O_NOCTTY) &&
+ current->leader &&
+ current->tty<0 &&
+ tty->session==0) {
+ current->tty = dev;
+ tty->session = current->session;
+ tty->pgrp = current->pgrp;
+ }
+ if (IS_A_SERIAL(dev))
+ serial_open(dev-64);
+ return 0;
+}
+
+static void tty_release(struct inode * inode, struct file * filp)
{
+ int dev;
+ unsigned short port;
+ struct tty_struct * tty, * slave;
+
+ dev = inode->i_rdev;
+ if (MAJOR(dev) == 5)
+ dev = current->tty;
+ else
+ dev = MINOR(dev);
+ if (dev < 0)
+ return;
+ tty = TTY_TABLE(dev);
+ if (--tty->count)
+ return;
+ if (tty == redirect)
+ redirect = NULL;
+ if (port = tty->read_q->data)
+ outb(0x0c,port+4); /* reset DTR, RTS, */
+ if (IS_A_PTY_MASTER(dev)) {
+ slave = tty_table + PTY_OTHER(dev);
+ if (slave->pgrp > 0)
+ kill_pg(slave->pgrp,SIGHUP,1);
+ }
}
+static struct file_operations tty_fops = {
+ tty_lseek,
+ tty_read,
+ tty_write,
+ NULL, /* tty_readdir */
+ NULL, /* tty_select */
+ tty_ioctl,
+ tty_open,
+ tty_release
+};
+
+static struct file_operations ttyx_fops = {
+ tty_lseek,
+ ttyx_read,
+ ttyx_write,
+ NULL, /* ttyx_readdir */
+ NULL, /* ttyx_select */
+ tty_ioctl, /* ttyx_ioctl */
+ tty_open,
+ tty_release
+};
+
void tty_init(void)
{
int i;
+ chrdev_fops[4] = &ttyx_fops;
+ chrdev_fops[5] = &tty_fops;
for (i=0 ; i < QUEUES ; i++)
tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
for (i=0 ; i<256 ; i++) {
tty_table[i] = (struct tty_struct) {
{0, 0, 0, 0, 0, INIT_C_CC},
- -1, 0, 0, 0, {0,0,0,0},
+ -1, 0, 0, 0, 0, {0,0,0,0},
NULL, NULL, NULL, NULL
};
}
0, /* initial session */
0, /* initial stopped */
0, /* initial busy */
+ 0, /* initial count */
{video_num_lines,video_num_columns,0,0},
con_write,
con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
0,
0,
0,
+ 0,
{25,80,0,0},
rs_write,
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
0,
0,
0,
+ 0,
{25,80,0,0},
mpty_write,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
0,
0,
0,
+ 0,
{25,80,0,0},
spty_write,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
rs_init();
printk("%d virtual consoles\n\r",NR_CONSOLES);
printk("%d pty's\n\r",NR_PTYS);
- lp_init();
}
#include <errno.h>
#include <termios.h>
+#include <sys/types.h>
#include <linux/sched.h>
#include <linux/kernel.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,
sti();
}
-static void flush(struct tty_queue * queue)
+void flush(struct tty_queue * queue)
{
if (queue) {
cli();
static void wait_until_sent(struct tty_struct * tty)
{
- cli();
while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
+ TTY_WRITE_FLUSH(tty);
current->counter = 0;
- interruptible_sleep_on(&tty->write_q->proc_list);
+ cli();
+ if (EMPTY(tty->write_q))
+ break;
+ else
+ interruptible_sleep_on(&tty->write_q->proc_list);
+ sti();
}
sti();
}
static void send_break(struct tty_struct * tty)
{
- /* do nothing - not implemented */
+ unsigned short port;
+
+ if (!(port = tty->read_q->data))
+ return;
+ port += 3;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 25;
+ outb_p(inb_p(port) | 0x40,port);
+ schedule();
+ outb_p(inb_p(port) & 0xbf,port);
}
static int do_get_ps_info(int arg)
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
- int i, retsig;
+ int i;
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
- if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
- retsig = tty_signal(SIGTTOU, tty);
- if (retsig == -ERESTARTSYS || retsig == -EINTR)
- return retsig;
+ if ((current->tty == channel) &&
+ (tty->pgrp != current->pgrp)) {
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ if (!is_ignored(SIGTTOU))
+ return tty_signal(SIGTTOU, tty);
}
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
- int i, retsig;
+ int i;
struct termio tmp_termio;
- if ((current->tty == channel) && (tty->pgrp != current->pgrp)) {
- retsig = tty_signal(SIGTTOU, tty);
- if (retsig == -ERESTARTSYS || retsig == -EINTR)
- return retsig;
+ if ((current->tty == channel) &&
+ (tty->pgrp > 0) &&
+ (tty->pgrp != current->pgrp)) {
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ if (!is_ignored(SIGTTOU))
+ return tty_signal(SIGTTOU, tty);
}
for (i=0 ; i< (sizeof (*termio)) ; i++)
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
return 0;
}
-int tty_ioctl(int dev, int cmd, int arg)
+int tty_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned int arg)
{
struct tty_struct * tty;
struct tty_struct * other_tty;
int pgrp;
+ int dev;
- if (MAJOR(dev) == 5) {
+ if (MAJOR(inode->i_rdev) == 5) {
dev = current->tty;
if (dev<0)
return -EINVAL;
} else
- dev=MINOR(dev);
+ dev = MINOR(inode->i_rdev);
tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
if (IS_A_PTY(dev))
case TCSETA:
return set_termio(tty,(struct termio *) arg, dev);
case TCSBRK:
- if (!arg) {
- wait_until_sent(tty);
+ wait_until_sent(tty);
+ if (!arg)
send_break(tty);
- }
return 0;
case TCXONC:
switch (arg) {
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;
default:
- return -EINVAL;
+ return vt_ioctl(tty, dev, cmd, arg);
}
}
--- /dev/null
+/*
+ * kernel/chr_drv/vt.c
+ *
+ * (C) 1992 obz under the linux copyright
+ */
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/kd.h>
+#include <sys/vt.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+
+#include "vt_kern.h"
+
+/*
+ * console (vt and kd) routines, as defined by usl svr4 manual
+ */
+
+struct vt_cons vt_cons[MAX_CONSOLES];
+
+extern int NR_CONSOLES;
+extern unsigned char kleds;
+extern unsigned char kraw;
+extern unsigned char ke0;
+
+extern int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern void set_leds(void);
+
+/*
+ * these are the valid i/o ports we're allowed to change. they map all the
+ * video ports
+ */
+#define GPFIRST 0x3b4
+#define GPLAST 0x3df
+#define GPNUM (GPLAST - GPFIRST + 1)
+
+/*
+ * turns on sound of some freq. 0 turns it off.
+ * stolen from console.c, so i'm not sure if its the correct interpretation
+ */
+static int
+kiocsound(unsigned int freq)
+{
+ if (freq == 0) {
+ /* disable counter 2 */
+ outb(inb_p(0x61)&0xFC, 0x61);
+ }
+ else {
+ /* enable counter 2 */
+ outb_p(inb_p(0x61)|3, 0x61);
+ /* set command for counter 2, 2 byte write */
+ outb_p(0xB6, 0x43);
+ /* select desired HZ */
+ outb_p(freq & 0xff, 0x42);
+ outb((freq >> 8) & 0xff, 0x42);
+ }
+ return 0;
+}
+
+/*
+ * all the vt ioctls affect only consoles, so we reject all other ttys.
+ * we also have the capability to modify any console, not just the fg_console.
+ */
+int
+vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg)
+{
+ int console = dev ? dev - 1 : fg_console;
+ unsigned char ucval;
+
+ if (!IS_A_CONSOLE(dev) || console < 0 || console >= NR_CONSOLES)
+ return -EINVAL;
+
+ switch (cmd) {
+ case KIOCSOUND:
+ return kiocsound((unsigned int)arg);
+
+ case KDGKBTYPE:
+ /*
+ * this is naive.
+ */
+ verify_area((void *) arg, sizeof(unsigned char));
+ put_fs_byte(KB_101, (unsigned char *) arg);
+ return 0;
+
+ case KDADDIO:
+ case KDDELIO:
+ /*
+ * KDADDIO and KDDELIO may be able to add ports beyond what
+ * we reject here, but to be safe...
+ */
+ if (arg < GPFIRST || arg > GPLAST)
+ return -EINVAL;
+ return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+
+ case KDENABIO:
+ case KDDISABIO:
+ return sys_ioperm(GPFIRST, GPNUM,
+ (cmd == KDENABIO)) ? -ENXIO : 0;
+
+ case KDSETMODE:
+ /*
+ * currently, setting the mode from KD_TEXT to KD_GRAPHICS
+ * doesn't do a whole lot. i'm not sure if it should do any
+ * restoration of modes or what...
+ */
+ switch (arg) {
+ case KD_GRAPHICS:
+ break;
+ case KD_TEXT0:
+ case KD_TEXT1:
+ arg = KD_TEXT;
+ case KD_TEXT:
+ break;
+ default:
+ return -EINVAL;
+ }
+ vt_cons[console].vt_mode = arg;
+ return 0;
+ case KDGETMODE:
+ verify_area((void *) arg, sizeof(unsigned long));
+ put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg);
+ return 0;
+
+ case KDMAPDISP:
+ case KDUNMAPDISP:
+ /*
+ * these work like a combination of mmap and KDENABIO.
+ * this could be easily finished.
+ */
+ return -EINVAL;
+
+ case KDSKBMODE:
+ if (arg == K_RAW) {
+ if (console == fg_console) {
+ kraw = 1;
+ ke0 = 0;
+ } else {
+ vt_cons[console].vc_kbdraw = 1;
+ vt_cons[console].vc_kbde0 = 0;
+ }
+ }
+ else if (arg == K_XLATE) {
+ if (console == fg_console)
+ kraw = 0;
+ else
+ vt_cons[console].vc_kbdraw = 0;
+ }
+ else
+ return -EINVAL;
+ flush(tty->read_q);
+ flush(tty->secondary);
+ return 0;
+ case KDGKBMODE:
+ verify_area((void *) arg, sizeof(unsigned long));
+ ucval = (console == fg_console) ? kraw :
+ vt_cons[console].vc_kbdraw;
+ put_fs_long(ucval ? K_RAW : K_XLATE, (unsigned long *) arg);
+ return 0;
+
+ case KDGETLED:
+ verify_area((void *) arg, sizeof(unsigned char));
+ ucval = (console == fg_console) ? kleds :
+ vt_cons[console].vc_kbdleds;
+ put_fs_byte((((ucval & 1) ? LED_SCR : 0) |
+ ((ucval & 2) ? LED_NUM : 0) |
+ ((ucval & 4) ? LED_CAP : 0)),
+ (unsigned char *) arg);
+ return 0;
+ case KDSETLED:
+ if (arg & ~7)
+ return -EINVAL;
+ ucval = (((arg & LED_SCR) ? 1 : 0) |
+ ((arg & LED_NUM) ? 2 : 0) |
+ ((arg & LED_CAP) ? 4 : 0));
+ if (console == fg_console) {
+ kleds = ucval;
+ set_leds();
+ }
+ else
+ vt_cons[console].vc_kbdleds = ucval;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
--- /dev/null
+#ifndef _VT_KERN_H
+#define _VT_KERN_H
+
+/*
+ * this really is an extension of the vc_cons structure in console.c, but
+ * with information needed by the vt package
+ */
+extern struct vt_cons {
+ int vt_mode; /* KD_TEXT, ... */
+ unsigned char vc_kbdraw;
+ unsigned char vc_kbde0;
+ unsigned char vc_kbdleds;
+} vt_cons[MAX_CONSOLES];
+
+#endif /* _VT_KERN_H */
int sys_close(int fd);
-inline int send_sig(long sig,struct task_struct * p,int priv)
+int send_sig(long sig,struct task_struct * p,int priv)
{
if (!p || (sig < 0) || (sig > 32))
return -EINVAL;
- if (!priv && (current->euid!=p->euid) && !suser())
+ if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
+ (current->euid != p->euid) && !suser())
return -EPERM;
if (!sig)
return 0;
}
#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);
current->root = NULL;
iput(current->executable);
current->executable = NULL;
- iput(current->library);
- current->library = NULL;
+ for (i=0; i < current->numlibraries; i++) {
+ iput(current->libraries[i].library);
+ current->libraries[i].library = NULL;
+ }
current->state = TASK_ZOMBIE;
current->exit_code = code;
current->rss = 0;
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)
}
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,
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/
#include <errno.h>
+#include <stddef.h>
#include <linux/sched.h>
#include <linux/kernel.h>
int i;
repeat:
- if ((++last_pid)<0) last_pid=1;
+ if ((++last_pid) & 0xffff0000)
+ last_pid=1;
for(i=0 ; i<NR_TASKS ; i++)
if (task[i] && ((task[i]->pid == last_pid) ||
(task[i]->pgrp == last_pid)))
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE;
p->pid = last_pid;
+ p->p_pptr = current;
+ p->p_cptr = NULL;
+ p->p_ysptr = NULL;
+ if (p->p_osptr = current->p_cptr)
+ p->p_osptr->p_ysptr = p;
+ current->p_cptr = p;
p->counter = p->priority;
p->signal = 0;
p->alarm = 0;
p->tss.fs = fs & 0xffff;
p->tss.gs = gs & 0xffff;
p->tss.ldt = _LDT(nr);
- p->tss.trace_bitmap = 0x80000000;
+ p->tss.trace_bitmap = offsetof(struct tss_struct,io_bitmap) << 16;
+ for (i = 0; i<IO_BITMAP_SIZE ; i++)
+ p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) {
task[nr] = NULL;
+ if (p->p_pptr->p_cptr == p)
+ p->p_pptr->p_cptr = p->p_osptr;
+ if (p->p_osptr)
+ p->p_osptr->p_ysptr = p->p_ysptr;
+ if (p->p_ysptr)
+ p->p_ysptr->p_osptr = p->p_osptr;
free_page((long) p);
return -EAGAIN;
}
current->root->i_count++;
if (current->executable)
current->executable->i_count++;
- if (current->library)
- current->library->i_count++;
+ for (i=0; i < current->numlibraries ; i++)
+ if (current->libraries[i].library)
+ current->libraries[i].library->i_count++;
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
- p->p_pptr = current;
- p->p_cptr = 0;
- p->p_ysptr = 0;
- p->p_osptr = current->p_cptr;
- if (p->p_osptr)
- p->p_osptr->p_ysptr = p;
- current->p_cptr = p;
p->state = TASK_RUNNING; /* do this last, just in case */
return p->pid;
}
--- /dev/null
+/*
+ * linux/kernel/ioport.c
+ *
+ * This contains the io-permission bitmap code - written by obz, with changes
+ * by Linus.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <sys/types.h>
+#include <errno.h>
+
+#define _IODEBUG
+
+#ifdef IODEBUG
+static char * ios(unsigned long l)
+{
+ static char str[33] = { '\0' };
+ int i;
+ unsigned long mask;
+
+ for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1)
+ str[i] = (l & mask) ? '1' : '0';
+ return str;
+}
+
+static void dump_io_bitmap(void)
+{
+ int i, j;
+ int numl = sizeof(current->tss.io_bitmap) >> 2;
+
+ for (i = j = 0; j < numl; ++i)
+ {
+ printk("%4d [%3x]: ", 64*i, 64*i);
+ printk("%s ", ios(current->tss.io_bitmap[j++]));
+ if (j < numl)
+ printk("%s", ios(current->tss.io_bitmap[j++]));
+ printk("\n");
+ }
+}
+#endif
+
+/*
+ * this changes the io permissions bitmap in the current task.
+ */
+int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+ unsigned long froml, lindex, tnum, numl, rindex, mask;
+ unsigned long *iop;
+
+ froml = from >> 5;
+ lindex = from & 0x1f;
+ tnum = lindex + num;
+ numl = (tnum + 0x1f) >> 5;
+ rindex = tnum & 0x1f;
+
+ if (!suser())
+ return -EPERM;
+ if (froml * 32 + tnum > sizeof(current->tss.io_bitmap) * 8 - 8)
+ return -EINVAL;
+
+#ifdef IODEBUG
+ printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
+#endif
+
+ if (numl) {
+ iop = (unsigned long *)current->tss.io_bitmap + froml;
+ if (lindex != 0) {
+ mask = (~0 << lindex);
+ if (--numl == 0 && rindex)
+ mask &= ~(~0 << rindex);
+ if (turn_on)
+ *iop++ &= ~mask;
+ else
+ *iop++ |= mask;
+ }
+ if (numl) {
+ if (rindex)
+ --numl;
+ mask = (turn_on ? 0 : ~0);
+ while (numl--)
+ *iop++ = mask;
+ if (numl && rindex) {
+ mask = ~(~0 << rindex);
+ if (turn_on)
+ *iop++ &= ~mask;
+ else
+ *iop++ |= mask;
+ }
+ }
+ }
+ return 0;
+}
cp tmp_make Makefile
### Dependencies:
-add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+add.s add.o : add.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h
-compare.s compare.o : compare.c ../../include/linux/math_emu.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+compare.s compare.o : compare.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h
-convert.s convert.o : convert.c ../../include/linux/math_emu.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+convert.s convert.o : convert.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h
-div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+div.s div.o : div.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h
-ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+ea.s ea.o : ea.c ../../include/stddef.h ../../include/linux/math_emu.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/types.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h ../../include/asm/segment.h
-error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h \
- ../../include/linux/sched.h ../../include/linux/head.h \
- ../../include/linux/fs.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/sys/param.h \
- ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h
-get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h \
- ../../include/linux/math_emu.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/linux/mm.h ../../include/linux/kernel.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
- ../../include/sys/resource.h ../../include/asm/segment.h
-emulate.s emulate.o : emulate.c ../../include/linux/config.h
-mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h \
- ../../include/linux/head.h ../../include/linux/fs.h \
- ../../include/sys/types.h ../../include/linux/mm.h \
- ../../include/linux/kernel.h ../../include/signal.h \
- ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
+emulate.s emulate.o : emulate.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h
+error.s error.o : error.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/sched.h \
+ ../../include/linux/head.h ../../include/linux/fs.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h
+get_put.s get_put.o : get_put.c ../../include/signal.h ../../include/sys/types.h ../../include/linux/math_emu.h \
+ ../../include/linux/sched.h ../../include/linux/head.h ../../include/linux/fs.h \
+ ../../include/sys/dirent.h ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h ../../include/sys/resource.h \
+ ../../include/asm/segment.h
+mul.s mul.o : mul.c ../../include/linux/math_emu.h ../../include/linux/sched.h ../../include/linux/head.h \
+ ../../include/linux/fs.h ../../include/sys/types.h ../../include/sys/dirent.h \
+ ../../include/limits.h ../../include/linux/mm.h ../../include/linux/kernel.h \
+ ../../include/signal.h ../../include/sys/param.h ../../include/sys/time.h ../../include/time.h \
../../include/sys/resource.h
* (C) 1991 Linus Torvalds
*/
-/*
- * When in kernel-mode, we cannot use printf, as fs is liable to
- * point to 'interesting' things. Make a printf with fs-saving, and
- * all is well.
- */
#include <stdarg.h>
#include <stddef.h>
+#include <errno.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
#include <linux/kernel.h>
static char buf[1024];
extern int vsprintf(char * buf, const char * fmt, va_list args);
+extern void console_print(const char *);
+
+static unsigned long log_page = 0;
+static unsigned long log_start = 0;
+static unsigned long log_size = 0;
+static struct task_struct * log_wait = NULL;
+
+int sys_syslog(int type, char * buf, int len)
+{
+ unsigned long i;
+ char c;
+
+ if (!suser())
+ return -EPERM;
+ switch (type) {
+ case 0:
+ i = log_page;
+ log_page = 0;
+ free_page(i);
+ wake_up(&log_wait);
+ return 0;
+ case 1:
+ i = get_free_page();
+ if (log_page) {
+ free_page(i);
+ return 0;
+ } else if (log_page = i) {
+ log_start = log_size = 0;
+ return 0;
+ }
+ return -ENOMEM;
+ case 2:
+ if (!buf || len < 0)
+ return -EINVAL;
+ if (!len)
+ return 0;
+ verify_area(buf,len);
+ while (!log_size) {
+ if (!log_page)
+ return -EIO;
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ cli();
+ if (!log_size)
+ interruptible_sleep_on(&log_wait);
+ sti();
+ }
+ i = 0;
+ while (log_size && len) {
+ c = *((char *) log_page+log_start);
+ log_start++;
+ log_size--;
+ log_start &= 4095;
+ put_fs_byte(c,buf);
+ buf++;
+ i++;
+ }
+ return i;
+ }
+ return -EINVAL;
+}
+
int printk(const char *fmt, ...)
{
va_list args;
- int i;
+ int i,j;
+ char * p;
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
+ for (j = 0; j < i && log_page ; j++) {
+ p = (char *) log_page + (4095 & (log_start+log_size));
+ *p = buf[j];
+ if (log_size < 4096)
+ log_size++;
+ else
+ log_start++;
+ }
+ if (log_page)
+ wake_up(&log_wait);
console_print(buf);
return i;
}
*/
#define MAGICNUMBER 68
-void do_no_page(unsigned long, unsigned long, struct task_struct *);
+void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned long);
void write_verify(unsigned long);
/* change a pid into a task struct. */
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)) {
return 0;
}
-/* Perform ptrace(request, pid, addr, data) syscall */
-int sys_ptrace(unsigned long *buffer)
+int sys_ptrace(long request, long pid, long addr, long data)
{
- long request, pid, data;
- long addr;
struct task_struct *child;
int childno;
- request = get_fs_long(buffer++);
- pid = get_fs_long(buffer++);
- addr = get_fs_long(buffer++); /* assume long = void * */
- data = get_fs_long(buffer++);
-
if (request == 0) {
/* set the ptrace bit in the proccess flags. */
current->flags |= PF_PTRACED;
#include <signal.h>
#include <errno.h>
+int need_resched = 0;
+
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
void show_state(void)
{
- static int lock = 0;
int i;
- cli();
- if (lock) {
- sti();
- return;
- }
- lock = 1;
- sti();
printk("\rTask-info:\n\r");
for (i=0 ; i<NR_TASKS ; i++)
if (task[i])
show_task(i,task[i]);
- lock = 0;
}
#define LATCH (1193180/HZ)
/* 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)
return -EINTR;
}
+/*
+ * wake_up doesn't wake up stopped processes - they have to be awakened
+ * with signals or similar.
+ */
void wake_up(struct task_struct **p)
{
struct task_struct * wakeup_ptr, * tmp;
wakeup_ptr = *p;
*p = NULL;
while (wakeup_ptr && wakeup_ptr != task[0]) {
- if (wakeup_ptr->state == TASK_STOPPED)
- printk("wake_up: TASK_STOPPED\n");
- else if (wakeup_ptr->state == TASK_ZOMBIE)
+ if (wakeup_ptr->state == TASK_ZOMBIE)
printk("wake_up: TASK_ZOMBIE\n");
- else
+ else if (wakeup_ptr->state != TASK_STOPPED) {
wakeup_ptr->state = TASK_RUNNING;
+ if (wakeup_ptr->counter > current->counter)
+ need_resched = 1;
+ }
tmp = wakeup_ptr->next_wait;
wakeup_ptr->next_wait = task[0];
wakeup_ptr = tmp;
sti();
}
+#define FSHIFT 11
+#define FSCALE (1<<FSHIFT)
+/*
+ * Constants for averages over 1, 5, and 15 minutes
+ * when sampling at 5 second intervals.
+ */
+static unsigned long cexp[3] = {
+ 1884, /* 0.9200444146293232 * FSCALE, exp(-1/12) */
+ 2014, /* 0.9834714538216174 * FSCALE, exp(-1/60) */
+ 2037, /* 0.9944598480048967 * FSCALE, exp(-1/180) */
+};
+unsigned long averunnable[3]; /* fixed point numbers */
+
+void update_avg(void)
+{
+ int i, n=0;
+ struct task_struct **p;
+
+ for(p = &LAST_TASK; p > &FIRST_TASK; --p)
+ if (*p && ((*p)->state == TASK_RUNNING ||
+ (*p)->state == TASK_UNINTERRUPTIBLE))
+ ++n;
+
+ for (i = 0; i < 3; ++i)
+ averunnable[i] = (cexp[i] * averunnable[i] +
+ n * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
+}
+
unsigned long timer_active = 0;
struct timer_struct timer_table[32];
{
unsigned long mask;
struct timer_struct *tp = timer_table+0;
+ static int avg_cnt;
for (mask = 1 ; mask ; tp++,mask += mask) {
if (mask > timer_active)
continue;
timer_active &= ~mask;
tp->fn();
+ sti();
}
if (cpl)
}
if (current_DOR & 0xf0)
do_floppy_timer();
- if ((--current->counter)>0) return;
- current->counter=0;
- if (!cpl) return;
- schedule();
+ if (--avg_cnt < 0) {
+ avg_cnt = 500;
+ update_avg();
+ }
+ if ((--current->counter)<=0) {
+ current->counter=0;
+ need_resched = 1;
+ }
}
int sys_alarm(long seconds)
{
if (increment < 0 && !suser())
return -EPERM;
- if (increment > current->priority)
+ if (increment >= current->priority)
increment = current->priority-1;
current->priority -= increment;
return 0;
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
-
-int send_sig (int, struct task_struct *, int);
-
+
int sys_sgetmask()
{
return current->blocked;
#include <sys/utsname.h>
#include <sys/param.h>
#include <sys/resource.h>
-#include <string.h>
+#include <linux/string.h>
/*
* this indicates wether you can reboot with ctrl-alt-del: the deault is yes
extern int session_of_pgrp(int pgrp);
+#define PZERO 15
+
+static int proc_sel(struct task_struct *p, int which, int who)
+{
+ switch (which) {
+ case PRIO_PROCESS:
+ if (!who && p == current)
+ return 1;
+ return(p->pid == who);
+ case PRIO_PGRP:
+ if (!who)
+ who = current->pgrp;
+ return(p->pgrp == who);
+ case PRIO_USER:
+ if (!who)
+ who = current->uid;
+ return(p->uid == who);
+ }
+ return 0;
+}
+
+int sys_setpriority(int which, int who, int niceval)
+{
+ struct task_struct **p;
+ int error = ESRCH;
+ int priority;
+
+ if (which > 2 || which < 0)
+ return -EINVAL;
+
+ if ((priority = PZERO - niceval) <= 0)
+ priority = 1;
+
+ for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
+ if (!*p || !proc_sel(*p, which, who))
+ continue;
+ if ((*p)->uid != current->euid &&
+ (*p)->uid != current->uid && !suser()) {
+ error = EPERM;
+ continue;
+ }
+ if (error == ESRCH)
+ error = 0;
+ if (priority > (*p)->priority && !suser())
+ error = EACCES;
+ else
+ (*p)->priority = priority;
+ }
+ return -error;
+}
+
+int sys_getpriority(int which, int who)
+{
+ struct task_struct **p;
+ int max_prio = 0;
+
+ if (which > 2 || which < 0)
+ return -EINVAL;
+
+ for(p = &LAST_TASK; p > &FIRST_TASK; --p) {
+ if (!*p || !proc_sel(*p, which, who))
+ continue;
+ if ((*p)->priority > max_prio)
+ max_prio = (*p)->priority;
+ }
+ return(max_prio ? max_prio : -ESRCH);
+}
+
+int sys_profil()
+{
+ return -ENOSYS;
+}
+
int sys_ftime()
{
return -ENOSYS;
{
int i;
- if (!name) return -ERROR;
+ if (!name)
+ return -EINVAL;
verify_area(name,sizeof *name);
for(i=0;i<sizeof *name;i++)
put_fs_byte(((char *) &thisname)[i],i+(char *) name);
--- /dev/null
+/*
+ * linux/kernel/sys_call.S
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * sys_call.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
+ * updated in fork.c:copy_process, signal.c:do_signal,
+ * ptrace.c and ptrace.h
+ *
+ * 0(%esp) - %ebx
+ * 4(%esp) - %ecx
+ * 8(%esp) - %edx
+ * C(%esp) - %esi
+ * 10(%esp) - %edi
+ * 14(%esp) - %ebp
+ * 18(%esp) - %eax
+ * 1C(%esp) - %ds
+ * 20(%esp) - %es
+ * 24(%esp) - %fs
+ * 28(%esp) - %gs
+ * 2C(%esp) - orig_eax
+ * 30(%esp) - %eip
+ * 34(%esp) - %cs
+ * 38(%esp) - %eflags
+ * 3C(%esp) - %oldesp
+ * 40(%esp) - %oldss
+ */
+
+SIG_CHLD = 17
+
+EBX = 0x00
+ECX = 0x04
+EDX = 0x08
+ESI = 0x0C
+EDI = 0x10
+EBP = 0x14
+EAX = 0x18
+DS = 0x1C
+ES = 0x20
+FS = 0x24
+GS = 0x28
+ORIG_EAX = 0x2C
+EIP = 0x30
+CS = 0x34
+EFLAGS = 0x38
+OLDESP = 0x3C
+OLDSS = 0x40
+
+/*
+ * these are offsets into the task-struct.
+ */
+state = 0
+counter = 4
+priority = 8
+signal = 12
+sigaction = 16 # MUST be 16 (=len of sigaction)
+blocked = (33*16)
+
+/*
+ * offsets within sigaction
+ */
+sa_handler = 0
+sa_mask = 4
+sa_flags = 8
+sa_restorer = 12
+
+ENOSYS = 38
+
+/*
+ * Ok, I get parallel printer interrupts while using the floppy for some
+ * strange reason. Urgel. Now I just ignore them.
+ */
+.globl _system_call,_timer_interrupt,_sys_execve
+.globl _device_not_available, _coprocessor_error
+.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
+.globl _double_fault,_coprocessor_segment_overrun
+.globl _invalid_TSS,_segment_not_present,_stack_segment
+.globl _general_protection,_irq13,_reserved
+.globl _alignment_check,_page_fault
+.globl _keyboard_interrupt,_hd_interrupt
+.globl _IRQ3_interrupt,_IRQ4_interrupt
+
+#define SAVE_ALL \
+ cld; \
+ push %gs; \
+ push %fs; \
+ push %es; \
+ push %ds; \
+ pushl %eax; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx; \
+ movl $0x10,%edx; \
+ mov %dx,%ds; \
+ mov %dx,%es; \
+ movl $0x17,%edx; \
+ mov %dx,%fs
+
+#define ACK_FIRST(mask) \
+ inb $0x21,%al; \
+ jmp 1f; \
+1: jmp 1f; \
+1: orb $(mask),%al; \
+ outb %al,$0x21; \
+ jmp 1f; \
+1: jmp 1f; \
+1: movb $0x20,%al; \
+ outb %al,$0x20
+
+#define ACK_SECOND(mask) \
+ inb $0xA1,%al; \
+ jmp 1f; \
+1: jmp 1f; \
+1: orb $(mask),%al; \
+ outb %al,$0xA1; \
+ jmp 1f; \
+1: jmp 1f; \
+1: movb $0x20,%al; \
+ outb %al,$0xA0 \
+ jmp 1f; \
+1: jmp 1f; \
+1: outb %al,$0x20
+
+#define UNBLK_FIRST(mask) \
+ inb $0x21,%al; \
+ jmp 1f; \
+1: jmp 1f; \
+1: andb $~(mask),%al; \
+ outb %al,$0x21
+
+#define UNBLK_SECOND(mask) \
+ inb $0xA1,%al; \
+ jmp 1f; \
+1: jmp 1f; \
+1: andb $~(mask),%al; \
+ outb %al,$0xA1
+
+.align 2
+bad_sys_call:
+ movl $-ENOSYS,EAX(%esp)
+ jmp ret_from_sys_call
+.align 2
+reschedule:
+ pushl $ret_from_sys_call
+ jmp _schedule
+.align 2
+_system_call:
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ cmpl _NR_syscalls,%eax
+ jae bad_sys_call
+ call _sys_call_table(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ret_from_sys_call:
+ cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
+ jne 2f
+ cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
+ jne 2f
+1: movl _current,%eax
+ cmpl _task,%eax # task[0] cannot have signals
+ je 2f
+ cmpl $0,_need_resched
+ jne reschedule
+ cmpl $0,state(%eax) # state
+ jne reschedule
+ cmpl $0,counter(%eax) # counter
+ je reschedule
+ movl signal(%eax),%ebx
+ movl blocked(%eax),%ecx
+ notl %ecx
+ andl %ebx,%ecx
+ bsfl %ecx,%ecx
+ je 2f
+ btrl %ecx,%ebx
+ movl %ebx,signal(%eax)
+ incl %ecx
+ pushl %ecx
+ call _do_signal
+ popl %ecx
+ testl %eax, %eax
+ jne 1b # see if we need to switch tasks, or do more signals
+2: popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ pop %ds
+ pop %es
+ pop %fs
+ pop %gs
+ addl $4,%esp # skip the orig_eax
+ iret
+
+.align 2
+_irq13:
+ pushl %eax
+ xorb %al,%al
+ outb %al,$0xF0
+ movb $0x20,%al
+ outb %al,$0x20
+ jmp 1f
+1: jmp 1f
+1: outb %al,$0xA0
+ popl %eax
+_coprocessor_error:
+ pushl $-1 # mark this as an int.
+ SAVE_ALL
+ pushl $ret_from_sys_call
+ jmp _math_error
+
+.align 2
+_device_not_available:
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ pushl $ret_from_sys_call
+ clts # clear TS so that we can use math
+ movl %cr0,%eax
+ testl $0x4,%eax # EM (math emulation bit)
+ je _math_state_restore
+ pushl $0 # temporary storage for ORIG_EIP
+ call _math_emulate
+ addl $4,%esp
+ ret
+
+.align 2
+_keyboard_interrupt:
+ pushl $-1
+ SAVE_ALL
+ ACK_FIRST(0x02)
+ sti
+ call _do_keyboard
+ cli
+ UNBLK_FIRST(0x02)
+ jmp ret_from_sys_call
+
+.align 2
+_IRQ3_interrupt:
+ pushl $-1
+ SAVE_ALL
+ ACK_FIRST(0x08)
+ sti
+ call _do_IRQ3
+ cli
+ UNBLK_FIRST(0x08)
+ jmp ret_from_sys_call
+
+.align 2
+_IRQ4_interrupt:
+ pushl $-1
+ SAVE_ALL
+ ACK_FIRST(0x10)
+ sti
+ call _do_IRQ4
+ cli
+ UNBLK_FIRST(0x10)
+ jmp ret_from_sys_call
+
+.align 2
+_timer_interrupt:
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ ACK_FIRST(0x01)
+ sti
+ incl _jiffies
+ movl CS(%esp),%eax
+ andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
+ pushl %eax
+ call _do_timer # 'do_timer(long CPL)' does everything from
+ addl $4,%esp # task switching to accounting ...
+ cli
+ UNBLK_FIRST(0x01)
+ jmp ret_from_sys_call
+
+.align 2
+_hd_interrupt:
+ pushl $-1
+ SAVE_ALL
+ ACK_SECOND(0x40)
+ andl $0xfffeffff,_timer_active
+ xorl %edx,%edx
+ xchgl _do_hd,%edx
+ testl %edx,%edx
+ jne 1f
+ movl $_unexpected_hd_interrupt,%edx
+1: call *%edx # "interesting" way of handling intr.
+ cli
+ UNBLK_SECOND(0x40)
+ jmp ret_from_sys_call
+
+.align 2
+_sys_execve:
+ lea (EIP+4)(%esp),%eax # don't forget about the return address.
+ pushl %eax
+ call _do_execve
+ addl $4,%esp
+ ret
+
+_divide_error:
+ pushl $0 # no error code
+ pushl $_do_divide_error
+error_code:
+ push %fs
+ push %es
+ push %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ cld
+ movl $-1, %eax
+ xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
+ xorl %ebx,%ebx # zero ebx
+ mov %gs,%bx # get the lower order bits of gs
+ xchgl %ebx, GS(%esp) # get the address and save gs.
+ pushl %eax # push the error code
+ lea 52(%esp),%edx
+ pushl %edx
+ movl $0x10,%edx
+ mov %dx,%ds
+ mov %dx,%es
+ movl $0x17,%edx
+ mov %dx,%fs
+ call *%ebx
+ addl $8,%esp
+ jmp ret_from_sys_call
+
+_debug:
+ pushl $0
+ pushl $_do_int3 # _do_debug
+ jmp error_code
+
+_nmi:
+ pushl $0
+ pushl $_do_nmi
+ jmp error_code
+
+_int3:
+ pushl $0
+ pushl $_do_int3
+ jmp error_code
+
+_overflow:
+ pushl $0
+ pushl $_do_overflow
+ jmp error_code
+
+_bounds:
+ pushl $0
+ pushl $_do_bounds
+ jmp error_code
+
+_invalid_op:
+ pushl $0
+ pushl $_do_invalid_op
+ jmp error_code
+
+_coprocessor_segment_overrun:
+ pushl $0
+ pushl $_do_coprocessor_segment_overrun
+ jmp error_code
+
+_reserved:
+ pushl $0
+ pushl $_do_reserved
+ jmp error_code
+
+_double_fault:
+ pushl $_do_double_fault
+ jmp error_code
+
+_invalid_TSS:
+ pushl $_do_invalid_TSS
+ jmp error_code
+
+_segment_not_present:
+ pushl $_do_segment_not_present
+ jmp error_code
+
+_stack_segment:
+ pushl $_do_stack_segment
+ jmp error_code
+
+_general_protection:
+ pushl $_do_general_protection
+ jmp error_code
+
+_alignment_check:
+ pushl $_do_alignment_check
+ jmp error_code
+
+_page_fault:
+ pushl $_do_page_fault
+ jmp error_code
+++ /dev/null
-/*
- * linux/kernel/system_call.s
- *
- * (C) 1991 Linus Torvalds
- */
-
-/*
- * system_call.s contains the system-call low-level handling routines.
- * This also contains the timer-interrupt handler, as some of the code is
- * the same. The hd- and flopppy-interrupts are also here.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call. Ordinary interrupts
- * don't handle signal-recognition, as that would clutter them up totally
- * unnecessarily.
- *
- * Stack layout in 'ret_from_system_call':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in fork.c:copy_process, signal.c:do_signal,
- * ptrace.c ptrace.h
- *
- * 0(%esp) - %ebx
- * 4(%esp) - %ecx
- * 8(%esp) - %edx
- * C(%esp) - %esi
- * 10(%esp) - %edi
- * 14(%esp) - %ebp
- * 18(%esp) - %eax
- * 1C(%esp) - %ds
- * 20(%esp) - %es
- * 24(%esp) - %fs
- * 28(%esp) - %gs
- * 2C(%esp) - orig_eax
- * 30(%esp) - %eip
- * 34(%esp) - %cs
- * 38(%esp) - %eflags
- * 3C(%esp) - %oldesp
- * 40(%esp) - %oldss
- */
-
-SIG_CHLD = 17
-
-EBX = 0x00
-ECX = 0x04
-EDX = 0x08
-ESI = 0x0C
-EDI = 0x10
-EBP = 0x14
-EAX = 0x18
-DS = 0x1C
-ES = 0x20
-FS = 0x24
-GS = 0x28
-ORIG_EAX = 0x2C
-EIP = 0x30
-CS = 0x34
-EFLAGS = 0x38
-OLDESP = 0x3C
-OLDSS = 0x40
-
-state = 0 # these are offsets into the task-struct.
-counter = 4
-priority = 8
-signal = 12
-sigaction = 16 # MUST be 16 (=len of sigaction)
-blocked = (33*16)
-
-# offsets within sigaction
-sa_handler = 0
-sa_mask = 4
-sa_flags = 8
-sa_restorer = 12
-
-nr_system_calls = 82
-
-ENOSYS = 38
-
-/*
- * Ok, I get parallel printer interrupts while using the floppy for some
- * strange reason. Urgel. Now I just ignore them.
- */
-.globl _system_call,_timer_interrupt,_sys_execve
-.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
-.globl _device_not_available, _coprocessor_error
-
-.align 2
-bad_sys_call:
- pushl $-ENOSYS
- jmp ret_from_sys_call
-.align 2
-reschedule:
- pushl $ret_from_sys_call
- jmp _schedule
-.align 2
-_system_call:
- cld
- pushl %eax # save orig_eax
- push %gs
- push %fs
- push %es
- push %ds
- pushl %eax # save eax. The return value will be put here.
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx # push %ebx,%ecx,%edx as parameters
- pushl %ebx # to the system call
- movl $0x10,%edx # set up ds,es to kernel space
- mov %dx,%ds
- mov %dx,%es
- movl $0x17,%edx # fs points to local data space
- mov %dx,%fs
- cmpl _NR_syscalls,%eax
- jae bad_sys_call
- call _sys_call_table(,%eax,4)
- movl %eax,EAX(%esp) # save the return value
-2: movl _current,%eax
- cmpl $0,state(%eax) # state
- jne reschedule
- cmpl $0,counter(%eax) # counter
- je reschedule
-ret_from_sys_call:
- movl _current,%eax
- cmpl _task,%eax # task[0] cannot have signals
- je 3f
- cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
- jne 3f
- cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
- jne 3f
- movl signal(%eax),%ebx
- movl blocked(%eax),%ecx
- notl %ecx
- andl %ebx,%ecx
- bsfl %ecx,%ecx
- je 3f
- btrl %ecx,%ebx
- movl %ebx,signal(%eax)
- incl %ecx
- pushl %ecx
- call _do_signal
- popl %ecx
- testl %eax, %eax
- jne 2b # see if we need to switch tasks, or do more signals
-3:
- popl %ebx
- popl %ecx
- popl %edx
- popl %esi
- popl %edi
- popl %ebp
- popl %eax
- pop %ds
- pop %es
- pop %fs
- pop %gs
- addl $4,%esp # skip the orig_eax
- iret
-
-.align 2
-_coprocessor_error:
- cld
- pushl $-1 # mark this as an int.
- push %gs
- push %fs
- push %es
- push %ds
- pushl %eax # save eax.
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx
- pushl %ebx
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- pushl $ret_from_sys_call
- jmp _math_error
-
-.align 2
-_device_not_available:
- cld
- pushl $-1 # mark this as an int
- push %gs
- push %fs
- push %es
- push %ds
- pushl %eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx
- pushl %ebx
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- pushl $ret_from_sys_call
- clts # clear TS so that we can use math
- movl %cr0,%eax
- testl $0x4,%eax # EM (math emulation bit)
- je _math_state_restore
- pushl $0 # temporary storage for ORIG_EIP
- call _math_emulate
- addl $4,%esp
- ret
-
-.align 2
-_timer_interrupt:
- cld
- pushl $-1 # mark this as an int
- push %gs
- push %fs
- push %es
- push %ds
- pushl %eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx
- pushl %ebx
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- incl _jiffies
- movb $0x20,%al # EOI to interrupt controller #1
- outb %al,$0x20
- movl CS(%esp),%eax
- andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
- pushl %eax
- call _do_timer # 'do_timer(long CPL)' does everything from
- addl $4,%esp # task switching to accounting ...
- jmp ret_from_sys_call
-
-.align 2
-_sys_execve:
- lea (EIP+4)(%esp),%eax # don't forget about the return address.
- pushl %eax
- call _do_execve
- addl $4,%esp
- ret
-
-_hd_interrupt:
- cld
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- movb $0x20,%al
- outb %al,$0xA0 # EOI to interrupt controller #1
- jmp 1f # give port chance to breathe
-1: jmp 1f
-1: outb %al,$0x20
- andl $0xfffeffff,_timer_active
- xorl %edx,%edx
- xchgl _do_hd,%edx
- testl %edx,%edx
- jne 1f
- movl $_unexpected_hd_interrupt,%edx
-1: call *%edx # "interesting" way of handling intr.
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-
-_floppy_interrupt:
- cld
- pushl %eax
- pushl %ecx
- pushl %edx
- push %ds
- push %es
- push %fs
- movl $0x10,%eax
- mov %ax,%ds
- mov %ax,%es
- movl $0x17,%eax
- mov %ax,%fs
- movb $0x20,%al
- outb %al,$0x20 # EOI to interrupt controller #1
- xorl %eax,%eax
- xchgl _do_floppy,%eax
- testl %eax,%eax
- jne 1f
- movl $_unexpected_floppy_interrupt,%eax
-1: call *%eax # "interesting" way of handling intr.
- pop %fs
- pop %es
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- iret
-
-_parallel_interrupt:
- cld
- pushl %eax
- movb $0x20,%al
- outb %al,$0x20
- popl %eax
- iret
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
*/
-#include <string.h>
+#include <linux/string.h>
#include <linux/head.h>
#include <linux/sched.h>
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)
{
for(i=0;i<10;i++)
printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
printk("\n\r");
- do_exit(11); /* play segment exception */
+ if ((0xffff & esp[1]) == 0xf)
+ send_sig(SIGSEGV, current, 0);
+ else
+ do_exit(SIGSEGV);
}
void do_double_fault(long esp, long error_code)
void do_alignment_check(long esp, long error_code)
{
- die("alignment check",esp,error_code);
+ die("alignment check",esp,error_code);
}
void do_divide_error(long esp, long error_code)
void do_debug(long esp, long error_code)
{
- send_sig(SIGTRAP, current, 0);
+ send_sig(SIGTRAP, current, 0);
}
void do_overflow(long esp, long error_code)
*/
#include <stdarg.h>
-#include <string.h>
+#include <linux/string.h>
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
LD =ld
LDFLAGS =-s -x
CC =gcc -nostdinc -I../include
-CPP =cpp -nostdinc -I../include
+CPP =gcc -E -nostdinc -I../include
.c.s:
$(CC) $(CFLAGS) \
cp tmp_make Makefile
### Dependencies:
-_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
-close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
-ctype.s ctype.o : ctype.c ../include/ctype.h
-dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
+_exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
+close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
+ctype.s ctype.o : ctype.c ../include/linux/ctype.h
+dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
errno.s errno.o : errno.c
-execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
-malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \
+execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
+malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h ../include/linux/fs.h \
+ ../include/sys/types.h ../include/sys/dirent.h ../include/limits.h ../include/signal.h \
../include/asm/system.h
-open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h ../include/stdarg.h
-setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
-string.s string.o : string.c ../include/string.h
-wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h ../include/sys/wait.h
-write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \
- ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \
- ../include/utime.h
+open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h \
+ ../include/stdarg.h
+setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
+string.s string.o : string.c ../include/linux/string.h
+wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h \
+ ../include/sys/wait.h
+write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/times.h ../include/sys/utsname.h \
+ ../include/sys/param.h ../include/sys/resource.h ../include/utime.h ../include/linux/unistd.h
#include <unistd.h>
_syscall1(int,close,int,fd)
+
* (C) 1991 Linus Torvalds
*/
-#include <ctype.h>
+#include <linux/ctype.h>
char _ctmp;
unsigned char _ctype[] = {0x00, /* EOF */
#include <unistd.h>
_syscall1(int,dup,int,fd)
+
#include <unistd.h>
_syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+
#include <unistd.h>
_syscall0(pid_t,setsid)
+
#define extern
#define inline
#define __LIBRARY__
-#include <string.h>
+#include <linux/string.h>
{
return waitpid(-1,wait_stat,0);
}
+
#include <unistd.h>
_syscall3(int,write,int,fd,const char *,buf,off_t,count)
+
$(CC) $(CFLAGS) \
-S -o $*.s $<
-OBJS = memory.o swap.o
+OBJS = memory.o swap.o mmap.o
mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS)
cp tmp_make Makefile
### Dependencies:
-memory.o : memory.c ../include/signal.h ../include/sys/types.h \
- ../include/asm/system.h ../include/linux/sched.h ../include/linux/head.h \
- ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
- ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
+memory.o : memory.c ../include/signal.h ../include/sys/types.h ../include/asm/system.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
../include/sys/time.h ../include/time.h ../include/sys/resource.h
-swap.o : swap.c ../include/string.h ../include/errno.h \
- ../include/linux/mm.h ../include/linux/fs.h ../include/sys/types.h \
- ../include/sys/dirent.h ../include/limits.h ../include/linux/kernel.h \
- ../include/signal.h ../include/sys/stat.h ../include/linux/sched.h \
- ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h \
- ../include/time.h ../include/sys/resource.h
+mmap.o : mmap.c ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/mm.h ../include/linux/kernel.h ../include/signal.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/segment.h \
+ ../include/asm/system.h ../include/errno.h ../include/sys/mman.h
+swap.o : swap.c ../include/errno.h ../include/sys/stat.h ../include/sys/types.h \
+ ../include/linux/mm.h ../include/linux/fs.h ../include/sys/dirent.h ../include/limits.h \
+ ../include/linux/kernel.h ../include/signal.h ../include/linux/string.h ../include/linux/sched.h \
+ ../include/linux/head.h ../include/sys/param.h ../include/sys/time.h ../include/time.h \
+ ../include/sys/resource.h
return 0;
}
+/*
+ * a more complete version of free_page_tables which performs with page
+ * granularity.
+ */
+int
+unmap_page_range(unsigned long from, unsigned long size)
+{
+ unsigned long page, page_dir;
+ unsigned long *page_table, *dir;
+ unsigned long poff, pcnt, pc;
+
+ if (from & 0xfff)
+ panic("unmap_page_range called with wrong alignment");
+ if (!from)
+ panic("unmap_page_range trying to free swapper memory space");
+ size = (size + 0xfff) >> 12;
+ dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
+ poff = (from >> 12) & 0x3ff;
+ if ((pcnt = 1024 - poff) > size)
+ pcnt = size;
+
+ for ( ; size > 0; ++dir, size -= pcnt,
+ pcnt = (size > 1024 ? 1024 : size)) {
+ if (!(page_dir = *dir)) {
+ poff = 0;
+ continue;
+ }
+ if (!(page_dir & 1)) {
+ printk("unmap_page_range: bad page directory.");
+ continue;
+ }
+ page_table = (unsigned long *)(0xfffff000 & page_dir);
+ if (poff) {
+ page_table += poff;
+ poff = 0;
+ }
+ for (pc = pcnt; pc--; page_table++) {
+ if (page = *page_table) {
+ --current->rss;
+ *page_table = 0;
+ if (1 & page)
+ free_page(0xfffff000 & page);
+ else
+ swap_free(page >> 1);
+ }
+ }
+ if (pcnt == 1024) {
+ free_page(0xfffff000 & page_dir);
+ *dir = 0;
+ }
+ }
+ invalidate();
+ for (page = 0; page < CHECK_LAST_NR ; page++)
+ last_pages[page] = 0;
+ return 0;
+}
+
+/*
+ * maps a range of physical memory into the requested pages. the old
+ * mappings are removed. any references to nonexistent pages results
+ * in null mappings (currently treated as "copy-on-access")
+ *
+ * permiss is encoded as cxwr (copy,exec,write,read) where copy modifies
+ * the behavior of write to be copy-on-write.
+ *
+ * due to current limitations, we actually have the following
+ * on off
+ * read: yes yes
+ * write/copy: yes/copy copy/copy
+ * exec: yes yes
+ */
+int
+remap_page_range(unsigned long from, unsigned long to, unsigned long size,
+ int permiss)
+{
+ unsigned long *page_table, *dir;
+ unsigned long poff, pcnt;
+
+ if ((from & 0xfff) || (to & 0xfff))
+ panic("remap_page_range called with wrong alignment");
+ dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
+ size = (size + 0xfff) >> 12;
+ poff = (from >> 12) & 0x3ff;
+ if ((pcnt = 1024 - poff) > size)
+ pcnt = size;
+
+ while (size > 0) {
+ if (!(1 & *dir)) {
+ if (!(page_table = (unsigned long *)get_free_page())) {
+ invalidate();
+ return -1;
+ }
+ *dir++ = ((unsigned long) page_table) | 7;
+ }
+ else
+ page_table = (unsigned long *)(0xfffff000 & *dir++);
+ if (poff) {
+ page_table += poff;
+ poff = 0;
+ }
+
+ for (size -= pcnt; pcnt-- ;) {
+ int mask;
+
+ mask = 4;
+ if (permiss & 1)
+ mask |= 1;
+ if (permiss & 2) {
+ if (permiss & 8)
+ mask |= 1;
+ else
+ mask |= 3;
+ }
+ if (permiss & 4)
+ mask |= 1;
+
+ if (*page_table) {
+ --current->rss;
+ if (1 & *page_table)
+ free_page(0xfffff000 & *page_table);
+ else
+ swap_free(*page_table >> 1);
+ }
+
+ /*
+ * i'm not sure of the second cond here. should we
+ * report failure?
+ * the first condition should return an invalid access
+ * when the page is referenced. current assumptions
+ * cause it to be treated as demand allocation.
+ */
+ if (mask == 4 || to >= HIGH_MEMORY)
+ *page_table++ = 0; /* not present */
+ else {
+ ++current->rss;
+ *page_table++ = (to | mask);
+ if (to > LOW_MEM) {
+ unsigned long frame;
+ frame = to - LOW_MEM;
+ frame >>= 12;
+ mem_map[frame]++;
+ }
+ }
+ to += PAGE_SIZE;
+ }
+ pcnt = (size > 1024 ? 1024 : size);
+ }
+ invalidate();
+ for (to = 0; to < CHECK_LAST_NR ; to++)
+ last_pages[to] = 0;
+ return 0;
+}
+
/*
* This function puts a page in memory at the wanted address.
* It returns the physical address of the page gotten, 0 if
return 0;
}
if (mem_map[(page-LOW_MEM)>>12] != 1) {
- printk("mem_map disagrees with %p at %p\n",page,address);
+ printk("put_page: mem_map disagrees with %p at %p\n",page,address);
return 0;
}
page_table = (unsigned long *) ((address>>20) & 0xffc);
static int share_page(struct inode * inode, unsigned long address)
{
struct task_struct ** p;
+ int i;
if (inode->i_count < 2 || !inode)
return 0;
if (inode != (*p)->executable)
continue;
} else {
- if (inode != (*p)->library)
+ for (i=0; i < (*p)->numlibraries; i++)
+ if (inode == (*p)->libraries[i].library)
+ break;
+ if (i >= (*p)->numlibraries)
continue;
}
if (try_to_share(address,*p))
return 0;
}
+/*
+ * fill in an empty page or directory if none exists
+ */
+static unsigned long get_empty(unsigned long * p)
+{
+ unsigned long page = 0;
+
+repeat:
+ if (1 & *p) {
+ free_page(page);
+ return *p;
+ }
+ if (*p) {
+ printk("get_empty: bad page entry \n");
+ *p = 0;
+ }
+ if (page) {
+ *p = page | 7;
+ return *p;
+ }
+ if (!(page = get_free_page()))
+ oom();
+ goto repeat;
+}
+
void do_no_page(unsigned long error_code, unsigned long address,
- struct task_struct *tsk)
+ struct task_struct *tsk, unsigned long user_esp)
{
static unsigned int last_checked = 0;
int nr[4];
unsigned long tmp;
unsigned long page;
- int block,i;
+ unsigned int block,i;
struct inode * inode;
/* Thrashing ? Make it interruptible, but don't penalize otherwise */
printk("Bad things happen: nonexistent page error in do_no_page\n\r");
do_exit(SIGSEGV);
}
+ page = get_empty((unsigned long *) ((address >> 20) & 0xffc));
+ page &= 0xfffff000;
+ page += (address >> 10) & 0xffc;
+ tmp = *(unsigned long *) page;
+ if (tmp & 1) {
+ printk("bogus do_no_page\n");
+ return;
+ }
++tsk->rss;
- page = *(unsigned long *) ((address >> 20) & 0xffc);
-/* check the page directory: make a page dir entry if no such exists */
- if (page & 1) {
- page &= 0xfffff000;
- page += (address >> 10) & 0xffc;
- tmp = *(unsigned long *) page;
- if (tmp && !(1 & tmp)) {
- ++tsk->maj_flt;
- swap_in((unsigned long *) page);
- return;
- }
- } else {
- if (page)
- printk("do_no_page: bad page directory\n");
- if (!(page = get_free_page()))
- oom();
- page |= 7;
- *(unsigned long *) ((address >> 20) & 0xffc) = page;
+ if (tmp) {
+ ++tsk->maj_flt;
+ swap_in((unsigned long *) page);
+ return;
}
address &= 0xfffff000;
tmp = address - tsk->start_code;
- if (tmp >= LIBRARY_OFFSET ) {
- inode = tsk->library;
- block = 1 + (tmp-LIBRARY_OFFSET) / BLOCK_SIZE;
- } else if (tmp < tsk->end_data) {
+ inode = NULL;
+ block = 0;
+ if (tmp < tsk->end_data) {
inode = tsk->executable;
block = 1 + tmp / BLOCK_SIZE;
} else {
- inode = NULL;
- block = 0;
+ i = tsk->numlibraries;
+ while (i-- > 0) {
+ if (tmp < tsk->libraries[i].start)
+ continue;
+ block = tmp - tsk->libraries[i].start;
+ if (block >= tsk->libraries[i].length)
+ continue;
+ inode = tsk->libraries[i].library;
+ block = 1 + block / BLOCK_SIZE;
+ break;
+ }
}
if (!inode) {
++tsk->min_flt;
- if (tmp > tsk->brk && tsk == current &&
- LIBRARY_OFFSET - tmp > tsk->rlim[RLIMIT_STACK].rlim_max)
- do_exit(SIGSEGV);
get_empty_page(address);
+ if (tsk != current)
+ return;
+ if (tmp >= LIBRARY_OFFSET || tmp < tsk->brk)
+ return;
+ if (tmp+8192 >= (user_esp & 0xfffff000))
+ return;
+ send_sig(SIGSEGV,tsk,1);
return;
}
if (tsk == current)
++tsk->maj_flt;
if (!(page = get_free_page()))
oom();
-/* remember that 1 block is used for header */
for (i=0 ; i<4 ; block++,i++)
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
if (i>4095)
i = 0;
tmp = page + 4096;
- while (i-- > 0) {
+ while (i--) {
tmp--;
*(char *)tmp = 0;
}
int i,j,k,free=0,total=0;
int shared = 0;
unsigned long * pg_tbl;
- static int lock = 0;
- cli();
- if (lock) {
- sti();
- return;
- }
- lock = 1;
- sti();
printk("Mem-info:\n\r");
for(i=0 ; i<PAGING_PAGES ; i++) {
if (mem_map[i] == USED)
}
}
printk("Memory found: %d (%d)\n\r",free-shared,total);
- lock = 0;
}
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);
--- /dev/null
+/*
+ * linux/mm/mmap.c
+ *
+ * Written by obz.
+ */
+#include <sys/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+/*
+ * description of effects of mapping type and prot in current implementation.
+ * this is due to the current handling of page faults in memory.c. the expected
+ * behavior is in parens:
+ *
+ * map_type prot
+ * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC
+ * MAP_SHARED r: (no) yes r: (yes) yes r: (no) yes r: (no) no
+ * w: (no) yes w: (no) copy w: (yes) yes w: (no) no
+ * x: (no) no x: (no) no x: (no) no x: (yes) no
+ *
+ * MAP_PRIVATE r: (no) yes r: (yes) yes r: (no) yes r: (no) no
+ * w: (no) copy w: (no) copy w: (copy) copy w: (no) no
+ * x: (no) no x: (no) no x: (no) no x: (yes) no
+ *
+ * the permissions are encoded as cxwr (copy,exec,write,read)
+ */
+#define MTYP(T) ((T) & MAP_TYPE)
+#define PREAD(T,P) (((P) & PROT_READ) ? 1 : 0)
+#define PWRITE(T,P) (((P) & PROT_WRITE) ? (MTYP(T) == MAP_SHARED ? 2 : 10) : 0)
+#define PEXEC(T,P) (((P) & PROT_EXEC) ? 4 : 0)
+#define PERMISS(T,P) (PREAD(T,P)|PWRITE(T,P)|PEXEC(T,P))
+
+#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
+ current->start_code + current->end_code)
+
+extern int remap_page_range(unsigned long from, unsigned long to,
+ unsigned long size, int permiss);
+extern int unmap_page_range(unsigned long from, unsigned long size);
+
+static caddr_t
+mmap_chr(unsigned long addr, size_t len, int prot, int flags,
+ struct inode *inode, unsigned long off)
+{
+ int major, minor;
+ extern unsigned long HIGH_MEMORY;
+
+ major = MAJOR(inode->i_rdev);
+ minor = MINOR(inode->i_rdev);
+
+ /*
+ * for character devices, only /dev/mem may be mapped. when the
+ * swapping code is modified to allow arbitrary sources of pages,
+ * then we can open it up to regular files.
+ */
+
+ if (major != 1 || minor != 1)
+ return (caddr_t)-ENODEV;
+
+ /*
+ * we only allow mappings from address 0 to HIGH_MEMORY, since thats
+ * the range of our memory [actually this is a lie. the buffer cache
+ * and ramdisk occupy higher memory, but the paging stuff won't
+ * let us map to it anyway, so we break it here].
+ *
+ * this call is very dangerous! because of the lack of adequate
+ * tagging of frames, it is possible to mmap over a frame belonging
+ * to another (innocent) process. with MAP_SHARED|MAP_WRITE, this
+ * rogue process can trample over the other's data! we ignore this :{
+ * for now, we hope people will malloc the required amount of space,
+ * then mmap over it. the mm needs serious work before this can be
+ * truly useful.
+ */
+
+ if (len > HIGH_MEMORY || off > HIGH_MEMORY - len) /* avoid overflow */
+ return (caddr_t)-ENXIO;
+
+ if (remap_page_range(addr, off, len, PERMISS(flags, prot)))
+ return (caddr_t)-EAGAIN;
+
+ return (caddr_t)addr;
+}
+
+caddr_t
+sys_mmap(unsigned long *buffer)
+{
+ unsigned long base, addr;
+ unsigned long len, limit, off;
+ int prot, flags, fd;
+ struct file *file;
+ struct inode *inode;
+
+ addr = (unsigned long) get_fs_long(buffer); /* user address space*/
+ len = (size_t) get_fs_long(buffer+1); /* nbytes of mapping */
+ prot = (int) get_fs_long(buffer+2); /* protection */
+ flags = (int) get_fs_long(buffer+3); /* mapping type */
+ fd = (int) get_fs_long(buffer+4); /* object to map */
+ off = (unsigned long) get_fs_long(buffer+5); /* offset in object */
+
+ if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
+ return (caddr_t) -EBADF;
+ if (addr > TASK_SIZE || (addr+(unsigned long) len) > TASK_SIZE)
+ return (caddr_t) -EINVAL;
+ inode = file->f_inode;
+
+ /*
+ * do simple checking here so the lower-level routines won't have
+ * to. we assume access permissions have been handled by the open
+ * of the memory object, so we don't do any here.
+ */
+
+ switch (flags & MAP_TYPE) {
+ case MAP_SHARED:
+ if ((prot & PROT_WRITE) && !(file->f_mode & 2))
+ return (caddr_t)-EINVAL;
+ /* fall through */
+ case MAP_PRIVATE:
+ if (!(file->f_mode & 1))
+ return (caddr_t)-EINVAL;
+ break;
+
+ default:
+ return (caddr_t)-EINVAL;
+ }
+
+ /*
+ * obtain the address to map to. we verify (or select) it and ensure
+ * that it represents a valid section of the address space. we assume
+ * that if PROT_EXEC is specified this should be in the code segment.
+ */
+ if (prot & PROT_EXEC) {
+ base = get_base(current->ldt[1]); /* cs */
+ limit = get_limit(0x0f); /* cs limit */
+ } else {
+ base = get_base(current->ldt[2]); /* ds */
+ limit = get_limit(0x17); /* ds limit */
+ }
+
+ if (flags & MAP_FIXED) {
+ /*
+ * if MAP_FIXED is specified, we have to map exactly at this
+ * address. it must be page aligned and not ambiguous.
+ */
+ if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
+ (off & 0xfff))
+ return (caddr_t)-EINVAL;
+ if (addr + len > limit)
+ return (caddr_t)-ENOMEM;
+ } else {
+ /*
+ * we're given a hint as to where to put the address.
+ * that we still need to search for a range of pages which
+ * are not mapped and which won't impact the stack or data
+ * segment.
+ * in linux, we only have a code segment and data segment.
+ * since data grows up and stack grows down, we're sort of
+ * stuck. placing above the data will break malloc, below
+ * the stack will cause stack overflow. because of this
+ * we don't allow nonspecified mappings...
+ */
+ return (caddr_t)-ENOMEM;
+ }
+
+ /*
+ * determine the object being mapped and call the appropriate
+ * specific mapper. the address has already been validated, but
+ * not unmapped
+ */
+ if (S_ISCHR(inode->i_mode))
+ addr = (unsigned long)mmap_chr(base + addr, len, prot, flags,
+ inode, off);
+ else
+ addr = (unsigned long)-ENODEV;
+ if ((long)addr > 0)
+ addr -= base;
+
+ return (caddr_t)addr;
+}
+
+int sys_munmap(unsigned long addr, size_t len)
+{
+ unsigned long base, limit;
+
+ base = get_base(current->ldt[2]); /* map into ds */
+ limit = get_limit(0x17); /* ds limit */
+
+ if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
+ addr + len > limit)
+ return -EINVAL;
+ if (unmap_page_range(base + addr, len))
+ return -EAGAIN; /* should never happen */
+ return 0;
+}
* Started 18.12.91
*/
-#include <string.h>
#include <errno.h>
+#include <sys/stat.h>
#include <linux/mm.h>
-#include <sys/stat.h>
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
/*
* Go through the page tables, searching for a user page that
* we can swap out.
+ *
+ * Here it's easy to add a check for tasks that may not be swapped out:
+ * loadable device drivers or similar. Just add an entry to the task-struct
+ * and check it at the same time you check for the existence of the task.
+ * The code assumes tasks are page-table aligned, but so do other parts
+ * of the memory manager...
*/
int swap_out(void)
{
static int page_entry = -1;
int counter = VM_PAGES;
int pg_table;
+ struct task_struct * p;
check_dir:
if (counter < 0)
goto no_swap;
if (dir_entry >= 1024)
dir_entry = FIRST_VM_PAGE>>10;
+ if (!(p = task[dir_entry >> 4])) {
+ counter -= 1024;
+ dir_entry++;
+ goto check_dir;
+ }
if (!(1 & (pg_table = pg_dir[dir_entry]))) {
if (pg_table) {
printk("bad page-table at pg_dir[%d]: %08x\n\r",
goto check_dir;
}
if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
- if (! task[dir_entry >> 4])
- printk("swapping out page from non-existent task\n\r");
- else
- task[dir_entry >> 4]->rss--;
+ p->rss--;
return 1;
}
goto check_table;
*
* The swapon system call
*/
-
int sys_swapon(const char * specialfile)
{
struct inode * swap_inode;
+ char * tmp;
int i,j;
if (!suser())
iput(swap_inode);
return -EINVAL;
}
- swap_bitmap = (char *) get_free_page();
- if (!swap_bitmap) {
+ tmp = (char *) get_free_page();
+ if (!tmp) {
iput(swap_file);
swap_device = 0;
swap_file = NULL;
printk("Unable to start swapping: out of memory :-)\n");
return -ENOMEM;
}
- read_swap_page(0,swap_bitmap);
- if (strncmp("SWAP-SPACE",swap_bitmap+4086,10)) {
+ read_swap_page(0,tmp);
+ if (strncmp("SWAP-SPACE",tmp+4086,10)) {
printk("Unable to find swap-space signature\n\r");
- free_page((long) swap_bitmap);
+ free_page((long) tmp);
iput(swap_file);
swap_device = 0;
swap_file = NULL;
swap_bitmap = NULL;
return -EINVAL;
}
- memset(swap_bitmap+4086,0,10);
+ memset(tmp+4086,0,10);
j = 0;
for (i = 1 ; i < SWAP_BITS ; i++)
- if (bit(swap_bitmap,i))
+ if (bit(tmp,i))
j++;
if (!j) {
printk("Empty swap-file\n");
- free_page((long) swap_bitmap);
+ free_page((long) tmp);
iput(swap_file);
swap_device = 0;
swap_file = NULL;
swap_bitmap = NULL;
return -EINVAL;
}
+ swap_bitmap = tmp;
printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
return 0;
}
--- /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...
+
+AS =as
+AR =ar
+LD =ld
+CC =gcc -nostdinc -I../include -Wall # -DSOCK_DEBUG
+CPP =cpp -nostdinc -I../include
+
+.c.o:
+ $(CC) $(CFLAGS) \
+ -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.s:
+ $(CC) $(CFLAGS) \
+ -S -o $*.s $<
+
+OBJS = socket.o unix.o
+
+net.o: $(OBJS)
+ $(LD) -r -o net.o $(OBJS)
+
+clean:
+ rm -f core *.o *.a tmp_make
+ for i in *.c;do rm -f `basename $$i .c`.s;done
+
+dep:
+ sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
+ (for i in *.c;do $(CPP) -M $$i;done) >> tmp_make
+ cp tmp_make Makefile
+
+### Dependencies:
+socket.o : socket.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+ ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h ../include/sys/dirent.h \
+ ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h ../include/sys/param.h \
+ ../include/sys/time.h ../include/time.h ../include/sys/resource.h ../include/asm/system.h \
+ ../include/asm/segment.h ../include/sys/socket.h ../include/sys/stat.h ../include/fcntl.h \
+ ../include/termios.h kern_sock.h socketcall.h
+unix.o : unix.c ../include/signal.h ../include/sys/types.h ../include/errno.h \
+ ../include/linux/string.h ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \
+ ../include/sys/dirent.h ../include/limits.h ../include/linux/mm.h ../include/linux/kernel.h \
+ ../include/sys/param.h ../include/sys/time.h ../include/time.h ../include/sys/resource.h \
+ ../include/asm/system.h ../include/asm/segment.h ../include/sys/socket.h ../include/sys/un.h \
+ ../include/sys/stat.h ../include/fcntl.h ../include/termios.h kern_sock.h
--- /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 task_struct **wait; /* ptr to place to wait on */
+ void *dummy;
+};
+
+struct proto_ops {
+ int (*init)(void);
+ int (*create)(struct socket *sock, int protocol);
+ int (*dup)(struct socket *newsock, struct socket *oldsock);
+ int (*release)(struct socket *sock, struct socket *peer);
+ int (*bind)(struct socket *sock, struct sockaddr *umyaddr,
+ int sockaddr_len);
+ int (*connect)(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len);
+ int (*socketpair)(struct socket *sock1, struct socket *sock2);
+ int (*accept)(struct socket *sock, struct socket *newsock);
+ int (*getname)(struct socket *sock, struct sockaddr *uaddr,
+ int *usockaddr_len, int peer);
+ int (*read)(struct socket *sock, char *ubuf, int size, int nonblock);
+ int (*write)(struct socket *sock, char *ubuf, int size, int nonblock);
+ int (*select)(struct socket *sock, int which);
+ int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
+};
+
+extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
+
+#ifdef SOCK_DEBUG
+#define PRINTK printk
+#else
+#define PRINTK (void)
+#endif
+
+#endif /* _KERN_SOCK_H */
--- /dev/null
+#include <signal.h>
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "kern_sock.h"
+#include "socketcall.h"
+
+extern int sys_close(int fd);
+
+extern struct proto_ops unix_proto_ops;
+
+static struct {
+ short family;
+ char *name;
+ struct proto_ops *ops;
+} proto_table[] = {
+ AF_UNIX, "AF_UNIX", &unix_proto_ops
+};
+#define NPROTO (sizeof(proto_table) / sizeof(proto_table[0]))
+
+static char *
+family_name(int family)
+{
+ int i;
+
+ for (i = 0; i < NPROTO; ++i)
+ if (proto_table[i].family == family)
+ return proto_table[i].name;
+ return "UNKNOWN";
+}
+
+static int sock_lseek(struct inode *inode, struct file *file, off_t offset,
+ int whence);
+static int sock_read(struct inode *inode, struct file *file, char *buf,
+ int size);
+static int sock_write(struct inode *inode, struct file *file, char *buf,
+ int size);
+static int sock_readdir(struct inode *inode, struct file *file,
+ struct dirent *dirent, int count);
+static void sock_close(struct inode *inode, struct file *file);
+/*static*/ int sock_select(struct inode *inode, struct file *file, int which,
+ select_table *seltable);
+static int sock_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned int arg);
+
+static struct file_operations socket_file_ops = {
+ sock_lseek,
+ sock_read,
+ sock_write,
+ sock_readdir,
+ sock_select, /* not in vfs yet */
+ sock_ioctl,
+ NULL, /* no special open code... */
+ sock_close
+};
+
+#define SOCK_INODE(S) ((struct inode *)(S)->dummy)
+
+static struct socket sockets[NSOCKETS];
+#define last_socket (sockets + NSOCKETS - 1)
+static struct task_struct *socket_wait_free = NULL;
+
+/*
+ * obtains the first available file descriptor and sets it up for use
+ */
+static int
+get_fd(struct inode *inode)
+{
+ int fd, i;
+ struct file *file;
+
+ /*
+ * find a file descriptor suitable for return to the user.
+ */
+ for (fd = 0; fd < NR_OPEN; ++fd)
+ if (!current->filp[fd])
+ break;
+ if (fd == NR_OPEN)
+ return -1;
+ current->close_on_exec &= ~(1 << fd);
+ for (file = file_table, i = 0; i < NR_FILE; ++i, ++file)
+ if (!file->f_count)
+ break;
+ if (i == NR_FILE)
+ return -1;
+ current->filp[fd] = file;
+ file->f_op = &socket_file_ops;
+ file->f_mode = 3;
+ file->f_flags = 0;
+ file->f_count = 1;
+ file->f_inode = inode;
+ file->f_pos = 0;
+ return fd;
+}
+
+/*
+ * reverses the action of get_fd() by releasing the file. it closes the
+ * descriptor, but makes sure it does nothing more. called when an incomplete
+ * socket must be closed, along with sock_release().
+ */
+static inline void
+toss_fd(int fd)
+{
+ current->filp[fd]->f_inode = NULL; /* safe from iput */
+ sys_close(fd);
+}
+
+static inline struct socket *
+socki_lookup(struct inode *inode)
+{
+ struct socket *sock;
+
+ for (sock = sockets; sock <= last_socket; ++sock)
+ if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)
+ return sock;
+ return NULL;
+}
+
+static inline struct socket *
+sockfd_lookup(int fd, struct file **pfile)
+{
+ struct file *file;
+
+ if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd]))
+ return NULL;
+ if (pfile)
+ *pfile = file;
+ return socki_lookup(file->f_inode);
+}
+
+static struct socket *
+sock_alloc(int wait)
+{
+ struct socket *sock;
+
+ while (1) {
+ cli();
+ for (sock = sockets; sock <= last_socket; ++sock)
+ if (sock->state == SS_FREE) {
+ sock->state = SS_UNCONNECTED;
+ sti();
+ sock->flags = 0;
+ sock->ops = NULL;
+ sock->data = NULL;
+ sock->conn = NULL;
+ sock->iconn = NULL;
+ /*
+ * this really shouldn't be necessary, but
+ * everything else depends on inodes, so we
+ * grab it.
+ * sleeps are also done on the i_wait member
+ * of this inode.
+ * the close system call will iput this inode
+ * for us.
+ */
+ if (!(SOCK_INODE(sock) = get_empty_inode())) {
+ printk("sock_alloc: no more inodes\n");
+ sock->state = SS_FREE;
+ return NULL;
+ }
+ SOCK_INODE(sock)->i_mode = S_IFSOCK;
+ sock->wait = &SOCK_INODE(sock)->i_wait;
+ PRINTK("sock_alloc: socket 0x%x, inode 0x%x\n",
+ sock, SOCK_INODE(sock));
+ return sock;
+ }
+ sti();
+ if (!wait)
+ return NULL;
+ PRINTK("sock_alloc: no free sockets, sleeping...\n");
+ interruptible_sleep_on(&socket_wait_free);
+ if (current->signal & ~current->blocked) {
+ PRINTK("sock_alloc: sleep was interrupted\n");
+ return NULL;
+ }
+ PRINTK("sock_alloc: wakeup... trying again...\n");
+ }
+}
+
+static inline void
+sock_release_peer(struct socket *peer)
+{
+ peer->state = SS_DISCONNECTING;
+ wake_up(peer->wait);
+}
+
+static void
+sock_release(struct socket *sock)
+{
+ int oldstate;
+ struct socket *peersock, *nextsock;
+
+ PRINTK("sock_release: socket 0x%x, inode 0x%x\n", sock,
+ SOCK_INODE(sock));
+ if ((oldstate = sock->state) != SS_UNCONNECTED)
+ sock->state = SS_DISCONNECTING;
+ /*
+ * wake up anyone waiting for connections
+ */
+ for (peersock = sock->iconn; peersock; peersock = nextsock) {
+ nextsock = peersock->next;
+ sock_release_peer(peersock);
+ }
+ /*
+ * wake up anyone we're connected to. first, we release the
+ * protocol, to give it a chance to flush data, etc.
+ */
+ peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;
+ if (sock->ops)
+ sock->ops->release(sock, peersock);
+ if (peersock)
+ sock_release_peer(peersock);
+ sock->state = SS_FREE; /* this really releases us */
+ wake_up(&socket_wait_free);
+}
+
+static int
+sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence)
+{
+ PRINTK("sock_lseek: huh?\n");
+ return -EBADF;
+}
+
+static int
+sock_read(struct inode *inode, struct file *file, char *ubuf, int size)
+{
+ struct socket *sock;
+
+ PRINTK("sock_read: buf=0x%x, size=%d\n", ubuf, size);
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_read: can't find socket for inode!\n");
+ return -EBADF;
+ }
+ if (sock->flags & SO_ACCEPTCON)
+ return -EINVAL;
+ return sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK));
+}
+
+static int
+sock_write(struct inode *inode, struct file *file, char *ubuf, int size)
+{
+ struct socket *sock;
+
+ PRINTK("sock_write: buf=0x%x, size=%d\n", ubuf, size);
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_write: can't find socket for inode!\n");
+ return -EBADF;
+ }
+ if (sock->flags & SO_ACCEPTCON)
+ return -EINVAL;
+ return sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK));
+}
+
+static int
+sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent,
+ int count)
+{
+ PRINTK("sock_readdir: huh?\n");
+ return -EBADF;
+}
+
+int
+sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned int arg)
+{
+ struct socket *sock;
+
+ PRINTK("sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n", inode, cmd, arg);
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_ioctl: can't find socket for inode!\n");
+ return -EBADF;
+ }
+ switch (cmd) {
+ case TIOCINQ:
+ case TIOCOUTQ:
+ if (sock->flags & SO_ACCEPTCON)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return sock->ops->ioctl(sock, cmd, arg);
+}
+
+/*static*/ int
+sock_select(struct inode *inode, struct file *file, int which,
+ select_table *seltable)
+{
+ struct socket *sock;
+
+ PRINTK("sock_select: inode = 0x%x, kind = %s\n", inode,
+ (which == SEL_IN) ? "in" :
+ (which == SEL_OUT) ? "out" : "ex");
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_write: can't find socket for inode!\n");
+ return -EBADF;
+ }
+
+ /*
+ * handle server sockets specially
+ */
+ if (sock->flags & SO_ACCEPTCON) {
+ if (which == SEL_IN) {
+ PRINTK("sock_select: %sconnections pending\n",
+ sock->iconn ? "" : "no ");
+ return sock->iconn ? 1 : 0;
+ }
+ PRINTK("sock_select: nothing else for server socket\n");
+ return 0;
+ }
+
+ /*
+ * we can't return errors to select, so its either yes or no.
+ */
+ return sock->ops->select(sock, which) ? 1 : 0;
+}
+
+void
+sock_close(struct inode *inode, struct file *file)
+{
+ struct socket *sock;
+
+ PRINTK("sock_close: inode=0x%x (cnt=%d)\n", inode, inode->i_count);
+ /*
+ * it's possible the inode is NULL if we're closing an unfinished
+ * socket.
+ */
+ if (!inode)
+ return;
+ if (!(sock = socki_lookup(inode))) {
+ printk("sock_close: can't find socket for inode!\n");
+ return;
+ }
+ sock_release(sock);
+}
+
+int
+sock_awaitconn(struct socket *mysock, struct socket *servsock)
+{
+ struct socket *last;
+
+ PRINTK("sock_awaitconn: trying to connect socket 0x%x to 0x%x\n",
+ mysock, servsock);
+ if (!(servsock->flags & SO_ACCEPTCON)) {
+ PRINTK("sock_awaitconn: server not accepting connections\n");
+ return -EINVAL;
+ }
+
+ /*
+ * put ourselves on the server's incomplete connection queue.
+ */
+ mysock->next = NULL;
+ cli();
+ if (!(last = servsock->iconn))
+ servsock->iconn = mysock;
+ else {
+ while (last->next)
+ last = last->next;
+ last->next = mysock;
+ }
+ mysock->state = SS_CONNECTING;
+ mysock->conn = servsock;
+ sti();
+
+ /*
+ * wake up server, then await connection. server will set state to
+ * SS_CONNECTED if we're connected.
+ */
+ wake_up(servsock->wait);
+ if (mysock->state != SS_CONNECTED) {
+ interruptible_sleep_on(mysock->wait);
+ if (mysock->state != SS_CONNECTED) {
+ /*
+ * if we're not connected we could have been
+ * 1) interrupted, so we need to remove ourselves
+ * from the server list
+ * 2) rejected (mysock->conn == NULL), and have
+ * already been removed from the list
+ */
+ if (mysock->conn == servsock) {
+ cli();
+ if ((last = servsock->iconn) == mysock)
+ servsock->iconn = mysock->next;
+ else {
+ while (last->next != mysock)
+ last = last->next;
+ last->next = mysock->next;
+ }
+ sti();
+ }
+ return mysock->conn ? -EINTR : -EACCES;
+ }
+ }
+ return 0;
+}
+
+/*
+ * perform the socket system call. we locate the appropriate family, then
+ * create a fresh socket.
+ */
+static int
+sock_socket(int family, int type, int protocol)
+{
+ int i, fd;
+ struct socket *sock;
+ struct proto_ops *ops;
+
+ PRINTK("sys_socket: family = %d (%s), type = %d, protocol = %d\n",
+ family, family_name(family), type, protocol);
+
+ /*
+ * locate the correct protocol family
+ */
+ for (i = 0; i < NPROTO; ++i)
+ if (proto_table[i].family == family)
+ break;
+ if (i == NPROTO) {
+ PRINTK("sys_socket: family not found\n");
+ return -EINVAL;
+ }
+ ops = proto_table[i].ops;
+
+ /*
+ * check that this is a type that we know how to manipulate and
+ * the protocol makes sense here. the family can still reject the
+ * protocol later.
+ */
+ if ((type != SOCK_STREAM &&
+ type != SOCK_DGRAM &&
+ type != SOCK_SEQPACKET &&
+ type != SOCK_RAW) ||
+ protocol < 0)
+ return -EINVAL;
+
+ /*
+ * allocate the socket and allow the family to set things up. if
+ * the protocol is 0, the family is instructed to select an appropriate
+ * default.
+ */
+ if (!(sock = sock_alloc(1))) {
+ printk("sys_socket: no more sockets\n");
+ return -EAGAIN;
+ }
+ sock->type = type;
+ sock->ops = ops;
+ if ((i = sock->ops->create(sock, protocol)) < 0) {
+ sock_release(sock);
+ return i;
+ }
+
+ if ((fd = get_fd(SOCK_INODE(sock))) < 0) {
+ sock_release(sock);
+ return -EINVAL;
+ }
+
+ return fd;
+}
+
+static int
+sock_socketpair(int family, int type, int protocol, int usockvec[2])
+{
+ int fd1, fd2, i;
+ struct socket *sock1, *sock2;
+
+ PRINTK("sys_socketpair: family = %d, type = %d, protocol = %d\n",
+ family, type, protocol);
+
+ /*
+ * obtain the first socket and check if the underlying protocol
+ * supports the socketpair call
+ */
+ if ((fd1 = sock_socket(family, type, protocol)) < 0)
+ return fd1;
+ sock1 = sockfd_lookup(fd1, NULL);
+ if (!sock1->ops->socketpair) {
+ sys_close(fd1);
+ return -EINVAL;
+ }
+
+ /*
+ * now grab another socket and try to connect the two together
+ */
+ if ((fd2 = sock_socket(family, type, protocol)) < 0) {
+ sys_close(fd1);
+ return -EINVAL;
+ }
+ sock2 = sockfd_lookup(fd2, NULL);
+ if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) {
+ sys_close(fd1);
+ sys_close(fd2);
+ return i;
+ }
+ sock1->conn = sock2;
+ sock2->conn = sock1;
+ sock1->state = SS_CONNECTED;
+ sock2->state = SS_CONNECTED;
+
+ verify_area(usockvec, 2 * sizeof(int));
+ put_fs_long(fd1, &usockvec[0]);
+ put_fs_long(fd2, &usockvec[1]);
+
+ return 0;
+}
+
+/*
+ * binds a name to a socket. nothing much to do here since its the
+ * protocol's responsibility to handle the local address
+ */
+static int
+sock_bind(int fd, struct sockaddr *umyaddr, int addrlen)
+{
+ struct socket *sock;
+ int i;
+
+ PRINTK("sys_bind: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return -EBADF;
+ if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) {
+ PRINTK("sys_bind: bind failed\n");
+ return i;
+ }
+ return 0;
+}
+
+/*
+ * perform a listen. basically, we allow the protocol to do anything
+ * necessary for a listen, and if that works, we mark the socket as
+ * ready for listening.
+ */
+static int
+sock_listen(int fd, int backlog)
+{
+ struct socket *sock;
+
+ PRINTK("sys_listen: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return -EBADF;
+ if (sock->state != SS_UNCONNECTED) {
+ PRINTK("sys_listen: socket isn't unconnected\n");
+ return -EINVAL;
+ }
+ if (sock->flags & SO_ACCEPTCON) {
+ PRINTK("sys_listen: socket already accepting connections!\n");
+ return -EINVAL;
+ }
+ sock->flags |= SO_ACCEPTCON;
+ return 0;
+}
+
+/*
+ * for accept, we attempt to create a new socket, set up the link with the
+ * client, wake up the client, then return the new connected fd.
+ */
+static int
+sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
+{
+ struct file *file;
+ struct socket *sock, *clientsock, *newsock;
+ int i;
+
+ PRINTK("sys_accept: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, &file)))
+ return -EBADF;
+ if (sock->state != SS_UNCONNECTED) {
+ PRINTK("sys_accept: socket isn't unconnected\n");
+ return -EINVAL;
+ }
+ if (!(sock->flags & SO_ACCEPTCON)) {
+ PRINTK("sys_accept: socket not accepting connections!\n");
+ return -EINVAL;
+ }
+
+ /*
+ * if there aren't any sockets awaiting connection, then wait for
+ * one, unless nonblocking
+ */
+ while (!(clientsock = sock->iconn)) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ PRINTK("sys_accept: sleep was interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ if (!(newsock = sock_alloc(0))) {
+ printk("sys_accept: no more sockets\n");
+ return -EINVAL;
+ }
+ newsock->type = sock->type;
+ newsock->ops = sock->ops;
+ if ((i = sock->ops->dup(newsock, sock)) < 0) {
+ sock_release(newsock);
+ return i;
+ }
+
+ if ((fd = get_fd(SOCK_INODE(newsock))) < 0) {
+ sock_release(newsock);
+ return -EINVAL;
+ }
+
+ /*
+ * great. finish the connection relative to server and client,
+ * wake up the client and return the new fd to the server
+ */
+ sock->iconn = clientsock->next;
+ clientsock->next = NULL;
+ newsock->conn = clientsock;
+ clientsock->conn = newsock;
+ clientsock->state = SS_CONNECTED;
+ newsock->state = SS_CONNECTED;
+ newsock->ops->accept(sock, newsock);
+ PRINTK("sys_accept: connected socket 0x%x via 0x%x to 0x%x\n",
+ sock, newsock, clientsock);
+ if (upeer_sockaddr)
+ newsock->ops->getname(newsock, upeer_sockaddr,
+ upeer_addrlen, 1);
+ wake_up(clientsock->wait);
+
+ return fd;
+}
+
+/*
+ * attempt to connect to a socket with the server address.
+ */
+static int
+sock_connect(int fd, struct sockaddr *uservaddr, int addrlen)
+{
+ struct socket *sock;
+ int i;
+
+ PRINTK("sys_connect: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return -EBADF;
+ if (sock->state != SS_UNCONNECTED) {
+ PRINTK("sys_connect: socket not unconnected\n");
+ return -EINVAL;
+ }
+ if ((i = sock->ops->connect(sock, uservaddr, addrlen)) < 0) {
+ PRINTK("sys_connect: connect failed\n");
+ return i;
+ }
+ return 0;
+}
+
+static int
+sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+{
+ struct socket *sock;
+
+ PRINTK("sys_getsockname: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return -EBADF;
+ return sock->ops->getname(sock, usockaddr, usockaddr_len, 0);
+}
+
+static int
+sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+{
+ struct socket *sock;
+
+ PRINTK("sys_getpeername: fd = %d\n", fd);
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return -EBADF;
+ return sock->ops->getname(sock, usockaddr, usockaddr_len, 1);
+}
+
+/*
+ * system call vectors. since i want to rewrite sockets as streams, we have
+ * this level of indirection. not a lot of overhead, since more of the work is
+ * done via read/write/select directly
+ */
+int
+sys_socketcall(int call, unsigned long *args)
+{
+ switch (call) {
+ case SYS_SOCKET:
+ verify_area(args, 3 * sizeof(long));
+ return sock_socket(get_fs_long(args+0),
+ get_fs_long(args+1),
+ get_fs_long(args+2));
+
+ case SYS_BIND:
+ verify_area(args, 3 * sizeof(long));
+ return sock_bind(get_fs_long(args+0),
+ (struct sockaddr *)get_fs_long(args+1),
+ get_fs_long(args+2));
+
+ case SYS_CONNECT:
+ verify_area(args, 3 * sizeof(long));
+ return sock_connect(get_fs_long(args+0),
+ (struct sockaddr *)get_fs_long(args+1),
+ get_fs_long(args+2));
+
+ case SYS_LISTEN:
+ verify_area(args, 2 * sizeof(long));
+ return sock_listen(get_fs_long(args+0),
+ get_fs_long(args+1));
+
+ case SYS_ACCEPT:
+ verify_area(args, 3 * sizeof(long));
+ return sock_accept(get_fs_long(args+0),
+ (struct sockaddr *)get_fs_long(args+1),
+ (int *)get_fs_long(args+2));
+
+ case SYS_GETSOCKNAME:
+ verify_area(args, 3 * sizeof(long));
+ return sock_getsockname(get_fs_long(args+0),
+ (struct sockaddr *)get_fs_long(args+1),
+ (int *)get_fs_long(args+2));
+
+ case SYS_GETPEERNAME:
+ verify_area(args, 3 * sizeof(long));
+ return sock_getpeername(get_fs_long(args+0),
+ (struct sockaddr *)get_fs_long(args+1),
+ (int *)get_fs_long(args+2));
+
+ case SYS_SOCKETPAIR:
+ verify_area(args, 4 * sizeof(long));
+ return sock_socketpair(get_fs_long(args+0),
+ get_fs_long(args+1),
+ get_fs_long(args+2),
+ (int *)get_fs_long(args+3));
+
+ default:
+ return -EINVAL;
+ }
+}
+
+void
+sock_init(void)
+{
+ struct socket *sock;
+ int i, ok;
+
+ for (sock = sockets; sock <= last_socket; ++sock)
+ sock->state = SS_FREE;
+ for (i = ok = 0; i < NPROTO; ++i) {
+ printk("sock_init: initializing family %d (%s)\n",
+ proto_table[i].family, proto_table[i].name);
+ if ((*proto_table[i].ops->init)() < 0) {
+ printk("sock_init: init failed.\n",
+ proto_table[i].family);
+ proto_table[i].family = -1;
+ }
+ else
+ ++ok;
+ }
+ if (!ok)
+ printk("sock_init: warning: no protocols initialized\n");
+ return;
+}
+
--- /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 <signal.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "kern_sock.h"
+
+static struct unix_proto_data {
+ int refcnt; /* cnt of reference 0=free */
+ struct socket *socket; /* socket we're bound to */
+ int protocol;
+ struct sockaddr_un sockaddr_un;
+ short sockaddr_len; /* >0 if name bound */
+ char *buf;
+ int bp_head, bp_tail;
+ struct inode *inode;
+ struct unix_proto_data *peerupd;
+} unix_datas[NSOCKETS];
+#define last_unix_data (unix_datas + NSOCKETS - 1)
+
+#define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data)
+#define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0)->sun_path)
+
+/*
+ * buffer size must be power of 2. buffer mgmt inspired by pipe code.
+ * note that buffer contents can wraparound, and we can write one byte less
+ * than full size to discern full vs empty.
+ */
+#define BUF_SIZE PAGE_SIZE
+#define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & (BUF_SIZE-1))
+#define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD))
+
+static int unix_proto_init(void);
+static int unix_proto_create(struct socket *sock, int protocol);
+static int unix_proto_dup(struct socket *newsock, struct socket *oldsock);
+static int unix_proto_release(struct socket *sock, struct socket *peer);
+static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+ int sockaddr_len);
+static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len);
+static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2);
+static int unix_proto_accept(struct socket *sock, struct socket *newsock);
+static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+ int *usockaddr_len, int peer);
+static int unix_proto_read(struct socket *sock, char *ubuf, int size,
+ int nonblock);
+static int unix_proto_write(struct socket *sock, char *ubuf, int size,
+ int nonblock);
+static int unix_proto_select(struct socket *sock, int which);
+static int unix_proto_ioctl(struct socket *sock, unsigned int cmd,
+ unsigned long arg);
+
+struct proto_ops unix_proto_ops = {
+ unix_proto_init,
+ unix_proto_create,
+ unix_proto_dup,
+ unix_proto_release,
+ unix_proto_bind,
+ unix_proto_connect,
+ unix_proto_socketpair,
+ unix_proto_accept,
+ unix_proto_getname,
+ unix_proto_read,
+ unix_proto_write,
+ unix_proto_select,
+ unix_proto_ioctl
+};
+
+#ifdef SOCK_DEBUG
+void
+sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
+{
+ char buf[sizeof(sockun->sun_path) + 1];
+
+ sockaddr_len -= UN_PATH_OFFSET;
+ if (sockun->sun_family != AF_UNIX)
+ printk("sockaddr_un: <BAD FAMILY: %d>\n", sockun->sun_family);
+ else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)-1)
+ printk("sockaddr_un: <BAD LENGTH: %d>\n", sockaddr_len);
+ else {
+ memcpy(buf, sockun->sun_path, sockaddr_len);
+ buf[sockaddr_len] = '\0';
+ printk("sockaddr_un: '%s'[%d]\n", buf,
+ sockaddr_len + UN_PATH_OFFSET);
+ }
+}
+#endif
+
+static struct unix_proto_data *
+unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
+{
+ struct unix_proto_data *upd;
+
+ for (upd = unix_datas; upd <= last_unix_data; ++upd) {
+ if (upd->refcnt && upd->socket &&
+ upd->sockaddr_len == sockaddr_len &&
+ memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0)
+ return upd;
+ }
+ return NULL;
+}
+
+static struct unix_proto_data *
+unix_data_alloc(void)
+{
+ struct unix_proto_data *upd;
+
+ cli();
+ for (upd = unix_datas; upd <= last_unix_data; ++upd) {
+ if (!upd->refcnt) {
+ upd->refcnt = 1;
+ sti();
+ upd->socket = NULL;
+ upd->sockaddr_len = 0;
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ upd->inode = NULL;
+ upd->peerupd = NULL;
+ return upd;
+ }
+ }
+ sti();
+ return NULL;
+}
+
+static inline void
+unix_data_ref(struct unix_proto_data *upd)
+{
+ ++upd->refcnt;
+ PRINTK("unix_data_ref: refing data 0x%x (%d)\n", upd, upd->refcnt);
+}
+
+static void
+unix_data_deref(struct unix_proto_data *upd)
+{
+ if (upd->refcnt == 1) {
+ PRINTK("unix_data_deref: releasing data 0x%x\n", upd);
+ if (upd->buf) {
+ free_page((unsigned long)upd->buf);
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ }
+ }
+ --upd->refcnt;
+}
+
+/*
+ * upon a create, we allocate an empty protocol data, and grab a page to
+ * buffer writes
+ */
+static int
+unix_proto_create(struct socket *sock, int protocol)
+{
+ struct unix_proto_data *upd;
+
+ PRINTK("unix_proto_create: socket 0x%x, proto %d\n", sock, protocol);
+ if (protocol != 0) {
+ PRINTK("unix_proto_create: protocol != 0\n");
+ return -EINVAL;
+ }
+ if (!(upd = unix_data_alloc())) {
+ printk("unix_proto_create: can't allocate buffer\n");
+ return -ENOMEM;
+ }
+ if (!(upd->buf = (char *)get_free_page())) {
+ printk("unix_proto_create: can't get page!\n");
+ unix_data_deref(upd);
+ return -ENOMEM;
+ }
+ upd->protocol = protocol;
+ upd->socket = sock;
+ UN_DATA(sock) = upd;
+ PRINTK("unix_proto_create: allocated data 0x%x\n", upd);
+ return 0;
+}
+
+static int
+unix_proto_dup(struct socket *newsock, struct socket *oldsock)
+{
+ struct unix_proto_data *upd = UN_DATA(oldsock);
+
+ return unix_proto_create(newsock, upd->protocol);
+}
+
+static int
+unix_proto_release(struct socket *sock, struct socket *peer)
+{
+ struct unix_proto_data *upd = UN_DATA(sock);
+
+ PRINTK("unix_proto_release: socket 0x%x, unix_data 0x%x\n",
+ sock, upd);
+ if (!upd)
+ return 0;
+ if (upd->socket != sock) {
+ printk("unix_proto_release: socket link mismatch!\n");
+ return -EINVAL;
+ }
+ if (upd->inode) {
+ PRINTK("unix_proto_release: releasing inode 0x%x\n",
+ upd->inode);
+ iput(upd->inode);
+ upd->inode = NULL;
+ }
+ UN_DATA(sock) = NULL;
+ upd->socket = NULL;
+ if (upd->peerupd)
+ unix_data_deref(upd->peerupd);
+ unix_data_deref(upd);
+ return 0;
+}
+
+/*
+ * bind a name to a socket. this is where much of the work is done. we
+ * allocate a fresh page for the buffer, grab the appropriate inode and
+ * set things up.
+ *
+ * XXX what should we do if an address is already bound? here we return
+ * EINVAL, but it may be necessary to re-bind. i think thats what bsd does
+ * in the case of datagram sockets
+ */
+static int
+unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+ int sockaddr_len)
+{
+ struct unix_proto_data *upd = UN_DATA(sock);
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+ int i;
+ unsigned long old_fs;
+ unsigned short old_euid;
+
+ PRINTK("unix_proto_bind: socket 0x%x, len=%d\n", sock,
+ sockaddr_len);
+ if (sockaddr_len <= UN_PATH_OFFSET ||
+ sockaddr_len >= sizeof(struct sockaddr_un)) {
+ PRINTK("unix_proto_bind: bad length %d\n", sockaddr_len);
+ return -EINVAL;
+ }
+ if (upd->sockaddr_len || upd->inode) {
+ printk("unix_proto_bind: already bound!\n");
+ return -EINVAL;
+ }
+ verify_area(umyaddr, sockaddr_len);
+ memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
+ if (upd->sockaddr_un.sun_family != AF_UNIX) {
+ PRINTK("unix_proto_bind: family is %d, not AF_UNIX (%d)\n",
+ upd->sockaddr_un.sun_family, AF_UNIX);
+ return -EINVAL;
+ }
+
+ /*
+ * W A R N I N G
+ * this is a terrible hack. i want to create a socket in the
+ * filesystem and get its inode. sys_mknod() can create one for
+ * me, but it needs superuser privs and doesn't give me the inode.
+ * we fake suser here and get the file created... ugh.
+ */
+ memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ old_fs = get_fs();
+ set_fs(get_ds());
+ old_euid = current->euid;
+ current->euid = 0;
+ i = sys_mknod(fname, S_IFSOCK, 0);
+ current->euid = old_euid;
+ if (i == 0)
+ i = open_namei(fname, 0, S_IFSOCK, &upd->inode);
+ set_fs(old_fs);
+ if (i < 0) {
+ printk("unix_proto_bind: can't open socket %s\n", fname);
+ return i;
+ }
+
+ upd->sockaddr_len = sockaddr_len; /* now its legal */
+ PRINTK("unix_proto_bind: bound socket address: ");
+#ifdef SOCK_DEBUG
+ sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
+#endif
+ return 0;
+}
+
+/*
+ * perform a connection. we can only connect to unix sockets (i can't for
+ * the life of me find an application where that wouldn't be the case!)
+ */
+static int
+unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len)
+{
+ int i;
+ struct unix_proto_data *serv_upd;
+ struct sockaddr_un sockun;
+
+ PRINTK("unix_proto_connect: socket 0x%x, servlen=%d\n", sock,
+ sockaddr_len);
+ if (sockaddr_len <= UN_PATH_OFFSET ||
+ sockaddr_len >= sizeof(struct sockaddr_un)) {
+ PRINTK("unix_proto_connect: bad length %d\n", sockaddr_len);
+ return -EINVAL;
+ }
+ verify_area(uservaddr, sockaddr_len);
+ memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
+ if (sockun.sun_family != AF_UNIX) {
+ PRINTK("unix_proto_connect: family is %d, not AF_UNIX (%d)\n",
+ sockun.sun_family, AF_UNIX);
+ return -EINVAL;
+ }
+ if (!(serv_upd = unix_data_lookup(&sockun, sockaddr_len))) {
+ PRINTK("unix_proto_connect: can't locate peer\n");
+ return -EINVAL;
+ }
+ if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
+ PRINTK("unix_proto_connect: can't await connection\n");
+ return i;
+ }
+ unix_data_ref(UN_DATA(sock->conn));
+ UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
+ return 0;
+}
+
+/*
+ * to do a socketpair, we make just connect the two datas, easy! since we
+ * always wait on the socket inode, they're no contention for a wait area,
+ * and deadlock prevention in the case of a process writing to itself is,
+ * ignored, in true unix fashion!
+ */
+static int
+unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
+{
+ struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
+
+ unix_data_ref(upd1);
+ unix_data_ref(upd2);
+ upd1->peerupd = upd2;
+ upd2->peerupd = upd1;
+ return 0;
+}
+
+/*
+ * on accept, we ref the peer's data for safe writes
+ */
+static int
+unix_proto_accept(struct socket *sock, struct socket *newsock)
+{
+ PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n",
+ sock, newsock);
+ unix_data_ref(UN_DATA(newsock->conn));
+ UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn);
+ return 0;
+}
+
+/*
+ * gets the current name or the name of the connected socket.
+ */
+static int
+unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+ int *usockaddr_len, int peer)
+{
+ struct unix_proto_data *upd;
+ int len;
+
+ PRINTK("unix_proto_getname: socket 0x%x for %s\n", sock,
+ peer ? "peer" : "self");
+ if (peer) {
+ if (sock->state != SS_CONNECTED) {
+ PRINTK("unix_proto_getname: socket not connected\n");
+ return -EINVAL;
+ }
+ upd = UN_DATA(sock->conn);
+ }
+ else
+ upd = UN_DATA(sock);
+ verify_area(usockaddr_len, sizeof(*usockaddr_len));
+ if ((len = get_fs_long(usockaddr_len)) <= 0)
+ return -EINVAL;
+ if (len > upd->sockaddr_len)
+ len = upd->sockaddr_len;
+ if (len) {
+ verify_area(usockaddr, len);
+ memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
+ }
+ put_fs_long(len, usockaddr_len);
+ return 0;
+}
+
+/*
+ * we read from our own buf.
+ */
+static int
+unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *upd;
+ int todo, avail;
+
+ if ((todo = size) <= 0)
+ return 0;
+ upd = UN_DATA(sock);
+ while (!(avail = UN_BUF_AVAIL(upd))) {
+ if (sock->state != SS_CONNECTED) {
+ PRINTK("unix_proto_read: socket not connected\n");
+ return (sock->state == SS_DISCONNECTING) ? 0 : -EINVAL;
+ }
+ PRINTK("unix_proto_read: no data available...\n");
+ if (nonblock)
+ return -EAGAIN;
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ PRINTK("unix_proto_read: interrupted\n");
+ return -ERESTARTSYS;
+ }
+ if (sock->state == SS_DISCONNECTING) {
+ PRINTK("unix_proto_read: disconnected\n");
+ return 0;
+ }
+ }
+
+ /*
+ * copy from the read buffer into the user's buffer, watching for
+ * wraparound. then we wake up the writer
+ */
+ do {
+ int part, cando;
+
+ if (avail <= 0) {
+ PRINTK("unix_proto_read: AVAIL IS NEGATIVE!!!\n");
+ current->signal |= (1 << (SIGKILL-1));
+ return -EINTR;
+ }
+
+ if ((cando = todo) > avail)
+ cando = avail;
+ if (cando > (part = BUF_SIZE - upd->bp_tail))
+ cando = part;
+ PRINTK("unix_proto_read: avail=%d, todo=%d, cando=%d\n",
+ avail, todo, cando);
+ verify_area(ubuf, cando);
+ memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
+ upd->bp_tail = (upd->bp_tail + cando) & (BUF_SIZE-1);
+ ubuf += cando;
+ todo -= cando;
+ if (sock->state == SS_CONNECTED)
+ wake_up(sock->conn->wait);
+ avail = UN_BUF_AVAIL(upd);
+ } while (todo && avail);
+ return size - todo;
+}
+
+/*
+ * we write to our peer's buf. when we connected we ref'd this peer so we
+ * are safe that the buffer remains, even after the peer has disconnected,
+ * which we check other ways.
+ */
+static int
+unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *pupd;
+ int todo, space;
+
+ if ((todo = size) <= 0)
+ return 0;
+ if (sock->state != SS_CONNECTED) {
+ PRINTK("unix_proto_write: socket not connected\n");
+ if (sock->state == SS_DISCONNECTING) {
+ current->signal |= (1 << (SIGPIPE-1));
+ return -EINTR;
+ }
+ return -EINVAL;
+ }
+ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
+
+ while (!(space = UN_BUF_SPACE(pupd))) {
+ PRINTK("unix_proto_write: no space left...\n");
+ if (nonblock)
+ return 0;
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ PRINTK("unix_proto_write: interrupted\n");
+ return -EINTR;
+ }
+ if (sock->state == SS_DISCONNECTING) {
+ PRINTK("unix_proto_write: disconnected (SIGPIPE)\n");
+ current->signal |= (1 << (SIGPIPE-1));
+ return -EINTR;
+ }
+ }
+
+ /*
+ * copy from the user's buffer to the write buffer, watching for
+ * wraparound. then we wake up the reader
+ */
+ do {
+ int part, cando;
+
+ if (space <= 0) {
+ PRINTK("unix_proto_write: SPACE IS NEGATIVE!!!\n");
+ current->signal |= (1 << (SIGKILL-1));
+ return -EINTR;
+ }
+
+ /*
+ * we may become disconnected inside this loop, so watch
+ * for it (peerupd is safe until we close)
+ */
+ if (sock->state == SS_DISCONNECTING) {
+ current->signal |= (1 << (SIGPIPE-1));
+ return -EINTR;
+ }
+ if ((cando = todo) > space)
+ cando = space;
+ if (cando > (part = BUF_SIZE - pupd->bp_head))
+ cando = part;
+ PRINTK("unix_proto_write: space=%d, todo=%d, cando=%d\n",
+ space, todo, cando);
+ verify_area(ubuf, cando);
+ memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
+ pupd->bp_head = (pupd->bp_head + cando) & (BUF_SIZE-1);
+ ubuf += cando;
+ todo -= cando;
+ if (sock->state == SS_CONNECTED)
+ wake_up(sock->conn->wait);
+ space = UN_BUF_SPACE(pupd);
+ } while (todo && space);
+ return size - todo;
+}
+
+static int
+unix_proto_select(struct socket *sock, int which)
+{
+ struct unix_proto_data *upd, *peerupd;
+
+ if (which == SEL_IN) {
+ upd = UN_DATA(sock);
+ PRINTK("unix_proto_select: there is%s data available\n",
+ UN_BUF_AVAIL(upd) ? "" : " no");
+ if (UN_BUF_AVAIL(upd)) /* even if disconnected */
+ return 1;
+ else if (sock->state != SS_CONNECTED) {
+ PRINTK("unix_proto_select: socket not connected (read EOF)\n");
+ return 1;
+ }
+ else
+ return 0;
+ }
+ if (which == SEL_OUT) {
+ if (sock->state != SS_CONNECTED) {
+ PRINTK("unix_proto_select: socket not connected (write EOF)\n");
+ return 1;
+ }
+ peerupd = UN_DATA(sock->conn);
+ PRINTK("unix_proto_select: there is%s space available\n",
+ UN_BUF_SPACE(peerupd) ? "" : " no");
+ return (UN_BUF_SPACE(peerupd) > 0);
+ }
+ /* SEL_EX */
+ PRINTK("unix_proto_select: there are no exceptions here?!\n");
+ return 0;
+}
+
+static int
+unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct unix_proto_data *upd, *peerupd;
+
+ upd = UN_DATA(sock);
+ peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
+
+ switch (cmd) {
+ case TIOCINQ:
+ verify_area((void *)arg, sizeof(unsigned long));
+ if (UN_BUF_AVAIL(upd) || peerupd)
+ put_fs_long(UN_BUF_AVAIL(upd), (unsigned long *)arg);
+ else
+ put_fs_long(1, (unsigned long *)arg); /* read EOF */
+ break;
+
+ case TIOCOUTQ:
+ verify_area((void *)arg, sizeof(unsigned long));
+ if (peerupd)
+ put_fs_long(UN_BUF_SPACE(peerupd),
+ (unsigned long *)arg);
+ else
+ put_fs_long(0, (unsigned long *)arg);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+unix_proto_init(void)
+{
+ struct unix_proto_data *upd;
+
+ PRINTK("unix_proto_init: initializing...\n");
+ for (upd = unix_datas; upd <= last_unix_data; ++upd)
+ upd->refcnt = 0;
+ return 0;
+}